Attached is a patch to implement computed-goto on gcc, taken from the original post by Daniel Grunblatt: http:[EMAIL PROTECTED]/msg06255.html
Changes since his original patch: + works with the current codebase + handles all jumps properly, and passes all tests (I'm not sure, but I don't believe the original did this) + updated to reflect the precedent set by prederef in terms of naming and code conventions Note, that some of the configure.pl and makefile.in hackery is done so that this file doesn't get compiled all the time. Not sure if there's a better way to do this, as I'm not really a configure/makefile expert. Relevant mops.pasm times on this 1ghz machine: MSVC normal dispatch: 30.35 Mops/sec GCC normal dispatch: 14.61 Mops/sec GCC computed goto: 41.74 Mops/sec Enjoy, Mike Lambert
? parrot/ops2cgc.pl ? parrot/testcomputedgoto_c.in Index: parrot/.cvsignore =================================================================== RCS file: /cvs/public/parrot/.cvsignore,v retrieving revision 1.14 diff -u -r1.14 .cvsignore --- parrot/.cvsignore 8 Jan 2002 17:24:29 -0000 1.14 +++ parrot/.cvsignore 27 Mar 2002 07:50:27 -0000 @@ -1,5 +1,6 @@ blib config.opt +core_ops_cg.c core_ops.c core_ops_prederef.c Makefile Index: parrot/Configure.pl =================================================================== RCS file: /cvs/public/parrot/Configure.pl,v retrieving revision 1.101 diff -u -r1.101 Configure.pl --- parrot/Configure.pl 19 Mar 2002 22:53:57 -0000 1.101 +++ parrot/Configure.pl 27 Mar 2002 07:50:27 -0000 @@ -238,6 +238,17 @@ cp => 'cp', slash => '/', + cg_h => '$(INC)/oplib/core_ops_cg.h', + cg_c => <<'EOF', +core_ops_cg$(O): $(GENERAL_H_FILES) core_ops_cg.c + +core_ops_cg.c $(INC)/oplib/core_ops_cg.h: $(OPS_FILES) ops2cgc.pl +lib/Parrot/OpsFile.pm lib/Parrot/Op.pm + $(PERL) ops2cgc.pl CGoto $(OPS_FILES) +EOF + cg_o => 'core_ops_cg$(O)', + cg_r => '$(RM_F) $(INC)/oplib/core_ops_cg.h core_ops_cg.c', + cg_flag => '-DHAVE_COMPUTED_GOTO', + VERSION => $parrot_version, MAJOR => $parrot_version[0], MINOR => $parrot_version[1], @@ -690,6 +701,32 @@ unlink("include/parrot/vtable.h"); } + +# and now test if we can use computed goto +print <<"END"; + +Still everything ok, let's check if we can use computed goto, +don't worry if you see some errors, it will be all right, +This could take a bit... +END + +{ + buildfile("testcomputedgoto_c"); + my $test = system("$c{cc} $c{ccflags} -o testcomputedgoto$c{exe} +testcomputedgoto.c"); + + if ($test != 0) { + $c{"cg_h"}=''; + $c{"cg_c"}=''; + $c{"cg_o"}=''; + $c{"cg_r"}=''; + $c{"cg_flag"}=''; + } + + unlink('testcomputedgoto.c', "testcomputedgoto$c{exe}", "testcomputedgoto$c{o}"); +} + +# rewrite the Makefile with the updated info +buildfile("Makefile"); # # Rewrite the config file with the updated info Index: parrot/MANIFEST =================================================================== RCS file: /cvs/public/parrot/MANIFEST,v retrieving revision 1.133 diff -u -r1.133 MANIFEST --- parrot/MANIFEST 24 Mar 2002 21:10:49 -0000 1.133 +++ parrot/MANIFEST 27 Mar 2002 07:50:27 -0000 @@ -246,6 +246,7 @@ misc.c obscure.ops ops2c.pl +ops2cgc.pl ops2pm.pl optimizer.pl packdump.c @@ -292,6 +293,7 @@ test_c.in test_gnuc.c test_main.c +testcomputedgoto_c.in testparrotfuncptr.c testparrotsizes_c.in trace.c Index: parrot/MANIFEST.SKIP =================================================================== RCS file: /cvs/public/parrot/MANIFEST.SKIP,v retrieving revision 1.2 diff -u -r1.2 MANIFEST.SKIP --- parrot/MANIFEST.SKIP 21 Mar 2002 23:39:49 -0000 1.2 +++ parrot/MANIFEST.SKIP 27 Mar 2002 07:50:27 -0000 @@ -16,6 +16,7 @@ ^include/parrot/jit_struct\.h$ ^include/parrot/oplib/core_ops\.h$ ^include/parrot/oplib/core_ops_prederef\.h$ +^include/parrot/oplib/core_ops_cg\.h$ ^core_ops\.c$ ^core_ops_prederef\.c$ Index: parrot/Makefile.in =================================================================== RCS file: /cvs/public/parrot/Makefile.in,v retrieving revision 1.141 diff -u -r1.141 Makefile.in --- parrot/Makefile.in 21 Mar 2002 23:47:22 -0000 1.141 +++ parrot/Makefile.in 27 Mar 2002 07:50:27 -0000 @@ -65,7 +65,7 @@ $(INC)/memory.h $(INC)/parrot.h $(INC)/stacks.h $(INC)/packfile.h \ $(INC)/global_setup.h $(INC)/vtable.h $(INC)/oplib/core_ops.h \ $(INC)/oplib/core_ops_prederef.h $(INC)/runops_cores.h $(INC)/trace.h \ -$(INC)/pmc.h $(INC)/key.h $(INC)/resources.h $(INC)/platform.h \ +$(INC)/pmc.h $(INC)/key.h $(INC)/resources.h $(INC)/platform.h ${cg_h} \ $(INC)/interp_guts.h ${jit_h} $(INC)/rx.h $(INC)/rxstacks.h \ $(INC)/embed.h $(INC)/warnings.h $(INC)/misc.h @@ -87,7 +87,7 @@ core_ops$(O) core_ops_prederef$(O) memory$(O) packfile$(O) stacks$(O) \ string$(O) encoding$(O) chartype$(O) runops_cores$(O) trace$(O) pmc$(O) key$(O) \ platform$(O) ${jit_o} resources$(O) rx$(O) rxstacks$(O) embed$(O) warnings$(O) \ -misc$(O) +misc$(O) ${cg_o} O_FILES = $(INTERP_O_FILES) $(IO_O_FILES) $(CLASS_O_FILES) $(ENCODING_O_FILES) $(CHARTYPE_O_FILES) @@ -103,7 +103,7 @@ # ############################################################################### -CFLAGS = ${ccflags} ${cc_warn} ${cc_debug} ${cc_inc} ${cc_hasjit} +CFLAGS = ${ccflags} ${cc_warn} ${cc_debug} ${cc_inc} ${cc_hasjit} ${cg_flag} LDFLAGS = ${ldflags} ${ld_debug} C_LIBS = ${libs} @@ -352,6 +352,8 @@ core_ops_prederef.c $(INC)/oplib/core_ops_prederef.h: $(OPS_FILES) ops2c.pl lib/Parrot/OpsFile.pm lib/Parrot/Op.pm $(PERL) ops2c.pl CPrederef $(OPS_FILES) +${cg_c} + warnings$(O): $(H_FILES) misc$(O): $(H_FILES) @@ -422,6 +424,7 @@ ############################################################################### clean: testclean + ${cg_r} $(RM_F) $(O_FILES) $(RM_F) *.s $(RM_F) $(FLUID_FILES) Index: parrot/core.ops =================================================================== RCS file: /cvs/public/parrot/core.ops,v retrieving revision 1.113 diff -u -r1.113 core.ops --- parrot/core.ops 22 Mar 2002 20:24:02 -0000 1.113 +++ parrot/core.ops 27 Mar 2002 07:50:28 -0000 @@ -572,6 +572,7 @@ =cut inline op set_keyed (out PMC, in PMC, in PMC, in PMC) { +/* KEY_PAIR src_key_p, dest_key_p; KEY src_key, dest_key; @@ -580,6 +581,7 @@ $1->vtable->set_pmc_keyed(interpreter, $1, $2 ? &src_key : NULL, $3, $4 ? &dest_key : NULL); +*/ goto NEXT(); } Index: parrot/interpreter.c =================================================================== RCS file: /cvs/public/parrot/interpreter.c,v retrieving revision 1.80 diff -u -r1.80 interpreter.c --- parrot/interpreter.c 16 Mar 2002 17:38:45 -0000 1.80 +++ parrot/interpreter.c 27 Mar 2002 07:50:29 -0000 @@ -17,6 +17,9 @@ #ifdef HAS_JIT # include "parrot/jit.h" #endif +#ifdef HAVE_COMPUTED_GOTO +# include "parrot/oplib/core_cg_ops.h" +#endif /*=for api interpreter check_fingerprint Index: parrot/pbc2c.pl =================================================================== RCS file: /cvs/public/parrot/pbc2c.pl,v retrieving revision 1.20 diff -u -r1.20 pbc2c.pl --- parrot/pbc2c.pl 19 Mar 2002 23:23:30 -0000 1.20 +++ parrot/pbc2c.pl 27 Mar 2002 07:50:29 -0000 @@ -77,7 +77,7 @@ sub compile_byte_code { my ($pf, $file_name) = @_; my ($byte_code); - my $pc; + my $pc = 1; my $new_pc = 0; my $offset=0; my $op_code; @@ -104,14 +104,14 @@ # of control flow changing opcodes including the possible targets of ret # opcodes while ($offset + sizeof('op') <= $length) { - my ($src, $is_branch); + my ($src, $is_branch); $pc = $new_pc; - $op_code = unpack "x$offset l", $pf->byte_code; + $op_code = unpack "x$offset l", $pf->byte_code; $op = $ops->op($op_code) || die "Can't find an op for opcode $op_code\n"; - $offset += sizeof('op'); - push @pc_list, $pc; - $opcodes{$pc}->{op} = $op; + $offset += sizeof('op'); + push @pc_list, $pc; + $opcodes{$pc}->{op} = $op; $new_pc = $pc + $op->size; @args = (); @@ -123,53 +123,52 @@ $offset += sizeof('op'); push @args, $arg; } - push @{$opcodes{$pc}->{args}}, @args; + push @{$opcodes{$pc}->{args}}, @args; $src = $op->full_body(); - # The regexes here correspond to the rewriting rules for the various - # forms of goto recognized by Parrot/OpsFile.pm and Parrot/Op.pm + # The regexes here correspond to the rewriting rules for the various + # forms of goto recognized by Parrot/OpsFile.pm and Parrot/Op.pm - # absolute address goto - while($src =~ /{{=(.*?)}}/g){ - my $offset = $1; - $is_branch = 1; - } - # relative branch - while($src =~ /{{(\-|\+)=(.*?)}}/g){ - my $dir = $1; - my $forward_off = $2; - - # Substitute constant branch values - if($forward_off =~ /\@(\d+)/){ - $forward_off = $args[$1 - 1] - if $op->arg_type($1) eq 'ic'; - } - - if($forward_off =~ /^-?\d+$/){ - $forward_off = -$forward_off if $dir eq '-'; - - if($forward_off != $op->size){ - $leaders{$forward_off + $pc} = 1; - $is_branch = 1; - } - } - else { - $is_branch = 1; - } - } + # absolute address goto + while($src =~ /{{=(.*?)}}/g){ + my $offset = $1; + $is_branch = 1; + } + # relative branch + while($src =~ /{{(\-|\+)=(.*?)}}/g){ + my $dir = $1; + my $forward_off = $2; + + # Substitute constant branch values + if($forward_off =~ /\@(\d+)/){ + $forward_off = $args[$1 - 1] if $op->arg_type($1) eq 'ic'; + } + + if($forward_off =~ /^-?\d+$/){ + $forward_off = -$forward_off if $dir eq '-'; + + if($forward_off != $op->size){ + $leaders{$forward_off + $pc} = 1; + $is_branch = 1; + } + } + else { + $is_branch = 1; + } + } - $leaders{$new_pc} = 1 if $is_branch; + $leaders{$new_pc} = 1 if $is_branch; } my $enternative; FINDENTERN: foreach my $cur_op (@$Parrot::OpLib::core::ops) { - if($cur_op->full_name eq 'enternative'){ - $enternative = pack_op($cur_op->code); - last FINDENTERN; - } + if($cur_op->full_name eq 'enternative'){ + $enternative = pack_op($cur_op->code); + last FINDENTERN; + } } die "Could not locate enternative op!\n" unless defined $enternative; @@ -183,15 +182,15 @@ substr($byte_code, 0, sizeof('op')) = $enternative; while (@pc_list) { - my $instr_pc = shift @pc_list; - # block leader found, start new block - if(exists $leaders{$instr_pc}) { - substr($byte_code, $instr_pc, sizeof('op')) = $enternative; - push @blocks, [$instr_pc ]; - } - else { - push @{$blocks[-1]}, $instr_pc; - } + my $instr_pc = shift @pc_list; + # block leader found, start new block + if(exists $leaders{$instr_pc}) { + substr($byte_code, $instr_pc, sizeof('op')) = $enternative; + push @blocks, [$instr_pc ]; + } + else { + push @{$blocks[-1]}, $instr_pc; + } } print<<END_C; @@ -207,9 +206,9 @@ $offset = 0; while($offset < length($byte_code)){ - print join(',', unpack("c*", substr($byte_code, $offset, 20))); - print ",\n"; - $offset += 20; + print join(',', unpack("c*", substr($byte_code, $offset, 20))); + print ",\n"; + $offset += 20; } print "};"; @@ -217,6 +216,7 @@ int main(int argc, char **argv) { + int cur_opcode; struct Parrot_Interp * interpreter; struct PackFile * pf; @@ -228,8 +228,8 @@ if( !PackFile_unpack(interpreter, pf, program_code, (opcode_t)sizeof(program_code)) ) { - printf( "Can't unpack.\n" ); - return 1; + printf( "Can't unpack.\n" ); + return 1; } interpreter->code = pf; runops(interpreter, pf, 0); Index: parrot/runops_cores.c =================================================================== RCS file: /cvs/public/parrot/runops_cores.c,v retrieving revision 1.14 diff -u -r1.14 runops_cores.c --- parrot/runops_cores.c 5 Mar 2002 05:17:14 -0000 1.14 +++ parrot/runops_cores.c 27 Mar 2002 07:50:30 -0000 @@ -15,6 +15,10 @@ #include "parrot/interp_guts.h" +#ifdef HAVE_COMPUTED_GOTO +# include "parrot/oplib/core_ops_cg.h" +#endif + /*=for api interpreter runops_fast_core * run parrot operations until the program is complete * @@ -26,9 +30,13 @@ opcode_t * runops_fast_core(struct Parrot_Interp *interpreter, opcode_t *pc) { +#ifdef HAVE_COMPUTED_GOTO + pc = cg_core(pc, interpreter); +#else while (pc) { DO_OP(pc, interpreter); } +#endif return pc; } Index: parrot/include/parrot/oplib/.cvsignore =================================================================== RCS file: /cvs/public/parrot/include/parrot/oplib/.cvsignore,v retrieving revision 1.3 diff -u -r1.3 .cvsignore --- parrot/include/parrot/oplib/.cvsignore 13 Dec 2001 12:12:45 -0000 1.3 +++ parrot/include/parrot/oplib/.cvsignore 27 Mar 2002 07:50:30 -0000 @@ -1,2 +1,3 @@ *_ops.h *_ops_prederef.h +*_ops_cg.h Index: parrot/lib/Parrot/OpTrans/CGoto.pm =================================================================== RCS file: /cvs/public/parrot/lib/Parrot/OpTrans/CGoto.pm,v retrieving revision 1.6 diff -u -r1.6 CGoto.pm --- parrot/lib/Parrot/OpTrans/CGoto.pm 16 Feb 2002 04:38:18 -0000 1.6 +++ parrot/lib/Parrot/OpTrans/CGoto.pm 27 Mar 2002 07:50:30 -0000 @@ -16,6 +16,7 @@ sub defines { return <<END; +#define REL_PC ((size_t)(cur_opcode - interpreter->code->byte_code)) #define CUR_OPCODE cur_opcode END } @@ -75,13 +76,17 @@ { my ($self, $addr) = @_; #print STDERR "pbcc: map_ret_abs($addr)\n"; - return "cur_opcode = $addr;\ngoto switch_label"; + if ($addr eq '0') { + return "return (0);" + } else { + return "goto *ops_addr[*(cur_opcode = $addr)]"; + } } sub expr_offset { my ($self, $offset) = @_; - return sprintf("&&PC_%d", $self->pc + $offset); + return "cur_opcode + $offset"; } # @@ -91,12 +96,7 @@ sub goto_offset { my ($self, $offset) = @_; - if ($offset =~ /^-?\d+$/) { - return sprintf("goto PC_%d", $self->pc + $offset); - } else { - return sprintf("cur_opcode = &&PC_%d; cur_opcode += %s; goto switch_label", $self->pc, $offset); - } -#print STDERR "pbcc: map_ret_rel($offset)\n"; + return "goto *ops_addr[*(cur_opcode += $offset)]"; } @@ -107,7 +107,7 @@ sub goto_pop { my ($self) = @_; - return "goto *pop_dest(interpreter)"; + return "opcode_t* pop_addr = (opcode_t*)pop_dest(interpreter);\ncur_opcode = +pop_addr;goto *ops_addr[*(pop_addr)]"; } # @@ -115,22 +115,26 @@ # my %arg_maps = ( - 'i' => "interpreter->int_reg.registers[%ld]", - 'n' => "interpreter->num_reg.registers[%ld]", - 'p' => "interpreter->pmc_reg.registers[%ld]", - 's' => "interpreter->string_reg.registers[%ld]", + 'op' => "cur_opcode[%ld]", + + 'i' => "interpreter->int_reg.registers[cur_opcode[%ld]]", + 'n' => "interpreter->num_reg.registers[cur_opcode[%ld]]", + 'p' => "interpreter->pmc_reg.registers[cur_opcode[%ld]]", + 's' => "interpreter->string_reg.registers[cur_opcode[%ld]]", - 'ic' => "%ld", - 'nc' => "interpreter->code->const_table->constants[%ld]->number", + 'ic' => "cur_opcode[%ld]", + 'nc' => "interpreter->code->const_table->constants[cur_opcode[%ld]]->number", 'pc' => "%ld /* ERROR: Don't know how to handle PMC constants yet! */", - 'sc' => "interpreter->code->const_table->constants[%ld]->string", + 'sc' => "interpreter->code->const_table->constants[cur_opcode[%ld]]->string", ); sub access_arg { my ($self, $type, $num, $op) = @_; #print STDERR "pbcc: map_arg($type, $num)\n"; - return sprintf($arg_maps{$type}, $self->arg($num - 1)); + die "Unrecognized type '$type' for num '$num'" unless exists $arg_maps{$type}; + + return sprintf($arg_maps{$type}, $num ); } @@ -141,7 +145,7 @@ sub restart_address { my ($self, $addr) = @_; - die "pbc2c.pl: Cannot handle RESUME ops!"; + return "interpreter->resume_offset = $addr; interpreter->resume_flag = 1"; } @@ -152,9 +156,8 @@ sub restart_offset { my ($self, $offset) = @_; - die "pbc2c.pl: Cannot handle RESUME ops!"; + return "interpreter->resume_offset = REL_PC + $offset; interpreter->resume_flag = +1"; } - 1;
/* * testcomputedgoto.c - figure out if we can use computed goto * * This file is automatically generated by Configure * from testcomputedgoto_c.in. */ int main(int argc, char **argv) { static void *ptr = &&LABEL; int a; goto *ptr; LABEL: { a = 1; } return 0; }
ops2cgc.pl
Description: ops2cgc.pl