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";
}

Reply via email to