All --

Here's the actual patch...

> I've updated the patch for the bytecode --> C compiler to work with
> the latest code out of CVS. I've modified Makefile so that when you
> build, it automatically assembles t/test1.pasm to t/test1.pbc, and
> automatically runs the bytecode compiler "pbcc" to produce t/test1.c,
> compiles and links the C file so that you can run t/test1. I get a
> HUGE speedup (as would be expected) on my machine.
> 
> BTW, I renamed t/test.pasm to t/test1.pasm because I wanted to name
> the final output program the same as the base name of the source file,
> and naming a program 'test' is a no-no.


Regards,

-- Gregor
 _____________________________________________________________________ 
/     perl -e 'srand(-2091643526); print chr rand 90 for (0..4)'      \

   Gregor N. Purdy                          [EMAIL PROTECTED]
   Focus Research, Inc.                http://www.focusresearch.com/
   8080 Beckett Center Drive #203                   513-860-3570 vox
   West Chester, OH 45069                           513-860-3579 fax
\_____________________________________________________________________/
? pbcc.patch
Index: MANIFEST
===================================================================
RCS file: /home/perlcvs/parrot/MANIFEST,v
retrieving revision 1.23
diff -a -u -r1.23 MANIFEST
--- MANIFEST    2001/09/30 20:25:22     1.23
+++ MANIFEST    2001/10/03 12:17:19
@@ -4,6 +4,7 @@
 Makefile.in
 Parrot/Assembler.pm
 Parrot/Opcode.pm
+Parrot/OpFunc.pm
 Parrot/PackFile.pm
 Parrot/PackFile/ConstTable.pm
 Parrot/PackFile/Constant.pm
@@ -53,6 +54,7 @@
 opcode_table
 packfile.c
 parrot.c
+pbcc
 pdump.c
 process_opfunc.pl
 register.c
@@ -71,7 +73,7 @@
 t/op/string.t
 t/op/time.t
 t/op/trans.t
-t/test.pasm
+t/test1.pasm
 t/test2.pasm
 t/test3.pasm
 test_c.in
Index: Makefile.in
===================================================================
RCS file: /home/perlcvs/parrot/Makefile.in,v
retrieving revision 1.15
diff -a -u -r1.15 Makefile.in
--- Makefile.in 2001/10/01 22:00:23     1.15
+++ Makefile.in 2001/10/03 12:17:19
@@ -22,7 +22,7 @@
 .c$(O):
        $(CC) $(CFLAGS) -o $@ -c $<
 
-all : $(TEST_PROG) $(PDUMP)
+all : $(TEST_PROG) $(PDUMP) t/test1${exe}
 
 #XXX This target is not portable to Win32
 shared: libparrot.so
@@ -35,6 +35,18 @@
 $(PDUMP): pdump$(O) $(O_FILES)
        $(CC) $(CFLAGS) -o $(PDUMP) $(O_FILES) pdump$(O) $(C_LIBS)
 
+t/test1.pbc: t/test1.pasm
+       cd t; make test1.pbc
+
+t/test1.c: t/test1.pbc
+       pbcc t/test1.pbc > t/test1.c
+
+t/test1$(O): t/test1.c
+       $(CC) -o t/test1$(O) -c -I ./include t/test1.c
+
+t/test1${exe}: t/test1$(O) $(O_FILES)
+       $(CC) $(CFLAGS) -o t/test1${exe} $(O_FILES) t/test1$(O) $(C_LIBS)
+
 test_main$(O): $(H_FILES)
 
 global_setup$(O): $(H_FILES)
@@ -75,3 +87,4 @@
 
 update:
        cvs -q update -dP
