NAME
Ops::File - Ops To C Code Generation
SYNOPSIS
use Ops::File;
DESCRIPTION
Ops::File
takes one or more files of op functions and creates real C code for them.
This class is used by tools/build/ops2c.pl.
Op Functions
For ops that have trivial bodies (such as just a call to some other function and a return
statement), opcode functions are in the format:
inline op opname (args) :flags {
... body of function ...
}
Note that currently the inline
op type is ignored.
Alternately, for opcode functions that have more internal complexity the format is:
op opname (args) :flags {
... body of function ...
}
There may be more than one return
.
In both cases the closing brace must be on its own line.
When specifying multiple flags, each flag gets its own prefixing colon.
Op Arguments
Op arguments are a comma-separated list of direction and type pairs.
Argument direction is one of:
in the argument passes a value into the op
out the argument passes a value out of the op
inout the argument passes a value into and out of the op
inconst the argument passes a constant value into the op
invar the argument passes a variable value into the op
Argument direction is used to determine the life times of symbols and their related register allocations. When an argument is passed into an op a register is read from, when it's passed out of an op a register is written to.
Argument type is one of:
INT the argument is an integer
NUM the argument is an numeric
STR the argument is an string
PMC the argument is an PMC
KEY the argument is an aggregate PMC key
INTKEY the argument is an aggregate PMC integer key
LABEL the argument is an integer branch offset or address
The size of the return offset is determined from the op function's signature.
Op Flags
The flags are of two types:
- 1 class
-
The classification of ops is intended to facilitate the selection of suitable ops for a Parrot safe mode.
- 2 behavior
-
The presence (or absence) of certain flags will change how the op behaves. For example, the lack of the
flow
flag will cause the op to be implicitly terminated withgoto NEXT()
. (See next section).The :deprecated flag will generate a diagnostic to standard error at runtime when a deprecated opcode is invoked and
PARROT_WARNINGS_DEPRECATED_FLAG
has been set.
Op Body (Macro Substitutions)
In the following macro descriptions, PC
and PC'
are the current and next position within the Parrot code.
goto OFFSET(X)
-
Transforms to
PC' = PC + X
. This is used for branches. goto NEXT()
-
Transforms to
PC' = PC + S
, whereS
is the size of an op. goto ADDRESS(X)
-
Transforms to
PC' = X
. This is used for absolute jumps. expr OFFSET(X)
-
Transforms to
PC + X
. This is used to give a relative address. expr NEXT()
-
Transforms to
PC + S
, the position of the next op. expr ADDRESS(X)
-
Transforms to
X
, an absolute address. OP_SIZE
-
Transforms to
S
, the size of an op. HALT()
-
Transforms to
PC' = 0
. Halts run loop, and resets the current position to the start of the Parrot code, without resuming. restart OFFSET(X)
-
Transforms to
PC' = 0
and restarts atPC + X
. restart NEXT()
-
Transforms to
PC' = 0
and restarts atPC + S
. $n
-
Transforms to the op function's nth argument.
$0
is the opcode itself.
Note that, for ease of parsing, if the argument to one of the above notations in a ops file contains parentheses, then double the enclosing parentheses and add a space around the argument, like so:
goto OFFSET(( (void*)interp->happy_place ))
Class Methods
class Ops::File is Hash;
pir::load_bytecode('config.pbc');
new(@files)
Returns a new instance initialized by calling read_ops()
on each of the specified op files.
new_str($str)
Returns a new instance initialized by compiling $str
as the contents of an ops file.
method new(*@files, :$oplib, :$core!, :$nolines, :$quiet? = 0) { self<files> := @files; self<core> := $core; self<ops> := list(); # Ops self<preamble>:= ''; self<compiler>:= pir::compreg__Ps('Ops'); self<op_order>:= 0; self<quiet> := $quiet;
if $core {
self<oplib> := $oplib;
self<compiler>.set_oplib($oplib);
}
else {
self<file> := @files[0];
}
self._set_version();
for @files { self.read_ops( $_, $nolines ) }
self._calculate_op_codes();
self;
}
method new_str($str, :$oplib) { self<ops> := list(); # Ops self<preamble> := '';
self<compiler> := pir::compreg__Ps('Ops');
self<oplib> := $oplib;
self<compiler>.set_oplib($oplib);
self._set_version();
self._set_version();
self.compile_ops($str);
self;
}
Instance Methods
read_ops($file,$nolines)
-
Reads in the specified .ops file, gathering information about the ops.
method read_ops($file, $nolines) { $Ops::Compiler::Actions::OPLIB := self<oplib>;
self<quiet> || say("# Parsing $file..."); my $start_time := pir::time__N(); my $buffer := transcode_slurp($file); my $start_ops := +self<ops>; self.compile_ops($buffer, :experimental( $file ~~ /experimental\.ops/)); my $end_ops := +self<ops>; pir::sprintf(my $time, "%.3f", [pir::time__N() - $start_time] ); self<quiet> || say("# Parsed $file in $time seconds; found "~ ($end_ops - $start_ops) ~" ops."); }
method compile_ops($str, :$experimental? = 0) { my $compiler := self<compiler>; my $past := $compiler.compile($str, :target('past'));
for @($past<ops>) { $_.experimental($experimental); $_.deprecated($_.flags<deprecated> ?? 1 !! 0); self<ops>.push($_); #say($_.full_name ~ " is number " ~ self<op_order>); self<op_order>++; } for @( $past<preamble> ) { self<preamble> := self<preamble> ~ $_; } $past; }
method get_parse_tree($str) { my $compiler := pir::compreg__Ps('Ops'); $compiler.compile($str, :target('parse')); }
method preamble() { self<preamble> }; method ops() { self<ops> }; method oplib() { self<oplib> }; method version() { self<version>; }
method version_major() { self<version_major> } method version_minor() { self<version_minor> } method version_patch() { self<version_patch> }
method _calculate_op_codes() {
my $code := 0; for self<ops> -> $op { $op<code> := $code++; } }
method _set_version() { my $config := _config(); my $version_filename; if $config<installed> { $version_filename := $config<libdir> ~ $config<versiondir> ~ $config<slash> ~ 'VERSION'; } else { $version_filename := $config<prefix> ~ $config<slash> ~ 'VERSION'; }
grammar VERSION { rule TOP { <version> } rule version { $<major>=(\d+) '.' $<minor>=(\d+) '.' $<patch>=(\d+) } } my $version := slurp($version_filename); my $version_match := VERSION.parse($version); #say("# $version"); self<version_major> := +$version_match<version><major>; self<version_minor> := +$version_match<version><minor>; self<version_patch> := +$version_match<version><patch>; self<version> := [ +self<version_major>, +self<version_minor>, +self<version_patch>, ]; }
# Local Variables: # mode: cperl # cperl-indent-level: 4 # fill-column: 100 # End: # vim: ft=perl6 expandtab shiftwidth=4:
8 POD Errors
The following errors were encountered while parsing the POD:
- Around line 6:
=begin without a target?
- Around line 162:
You can't have =items (as at line 172) unless the first thing after the =over is an =item
- Around line 164:
'=end' without a target?
- Around line 170:
=begin without a target?
- Around line 182:
'=end' without a target?
- Around line 228:
=begin without a target?
- Around line 234:
=over without closing =back
- Around line 240:
'=end' without a target?