[svn:parrot] r44767 - in branches/ops_pct/compilers/opsc: . src/Ops
bacek at svn.parrot.org
bacek at svn.parrot.org
Mon Mar 8 19:56:03 UTC 2010
Author: bacek
Date: Mon Mar 8 19:56:02 2010
New Revision: 44767
URL: https://trac.parrot.org/parrot/changeset/44767
Log:
Readd Ops::OpLib
Added:
branches/ops_pct/compilers/opsc/src/Ops/OpLib.pm
Modified:
branches/ops_pct/compilers/opsc/Defines.mak
branches/ops_pct/compilers/opsc/opsc.pir
Modified: branches/ops_pct/compilers/opsc/Defines.mak
==============================================================================
--- branches/ops_pct/compilers/opsc/Defines.mak Mon Mar 8 19:55:38 2010 (r44766)
+++ branches/ops_pct/compilers/opsc/Defines.mak Mon Mar 8 19:56:02 2010 (r44767)
@@ -9,6 +9,7 @@
$(OPSC_DIR)/gen/Ops/Trans/C.pir \
\
$(OPSC_DIR)/gen/Ops/Op.pir \
+ $(OPSC_DIR)/gen/Ops/OpLib.pir \
$(OPSC_DIR)/gen/Ops/File.pir
OPSC_SOURCES = \
Modified: branches/ops_pct/compilers/opsc/opsc.pir
==============================================================================
--- branches/ops_pct/compilers/opsc/opsc.pir Mon Mar 8 19:55:38 2010 (r44766)
+++ branches/ops_pct/compilers/opsc/opsc.pir Mon Mar 8 19:56:02 2010 (r44767)
@@ -18,6 +18,7 @@
.include 'compilers/opsc/gen/Ops/Trans/C.pir'
.include 'compilers/opsc/gen/Ops/Op.pir'
+.include 'compilers/opsc/gen/Ops/OpLib.pir'
.include 'compilers/opsc/gen/Ops/File.pir'
.sub 'main' :main
Added: branches/ops_pct/compilers/opsc/src/Ops/OpLib.pm
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ branches/ops_pct/compilers/opsc/src/Ops/OpLib.pm Mon Mar 8 19:56:02 2010 (r44767)
@@ -0,0 +1,426 @@
+# Copyright (C) 2009, Parrot Foundation.
+# $Id$
+
+INIT {
+ pir::load_bytecode("dumper.pbc");
+ pir::load_bytecode("nqp-settings.pbc");
+};
+
+class Ops::OpLib is Hash;
+
+=begin NAME
+
+C<Ops::OpLib> - library of Parrot Operations.
+
+=end NAME
+
+=begin DESCRIPTION
+
+Responsible for loading F<src/ops/ops.num> and F<src/ops/ops.skip> files,
+parse F<.ops> files, sort them, etc.
+
+Heavily inspired by Perl5 Parrot::Ops2pm.
+
+=end DESCRIPTION
+
+=begin SYNOPSIS
+
+ my $oplib := Ops::OpLib.new.BUILD(
+ :files(@files),
+ :num_file('../../src/ops/ops.num'),
+ :skip_file('../../src/ops/ops.skip'),
+ ));
+
+=end SYNOPSIS
+
+=begin ATTRIBUTES
+
+=over 4
+
+=item * C<@.files>
+
+Op files. Mandatory argument of C<BUILD> method.
+
+=item * C<@.ops_past>
+
+List of parsed ops. Currently as C<PAST::Block>, but we probably will use
+more specific class inherited from C<PAST::Block> to provide some helper
+methods.
+
+=item * C<$.max_op_num>
+
+Scalar holding number of highest non-experimental op. Example:
+
+ 'max_op_num' => 1246,
+
+=item * C<%.optable>
+
+Hash holding mapping of opcode names ops to their numbers.
+Example:
+
+ 'optable' => {
+ 'pow_p_p_i' => 650,
+ 'say_s' => 463,
+ 'lsr_p_p_i' => 207,
+ 'lt_s_sc_ic' => 289,
+ # ...
+ 'debug_init' => 429,
+ 'iseq_i_nc_n' => 397,
+ 'eq_addr_sc_s_ic' => 254
+ },
+
+Per F<src/ops/ops.num>, this mapping exists so that we can nail down
+the op numbers for the core opcodes in a particular version of the
+bytecode and provide backward-compatibility for bytecode.
+
+=item * C<%.skiptable>
+
+Reference to a 'seen-hash' of skipped opcodes.
+
+ 'skiptable' => {
+ 'bor_i_ic_ic' => 1,
+ 'xor_i_ic_ic' => 1,
+ 'tanh_n_nc' => 1,
+ # ...
+ },
+
+As F<src/ops/ops.skip> states, these are "... opcodes that could be listed in
+F<[src/ops/]ops.num> but aren't ever to be generated or implemented because
+they are useless and/or silly."
+
+=back
+
+=end ATTRIBUTES
+
+=begin METHODS
+
+=over 4
+
+=item C<BUILD>
+
+Build OpLib.
+
+(It's NQP. In Perl 6 it should be submethod and invoked automatically)
+
+=end METHODS
+
+method new(:@files, :$num_file, :$skip_file) {
+ # Process arguments
+ if + at files == 0 {
+ die("We need some files!")
+ }
+ self<files> := @files;
+ self<num_file> := $num_file || './src/ops/ops.num';
+ self<skip_file> := $skip_file || './src/ops/ops.skip';
+
+ # Initialize self.
+ self<max_op_num> := 0;
+ self<optable> := hash();
+ self<skiptable> := hash();
+ self<ops_past> := list();
+
+ self.load_op_map_files();
+
+ self;
+}
+
+=begin METHODS
+
+=item C<parse_ops>
+
+Parse all ops files passed to BUILD method. Create self.ops list for parsed
+ops. This function is used primarily for testing. When invoked directly, the
+HLLCompiler sets the past directly.
+
+=end METHODS
+
+method parse_ops() {
+ for self.files() {
+ for @(self.parse_ops_file($_)) {
+ self<ops_past>.push($_);
+ }
+ }
+}
+
+=begin METHODS
+
+=item C<parse_ops_file>
+
+Parse single ops file. Returns list of parsed ops.
+
+=end METHODS
+
+method parse_ops_file($file) {
+ my $parser := self._get_compiler();
+ my $buffer := slurp($file);
+ my $past := $parser.compile($buffer, :target('past'));
+ #_dumper($past);
+ #say($file ~ ' ' ~ +@($past<ops>));
+ $past<ops>;
+}
+
+=begin METHODS
+
+=item C<set_ops_past>
+
+Assign an already-constructed past tree to self.
+
+=end METHODS
+
+method set_ops_past($past) {
+ self<ops_past> := $past;
+}
+
+=begin METHODS
+
+=item C<load_op_map_files>
+
+Load ops.num and ops.skip files.
+
+=end METHODS
+
+method load_op_map_files() {
+ self._load_num_file;
+ self._load_skip_file;
+}
+
+=begin METHODS
+
+=item C<build_ops>
+
+Take C<ops_past> and do any runcore-agnostic processing on it. This means such
+things as expanding opcodes with C<in> params into multiple functions,
+determining jump flags, etc.
+
+=end METHODS
+
+method build_ops() {
+
+ #ops.num is guaranteed not to have any holes, but the ordering also comes
+ #from all the .ops files catted together. It should be sufficient to go
+ #through the past, expanding ops to opfuncs as necessary and simply
+ #verifying that they end up with the right number. A special case is
+ #experimental.ops, which don't appear in ops.num.
+
+ my $op_num := 0;
+
+ for self<ops_past><ops>.iterator {
+ my $cur_op := $_;
+ say("found an op: "~ ~$_<name>);
+ #my $jump_flags := self.get_jump_flags($cur_op);
+ #figure out all the constant data: flags, name, etc
+ #build an array of args
+ #$args := [ [] ];
+ #for eq:
+ # [ [ {'dir'=>'in', 'type'=>'ic', 'label'=>0}, {'dir'=>'in', 'type'=>'i', 'label'=>0} ] , ...
+
+
+
+ #check for any skiplisted long opnames before adding them to ops
+
+ }
+
+ #'JUMP' => '0',
+ #'NAME' => 'end',
+ #'FLAGS' => {
+ # '' => undef,
+ # 'flow' => undef,
+ # 'check_event' => undef,
+ # 'base_core' => undef
+ #},
+ #'ARGDIRS' => [],
+ #'TYPE' => 'inline',
+ #'CODE' => 0,
+ #'ARGS' => [],
+ #'BODY' => '#line 53 "src/ops/core.ops"
+ #{{=0}};
+ #',
+ #'LABELS' => []
+
+
+}
+
+=begin METHODS
+
+=item C<get_jump_flags>
+
+Process the body of this op to figure out which jump flags need to be set.
+
+=end METHODS
+
+method get_jump_flags($op) {
+ my %jumps;
+ my @jumps;
+
+ #figure out which control flow flags need to be set for this op
+ if (match( " 'goto' \s+ 'ADDRESS' ", ~$op)) {
+ %jumps{'PARROT_JUMP_ADDRESS'} := 1;
+ }
+
+ if (match( " 'goto' \s+ 'OFFSET' ", ~$op) ||
+ $op.name eq 'runinterp' ) {
+ %jumps{'PARROT_JUMP_RELATIVE'} := 1;
+ }
+
+ if (match( " 'goto' \s+ 'POP' ", ~$op)) {
+ %jumps{'PARROT_JUMP_POP'} := 1;
+ }
+
+ if (match( " 'expr' \s+ 'NEXT' ", ~$op) ||
+ $op.name eq 'runinterp' ) {
+ %jumps{'PARROT_JUMP_ENEXT'} := 1;
+ }
+
+ if (match( " 'restart' \s+ 'OFFSET' ", ~$op)) {
+ %jumps{'PARROT_JUMP_RELATIVE'} := 1;
+ %jumps{'PARROT_JUMP_RESTART'} := 1;
+ }
+ elsif (match( " 'restart' \s+ 'OFFSET' ", ~$op)) {
+ %jumps{'PARROT_JUMP_RESTART'} := 1;
+ %jumps{'PARROT_JUMP_ENEXT'} := 1;
+ }
+ elsif ($op.name eq 'branch_cs' || $op.name eq 'returncc' ) {
+ %jumps{'PARROT_JUMP_RESTART'} := 1;
+ }
+ elsif (match( " 'restart' \s+ 'ADDRESS' ", ~~$op)) {
+ %jumps{'PARROT_JUMP_RESTART'} := 1;
+ %jumps{'PARROT_JUMP_ENEXT'} := 0;
+ }
+
+ #XXX: need to handle PARROT_JUMP_GNEXT
+
+ for %jumps {
+ if %jumps{$_} {
+ @jumps.push($_);
+ }
+ }
+
+ if + at jumps == 0 {
+ $op<jump_flags> := '0';
+ }
+ else {
+ $op<jump_flags> := join('|', @jumps);
+ }
+ say(~$op<jump_flags>);
+}
+
+
+
+my method _load_num_file() {
+ # slurp isn't very efficient. But extending NQP beyond bare minimum is not in scope.
+ my $buf := slurp(self<num_file>);
+ grammar NUM {
+ rule TOP { <op>+ }
+
+ rule op { $<name>=(\w+) $<number>=(\d+) }
+ token ws {
+ [
+ | \s+
+ | '#' \N*
+ ]*
+ }
+ }
+
+ #say("Parsing NUM");
+ my $ops := NUM.parse($buf);
+ #_dumper($ops);
+
+ my $prev := -1;
+ for $ops<op> {
+ my $name := ~$_<name>;
+ my $number := +$_<number>;
+ #say(@parts[0] ~ ' => ' ~@parts[1]);
+ if (+$number) eq $number {
+ if ($prev + 1 != $number) {
+ die("hole in ops.num before #$number");
+ }
+ if self<optable>.exists($name) {
+ die("duplicate opcode $name and $number");
+ }
+
+ $prev := $number;
+ self<optable>{$name} := $number;
+ if ( $number > self<max_op_num> ) {
+ self<max_op_num> := $number;
+ }
+ }
+ }
+
+ #_dumper(self<optable>);
+}
+
+method _load_skip_file() {
+ my $buf := slurp(self<skip_file>);
+ grammar SKIP {
+ rule TOP { <op>+ }
+
+ rule op { $<name>=(\w+) }
+ token ws {
+ [
+ | \s+
+ | '#' \N*
+ ]*
+ }
+ }
+
+ my $lines := SKIP.parse($buf);
+
+ for $lines<op> {
+ if self<optable>.exists($_<name>) {
+ die("skipped opcode '$_' is also in num_file");
+ }
+ self<skiptable>{$_<name>} := 1;
+ }
+}
+
+
+method _get_compiler() {
+ Q:PIR {
+ %r = compreg 'Ops'
+ };
+}
+
+=begin ACCESSORS
+
+Various methods for accessing internals.
+
+=over 4
+
+=item * C<ops_past>
+
+=item * C<files>
+
+=item * C<max_op_num>
+
+=item * C<optable>
+
+=item * C<skiptable>
+
+=end ACCESSORS
+
+method ops_past() {
+ self<ops_past>;
+}
+
+method files() {
+ self<files>;
+}
+
+method max_op_num() {
+ self<max_op_num>;
+}
+
+method optable() {
+ self<optable>;
+}
+
+method skiptable() {
+ self<skiptable>;
+}
+
+
+# Local Variables:
+# mode: perl6
+# fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=perl6:
More information about the parrot-commits
mailing list