2 # src/vm/jit/verify/generate.pl - verifier generator
4 # Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
5 # C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
6 # E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
7 # J. Wenninger, Institut f. Computersprachen - TU Wien
9 # This file is part of CACAO.
11 # This program is free software; you can redistribute it and/or
12 # modify it under the terms of the GNU General Public License as
13 # published by the Free Software Foundation; either version 2, or (at
14 # your option) any later version.
16 # This program is distributed in the hope that it will be useful, but
17 # WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 # General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with this program; if not, write to the Free Software
23 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 # Contact: cacao@cacaojvm.org
28 # Authors: Edwin Steiner
38 #################### options
43 my $opt_variables = 0;
44 my $opt_typeinferer = 0;
48 my $usage = <<"END_USAGE";
50 $0 --icmdtable FILE { --table | --stack | --variables | --typeinferer } [--debug]
53 --icmdtable FILE read ICMD table from FILE
54 --table print ICMD table
55 --stack generate stackbased verifier
56 --variables generate variablesbased verifier
57 --typeinferer generate the type inference pass
58 --debug generate additional debugging code
60 Please specify exactly one of --table, --stack, --variables, or --typeinferer.
64 my $result = GetOptions("icmdtable=s" => \$opt_icmdtable,
65 "table" => \$opt_table,
66 "stack" => \$opt_stack,
67 "variables" => \$opt_variables,
68 "typeinferer" => \$opt_typeinferer,
69 "debug" => \$opt_debug,
70 "help|h|?" => \$opt_help,
73 $result or die "$0: invalid options\n";
80 if (!defined($opt_icmdtable)
81 || ($opt_table + $opt_stack + $opt_variables + $opt_typeinferer != 1))
87 #################### constants
89 my $VERIFY_C = 'src/vm/jit/verify/icmds.c';
90 my $TYPECHECK_STACKBASED_INC = 'src/vm/jit/verify/typecheck-stackbased-gen.inc';
91 my $TYPECHECK_VARIABLESBASED_INC = 'src/vm/jit/verify/typecheck-variablesbased-gen.inc';
92 my $TYPECHECK_TYPEINFERER_INC = 'src/vm/jit/verify/typecheck-typeinferer-gen.inc';
96 my @basictypes = qw(A I F L D R); # XXX remove R?
97 my %basictypes = map { $_ => 1 } @basictypes;
107 R => 1, # XXX remove?
116 R => 'TYPE_RET', # XXX remove?
119 my @superblockend = qw(END GOTO JSR RET TABLE LOOKUP);
120 my %superblockend = map { $_ => 1 } @superblockend;
122 my @validstages = qw( -- -S S+ );
123 my %validstages = map { $_ => 1 } @validstages;
125 my @valid_tags = qw(STACKBASED VARIABLESBASED TYPEINFERER);
126 my @default_tags = qw(STACKBASED VARIABLESBASED);
128 my %valid_tag = map { $_ => 1 } @valid_tags;
130 #################### global variables
139 #################### subs
141 sub parse_verify_code
143 my ($filename, $select) = @_;
145 my $file = IO::File->new($filename) or die "$0: could not open: $filename";
151 last if /^\s*\/\*\s*{START_OF_CODE}\s*\*\/\s*$/;
155 last if /^\s*\/\*\s*{END_OF_CODE}\s*\*\/\s*$/;
158 unless (/^case \s+ (\w+) \s* :
159 \s* ( \/\* \s* {\s* (\w+ (\s*,\s* \w+)*) \s*} \s* \*\/ )?
162 die "$0: invalid case line: $filename:$.: $_";
164 my ($n, $unused, $tags) = ($1, $2, $3 || '');
166 my @tags = split /\s*,\s*/, $tags;
168 if (@tags == 1 && $tags[0] eq 'ALL') {
171 @tags = @default_tags unless @tags;
173 defined($icmds{$n}) or die "$0: unknown ICMD: $filename:$.: $_";
177 for my $tag (@tags) {
178 $valid_tag{$tag} or die "$0: invalid tag: $filename:$.: $tag";
180 $ignore = 0 if $tag eq $select;
187 if (defined($icmd)) {
188 $code = $icmd->{VERIFYCODE};
189 $codeprops = $icmd->{VERIFYCODEPROPS};
193 $icmd->{VERIFYCODE} = $code;
194 $icmd->{VERIFYCODELINE} = $. + 1;
195 $icmd->{VERIFYCODEFILE} = $filename;
196 $icmd->{VERIFYCODEPROPS} = $codeprops;
200 if (/^\s*break\s*;\s*$/
201 || /^\s*goto\s+(\w+)\s*;\s*$/)
206 elsif (defined($icmd)) {
207 if (/^\s*break\s*;\s*$/) {
210 elsif (/^\s*goto\s+(\w+)\s*;\s*$/) {
211 $icmd->{GOTOLABEL} = $1;
215 if (/\{RESULTNOW\}/) {
216 $codeprops->{RESULTNOW} = 1;
219 if (/\S/ || scalar @{$icmd->{VERIFYCODE}} != 0) {
220 push @{$icmd->{VERIFYCODE}}, $_;
226 next if /^\s*\/\*.*\*\/\s*$/;
228 die "$0: cannot handle code line outside case: $filename:$.: $_";
235 my ($str, $len) = @_;
237 return $str . (' ' x ($len - length($str)));
242 my ($flags, $name) = @_;
244 if ($$flags eq '0') {
248 $$flags .= '|'.$name;
254 my ($icmd,$key,$default) = @_;
256 $default = "\0" unless defined($default);
258 return (defined($icmd->{$key})) ? ":$key:".($icmd->{$key})
264 my ($icmd,$key,$traits) = @_;
266 $traits = $key . ':' . $traits;
268 $icmd->{$key} = $traits;
269 push @{$icmdtraits{$traits}}, $icmd;
272 sub post_process_icmds
277 my $maxfullnamelen = 0;
278 my $maxactionlen = 0;
281 for my $icmdname (@icmds) {
282 my $icmd = $icmds{$icmdname};
285 my $action = $icmd->{ACTION};
286 my @variants = split (/\s*\|\s*/, $action);
288 $icmd->{VARIANTS} = [];
290 for my $v (@variants) {
291 $v =~ /^(.*?)\s*--\s*(.*)$/ or die "invalid action: $_";
292 my ($in, $out) = ($1, $2);
297 @in = split /\s*/, $in;
303 @out = split /\s*/, $out;
306 @out = split //, $out;
308 my $invars = scalar @in;
309 my $outvars = scalar @out;
312 push @{$icmd->{VARIANTS}}, $var;
317 $icmd->{INVARS} = $invars;
318 $icmd->{OUTVARS} = $outvars;
323 my $slots = $slots{$_};
324 defined($slots) or undef $inslots, last;
328 my $slots = $slots{$_};
329 defined($slots) or undef $outslots, last;
333 $var->{INSLOTS} = $inslots;
334 $var->{OUTSLOTS} = $outslots;
336 if (defined($inslots)) {
337 if (!defined($icmd->{MININSLOTS}) || $inslots < $icmd->{MININSLOTS}) {
338 $icmd->{MININSLOTS} = $inslots;
341 if (exists $icmd->{INSLOTS}) {
342 if ($icmd->{INSLOTS} != $inslots) {
343 $icmd->{INSLOTS} = undef;
347 $icmd->{INSLOTS} = $inslots;
351 $icmd->{INSLOTS} = undef;
352 $icmd->{MININSLOTS} = undef;
355 if (defined($outslots)) {
356 if (exists $icmd->{OUTSLOTS}) {
357 if (defined($icmd->{OUTSLOTS}) && $icmd->{OUTSLOTS} != $outslots) {
358 $icmd->{OUTSLOTS} = undef;
362 $icmd->{OUTSLOTS} = $outslots;
366 $icmd->{OUTSLOTS} = undef;
369 if ($outvars == 0 || $outvars == 1) {
370 my $df = $invars . '_TO_' . $outvars;
371 if (defined($icmd->{DATAFLOW})) {
372 if ($icmd->{DATAFLOW} =~ /^\d_TO_\d$/) {
373 $icmd->{DATAFLOW} eq $df
374 or die "$0: dataflow not consistent with action: "
375 .$icmd->{FULLNAME}."\n";
379 $icmd->{DATAFLOW} = $df;
384 if ($basictypes{$out[0]}) {
385 $icmd->{BASICOUTTYPE} = $out[0];
389 $icmd->{ACTION} =~ s/\s//g;
392 $maxfullnamelen = length($icmdname) if length($icmdname) > $maxfullnamelen;
393 $maxnamelen = length($icmd->{NAME}) if length($icmd->{NAME}) > $maxnamelen;
394 $maxactionlen = length($icmd->{ACTION}) if length($icmd->{ACTION}) > $maxactionlen;
398 $icmd->{STAGE} = ' ' unless defined($icmd->{STAGE});
400 if ($icmdname =~ /^(.*)CONST$/ && defined($icmds{$1})) {
401 $parent = $icmds{$1};
404 if (!defined($icmd->{DATAFLOW}) && defined($parent)) {
405 if ($parent->{DATAFLOW} =~ /(\d)_TO_(\d)/) {
406 $1 >= 0 or die "$0: cannot derive data-flow: $icmdname from ".$parent->{FULLNAME};
407 $icmd->{DATAFLOW} = ($1-1).'_TO_'.$2;
411 if (!defined($icmd->{BASICOUTTYPE}) && defined($parent)) {
412 $icmd->{BASICOUTTYPE} = $parent->{BASICOUTTYPE};
415 if (defined($icmd->{INSLOTS}) && defined($icmd->{OUTSLOTS})) {
416 $icmd->{STACKCHANGE} = $icmd->{OUTSLOTS} - $icmd->{INSLOTS};
420 add_flag(\$flags, 'PEI') if $icmd->{MAYTHROW};
421 add_flag(\$flags, $icmd->{CALLS}) if $icmd->{CALLS};
423 $icmd->{FLAGS} = $flags;
425 $maxflagslen = length($flags) if length($flags) > $maxflagslen;
427 ### calculate traits for building equivalence classes of ICMDs
429 # traits used in all cases
430 my $commontraits = trait($icmd, 'CONTROLFLOW')
431 . trait($icmd, 'MAYTHROW', 0)
432 . trait($icmd, 'VERIFYCODE');
434 # traits that completely define the kind of dataflow
435 my $datatraits = trait($icmd, 'DATAFLOW')
436 . trait($icmd, 'ACTION');
438 # traits defining the output type
440 if ($icmd->{DATAFLOW} =~ /^\d_TO_\d$/) {
441 $outputtraits = trait($icmd, 'OUTVARS')
442 . trait($icmd, 'BASICOUTTYPE');
445 $outputtraits = $datatraits;
448 # traits used by the stack-based verifier
449 my $traits = $commontraits
451 set_icmd_traits($icmd, 'STACKBASED', $traits);
453 # traits used by the variables-based verifier
454 $traits = $commontraits
455 . ($opt_debug ? $datatraits : $outputtraits);
456 set_icmd_traits($icmd, 'VARIABLESBASED', $traits);
458 # traits used by the type inference pass
459 $traits = $commontraits
460 . ($opt_debug ? $datatraits : $outputtraits);
461 set_icmd_traits($icmd, 'TYPEINFERER', $traits);
465 $maxactionlen = $maxmax if $maxactionlen > $maxmax;
467 for my $icmdname (@icmds) {
468 my $icmd = $icmds{$icmdname};
470 $icmd->{FULLNAME_FILLED} = fill($icmd->{FULLNAME}, $maxfullnamelen);
471 $icmd->{NAME_FILLED} = fill($icmd->{NAME}, $maxnamelen);
472 $icmd->{ACTION_FILLED} = fill("(".$icmd->{ACTION}.")", $maxactionlen+2);
473 $icmd->{FLAGS_FILLED} = fill($icmd->{FLAGS}, $maxflagslen);
479 my $text = join '', @_;
481 $text =~ s/\n/\n GENERATED /g;
482 $text =~ s/^#/\n# /g;
484 my $newlines = () = $text =~ /\n/g;
486 print $codefile $text;
487 $codeline += $newlines;
490 sub write_verify_stackbased_stackchange
494 my $outslots = $icmd->{OUTSLOTS};
495 my $inslots = $icmd->{INSLOTS};
496 my $outtype = $icmd->{BASICOUTTYPE};
497 my $stackchange = $icmd->{STACKCHANGE};
501 if (defined($inslots) && defined($outslots)) {
503 ### modify stack pointer and write destination type
505 if ($stackchange != 0) {
506 code "\tstack += ", $stackchange, ";\n";
509 if (defined($icmd->{VARIANTS}) && scalar @{$icmd->{VARIANTS}} == 1) {
510 my $var = $icmd->{VARIANTS}->[0];
512 if (defined($outtype)) {
513 if ($outslots && ($inslots < $outslots || $var->{IN}->[0] ne $outtype)) {
514 if ($outslots == 1) {
515 code "\tstack[0].type = ", $cacaotypes{$outtype}, ";\n";
518 elsif ($outslots == 2) {
519 code "\tstack[0].type = TYPE_VOID;\n";
520 code "\tstack[-1].type = ", $cacaotypes{$outtype}, ";\n";
533 my ($icmd, $traits, $condition, $done) = @_;
535 code "case ", $icmd->{FULLNAME}, ":\n";
537 my $eqgroup = $icmdtraits{$icmd->{$traits}};
538 my @actions = ($icmd->{ACTION});
540 for my $ocmd (@$eqgroup) {
541 next unless $condition->($ocmd);
542 if ($ocmd->{FULLNAME} ne $icmd->{FULLNAME}) {
543 code "case ", $ocmd->{FULLNAME}, ":\n";
544 $done->{$ocmd->{FULLNAME}}++;
546 unless (grep { $_ eq $ocmd->{ACTION} } @actions) {
547 push @actions, $ocmd->{ACTION};
552 code "\t/* ", join(", ", map { "($_)" } @actions), " */\n";
555 sub write_icmd_set_props
559 if ($icmd->{MAYTHROW}) {
560 code "\tmaythrow = true;\n";
562 if ($superblockend{$icmd->{CONTROLFLOW}}) {
563 code "\tsuperblockend = true;\n";
571 print $file "\n#undef GENERATED\n";
572 print $file "/* vim:filetype=c:\n";
576 sub get_dst_slots_and_ctype
578 my ($icmd, $op1) = @_;
582 for my $v (@{$icmd->{VARIANTS}}) {
583 my $intype = $v->{IN}->[0];
584 if (defined($inslots) && $inslots != $slots{$intype}) {
585 die "$0: error: mixed slotsize for STORE is not supported: ".$icmd->{NAME};
588 $inslots = $slots{$intype};
591 if (defined($type) && $type ne $cacaotypes{$intype}) {
592 $type = "$op1->type";
595 $type = $cacaotypes{$intype};
599 return ($inslots, $type);
602 sub write_verify_stackbased_code
610 my $codefilename = $TYPECHECK_STACKBASED_INC;
612 print $file "#define GENERATED\n";
615 my $condition = sub { $_[0]->{STAGE} ne '--' and $_[0]->{STAGE} ne 'S+' };
617 for my $icmdname (@icmds) {
618 my $icmd = $icmds{$icmdname};
620 next if $done{$icmdname};
621 next unless $condition->($icmd);
625 my $outslots = $icmd->{OUTSLOTS};
626 my $inslots = $icmd->{INSLOTS};
627 my $outtype = $icmd->{BASICOUTTYPE};
628 my $stackchange = $icmd->{STACKCHANGE};
632 ### start instruction case, group instructions with same code
635 write_icmd_cases($icmd, 'STACKBASED', $condition, \%done);
637 ### instruction properties
639 write_icmd_set_props($icmd);
641 ### check stackdepth and stack types
643 if (defined($inslots) && $inslots > 0) {
644 code "\tCHECK_STACK_DEPTH($inslots);\n";
646 elsif (!defined($inslots)) {
647 code "\t/* variable number of inslots! */\n";
650 if (defined($stackchange) && $stackchange > 0) {
651 code "\tCHECK_STACK_SPACE(", $stackchange, ");\n";
653 elsif (!defined($outslots)) {
654 code "\t/* variable number of outslots! */\n";
657 if (defined($inslots) && defined($outslots) && defined($icmd->{VARIANTS})
658 && scalar @{$icmd->{VARIANTS}} == 1)
660 my $var = $icmd->{VARIANTS}->[0];
662 my $depth = 1 - $inslots;
664 for my $in (@{$var->{IN}}) {
665 my $ctype = $cacaotypes{$in};
666 my $slots = $slots{$in};
667 if (defined($ctype)) {
668 code "\tCHECK_STACK_TYPE(stack[$depth], $ctype);\n";
675 ### check/store local types
677 my $prohibit_stackchange = 0;
679 if ($icmd->{DATAFLOW} eq 'LOAD') {
680 code "\tCHECK_LOCAL_TYPE(IPTR->s1.varindex, ".$cacaotypes{$outtype}.");\n";
681 if ($icmd->{VERIFYCODE}) {
682 code "#\tdefine OP1 LOCAL_SLOT(IPTR->s1.varindex)\n";
686 elsif ($icmd->{DATAFLOW} eq 'IINC') {
687 code "\tCHECK_LOCAL_TYPE(IPTR->s1.varindex, TYPE_INT);\n";
689 elsif ($icmd->{DATAFLOW} eq 'STORE') {
690 my ($inslots, $type) = get_dst_slots_and_ctype($icmd, 'OP1');
691 if ($type =~ /OP1/) {
692 code "#\tdefine OP1 (&(stack[".(1-$inslots)."]))\n";
694 $prohibit_stackchange = 1;
697 code "\tSTORE_LOCAL_2_WORD(".$type.", IPTR->dst.varindex);\n";
700 code "\tSTORE_LOCAL(".$type.", IPTR->dst.varindex);\n";
702 if ($icmd->{VERIFYCODE}) {
703 code "#\tdefine DST LOCAL_SLOT(IPTR->dst.varindex)\n";
708 ### custom verification code
712 if ($icmd->{VERIFYCODE}) {
713 if ($icmd->{VERIFYCODEPROPS}->{RESULTNOW}) {
714 if ($prohibit_stackchange) {
715 die "$0: prohibited stack change before custom code: ".$icmd->{NAME};
717 if (write_verify_stackbased_stackchange($icmd)) {
718 code "\t/* CAUTION: stack types changed before custom code! */\n";
721 code "\t/* CAUTION: stack pointer changed before custom code! */\n";
726 if (defined($inslots) && defined($outslots) && defined($icmd->{VARIANTS})
727 && scalar @{$icmd->{VARIANTS}} == 1)
729 my $var = $icmd->{VARIANTS}->[0];
731 my $depth = 1 - $inslots;
732 $depth -= $stackchange if $stackdone;
734 for my $in (@{$var->{IN}}) {
735 my $ctype = $cacaotypes{$in};
736 my $slots = $slots{$in};
737 if (defined($ctype)) {
738 code "#\tdefine OP$opindex (&(stack[$depth]))\n";
739 push @macros, "OP$opindex";
745 $depth = 1 - $inslots;
746 $depth -= $stackchange if $stackdone;
748 code "#\tdefine DST (&(stack[$depth]))\n";
753 if (defined($inslots) && defined($outslots)) {
754 my $min = 1 - $inslots;
755 my $max = $outslots - $inslots;
756 $max = 0 if ($max < 0);
758 $min -= $stackchange;
759 $max -= $stackchange;
762 code "\t/* may use stack[$min] ... stack[$max] */\n";
767 code "#\tline ".$icmd->{VERIFYCODELINE}." \"".$icmd->{VERIFYCODEFILE}."\"\n";
768 code $_ for @{$icmd->{VERIFYCODE}};
769 code "#\tline ", $codeline+2, " \"", $codefilename, "\"\n";
773 ### stack manipulation code
775 if (!defined($icmd->{GOTOLABEL})) {
777 unless ($stackdone) {
778 write_verify_stackbased_stackchange($icmd);
784 code "\tgoto ", $icmd->{GOTOLABEL}, ";\n";
787 ### undef macros that were defined above
791 code "#\tundef $_\n" for @macros;
796 write_trailer($file);
799 sub write_verify_variablesbased_code
801 my ($file,$select,$codefilename) = @_;
808 print $file "#define GENERATED\n";
811 my $condition = sub { $_[0]->{STAGE} ne '--' and $_[0]->{STAGE} ne '-S' };
813 my $model_basic_types = 1;
814 my $check_basic_types = $opt_debug;
815 my $model_basic_local_types = $model_basic_types;
816 my $check_basic_local_types = ($select ne 'TYPEINFERER') || $opt_debug;
818 for my $icmdname (@icmds) {
819 my $icmd = $icmds{$icmdname};
821 next if $done{$icmdname};
822 next unless $condition->($icmd);
826 my $outvars = $icmd->{OUTVARS};
827 my $invars = $icmd->{INVARS};
828 my $outtype = $icmd->{BASICOUTTYPE};
832 ### start instruction case, group instructions with same code
836 write_icmd_cases($icmd, $select, $condition, \%done);
838 ### instruction properties
840 write_icmd_set_props($icmd);
842 ### check basic types (only in --debug mode)
844 if ($check_basic_types) {
845 if (scalar(@{$icmd->{VARIANTS}}) == 1 && defined($invars)) {
846 my $intypes = $icmd->{VARIANTS}->[0]->{IN};
847 if ($invars >= 1 && defined($cacaotypes{$intypes->[0]})) {
848 code "\tif (VAROP(IPTR->s1)->type != ".$cacaotypes{$intypes->[0]}.")\n";
849 code "\t\tVERIFY_ERROR(\"basic type mismatch\");\n";
851 if ($invars >= 2 && defined($cacaotypes{$intypes->[1]})) {
852 code "\tif (VAROP(IPTR->sx.s23.s2)->type != ".$cacaotypes{$intypes->[1]}.")\n";
853 code "\t\tVERIFY_ERROR(\"basic type mismatch\");\n";
855 if ($invars >= 3 && defined($cacaotypes{$intypes->[2]})) {
856 code "\tif (VAROP(IPTR->sx.s23.s3)->type != ".$cacaotypes{$intypes->[2]}.")\n";
857 code "\t\tVERIFY_ERROR(\"basic type mismatch\");\n";
862 ### check local types
864 if ($check_basic_local_types) {
865 if ($icmd->{DATAFLOW} eq 'LOAD') {
866 code "\tCHECK_LOCAL_TYPE(IPTR->s1.varindex, ".$cacaotypes{$outtype}.");\n";
868 elsif ($icmd->{DATAFLOW} eq 'IINC') {
869 code "\tCHECK_LOCAL_TYPE(IPTR->s1.varindex, TYPE_INT);\n";
873 ### store local types
875 if ($model_basic_local_types) {
876 if ($icmd->{DATAFLOW} eq 'STORE') {
877 my ($inslots, $type) = get_dst_slots_and_ctype($icmd, 'VAROP(iptr->s1)');
879 code "\tSTORE_LOCAL_2_WORD(".$type.", IPTR->dst.varindex);\n";
882 code "\tSTORE_LOCAL(".$type.", IPTR->dst.varindex);\n";
887 ### custom verification code
891 if ($icmd->{VERIFYCODE}) {
892 # set OP1/DST for local variables
894 if ($icmd->{DATAFLOW} eq 'LOAD') {
895 code "#\tdefine OP1 VAROP(IPTR->s1)\n";
898 elsif ($icmd->{DATAFLOW} eq 'STORE') {
899 code "#\tdefine DST VAROP(IPTR->dst)\n";
903 # model stack-action, if RESULTNOW tag was used
905 if ($icmd->{VERIFYCODEPROPS}->{RESULTNOW}) {
906 if ($model_basic_types
907 && defined($outtype) && defined($outvars) && $outvars == 1)
909 code "\tVAROP(iptr->dst)->type = ", $cacaotypes{$outtype}, ";\n";
914 # define OP1/DST for stack variables
916 if (defined($invars) && $invars >= 1) {
917 code "#\tdefine OP1 VAROP(iptr->s1)\n";
921 if (defined($outvars) && $outvars == 1) {
922 code "#\tdefine DST VAROP(iptr->dst)\n";
926 # insert the custom code
929 code "#\tline ".$icmd->{VERIFYCODELINE}." \"".$icmd->{VERIFYCODEFILE}."\"\n";
930 code $_ for @{$icmd->{VERIFYCODE}};
931 code "#\tline ", $codeline+2, " \"", $codefilename, "\"\n";
937 if (!defined($icmd->{GOTOLABEL})) {
939 unless ($resultdone) {
940 if ($model_basic_types
941 && defined($outtype) && defined($outvars) && $outvars == 1)
943 code "\tVAROP(iptr->dst)->type = ", $cacaotypes{$outtype}, ";\n";
950 code "\tgoto ", $icmd->{GOTOLABEL}, ";\n";
953 ### undef macros that were defined above
957 code "#\tundef $_\n" for @macros;
962 write_trailer($file);
969 for my $icmdname (@icmds) {
970 my $icmd = $icmds{$icmdname};
972 printf $file "/*%3d*/ {", $icmd->{OPCODE};
973 print $file 'N("', $icmd->{NAME_FILLED}, '") ';
974 defined($icmd->{DATAFLOW}) or print STDERR "$0: warning: undefined data-flow: $icmdname\n";
975 printf $file "DF_%-7s", $icmd->{DATAFLOW} || '0_TO_0';
977 printf $file "CF_%-6s", $icmd->{CONTROLFLOW} || 'NORMAL';
980 my $flags = $icmd->{FLAGS_FILLED};
985 my $stage = $icmd->{STAGE} || ' ';
989 print $file "", $icmd->{ACTION_FILLED}, "";
992 print $file "," unless $icmdname eq $icmds[-1];
1001 my ($filename) = (@_);
1004 $file = IO::File->new($filename) or die "$0: could not open file: $filename: $!\n";
1011 # check if it looks like a table line
1013 next unless /^ \s* \/\* \s* (\d+) \s* \*\/ \s* (.*) $/x;
1017 # look at this monster! ;)
1019 if (/^ \{ \s* N\( \s* \" (\w+) \s* \" \) # ICMD name --> $1
1020 \s* DF_(\w+) \s* , # data-flow --> $2
1021 \s* CF_(\w+) \s* , # control flow --> $3
1022 \s* ([^\/]*?) # the rest (flags) --> $4
1023 \s* \/\* \s* (\S+)? # stage --> $5
1024 \s* \( ([^)]*) \) # stack action --> $6
1027 \s* \} \s* ,? # closing brace and comma
1028 \s* (\/\* .* \*\/)? # optional comment
1031 my ($name, $df, $cf, $rest, $stage, $action) = ($1,$2,$3,$4,$5,$6);
1033 my $fn = 'ICMD_' . $name;
1046 $validstages{$stage} || die "$0: invalid stage: $filename:$.: $stage\n";
1047 $icmd->{STAGE} = $stage;
1050 my @flags = split /\s*\|\s*/, $rest;
1052 for my $f (@flags) {
1053 $icmd->{MAYTHROW} = 1 if $f eq 'PEI';
1054 $icmd->{CALLS} = $f if $f =~ /^(.*_)?CALLS$/;
1057 $icmds{$fn} = $icmd;
1060 die "$0: invalid ICMD table line: $filename:$.: $line";
1067 #################### main program
1069 parse_icmd_table($opt_icmdtable);
1072 parse_verify_code($VERIFY_C, 'STACKBASED');
1073 post_process_icmds();
1075 my $outfile = IO::File->new(">$TYPECHECK_STACKBASED_INC")
1076 or die "$0: could not create: $TYPECHECK_STACKBASED_INC";
1077 write_verify_stackbased_code($outfile);
1080 elsif ($opt_variables) {
1081 parse_verify_code($VERIFY_C, 'VARIABLESBASED');
1082 post_process_icmds();
1084 my $outfile = IO::File->new(">$TYPECHECK_VARIABLESBASED_INC")
1085 or die "$0: could not create: $TYPECHECK_VARIABLESBASED_INC";
1086 write_verify_variablesbased_code($outfile, 'VARIABLESBASED',
1087 $TYPECHECK_VARIABLESBASED_INC);
1090 elsif ($opt_typeinferer) {
1091 parse_verify_code($VERIFY_C, 'TYPEINFERER');
1092 post_process_icmds();
1094 my $outfile = IO::File->new(">$TYPECHECK_TYPEINFERER_INC")
1095 or die "$0: could not create: $TYPECHECK_TYPEINFERER_INC";
1096 write_verify_variablesbased_code($outfile, 'TYPEINFERER',
1097 $TYPECHECK_TYPEINFERER_INC);
1100 elsif ($opt_table) {
1101 post_process_icmds();
1102 write_icmd_table(\*STDOUT);