Ok, this is a big one. Over 500 line diff, plus a new module
for parrot/Parrot.

This patch adds a prompt to Configure.pl to allow the choice
of DO_OP() as a function dereference (current behavior) or
as a C switch() statement.

Current up until Gregor applied 2 of Bryan's patches this evening.
I hope they don't mess it up, as I haven't the energy tonight
to do more. :-(

This patchset gave the following, when run with options for
function dereference ( the current mode ), and the switch()

[ SuSE linux x86 750Mhz Athlon, 256MB RAM ]
Normal:

Iterations: 100000000
Start time: 1002505053
End time: 1002505082
Count: 100000000
Elapsed time:29
Estimated ops:300000000
Estimated ops (numerically):300000000.000000
Elapsed time:29
Elapsed time:29.000000
Ops/sec:10344827.586207

Switched:

Iterations: 100000000
Start time: 1002507616
End time: 1002507639
Count: 100000000
Elapsed time:23
Estimated ops:300000000
Estimated ops (numerically):300000000.000000
Elapsed time:23
Elapsed time:23.000000
Ops/sec:13043478.260870


and courtesy of Mr. Schwern (debian on PowerPC, I believe)

Normal:

Iterations: 100000000
Start time: 1002507775
End time: 1002507838
Count: 100000000
Elapsed time:63
Estimated ops:300000000
Estimated ops (numerically):300000000.000000
Elapsed time:63
Elapsed time:63.000000
Ops/sec:4761904.761905


Switched:

Iterations: 100000000
Start time: 1002508550
End time: 1002508596
Count: 100000000
Elapsed time:46
Estimated ops:300000000
Estimated ops (numerically):300000000.000000
Elapsed time:46
Elapsed time:46.000000
Ops/sec:6521739.130435

------------------------------------------------------------------

Questions, comments, criticisms?

Cheers.

-- 
Michael Fischer                         7.5 million years to run
[EMAIL PROTECTED]                        printf "%d", 0x2a;
                                                -- deep thought 
diff -ru parrot/Configure.pl parrot-switched/Configure.pl
--- parrot/Configure.pl Thu Oct  4 16:19:38 2001
+++ parrot-switched/Configure.pl        Sun Oct  7 21:59:27 2001
@@ -85,6 +85,7 @@
        perl =>                 $^X,
        debugging =>    $opt_debugging,
        rm_f =>         'rm -f',
+       do_op_t =>      'switch',
 );
 
 #copy the things from --define foo=bar
@@ -108,6 +109,7 @@
 prompt("How big would you like integers to be?", 'iv');
 prompt("And your floats?", 'nv');
 prompt("What is your native opcode type?", 'opcode_t');
