MODULE------------------------------------------------------------------- I/O ---; 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; FROM M3CG IMPORT MemoryOrder; 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; store_ordered := store_ordered; load_ordered := load_ordered; exchange := exchange; compare_exchange := compare_exchange; fence := fence; fetch_and_op := fetch_and_op; END; M3CG_BinWr
PROCEDURE--------------------------------------------------------- low level I/O ---Cmd (u: U; cmd: Bop) = BEGIN OutI (u, ORD (cmd)); END Cmd; PROCEDUREZName (u: U; n: Name) = BEGIN IF (n = M3ID.NoID) THEN OutI (u, -1); ELSE Txt (u, M3ID.ToText (n)); END; END ZName; PROCEDUREVName (u: U; v: Var) = BEGIN TYPECASE v OF | NULL => OutI (u, 0); | WrVar(x) => OutI (u, x.tag); ELSE <*ASSERT FALSE*> END; END VName; PROCEDUREPName (u: U; p: Proc) = BEGIN TYPECASE p OF | NULL => OutI (u, 0); | WrProc(x) => OutI (u, x.tag); ELSE <*ASSERT FALSE*> END; END PName; PROCEDURETName (u: U; t: Type) = BEGIN OutI (u, ORD (t)); END TName; PROCEDUREFlt (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; PROCEDUREBool (u: U; b: BOOLEAN) = BEGIN OutI (u, ORD (b)); END Bool; PROCEDURELab (u: U; i: Label) = BEGIN OutI (u, i); END Lab; PROCEDURETipe (u: U; t: TypeUID) = BEGIN OutI (u, t); END Tipe; PROCEDUREInt (u: U; i: INTEGER) = BEGIN OutI (u, i); END Int; PROCEDURETInt (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; PROCEDUREBInt (u: U; i: INTEGER) = BEGIN OutI (u, i); END BInt; PROCEDURETxt (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;
PROCEDURE---------------------------------------------------------------------------Flush (u: U) = BEGIN M3Buf.Flush (u.buf, u.wr); u.buf_len := 0; END Flush; PROCEDUREOutI (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; PROCEDUREAddBigInt (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; PROCEDUREAddBigX (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; PROCEDUREDumpInt (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----------------------------------------------------------- ID counters ---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;
PROCEDURE------------------------------------------------ READONLY configuration ---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;
PROCEDURE----------------------------------------------------- compilation units ---set_error_handler (<*UNUSED*> u: U; <*UNUSED*> p: M3CG_Ops.ErrorHandler) = BEGIN (* skip -- we don't generate any errors *) END set_error_handler;
PROCEDURE------------------------------------------------ debugging line numbers ---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; PROCEDUREend_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; PROCEDUREimport_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; PROCEDUREexport_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;
PROCEDURE------------------------------------------- debugging type declarations ---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; PROCEDUREset_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;
PROCEDURE--------------------------------------------------------- runtime hooks ---declare_typename (u: U; t: TypeUID; n: Name) = BEGIN Cmd (u, Bop.declare_typename); Tipe (u, t); ZName (u, n); END declare_typename; PROCEDUREdeclare_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; PROCEDUREdeclare_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; PROCEDUREdeclare_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; PROCEDUREdeclare_enum_elt (u: U; n: Name) = BEGIN Cmd (u, Bop.declare_enum_elt); ZName (u, n); END declare_enum_elt; PROCEDUREdeclare_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; PROCEDUREdeclare_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; PROCEDUREdeclare_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; PROCEDUREdeclare_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; PROCEDUREdeclare_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; PROCEDUREdeclare_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; PROCEDUREdeclare_indirect (u: U; t, target: TypeUID) = BEGIN Cmd (u, Bop.declare_indirect); Tipe (u, t); Tipe (u, target); END declare_indirect; PROCEDUREdeclare_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; PROCEDUREdeclare_formal (u: U; n: Name; t: TypeUID) = BEGIN Cmd (u, Bop.declare_formal); ZName (u, n); Tipe (u, t); END declare_formal; PROCEDUREdeclare_raises (u: U; n: Name) = BEGIN Cmd (u, Bop.declare_raises); ZName (u, n); END declare_raises; PROCEDUREdeclare_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; PROCEDUREdeclare_method (u: U; n: Name; signature: TypeUID) = BEGIN Cmd (u, Bop.declare_method); ZName (u, n); Tipe (u, signature); END declare_method; PROCEDUREdeclare_opaque (u: U; t, super: TypeUID) = BEGIN Cmd (u, Bop.declare_opaque); Tipe (u, t); Tipe (u, super); END declare_opaque; PROCEDUREreveal_opaque (u: U; lhs, rhs: TypeUID) = BEGIN Cmd (u, Bop.reveal_opaque); Tipe (u, lhs); Tipe (u, rhs); END reveal_opaque; PROCEDUREdeclare_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;
PROCEDURE------------------------------------------------- variable declarations ---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; PROCEDUREset_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; PROCEDUREset_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; PROCEDUREget_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;
PROCEDURE---------------------------------------- static variable initialization ---NewVar (u: U): Var = VAR v := NEW (WrVar, tag := u.next_var); BEGIN INC (u.next_var); RETURN v; END NewVar; PROCEDUREimport_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; PROCEDUREdeclare_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; PROCEDUREbind_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; PROCEDUREdeclare_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; PROCEDUREdeclare_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; PROCEDUREdeclare_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; PROCEDUREdeclare_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; PROCEDUREdeclare_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; PROCEDUREfree_temp (u: U; v: Var) = BEGIN Cmd (u, Bop.free_temp); VName (u, v); END free_temp;
PROCEDURE------------------------------------------------------------ procedures ---begin_init (u: U; v: Var) = BEGIN Cmd (u, Bop.begin_init); VName (u, v); END begin_init; PROCEDUREend_init (u: U; v: Var) = BEGIN Cmd (u, Bop.end_init); VName (u, v); END end_init; PROCEDUREinit_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; PROCEDUREinit_proc (u: U; o: ByteOffset; value: Proc) = BEGIN Cmd (u, Bop.init_proc); Int (u, o); PName (u, value); END init_proc; PROCEDUREinit_label (u: U; o: ByteOffset; value: Label) = BEGIN Cmd (u, Bop.init_label); Int (u, o); Lab (u, value); END init_label; PROCEDUREinit_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; PROCEDUREinit_offset (u: U; o: ByteOffset; value: Var) = BEGIN Cmd (u, Bop.init_offset); Int (u, o); VName (u, value); END init_offset; PROCEDUREinit_chars (u: U; o: ByteOffset; value: TEXT) = BEGIN Cmd (u, Bop.init_chars); Int (u, o); Txt (u, value); END init_chars; PROCEDUREinit_float (u: U; o: ByteOffset; READONLY f: Target.Float) = BEGIN Cmd (u, Bop.init_float); Int (u, o); Flt (u, f); END init_float;
PROCEDURE------------------------------------------------------------ statements ---NewProc (u: U): Proc = VAR p := NEW (WrProc, tag := u.next_proc); BEGIN INC (u.next_proc); RETURN p; END NewProc; PROCEDUREimport_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; PROCEDUREdeclare_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; PROCEDUREbegin_procedure (u: U; p: Proc) = BEGIN Cmd (u, Bop.begin_procedure); PName (u, p); END begin_procedure; PROCEDUREend_procedure (u: U; p: Proc) = BEGIN Cmd (u, Bop.end_procedure); PName (u, p); END end_procedure; PROCEDUREbegin_block (u: U) = (* marks the beginning of a nested anonymous block *) BEGIN Cmd (u, Bop.begin_block); END begin_block; PROCEDUREend_block (u: U) = (* marks the ending of a nested anonymous block *) BEGIN Cmd (u, Bop.end_block); END end_block; PROCEDUREnote_procedure_origin (u: U; p: Proc) = BEGIN Cmd (u, Bop.note_procedure_origin); PName (u, p); END note_procedure_origin;
PROCEDURE------------------------------------------------------------ load/store ---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; PROCEDUREjump (u: U; l: Label) = (* GOTO l *) BEGIN Cmd (u, Bop.jump); Lab (u, l); END jump; PROCEDUREif_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; PROCEDUREif_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; PROCEDUREif_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; PROCEDUREcase_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; PROCEDUREexit_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;
PROCEDURE-------------------------------------------------------------- literals ---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; PROCEDUREstore (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; PROCEDUREload_address (u: U; v: Var; o: ByteOffset) = BEGIN Cmd (u, Bop.load_address); VName (u, v); Int (u, o); END load_address; PROCEDUREload_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; PROCEDUREstore_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;
PROCEDURE------------------------------------------------------------ arithmetic ---load_nil (u: U) = (* push ; s0.A := a *) BEGIN Cmd (u, Bop.load_nil); END load_nil; PROCEDUREload_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; PROCEDUREload_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;
PROCEDURE------------------------------------------------------------------ sets ---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; PROCEDUREadd (u: U; t: AType) = (* s1.t := s1.t + s0.t ; pop *) BEGIN Cmd (u, Bop.add); TName (u, t); END add; PROCEDUREsubtract (u: U; t: AType) = (* s1.t := s1.t - s0.t ; pop *) BEGIN Cmd (u, Bop.subtract); TName (u, t); END subtract; PROCEDUREmultiply (u: U; t: AType) = (* s1.t := s1.t * s0.t ; pop *) BEGIN Cmd (u, Bop.multiply); TName (u, t); END multiply; PROCEDUREdivide (u: U; t: RType) = (* s1.t := s1.t / s0.t ; pop *) BEGIN Cmd (u, Bop.divide); TName (u, t); END divide; PROCEDUREdiv (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; PROCEDUREmod (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; PROCEDUREnegate (u: U; t: AType) = (* s0.t := - s0.t *) BEGIN Cmd (u, Bop.negate); TName (u, t); END negate; PROCEDUREabs (u: U; t: AType) = (* s0.t := ABS (s0.t) (noop on Words) *) BEGIN Cmd (u, Bop.abs); TName (u, t); END abs; PROCEDUREmax (u: U; t: ZType) = (* s1.t := MAX (s1.t, s0.t) ; pop *) BEGIN Cmd (u, Bop.max); TName (u, t); END max; PROCEDUREmin (u: U; t: ZType) = (* s1.t := MIN (s1.t, s0.t) ; pop *) BEGIN Cmd (u, Bop.min); TName (u, t); END min; PROCEDUREcvt_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; PROCEDUREcvt_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;
PROCEDURE------------------------------------------------- Word.T bit operations ---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; PROCEDUREset_difference (u: U; s: ByteSize) = (* s1.B := s1.B - s0.B ; pop *) BEGIN Cmd (u, Bop.set_difference); Int (u, s); END set_difference; PROCEDUREset_intersection (u: U; s: ByteSize) = (* s1.B := s1.B * s0.B ; pop *) BEGIN Cmd (u, Bop.set_intersection); Int (u, s); END set_intersection; PROCEDUREset_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; PROCEDUREset_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; PROCEDUREset_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; PROCEDUREset_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; PROCEDUREset_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;
PROCEDURE------------------------------------------------ misc. stack/memory ops ---not (u: U; t: IType) = (* s0.t := Word.Not (s0.t) *) BEGIN Cmd (u, Bop.not); TName (u, t); END not; PROCEDUREand (u: U; t: IType) = (* s1.t := Word.And (s1.t, s0.t) ; pop *) BEGIN Cmd (u, Bop.and); TName (u, t); END and; PROCEDUREor (u: U; t: IType) = (* s1.t := Word.Or (s1.t, s0.t) ; pop *) BEGIN Cmd (u, Bop.or); TName (u, t); END or; PROCEDURExor (u: U; t: IType) = (* s1.t := Word.Xor (s1.t, s0.t) ; pop *) BEGIN Cmd (u, Bop.xor); TName (u, t); END xor; PROCEDUREshift (u: U; t: IType) = (* s1.t := Word.Shift (s1.t, s0.t) ; pop *) BEGIN Cmd (u, Bop.shift); TName (u, t); END shift; PROCEDUREshift_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; PROCEDUREshift_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; PROCEDURErotate (u: U; t: IType) = (* s1.t := Word.Rotate (s1.t, s0.t) ; pop *) BEGIN Cmd (u, Bop.rotate); TName (u, t); END rotate; PROCEDURErotate_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; PROCEDURErotate_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; PROCEDUREwiden (u: U; sign: BOOLEAN) = (* s0.I64 := s0.I32; IF sign THEN SignExtend s0; *) BEGIN Cmd (u, Bop.widen); Bool (u, sign); END widen; PROCEDUREchop (u: U) = (* s0.I32 := Word.And (s0.I64, 16_ffffffff); *) BEGIN Cmd (u, Bop.chop); END chop; PROCEDUREextract (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; PROCEDUREextract_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; PROCEDUREextract_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; PROCEDUREinsert (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; PROCEDUREinsert_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; PROCEDUREinsert_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;
PROCEDURE----------------------------------------------------------- conversions ---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; PROCEDUREpop (u: U; t: Type) = (* pop(1) (i.e. discard s0) *) BEGIN Cmd (u, Bop.pop); TName (u, t); END pop; PROCEDUREcopy_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; PROCEDUREcopy (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; PROCEDUREzero_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; PROCEDUREzero (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;
PROCEDURE------------------------------------------------ traps & runtime checks ---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;
PROCEDURE---------------------------------------------------- address arithmetic ---abort (u: U; code: RuntimeError) = BEGIN Cmd (u, Bop.abort); Int (u, ORD (code)); END abort; PROCEDUREcheck_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; PROCEDUREcheck_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; PROCEDUREcheck_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; PROCEDUREcheck_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; PROCEDUREcheck_index (u: U; t: IType; code: RuntimeError) = BEGIN Cmd (u, Bop.check_index); TName (u, t); Int (u, ORD (code)); END check_index; PROCEDUREcheck_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;
PROCEDURE------------------------------------------------------- procedure calls ---add_offset (u: U; i: INTEGER) = (* s0.A := s0.A + i *) BEGIN Cmd (u, Bop.add_offset); Int (u, i); END add_offset; PROCEDUREindex_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------------------------------------------- procedure and closure types ---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; PROCEDUREstart_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; PROCEDUREpop_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; PROCEDUREpop_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; PROCEDUREpop_static_link (u: U) = BEGIN Cmd (u, Bop.pop_static_link); END pop_static_link; PROCEDUREcall_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; PROCEDUREcall_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----------------------------------------------------------------- misc. ---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; PROCEDUREload_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;
PROCEDURE--------------------------------------------------------------- atomics ---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;
PROCEDUREstore_ordered (u: U; t: ZType; z: MType; order: MemoryOrder) = BEGIN Cmd (u, Bop.store_ordered); TName (u, t); TName (u, z); Int (u, ORD(order)); END store_ordered; PROCEDUREload_ordered (u: U; t: MType; z: ZType; order: MemoryOrder) = BEGIN Cmd (u, Bop.load_ordered); TName (u, t); TName (u, z); Int (u, ORD(order)); END load_ordered; PROCEDUREexchange (u: U; t: MType; z: ZType; order: MemoryOrder) = BEGIN Cmd (u, Bop.exchange); TName (u, t); TName (u, z); Int (u, ORD(order)); END exchange; PROCEDUREcompare_exchange (u: U; t: MType; z: ZType; r: IType; success, failure: MemoryOrder) = BEGIN Cmd (u, Bop.exchange); TName (u, t); TName (u, z); TName (u, r); Int (u, ORD(success)); Int (u, ORD(failure)); END compare_exchange; PROCEDUREfence (u: U; order: MemoryOrder) = BEGIN Cmd (u, Bop.fence); Int (u, ORD(order)); END fence; PROCEDUREfetch_and_op (u: U; op: AtomicOp; t: MType; z: ZType; order: MemoryOrder) = 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 }; BEGIN Cmd (u, OpName [op]); TName (u, t); TName (u, z); Int (u, ORD(order)); END fetch_and_op; BEGIN END M3CG_BinWr.