All: Here's a list of the things I've been doing: * Added ops2cgc.pl which generates core_cg_ops.c and core_cg_ops.h from core.ops, and modified Makefile.in to use it. In core_cg_ops.c resides cg_core which has an array with the addresses of the label of each opcode and starts the execution "jumping" to the address in array[*cur_opcode].
* Modified interpreter.c to include core_cg_ops.h * Modified runcore_ops.c to discard the actual dispatching method and call cg_core, but left everything else untouched so that -b,-p and -t keep working. * Modified pbc2c.pl to use computed goto when handling jump or ret, may be I can modified this once again not to define the array with the addresses if it's not going to be used but I don't think that in real life a program won't use jump or ret, am I right? Hope some one find this usefull. Actual dispatcher: #./test_prog examples/assembly/mops.pbc Iterations: 100000000 Estimated ops: 300000000 Elapsed time: 22.642827 M op/s: 13.249229 Actual dispatcher -O3: #./test_prog examples/assembly/mops.pbc Iterations: 100000000 Estimated ops: 300000000 Elapsed time: 14.651587 M op/s: 20.475598 With this patch: #./test_prog examples/assembly/mops.pbc Iterations: 100000000 Estimated ops: 300000000 Elapsed time: 8.398673 M op/s: 35.719929 With this patch and -O3: #./test_prog examples/assembly/mops.pbc Iterations: 100000000 Estimated ops: 300000000 Elapsed time: 4.554578 M op/s: 65.867792 With -O3: #./mops Iterations: 100000000 Estimated ops: 300000000 Elapsed time: 1.023564 M op/s: 293.093515 #java -Xint mops Iterations: 100000000 Estimated ops: 300000000 Elapsed time: 9.705000042915344 M op/s: 30.911900945224637 Daniel Grunblatt.
Index: Makefile.in =================================================================== RCS file: /home/perlcvs/parrot/Makefile.in,v retrieving revision 1.43 diff -u -r1.43 Makefile.in --- Makefile.in 2001/11/02 12:11:15 1.43 +++ Makefile.in 2001/11/04 01:05:01 @@ -8,14 +8,15 @@ $(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)/runops_cores.h $(INC)/trace.h $(INC)/oplib/vtable_ops.h \ -$(INC)/pmc.h $(INC)/resources.h $(INC)/platform.h +$(INC)/pmc.h $(INC)/resources.h $(INC)/platform.h $(INC)/oplib/core_cg_ops.h + O_FILES = global_setup$(O) interpreter$(O) parrot$(O) register$(O) \ core_ops$(O) memory$(O) packfile$(O) stacks$(O) string$(O) encoding$(O) \ chartype$(O) runops_cores$(O) trace$(O) vtable_ops$(O) classes/intclass$(O) \ encodings/singlebyte$(O) encodings/utf8$(O) encodings/utf16$(O) \ encodings/utf32$(O) chartypes/unicode$(O) chartypes/usascii$(O) resources$(O) \ -platform$(O) +platform$(O) core_cg_ops$(O) #DO NOT ADD C COMPILER FLAGS HERE #Add them in Configure.pl--look for the @@ -101,6 +102,11 @@ stacks$(O): $(H_FILES) +core_cg_ops$(O): $(H_FILES) core_ops.c + +core_cg_ops.c $(INC)/oplib/core_cg_ops.h: core.ops ops2cgc.pl + $(PERL) ops2cgc.pl core.ops + core_ops$(O): $(H_FILES) core_ops.c core_ops.c $(INC)/oplib/core_ops.h: core.ops ops2c.pl @@ -130,8 +136,9 @@ cd docs; make clean: - $(RM_F) *$(O) *.s core_ops.c $(TEST_PROG) $(PDISASM) $(PDUMP) + $(RM_F) *$(O) *.s core_cg_ops.c core_ops.c $(TEST_PROG) $(PDISASM) $(PDUMP) $(RM_F) $(INC)/vtable.h + $(RM_F) $(INC)/oplib/core_cg_ops.h $(RM_F) $(INC)/oplib/core_ops.h $(RM_F) $(INC)/oplib/vtable_ops.h vtable_ops.c vtable.ops $(RM_F) $(TEST_PROG) $(PDISASM) $(PDUMP) Index: interpreter.c =================================================================== RCS file: /home/perlcvs/parrot/interpreter.c,v retrieving revision 1.33 diff -u -r1.33 interpreter.c --- interpreter.c 2001/10/26 18:58:02 1.33 +++ interpreter.c 2001/11/04 01:05:01 @@ -13,6 +13,7 @@ #include "parrot/parrot.h" #include "parrot/interp_guts.h" #include "parrot/oplib/core_ops.h" +#include "parrot/oplib/core_cg_ops.h" #include "parrot/runops_cores.h" Index: pbc2c.pl =================================================================== RCS file: /home/perlcvs/parrot/pbc2c.pl,v retrieving revision 1.3 diff -u -r1.3 pbc2c.pl --- pbc2c.pl 2001/10/24 13:03:42 1.3 +++ pbc2c.pl 2001/11/04 01:05:02 @@ -65,9 +65,11 @@ # compile_byte_code() # -my $pc; +my $pc = 1; +my $op; my $new_pc = 1; my @args = (); +my @pcs = (); sub compile_byte_code { my ($pf) = @_; @@ -85,11 +87,59 @@ int main(int argc, char **argv) { - int i; + int cur_opcode; struct Parrot_Interp * interpreter; struct PackFile_Constant * c; struct PackFile * pf; +END_C + my $cursor = 0; + my $length = length($pf->byte_code); + + my $offset=0; + + my $op_code; + my @addr; + my @source; + + while ($offset + sizeof('op') <= $length) { + foreach ($pc..$new_pc-2) { + push @addr, " NULL,\n"; + } + $pc = $new_pc; + push @addr, " &&PC_$pc,\n"; + $op_code = unpack "x$offset l", $pf->byte_code; + $op = $ops->op($op_code); + $offset += sizeof('op'); + $new_pc = $pc + $op->size; + + @args = (); + foreach (1 .. scalar($op->arg_types) - 1) { + die "$0: Premature end of bytecode in argument.\n" + if ($offset + sizeof('op')) > $length; + my $arg = unpack "x$offset l", $pf->byte_code; + $offset += sizeof('op'); + push @args, $arg; + } + + my $source = $op->source(\&map_ret_abs, \&map_ret_rel, \&map_arg, +\&map_res_abs, \&map_res_rel); + if ($source =~ m/cur_opcode/) { + $source =~ s/cur_opcode \+ (\d+)/(opcode_t *)(cur_opcode + $1)/g; + $source = "cur_opcode = " . $pc . ";\n" . $source; + } + push @source, sprintf("PC_%d: /* %s */\n{\n%s}\n\n", $pc, $op->full_name, +$source); + } + + print <<END_C; + static void *pc_l[] = { + &&PC_0, +END_C + + print @addr; + print <<END_C; + NULL + }; + init_world(); interpreter = make_interpreter(); @@ -98,7 +148,6 @@ interpreter->code = pf; END_C - for(my $i = 0; $i < $nconst; $i++) { my $const = $pf->const_table->constant($i); my $value = $const->value; @@ -133,43 +182,15 @@ END_C } - my $cursor = 0; - my $length = length($pf->byte_code); - - my $offset=0; - - my $op_code; - my $op; - - while ($offset + sizeof('op') <= $length) { - $pc = $new_pc; - $op_code = unpack "x$offset l", $pf->byte_code; - $op = $ops->op($op_code); - $offset += sizeof('op'); - $new_pc = $pc + $op->size; - - @args = (); - - foreach (1 .. scalar($op->arg_types) - 1) { - die "$0: Premature end of bytecode in argument.\n" - if ($offset + sizeof('op')) > $length; - my $arg = unpack "x$offset l", $pf->byte_code; - $offset += sizeof('op'); - push @args, $arg; - } - my $source = $op->source(\&map_ret_abs, \&map_ret_rel, \&map_arg, \&map_res_abs, \&map_res_rel); - - printf("PC_%d: { /* %s */\n%s}\n\n", $pc, $op->full_name, $source); - } - + print @source; print <<END_C; - -PC_$new_pc: PC_0: { exit(0); } + + return 0; } END_C @@ -186,7 +207,11 @@ { my ($addr) = @_; #print STDERR "pbcc: map_ret_abs($addr)\n"; - return sprintf("goto PC_%d", $addr); + if ($op->full_name eq 'ret') { + return sprintf("goto *pc_l[(int)dest]"); + } else { + return sprintf("goto PC_%d", $addr); + } } @@ -198,7 +223,11 @@ { my ($offset) = @_; #print STDERR "pbcc: map_ret_rel($offset)\n"; - return sprintf("goto PC_%d", $pc + $offset); + if ($op->full_name eq 'jump_i') { + return sprintf("goto *pc_l[" . $pc . "+" . $offset . "]"); + } else { + return sprintf("goto PC_%d", $pc + $offset); + } } Index: runops_cores.c =================================================================== RCS file: /home/perlcvs/parrot/runops_cores.c,v retrieving revision 1.2 diff -u -r1.2 runops_cores.c --- runops_cores.c 2001/10/19 01:43:00 1.2 +++ runops_cores.c 2001/11/04 01:05:02 @@ -36,7 +36,7 @@ opcode_t * runops_t0p0b0_core (struct Parrot_Interp *interpreter, opcode_t * pc) { - while (pc) { DO_OP(pc, interpreter); } + cg_core(pc, interpreter); return pc; }
#! /usr/bin/perl -w # # ops2cgc.pl # # Generate a C header and source file from the operation definitions in # an .ops file. # use strict; use Parrot::OpsFile; # # Process command-line argument: # if (@ARGV != 1) { die "ops2cgc.pl: usage: perl ops2cgc.pl input.ops\n"; } my $file = $ARGV[0]; my $base = $file; $base =~ s/\.ops$//; my $incdir = "include/parrot/oplib"; my $include = "parrot/oplib/${base}_cg_ops.h"; my $header = "include/$include"; my $source = "${base}_cg_ops.c"; # # Read the input file: # my $ops = new Parrot::OpsFile $file; die "ops2cgc.pl: Could not read ops file '$file'!\n" unless $ops; my $num_ops = scalar $ops->ops; my $num_entries = $num_ops + 1; # For trailing NULL # # Open the output files: # if (! -d $incdir) { mkdir($incdir, 0755) or die "ops2cgc.pl: Could not mkdir $incdir $!!\n"; } open HEADER, ">$header" or die "ops2cgc.pl: Could not open header file '$header' for writing: $!!\n"; open SOURCE, ">$source" or die "ops2cgc.pl: Could not open source file '$source' for writing: $!!\n"; # # Print the preamble for the HEADER and SOURCE files: # my $preamble = <<END_C; /* ** !!!!!!! DO NOT EDIT THIS FILE !!!!!!! ** ** This file is generated automatically from '$file'. ** Any changes made here will be lost! */ END_C print HEADER $preamble; print HEADER <<END_C; #include "parrot/parrot.h" opcode_t *cg_core(opcode_t *, struct Parrot_Interp *); END_C print SOURCE $preamble; print SOURCE <<END_C; #include "$include" opcode_t * cg_core(opcode_t *cur_opcode, struct Parrot_Interp *interpreter) { static void *ops_addr[] = { END_C # # Iterate over the ops, appending SOURCE fragments: # my @op_source; my $index = 0; foreach my $op ($ops->ops) { my $definition = "PC_$index:"; my $source = $op->source(\&map_cg_abs, \&map_cg_rel, \&map_arg, \&map_res_abs, \&map_res_rel); print SOURCE " &&PC_" . $index++ . ",\n"; push @op_source, "$definition /* " . $op->func_name . " */\n{\n$source}\n\n"; } # # Finish the array and stat the execution: # print SOURCE <<END_C; NULL }; goto *ops_addr[*cur_opcode]; END_C # # Dump the source: # print SOURCE @op_source; print SOURCE <<END_C; }; END_C # # map_cg_abs() # sub map_cg_abs { my ($addr) = @_; if ($addr eq '0') { return "return (0);" } else { return "goto *ops_addr[*(cur_opcode = $addr)]"; } } # # map_cg_rel() # sub map_cg_rel { my ($offset) = @_; return "goto *ops_addr[*(cur_opcode += $offset)]"; } # # map_arg() # sub map_arg { my ($type, $num) = @_; my %arg_maps = ( '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' => "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[cur_opcode[%ld]]->string", ); die "Unrecognized type '$type' for num '$num'" unless exists $arg_maps{$type}; return sprintf($arg_maps{$type}, $num); } # # map_res_rel() # sub map_res_rel { my ($offset) = @_; return "interpreter->resume_addr = cur_opcode + $offset"; } # # map_res_abs() # sub map_res_abs { my ($addr) = @_; return "interpreter->resume_addr = $addr"; }