Copyright 1996-2000, Critical Mass, Inc. All rights reserved.
See file COPYRIGHT-CMASS for details.
MODULE M3CG_BinWr;
IMPORT Wr, Text, IntRefTbl, Word;
IMPORT M3Buf, M3ID, M3CG, M3CG_Ops, M3CG_Binary;
IMPORT Target, TInt AS TargetInt, TFloat, TWord;
FROM M3CG IMPORT Name, ByteOffset, TypeUID, CallingConvention;
FROM M3CG IMPORT BitSize, ByteSize, Alignment, Frequency;
FROM M3CG IMPORT Var, Proc, Label, Sign, BitOffset;
FROM M3CG IMPORT Type, ZType, AType, RType, IType, MType;
FROM M3CG IMPORT CompareOp, ConvertOp, AtomicOp, RuntimeError;
TYPE Bop = M3CG_Binary.Op;
TYPE WrVar = Var OBJECT tag: INTEGER END;
TYPE WrProc = Proc OBJECT tag: INTEGER END;
TYPE
RuntimeHook = REF RECORD
name : Name;
proc : Proc := NIL;
var : Var := NIL;
offset : ByteOffset := 0;
END;
TYPE
U = M3CG.T OBJECT
wr : Wr.T := NIL;
buf : M3Buf.T := NIL;
buf_len : INTEGER := 0;
runtime : IntRefTbl.T := NIL; (* Name -> RuntimeHook *)
next_label_id := 1;
next_var := 1;
next_proc := 1;
next_scope := 1;
OVERRIDES
next_label := next_label;
set_error_handler := set_error_handler;
begin_unit := begin_unit;
end_unit := end_unit;
import_unit := import_unit;
export_unit := export_unit;
set_source_file := set_source_file;
set_source_line := set_source_line;
declare_typename := declare_typename;
declare_array := declare_array;
declare_open_array := declare_open_array;
declare_enum := declare_enum;
declare_enum_elt := declare_enum_elt;
declare_packed := declare_packed;
declare_record := declare_record;
declare_field := declare_field;
declare_set := declare_set;
declare_subrange := declare_subrange;
declare_pointer := declare_pointer;
declare_indirect := declare_indirect;
declare_proctype := declare_proctype;
declare_formal := declare_formal;
declare_raises := declare_raises;
declare_object := declare_object;
declare_method := declare_method;
declare_opaque := declare_opaque;
reveal_opaque := reveal_opaque;
set_runtime_proc := set_runtime_proc;
set_runtime_hook := set_runtime_hook;
get_runtime_hook := get_runtime_hook;
import_global := import_global;
declare_segment := declare_segment;
bind_segment := bind_segment;
declare_global := declare_global;
declare_constant := declare_constant;
declare_local := declare_local;
declare_param := declare_param;
declare_temp := declare_temp;
free_temp := free_temp;
declare_exception := declare_exception;
begin_init := begin_init;
end_init := end_init;
init_int := init_int;
init_proc := init_proc;
init_label := init_label;
init_var := init_var;
init_offset := init_offset;
init_chars := init_chars;
init_float := init_float;
import_procedure := import_procedure;
declare_procedure := declare_procedure;
begin_procedure := begin_procedure;
end_procedure := end_procedure;
begin_block := begin_block;
end_block := end_block;
note_procedure_origin := note_procedure_origin;
set_label := set_label;
jump := jump;
if_true := if_true;
if_false := if_false;
if_compare := if_compare;
case_jump := case_jump;
exit_proc := exit_proc;
load := load;
store := store;
load_address := load_address;
load_indirect := load_indirect;
store_indirect := store_indirect;
load_nil := load_nil;
load_integer := load_integer;
load_float := load_float;
compare := compare;
add := add;
subtract := subtract;
multiply := multiply;
divide := divide;
div := div;
mod := mod;
negate := negate;
abs := abs;
max := max;
min := min;
cvt_int := cvt_int;
cvt_float := cvt_float;
set_union := set_union;
set_difference := set_difference;
set_intersection := set_intersection;
set_sym_difference := set_sym_difference;
set_member := set_member;
set_compare := set_compare;
set_range := set_range;
set_singleton := set_singleton;
not := not;
and := and;
or := or;
xor := xor;
shift := shift;
shift_left := shift_left;
shift_right := shift_right;
rotate := rotate;
rotate_left := rotate_left;
rotate_right := rotate_right;
widen := widen;
chop := chop;
extract := extract;
extract_n := extract_n;
extract_mn := extract_mn;
insert := insert;
insert_n := insert_n;
insert_mn := insert_mn;
swap := swap;
pop := pop;
copy := copy;
copy_n := copy_n;
zero := zero;
zero_n := zero_n;
loophole := loophole;
abort := abort;
check_nil := check_nil;
check_lo := check_lo;
check_hi := check_hi;
check_range := check_range;
check_index := check_index;
check_eq := check_eq;
add_offset := add_offset;
index_address := index_address;
start_call_direct := start_call_direct;
call_direct := call_direct;
start_call_indirect := start_call_indirect;
call_indirect := call_indirect;
pop_param := pop_param;
pop_struct := pop_struct;
pop_static_link := pop_static_link;
load_procedure := load_procedure;
load_static_link := load_static_link;
comment := comment;
fetch_and_op := fetch_and_op;
op_and_fetch := op_and_fetch;
bool_compare_and_swap := bool_compare_and_swap;
val_compare_and_swap := val_compare_and_swap;
synchronize := synchronize;
lock_test_and_set := lock_test_and_set;
lock_release := lock_release;
END;
------------------------------------------------------------------- I/O ---
PROCEDURE Cmd (u: U; cmd: Bop) =
BEGIN
OutI (u, ORD (cmd));
END Cmd;
PROCEDURE ZName (u: U; n: Name) =
BEGIN
IF (n = M3ID.NoID)
THEN OutI (u, -1);
ELSE Txt (u, M3ID.ToText (n));
END;
END ZName;
PROCEDURE VName (u: U; v: Var) =
BEGIN
TYPECASE v OF
| NULL => OutI (u, 0);
| WrVar(x) => OutI (u, x.tag);
ELSE <*ASSERT FALSE*>
END;
END VName;
PROCEDURE PName (u: U; p: Proc) =
BEGIN
TYPECASE p OF
| NULL => OutI (u, 0);
| WrProc(x) => OutI (u, x.tag);
ELSE <*ASSERT FALSE*>
END;
END PName;
PROCEDURE TName (u: U; t: Type) =
BEGIN
OutI (u, ORD (t));
END TName;
PROCEDURE Flt (u: U; READONLY f: Target.Float) =
VAR
buf : ARRAY [0..BYTESIZE (EXTENDED)] OF TFloat.Byte;
len := TFloat.ToBytes (f, buf);
BEGIN
OutI (u, ORD (TFloat.Prec (f)));
FOR i := 0 TO len-1 DO
OutI (u, buf[i]);
END;
END Flt;
PROCEDURE Bool (u: U; b: BOOLEAN) =
BEGIN
OutI (u, ORD (b));
END Bool;
PROCEDURE Lab (u: U; i: Label) =
BEGIN
OutI (u, i);
END Lab;
PROCEDURE Tipe (u: U; t: TypeUID) =
BEGIN
OutI (u, t);
END Tipe;
PROCEDURE Int (u: U; i: INTEGER) =
BEGIN
OutI (u, i);
END Int;
PROCEDURE TInt (u: U; READONLY i: Target.Int) =
VAR x: INTEGER;
BEGIN
IF TargetInt.ToInt (i, x)
THEN OutI (u, x);
ELSE AddBigX (u, i);
END;
END TInt;
PROCEDURE BInt (u: U; i: INTEGER) =
BEGIN
OutI (u, i);
END BInt;
PROCEDURE Txt (u: U; t: TEXT) =
VAR len: INTEGER;
BEGIN
IF (t = NIL) THEN
OutI (u, -1);
ELSE
len := Text.Length (t);
OutI (u, len);
M3Buf.PutText (u.buf, t);
INC (u.buf_len, len);
IF (u.buf_len >= 1024) THEN Flush (u) END;
END;
END Txt;
--------------------------------------------------------- low level I/O ---
PROCEDURE Flush (u: U) =
BEGIN
M3Buf.Flush (u.buf, u.wr);
u.buf_len := 0;
END Flush;
PROCEDURE OutI (u: U; i: INTEGER) =
BEGIN
IF (0 <= i) AND (i <= M3CG_Binary.LastRegular) THEN
M3Buf.PutChar (u.buf, VAL (i, CHAR));
INC (u.buf_len);
ELSIF (i < 0) THEN
IF (-255 <= i) THEN
i := -i;
M3Buf.PutChar (u.buf, VAL (M3CG_Binary.NInt1, CHAR));
M3Buf.PutChar (u.buf, VAL (i, CHAR));
INC (u.buf_len, 2);
ELSIF (-16_ffff <= i) THEN
i := -i;
M3Buf.PutChar (u.buf, VAL (M3CG_Binary.NInt2, CHAR));
M3Buf.PutChar (u.buf, VAL (Word.And (i, 16_ff), CHAR));
M3Buf.PutChar (u.buf, VAL (Word.And (Word.RightShift (i, 8), 16_ff), CHAR));
INC (u.buf_len, 3);
ELSE
AddBigInt (u, i);
END;
ELSE (* i > 0 *)
IF (i <= 255) THEN
M3Buf.PutChar (u.buf, VAL (M3CG_Binary.Int1, CHAR));
M3Buf.PutChar (u.buf, VAL (i, CHAR));
INC (u.buf_len, 2);
ELSIF (i <= 16_ffff) THEN
M3Buf.PutChar (u.buf, VAL (M3CG_Binary.Int2, CHAR));
M3Buf.PutChar (u.buf, VAL (Word.And (i, 16_ff), CHAR));
M3Buf.PutChar (u.buf, VAL (Word.And (Word.RightShift (i, 8), 16_ff), CHAR));
INC (u.buf_len, 3);
ELSE
AddBigInt (u, i);
END;
END;
IF (u.buf_len >= 1024) THEN Flush (u) END;
END OutI;
TYPE
IntDesc = RECORD
negative : BOOLEAN;
n_bytes : CARDINAL;
bytes : ARRAY [0..7] OF [0..255];
END;
PROCEDURE AddBigInt (u: U; i: INTEGER) =
VAR z: IntDesc;
BEGIN
z.negative := (i < 0);
IF (i < 0) THEN i := Word.Minus (0, i); END;
z.n_bytes := 0;
WHILE (i # 0) DO
z.bytes[z.n_bytes] := Word.And (i, 16_ff); INC (z.n_bytes);
i := Word.RightShift (i, 8);
END;
DumpInt (u, z);
END AddBigInt;
PROCEDURE AddBigX (u: U; READONLY i: Target.Int) =
VAR n := i; z: IntDesc;
BEGIN
z.negative := TargetInt.LT (n, TargetInt.Zero);
IF (z.negative) THEN TWord.Subtract (TargetInt.Zero, i, n); END;
z.n_bytes := TargetInt.ToBytes (n, z.bytes);
DumpInt (u, z);
END AddBigX;
PROCEDURE DumpInt (u: U; VAR i: IntDesc) =
CONST
Tag4 = ARRAY BOOLEAN OF [0..255] { M3CG_Binary.NInt4, M3CG_Binary.Int4 };
Tag8 = ARRAY BOOLEAN OF [0..255] { M3CG_Binary.NInt8, M3CG_Binary.Int8 };
VAR tag: [0..255]; cnt := i.n_bytes;
BEGIN
(* zero fill the rest of the bytes *)
FOR x := cnt TO LAST(i.bytes) DO i.bytes[x] := 0; END;
(* select the encoding *)
IF (cnt <= 4)
THEN tag := Tag4 [NOT i.negative]; cnt := 4;
ELSE tag := Tag8 [NOT i.negative]; cnt := 8;
END;
(* finally, dump the bytes *)
M3Buf.PutChar (u.buf, VAL (tag, CHAR));
FOR x := 0 TO cnt-1 DO
M3Buf.PutChar (u.buf, VAL (i.bytes[x], CHAR));
END;
INC (u.buf_len, cnt+1);
END DumpInt;
---------------------------------------------------------------------------
PROCEDURE New (output: Wr.T): M3CG.T =
VAR mbuf := M3Buf.New ();
BEGIN
M3Buf.AttachDrain (mbuf, output);
RETURN NEW (U, wr := output, buf := mbuf, buf_len := 0,
runtime := NEW (IntRefTbl.Default).init (20));
END New;
----------------------------------------------------------- ID counters ---
PROCEDURE next_label (u: U; n: INTEGER := 1): Label =
VAR x := u.next_label_id;
BEGIN
INC (u.next_label_id, n);
RETURN x;
END next_label;
------------------------------------------------ READONLY configuration ---
PROCEDURE set_error_handler (<*UNUSED*> u: U;
<*UNUSED*> p: M3CG_Ops.ErrorHandler) =
BEGIN
(* skip -- we don't generate any errors *)
END set_error_handler;
----------------------------------------------------- compilation units ---
PROCEDURE begin_unit (u: U; optimize: INTEGER) =
(* called before any other method to initialize the compilation unit *)
BEGIN
Int (u, M3CG_Binary.Version);
Cmd (u, Bop.begin_unit);
Int (u, optimize);
END begin_unit;
PROCEDURE end_unit (u: U) =
(* called after all other methods to finalize the unit and write the
resulting object *)
BEGIN
Cmd (u, Bop.end_unit);
Flush (u);
END end_unit;
PROCEDURE import_unit (u: U; n: Name) =
(* note that the current compilation unit imports the interface 'n' *)
BEGIN
Cmd (u, Bop.import_unit);
ZName (u, n);
END import_unit;
PROCEDURE export_unit (u: U; n: Name) =
(* note that the current compilation unit exports the interface 'n' *)
BEGIN
Cmd (u, Bop.export_unit);
ZName (u, n);
END export_unit;
------------------------------------------------ debugging line numbers ---
PROCEDURE set_source_file (u: U; file: TEXT) =
(* Sets the current source file name. Subsequent statements
and expressions are associated with this source location. *)
BEGIN
Cmd (u, Bop.set_source_file);
Txt (u, file);
END set_source_file;
PROCEDURE set_source_line (u: U; line: INTEGER) =
(* Sets the current source line number. Subsequent statements
and expressions are associated with this source location. *)
BEGIN
Cmd (u, Bop.set_source_line);
Int (u, line);
END set_source_line;
------------------------------------------- debugging type declarations ---
PROCEDURE declare_typename (u: U; t: TypeUID; n: Name) =
BEGIN
Cmd (u, Bop.declare_typename);
Tipe (u, t);
ZName (u, n);
END declare_typename;
PROCEDURE declare_array (u: U; t, index, elt: TypeUID; s: BitSize) =
BEGIN
Cmd (u, Bop.declare_array);
Tipe (u, t);
Tipe (u, index);
Tipe (u, elt);
BInt (u, s);
END declare_array;
PROCEDURE declare_open_array (u: U; t, elt: TypeUID; s: BitSize) =
BEGIN
Cmd (u, Bop.declare_open_array);
Tipe (u, t);
Tipe (u, elt);
BInt (u, s);
END declare_open_array;
PROCEDURE declare_enum (u: U; t: TypeUID; n_elts: INTEGER; s: BitSize) =
BEGIN
Cmd (u, Bop.declare_enum);
Tipe (u, t);
Int (u, n_elts);
BInt (u, s);
END declare_enum;
PROCEDURE declare_enum_elt (u: U; n: Name) =
BEGIN
Cmd (u, Bop.declare_enum_elt);
ZName (u, n);
END declare_enum_elt;
PROCEDURE declare_packed (u: U; t: TypeUID; s: BitSize; base: TypeUID) =
BEGIN
Cmd (u, Bop.declare_packed);
Tipe (u, t);
BInt (u, s);
Tipe (u, base);
END declare_packed;
PROCEDURE declare_record (u: U; t: TypeUID; s: BitSize;
n_fields: INTEGER)=
BEGIN
Cmd (u, Bop.declare_record);
Tipe (u, t);
BInt (u, s);
Int (u, n_fields);
END declare_record;
PROCEDURE declare_field (u: U; n: Name; o: BitOffset; s: BitSize;
t: TypeUID)=
BEGIN
Cmd (u, Bop.declare_field);
ZName (u, n);
BInt (u, o);
BInt (u, s);
Tipe (u, t);
END declare_field;
PROCEDURE declare_set (u: U; t, domain: TypeUID; s: BitSize) =
BEGIN
Cmd (u, Bop.declare_set);
Tipe (u, t);
Tipe (u, domain);
BInt (u, s);
END declare_set;
PROCEDURE declare_subrange (u: U; t, domain: TypeUID;
READONLY min, max: Target.Int;
s: BitSize) =
BEGIN
Cmd (u, Bop.declare_subrange);
Tipe (u, t);
Tipe (u, domain);
TInt (u, min);
TInt (u, max);
BInt (u, s);
END declare_subrange;
PROCEDURE declare_pointer (u: U; t, target: TypeUID; brand: TEXT;
traced: BOOLEAN) =
BEGIN
Cmd (u, Bop.declare_pointer);
Tipe (u, t);
Tipe (u, target);
Txt (u, brand);
Bool (u, traced);
END declare_pointer;
PROCEDURE declare_indirect (u: U; t, target: TypeUID) =
BEGIN
Cmd (u, Bop.declare_indirect);
Tipe (u, t);
Tipe (u, target);
END declare_indirect;
PROCEDURE declare_proctype (u: U; t: TypeUID; n_formals: INTEGER;
result: TypeUID; n_raises: INTEGER;
cc: CallingConvention) =
BEGIN
Cmd (u, Bop.declare_proctype);
Tipe (u, t);
Int (u, n_formals);
Tipe (u, result);
Int (u, n_raises);
Int (u, cc.m3cg_id);
END declare_proctype;
PROCEDURE declare_formal (u: U; n: Name; t: TypeUID) =
BEGIN
Cmd (u, Bop.declare_formal);
ZName (u, n);
Tipe (u, t);
END declare_formal;
PROCEDURE declare_raises (u: U; n: Name) =
BEGIN
Cmd (u, Bop.declare_raises);
ZName (u, n);
END declare_raises;
PROCEDURE declare_object (u: U; t, super: TypeUID;
brand: TEXT; traced: BOOLEAN;
n_fields, n_methods: INTEGER;
field_size: BitSize) =
BEGIN
Cmd (u, Bop.declare_object);
Tipe (u, t);
Tipe (u, super);
Txt (u, brand);
Bool (u, traced);
Int (u, n_fields);
Int (u, n_methods);
BInt (u, field_size);
END declare_object;
PROCEDURE declare_method (u: U; n: Name; signature: TypeUID) =
BEGIN
Cmd (u, Bop.declare_method);
ZName (u, n);
Tipe (u, signature);
END declare_method;
PROCEDURE declare_opaque (u: U; t, super: TypeUID) =
BEGIN
Cmd (u, Bop.declare_opaque);
Tipe (u, t);
Tipe (u, super);
END declare_opaque;
PROCEDURE reveal_opaque (u: U; lhs, rhs: TypeUID) =
BEGIN
Cmd (u, Bop.reveal_opaque);
Tipe (u, lhs);
Tipe (u, rhs);
END reveal_opaque;
PROCEDURE declare_exception (u: U; n: Name; arg_type: TypeUID;
raise_proc: BOOLEAN; base: Var; offset: INTEGER) =
BEGIN
Cmd (u, Bop.declare_exception);
ZName (u, n);
Tipe (u, arg_type);
Bool (u, raise_proc);
VName (u, base);
Int (u, offset);
END declare_exception;
--------------------------------------------------------- runtime hooks ---
PROCEDURE GetRuntimeHook (u: U; n: Name): RuntimeHook =
VAR ref: REFANY; e: RuntimeHook;
BEGIN
IF u.runtime.get (n, ref) THEN
e := ref;
ELSE
e := NEW (RuntimeHook, name := n, proc := NIL, var := NIL, offset := 0);
EVAL u.runtime.put (n, e);
END;
RETURN e;
END GetRuntimeHook;
PROCEDURE set_runtime_proc (u: U; n: Name; p: Proc) =
VAR e := GetRuntimeHook (u, n);
BEGIN
e.proc := p;
Cmd (u, Bop.set_runtime_proc);
ZName (u, n);
PName (u, p);
END set_runtime_proc;
PROCEDURE set_runtime_hook (u: U; n: Name; v: Var; o: ByteOffset) =
VAR e := GetRuntimeHook (u, n);
BEGIN
e.var := v;
e.offset := o;
Cmd (u, Bop.set_runtime_hook);
ZName (u, n);
VName (u, v);
Int (u, o);
END set_runtime_hook;
PROCEDURE get_runtime_hook (u: U; n: Name; VAR p: Proc;
VAR v: Var; VAR o: ByteOffset) =
VAR e := GetRuntimeHook (u, n);
BEGIN
(* no output is generated ... *)
p := e.proc;
v := e.var;
o := e.offset;
END get_runtime_hook;
------------------------------------------------- variable declarations ---
PROCEDURE NewVar (u: U): Var =
VAR v := NEW (WrVar, tag := u.next_var);
BEGIN
INC (u.next_var);
RETURN v;
END NewVar;
PROCEDURE import_global (u: U; n: Name; s: ByteSize; a: Alignment;
t: Type; m3t: TypeUID): Var =
VAR v := NewVar (u);
BEGIN
Cmd (u, Bop.import_global);
ZName (u, n);
Int (u, s);
Int (u, a);
TName (u, t);
Tipe (u, m3t);
VName (u, v);
RETURN v;
END import_global;
PROCEDURE declare_segment (u: U; n: Name; m3t: TypeUID; is_const: BOOLEAN): Var =
VAR v := NewVar (u);
BEGIN
Cmd (u, Bop.declare_segment);
ZName (u, n);
Tipe (u, m3t);
Bool (u, is_const);
VName (u, v);
RETURN v;
END declare_segment;
PROCEDURE bind_segment (u: U; seg: Var; s: ByteSize; a: Alignment;
t: Type; exported, inited: BOOLEAN) =
BEGIN
Cmd (u, Bop.bind_segment);
VName (u, seg);
Int (u, s);
Int (u, a);
TName (u, t);
Bool (u, exported);
Bool (u, inited);
END bind_segment;
PROCEDURE declare_global (u: U; n: Name; s: ByteSize; a: Alignment;
t: Type; m3t: TypeUID; exported, inited: BOOLEAN): Var =
VAR v := NewVar (u);
BEGIN
Cmd (u, Bop.declare_global);
ZName (u, n);
Int (u, s);
Int (u, a);
TName (u, t);
Tipe (u, m3t);
Bool (u, exported);
Bool (u, inited);
VName (u, v);
RETURN v;
END declare_global;
PROCEDURE declare_constant (u: U; n: Name; s: ByteSize; a: Alignment;
t: Type; m3t: TypeUID; exported, inited: BOOLEAN): Var =
VAR v := NewVar (u);
BEGIN
Cmd (u, Bop.declare_constant);
ZName (u, n);
Int (u, s);
Int (u, a);
TName (u, t);
Tipe (u, m3t);
Bool (u, exported);
Bool (u, inited);
VName (u, v);
RETURN v;
END declare_constant;
PROCEDURE declare_local (u: U; n: Name; s: ByteSize; a: Alignment;
t: Type; m3t: TypeUID; in_memory, up_level: BOOLEAN;
f: Frequency): Var =
VAR v := NewVar (u);
BEGIN
Cmd (u, Bop.declare_local);
ZName (u, n);
Int (u, s);
Int (u, a);
TName (u, t);
Tipe (u, m3t);
Bool (u, in_memory);
Bool (u, up_level);
Int (u, f);
VName (u, v);
RETURN v;
END declare_local;
PROCEDURE declare_param (u: U; n: Name; s: ByteSize; a: Alignment;
t: Type; m3t: TypeUID; in_memory, up_level: BOOLEAN;
f: Frequency): Var =
VAR v := NewVar (u);
BEGIN
Cmd (u, Bop.declare_param);
ZName (u, n);
Int (u, s);
Int (u, a);
TName (u, t);
Tipe (u, m3t);
Bool (u, in_memory);
Bool (u, up_level);
Int (u, f);
VName (u, v);
RETURN v;
END declare_param;
PROCEDURE declare_temp (u: U; s: ByteSize; a: Alignment; t: Type;
in_memory:BOOLEAN): Var =
VAR v := NewVar (u);
BEGIN
Cmd (u, Bop.declare_temp);
Int (u, s);
Int (u, a);
TName (u, t);
Bool (u, in_memory);
VName (u, v);
RETURN v;
END declare_temp;
PROCEDURE free_temp (u: U; v: Var) =
BEGIN
Cmd (u, Bop.free_temp);
VName (u, v);
END free_temp;
---------------------------------------- static variable initialization ---
PROCEDURE begin_init (u: U; v: Var) =
BEGIN
Cmd (u, Bop.begin_init);
VName (u, v);
END begin_init;
PROCEDURE end_init (u: U; v: Var) =
BEGIN
Cmd (u, Bop.end_init);
VName (u, v);
END end_init;
PROCEDURE init_int (u: U; o: ByteOffset; READONLY value: Target.Int;
t: Type) =
BEGIN
Cmd (u, Bop.init_int);
Int (u, o);
TInt (u, value);
TName (u, t);
END init_int;
PROCEDURE init_proc (u: U; o: ByteOffset; value: Proc) =
BEGIN
Cmd (u, Bop.init_proc);
Int (u, o);
PName (u, value);
END init_proc;
PROCEDURE init_label (u: U; o: ByteOffset; value: Label) =
BEGIN
Cmd (u, Bop.init_label);
Int (u, o);
Lab (u, value);
END init_label;
PROCEDURE init_var (u: U; o: ByteOffset; value: Var; bias: ByteOffset) =
BEGIN
Cmd (u, Bop.init_var);
Int (u, o);
VName (u, value);
Int (u, bias);
END init_var;
PROCEDURE init_offset (u: U; o: ByteOffset; value: Var) =
BEGIN
Cmd (u, Bop.init_offset);
Int (u, o);
VName (u, value);
END init_offset;
PROCEDURE init_chars (u: U; o: ByteOffset; value: TEXT) =
BEGIN
Cmd (u, Bop.init_chars);
Int (u, o);
Txt (u, value);
END init_chars;
PROCEDURE init_float (u: U; o: ByteOffset; READONLY f: Target.Float) =
BEGIN
Cmd (u, Bop.init_float);
Int (u, o);
Flt (u, f);
END init_float;
------------------------------------------------------------ procedures ---
PROCEDURE NewProc (u: U): Proc =
VAR p := NEW (WrProc, tag := u.next_proc);
BEGIN
INC (u.next_proc);
RETURN p;
END NewProc;
PROCEDURE import_procedure (u: U; n: Name; n_params: INTEGER;
ret_type: Type; cc: CallingConvention): Proc =
VAR p := NewProc (u);
BEGIN
Cmd (u, Bop.import_procedure);
ZName (u, n);
Int (u, n_params);
TName (u, ret_type);
Int (u, cc.m3cg_id);
PName (u, p);
RETURN p;
END import_procedure;
PROCEDURE declare_procedure (u: U; n: Name; n_params: INTEGER;
return_type: Type; lev: INTEGER;
cc: CallingConvention;
exported: BOOLEAN; parent: Proc): Proc =
VAR p := NewProc (u);
BEGIN
Cmd (u, Bop.declare_procedure);
ZName (u, n);
Int (u, n_params);
TName (u, return_type);
Int (u, lev);
Int (u, cc.m3cg_id);
Bool (u, exported);
PName (u, parent);
PName (u, p);
RETURN p;
END declare_procedure;
PROCEDURE begin_procedure (u: U; p: Proc) =
BEGIN
Cmd (u, Bop.begin_procedure);
PName (u, p);
END begin_procedure;
PROCEDURE end_procedure (u: U; p: Proc) =
BEGIN
Cmd (u, Bop.end_procedure);
PName (u, p);
END end_procedure;
PROCEDURE begin_block (u: U) =
(* marks the beginning of a nested anonymous block *)
BEGIN
Cmd (u, Bop.begin_block);
END begin_block;
PROCEDURE end_block (u: U) =
(* marks the ending of a nested anonymous block *)
BEGIN
Cmd (u, Bop.end_block);
END end_block;
PROCEDURE note_procedure_origin (u: U; p: Proc) =
BEGIN
Cmd (u, Bop.note_procedure_origin);
PName (u, p);
END note_procedure_origin;
------------------------------------------------------------ statements ---
PROCEDURE set_label (u: U; l: Label; barrier: BOOLEAN) =
(* define 'l' to be at the current pc *)
BEGIN
Cmd (u, Bop.set_label);
Lab (u, l);
Bool (u, barrier);
END set_label;
PROCEDURE jump (u: U; l: Label) =
(* GOTO l *)
BEGIN
Cmd (u, Bop.jump);
Lab (u, l);
END jump;
PROCEDURE if_true (u: U; t: IType; l: Label; f: Frequency) =
(* IF (s0.t # 0) GOTO l ; pop *)
BEGIN
Cmd (u, Bop.if_true);
TName (u, t);
Lab (u, l);
Int (u, f);
END if_true;
PROCEDURE if_false (u: U; t: IType; l: Label; f: Frequency) =
(* IF (s0.t = 0) GOTO l ; pop *)
BEGIN
Cmd (u, Bop.if_false);
TName (u, t);
Lab (u, l);
Int (u, f);
END if_false;
PROCEDURE if_compare (u: U; t: ZType; op: CompareOp; l: Label; f: Frequency) =
(* IF (s1.t op s0.t) GOTO l ; pop(2) *)
CONST OpName = ARRAY CompareOp OF Bop {
Bop.if_eq, Bop.if_ne, Bop.if_gt, Bop.if_ge, Bop.if_lt, Bop.if_le };
BEGIN
Cmd (u, OpName [op]);
TName (u, t);
Lab (u, l);
Int (u, f);
END if_compare;
PROCEDURE case_jump (u: U; t: IType; READONLY labels: ARRAY OF Label) =
(* "GOTO labels[s0.t] ; pop" with no range checking on s0.t *)
BEGIN
Cmd (u, Bop.case_jump);
TName (u, t);
Int (u, NUMBER(labels));
FOR i := FIRST (labels) TO LAST (labels) DO Lab (u, labels [i]); END;
END case_jump;
PROCEDURE exit_proc (u: U; t: Type) =
(* Returns s0.t if the stack is non-empty, otherwise returns no value. *)
BEGIN
Cmd (u, Bop.exit_proc);
TName (u, t);
END exit_proc;
------------------------------------------------------------ load/store ---
PROCEDURE load (u: U; v: Var; o: ByteOffset; t: MType; z: ZType) =
BEGIN
Cmd (u, Bop.load);
VName (u, v);
Int (u, o);
TName (u, t);
TName (u, z);
END load;
PROCEDURE store (u: U; v: Var; o: ByteOffset; t: ZType; z: MType) =
BEGIN
Cmd (u, Bop.store);
VName (u, v);
Int (u, o);
TName (u, t);
TName (u, z);
END store;
PROCEDURE load_address (u: U; v: Var; o: ByteOffset) =
BEGIN
Cmd (u, Bop.load_address);
VName (u, v);
Int (u, o);
END load_address;
PROCEDURE load_indirect (u: U; o: ByteOffset; t: MType; z: ZType) =
BEGIN
Cmd (u, Bop.load_indirect);
Int (u, o);
TName (u, t);
TName (u, z);
END load_indirect;
PROCEDURE store_indirect (u: U; o: ByteOffset; t: ZType; z: MType) =
BEGIN
Cmd (u, Bop.store_indirect);
Int (u, o);
TName (u, t);
TName (u, z);
END store_indirect;
-------------------------------------------------------------- literals ---
PROCEDURE load_nil (u: U) =
(* push ; s0.A := a *)
BEGIN
Cmd (u, Bop.load_nil);
END load_nil;
PROCEDURE load_integer (u: U; t: IType; READONLY i: Target.Int) =
(* push ; s0.t:= i *)
BEGIN
Cmd (u, Bop.load_integer);
TName (u, t);
TInt (u, i);
END load_integer;
PROCEDURE load_float (u: U; t: RType; READONLY f: Target.Float) =
(* push ; s0.t := f *)
BEGIN
Cmd (u, Bop.load_float);
TName (u, t);
Flt (u, f);
END load_float;
------------------------------------------------------------ arithmetic ---
PROCEDURE compare (u: U; t: ZType; z: IType; op: CompareOp) =
(* s1.z := (s1.t op s0.t) ; pop *)
CONST OpName = ARRAY CompareOp OF Bop {
Bop.eq, Bop.ne, Bop.gt, Bop.ge, Bop.lt, Bop.le };
BEGIN
Cmd (u, OpName [op]);
TName (u, t);
TName (u, z);
END compare;
PROCEDURE add (u: U; t: AType) =
(* s1.t := s1.t + s0.t ; pop *)
BEGIN
Cmd (u, Bop.add);
TName (u, t);
END add;
PROCEDURE subtract (u: U; t: AType) =
(* s1.t := s1.t - s0.t ; pop *)
BEGIN
Cmd (u, Bop.subtract);
TName (u, t);
END subtract;
PROCEDURE multiply (u: U; t: AType) =
(* s1.t := s1.t * s0.t ; pop *)
BEGIN
Cmd (u, Bop.multiply);
TName (u, t);
END multiply;
PROCEDURE divide (u: U; t: RType) =
(* s1.t := s1.t / s0.t ; pop *)
BEGIN
Cmd (u, Bop.divide);
TName (u, t);
END divide;
PROCEDURE div (u: U; t: IType; a, b: Sign) =
(* s1.t := s1.t DIV s0.t ; pop *)
BEGIN
Cmd (u, Bop.div);
TName (u, t);
Int (u, ORD (a));
Int (u, ORD (b));
END div;
PROCEDURE mod (u: U; t: IType; a, b: Sign) =
(* s1.t := s1.t MOD s0.t ; pop *)
BEGIN
Cmd (u, Bop.mod);
TName (u, t);
Int (u, ORD (a));
Int (u, ORD (b));
END mod;
PROCEDURE negate (u: U; t: AType) =
(* s0.t := - s0.t *)
BEGIN
Cmd (u, Bop.negate);
TName (u, t);
END negate;
PROCEDURE abs (u: U; t: AType) =
(* s0.t := ABS (s0.t) (noop on Words) *)
BEGIN
Cmd (u, Bop.abs);
TName (u, t);
END abs;
PROCEDURE max (u: U; t: ZType) =
(* s1.t := MAX (s1.t, s0.t) ; pop *)
BEGIN
Cmd (u, Bop.max);
TName (u, t);
END max;
PROCEDURE min (u: U; t: ZType) =
(* s1.t := MIN (s1.t, s0.t) ; pop *)
BEGIN
Cmd (u, Bop.min);
TName (u, t);
END min;
PROCEDURE cvt_int (u: U; t: RType; x: IType; op: ConvertOp) =
(* s0.x := op (s0.t) *)
CONST OpName = ARRAY ConvertOp OF Bop {
Bop.round, Bop.trunc, Bop.floor, Bop.ceiling } ;
BEGIN
Cmd (u, OpName [op]);
TName (u, t);
TName (u, x);
END cvt_int;
PROCEDURE cvt_float (u: U; t: AType; x: RType) =
(* s0.x := FLOAT (s0.t, x) *)
BEGIN
Cmd (u, Bop.cvt_float);
TName (u, t);
TName (u, x);
END cvt_float;
------------------------------------------------------------------ sets ---
PROCEDURE set_union (u: U; s: ByteSize) =
(* s1.B := s1.B + s0.B ; pop *)
BEGIN
Cmd (u, Bop.set_union);
Int (u, s);
END set_union;
PROCEDURE set_difference (u: U; s: ByteSize) =
(* s1.B := s1.B - s0.B ; pop *)
BEGIN
Cmd (u, Bop.set_difference);
Int (u, s);
END set_difference;
PROCEDURE set_intersection (u: U; s: ByteSize) =
(* s1.B := s1.B * s0.B ; pop *)
BEGIN
Cmd (u, Bop.set_intersection);
Int (u, s);
END set_intersection;
PROCEDURE set_sym_difference (u: U; s: ByteSize) =
(* s1.B := s1.B / s0.B ; pop *)
BEGIN
Cmd (u, Bop.set_sym_difference);
Int (u, s);
END set_sym_difference;
PROCEDURE set_member (u: U; s: ByteSize; t: IType) =
(* s1.t := (s0.t IN s1.B) ; pop *)
BEGIN
Cmd (u, Bop.set_member);
Int (u, s);
TName (u, t);
END set_member;
PROCEDURE set_compare (u: U; s: ByteSize; op: CompareOp; t: IType) =
(* s1.t := (s1.B op s0.B) ; pop *)
CONST OpName = ARRAY CompareOp OF Bop {
Bop.set_eq, Bop.set_ne, Bop.set_gt, Bop.set_ge, Bop.set_lt, Bop.set_le };
BEGIN
Cmd (u, OpName [op]);
Int (u, s);
TName (u, t);
END set_compare;
PROCEDURE set_range (u: U; s: ByteSize; t: IType) =
(* s2.A [s1.t .. s0.t] := 1's; pop(3)*)
BEGIN
Cmd (u, Bop.set_range);
Int (u, s);
TName (u, t);
END set_range;
PROCEDURE set_singleton (u: U; s: ByteSize; t: IType) =
(* s1.A [s0.t] := 1; pop(2) *)
BEGIN
Cmd (u, Bop.set_singleton);
Int (u, s);
TName (u, t);
END set_singleton;
------------------------------------------------- Word.T bit operations ---
PROCEDURE not (u: U; t: IType) =
(* s0.t := Word.Not (s0.t) *)
BEGIN
Cmd (u, Bop.not);
TName (u, t);
END not;
PROCEDURE and (u: U; t: IType) =
(* s1.t := Word.And (s1.t, s0.t) ; pop *)
BEGIN
Cmd (u, Bop.and);
TName (u, t);
END and;
PROCEDURE or (u: U; t: IType) =
(* s1.t := Word.Or (s1.t, s0.t) ; pop *)
BEGIN
Cmd (u, Bop.or);
TName (u, t);
END or;
PROCEDURE xor (u: U; t: IType) =
(* s1.t := Word.Xor (s1.t, s0.t) ; pop *)
BEGIN
Cmd (u, Bop.xor);
TName (u, t);
END xor;
PROCEDURE shift (u: U; t: IType) =
(* s1.t := Word.Shift (s1.t, s0.t) ; pop *)
BEGIN
Cmd (u, Bop.shift);
TName (u, t);
END shift;
PROCEDURE shift_left (u: U; t: IType) =
(* s1.t := Word.Shift (s1.t, s0.t) ; pop *)
BEGIN
Cmd (u, Bop.shift_left);
TName (u, t);
END shift_left;
PROCEDURE shift_right (u: U; t: IType) =
(* s1.t := Word.Shift (s1.t, -s0.t) ; pop *)
BEGIN
Cmd (u, Bop.shift_right);
TName (u, t);
END shift_right;
PROCEDURE rotate (u: U; t: IType) =
(* s1.t := Word.Rotate (s1.t, s0.t) ; pop *)
BEGIN
Cmd (u, Bop.rotate);
TName (u, t);
END rotate;
PROCEDURE rotate_left (u: U; t: IType) =
(* s1.t := Word.Rotate (s1.t, s0.t) ; pop *)
BEGIN
Cmd (u, Bop.rotate_left);
TName (u, t);
END rotate_left;
PROCEDURE rotate_right (u: U; t: IType) =
(* s1.t := Word.Rotate (s1.t, -s0.t) ; pop *)
BEGIN
Cmd (u, Bop.rotate_right);
TName (u, t);
END rotate_right;
PROCEDURE widen (u: U; sign: BOOLEAN) =
(* s0.I64 := s0.I32; IF sign THEN SignExtend s0; *)
BEGIN
Cmd (u, Bop.widen);
Bool (u, sign);
END widen;
PROCEDURE chop (u: U) =
(* s0.I32 := Word.And (s0.I64, 16_ffffffff); *)
BEGIN
Cmd (u, Bop.chop);
END chop;
PROCEDURE extract (u: U; t: IType; sign: BOOLEAN) =
(* s2.t := Word.Extract(s2.t, s1.t, s0.t);
IF sign THEN SignExtend s2 END; pop(2) *)
BEGIN
Cmd (u, Bop.extract);
TName (u, t);
Bool (u, sign);
END extract;
PROCEDURE extract_n (u: U; t: IType; sign: BOOLEAN; n: INTEGER) =
(* s1.t := Word.Extract(s1.t, s0.t, n);
IF sign THEN SignExtend s1 END; pop(1) *)
BEGIN
Cmd (u, Bop.extract_n);
TName (u, t);
Bool (u, sign);
Int (u, n);
END extract_n;
PROCEDURE extract_mn (u: U; t: IType; sign: BOOLEAN; m, n: INTEGER) =
(* s0.t := Word.Extract(s0.t, m, n);
IF sign THEN SignExtend s0 END; *)
BEGIN
Cmd (u, Bop.extract_mn);
TName (u, t);
Bool (u, sign);
Int (u, m);
Int (u, n);
END extract_mn;
PROCEDURE insert (u: U; t: IType) =
(* s3.t := Word.Insert (s3.t, s2.t, s1.t, s0.t) ; pop(3) *)
BEGIN
Cmd (u, Bop.insert);
TName (u, t);
END insert;
PROCEDURE insert_n (u: U; t: IType; n: INTEGER) =
(* s2.t := Word.Insert (s2.t, s1.t, s0.t, n) ; pop(2) *)
BEGIN
Cmd (u, Bop.insert_n);
TName (u, t);
Int (u, n);
END insert_n;
PROCEDURE insert_mn (u: U; t: IType; m, n: INTEGER) =
(* s1.t := Word.Insert (s1.t, s0.t, m, n) ; pop(2) *)
BEGIN
Cmd (u, Bop.insert_mn);
TName (u, t);
Int (u, m);
Int (u, n);
END insert_mn;
------------------------------------------------ misc. stack/memory ops ---
PROCEDURE swap (u: U; a, b: Type) =
(* tmp := s1 ; s1 := s0 ; s0 := tmp *)
BEGIN
Cmd (u, Bop.swap);
TName (u, a);
TName (u, b);
END swap;
PROCEDURE pop (u: U; t: Type) =
(* pop(1) (i.e. discard s0) *)
BEGIN
Cmd (u, Bop.pop);
TName (u, t);
END pop;
PROCEDURE copy_n (u: U; z: IType; t: MType; overlap: BOOLEAN) =
(* Mem[s2.A:s0.z] := Mem[s1.A:s0.z]; pop(3)*)
BEGIN
Cmd (u, Bop.copy_n);
TName (u, z);
TName (u, t);
Bool (u, overlap);
END copy_n;
PROCEDURE copy (u: U; n: INTEGER; t: MType; overlap: BOOLEAN) =
(* Mem[s2.A:sz] := Mem[s1.A:sz]; pop(2)*)
BEGIN
Cmd (u, Bop.copy);
Int (u, n);
TName (u, t);
Bool (u, overlap);
END copy;
PROCEDURE zero_n (u: U; z: IType; t: MType) =
(* Mem[s1.A:s0.z] := 0; pop(2) *)
BEGIN
Cmd (u, Bop.zero_n);
TName (u, z);
TName (u, t);
END zero_n;
PROCEDURE zero (u: U; n: INTEGER; t: MType) =
(* Mem[s1.A:sz] := 0; pop(1) *)
BEGIN
Cmd (u, Bop.zero);
Int (u, n);
TName (u, t);
END zero;
----------------------------------------------------------- conversions ---
PROCEDURE loophole (u: U; from, two: ZType) =
(* s0.to := LOOPHOLE(s0.from, to) *)
BEGIN
Cmd (u, Bop.loophole);
TName (u, from);
TName (u, two);
END loophole;
------------------------------------------------ traps & runtime checks ---
PROCEDURE abort (u: U; code: RuntimeError) =
BEGIN
Cmd (u, Bop.abort);
Int (u, ORD (code));
END abort;
PROCEDURE check_nil (u: U; code: RuntimeError) =
(* IF (s0.A = NIL) THEN abort(code) *)
BEGIN
Cmd (u, Bop.check_nil);
Int (u, ORD (code));
END check_nil;
PROCEDURE check_lo (u: U; t: IType; READONLY i: Target.Int; code: RuntimeError) =
(* IF (s0.t < i) THEN abort(code) *)
BEGIN
Cmd (u, Bop.check_lo);
TName (u, t);
TInt (u, i);
Int (u, ORD (code));
END check_lo;
PROCEDURE check_hi (u: U; t: IType; READONLY i: Target.Int; code: RuntimeError) =
(* IF (i < s0.t) THEN abort(code) *)
BEGIN
Cmd (u, Bop.check_hi);
TName (u, t);
TInt (u, i);
Int (u, ORD (code));
END check_hi;
PROCEDURE check_range (u: U; t: IType; READONLY a, b: Target.Int; code: RuntimeError) =
(* IF (s0.t < a) OR (b < s0.t) THEN abort(code) *)
BEGIN
Cmd (u, Bop.check_range);
TName (u, t);
TInt (u, a);
TInt (u, b);
Int (u, ORD (code));
END check_range;
PROCEDURE check_index (u: U; t: IType; code: RuntimeError) =
BEGIN
Cmd (u, Bop.check_index);
TName (u, t);
Int (u, ORD (code));
END check_index;
PROCEDURE check_eq (u: U; t: IType; code: RuntimeError) =
(* IF (s0.t # s1.t) THEN abort(code); Pop (2) *)
BEGIN
Cmd (u, Bop.check_eq);
TName (u, t);
Int (u, ORD (code));
END check_eq;
---------------------------------------------------- address arithmetic ---
PROCEDURE add_offset (u: U; i: INTEGER) =
(* s0.A := s0.A + i *)
BEGIN
Cmd (u, Bop.add_offset);
Int (u, i);
END add_offset;
PROCEDURE index_address (u: U; t: IType; size: INTEGER) =
(* s1.A := s1.A + s0.t * size ; pop *)
BEGIN
Cmd (u, Bop.index_address);
TName (u, t);
Int (u, size);
END index_address;
------------------------------------------------------- procedure calls ---
PROCEDURE start_call_direct (u: U; p: Proc; lev: INTEGER; t: Type) =
(* begin a procedure call to a procedure at static level 'lev'. *)
BEGIN
Cmd (u, Bop.start_call_direct);
PName (u, p);
Int (u, lev);
TName (u, t);
END start_call_direct;
PROCEDURE start_call_indirect (u: U; t: Type; cc: CallingConvention) =
(* begin a procedure call to a procedure at static level 'lev'. *)
BEGIN
Cmd (u, Bop.start_call_indirect);
TName (u, t);
Int (u, cc.m3cg_id);
END start_call_indirect;
PROCEDURE pop_param (u: U; t: MType) =
(* pop s0 and make it the "next" paramter in the current call *)
BEGIN
Cmd (u, Bop.pop_param);
TName (u, t);
END pop_param;
PROCEDURE pop_struct (u: U; s: ByteSize; a: Alignment) =
(* pop s0 and make it the "next" paramter in the current call *)
BEGIN
Cmd (u, Bop.pop_struct);
Int (u, s);
Int (u, a);
END pop_struct;
PROCEDURE pop_static_link (u: U) =
BEGIN
Cmd (u, Bop.pop_static_link);
END pop_static_link;
PROCEDURE call_direct (u: U; p: Proc; t: Type) =
(* call the procedure identified by block b. The procedure
returns a value of type t. *)
BEGIN
Cmd (u, Bop.call_direct);
PName (u, p);
TName (u, t);
END call_direct;
PROCEDURE call_indirect (u: U; t: Type; cc: CallingConvention) =
(* call the procedure whose address is in s0.A and pop s0. The
procedure returns a value of type t. *)
BEGIN
Cmd (u, Bop.call_indirect);
TName (u, t);
Int (u, cc.m3cg_id);
END call_indirect;
------------------------------------------- procedure and closure types ---
PROCEDURE load_procedure (u: U; p: Proc) =
(* push; s0.A := ADDR (p's body) *)
BEGIN
Cmd (u, Bop.load_procedure);
PName (u, p);
END load_procedure;
PROCEDURE load_static_link (u: U; p: Proc) =
(* push; s0.A := (static link needed to call p, NIL for top-level procs) *)
BEGIN
Cmd (u, Bop.load_static_link);
PName (u, p);
END load_static_link;
----------------------------------------------------------------- misc. ---
PROCEDURE comment (u: U; a, b, c, d: TEXT := NIL) =
VAR msg: TEXT := "";
BEGIN
IF (a # NIL) THEN msg := msg & a; END;
IF (b # NIL) THEN msg := msg & b; END;
IF (c # NIL) THEN msg := msg & c; END;
IF (d # NIL) THEN msg := msg & d; END;
Cmd (u, Bop.comment);
Txt (u, msg);
END comment;
--------------------------------------------------------------- atomics ---
PROCEDURE fetch_and_op (u: U; op: AtomicOp; t: MType) =
CONST
OpName = ARRAY AtomicOp OF Bop { Bop.fetch_and_add, Bop.fetch_and_sub,
Bop.fetch_and_or, Bop.fetch_and_and,
Bop.fetch_and_xor, Bop.fetch_and_nand };
BEGIN
Cmd (u, OpName [op]);
TName (u, t);
END fetch_and_op;
PROCEDURE op_and_fetch (u: U; op: AtomicOp; t: MType) =
CONST
OpName = ARRAY AtomicOp OF Bop { Bop.add_and_fetch, Bop.sub_and_fetch,
Bop.or_and_fetch, Bop.and_and_fetch,
Bop.xor_and_fetch, Bop.nand_and_fetch };
BEGIN
Cmd (u, OpName [op]);
TName (u, t);
END op_and_fetch;
PROCEDURE bool_compare_and_swap (u: U; t: MType; z: IType) =
BEGIN
Cmd (u, Bop.bool_compare_and_swap);
TName (u, t);
TName (u, z);
END bool_compare_and_swap;
PROCEDURE val_compare_and_swap (u: U; t: MType) =
BEGIN
Cmd (u, Bop.val_compare_and_swap);
TName (u, t);
END val_compare_and_swap;
PROCEDURE synchronize (u: U) =
BEGIN
Cmd (u, Bop.synchronize);
END synchronize;
PROCEDURE lock_test_and_set (u: U; t: MType) =
BEGIN
Cmd (u, Bop.lock_test_and_set);
TName (u, t);
END lock_test_and_set;
PROCEDURE lock_release (u: U; t: MType) =
BEGIN
Cmd (u, Bop.lock_release);
TName (u, t);
END lock_release;
BEGIN
END M3CG_BinWr.