+prompt("Opcode dispatch by switch or function ('switch' or 'func')", 'do_op_t');
 
 unless( $c{debugging} ) {
        $c{ld_debug} = ' ';
diff -ru parrot/MANIFEST parrot-switched/MANIFEST
--- parrot/MANIFEST     Sat Oct  6 08:41:57 2001
+++ parrot-switched/MANIFEST    Sun Oct  7 21:59:35 2001
@@ -14,6 +14,7 @@
 Parrot/String.pm
 Parrot/Test.pm
 Parrot/Vtable.pm
+Parrot/PPP.pm
 Test/More.pm
 Test/Simple.pm
 Test/Utils.pm
diff -ru parrot/Makefile.in parrot-switched/Makefile.in
--- parrot/Makefile.in  Sun Oct  7 10:41:18 2001
+++ parrot-switched/Makefile.in Sun Oct  7 21:59:35 2001
@@ -18,6 +18,7 @@
 PERL = ${perl}
 TEST_PROG = test_prog${exe}
 PDUMP = pdump${exe}
+DO_OP_T = ${do_op_t}
 
 .c$(O):
        $(CC) $(CFLAGS) -o $@ -c $<
@@ -31,7 +32,7 @@
 
 $(TEST_PROG): test_main$(O) $(O_FILES) interp_guts$(O) op_info$(O)
        $(CC) $(CFLAGS) -o $(TEST_PROG) $(O_FILES) interp_guts$(O) op_info$(O) 
test_main$(O) $(C_LIBS)
-       
+
 $(PDUMP): pdump$(O) packfile$(O) memory$(O) global_setup$(O) string$(O) strnative$(O)
        $(CC) $(CFLAGS) -o $(PDUMP) pdump$(O) packfile$(O) memory$(O) global_setup$(O) 
string$(O) strnative$(O) $(C_LIBS)
 
@@ -44,7 +45,7 @@
 strnative$(O): $(H_FILES)
 
 $(INC)/interp_guts.h interp_guts.c $(INC)/op_info.h op_info.c: opcode_table 
build_interp_starter.pl
-       $(PERL) build_interp_starter.pl
+       $(PERL) build_interp_starter.pl -t $(DO_OP_T)
 
 interpreter$(O): interpreter.c $(H_FILES) $(INC)/interp_guts.h
 
@@ -59,7 +60,7 @@
 basic_opcodes$(O): $(H_FILES) basic_opcodes.c
 
 basic_opcodes.c: basic_opcodes.ops process_opfunc.pl $(INC)/interp_guts.h
-       $(PERL) process_opfunc.pl basic_opcodes.ops
+       $(PERL) process_opfunc.pl > basic_opcodes.c
 
 $(INC)/op.h: opcode_table make_op_header.pl
        $(PERL) make_op_header.pl opcode_table > $(INC)/op.h
Only in parrot-switched/Parrot: PPP.pm
diff -ru parrot/basic_opcodes.ops parrot-switched/basic_opcodes.ops
--- parrot/basic_opcodes.ops    Sun Oct  7 11:27:42 2001
+++ parrot-switched/basic_opcodes.ops   Sun Oct  7 21:59:35 2001
@@ -1,11 +1,3 @@
-/* basic_opcodes.c
- *
- * Just some basic opcodes
- *
- */
-
-#include "parrot/parrot.h"
-#include <math.h>
 
 /* SET Ix, CONSTANT */
 AUTO_OP set_i_ic {
diff -ru parrot/build_interp_starter.pl parrot-switched/build_interp_starter.pl
--- parrot/build_interp_starter.pl      Sun Oct  7 20:46:15 2001
+++ parrot-switched/build_interp_starter.pl     Sun Oct  7 21:59:35 2001
@@ -7,6 +7,16 @@
 
 use strict;
 use Parrot::Opcode;
+use Parrot::PPP;
+
+use Getopt::Std;
+
+use vars qw($opt_t);
+getopts('t:');
+
+die "You didn't specifiy how you want DO_OP written!\n
+Use the -t ['func' | 'switch' ] flag, please\n"
+unless $opt_t eq 'func' or $opt_t eq 'switch';
 
 my %opcodes            = Parrot::Opcode::read_ops();
 my $opcode_fingerprint = Parrot::Opcode::fingerprint();
@@ -37,7 +47,10 @@
 
 extern op_func_table_t builtin_op_func_table;
 
+CONST
 
+if ($opt_t eq 'func') {
+    print INTERP_GUTS_H <<EOI;
 /*
  * DO_OP macro:
  *
@@ -46,11 +59,20 @@
  */
 
 #define DO_OP(PC,INTERP) PC = ((INTERP->opcode_funcs)[*PC])(PC,INTERP);
+EOI
+}
+elsif ( $opt_t eq 'switch' ) {
+        print INTERP_GUTS_H Parrot::PPP::opcode_enum(%opcodes);
+        print INTERP_GUTS_H Parrot::PPP::process_opcodes($opt_t, %opcodes);
+}
+
+print INTERP_GUTS_H <<EOII;
+
 #define OPCODE_FINGERPRINT "$opcode_fingerprint"
 
 #endif /* INTERP_GUTS_H */
+EOII
 
-CONST
 
 
 ###############################################################################
diff -ru parrot/include/parrot/parrot.h parrot-switched/include/parrot/parrot.h
--- parrot/include/parrot/parrot.h      Sat Oct  6 08:41:58 2001
+++ parrot-switched/include/parrot/parrot.h     Sun Oct  7 21:59:57 2001
@@ -25,6 +25,7 @@
 #include <stdio.h>
 /*#include <types.h> */
 #include <time.h>
+#include <math.h>
 
 #ifdef WIN32
 #      include <io.h>
diff -ru parrot/process_opfunc.pl parrot-switched/process_opfunc.pl
--- parrot/process_opfunc.pl    Sun Oct  7 11:27:42 2001
+++ parrot-switched/process_opfunc.pl   Sun Oct  7 21:59:35 2001
@@ -1,120 +1,24 @@
-#! perl -w
-#
-# process_opfunc.pl
-#
-# Take a file of opcode functions and emit real C code for them
-#
-# opcode functions are in the format:
-#
-#  AUTO_OP opname {
-#
-#   ... body of function ...
-#
-#  }
-#
-# Where the closing brace is on its own line. Alternately, for opcode
-# functions that manage their own return values:
-#
-# MANUAL_OP opname {
-#
-#    ... body of function ...
-#
-#    RETURN(x);
-#
-# }
-#
-# There may be more than one RETURN
-#
-# The functions have the magic variables Pnnn for parameters 1 through
-# X. (Parameter 0 is the opcode number) Types for each, and the size
-# of the return offset, are taken from the opcode_table file
-
+#!/usr/bin/perl -w 
 use strict;
+
+use Parrot::PPP;
 use Parrot::Opcode;
 use Parrot::Config;
 use Parrot::Types;
 
-my %opcodes = Parrot::Opcode::read_ops();
-
-my $orig = my $file = $ARGV[0];
-open INPUT, $file or die "Can't open $file, $!/$^E";
-if (! ($file =~ s/\.ops$/.c/)) {
-    $file .= ".c";
-}
-open OUTPUT, ">$file" or die "Can't open $file, $!/$^E";
-print OUTPUT <<EOF;
-/* !!!!!!!   DO NOT EDIT THIS FILE   !!!!!!!
-   This file is built by $orig from its data.  Any changes made here
-   will be lost!
-*/
-
 
-EOF
-
-
-my($name, $footer, @param_sub);
-while (<INPUT>) {
-
-    if (/^AUTO_OP/) {
-       ($name, $footer) = emit_auto_header($_);
-    }
-
-    if (/^MANUAL_OP/) {
-       ($name, $footer) = emit_manual_header($_);
-    }
-
-    if (/^(AUTO|MANUAL)_OP/) {
-       my $count = 1;
-       @param_sub = ("",
-           map { "cur_opcode[" . $count++ . "]" } @{$opcodes{$name}{TYPES}});
-       next;
-    }
-
-    s/RETVAL/return_offset/;
-
-    s/RETURN\(0\);/return 0;/;
-
-    s/RETURN\((.*)\)/return cur_opcode + $1/;
-    s/RESUME\((.*)\)/interpreter->resume_addr = cur_opcode + $1/;
-
-    s/\bP(\d+)\b/$param_sub[$1]/g;
-    s/INT_REG\(([^)]+)\)/interpreter->int_reg->registers[$1]/g;
-    s/STR_REG\(([^)]+)\)/interpreter->string_reg->registers[$1]/g;
-    s/PMC_REG\(([^)]+)\)/interpreter->pmc_reg->registers[$1]/g;
-    s/NUM_REG\(([^)]+)\)/interpreter->num_reg->registers[$1]/g;
-
-    s/NUM_CONST\(([^)]+)\)/interpreter->code->const_table->constants[$1]->number/g;
-    s/STR_CONST\(([^)]+)\)/interpreter->code->const_table->constants[$1]->string/g;
-    s/INT_CONST\(([^)]+)\)/$1/g;
-
-    if (/^}/) {
-        print OUTPUT $footer, "\n";
-       next;
-    }
-
-    print OUTPUT $_;
-}
-
-sub emit_auto_header {
-    my $line = shift;
-    my ($name) = $line =~ /AUTO_OP\s+(\w+)/;
-
-    my $return_offset = $opcodes{$name}{RETURN_OFFSET};
+my %opcodes = Parrot::Opcode::read_ops();
 
-    print OUTPUT ("opcode_t *$opcodes{$name}{FUNC}".
-                 "(opcode_t cur_opcode[], struct Parrot_Interp *interpreter) {\n");
-    return($name, "  return cur_opcode + " . $return_offset . ";\n}\n");
-}
+#
+# Because build_interp_starter.pl wanted most of the functionality
+# originally found in this file, almost all the code was moved
+# to Parrot::PPP.pm (ParrotPreProcessor -- sorry, best I could think of).
+# Both driver scripts really want the same input file, "basic_opcodes.ops",
+# so I hardcoded that infile there.
+# So, for simplicity, it is easier to write the outuput filename
+# of this program driver ( basic_opcodes.c ) into the Makefile.in
+# with a shell redirect '>'
+#
 
