QbeGen.def 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. DEFINITION MODULE QbeGen;
  2. (* Fresh QBE backend for m2compiler-V3, Step 1: minimal integer pipeline.
  3. Emits QBE SSA text to "gen_ssa/<Module>.ssa" (run the M2 driver from
  4. compiler/). Step-1 subset: INTEGER globals/CONSTs, integer
  5. expressions (+ - * DIV MOD, leading sign, parens), assignment.
  6. Every expression synthesizes a QBE operand in q (immediate like
  7. "42"/"-5" or fresh "%tN"); invalid types synthesize "0" so the
  8. .ssa stays assembleable.
  9. Test convention: a global VAR ExitCode : INTEGER makes generated
  10. $main return its value as the process exit code, else return 0. *)
  11. TYPE
  12. QVal = ARRAY [0 .. 63] OF CHAR;
  13. PROCEDURE OpenModule (name: ARRAY OF CHAR);
  14. (* Opens gen_ssa/<name>.ssa, resets counters. *)
  15. PROCEDURE DeclVar (name: ARRAY OF CHAR; t: INTEGER);
  16. (* Emits "data $name = { w 0 }". t is a SymTab.TypeIndex (reserved
  17. for later steps; step 1 only sees INTEGER). *)
  18. PROCEDURE DeclConst (name: ARRAY OF CHAR; val: ARRAY OF CHAR; t: INTEGER);
  19. (* Emits "data $name = { w val }" for literal val, else a 0
  20. placeholder (caller reports 230). *)
  21. PROCEDURE BeginBody;
  22. (* Emits "export function w $main() {@start" (once). *)
  23. PROCEDURE EndModule;
  24. (* Return sequence (via ExitCode when present), close file. *)
  25. PROCEDURE CloseModule;
  26. (* Closes the .ssa without emitting a function (units whose
  27. lowering waits for step 4: definitions, implementations,
  28. and any unit containing nested modules). *)
  29. PROCEDURE SetNoEmit (b: BOOLEAN);
  30. (* Suppresses all output while TRUE (nested procedures in 4.1:
  31. SymTab tracks, QbeGen stays silent). *)
  32. PROCEDURE Mangled (pname: ARRAY OF CHAR; uid: CARDINAL; VAR q: QVal);
  33. (* q := "name_uid" (function symbols; same-named methods never
  34. collide; deterministic). *)
  35. PROCEDURE BeginFunc (mangled: ARRAY OF CHAR);
  36. (* Opens function context (locals cleared, header buffering). *)
  37. PROCEDURE SetFuncRes (t: INTEGER);
  38. (* Sets the buffered header's result class. *)
  39. PROCEDURE FuncParam (name: ARRAY OF CHAR; isVar: BOOLEAN;
  40. t: INTEGER): BOOLEAN;
  41. (* Records one formal (FALSE past 64 → 233). Header class 'l'
  42. for all composites; entry copies restore value semantics. *)
  43. PROCEDURE EndFuncHeader;
  44. (* Emits the header + body label + entry copies (params to slots). *)
  45. PROCEDURE AbortFunc;
  46. (* Discards function context without emitting (DefUnit headings,
  47. FORWARD, methods, nested-in-4.1). *)
  48. PROCEDURE EndFunc (resT: INTEGER);
  49. (* Default return by result class, close, leave function context. *)
  50. PROCEDURE EmitRet (q: ARRAY OF CHAR; hasVal: BOOLEAN);
  51. (* Emits "ret q" (or dummy "ret 0"); always a terminator. *)
  52. PROCEDURE CallBegin (mangled: ARRAY OF CHAR; resT: INTEGER;
  53. fdep: CARDINAL);
  54. (* Starts accumulating a call's actuals; resolves the static link
  55. from the caller's context and the callee's lexical depth. *)
  56. PROCEDURE CallArg (q: ARRAY OF CHAR; cls: CHAR): BOOLEAN;
  57. (* Appends one typed actual (FALSE when full → 233). *)
  58. PROCEDURE CallEnd (wantRes: BOOLEAN; VAR q: QVal);
  59. (* Emits the call (result temp in q when wanted). *)
  60. PROCEDURE InitStack (addr: ARRAY OF CHAR; t: INTEGER);
  61. (* Like InitHeap but nested objects go to stack slots. *)
  62. PROCEDURE ArgClass (t: INTEGER): CHAR;
  63. (* Formal/actual class for call emission. *)
  64. PROCEDURE LocFull (): BOOLEAN;
  65. (* TRUE past 64 locals in the current scope (→ 233). *)
  66. PROCEDURE NewTemp (VAR t: QVal);
  67. (* Fresh "%tN" operand (deterministic counter: fixpoint-safe). *)
  68. PROCEDURE NewLabel (VAR l: QVal);
  69. (* Fresh "@LN" label (deterministic counter). *)
  70. PROCEDURE EmitLabel (l: ARRAY OF CHAR);
  71. PROCEDURE Jmp (l: ARRAY OF CHAR);
  72. PROCEDURE Jnz (c, t, f: ARRAY OF CHAR);
  73. (* "jnz c, @t, @f". *)
  74. PROCEDURE Cmp (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal;
  75. isReal: BOOLEAN);
  76. (* Integer comparison selected by a SymTab.OpEq..OpGe code
  77. (ceqw/cnew/csltw/cslew/csgtw/csgew); q := fresh w holding 0/1.
  78. isReal reserved; step 2 passes FALSE. *)
  79. PROCEDURE CmpL (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal);
  80. (* Address comparison (ceql/cnel, =/# only); q := fresh w. *)
  81. PROCEDURE NewHeap (t: INTEGER; VAR q: QVal);
  82. (* q := malloc(HeapSize(t)) via extern call (object skeleton). *)
  83. PROCEDURE FreeHeap (v: ARRAY OF CHAR);
  84. (* call $free(l v). Shallow (nested objects leak — documented). *)
  85. PROCEDURE InitHeap (addr: ARRAY OF CHAR; t: INTEGER);
  86. (* Stores static counts and allocates nested objects recursively;
  87. elements/members otherwise garbage per Wirth. *)
  88. PROCEDURE NotQ (a: ARRAY OF CHAR; VAR q: QVal);
  89. (* q := fresh w holding "NOT a" (xor 1, a). *)
  90. PROCEDURE PushLoop (exit: ARRAY OF CHAR);
  91. PROCEDURE PopLoop;
  92. PROCEDURE TopLoop (VAR exit: QVal): BOOLEAN;
  93. (* Innermost LOOP exit label; FALSE when outside any LOOP. *)
  94. PROCEDURE LoadVar (name: ARRAY OF CHAR; isReal: BOOLEAN; VAR q: QVal);
  95. (* q := fresh temp holding $name (isReal reserved; step 1: FALSE). *)
  96. PROCEDURE LoadPtr (name: ARRAY OF CHAR; VAR q: QVal);
  97. (* q := fresh l temp holding the pointer $name. *)
  98. PROCEDURE StoreVar (name: ARRAY OF CHAR; q: ARRAY OF CHAR; isReal: BOOLEAN);
  99. (* "storew q, $name" (isReal reserved; step 1: FALSE). *)
  100. PROCEDURE StorePtr (name: ARRAY OF CHAR; q: ARRAY OF CHAR);
  101. (* "storel q, $name". *)
  102. PROCEDURE Op3 (mn: ARRAY OF CHAR; res, l, r: ARRAY OF CHAR;
  103. isReal: BOOLEAN);
  104. (* "res =w mn l, r" with mn = add/sub/mul/div/rem. *)
  105. PROCEDURE NegQ (a: ARRAY OF CHAR; VAR q: QVal; isReal: BOOLEAN);
  106. (* q := fresh temp holding "-a". a and q must differ. *)
  107. PROCEDURE ConvIR (a: ARRAY OF CHAR; VAR q: QVal);
  108. (* q := fresh double holding "swtof a" (INTEGER -> REAL widening). *)
  109. PROCEDURE CopyOp (s: ARRAY OF CHAR; VAR d: ARRAY OF CHAR);
  110. PROCEDURE NoteAddr (val: ARRAY OF CHAR; addr: ARRAY OF CHAR);
  111. (* Records a value-temp → address mapping for VAR actuals. *)
  112. PROCEDURE AddrOfVal (val: ARRAY OF CHAR; VAR addr: QVal): BOOLEAN;
  113. (* Retrieves the recorded address (FALSE → actual is not an
  114. addressable designator → 233). *)
  115. PROCEDURE AddrOf (name: ARRAY OF CHAR; VAR q: QVal);
  116. (* q := "$name" descriptor-address operand. *)
  117. PROCEDURE IntStr (v: INTEGER; VAR s: QVal);
  118. PROCEDURE NormInt (s: ARRAY OF CHAR; VAR d: QVal);
  119. (* "0xFF" -> "255"; plain decimals copied through. *)
  120. PROCEDURE NormLit (s: ARRAY OF CHAR; VAR d: QVal; VAR isCh: BOOLEAN);
  121. (* Full V3 integer literal normalization:
  122. "12" -> "12" (decimal)
  123. "60B"/"60b" -> "48" (octal, suffix stripped)
  124. "0FFH"/"0ffh" -> "255" (hex)
  125. "0x1F"/"0X20" -> "31"/"32" (hex)
  126. "0C"/"03C"/"012C" -> "0"/"3"/"12" (hex, isCh := TRUE)
  127. isCh is TRUE for the character-constant C/c suffix only. *)
  128. PROCEDURE NormReal (s: ARRAY OF CHAR; VAR d: QVal);
  129. (* "3.14" -> "d_3.14" (QBE double immediates carry a d_ prefix). *)
  130. PROCEDURE CharVal (s: ARRAY OF CHAR): INTEGER;
  131. (* ORD of a 1-character literal such as 'a'. *)
  132. PROCEDURE NegFold (a: ARRAY OF CHAR; VAR q: QVal);
  133. (* Folds unary minus into a literal ("5" -> "-5"). Safe for same var. *)
  134. PROCEDURE IsImm (s: ARRAY OF CHAR): BOOLEAN;
  135. (* TRUE for literal operands (not %temporaries). *)
  136. PROCEDURE Remark (s: ARRAY OF CHAR);
  137. (* Emits a "# s" comment line. *)
  138. (* ---------------- arrays (step 3.1: length-prefixed layout) ---------------- *)
  139. (* Every array value: LONGCARD count + packed elements. Indexes and
  140. counts are LONGCARD (l) inside emitted code; immediates pass
  141. through, w-temps widen via extsw. *)
  142. PROCEDURE DeclArr (name: ARRAY OF CHAR; t: INTEGER);
  143. (* Recursive data emission for fixed arrays (`data $name = { l n,
  144. ... }`, nested levels as `$name_i`). CHAR→b, int-family/bool/
  145. enum→w, REAL→d, nested/pointer→l, all zero. *)
  146. PROCEDURE DeclStr (text: ARRAY OF CHAR; VAR q: QVal);
  147. (* Emits `data $strN = { l len, b ... }` for a quoted literal and
  148. returns its address operand. Deterministic counter. *)
  149. PROCEDURE WidenIndex (idx: ARRAY OF CHAR; VAR q: QVal);
  150. (* Immediates copy through; w-temps widen via extsw to l. *)
  151. PROCEDURE OpenHi (base: ARRAY OF CHAR; VAR q: QVal);
  152. (* q := loadl(base) - 1 in l (open-array upper bound). *)
  153. PROCEDURE CheckRange (idx, lo, hi: ARRAY OF CHAR);
  154. (* Trap unless lo <= idx <= hi (l-domain operands). *)
  155. PROCEDURE ElemAddr (base, idx, lo: ARRAY OF CHAR; elemT: INTEGER;
  156. VAR q: QVal);
  157. (* q := base + 8 + (idx - lo) * elemSizeOf(elemT's array) in l.
  158. elemT is the array descriptor (open or fixed). *)
  159. PROCEDURE ElemLoad (addr: ARRAY OF CHAR; t: INTEGER; VAR q: QVal);
  160. PROCEDURE ElemStore (addr, v: ARRAY OF CHAR; t: INTEGER);
  161. (* Element access by element-type index (CHAR→loadub … nested→loadl). *)
  162. PROCEDURE Op3L (mn: ARRAY OF CHAR; res, l, r: ARRAY OF CHAR);
  163. (* "=l mn l, r" (address/count arithmetic). *)
  164. PROCEDURE CopyArray (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  165. t: INTEGER);
  166. (* Whole-array copy with runtime count check + blit, recursive for
  167. nested levels via a runtime loop. Counts mismatch traps. *)
  168. PROCEDURE Trap;
  169. (* call $abort(); hlt. Interim trap until runtime/syslib/Trap;
  170. sets the dead flag (terminator). *)
  171. (* ---------------- sets (step 3.3: multi-word masks, no header) ---------------- *)
  172. (* Set values are memory addresses (globals or alloc8 temps holding
  173. W words). All counts static; bit positions runtime-checked. *)
  174. PROCEDURE DeclSet (name: ARRAY OF CHAR; t: INTEGER);
  175. (* `data $name = { w 0, ... }` with SetWords(t) words (fallback
  176. single word when unsuitable — grammar already 230'd it). *)
  177. PROCEDURE NewSetTemp (words: CARDINAL; VAR q: QVal);
  178. (* Fresh alloc8 stack slot for a set value; q is its address. *)
  179. PROCEDURE SetZero (addr: ARRAY OF CHAR; words: CARDINAL);
  180. (* Zeroes W words at addr. *)
  181. PROCEDURE SetBit (addr: ARRAY OF CHAR; val: ARRAY OF CHAR;
  182. lo: INTEGER; span: CARDINAL);
  183. (* ORs one element in: bit = val - lo, trapped outside [0, span). *)
  184. PROCEDURE SetRange (addr: ARRAY OF CHAR; a: ARRAY OF CHAR;
  185. b: ARRAY OF CHAR; lo: INTEGER; span: CARDINAL);
  186. (* ORs every value in [a..b] (empty when inverted): ends trapped
  187. in span, then a w-domain counter loop over SetBit. *)
  188. PROCEDURE SetBinOp (sel: INTEGER; l: ARRAY OF CHAR; r: ARRAY OF CHAR;
  189. lw, rw: CARDINAL; VAR q: QVal);
  190. (* sel 0 union / 1 intersection / 2 difference / 3 symdiff over
  191. possibly different spans (overlap via op, extras copied or
  192. zeroed); result has max words, q is its address. *)
  193. PROCEDURE CmpSet (op: INTEGER; l: ARRAY OF CHAR; r: ARRAY OF CHAR;
  194. lw, rw: CARDINAL; VAR q: QVal);
  195. (* =/# over min words plus zero-checks on the larger side's extras;
  196. q is fresh w 0/1. op is a SymTab.OpEq/Neq code. *)
  197. PROCEDURE CopySet (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  198. dw, sw: CARDINAL);
  199. (* Copies min words via memcpy, zero-fills dst extras. *)
  200. PROCEDURE InSet (x: ARRAY OF CHAR; s: ARRAY OF CHAR; lo: INTEGER;
  201. span: CARDINAL; VAR q: QVal);
  202. (* Membership bit test with span trap; q is fresh w 0/1. *)
  203. (* ---------------- records (step 3.4: flat blobs, pointer fields) ---------------- *)
  204. (* Records are flat: scalars/sets inline, array fields as 8-byte
  205. pointers to static descriptors, nested records inline. Field
  206. offsets are static (SymTab.FieldOffset). *)
  207. PROCEDURE DeclRec (name: ARRAY OF CHAR; t: INTEGER);
  208. (* `data $name = { ... }` flat emission with per-field statics. *)
  209. PROCEDURE FieldAddr (base: ARRAY OF CHAR; off: INTEGER; VAR q: QVal);
  210. (* q := base + off in l, fresh temp. *)
  211. PROCEDURE PushWith (base: ARRAY OF CHAR);
  212. PROCEDURE PopWith;
  213. PROCEDURE TopWith (VAR base: QVal): BOOLEAN;
  214. (* Innermost WITH base address; FALSE outside any WITH. *)
  215. PROCEDURE CopyRecord (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  216. t: INTEGER);
  217. (* Deep whole-record copy: scalars/sets by load/store, arrays via
  218. CopyArray on dereferenced fields, nested records recurse. *)
  219. END QbeGen.