+
Index: pbcc
===================================================================
RCS file: pbcc
diff -N pbcc
--- /dev/null   Wed Oct  3 03:04:34 2001
+++ pbcc        Wed Oct  3 05:17:19 2001
@@ -0,0 +1,327 @@
+#! /usr/bin/perl -w
+#
+# compile.pl
+#
+# Turn a parrot bytecode file into text.
+#
+# Copyright (C) 2001 The Parrot Team. All rights reserved.
+# This program is free software. It is subject to the same license
+# as the Parrot interpreter.
+#
+# $Id: $
+#
+
+use strict;
+
+use Parrot::Opcode;
+use Parrot::PackFile;
+use Parrot::PackFile::ConstTable;
+use Parrot::OpFunc;
+
+use Data::Dumper;
+$Data::Dumper::Useqq  = 1;
+$Data::Dumper::Terse  = 1;
+$Data::Dumper::Indent = 0;
+
+Parrot::OpFunc->init('basic_opcodes.ops');
+
+#
+# GLOBAL VARIABLES:
+#
+
+my %unpack_type = (i => 'l',
+                  I => 'l',
+                  n => 'd',
+                  N => 'l',
+                  D => 'l',
+                  S => 'l',
+                  s => 'l',
+                  );
+my %unpack_size = (i => 4,
+                  n => 8,
+                  I => 4,
+                  N => 4,
+                  D => 4,
+                  S => 4,
+                  s => 4,
+                  );
+
+my %opcodes            = Parrot::Opcode::read_ops();
+my $opcode_fingerprint = Parrot::Opcode::fingerprint();
+my @opcodes;
+for my $name (keys %opcodes) {
+    $opcodes[$opcodes{$name}{CODE}] = { NAME => $name,
+                                       %{$opcodes{$name}} };
+}
+
+
+#
+# dump_const_table()
+#
+
+sub dump_const_table {
+    my ($pf) = @_;
+
+    my $count = $pf->const_table->const_count;
+
+    if ($count < 1) {
+       warn "Disassembling without opcode table fingerprint!";
+       return;
+    }
+
+    die "Cannot compile (differing opcode table)!"
+        if $pf->const_table->constant(0)->data ne $opcode_fingerprint;
+
+    print "# Constants: $count entries\n";
+    print "# ID  Flags    Encoding Type     Size     Data\n"; 
+
+    my $constant_num = 0;
+
+    foreach ($pf->const_table->constants) {
+        printf("%04x: %08x %08x %08x %08x %s\n",
+           $constant_num, $_->flags, $_->encoding, $_->type,
+            $_->size, $_->data);
+
+       $constant_num++;
+    }
+}
+
+
+#
+# compile_byte_code()
+#
+
+sub compile_byte_code {
+    my ($pf) = @_;
+    my $pc;
+    my $new_pc = 1;
+    my $op_size;
+
+    my $nconst = $pf->const_table->const_count;
+
+    print <<END_C;
+#include "parrot/parrot.h"
+#include "parrot/string.h"
+#include <math.h>
+
+int
+main(int argc, char **argv) {
+    int                        i;
+    struct Parrot_Interp *     interpreter;
+    struct PackFile_Constant * c;
+    struct PackFile *          pf;
+
+    init_world();
+  
+    interpreter = make_interpreter();
+    pf          = PackFile_new();
+
+    interpreter->code = pf;
+
+END_C
+
+    for(my $i = 0; $i < $nconst; $i++) {
+      my $const    = $pf->const_table->constant($i);
+
+      if      ($const->type eq Parrot::PackFile::Constant::type_code('PFC_INTEGER')) 
+{ # TODO: Don't hardocde these codes.
+        print <<END_C;
+    c = PackFile_Constant_new_integer($const->value);
+END_C
+      } elsif ($const->type eq Parrot::PackFile::Constant::type_code('PFC_NUMBER')) { 
+# TODO: Don't hardocde these codes.
+        print <<END_C;
+    c = PackFile_Constant_new_number($const->value);
+END_C
+      } elsif ($const->type eq Parrot::PackFile::Constant::type_code('PFC_STRING')) { 
+# TODO: Don't hardocde these codes.
+        my $type     = $const->value->type;
+        my $encoding = $const->value->encoding;
+        my $size     = $const->value->size;
+        my $flags    = $const->value->flags;
+        my $data     = Dumper($const->value->data);
+
+        $data = '"' . $data . '"' unless $data =~ m/^"/;
+
+        print <<END_C;
+    c = PackFile_Constant_new_string(string_make($data, $size, $encoding, $flags, 
+$type));
+END_C
+      } else {
+        die;
+      }
+
+      print <<END_C;
+    PackFile_ConstTable_push_constant(pf->const_table, c);
+
+END_C
+    }
+
+    my $cursor = 0;
+    my $length = length($pf->byte_code);
+
+    my $offset=0;
+
+    while ($offset + 4 <= $length) {
+        $pc = $new_pc;
+
+       my $op_start = $offset;
+       my $op_code = unpack "x$offset l", $pf->byte_code;
+        my $op_name = $opcodes[$op_code]{NAME};
+
+       printf "/* $opcodes[$op_code]{NAME} ";
+
+       $offset += 4;
+        $op_size = 1;
+
+       my $arg_count = $opcodes[$op_code]{ARGS};
+       my @args = ();
+        my @comment_args = ();
+
+        if ($arg_count) {
+         foreach (0 .. $arg_count - 1) {
+             my $type        = $opcodes[$op_code]{TYPES}[$_];
+             my $unpack_type = $unpack_type{$type};
+             my $unpack_size = $unpack_size{$type};
+  
+             die "$0: Premature end of bytecode in argument.\n"
+                 if ($offset + $unpack_size) > $length;
+  
+             my $arg = unpack "x$offset $unpack_type", $pf->byte_code;
+             $offset += $unpack_size;
+              $op_size += $unpack_size / 4;
+  
+             if($type =~ m/^[INPS]$/) { # Register
+                 push @args, $arg;
+                 push @comment_args, $type . $arg;
+             } elsif($type eq "D") { # destination address
+                 push @args, "$arg";
+                 push @comment_args, $arg;
+             } elsif($type eq "s") { # string constant
+                 push @args, $arg;
+                 push @comment_args, "[String $arg]";
+             } else { # constant
+                 push @args, $arg;
+                 push @comment_args, $arg;
+             }
+         }
+  
+         print join(", ", @comment_args);
+        }
+
+        print " */\n";
+
+#        print "/* OP $op_name [$op_code] */\n";
+        my $body = $op_body{$op_name};
+
+        #
+        # Map {{@N}} ==> $args[N - 1]
+        #
+
+       while ($body =~ m/{{@(\d+)}}/m) {
+          my $rep = $args[$1 - 1];
+         $body =~ s/{{@(\d+)}}/$rep/m;
+        }
+
+        #
+        # Map {{=}} ==> PC_$pc
+        #
+
+       while ($body =~ m/{{=}}/m) {
+          my $rep = "PC_$pc";
+         $body =~ s/{{=}}/$rep/m;
+        }
+
+        #
+        # Map {{+=N}} ==> PC_$new_pc (where $new_pc = $pc + N)
+        #
+
+       $body =~ s/\+=-/-=/mg;
+
+       while ($body =~ m/{{([+-])=(\d+)}}/m) {
+          my $rep = "PC_" . ($pc + "$1$2");
+         $body =~ s/{{[+-]=(\d+)}}/$rep/m;
+        }
+
+        #
+        # Map {{N}} ==> PC_N
+        #
+
+       $body =~ s/\+=-/-=/mg;
+
+       while ($body =~ m/{{(\d+)}}/m) {
+          my $rep = "PC_$1";
+         $body =~ s/{{(\d+)}}/$rep/m;
+        }
+
+        print $body;
+
+        $new_pc = $pc + $op_size;
+    }
+
+    print <<END_C;
+
+PC_$new_pc:
+PC_0: {
+    exit(0);
+}
+
+    return 0;
+}
+END_C
+
+    return 0;
+}
+
+
+#
+# compile_file()
+#
+
+sub compile_file {
+    my ($file_name) = @_;
+
+    my $pf = Parrot::PackFile->new;
+    $pf->unpack_file($file_name);
+
+#    dump_const_table($pf);
+    compile_byte_code($pf);
+ 
+    undef $pf;
+
+    return;
+}
+
+
+#
+# MAIN PROGRAM:
+#
+
+@ARGV = qw(-) unless @ARGV;
+
+foreach (@ARGV) {
+    compile_file($_)
+}
+
+exit 0;
+
+__END__
+
+=head1 NAME
+
+compile.pl - compile the byte code from Parrot Pack Files to C
+
+=head1 SYNOPSIS
+
+  perl compile.pl FILE
+
+=head1 DESCRIPTION
+
+Compile the Parrot Pack Files listed on the command line, or
+from standard input if no file is named.
+
+=head1 COPYRIGHT
+
+Copyright (C) 2001 The Parrot Team. All rights reserved.
+
+=head1 LICENSE
+
+This program is free software. It is subject to the same license
+as the Parrot interpreter.
+
Index: Parrot/OpFunc.pm
===================================================================
RCS file: OpFunc.pm
diff -N OpFunc.pm
--- /dev/null   Wed Oct  3 03:04:34 2001
+++ OpFunc.pm   Wed Oct  3 05:17:20 2001
@@ -0,0 +1,226 @@
+#! perl -w
+#
+# OpFunc.pm
+#
+# Take a file of opcode functions and create 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
+#
+
+use strict;
+
+package Parrot::OpFunc;
+
+use Parrot::Opcode;
+use Parrot::Config;
+
+BEGIN {
+    use Exporter;
+    use vars qw(%op_body @EXPORT @ISA);
+    @ISA = qw(Exporter);
+    @EXPORT = qw(%op_body);
+};
+
+
+my $current_name = '';
+my $current_body = '';
+
+my %opcodes = Parrot::Opcode::read_ops();
+my %opcode;
+my $opcode;
+
+my %psize = (i => 1,
+            n => 1,
+            I => 1,
+            N => 1,
+            D => 1,
+            S => 1,
+            s => 1,
+            );
+
+
+#
+# init()
+#
+
+sub init
+{
+  my ($class, $file) = @_;
+
+  die "Parrot::OpFunc::init(): No file specified!\n" unless defined $file;
+
+open GUTS, "include/parrot/interp_guts.h"
+  or die "Could not open include/parrot/interp_guts.h";
+while (<GUTS>) {
+    next unless /\tx\[(\d+)\] = ([a-z_]+);/;
+    $opcode{$2}{OPNUM} = $1;
+}
+
+
+
+open OPCODE, "opcode_table" or die "Can't open opcode_table, $!/$^E";
+while (<OPCODE>) {
+    s/#.*//;
+    s/^\s+//;
+    chomp;
+    next unless $_;
+
+    my ($name, $params, @params) = split /\s+/;
+    $opcode{$name}{PARAM_COUNT} = $params;
+    $opcode{$name}{PARAM_ARRAY} = \@params;
+
+    my $psize=0;
+    foreach (@params) {
+       $psize+=$psize{$_};
+    }
+
+
+    $opcode{$name}{RETURN_OFFSET} = 1 + $psize;
+    my $count = 1;
+    $opcode{$name}{PARAMETER_SUB} = ["", map { "cur_opcode[" . $count++ . "]" } 
+@params];
+}
+
+my $orig = $file;
+open INPUT, $file or die "Can't open $file, $!/$^E";
+if (! ($file =~ s/\.ops$/.c/)) {
+    $file .= ".c";
+}
+
+
+#
+# Read through the file, generating C source code:
+#
+
+my($name, $footer, @param_sub);
+while (<INPUT>) {
+    my $op_size = 1;
+
+    next if m|^\s*$|;            # Skip blank lines
+    next if m|^\s*/\*.*\*/\s*$|; # Skip comment-only lines
+
+    if (/^AUTO_OP/) {
+       ($name, $footer, $op_size) = gen_auto_header($_);
+        die unless defined $op_size;
+    }
+
+    if (/^MANUAL_OP/) {
+       ($name, $footer, $op_size) = gen_manual_header($_);
+        die unless defined $op_size;
+    }
+
+    if (/^(AUTO|MANUAL)_OP/) {
+       my $count = 1;
+       @param_sub = ("",
+                     map { "{{\@" . $count++ . "}}"; } @{$opcodes{$name}{TYPES}});
+       next;
+    }
+
+    s/RETVAL/goto {{+=$op_size}}/;
+
+    s/RETURN\(0\);/goto {{0}};/;
+
+    s/RETURN\((.*)\)/goto {{+=$1}}/;
+
+    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\(([^)]+)\)/interpreter->code->const_table->constants[$1]->string/g;
+
+    s/\bP(\d+)\b/$param_sub[$1]/g;
+
+    if (/^}/) {
+        $current_body .= "$footer\n";
+       next;
+    }
+
+    $current_body .= $_;
+}
+
+if ($current_name ne '') {
+    $op_body{$current_name} = $current_body;
+}
+
+#print "OPS:\n";
+#print join(', ', sort keys %op_body), "\n";
+
+  return;
+}
+
+
+sub gen_auto_header {
+    my ($line) = @_;
+    my ($name) = $line =~ /AUTO_OP\s+(\w+)/;
+
+    if ($current_name ne '') {
+      $op_body{$current_name} = $current_body;
+    }
+
+    $current_name = $name;
+    $current_body = '';
+
+    my $psize=0;
+    foreach (@{$opcodes{$name}{TYPES}}) {
+       $psize+=$psize{$_};
+    }
+    my $return_offset = $psize + 1;
+
+    $opcode{$name}{RETURN_OFFSET} = 1 + $psize;
+    
+    $current_body .= "{{=}}: { /* $name */\n";
+
+    return($name, "  goto {{+=$return_offset}};\n}\n", $return_offset);
+}
+
+sub gen_manual_header {
+    my ($line) = @_;
+    my ($name) = $line =~ /MANUAL_OP\s+(\w+)/;
+
+    if ($current_name ne '') {
+      $op_body{$current_name} = $current_body;
+    }
+
+    $current_name = $name;
+    $current_body = '';
+    
+    my $psize=0;
+    foreach (@{$opcodes{$name}{TYPES}}) {
+       $psize+=$psize{$_};
+    }
+    my $return_offset = $psize + 1;
+
+    $opcode{$name}{RETURN_OFFSET} = 1 + $psize;
+    
+    $current_body .= "{{=}}: { /* $name */\n";
+
+    return($name, "  goto {{+=$return_offset}};\n}\n", $return_offset);
+}
+
+1;
+
Index: Parrot/Opcode.pm
===================================================================
RCS file: /home/perlcvs/parrot/Parrot/Opcode.pm,v
retrieving revision 1.9
diff -a -u -r1.9 Opcode.pm
--- Parrot/Opcode.pm    2001/10/02 14:01:30     1.9
+++ Parrot/Opcode.pm    2001/10/03 12:17:20
@@ -115,89 +115,4 @@
 a version of parrot supporting the appropriate opcodes.
 
 =cut