-sub emit_manual_header {
-    my $line = shift;
-    my ($name) = $line =~ /MANUAL_OP\s+(\w+)/;
-    
-    my $return_offset = $opcodes{$name}{RETURN_OFFSET};
-    
-    print OUTPUT ("opcode_t *$opcodes{$name}{FUNC}".
-                 "(opcode_t cur_opcode[], struct Parrot_Interp *interpreter) {\n");
-    print OUTPUT "  INTVAL return_offset = $return_offset;\n";
-    return($name, "  return cur_opcode + return_offset;\n}\n");
-}
+print Parrot::PPP::process_opcodes('func', %opcodes);
 
--- /dev/null   Tue Aug 22 11:27:21 2000
+++ parrot-switched/Parrot/PPP.pm       Sun Oct  7 21:59:41 2001
@@ -0,0 +1,235 @@
+package Parrot::PPP;
+use Exporter;
+@Parrot::PPP::ISA = qw(Exporter);
+@Parrot::PPP::EXPORT = qw(pprocess_opcodes opcode_enum);
+
+use strict;
+
+#
+# Parrot Pre-Processor, for lack of a better name
+#
+
+# define a sub which will
+# 1) normative circs, write out basic_opcodes.c, func defs in c.
+# 2) use the same info to write the switch() statement.
+#
+
+
+
+
+my %preliminaries = (
+                 'func' => qq|
+/* !!!!!!!   DO NOT EDIT THIS FILE   !!!!!!!
+   This file is built by basic_opcodes.ops from its data.  Any changes made here
+   will be lost!
+*/
+
+
+/* basic_opcodes.c
+ *
+ * Just some basic opcodes
+ *
+ */
+
+#include "parrot/parrot.h"
+#include <math.h>
+
+|,
+                 'switch' => qq|
+
+#define DO_OP(pc, interpreter) do { \\
+switch(*pc) { \\
+|,
+                );
+
+
+#
+# but do I want
+# interpreter->opcode_funcs[*temp]
+# ??????
+# 
+#
+#
+# pprocess_opcodes($outfile,$flag)
+#
+# Opens and loops through basic_opcodes.ops, 
+# transforms the lines for 
+# a) basic_opcodes.c -- C function definitions for the opcodes
+# b) a #define for DO_OPS() written as a C switch
+#
+# Builds a whoping $c_code string to be printed $wherever
+# by the caller
+#
+# $flag is one of 'func' or 'switch'
+#
+sub process_opcodes {
+    my ($flag, %opcodes) = @_;
+    my $c_code;
+    my $type;
+    my($name, $footer, $immediate_output,  @param_sub);
+    my $infile = "basic_opcodes.ops";
+
+    open INPUT, $infile or die "Couldn't open $infile: $!\n";
+
+    $c_code = $preliminaries{$flag};
+
+    while (<INPUT>) {
+
+       if ( $flag eq 'switch' ) {
+           chomp;
+           s|#include.*||; # we don't want them for interp_guts.h
+           s|/\*.+||; # strip C comments
+       }
+
+       if (/^AUTO_OP/) {
+           $type = 'AUTO';
+           ($name, $footer, $immediate_output) = emit_auto_header($_, $flag, 
+%opcodes);
+           $c_code .= $immediate_output;
+       }
+
+       if (/^MANUAL_OP/) {
+           $type = 'MANUAL';
+           ($name, $footer, $immediate_output) = emit_manual_header($_, $flag, 
+%opcodes);
+           $c_code .= $immediate_output;
+       }
+
+       if (/^(AUTO|MANUAL)_OP/) {
+           my $count = 1;
+           @param_sub = ("",
+                          map { $flag eq 'func'
+                                  ?  "cur_opcode[" . $count++ . "]"
+                                    : "pc[" . $count++ . "]"
+                              } @{$opcodes{$name}{TYPES}});
+           next;
+       }
+
+       if ( $flag eq 'func' ) {
+           s/RETURN\(0\);/return 0;/;
+           s/RETURN\((.*)\)/return cur_opcode + $1/;
+           s/RESUME\((.*)\)/interpreter->resume_addr = cur_opcode + $1/;
+       }
+       elsif ( $flag eq 'switch' ) {
+           s/RETURN\(0\)/pc = 0/;
+           s/RESUME\((.*)\)/interpreter->resume_addr = pc + $1/;
+           if ( $type eq 'AUTO' ) {
+               s/RETURN\((.*)\)/pc += $1/;
+           }
+           elsif ( $type eq 'MANUAL' ) {
+               s/RETURN\((.*)\);/pc += $1;  \\\n    break;  \\\n/;
+           }
+       }
+
+       s/\bP(\d+)\b/$param_sub[$1]/g;
+       s/INT_REG\(([^)]+)\)/interpreter->int_reg->registers[$1]/g;
+       s/STR_REG\(([^)]+)\)/interpreter->string_reg->registers[$1]/g;
+       s/PMC_REG\(([^)]+)\)/interpreter->pmc_reg->registers[$1]/g;
+       s/NUM_REG\(([^)]+)\)/interpreter->num_reg->registers[$1]/g;
+
+       s/NUM_CONST\(([^)]+)\)/interpreter->code->const_table->constants[$1]->number/g;
+       s/STR_CONST\(([^)]+)\)/interpreter->code->const_table->constants[$1]->string/g;
+       s/INT_CONST\(([^)]+)\)/$1/g;
+
+       if (/^}/) {
+#          $flag eq 'switch' && s/^}//;
+           my %eol = ('func' => "\n", 'switch' => "  \\\n  break;  \\\n}  \\\n");
+           $c_code .= $footer . $eol{$flag};
+           next;
+       }
+
+       if ( /\S+/ ) {
+           if ( $flag eq 'switch' ) {
+               $c_code .= "$_  \\\n";
+           }
+           else {
+               $c_code .= $_;
+           }
+       }
+       else { next; }
+    }
+    if ($flag eq 'switch') {
+       $c_code .= "} \\\n" . "} while (0);\n";
+    }
+    return $c_code;
+}
+
+
+sub emit_auto_header {
+    my ($line, $flag, %opcodes) = @_;
+    my ($name) = $line =~ /AUTO_OP\s+(\w+)/;
+
+    my $return_offset = $opcodes{$name}{RETURN_OFFSET};
+
+    my ($output, $footer);
+    if ( $flag eq 'func' ) {
+       $output = "opcode_t *$opcodes{$name}{FUNC}".
+         "(opcode_t cur_opcode[], struct Parrot_Interp *interpreter) {\n";
+       $footer = "  return cur_opcode + " . $return_offset . ";\n}\n";
+    }
+    elsif ( $flag eq 'switch' ) {
+       $output = "case $name" . "_idx:  \\\n" . "{  \\\n";
+       $footer = "  pc += " . $return_offset . ";";
+    }
+    return($name, $footer, $output);
+}
+
+sub emit_manual_header {
+    my ($line, $flag, %opcodes) = @_;
+    my ($name) = $line =~ /MANUAL_OP\s+(\w+)/;
+
+    my $return_offset = $opcodes{$name}{RETURN_OFFSET};
+
+    my ($output, $footer);
+    if ( $flag eq 'func' ) {
+       $output = "opcode_t *$opcodes{$name}{FUNC}".
+         "(opcode_t cur_opcode[], struct Parrot_Interp *interpreter) {\n";
+       $output .= "  INTVAL return_offset = $return_offset;\n";
+       $footer =  "  return cur_opcode + return_offset;\n}\n"
+    }
+    elsif ( $flag eq 'switch' ) {
+       $output = "case $name" . "_idx:  \\\n" . "{  \\\n";
+       $footer = "  pc += $return_offset;";
+        if ( $name =~ /end|jump_i|branch_ic/ ) {
+            $footer = "";
+        }
+    }
+    return($name, $footer, $output);
+}
+
+#
+# opcode_enum just something to make the switch more readable
+#
+
+#
+# stick [ print INTERP opcode_enum(); ] in build_interp_starter.pl
+#
+sub opcode_enum {
+    my ( %opcodes ) = @_;
+    my $enum = "
+
+
+/* just a convenience for legibility of the switch() in DO_OP() */
+/* the '_idx' is to prevent a namespace clash with 'Parrot_opname_foo' */
+";
+    $enum .= "enum {\n";
+    $enum .=
+      join ",\n",
+       map { "\t$_" . "_idx" }
+         sort {$opcodes{$a}{CODE} <=> $opcodes{$b}{CODE}}
+           keys %opcodes;
+
+    $enum .= "};\n\n";
+    return $enum;
+}
+
+
+"SQUAWK";
+
+=head1 NAME
+
+Parrot::PPP - routines for preprocessing basic_opcodes.ops
+into various other forms (DO_OPS() as a C switch(), basic_opcodes.c)
+
+=head1 DESCRIPTION
+
+No user-serviceable parts inside.
+

Reply via email to