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. +