-package Parrot::Opcode;
 
-use strict;
-use Symbol;
-
-sub read_ops {
-    my $file = @_ ? shift : "opcode_table";
-
-    my $fh = gensym;
-    open $fh, $file or die "$file: $!\n";
-
-    my %opcode;
-    my $count = 1;
-    while (<$fh>) {
-       s/#.*//;
-       s/^\s+//;
-       chomp;
-       next unless $_;
-
-       my($name, @params) = split /\s+/;
-       if (@params && $params[0] =~ /^\d+$/) {
-           my $count = shift @params;
-           die "$file, line $.: opcode $name parameters don't match count\n"
-             if ($count != @params);
-       }
-
-       warn "$file, line $.: opcode $name redefined\n" if $opcode{$name};
-
-       $opcode{$name}{ARGS}  = @params;
-       $opcode{$name}{TYPES} = \@params;
-       $opcode{$name}{CODE}  = ($name eq "end") ? 0 : $count++;
-       $opcode{$name}{FUNC}  = "Parrot_op_$name";
-
-       my $num_i = () = grep {/i/} @params;
-       my $num_n = () = grep {/n/} @params;
-       $opcode{$name}{RETURN_OFFSET} = 1 + $num_i + $num_n * $nvivsize;
-    }
-
-    return %opcode;
-}
-
-1;
-
-
-__END__
-
-=head1 NAME
-
-Parrot::Opcode - Read opcode definitions
-
-=head1 SYNOPSIS
-
-  use Parrot::Opcode;
-
-  %opcodes = Parrot::Opcode::read_ops();
-
-=head1 DESCRIPTION
-
-The read_ops() function parses the Parrot opcode_table file, and
-returns the contents as a hash.  The hash key is the opcode name;
-values are hashrefs containing the following fields:
-
-=over
-
-=item CODE
-
-The opcode number.
-
-=item ARGS
-
-The opcode argument count.
-
-=item TYPES
-
-The opcode argument types, as an arrayref.
-
-=item FUNC
-
-The name of the C function implementing this op.
-
-=back
-
-read_ops() takes an optional argument: the file to read the opcode table
-from.
-
-=cut
Index: t/.cvsignore
===================================================================
RCS file: /home/perlcvs/parrot/t/.cvsignore,v
retrieving revision 1.1
diff -a -u -r1.1 .cvsignore
--- t/.cvsignore        2001/09/13 07:23:59     1.1
+++ t/.cvsignore        2001/10/03 12:17:20
@@ -1,2 +1,5 @@
 *.pbc
 *.out
