QbeGen.def 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  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 BeginInit (mod: ARRAY OF CHAR);
  22. (* Emits an IMPLEMENTATION module's BEGIN body as `<mod>_init` and
  23. records it; main calls each at startup. *)
  24. PROCEDURE EndInit;
  25. PROCEDURE BeginBody;
  26. (* Emits "export function w $main() {@start" (once). *)
  27. PROCEDURE EndModule (name: ARRAY OF CHAR);
  28. (* Return sequence, hoisted data, then writes the whole image to
  29. gen_ssa/<name>.ssa (name = program module). *)
  30. PROCEDURE DelayBegin;
  31. PROCEDURE DelayEnd;
  32. PROCEDURE DelayFlush;
  33. (* Short-circuit AND/OR: DelayBegin buffers the RHS operand's code,
  34. DelayEnd restores output, DelayFlush replays the buffer where the
  35. branch needs it. *)
  36. PROCEDURE Slot4 (VAR s: QVal);
  37. (* s := fresh 4-byte stack slot (address).
  38. Used to merge short-circuit AND/OR results: each branch stores into
  39. the slot and the merge block loads it — robust regardless of how
  40. many blocks the RHS operand's code spans. *)
  41. PROCEDURE StoreW (slot: ARRAY OF CHAR; val: ARRAY OF CHAR);
  42. PROCEDURE LoadW (slot: ARRAY OF CHAR; VAR q: QVal);
  43. PROCEDURE SetNoEmit (b: BOOLEAN);
  44. (* Suppresses all output while TRUE (nested procedures in 4.1:
  45. SymTab tracks, QbeGen stays silent). *)
  46. PROCEDURE SaveSession;
  47. PROCEDURE RestoreSession;
  48. (* Snapshot/restore the session counters (Lower per-unit emit). *)
  49. PROCEDURE SetModule (name: ARRAY OF CHAR);
  50. (* Names the module being compiled; its globals emit as
  51. "<mod>_<name>" so separate modules never collide. *)
  52. PROCEDURE Mangled (pname: ARRAY OF CHAR; uid: CARDINAL; VAR q: QVal);
  53. (* q := "name_uid" (function symbols; same-named methods never
  54. collide; deterministic). *)
  55. PROCEDURE BeginFunc (mangled: ARRAY OF CHAR);
  56. (* Opens function context (locals cleared, header buffering). *)
  57. PROCEDURE SetFuncRes (t: INTEGER);
  58. (* Sets the buffered header's result class. *)
  59. PROCEDURE FuncParam (name: ARRAY OF CHAR; isVar: BOOLEAN;
  60. t: INTEGER): BOOLEAN;
  61. (* Records one formal (FALSE past 64 → 233). Header class 'l'
  62. for all composites; entry copies restore value semantics. *)
  63. PROCEDURE EndFuncHeader;
  64. (* Emits the header + body label + entry copies (params to slots). *)
  65. PROCEDURE AbortFunc;
  66. (* Discards function context without emitting (DefUnit headings,
  67. FORWARD, methods, nested-in-4.1). *)
  68. PROCEDURE EndFunc (resT: INTEGER);
  69. (* Default return by result class, close, leave function context. *)
  70. PROCEDURE EmitRet (q: ARRAY OF CHAR; hasVal: BOOLEAN);
  71. (* Emits "ret q" (or dummy "ret 0"); always a terminator. *)
  72. PROCEDURE ProcAddr (mangled: ARRAY OF CHAR; VAR q: QVal);
  73. (* q := "$<mangled>" — a procedure's code address as a value (for
  74. assigning a procedure to a procedure variable). *)
  75. PROCEDURE VirtCallBegin (obj: ARRAY OF CHAR; slot: INTEGER; resT: INTEGER);
  76. (* Begin a virtual (vtable) call: dispatch through obj's slot. *)
  77. PROCEDURE ArmRecv (q: ARRAY OF CHAR);
  78. (* Arms the receiver for the next class-method call (CallBegin passes
  79. it as the hidden first argument). *)
  80. PROCEDURE CallBegin (mangled: ARRAY OF CHAR; resT: INTEGER;
  81. fdep: CARDINAL; isExt: BOOLEAN);
  82. (* Starts accumulating a call's actuals; resolves the static link
  83. from the caller's context and the callee's lexical depth.
  84. External (C) callees get no static link. *)
  85. PROCEDURE CallBeginInd (callee: ARRAY OF CHAR; resT: INTEGER;
  86. isExt: BOOLEAN);
  87. (* Indirect call through the code pointer `callee`. The static link
  88. is 0 (top-level procedure values; nested values are not yet
  89. supported). resT/isExt describe the signature. *)
  90. PROCEDURE CallArg (q: ARRAY OF CHAR; cls: CHAR): BOOLEAN;
  91. (* Appends one typed actual (FALSE when full → 233). *)
  92. PROCEDURE CallEnd (wantRes: BOOLEAN; VAR q: QVal);
  93. (* Emits the call (result temp in q when wanted). *)
  94. PROCEDURE InitStack (addr: ARRAY OF CHAR; t: INTEGER);
  95. (* Like InitHeap but nested objects go to stack slots. *)
  96. PROCEDURE ArgClass (t: INTEGER): CHAR;
  97. (* Formal/actual class for call emission. *)
  98. PROCEDURE CArg (q: ARRAY OF CHAR; t: INTEGER; VAR out: QVal;
  99. VAR cls: CHAR);
  100. (* Prepare actual q (of type t) for a C varargs callee: a string or
  101. CHAR array becomes descriptor+8 (a C char pointer); otherwise q
  102. passes through by its natural class. *)
  103. PROCEDURE CArgAdd (q: ARRAY OF CHAR; t: INTEGER; VAR out: QVal;
  104. VAR cls: CHAR);
  105. (* Like CArg but appends the actual to the pending call. *)
  106. PROCEDURE LocFull (): BOOLEAN;
  107. (* TRUE past 64 locals in the current scope (→ 233). *)
  108. PROCEDURE NewTemp (VAR t: QVal);
  109. (* Fresh "%tN" operand (deterministic counter: fixpoint-safe). *)
  110. PROCEDURE NewLabel (VAR l: QVal);
  111. (* Fresh "@LN" label (deterministic counter). *)
  112. PROCEDURE EmitLabel (l: ARRAY OF CHAR);
  113. PROCEDURE Jmp (l: ARRAY OF CHAR);
  114. PROCEDURE Jnz (c, t, f: ARRAY OF CHAR);
  115. (* "jnz c, @t, @f". *)
  116. PROCEDURE Cmp (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal;
  117. isReal: BOOLEAN);
  118. (* Integer comparison selected by a SymTab.OpEq..OpGe code
  119. (ceqw/cnew/csltw/cslew/csgtw/csgew); q := fresh w holding 0/1.
  120. isReal reserved; step 2 passes FALSE. *)
  121. PROCEDURE CmpL (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal);
  122. (* Address comparison (ceql/cnel, =/# only); q := fresh w. *)
  123. PROCEDURE NewHeap (t: INTEGER; VAR q: QVal);
  124. (* q := malloc(HeapSize(t)) via extern call (object skeleton). *)
  125. PROCEDURE FreeHeap (v: ARRAY OF CHAR);
  126. (* call $free(l v). Shallow (nested objects leak — documented). *)
  127. PROCEDURE InitHeap (addr: ARRAY OF CHAR; t: INTEGER);
  128. (* Stores static counts and allocates nested objects recursively;
  129. elements/members otherwise garbage per Wirth. *)
  130. PROCEDURE NotQ (a: ARRAY OF CHAR; VAR q: QVal);
  131. (* q := fresh w holding "NOT a" (xor 1, a). *)
  132. PROCEDURE CapQ (a: ARRAY OF CHAR; VAR q: QVal);
  133. (* q := fresh w holding UPCASE(a): ASCII a-z mapped to A-Z. *)
  134. PROCEDURE PushLoop (exit: ARRAY OF CHAR);
  135. PROCEDURE PopLoop;
  136. PROCEDURE TopLoop (VAR exit: QVal): BOOLEAN;
  137. (* Innermost LOOP exit label; FALSE when outside any LOOP. *)
  138. PROCEDURE LoadVar (name: ARRAY OF CHAR; isReal: BOOLEAN; VAR q: QVal);
  139. (* q := fresh temp holding $name (isReal reserved; step 1: FALSE). *)
  140. PROCEDURE LoadPtr (name: ARRAY OF CHAR; VAR q: QVal);
  141. (* q := fresh l temp holding the pointer $name. *)
  142. PROCEDURE LoadDesignator (name: ARRAY OF CHAR; t: INTEGER; k: INTEGER;
  143. VAR q: QVal): BOOLEAN;
  144. (* Loads a resolved designator by kind/type class (used for
  145. qualified L.x access). FALSE for kinds with no value (230). *)
  146. PROCEDURE StoreVar (name: ARRAY OF CHAR; q: ARRAY OF CHAR; isReal: BOOLEAN);
  147. (* "storew q, $name" (isReal reserved; step 1: FALSE). *)
  148. PROCEDURE StorePtr (name: ARRAY OF CHAR; q: ARRAY OF CHAR);
  149. (* "storel q, $name". *)
  150. PROCEDURE LoadLong (name: ARRAY OF CHAR; VAR q: QVal);
  151. (* q := fresh l temp holding the 64-bit value $name. *)
  152. PROCEDURE StoreLong (name: ARRAY OF CHAR; q: ARRAY OF CHAR);
  153. (* "storel q, $name" for 64-bit integers. *)
  154. PROCEDURE WidenLong (a: ARRAY OF CHAR; VAR q: QVal);
  155. (* INTEGER (w) -> LONGINT (l) via extsw. *)
  156. PROCEDURE CmpLong (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal);
  157. (* 64-bit comparison (ceql/cnel/csltl/...); q is fresh w 0/1. *)
  158. PROCEDURE Op3 (mn: ARRAY OF CHAR; res, l, r: ARRAY OF CHAR;
  159. isReal: BOOLEAN);
  160. (* "res =w mn l, r" with mn = add/sub/mul/div/rem. *)
  161. PROCEDURE AbsQ (a: ARRAY OF CHAR; VAR q: QVal; isReal: BOOLEAN);
  162. (* q := |a| (compare + negate-select). *)
  163. PROCEDURE NegQ (a: ARRAY OF CHAR; VAR q: QVal; isReal: BOOLEAN);
  164. (* q := fresh temp holding "-a". a and q must differ. *)
  165. PROCEDURE NarrowLong (a: ARRAY OF CHAR; VAR q: QVal);
  166. (* LONGINT -> INTEGER (low 32 bits). *)
  167. PROCEDURE ConvRI (a: ARRAY OF CHAR; VAR q: QVal);
  168. (* REAL -> INTEGER (truncate). *)
  169. PROCEDURE ConvRL (a: ARRAY OF CHAR; VAR q: QVal);
  170. (* REAL -> LONGINT (truncate). *)
  171. PROCEDURE ConvLR (a: ARRAY OF CHAR; VAR q: QVal);
  172. (* LONGINT -> REAL. *)
  173. PROCEDURE ConvIR (a: ARRAY OF CHAR; VAR q: QVal);
  174. (* q := fresh double holding "swtof a" (INTEGER -> REAL widening). *)
  175. PROCEDURE CopyOp (s: ARRAY OF CHAR; VAR d: ARRAY OF CHAR);
  176. PROCEDURE NoteAddr (val: ARRAY OF CHAR; addr: ARRAY OF CHAR);
  177. (* Records a value-temp → address mapping for VAR actuals. *)
  178. PROCEDURE AddrOfVal (val: ARRAY OF CHAR; VAR addr: QVal): BOOLEAN;
  179. (* Retrieves the recorded address (FALSE → actual is not an
  180. addressable designator → 233). *)
  181. PROCEDURE AddrOf (name: ARRAY OF CHAR; VAR q: QVal);
  182. (* q := "$name" descriptor-address operand. *)
  183. PROCEDURE IntStr (v: INTEGER; VAR s: QVal);
  184. PROCEDURE NormInt (s: ARRAY OF CHAR; VAR d: QVal);
  185. (* "0xFF" -> "255"; plain decimals copied through. *)
  186. PROCEDURE NormLit (s: ARRAY OF CHAR; VAR d: QVal; VAR isCh: BOOLEAN);
  187. (* Full V3 integer literal normalization:
  188. "12" -> "12" (decimal)
  189. "60B"/"60b" -> "48" (octal, suffix stripped)
  190. "0FFH"/"0ffh" -> "255" (hex)
  191. "0x1F"/"0X20" -> "31"/"32" (hex)
  192. "0C"/"03C"/"012C" -> "0"/"3"/"12" (hex, isCh := TRUE)
  193. isCh is TRUE for the character-constant C/c suffix only. *)
  194. PROCEDURE NormReal (s: ARRAY OF CHAR; VAR d: QVal);
  195. (* "3.14" -> "d_3.14" (QBE double immediates carry a d_ prefix). *)
  196. PROCEDURE CharVal (s: ARRAY OF CHAR): INTEGER;
  197. (* ORD of a 1-character literal such as 'a'. *)
  198. PROCEDURE NegFold (a: ARRAY OF CHAR; VAR q: QVal);
  199. (* Folds unary minus into a literal ("5" -> "-5"). Safe for same var. *)
  200. PROCEDURE IsImm (s: ARRAY OF CHAR): BOOLEAN;
  201. (* TRUE for literal operands (not %temporaries). *)
  202. PROCEDURE Fold2 (kind: INTEGER; a, b: ARRAY OF CHAR; VAR r: QVal): BOOLEAN;
  203. (* Constant-folds integer binary ops when both operands are signed
  204. decimal literals: kind 0=+ 1=- 2=* 3=DIV 4=MOD. r gets the result
  205. and TRUE is returned; otherwise r is untouched and FALSE. *)
  206. (* ---------------- arrays (step 3.1: length-prefixed layout) ---------------- *)
  207. (* Every array value: LONGCARD count + packed elements. Indexes and
  208. counts are LONGCARD (l) inside emitted code; immediates pass
  209. through, w-temps widen via extsw. *)
  210. PROCEDURE DeclArr (name: ARRAY OF CHAR; t: INTEGER);
  211. (* Recursive data emission for fixed arrays (`data $name = { l n,
  212. ... }`, nested levels as `$name_i`). CHAR→b, int-family/bool/
  213. enum→w, REAL→d, nested/pointer→l, all zero. *)
  214. PROCEDURE CtorBegin (t: INTEGER);
  215. (* Begin an aggregate constructor (`T{...}`): t is the (fixed) array
  216. or record type. Elements accumulate via CtorElem. *)
  217. PROCEDURE CtorElem (v: ARRAY OF CHAR);
  218. (* Append one constructor element: v is the QBE operand (a constant
  219. for a static descriptor, else a runtime temp). The element type
  220. (array element, or record field in declaration order) is derived
  221. from the constructor's type and position. *)
  222. PROCEDURE CtorEnd (VAR q: QVal);
  223. (* Finish the constructor; q := "$ctoN" (a pooled static descriptor)
  224. when every element is constant, else a runtime-built descriptor
  225. address. *)
  226. PROCEDURE DeclStr (text: ARRAY OF CHAR; VAR q: QVal);
  227. (* Emits `data $strN = { l len, b ... }` for a quoted literal and
  228. returns its address operand. Deterministic counter. *)
  229. PROCEDURE DeclUStr (text: ARRAY OF CHAR; VAR q: QVal;
  230. VAR single: BOOLEAN; VAR cp: INTEGER;
  231. VAR ok: BOOLEAN);
  232. (* Strict RFC3629-decode a `U'...'`/`U"..."` lexeme. one codepoint ->
  233. single=TRUE, cp=it; otherwise a UString descriptor ($ustrN) in q.
  234. ok=FALSE on invalid UTF-8 (caller reports 234). *)
  235. PROCEDURE DeclCharStr (ch: ARRAY OF CHAR; VAR q: QVal);
  236. (* ch is the decimal ordinal of a CHAR literal; emits the equivalent
  237. 1-character string descriptor and returns its address. Lets a
  238. 1-char string literal be passed to an ARRAY OF CHAR formal. *)
  239. PROCEDURE WidenIndex (idx: ARRAY OF CHAR; VAR q: QVal);
  240. (* Immediates copy through; w-temps widen via extsw to l. *)
  241. PROCEDURE OpenHi (base: ARRAY OF CHAR; VAR q: QVal);
  242. (* q := loadl(base) - 1 in l (open-array upper bound). *)
  243. PROCEDURE OpenHiChar (base: ARRAY OF CHAR; VAR q: QVal);
  244. (* q := loadl(base) in l (CHAR arrays allow index = count: the NUL
  245. terminator slot). *)
  246. PROCEDURE LoadCount (base: ARRAY OF CHAR; VAR q: QVal);
  247. (* q := loadl(base) in l (open-array element count). *)
  248. PROCEDURE CheckRange (idx, lo, hi: ARRAY OF CHAR);
  249. (* Trap unless lo <= idx <= hi (l-domain operands). *)
  250. PROCEDURE ElemAddr (base, idx, lo: ARRAY OF CHAR; elemT: INTEGER;
  251. VAR q: QVal);
  252. (* q := base + 8 + (idx - lo) * elemSizeOf(elemT's array) in l.
  253. elemT is the array descriptor (open or fixed). *)
  254. PROCEDURE ElemLoad (addr: ARRAY OF CHAR; t: INTEGER; VAR q: QVal);
  255. PROCEDURE ElemStore (addr, v: ARRAY OF CHAR; t: INTEGER);
  256. (* Element access by element-type index (CHAR→loadub … nested→loadl). *)
  257. PROCEDURE Op3L (mn: ARRAY OF CHAR; res, l, r: ARRAY OF CHAR);
  258. (* "=l mn l, r" (address/count arithmetic). *)
  259. PROCEDURE CopyArray (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  260. t: INTEGER);
  261. (* Whole-array copy with runtime count check + blit, recursive for
  262. nested levels via a runtime loop. Counts mismatch traps. *)
  263. PROCEDURE HaltQ;
  264. (* HALT: terminate the process via exit(1) (noreturn). *)
  265. PROCEDURE Trap;
  266. (* call $abort(); hlt. Interim trap until runtime/syslib/Trap;
  267. sets the dead flag (terminator). *)
  268. (* ---------------- sets (step 3.3: multi-word masks, no header) ---------------- *)
  269. (* Set values are memory addresses (globals or alloc8 temps holding
  270. W words). All counts static; bit positions runtime-checked. *)
  271. PROCEDURE DeclSet (name: ARRAY OF CHAR; t: INTEGER);
  272. (* `data $name = { w 0, ... }` with SetWords(t) words (fallback
  273. single word when unsuitable — grammar already 230'd it). *)
  274. PROCEDURE NewSetTemp (words: CARDINAL; VAR q: QVal);
  275. (* Fresh alloc8 stack slot for a set value; q is its address. *)
  276. PROCEDURE SetZero (addr: ARRAY OF CHAR; words: CARDINAL);
  277. (* Zeroes W words at addr. *)
  278. PROCEDURE SetBit (addr: ARRAY OF CHAR; val: ARRAY OF CHAR;
  279. lo: INTEGER; span: CARDINAL);
  280. (* ORs one element in: bit = val - lo, trapped outside [0, span). *)
  281. PROCEDURE SetClearBit (addr: ARRAY OF CHAR; val: ARRAY OF CHAR;
  282. lo: INTEGER; span: CARDINAL);
  283. (* ANDs one element out (EXCL): bit = val - lo, trapped outside
  284. [0, span). *)
  285. PROCEDURE SetShift (src: ARRAY OF CHAR; n: ARRAY OF CHAR;
  286. words: CARDINAL; span: CARDINAL; isRot: BOOLEAN;
  287. VAR q: QVal);
  288. (* q := src shifted (SHIFT) or rotated (ROTATE) by n bit positions
  289. (a new set temp). *)
  290. PROCEDURE SetRange (addr: ARRAY OF CHAR; a: ARRAY OF CHAR;
  291. b: ARRAY OF CHAR; lo: INTEGER; span: CARDINAL);
  292. (* ORs every value in [a..b] (empty when inverted): ends trapped
  293. in span, then a w-domain counter loop over SetBit. *)
  294. PROCEDURE SetBinOp (sel: INTEGER; l: ARRAY OF CHAR; r: ARRAY OF CHAR;
  295. lw, rw: CARDINAL; VAR q: QVal);
  296. (* sel 0 union / 1 intersection / 2 difference / 3 symdiff over
  297. possibly different spans (overlap via op, extras copied or
  298. zeroed); result has max words, q is its address. *)
  299. PROCEDURE StrEq (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal);
  300. (* String equality (`=`/`OpNeq`) via the shim; result BOOLEAN. *)
  301. PROCEDURE StrAssign (dst, src: ARRAY OF CHAR);
  302. (* Content copy of a string into a CHAR array (NUL-terminated). *)
  303. PROCEDURE StrFold (a, b: ARRAY OF CHAR; clsA, clsB: INTEGER;
  304. VAR q: QVal; VAR ok: BOOLEAN);
  305. (* Constant-fold `a + b` when both operands are string literals
  306. (descriptors) or CHAR immediates: q := a fresh literal descriptor
  307. and ok := TRUE; ok := FALSE when either operand is not constant. *)
  308. PROCEDURE UAssign (dst, src: ARRAY OF CHAR);
  309. (* Content copy of a U"..." descriptor into a UCHAR array. *)
  310. PROCEDURE UStrLen (s: ARRAY OF CHAR; VAR q: QVal);
  311. (* q := the UString codepoint count (INTEGER). *)
  312. PROCEDURE DecQ (VAR q: QVal);
  313. (* q := q - 1 (l domain). *)
  314. PROCEDURE UStrCat (a, b: ARRAY OF CHAR; VAR q: QVal);
  315. (* q := a + b in the shim's UString concat buffer. *)
  316. PROCEDURE UStrFrom (cp: ARRAY OF CHAR; VAR q: QVal);
  317. (* q := a 1-codepoint UString descriptor for the UCHAR value cp. *)
  318. PROCEDURE StrCat (a, b: ARRAY OF CHAR; VAR q: QVal);
  319. (* q := a + b in the shim's concat buffer (a descriptor address). *)
  320. PROCEDURE CmpSet (op: INTEGER; l: ARRAY OF CHAR; r: ARRAY OF CHAR;
  321. lw, rw: CARDINAL; VAR q: QVal);
  322. (* =/# over min words plus zero-checks on the larger side's extras;
  323. q is fresh w 0/1. op is a SymTab.OpEq/Neq code. *)
  324. PROCEDURE CopySet (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  325. dw, sw: CARDINAL);
  326. (* Copies min words via memcpy, zero-fills dst extras. *)
  327. PROCEDURE InSet (x: ARRAY OF CHAR; s: ARRAY OF CHAR; lo: INTEGER;
  328. span: CARDINAL; VAR q: QVal);
  329. (* Membership bit test with span trap; q is fresh w 0/1. *)
  330. (* ---------------- records (step 3.4: flat blobs, pointer fields) ---------------- *)
  331. (* Records are flat: scalars/sets inline, array fields as 8-byte
  332. pointers to static descriptors, nested records inline. Field
  333. offsets are static (SymTab.FieldOffset). *)
  334. PROCEDURE DeclRec (name: ARRAY OF CHAR; t: INTEGER);
  335. (* `data $name = { ... }` flat emission with per-field statics. *)
  336. PROCEDURE InFunction (): BOOLEAN;
  337. (* TRUE while a function body is open (module-level test). *)
  338. PROCEDURE RecArrayNeedsInit (n: CARDINAL; t: INTEGER): BOOLEAN;
  339. (* TRUE for an array of records/classes that (recursively) has array
  340. fields and is too large to expand inline, so its inline length words
  341. must be initialised at run time (DeclRecTemplate + InitRecArray). *)
  342. PROCEDURE DeclRecTemplate (varName: ARRAY OF CHAR; rec: INTEGER);
  343. (* Emits a one-record template ($<mod>_<varName>_tmpl) with the inline
  344. array-field length words set; InitRecArray copies it over each
  345. element of the compact array-of-record blob. *)
  346. PROCEDURE InitRecArray (varName: ARRAY OF CHAR; arrT: INTEGER);
  347. (* Emits the loop that value-initialises every element of
  348. $<mod>_<varName> from its template. *)
  349. PROCEDURE FieldAddr (base: ARRAY OF CHAR; off: INTEGER; VAR q: QVal);
  350. (* q := base + off in l, fresh temp. *)
  351. PROCEDURE ThisBase (VAR q: QVal);
  352. (* The current method's receiver address (hidden THIS VAR parameter). *)
  353. PROCEDURE PushWith (base: ARRAY OF CHAR);
  354. PROCEDURE PopWith;
  355. PROCEDURE TopWith (VAR base: QVal): BOOLEAN;
  356. (* Innermost WITH base address; FALSE outside any WITH. *)
  357. PROCEDURE CopyRecord (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  358. t: INTEGER);
  359. (* Deep whole-record copy: scalars/sets by load/store, arrays via
  360. CopyArray on dereferenced fields, nested records recurse. *)
  361. (* ---------------- internal helpers ---------------- *)
  362. (* Declared here so they are visible throughout the implementation
  363. (ISO Modula-2: declaration before use) without FORWARD, which the
  364. gm2 whole-program pass rejects. Not part of the backend's usable
  365. API; do not call from generated parser code. *)
  366. PROCEDURE LocFindUp (name: ARRAY OF CHAR; VAR levels: CARDINAL;
  367. VAR flat: INTEGER): BOOLEAN;
  368. PROCEDURE LocAdd (name: ARRAY OF CHAR; tag: INTEGER; rep: ARRAY OF CHAR;
  369. cls: CHAR; typ: INTEGER);
  370. PROCEDURE ResClass (t: INTEGER): CHAR;
  371. PROCEDURE AllocLocal (t: INTEGER; VAR slot: QVal);
  372. PROCEDURE HApp (s: ARRAY OF CHAR);
  373. PROCEDURE UpAddrOf (flat: INTEGER; levels: CARDINAL; VAR q: QVal);
  374. PROCEDURE Revive;
  375. PROCEDURE FlushStrings;
  376. PROCEDURE FlushCtors;
  377. PROCEDURE FindStrPos (v: ARRAY OF CHAR; VAR k: CARDINAL): BOOLEAN;
  378. (* Index of the pooled string literal named by v ($strN). *)
  379. PROCEDURE EmitVTables;
  380. (* Emit a data array per class that has virtual methods. *)
  381. PROCEDURE VtRef (t: INTEGER; VAR q: QVal);
  382. (* The class's vtable symbol ($vt_<typeindex>). *)
  383. PROCEDURE FlushUStrings;
  384. (* Emit the recorded UString literal descriptors as top-level data. *)
  385. PROCEDURE ArrData (name: ARRAY OF CHAR; t: INTEGER);
  386. PROCEDURE HeapSize (t: INTEGER): CARDINAL;
  387. END QbeGen.