from codegen
from ststructs.mh
Variable was directly stack allocated
Array is contiguously allocated.
Imported into nested scope
Variable is referenced other than as
argument to V or :
With the -R option, the -G code generator keeps
identifier bindings or variables in v. registers:
displacement is v. register number
r.h.s always evaluates to integer constant decl_const_val:
RIC (Russell Intermediate Code) Op codes
The first group has a single string argument
branch unconditionally
branch if value in TL is true.
branch if value in TL is false.
call routine with given label
Needs to do any cleanup (e.g. stack pops)
necessitated by the preceding ARG instr that
passed the activation record pointer.
attach the given label to the next instruction
declare the label to be external
All labels that need to be known to the
outside are marked in this way. All labels
not beginning with an 'L' are intended to be
unique, and thus may be made globally visible.
supply a label argument to immediately
following instruction
begin named function
function temporaries may be reserved on the
stack at this point
FP should be set to point to one below return
address. AR should be set to first (and only)
argument. Other locations are set explicitly.
Locations (incl. AR) are implicitly saved
during a procedure call.
trace function entry
trace function exit
record function entry for profiling
character string data. A label for the
location of the data may be supplied by a
preceding LBA instruction OBSOLETE
branch to error routine with indicated label
Arguments may have been pushed.
begin short function. Identical to BFN,
except that AR should neither be set, nor does
the old value need to be saved.
Arguments to BSF functions are passed
individually using ARG, rather than passing a
a single argument containing the activation
record. If the name of the function does not
start with Ffn, the generated function must be
C callable. (Typically it will be, in any
case.)
declared by the immediately following DCL
Generate double precision floating point data.
May be labelled with an LBA instruction.
The argument is actually a string representing
representing a floating point constant.
Such data is read-only.
Analogous to FDT, but for single precision
constants.
The remainder has up to 3 integer arguments. Unless otherwise
specified, they refer to temporary locations (virtual
registers). An offset is a signed integer value.
An object is considered accessible only if there is an
accessible pointer to its beginning.
Pointers in any active temporary or on the stack are accessible
args
loc type -- declare temporary location
(i.e. virtual register)
The following types are allowed:
32 bit integer
DCL_ADDR and DCL_INT, are assumed to be the
same size. The distinction is only a hint
to the machine code generator.
DCL_FLOAT is unlikely to be used in the
near future.
In the following, size is a location:
loc -- free temporary location
If applied to a predefined location, this
constitutes a declaration that the value it
contains is dead at this point.
Duplicate UDC's for the same location may
occasionally appear. All but the first can be
safely ignored.
size loc -- loc := ptr to new heap object
i loc -- Get the ith argument (passed with
ARG) into loc
size -- allocate new stack object containing
pointer data
Both ALS and ALH are assumed to clear the
allocated space. This is necessary only for
garbage collection, and may frequently be
eliminated by an optimizer
index offset loc -- loc := index[offset]
index offset loc -- index[offset] := loc
index offset -- jsr index[offset]
Needs cleanup similar to CLL
signed_value loc -- loc := signed_value
-- return from function w/ value at loc RL
loc -- load value of label provided
by immediately preceding LBA instruction
The label must have been previously defined.
loc1 loc2 -- loc2 := loc1
arg put_fn -- save passed argument for trace
loc -- push contents of loc onto stack
equivalent to ALS 1; STI SP, 0, loc
$define MVI 34 loc1 loc2 -- *loc2++ := *loc1++
loc1 offset loc2 -- loc2 := &loc1[offset]
Add a (word) offset to a pointer value
Unlike LDI and STI, offset here is a location
nargs -- Call to a non-Russell routine or a BSF
style Russell routine. Nargs
is an integer. The routine name is given by
are supplied in reverse order by prior
ARG instructions.
size loc -- loc := ptr to new atomic heap
object. Object should never contain pointer
data.
kind arg1 arg2 -- Code generator hint.
n -- The next n instructions perform
runtime checks, and may be discarded at
suitably high levels of optimization.
The following ARG instruction refers to a
pointer to an object that may be on the
heap. The called procedure does not
preserve references to this object. Thus
the ARG instruction may be disregarded for
purposes of static ref. counting
size atom -- (size is a constant). The
following procedure call (CLC, CLL, CLI)
returns a new object of the indicated
size. If size is != 0 the object may
be deallocated by attaching it directly
to the free list of the indicated size.
If size is = 0, the size of the object
is unknown, and the object could be
statically allocated; rfree should be
called to release it.
Atom is either 0 or 1, and
specifies whether the allocated object is
atomic, and thus should be returned to the
atomic object free list.
loc size -- Indicates that
the object pointed to by loc may be freed.
This type of hint is inserted by the
static reference counter for the benefit
of the code generator.
A negative size indicates the object is
atomic; a positive size means composite,
and a 0 size means unknown.
Size is a constant, not a location.
The following CLL or CLI instruction
does not result in a saved continuation.
Thus the reference counts of objects
pointed to only by virtual registers
is unchanged across the call.
(This is always the case for CLC calls.)
loc -- The following STI instruction
should store the size of loc if it's known
that loc has exactly one reference, and 0
otherwise. Loc contains a pointer to a
composite object.
Analogous to NP, but a single reference is
preserved (passed through) as the function
result.
loc -- The value in loc will not be used
again. (The location itself may be reused.
Thus UDC would be inappropriate.)
GF is about to be updated, or AR is about
to be updated inside a BSF function.
Such a hint always precedes the first such
update in a routine.
loc -- The value in loc should be viewed
as live up to this point. Such a hint is
included whenever a location (other than
GF and AR) could appear to be dead, but a
derived pointer is not. A value in such a
location needs to be retained, so as not
to confuse the garbage collector.
We do not generate such HINTs if it is
known that the value in question is also
stored in an accessible memory location.
Similarly, we do not generate such a HINT
if the derived pointer is only implicit
in an LDI or STI instruction.
Defines the type of the following item
declared by an EXT. All EXTs that do not
refer to functions are preceded by such a
hint. The second argument is a type
specifier, as for the DCL instruction.
The following allocation instruction may
be implemented as a stack allocation.
This is used only if the comipler is not
allowed to generate ALS instructions (-f
or -F flag). Each allocation instruction
preceded by a HINT ONS is eventually
followed by a corresponding HINT ONS;
HINT DEA sequence. All such pairs are
properly nested. There are no branches
into or our of such a pair.
n loc -- Pass loc as the nth argument to CLC
ARG instructions always occur in reverse order,
with highest numbered argument first. The
lowest numbered argument is numbered 1.
Also used to pass the activation record pointer
through CLL and CLI calls.
MAY reserve space on the stack.
Integer operations
op1 op2 result -- result := (int)op1 + (int)op2
op1 op2 result -- result := (int)op1 - (int)op2
op1 op2 result -- result := (int)op1 * (int)op2
op1 op2 result -- result := (int)op1 / (int)op2
op result -- result := -op
data -- generate integer data. May be labeled
with an LBA
Consecutive IDTs w/o intervening LBAs generate
consecutive data.
Data is read-only.
op1 op2 result -- result := (int)op1 = (int)op2
op1 op2 result -- result := (int)op1 < (int)op2
op1 op2 result -- result := (int)op1 > (int)op2
op1 op2 result -- result := (int)op1 != (int)op2
op1 op2 result -- result := (int)op1 <= (int)op2
op1 op2 result -- result := (int)op1 >= (int)op2
op1 op2 result -- result := arith_shift(op1, op2)
op1 result -- result := abs(op1)
Boolean operations
loc -- load the constant true into the
indicated location.
loc -- load the constant false into the
indicated location.
The following instructions are assumed to work on
both Booleans and bit vectors:
op1 op2 result -- result := op1 & op2
op1 op2 result -- result := op1 | op2
The following applies only to Booleans:
op result -- result := ~ op
String operations
loc -- put a pointer to the string given by the
preceding LBA instruction into loc
index offset loc -- loc := index[offset]
Differs from LDI in that offset is a virtual
register (location) and it is a BYTE rather than
word displacement from index. Used to access
individual characters in a string.
Operations on single precision floating point numbers
op1 op2 result -- result := (float)op1 + (float)op2
op1 op2 result -- result := (float)op1 - (float)op2
op1 op2 result -- result := (float)op1 * (float)op2
op1 op2 result -- result := (float)op1 / (float)op2
op result -- result := - (float) op
op1 result -- result := (int) x s.t.
2 **(x-1) <= op1 < 2**x
op1 op2 result -- result := (float)op1 = (float)op2
op1 op2 result -- result := (float)op1 < (float)op2
op1 op2 result -- result := (float)op1 > (float)op2
op1 op2 result -- result := (float)op1 != (float)op2
op1 op2 result -- result := (float)op1 <= (float)op2
op1 op2 result -- result := (float)op1 >= (float)op2
op1 op2 result -- result := (float)op1 * 2** (int)op2
predefined locations
activation record pointer
stack pointer
pointer to global act. rec.
explicitly saved and restored by
Thus it can easily be assigned to a
fixed register.
location containing "undefined" value
value sink, nothing comes out ...
An instruction using SK as
destination or an STI SK,... is a
noop
location for function result
capable of holding max size object
0x30000000
result of operation. In-line code only
Can't be legitimate operand to anything
but LDN
Location tested in conditional branches
Dead after first reference.
always 0
always 1
always 2
always 3
always 4
T1 and T2 are short term temporaries. They should be
used only in fixed code sequences, not involving
arbitrary embedded code. T1 is mapped to the same
location as RL, and may thus conflict with RS in
inline code sequences. T2 will never be specified as
the result location for an inline code sequence.
T1 is assumed to be predeclared. T2 is not treated
specially by the final code generator.
Since T1 and RL are the same, and will presumably be
mapped to the location used for function results, we
assume that T1 may be clobbered by ALA and ALH.
Note: All general locations are expected to be saved and
restored on procedure call.
Activation record layout (all parts optional):
0: static link
1: 1st arg
...
locals
Function object layout:
0: size
1: ep
2: ip
Declarations for precedence levels
no 0 in list so 1 added
precedence levels for right associative operators */
for grammar.y
0x7fff
moved from grammar.icn
following from pass1/parser/rcs.h
will have to be changed alltogether!
The following are bit vectors defining which characters may legally */
appear inside quoted identifiers. The msb of each word corresponds */
to the character with smallest ascii code. */
Note the machine and character set dependence of this whole scheme. */
From scan.h
* character classes
*/
From precedence.h
* Declarations for precedence levels
*/
$define NLEVELS 14
$define INFINITE (NLEVELS+1)
for sigio
from pass4
Success indication returned by findsig
Special signature field values
FROM stplinks.mh
define SZSTANDARDPREFIX 4
used to be 5, before we dropped refcount */
Variable was directly stack allocated
Array is contiguously allocated.
Imported into nested scope
Variable is referenced other than as
argument to V or :=
With the -R option, the -G code generator keeps
identifier bindings or variables in v. registers:
displacement is v. register number
r.h.s always evaluates to integer constant decl_const_val:
parameter. NIL indicates no call
found so far. MULTIPLE_DEFS
indicates that different arguments
are passe, or we don't know the
identity of the argument.
MULTIPLE_TP_DEFS indicates that
different arguments are passed,
but they are all types with
standard := and V operations.
Gives list of quoted characters with
default signatures. Also used as a
type signature component.
Assumes ASCII, 32 bits per word
There is a sourrounding loop with no
define INSIDE_LOOP 1
intervening blocks or function
abstractions.
Also set if there is a possibility
that the block may be reexecuted
without leaving the surrounding
function due to Call/cc calls.
A closure value is built inside the
block.
There may be an embedded Call/cc
call.
We need an a.r. if this is inside a
define REQUIRES_AR 8
loop, and it either the block builds
a closure, or there is a Call/cc
call embedded in the block.
These imply that it is not safe to
promote bindings to surrounding
function activation record.
It is known that there is no
explicit loop between this block
and the surrounding function
construction. Implies not
INSIDE_LOOP, but can be computed
much earlier.
Static link not needed,
no "complicated" constructs,
no accesses through AR.
No calls to an output routine
Environment can't be saved by
call/cc call. This implies
that it's safe to allocate
variables directly on the stack
There are no nested fn constrs.
that could conceivably be
exported.
Thus it is safe to copy id
bindings into the closure itself
Closure must be explicitly represented
Nonlocal bindings WILL BE copied to
closure. Requires that NO_CONSTR
holds, that there aren't too many
non-locals, that the closure needs
to be explicitly built, that
none of the non-locals constitute
forward references, and that there
are no calls to the procedure that
could otherwise bypass evaluation
of the operator.
All nested fn constructions that require
a closure copy identifier bindings into
the closure itself. Thus it is
automatically safe to allocate
activation record on the stack.
Known to call itself directly and
tail-recursively.
There is a direct call to this
procedure that does not require
an explicit closure.
Procedure may indirect through
static link. Thus it better be
there. (Accesses through AR are
possible even if SL_ACC is false)
Procedure contains a nested block that
requires its own activation record.