+test1.c
+test1.o
+test1
Index: t/test.pasm
===================================================================
RCS file: test.pasm
diff -N test.pasm
--- /tmp/cvsnQ6eRsJocC  Wed Oct  3 05:17:20 2001
+++ /dev/null   Wed Oct  3 03:04:34 2001
@@ -1,55 +0,0 @@
-        time_i I1
-        set_i_ic I2, 0
-        set_i_ic I3, 1
-        set_i_ic I4, 100000000
-       set_s_sc S0, "\nIterations: "
-       print_s S0
-       print_i I4
-REDO:   eq_i_ic I2, I4, DONE
-        add_i I2, I2, I3
-        branch_ic REDO
-DONE:   time_i I5
-       set_s_sc S0, "\nStart time: "
-       print_s S0
-        print_i I1
-       set_s_sc S0, "\nEnd time: "
-       print_s S0
-        print_i I5
-
-       set_s_sc S0, "\nCount: "
-       print_s S0
-        print_i I2
-
-       set_s_sc S0, "\nElapsed time:"
-       print_s S0
-        sub_i I2, I5, I1
-        print_i I2
-
-        set_i_ic I1, 3
-        mul_i I4, I4, I1
-        iton_n_i N1, I4
-        iton_n_i N2, I2
-       set_s_sc S0, "\nEstimated ops:"
-       print_s S0
-        print_i I4
-
-       set_s_sc S0, "\nEstimated ops (numerically):"
-       print_s S0
-        print_n N1
-
-       set_s_sc S0, "\nElapsed time:"
-       print_s S0
-        print_i I2
-
-       set_s_sc S0, "\nElapsed time:"
-       print_s S0
-        print_n N2
-
-        div_n N1, N1, N2
-       set_s_sc S0, "\nOps/sec:"
-       print_s S0
-        print_n N1
-
-       set_s_sc S0, "\n"
-       print_s S0
-        end
Index: t/test1.pasm
===================================================================
RCS file: test1.pasm
diff -N test1.pasm
--- /dev/null   Wed Oct  3 03:04:34 2001
+++ test1.pasm  Wed Oct  3 05:17:20 2001
@@ -0,0 +1,55 @@
+        time_i I1
+        set_i_ic I2, 0
+        set_i_ic I3, 1
+        set_i_ic I4, 100000000
+       set_s_sc S0, "\nIterations: "
+       print_s S0
+       print_i I4
+REDO:   eq_i_ic I2, I4, DONE
+        add_i I2, I2, I3
+        branch_ic REDO
+DONE:   time_i I5
+       set_s_sc S0, "\nStart time: "
+       print_s S0
+        print_i I1
+       set_s_sc S0, "\nEnd time: "
+       print_s S0
+        print_i I5
+
+       set_s_sc S0, "\nCount: "
+       print_s S0
+        print_i I2
+
+       set_s_sc S0, "\nElapsed time:"
+       print_s S0
+        sub_i I2, I5, I1
+        print_i I2
+
+        set_i_ic I1, 3
+        mul_i I4, I4, I1
+        iton_n_i N1, I4
+        iton_n_i N2, I2
+       set_s_sc S0, "\nEstimated ops:"
+       print_s S0
+        print_i I4
+
+       set_s_sc S0, "\nEstimated ops (numerically):"
+       print_s S0
+        print_n N1
+
+       set_s_sc S0, "\nElapsed time:"
+       print_s S0
+        print_i I2
+
+       set_s_sc S0, "\nElapsed time:"
+       print_s S0
+        print_n N2
+
+        div_n N1, N1, N2
+       set_s_sc S0, "\nOps/sec:"
+       print_s S0
+        print_n N1
+
+       set_s_sc S0, "\n"
+       print_s S0
+        end

Reply via email to