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
40 #################### options
45 my $opt_variables = 0;
46 my $opt_typeinferer = 0;
50 my $usage = <<"END_USAGE";
52 $0 --icmdtable FILE { --table | --stack | --variables | --typeinferer } [--debug]
55 --icmdtable FILE read ICMD table from FILE
56 --table print ICMD table
57 --stack generate stackbased verifier
58 --variables generate variablesbased verifier
59 --typeinferer generate the type inference pass
60 --debug generate additional debugging code
62 Please specify exactly one of --table, --stack, --variables, or --typeinferer.
66 my $result = GetOptions("icmdtable=s" => \$opt_icmdtable,
67 "table" => \$opt_table,
68 "stack" => \$opt_stack,
69 "variables" => \$opt_variables,
70 "typeinferer" => \$opt_typeinferer,
71 "debug" => \$opt_debug,
72 "help|h|?" => \$opt_help,
75 $result or die "$0: invalid options\n";
82 if (!defined($opt_icmdtable)
83 || ($opt_table + $opt_stack + $opt_variables + $opt_typeinferer != 1))
89 #################### constants
91 my $VERIFY_C = 'src/vm/jit/verify/icmds.c';
92 my $TYPECHECK_STACKBASED_INC = 'src/vm/jit/verify/typecheck-stackbased-gen.inc';
93 my $TYPECHECK_VARIABLESBASED_INC = 'src/vm/jit/verify/typecheck-variablesbased-gen.inc';
94 my $TYPECHECK_TYPEINFERER_INC = 'src/vm/jit/verify/typecheck-typeinferer-gen.inc';
98 my @basictypes = qw(A I F L D R); # XXX remove R?
99 my %basictypes = map { $_ => 1 } @basictypes;
109 R => 1, # XXX remove?
118 R => 'TYPE_RET', # XXX remove?
121 my @superblockend = qw(END GOTO JSR RET TABLE LOOKUP);
122 my %superblockend = map { $_ => 1 } @superblockend;
124 my @validstages = qw( -- -S S+ );
125 my %validstages = map { $_ => 1 } @validstages;
127 my @valid_tags = qw(STACKBASED VARIABLESBASED TYPEINFERER);
128 my @default_tags = qw(STACKBASED VARIABLESBASED);
130 my %valid_tag = map { $_ => 1 } @valid_tags;
132 #################### global variables
141 #################### subs
143 sub parse_verify_code
145 my ($filename, $select) = @_;
147 my $file = IO::File->new($filename) or die "$0: could not open: $filename";
153 last if /^\s*\/\*\s*{START_OF_CODE}\s*\*\/\s*$/;
157 last if /^\s*\/\*\s*{END_OF_CODE}\s*\*\/\s*$/;
160 unless (/^case \s+ (\w+) \s* :
161 \s* ( \/\* \s* {\s* (\w+ (\s*,\s* \w+)*) \s*} \s* \*\/ )?
164 die "$0: invalid case line: $filename:$.: $_";
166 my ($n, $unused, $tags) = ($1, $2, $3 || '');
168 my @tags = split /\s*,\s*/, $tags;
170 if (@tags == 1 && $tags[0] eq 'ALL') {
173 @tags = @default_tags unless @tags;
175 defined($icmds{$n}) or die "$0: unknown ICMD: $filename:$.: $_";
179 for my $tag (@tags) {
180 $valid_tag{$tag} or die "$0: invalid tag: $filename:$.: $tag";
182 $ignore = 0 if $tag eq $select;
189 if (defined($icmd)) {
190 $code = $icmd->{VERIFYCODE};
191 $codeprops = $icmd->{VERIFYCODEPROPS};
195 $icmd->{VERIFYCODE} = $code;
196 $icmd->{VERIFYCODELINE} = $. + 1;
197 $icmd->{VERIFYCODEFILE} = $filename;
198 $icmd->{VERIFYCODEPROPS} = $codeprops;
202 if (/^\s*break\s*;\s*$/
203 || /^\s*goto\s+(\w+)\s*;\s*$/)
208 elsif (defined($icmd)) {
209 if (/^\s*break\s*;\s*$/) {
212 elsif (/^\s*goto\s+(\w+)\s*;\s*$/) {
213 $icmd->{GOTOLABEL} = $1;
217 if (/\{RESULTNOW\}/) {
218 $codeprops->{RESULTNOW} = 1;
221 if (/\S/ || scalar @{$icmd->{VERIFYCODE}} != 0) {
222 push @{$icmd->{VERIFYCODE}}, $_;
228 next if /^\s*\/\*.*\*\/\s*$/;
230 die "$0: cannot handle code line outside case: $filename:$.: $_";
237 my ($str, $len) = @_;
239 return $str . (' ' x ($len - length($str)));
244 my ($flags, $name) = @_;
246 if ($$flags eq '0') {
250 $$flags .= '|'.$name;
256 my ($icmd,$key,$default) = @_;
258 $default = "\0" unless defined($default);
260 return (defined($icmd->{$key})) ? ":$key:".($icmd->{$key})
266 my ($icmd,$key,$traits) = @_;
268 $traits = $key . ':' . $traits;
270 $icmd->{$key} = $traits;
271 push @{$icmdtraits{$traits}}, $icmd;
274 sub post_process_icmds
279 my $maxfullnamelen = 0;
280 my $maxactionlen = 0;
283 for my $icmdname (@icmds) {
284 my $icmd = $icmds{$icmdname};
287 my $action = $icmd->{ACTION};
288 my @variants = split (/\s*\|\s*/, $action);
290 $icmd->{VARIANTS} = [];
292 for my $v (@variants) {
293 $v =~ /^(.*?)\s*--\s*(.*)$/ or die "invalid action: $_";
294 my ($in, $out) = ($1, $2);
299 @in = split /\s*/, $in;
305 @out = split /\s*/, $out;
308 @out = split //, $out;
310 my $invars = scalar @in;
311 my $outvars = scalar @out;
314 push @{$icmd->{VARIANTS}}, $var;
319 $icmd->{INVARS} = $invars;
320 $icmd->{OUTVARS} = $outvars;
325 my $slots = $slots{$_};
326 defined($slots) or undef $inslots, last;
330 my $slots = $slots{$_};
331 defined($slots) or undef $outslots, last;
335 $var->{INSLOTS} = $inslots;
336 $var->{OUTSLOTS} = $outslots;
338 if (defined($inslots)) {
339 if (!defined($icmd->{MININSLOTS}) || $inslots < $icmd->{MININSLOTS}) {
340 $icmd->{MININSLOTS} = $inslots;
343 if (exists $icmd->{INSLOTS}) {
344 if ($icmd->{INSLOTS} != $inslots) {
345 $icmd->{INSLOTS} = undef;
349 $icmd->{INSLOTS} = $inslots;
353 $icmd->{INSLOTS} = undef;
354 $icmd->{MININSLOTS} = undef;
357 if (defined($outslots)) {
358 if (exists $icmd->{OUTSLOTS}) {
359 if (defined($icmd->{OUTSLOTS}) && $icmd->{OUTSLOTS} != $outslots) {
360 $icmd->{OUTSLOTS} = undef;
364 $icmd->{OUTSLOTS} = $outslots;
368 $icmd->{OUTSLOTS} = undef;
371 if ($outvars == 0 || $outvars == 1) {
372 my $df = $invars . '_TO_' . $outvars;
373 if (defined($icmd->{DATAFLOW})) {
374 if ($icmd->{DATAFLOW} =~ /^\d_TO_\d$/) {
375 $icmd->{DATAFLOW} eq $df
376 or die "$0: dataflow not consistent with action: "
377 .$icmd->{FULLNAME}."\n";
381 $icmd->{DATAFLOW} = $df;
386 if ($basictypes{$out[0]}) {
387 $icmd->{BASICOUTTYPE} = $out[0];
391 $icmd->{ACTION} =~ s/\s//g;
394 $maxfullnamelen = length($icmdname) if length($icmdname) > $maxfullnamelen;
395 $maxnamelen = length($icmd->{NAME}) if length($icmd->{NAME}) > $maxnamelen;
396 $maxactionlen = length($icmd->{ACTION}) if length($icmd->{ACTION}) > $maxactionlen;
400 $icmd->{STAGE} = ' ' unless defined($icmd->{STAGE});
402 if ($icmdname =~ /^(.*)CONST$/ && defined($icmds{$1})) {
403 $parent = $icmds{$1};
406 if (!defined($icmd->{DATAFLOW}) && defined($parent)) {
407 if ($parent->{DATAFLOW} =~ /(\d)_TO_(\d)/) {
408 $1 >= 0 or die "$0: cannot derive data-flow: $icmdname from ".$parent->{FULLNAME};
409 $icmd->{DATAFLOW} = ($1-1).'_TO_'.$2;
413 if (!defined($icmd->{BASICOUTTYPE}) && defined($parent)) {
414 $icmd->{BASICOUTTYPE} = $parent->{BASICOUTTYPE};
417 if (defined($icmd->{INSLOTS}) && defined($icmd->{OUTSLOTS})) {
418 $icmd->{STACKCHANGE} = $icmd->{OUTSLOTS} - $icmd->{INSLOTS};
422 add_flag(\$flags, 'PEI') if $icmd->{MAYTHROW};
423 add_flag(\$flags, $icmd->{CALLS}) if $icmd->{CALLS};
425 $icmd->{FLAGS} = $flags;
427 $maxflagslen = length($flags) if length($flags) > $maxflagslen;
429 ### calculate traits for building equivalence classes of ICMDs
431 # traits used in all cases
432 my $commontraits = trait($icmd, 'CONTROLFLOW')
433 . trait($icmd, 'MAYTHROW', 0)
434 . trait($icmd, 'VERIFYCODE');
436 # traits that completely define the kind of dataflow
437 my $datatraits = trait($icmd, 'DATAFLOW')
438 . trait($icmd, 'ACTION');
440 # traits defining the output type
442 if ($icmd->{DATAFLOW} =~ /^\d_TO_\d$/) {
443 $outputtraits = trait($icmd, 'OUTVARS')
444 . trait($icmd, 'BASICOUTTYPE');
447 $outputtraits = $datatraits;
450 # traits used by the stack-based verifier
451 my $traits = $commontraits
453 set_icmd_traits($icmd, 'STACKBASED', $traits);
455 # traits used by the variables-based verifier
456 $traits = $commontraits
457 . ($opt_debug ? $datatraits : $outputtraits);
458 set_icmd_traits($icmd, 'VARIABLESBASED', $traits);
460 # traits used by the type inference pass
461 $traits = $commontraits
462 . ($opt_debug ? $datatraits : $outputtraits);
463 set_icmd_traits($icmd, 'TYPEINFERER', $traits);
467 $maxactionlen = $maxmax if $maxactionlen > $maxmax;
469 for my $icmdname (@icmds) {
470 my $icmd = $icmds{$icmdname};
472 $icmd->{FULLNAME_FILLED} = fill($icmd->{FULLNAME}, $maxfullnamelen);
473 $icmd->{NAME_FILLED} = fill($icmd->{NAME}, $maxnamelen);
474 $icmd->{ACTION_FILLED} = fill("(".$icmd->{ACTION}.")", $maxactionlen+2);
475 $icmd->{FLAGS_FILLED} = fill($icmd->{FLAGS}, $maxflagslen);
481 my $text = join '', @_;
483 $text =~ s/\n/\n GENERATED /g;
484 $text =~ s/^#/\n# /g;
486 my $newlines = () = $text =~ /\n/g;
488 print $codefile $text;
489 $codeline += $newlines;
492 sub write_verify_stackbased_stackchange
496 my $outslots = $icmd->{OUTSLOTS};
497 my $inslots = $icmd->{INSLOTS};
498 my $outtype = $icmd->{BASICOUTTYPE};
499 my $stackchange = $icmd->{STACKCHANGE};
503 if (defined($inslots) && defined($outslots)) {
505 ### modify stack pointer and write destination type
507 if ($stackchange != 0) {
508 code "\tstack += ", $stackchange, ";\n";
511 if (defined($icmd->{VARIANTS}) && scalar @{$icmd->{VARIANTS}} == 1) {
512 my $var = $icmd->{VARIANTS}->[0];
514 if (defined($outtype)) {
515 if ($outslots && ($inslots < $outslots || $var->{IN}->[0] ne $outtype)) {
516 if ($outslots == 1) {
517 code "\tstack[0].type = ", $cacaotypes{$outtype}, ";\n";
520 elsif ($outslots == 2) {
521 code "\tstack[0].type = TYPE_VOID;\n";
522 code "\tstack[-1].type = ", $cacaotypes{$outtype}, ";\n";
535 my ($icmd, $traits, $condition, $done) = @_;
537 code "case ", $icmd->{FULLNAME}, ":\n";
539 my $eqgroup = $icmdtraits{$icmd->{$traits}};
540 my @actions = ($icmd->{ACTION});
542 for my $ocmd (@$eqgroup) {
543 next unless $condition->($ocmd);
544 if ($ocmd->{FULLNAME} ne $icmd->{FULLNAME}) {
545 code "case ", $ocmd->{FULLNAME}, ":\n";
546 $done->{$ocmd->{FULLNAME}}++;
548 unless (grep { $_ eq $ocmd->{ACTION} } @actions) {
549 push @actions, $ocmd->{ACTION};
554 code "\t/* ", join(", ", map { "($_)" } @actions), " */\n";
557 sub write_icmd_set_props
561 if ($icmd->{MAYTHROW}) {
562 code "\tmaythrow = true;\n";
564 if ($superblockend{$icmd->{CONTROLFLOW}}) {
565 code "\tsuperblockend = true;\n";
573 print $file "\n#undef GENERATED\n";
574 print $file "/* vim:filetype=c:\n";
578 sub get_dst_slots_and_ctype
580 my ($icmd, $op1) = @_;
584 for my $v (@{$icmd->{VARIANTS}}) {
585 my $intype = $v->{IN}->[0];
586 if (defined($inslots) && $inslots != $slots{$intype}) {
587 die "$0: error: mixed slotsize for STORE is not supported: ".$icmd->{NAME};
590 $inslots = $slots{$intype};
593 if (defined($type) && $type ne $cacaotypes{$intype}) {
594 $type = "$op1->type";
597 $type = $cacaotypes{$intype};
601 return ($inslots, $type);
604 sub write_verify_stackbased_code
612 my $codefilename = $TYPECHECK_STACKBASED_INC;
614 print $file "#define GENERATED\n";
617 my $condition = sub { $_[0]->{STAGE} ne '--' and $_[0]->{STAGE} ne 'S+' };
619 for my $icmdname (@icmds) {
620 my $icmd = $icmds{$icmdname};
622 next if $done{$icmdname};
623 next unless $condition->($icmd);
627 my $outslots = $icmd->{OUTSLOTS};
628 my $inslots = $icmd->{INSLOTS};
629 my $outtype = $icmd->{BASICOUTTYPE};
630 my $stackchange = $icmd->{STACKCHANGE};
634 ### start instruction case, group instructions with same code
637 write_icmd_cases($icmd, 'STACKBASED', $condition, \%done);
639 ### instruction properties
641 write_icmd_set_props($icmd);
643 ### check stackdepth and stack types
645 if (defined($inslots) && $inslots > 0) {
646 code "\tCHECK_STACK_DEPTH($inslots);\n";
648 elsif (!defined($inslots)) {
649 code "\t/* variable number of inslots! */\n";
652 if (defined($stackchange) && $stackchange > 0) {
653 code "\tCHECK_STACK_SPACE(", $stackchange, ");\n";
655 elsif (!defined($outslots)) {
656 code "\t/* variable number of outslots! */\n";
659 if (defined($inslots) && defined($outslots) && defined($icmd->{VARIANTS})
660 && scalar @{$icmd->{VARIANTS}} == 1)
662 my $var = $icmd->{VARIANTS}->[0];
664 my $depth = 1 - $inslots;
666 for my $in (@{$var->{IN}}) {
667 my $ctype = $cacaotypes{$in};
668 my $slots = $slots{$in};
669 if (defined($ctype)) {
670 code "\tCHECK_STACK_TYPE(stack[$depth], $ctype);\n";
677 ### check/store local types
679 my $prohibit_stackchange = 0;
681 if ($icmd->{DATAFLOW} eq 'LOAD') {
682 code "\tCHECK_LOCAL_TYPE(IPTR->s1.varindex, ".$cacaotypes{$outtype}.");\n";
683 if ($icmd->{VERIFYCODE}) {
684 code "#\tdefine OP1 LOCAL_SLOT(IPTR->s1.varindex)\n";
688 elsif ($icmd->{DATAFLOW} eq 'IINC') {
689 code "\tCHECK_LOCAL_TYPE(IPTR->s1.varindex, TYPE_INT);\n";
691 elsif ($icmd->{DATAFLOW} eq 'STORE') {
692 my ($inslots, $type) = get_dst_slots_and_ctype($icmd, 'OP1');
693 if ($type =~ /OP1/) {
694 code "#\tdefine OP1 (&(stack[".(1-$inslots)."]))\n";
696 $prohibit_stackchange = 1;
699 code "\tSTORE_LOCAL_2_WORD(".$type.", IPTR->dst.varindex);\n";
702 code "\tSTORE_LOCAL(".$type.", IPTR->dst.varindex);\n";
704 if ($icmd->{VERIFYCODE}) {
705 code "#\tdefine DST LOCAL_SLOT(IPTR->dst.varindex)\n";
710 ### custom verification code
714 if ($icmd->{VERIFYCODE}) {
715 if ($icmd->{VERIFYCODEPROPS}->{RESULTNOW}) {
716 if ($prohibit_stackchange) {
717 die "$0: prohibited stack change before custom code: ".$icmd->{NAME};
719 if (write_verify_stackbased_stackchange($icmd)) {
720 code "\t/* CAUTION: stack types changed before custom code! */\n";
723 code "\t/* CAUTION: stack pointer changed before custom code! */\n";
728 if (defined($inslots) && defined($outslots) && defined($icmd->{VARIANTS})
729 && scalar @{$icmd->{VARIANTS}} == 1)
731 my $var = $icmd->{VARIANTS}->[0];
733 my $depth = 1 - $inslots;
734 $depth -= $stackchange if $stackdone;
736 for my $in (@{$var->{IN}}) {
737 my $ctype = $cacaotypes{$in};
738 my $slots = $slots{$in};
739 if (defined($ctype)) {
740 code "#\tdefine OP$opindex (&(stack[$depth]))\n";
741 push @macros, "OP$opindex";
747 $depth = 1 - $inslots;
748 $depth -= $stackchange if $stackdone;
750 code "#\tdefine DST (&(stack[$depth]))\n";
755 if (defined($inslots) && defined($outslots)) {
756 my $min = 1 - $inslots;
757 my $max = $outslots - $inslots;
758 $max = 0 if ($max < 0);
760 $min -= $stackchange;
761 $max -= $stackchange;
764 code "\t/* may use stack[$min] ... stack[$max] */\n";
769 code "#\tline ".$icmd->{VERIFYCODELINE}." \"".$icmd->{VERIFYCODEFILE}."\"\n";
770 code $_ for @{$icmd->{VERIFYCODE}};
771 code "#\tline ", $codeline+2, " \"", $codefilename, "\"\n";
775 ### stack manipulation code
777 if (!defined($icmd->{GOTOLABEL})) {
779 unless ($stackdone) {
780 write_verify_stackbased_stackchange($icmd);
786 code "\tgoto ", $icmd->{GOTOLABEL}, ";\n";
789 ### undef macros that were defined above
793 code "#\tundef $_\n" for @macros;
798 write_trailer($file);
801 sub write_verify_variablesbased_code
803 my ($file,$select,$codefilename) = @_;
810 print $file "#define GENERATED\n";
813 my $condition = sub { $_[0]->{STAGE} ne '--' and $_[0]->{STAGE} ne '-S' };
815 my $model_basic_types = 1;
816 my $check_basic_types = $opt_debug;
817 my $model_basic_local_types = $model_basic_types;
818 my $check_basic_local_types = ($select ne 'TYPEINFERER') || $opt_debug;
820 for my $icmdname (@icmds) {
821 my $icmd = $icmds{$icmdname};
823 next if $done{$icmdname};
824 next unless $condition->($icmd);
828 my $outvars = $icmd->{OUTVARS};
829 my $invars = $icmd->{INVARS};
830 my $outtype = $icmd->{BASICOUTTYPE};
834 ### start instruction case, group instructions with same code
838 write_icmd_cases($icmd, $select, $condition, \%done);
840 ### instruction properties
842 write_icmd_set_props($icmd);
844 ### check basic types (only in --debug mode)
846 if ($check_basic_types) {
847 if (scalar(@{$icmd->{VARIANTS}}) == 1 && defined($invars)) {
848 my $intypes = $icmd->{VARIANTS}->[0]->{IN};
849 if ($invars >= 1 && defined($cacaotypes{$intypes->[0]})) {
850 code "\tif (VAROP(IPTR->s1)->type != ".$cacaotypes{$intypes->[0]}.")\n";
851 code "\t\tVERIFY_ERROR(\"basic type mismatch\");\n";
853 if ($invars >= 2 && defined($cacaotypes{$intypes->[1]})) {
854 code "\tif (VAROP(IPTR->sx.s23.s2)->type != ".$cacaotypes{$intypes->[1]}.")\n";
855 code "\t\tVERIFY_ERROR(\"basic type mismatch\");\n";
857 if ($invars >= 3 && defined($cacaotypes{$intypes->[2]})) {
858 code "\tif (VAROP(IPTR->sx.s23.s3)->type != ".$cacaotypes{$intypes->[2]}.")\n";
859 code "\t\tVERIFY_ERROR(\"basic type mismatch\");\n";
864 ### check local types
866 if ($check_basic_local_types) {
867 if ($icmd->{DATAFLOW} eq 'LOAD') {
868 code "\tCHECK_LOCAL_TYPE(IPTR->s1.varindex, ".$cacaotypes{$outtype}.");\n";
870 elsif ($icmd->{DATAFLOW} eq 'IINC') {
871 code "\tCHECK_LOCAL_TYPE(IPTR->s1.varindex, TYPE_INT);\n";
875 ### store local types
877 if ($model_basic_local_types) {
878 if ($icmd->{DATAFLOW} eq 'STORE') {
879 my ($inslots, $type) = get_dst_slots_and_ctype($icmd, 'VAROP(iptr->s1)');
881 code "\tSTORE_LOCAL_2_WORD(".$type.", IPTR->dst.varindex);\n";
884 code "\tSTORE_LOCAL(".$type.", IPTR->dst.varindex);\n";
889 ### custom verification code
893 if ($icmd->{VERIFYCODE}) {
894 # set OP1/DST for local variables
896 if ($icmd->{DATAFLOW} eq 'LOAD') {
897 code "#\tdefine OP1 VAROP(IPTR->s1)\n";
900 elsif ($icmd->{DATAFLOW} eq 'STORE') {
901 code "#\tdefine DST VAROP(IPTR->dst)\n";
905 # model stack-action, if RESULTNOW tag was used
907 if ($icmd->{VERIFYCODEPROPS}->{RESULTNOW}) {
908 if ($model_basic_types
909 && defined($outtype) && defined($outvars) && $outvars == 1)
911 code "\tVAROP(iptr->dst)->type = ", $cacaotypes{$outtype}, ";\n";
916 # define OP1/DST for stack variables
918 if (defined($invars) && $invars >= 1) {
919 code "#\tdefine OP1 VAROP(iptr->s1)\n";
923 if (defined($outvars) && $outvars == 1) {
924 code "#\tdefine DST VAROP(iptr->dst)\n";
928 # insert the custom code
931 code "#\tline ".$icmd->{VERIFYCODELINE}." \"".$icmd->{VERIFYCODEFILE}."\"\n";
932 code $_ for @{$icmd->{VERIFYCODE}};
933 code "#\tline ", $codeline+2, " \"", $codefilename, "\"\n";
939 if (!defined($icmd->{GOTOLABEL})) {
941 unless ($resultdone) {
942 if ($model_basic_types
943 && defined($outtype) && defined($outvars) && $outvars == 1)
945 code "\tVAROP(iptr->dst)->type = ", $cacaotypes{$outtype}, ";\n";
952 code "\tgoto ", $icmd->{GOTOLABEL}, ";\n";
955 ### undef macros that were defined above
959 code "#\tundef $_\n" for @macros;
964 write_trailer($file);
971 for my $icmdname (@icmds) {
972 my $icmd = $icmds{$icmdname};
974 printf $file "/*%3d*/ {", $icmd->{OPCODE};
975 print $file 'N("', $icmd->{NAME_FILLED}, '") ';
976 defined($icmd->{DATAFLOW}) or print STDERR "$0: warning: undefined data-flow: $icmdname\n";
977 printf $file "DF_%-7s", $icmd->{DATAFLOW} || '0_TO_0';
979 printf $file "CF_%-6s", $icmd->{CONTROLFLOW} || 'NORMAL';
982 my $flags = $icmd->{FLAGS_FILLED};
987 my $stage = $icmd->{STAGE} || ' ';
991 print $file "", $icmd->{ACTION_FILLED}, "";
994 print $file "," unless $icmdname eq $icmds[-1];
1001 sub parse_icmd_table
1003 my ($filename) = (@_);
1006 $file = IO::File->new($filename) or die "$0: could not open file: $filename: $!\n";
1013 # check if it looks like a table line
1015 next unless /^ \s* \/\* \s* (\d+) \s* \*\/ \s* (.*) $/x;
1019 # look at this monster! ;)
1021 if (/^ \{ \s* N\( \s* \" (\w+) \s* \" \) # ICMD name --> $1
1022 \s* DF_(\w+) \s* , # data-flow --> $2
1023 \s* CF_(\w+) \s* , # control flow --> $3
1024 \s* ([^\/]*?) # the rest (flags) --> $4
1025 \s* \/\* \s* (\S+)? # stage --> $5
1026 \s* \( ([^)]*) \) # stack action --> $6
1029 \s* \} \s* ,? # closing brace and comma
1030 \s* (\/\* .* \*\/)? # optional comment
1033 my ($name, $df, $cf, $rest, $stage, $action) = ($1,$2,$3,$4,$5,$6);
1035 my $fn = 'ICMD_' . $name;
1048 $validstages{$stage} || die "$0: invalid stage: $filename:$.: $stage\n";
1049 $icmd->{STAGE} = $stage;
1052 my @flags = split /\s*\|\s*/, $rest;
1054 for my $f (@flags) {
1055 $icmd->{MAYTHROW} = 1 if $f eq 'PEI';
1056 $icmd->{CALLS} = $f if $f =~ /^(.*_)?CALLS$/;
1059 $icmds{$fn} = $icmd;
1062 die "$0: invalid ICMD table line: $filename:$.: $line";
1069 #################### main program
1071 parse_icmd_table($opt_icmdtable);
1074 parse_verify_code($VERIFY_C, 'STACKBASED');
1075 post_process_icmds();
1077 my $outfile = IO::File->new(">$TYPECHECK_STACKBASED_INC")
1078 or die "$0: could not create: $TYPECHECK_STACKBASED_INC";
1079 write_verify_stackbased_code($outfile);
1082 elsif ($opt_variables) {
1083 parse_verify_code($VERIFY_C, 'VARIABLESBASED');
1084 post_process_icmds();
1086 my $outfile = IO::File->new(">$TYPECHECK_VARIABLESBASED_INC")
1087 or die "$0: could not create: $TYPECHECK_VARIABLESBASED_INC";
1088 write_verify_variablesbased_code($outfile, 'VARIABLESBASED',
1089 $TYPECHECK_VARIABLESBASED_INC);
1092 elsif ($opt_typeinferer) {
1093 parse_verify_code($VERIFY_C, 'TYPEINFERER');
1094 post_process_icmds();
1096 my $outfile = IO::File->new(">$TYPECHECK_TYPEINFERER_INC")
1097 or die "$0: could not create: $TYPECHECK_TYPEINFERER_INC";
1098 write_verify_variablesbased_code($outfile, 'TYPEINFERER',
1099 $TYPECHECK_TYPEINFERER_INC);
1102 elsif ($opt_table) {
1103 post_process_icmds();
1104 write_icmd_table(\*STDOUT);