QbeGen.mod 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210
  1. IMPLEMENTATION MODULE QbeGen;
  2. IMPORT FileIO, SymTab;
  3. VAR
  4. out : FileIO.File;
  5. opened : BOOLEAN;
  6. inBody : BOOLEAN;
  7. dead : BOOLEAN; (* TRUE past a terminator: next instruction opens
  8. an unreachable block with a fresh label, so
  9. the .ssa stays valid QBE (no dangling temps,
  10. no instruction outside a block). *)
  11. nTemp : CARDINAL;
  12. nLab : CARDINAL;
  13. loopTop : CARDINAL;
  14. loopSt : ARRAY [0 .. 15] OF QVal;
  15. nR : CARDINAL; (* non-zero REAL consts flushed at BeginBody *)
  16. rNames : ARRAY [0 .. 31] OF QVal;
  17. rVals : ARRAY [0 .. 31] OF QVal;
  18. nStr : CARDINAL; (* string-literal data counter *)
  19. strNams : ARRAY [0 .. 255] OF QVal;
  20. strTexts : ARRAY [0 .. 255] OF ARRAY [0 .. 255] OF CHAR;
  21. withTop : CARDINAL;
  22. withSt : ARRAY [0 .. 7] OF QVal;
  23. noEmit : BOOLEAN; (* TRUE while parsing nested procedures in 4.1:
  24. SymTab tracks, QbeGen suppresses output *)
  25. inFunc : BOOLEAN; (* TRUE inside an emitted function body *)
  26. useStack : BOOLEAN;(* TRUE: NewHeap allocates stack slots *)
  27. funcRes : CHAR; (* current function result class *)
  28. nLoc : CARDINAL; (* function-local name table entries *)
  29. locNames : ARRAY [0 .. 255] OF SymTab.Name;
  30. locTag : ARRAY [0 .. 255] OF INTEGER; (* 0 slot, 1 data, 2 addr *)
  31. locRep : ARRAY [0 .. 255] OF QVal; (* slot temp / mangled / addr *)
  32. locCls : ARRAY [0 .. 255] OF CHAR;
  33. locTyp : ARRAY [0 .. 255] OF INTEGER;
  34. funcDepth : CARDINAL; (* open BeginFuncs; main body = 0 *)
  35. scopeTop : CARDINAL; (* open procedure scopes *)
  36. scopeBase : ARRAY [0 .. 16] OF CARDINAL;
  37. scopeLink : ARRAY [0 .. 15] OF QVal; (* per-scope link records *)
  38. slTmp : QVal; (* current static-link param temp *)
  39. hdrComma : BOOLEAN;
  40. stkLink : ARRAY [0 .. 15] OF QVal; (* per-call static links *)
  41. stkExt : ARRAY [0 .. 15] OF BOOLEAN; (* per-call external flag *)
  42. outSel : CARDINAL; (* 0 = file, else nestBufs[outSel-1] *)
  43. nInit : CARDINAL;
  44. initNames : ARRAY [0 .. 31] OF QVal;
  45. sessBuf : ARRAY [0 .. 1048575] OF CHAR; (* whole image, buffered *)
  46. sessUsed : CARDINAL;
  47. nestBufs : ARRAY [0 .. 15] OF ARRAY [0 .. 65535] OF CHAR;
  48. nestUsed : ARRAY [0 .. 15] OF CARDINAL;
  49. (* one buffer per nesting depth: each nested function stays
  50. contiguous no matter how deep the parse interleaves *)
  51. nPar : CARDINAL; (* recorded formal params for the header *)
  52. parCls : ARRAY [0 .. 63] OF CHAR;
  53. parTmp : ARRAY [0 .. 63] OF QVal;
  54. parNam : ARRAY [0 .. 63] OF SymTab.Name;
  55. parVar : ARRAY [0 .. 63] OF BOOLEAN;
  56. parTyp : ARRAY [0 .. 63] OF INTEGER;
  57. argBuf : ARRAY [0 .. 4095] OF CHAR; (* accumulated call args *)
  58. hbuf : ARRAY [0 .. 2047] OF CHAR; (* buffered function header *)
  59. nArg : CARDINAL;
  60. callDepth : CARDINAL; (* nested-call stack *)
  61. stkName : ARRAY [0 .. 15] OF QVal;
  62. stkRes : ARRAY [0 .. 15] OF CHAR;
  63. stkArg : ARRAY [0 .. 15] OF ARRAY [0 .. 1023] OF CHAR;
  64. stkN : ARRAY [0 .. 15] OF CARDINAL;
  65. funcName : QVal; (* current function / call target *)
  66. nVal : ARRAY [0 .. 255] OF QVal; (* VAR-actual note keys *)
  67. nAddr : ARRAY [0 .. 255] OF QVal; (* VAR-actual note addresses *)
  68. nn : CARDINAL;
  69. (* ---------------- small string utilities ---------------- *)
  70. PROCEDURE Len (s: ARRAY OF CHAR): CARDINAL;
  71. VAR i : CARDINAL;
  72. BEGIN
  73. i := 0;
  74. WHILE (i < HIGH(s)) & (s[i] # 0C) DO INC(i) END;
  75. RETURN i
  76. END Len;
  77. PROCEDURE Cpy (VAR d: ARRAY OF CHAR; s: ARRAY OF CHAR);
  78. VAR i : CARDINAL;
  79. BEGIN
  80. i := 0;
  81. WHILE (i < HIGH(d)) & (i < HIGH(s)) & (s[i] # 0C) DO
  82. d[i] := s[i]; INC(i)
  83. END;
  84. IF i <= HIGH(d) THEN d[i] := 0C END
  85. END Cpy;
  86. PROCEDURE App (VAR d: ARRAY OF CHAR; s: ARRAY OF CHAR);
  87. VAR i, j : CARDINAL;
  88. BEGIN
  89. i := 0;
  90. WHILE (i <= HIGH(d)) & (d[i] # 0C) DO INC(i) END;
  91. j := 0;
  92. WHILE (i < HIGH(d)) & (j < HIGH(s)) & (s[j] # 0C) DO
  93. d[i] := s[j]; INC(i); INC(j)
  94. END;
  95. IF i <= HIGH(d) THEN d[i] := 0C END
  96. END App;
  97. PROCEDURE BufApp (VAR buf: ARRAY OF CHAR; VAR used: CARDINAL;
  98. s: ARRAY OF CHAR; eol: BOOLEAN);
  99. VAR j : CARDINAL;
  100. BEGIN
  101. j := 0;
  102. WHILE (used < HIGH(buf)) & (j <= HIGH(s)) & (s[j] # 0C) DO
  103. buf[used] := s[j]; INC(used); INC(j)
  104. END;
  105. IF eol & (used < HIGH(buf)) THEN
  106. buf[used] := CHR(10); INC(used)
  107. END;
  108. IF used <= HIGH(buf) THEN buf[used] := 0C END
  109. END BufApp;
  110. PROCEDURE WEmit (s: ARRAY OF CHAR; eol: BOOLEAN);
  111. (* Single output sink: the session buffer, or a nesting-depth
  112. buffer for nested functions (QBE rejects definitions inside
  113. functions, so nested bodies hoist until EndModule). *)
  114. VAR b, u, j : CARDINAL;
  115. BEGIN
  116. IF ~opened OR noEmit THEN RETURN END;
  117. IF outSel = 0 THEN
  118. BufApp(sessBuf, sessUsed, s, eol);
  119. RETURN
  120. END;
  121. b := outSel - 1;
  122. IF b > HIGH(nestBufs) THEN b := HIGH(nestBufs) END;
  123. u := nestUsed[b];
  124. j := 0;
  125. WHILE (u < HIGH(nestBufs[b])) & (j <= HIGH(s)) & (s[j] # 0C) DO
  126. nestBufs[b][u] := s[j]; INC(u); INC(j)
  127. END;
  128. IF eol & (u < HIGH(nestBufs[b])) THEN
  129. nestBufs[b][u] := CHR(10); INC(u)
  130. END;
  131. IF u <= HIGH(nestBufs[b]) THEN nestBufs[b][u] := 0C END;
  132. nestUsed[b] := u
  133. END WEmit;
  134. PROCEDURE W (s: ARRAY OF CHAR);
  135. BEGIN
  136. WEmit(s, FALSE)
  137. END W;
  138. PROCEDURE WL (s: ARRAY OF CHAR);
  139. BEGIN
  140. WEmit(s, TRUE)
  141. END WL;
  142. PROCEDURE SetNoEmit (b: BOOLEAN);
  143. BEGIN
  144. noEmit := b
  145. END SetNoEmit;
  146. PROCEDURE Wc (c: CHAR);
  147. (* Writes a single class character (w/d/l). *)
  148. VAR s : ARRAY [0 .. 1] OF CHAR;
  149. BEGIN
  150. s[0] := c; s[1] := 0C;
  151. W(s)
  152. END Wc;
  153. PROCEDURE AppNum (VAR d: ARRAY OF CHAR; v: CARDINAL);
  154. (* Appends v in decimal to d. *)
  155. VAR buf : ARRAY [0 .. 15] OF CHAR;
  156. n, i, L : CARDINAL;
  157. BEGIN
  158. n := 0;
  159. IF v = 0 THEN buf[0] := "0"; n := 1 END;
  160. WHILE (v > 0) & (n <= HIGH(buf)) DO
  161. buf[n] := CHR(ORD("0") + v MOD 10); v := v DIV 10; INC(n)
  162. END;
  163. i := n;
  164. WHILE i > 0 DO
  165. DEC(i);
  166. L := Len(d);
  167. IF L < HIGH(d) THEN d[L] := buf[i]; d[L + 1] := 0C END
  168. END
  169. END AppNum;
  170. (* ---------------- exported helpers ---------------- *)
  171. PROCEDURE CopyOp (s: ARRAY OF CHAR; VAR d: ARRAY OF CHAR);
  172. BEGIN
  173. Cpy(d, s)
  174. END CopyOp;
  175. PROCEDURE NoteAddr (val: ARRAY OF CHAR; addr: ARRAY OF CHAR);
  176. (* Records value-temp → address mapping for VAR actuals. Ring of
  177. 256: safe because SSA temps are never reused (stale entries can
  178. never false-match, only age out on pathological expressions). *)
  179. BEGIN
  180. Cpy(nVal[nn], val);
  181. Cpy(nAddr[nn], addr);
  182. nn := nn + 1;
  183. IF nn > HIGH(nVal) THEN nn := 0 END
  184. END NoteAddr;
  185. PROCEDURE AddrOfVal (val: ARRAY OF CHAR; VAR addr: QVal): BOOLEAN;
  186. VAR i : CARDINAL;
  187. BEGIN
  188. i := 0;
  189. WHILE i <= HIGH(nVal) DO
  190. IF SymTab.Equal(nVal[i], val) THEN
  191. Cpy(addr, nAddr[i]);
  192. RETURN TRUE
  193. END;
  194. INC(i)
  195. END;
  196. RETURN FALSE
  197. END AddrOfVal;
  198. PROCEDURE AddrOf (name: ARRAY OF CHAR; VAR q: QVal);
  199. VAR idx : INTEGER;
  200. levels : CARDINAL;
  201. BEGIN
  202. IF LocFindUp(name, levels, idx) THEN
  203. IF levels = 0 THEN
  204. IF locTag[idx] = 1 THEN
  205. Cpy(q, "$");
  206. App(q, locRep[idx])
  207. ELSE
  208. Cpy(q, locRep[idx])
  209. END
  210. ELSE
  211. UpAddrOf(idx, levels, q)
  212. END;
  213. RETURN
  214. END;
  215. Cpy(q, "$");
  216. App(q, name)
  217. END AddrOf;
  218. PROCEDURE IntStr (v: INTEGER; VAR s: QVal);
  219. VAR neg : BOOLEAN;
  220. mag : CARDINAL;
  221. buf : ARRAY [0 .. 15] OF CHAR;
  222. n, i, L : CARDINAL;
  223. t : CHAR;
  224. BEGIN
  225. neg := v < 0;
  226. IF neg THEN mag := VAL(CARDINAL, -v) ELSE mag := VAL(CARDINAL, v) END;
  227. n := 0;
  228. IF mag = 0 THEN buf[0] := "0"; n := 1 END;
  229. WHILE (mag > 0) & (n < HIGH(buf)) DO
  230. buf[n] := CHR(ORD("0") + mag MOD 10); mag := mag DIV 10; INC(n)
  231. END;
  232. i := 0;
  233. WHILE i < n DIV 2 DO
  234. t := buf[i]; buf[i] := buf[n - 1 - i]; buf[n - 1 - i] := t; INC(i)
  235. END;
  236. s[0] := 0C;
  237. IF neg THEN App(s, "-") END;
  238. i := 0;
  239. WHILE i < n DO
  240. L := Len(s);
  241. IF L < HIGH(s) THEN s[L] := buf[i]; s[L + 1] := 0C END;
  242. INC(i)
  243. END
  244. END IntStr;
  245. PROCEDURE HexVal (ch: CHAR): INTEGER;
  246. BEGIN
  247. IF (ch >= "0") & (ch <= "9") THEN RETURN ORD(ch) - ORD("0") END;
  248. IF (ch >= "A") & (ch <= "F") THEN RETURN ORD(ch) - ORD("A") + 10 END;
  249. IF (ch >= "a") & (ch <= "f") THEN RETURN ORD(ch) - ORD("a") + 10 END;
  250. RETURN 0
  251. END HexVal;
  252. PROCEDURE NormInt (s: ARRAY OF CHAR; VAR d: QVal);
  253. (* "0xFF" -> "255", plain decimals are copied through. *)
  254. VAR n, i : CARDINAL;
  255. v : INTEGER;
  256. BEGIN
  257. n := Len(s);
  258. IF (n > 2) & (s[0] = "0")
  259. & ((s[1] = "x") OR (s[1] = "X")) THEN
  260. v := 0; i := 2;
  261. WHILE i < n DO v := v * 16 + HexVal(s[i]); INC(i) END;
  262. IntStr(v, d)
  263. ELSE
  264. Cpy(d, s)
  265. END
  266. END NormInt;
  267. PROCEDURE NormLit (s: ARRAY OF CHAR; VAR d: QVal; VAR isCh: BOOLEAN);
  268. (* Full V3 integer literal: octal B/b, hex H/h and C/c suffixes plus
  269. the 0x/0X prefix; C marks a character constant. The suffix letter
  270. is excluded from the digit run (HexVal would read 'B' as 11).
  271. A 0x/0X prefix takes priority over any trailing B/C/H (C-style
  272. hex digits, so 0xB is 11, never an octal suffix). *)
  273. VAR n, i, hi, base : CARDINAL;
  274. v : INTEGER;
  275. ch : CHAR;
  276. BEGIN
  277. n := Len(s);
  278. isCh := FALSE;
  279. IF n = 0 THEN Cpy(d, "0"); RETURN END;
  280. i := 0;
  281. IF (n >= 3) & (s[0] = "0") & ((s[1] = "x") OR (s[1] = "X")) THEN
  282. base := 16; hi := n; i := 2
  283. ELSE
  284. ch := s[n - 1];
  285. IF (ch = "B") OR (ch = "b") THEN
  286. base := 8; hi := n - 1
  287. ELSIF (ch = "H") OR (ch = "h") THEN
  288. base := 16; hi := n - 1
  289. ELSIF (ch = "C") OR (ch = "c") THEN
  290. base := 16; hi := n - 1; isCh := TRUE
  291. ELSE
  292. base := 10; hi := n
  293. END
  294. END;
  295. v := 0;
  296. WHILE i < hi DO
  297. v := v * VAL(INTEGER, base) + HexVal(s[i]); INC(i)
  298. END;
  299. IntStr(v, d)
  300. END NormLit;
  301. PROCEDURE NormReal (s: ARRAY OF CHAR; VAR d: QVal);
  302. (* "3.14" -> "d_3.14" (QBE double immediates carry a d_ prefix). *)
  303. BEGIN
  304. Cpy(d, "d_");
  305. App(d, s)
  306. END NormReal;
  307. PROCEDURE CharVal (s: ARRAY OF CHAR): INTEGER;
  308. BEGIN
  309. IF Len(s) >= 2 THEN RETURN ORD(s[1]) END;
  310. RETURN 0
  311. END CharVal;
  312. PROCEDURE NegFold (a: ARRAY OF CHAR; VAR q: QVal);
  313. (* Safe for a and q being the same variable. *)
  314. VAR i, j, L : CARDINAL;
  315. tmp : QVal;
  316. BEGIN
  317. Cpy(tmp, a);
  318. IF Len(tmp) = 0 THEN Cpy(q, "0"); RETURN END;
  319. IF tmp[0] = "-" THEN
  320. i := 1; j := 0;
  321. WHILE (tmp[i] # 0C) & (j < HIGH(q)) DO
  322. q[j] := tmp[i]; INC(i); INC(j)
  323. END;
  324. IF j <= HIGH(q) THEN q[j] := 0C END
  325. ELSIF (tmp[0] = "d") & (Len(tmp) > 1) & (tmp[1] = "_") THEN
  326. Cpy(q, "d_-");
  327. i := 2;
  328. WHILE tmp[i] # 0C DO
  329. L := Len(q);
  330. IF L < HIGH(q) THEN q[L] := tmp[i]; q[L + 1] := 0C END;
  331. INC(i)
  332. END
  333. ELSE
  334. Cpy(q, "-");
  335. App(q, tmp)
  336. END
  337. END NegFold;
  338. PROCEDURE IsImm (s: ARRAY OF CHAR): BOOLEAN;
  339. BEGIN
  340. IF Len(s) = 0 THEN RETURN FALSE END;
  341. RETURN ((s[0] >= "0") & (s[0] <= "9")) OR (s[0] = "-")
  342. OR (s[0] = "d")
  343. END IsImm;
  344. (* ---------------- module / data section ---------------- *)
  345. PROCEDURE OpenModule (name: ARRAY OF CHAR);
  346. VAR i : CARDINAL;
  347. BEGIN
  348. opened := TRUE;
  349. inBody := FALSE;
  350. dead := FALSE;
  351. nTemp := 0; nLab := 0; loopTop := 0; nR := 0; nStr := 0;
  352. withTop := 0;
  353. noEmit := FALSE; inFunc := FALSE; useStack := FALSE;
  354. nLoc := 0; nPar := 0; nArg := 0; nn := 0; callDepth := 0;
  355. funcDepth := 0; scopeTop := 0; scopeBase[0] := 0;
  356. nInit := 0;
  357. outSel := 0;
  358. sessUsed := 0; sessBuf[0] := 0C;
  359. i := 0;
  360. WHILE i <= HIGH(nestBufs) DO
  361. nestBufs[i][0] := 0C; nestUsed[i] := 0; INC(i)
  362. END;
  363. WL("# QBE IR generated by the V3 step-1 backend");
  364. WL("")
  365. END OpenModule;
  366. PROCEDURE DataLine (name: ARRAY OF CHAR; isReal: BOOLEAN;
  367. init: ARRAY OF CHAR);
  368. BEGIN
  369. IF ~opened THEN RETURN END;
  370. W("data $"); W(name);
  371. IF isReal THEN W(" = { d ") ELSE W(" = { w ") END;
  372. W(init);
  373. WL(" }")
  374. END DataLine;
  375. PROCEDURE DataLineL (name: ARRAY OF CHAR; init: ARRAY OF CHAR);
  376. BEGIN
  377. IF ~opened THEN RETURN END;
  378. W("data $"); W(name);
  379. W(" = { l ");
  380. W(init);
  381. WL(" }")
  382. END DataLineL;
  383. PROCEDURE DeclLocal (name: ARRAY OF CHAR; t: INTEGER);
  384. (* Function-local variable: stack slot + static init, recorded. *)
  385. VAR slot : QVal;
  386. BEGIN
  387. AllocLocal(t, slot);
  388. LocAdd(name, 0, slot, ResClass(t), t)
  389. END DeclLocal;
  390. PROCEDURE DeclVar (name: ARRAY OF CHAR; t: INTEGER);
  391. BEGIN
  392. IF inFunc THEN DeclLocal(name, t); RETURN END;
  393. IF SymTab.ClassOf(t) = SymTab.ClReal THEN DataLine(name, TRUE, "0")
  394. ELSIF SymTab.ClassOf(t) = SymTab.ClArray THEN DeclArr(name, t)
  395. ELSIF SymTab.ClassOf(t) = SymTab.ClSet THEN DeclSet(name, t)
  396. ELSIF (SymTab.ClassOf(t) = SymTab.ClRecord)
  397. OR (SymTab.ClassOf(t) = SymTab.ClClass) THEN
  398. DeclRec(name, t)
  399. ELSIF SymTab.ClassOf(t) = SymTab.ClPtr THEN DataLineL(name, "0")
  400. ELSE DataLine(name, FALSE, "0")
  401. END
  402. END DeclVar;
  403. PROCEDURE IsZeroReal (val: ARRAY OF CHAR): BOOLEAN;
  404. (* TRUE when the "d_..." literal denotes zero (checked textually). *)
  405. VAR i : CARDINAL;
  406. seen : BOOLEAN;
  407. ch : CHAR;
  408. BEGIN
  409. i := 0;
  410. IF (Len(val) > 1) & (val[0] = "d") & (val[1] = "_") THEN i := 2 END;
  411. IF (Len(val) > i) & (val[i] = "-") THEN INC(i) END;
  412. seen := FALSE;
  413. WHILE val[i] # 0C DO
  414. ch := val[i];
  415. IF (ch >= "0") & (ch <= "9") THEN
  416. seen := TRUE;
  417. IF ch # "0" THEN RETURN FALSE END
  418. ELSIF (ch # ".") & (ch # "E") & (ch # "e")
  419. & (ch # "+") & (ch # "-") THEN
  420. RETURN FALSE
  421. END;
  422. INC(i)
  423. END;
  424. RETURN seen
  425. END IsZeroReal;
  426. PROCEDURE DeclConst (name: ARRAY OF CHAR; val: ARRAY OF CHAR; t: INTEGER);
  427. VAR cls : INTEGER;
  428. mang : QVal;
  429. BEGIN
  430. cls := SymTab.ClassOf(t);
  431. IF inFunc THEN
  432. Cpy(mang, funcName); App(mang, "_"); App(mang, name);
  433. LocAdd(name, 1, mang, ResClass(t), t)
  434. ELSE
  435. Cpy(mang, name)
  436. END;
  437. IF (cls = SymTab.ClStr) OR ~IsImm(val) THEN
  438. DataLine(mang, FALSE, "0"); RETURN
  439. END;
  440. IF cls = SymTab.ClReal THEN
  441. (* This qbe accepts only integer/zero literals in "data":
  442. non-zero REALs flush at BeginBody. *)
  443. DataLine(mang, TRUE, "0");
  444. IF ~IsZeroReal(val) & (nR <= HIGH(rNames)) THEN
  445. Cpy(rNames[nR], mang); Cpy(rVals[nR], val); INC(nR)
  446. END
  447. ELSE DataLine(mang, FALSE, val)
  448. END
  449. END DeclConst;
  450. (* ---------------- function body ---------------- *)
  451. PROCEDURE BeginInit (mod: ARRAY OF CHAR);
  452. (* Module BEGIN body as `<mod>_init`; main calls it at startup. *)
  453. VAR sym : QVal;
  454. BEGIN
  455. IF ~opened THEN RETURN END;
  456. Cpy(sym, mod);
  457. App(sym, "_init");
  458. WL("");
  459. W("export function w $"); W(sym); WL("() {");
  460. WL("@start");
  461. IF nInit <= HIGH(initNames) THEN
  462. Cpy(initNames[nInit], sym); INC(nInit)
  463. END
  464. END BeginInit;
  465. PROCEDURE EndInit;
  466. BEGIN
  467. Revive;
  468. WL(" ret 0");
  469. WL("}")
  470. END EndInit;
  471. PROCEDURE BeginBody;
  472. VAR i : CARDINAL;
  473. t : QVal;
  474. BEGIN
  475. IF ~opened OR inBody THEN RETURN END;
  476. WL("");
  477. WL("export function w $main() {");
  478. WL("@start");
  479. inBody := TRUE;
  480. i := 0;
  481. WHILE i < nR DO
  482. NewTemp(t);
  483. W(" "); W(t); W(" =d copy "); WL(rVals[i]);
  484. StoreVar(rNames[i], t, TRUE);
  485. INC(i)
  486. END;
  487. i := 0;
  488. WHILE i < nInit DO
  489. W(" call $"); W(initNames[i]); WL("()");
  490. INC(i)
  491. END
  492. END BeginBody;
  493. PROCEDURE CloseModule;
  494. BEGIN
  495. IF ~opened THEN RETURN END;
  496. WL("# no code: unit lowering waits for step 4");
  497. FileIO.Close(out);
  498. opened := FALSE
  499. END CloseModule;
  500. PROCEDURE EndModule (name: ARRAY OF CHAR);
  501. VAR i : CARDINAL;
  502. fname : ARRAY [0 .. 127] OF CHAR;
  503. BEGIN
  504. IF ~opened THEN RETURN END;
  505. IF ~inBody THEN BeginBody END;
  506. IF SymTab.Lookup("ExitCode")
  507. & (SymTab.SymKind("ExitCode") = SymTab.KindVar)
  508. & SymTab.IsIntFamily(SymTab.SymType("ExitCode")) THEN
  509. WL(" %ec =w loadw $ExitCode");
  510. WL(" ret %ec")
  511. ELSE
  512. WL(" ret 0")
  513. END;
  514. WL("}");
  515. (* hoisted nested functions, then deferred data *)
  516. i := 0;
  517. WHILE i <= HIGH(nestBufs) DO
  518. IF nestUsed[i] > 0 THEN
  519. BufApp(sessBuf, sessUsed, nestBufs[i], FALSE)
  520. END;
  521. INC(i)
  522. END;
  523. FlushStrings;
  524. (* the image is named after the program module *)
  525. fname[0] := 0C;
  526. App(fname, "gen_ssa/");
  527. App(fname, name);
  528. App(fname, ".ssa");
  529. FileIO.Open(out, fname, TRUE);
  530. IF FileIO.Okay THEN
  531. FileIO.WriteString(out, sessBuf)
  532. END;
  533. FileIO.Close(out);
  534. opened := FALSE
  535. END EndModule;
  536. (* ---------------- functions and calls (step 4.1) ---------------- *)
  537. (* Module-level procedures only (nested → NoEmit until 4.2).
  538. Value params arrive as SSA values and are copied to slots;
  539. composite value params arrive as addresses and are copied;
  540. VAR params stay addresses. Locals live in stack slots. *)
  541. PROCEDURE LocFind (name: ARRAY OF CHAR): INTEGER;
  542. VAR i : CARDINAL;
  543. BEGIN
  544. i := 0;
  545. WHILE i < nLoc DO
  546. IF SymTab.Equal(locNames[i], name) THEN RETURN VAL(INTEGER, i) END;
  547. INC(i)
  548. END;
  549. RETURN -1
  550. END LocFind;
  551. PROCEDURE ScopeBegin;
  552. (* Pushes a procedure scope (always balanced, even under NoEmit). *)
  553. BEGIN
  554. IF scopeTop > HIGH(scopeLink) THEN RETURN END;
  555. scopeBase[scopeTop] := nLoc;
  556. INC(scopeTop);
  557. scopeBase[scopeTop] := nLoc
  558. END ScopeBegin;
  559. PROCEDURE ScopeEnd;
  560. BEGIN
  561. IF scopeTop > 0 THEN
  562. DEC(scopeTop);
  563. nLoc := scopeBase[scopeTop]
  564. END
  565. END ScopeEnd;
  566. PROCEDURE LocFindUp (name: ARRAY OF CHAR; VAR levels: CARDINAL;
  567. VAR flat: INTEGER): BOOLEAN;
  568. (* Innermost procedure scope holding name; levels = scopes crossed,
  569. flat = table index. FALSE when purely global. *)
  570. VAR s, top, lo, hi, j : CARDINAL;
  571. BEGIN
  572. levels := 0; flat := -1;
  573. IF scopeTop = 0 THEN RETURN FALSE END;
  574. top := scopeTop - 1;
  575. s := top;
  576. LOOP
  577. lo := scopeBase[s];
  578. IF s = top THEN hi := nLoc ELSE hi := scopeBase[s + 1] END;
  579. j := lo;
  580. WHILE j < hi DO
  581. IF SymTab.Equal(locNames[j], name) THEN
  582. levels := top - s;
  583. flat := VAL(INTEGER, j);
  584. RETURN TRUE
  585. END;
  586. INC(j)
  587. END;
  588. IF s = 0 THEN RETURN FALSE END;
  589. DEC(s)
  590. END
  591. END LocFindUp;
  592. PROCEDURE LocAdd (name: ARRAY OF CHAR; tag: INTEGER; rep: ARRAY OF CHAR;
  593. cls: CHAR; typ: INTEGER);
  594. VAR idx : CARDINAL;
  595. off : QVal;
  596. lk : QVal;
  597. BEGIN
  598. IF noEmit THEN RETURN END;
  599. IF (scopeTop = 0) OR (nLoc > HIGH(locNames)) THEN RETURN END;
  600. idx := nLoc - scopeBase[scopeTop - 1];
  601. IF idx > 63 THEN RETURN END;
  602. Cpy(locNames[nLoc], name);
  603. locTag[nLoc] := tag;
  604. Cpy(locRep[nLoc], rep);
  605. locCls[nLoc] := cls;
  606. locTyp[nLoc] := typ;
  607. INC(nLoc);
  608. IF tag = 1 THEN RETURN END;
  609. Cpy(lk, scopeLink[scopeTop - 1]);
  610. IntStr(VAL(INTEGER, 8 * (idx + 1)), off);
  611. NewTemp(lk);
  612. Op3L("add", lk, scopeLink[scopeTop - 1], off);
  613. Revive;
  614. W(" storel "); W(rep); W(", "); WL(lk)
  615. END LocAdd;
  616. PROCEDURE LocFull (): BOOLEAN;
  617. (* TRUE past 64 locals in the current scope (→ 233). *)
  618. BEGIN
  619. IF scopeTop = 0 THEN RETURN FALSE END;
  620. RETURN nLoc - scopeBase[scopeTop - 1] > 63
  621. END LocFull;
  622. PROCEDURE UpAddr (levels: CARDINAL; rel: CARDINAL; VAR q: QVal);
  623. (* Address of an up-level local: walks the static chain, then
  624. loads the link cell (slot address or actual address). *)
  625. VAR cur, t, off : QVal;
  626. L : CARDINAL;
  627. BEGIN
  628. Cpy(cur, scopeLink[scopeTop - 1]);
  629. L := levels;
  630. WHILE L > 0 DO
  631. NewTemp(t);
  632. Revive;
  633. W(" "); W(t); W(" =l loadl "); WL(cur);
  634. Cpy(cur, t);
  635. DEC(L)
  636. END;
  637. IntStr(VAL(INTEGER, 8 * (rel + 1)), off);
  638. NewTemp(t);
  639. Op3L("add", t, cur, off);
  640. NewTemp(q);
  641. Revive;
  642. W(" "); W(q); W(" =l loadl "); WL(t)
  643. END UpAddr;
  644. PROCEDURE ResClass (t: INTEGER): CHAR;
  645. VAR cls : INTEGER;
  646. BEGIN
  647. cls := SymTab.ClassOf(t);
  648. IF cls = SymTab.ClReal THEN RETURN "d" END;
  649. IF (cls = SymTab.ClArray) OR (cls = SymTab.ClSet)
  650. OR (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass)
  651. OR (cls = SymTab.ClPtr) THEN
  652. RETURN "l"
  653. END;
  654. RETURN "w"
  655. END ResClass;
  656. PROCEDURE Mangled (pname: ARRAY OF CHAR; uid: CARDINAL; VAR q: QVal);
  657. (* External procedures bind to their C link name; everything else
  658. mangles to <name>_<uid> (deterministic, collision-free). *)
  659. VAR link : SymTab.Name;
  660. BEGIN
  661. IF SymTab.ProcLink(pname, link) THEN
  662. Cpy(q, link);
  663. RETURN
  664. END;
  665. Cpy(q, pname);
  666. App(q, "_");
  667. AppNum(q, uid)
  668. END Mangled;
  669. PROCEDURE AllocLocal (t: INTEGER; VAR slot: QVal);
  670. (* Stack slot sized for t's inline footprint; arrays/records get
  671. full objects + static init. Scalar/pointer/set slots are
  672. zero-initialized: QBE rejects reads of never-stored slots, and
  673. the frontend emits a dead load for assignment targets (Test2
  674. heritage, harmless for zero-initialized globals). Locals match
  675. the globals' zero-init convention. *)
  676. VAR cls : INTEGER;
  677. nb : QVal;
  678. BEGIN
  679. cls := SymTab.ClassOf(t);
  680. NewTemp(slot);
  681. Revive;
  682. W(" "); W(slot);
  683. IF (cls = SymTab.ClArray) THEN
  684. IntStr(VAL(INTEGER, HeapSize(t)), nb);
  685. W(" =l alloc8 "); WL(nb);
  686. InitStack(slot, t)
  687. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  688. IntStr(VAL(INTEGER, SymTab.TypeSize(t)), nb);
  689. W(" =l alloc8 "); WL(nb);
  690. InitStack(slot, t)
  691. ELSIF cls = SymTab.ClSet THEN
  692. IntStr(VAL(INTEGER, SymTab.SetWords(t) * 4), nb);
  693. W(" =l alloc8 "); WL(nb);
  694. SetZero(slot, SymTab.SetWords(t))
  695. ELSIF cls = SymTab.ClReal THEN
  696. W(" =l alloc8 8"); WL("");
  697. W(" stored d_0.0, "); WL(slot)
  698. ELSIF cls = SymTab.ClPtr THEN
  699. W(" =l alloc8 8"); WL("");
  700. W(" storel 0, "); WL(slot)
  701. ELSE
  702. W(" =l alloc4 4"); WL("");
  703. W(" storew 0, "); WL(slot)
  704. END
  705. END AllocLocal;
  706. PROCEDURE BeginFunc (mangled: ARRAY OF CHAR);
  707. (* Opens function context and scope; the header (with a leading
  708. static-link param) buffers until EndFuncHeader. FORWARD/DefUnit
  709. paths discard via AbortFunc. *)
  710. BEGIN
  711. ScopeBegin;
  712. INC(funcDepth);
  713. inFunc := TRUE;
  714. nPar := 0;
  715. funcRes := "w";
  716. Cpy(funcName, mangled);
  717. hbuf[0] := 0C;
  718. NewTemp(slTmp);
  719. HApp("l ");
  720. HApp(slTmp);
  721. hdrComma := TRUE;
  722. IF funcDepth > 1 THEN
  723. outSel := funcDepth - 1;
  724. IF outSel > HIGH(nestBufs) + 1 THEN
  725. outSel := HIGH(nestBufs) + 1
  726. END
  727. ELSE
  728. outSel := 0
  729. END
  730. END BeginFunc;
  731. PROCEDURE SetFuncRes (t: INTEGER);
  732. BEGIN
  733. funcRes := ResClass(t)
  734. END SetFuncRes;
  735. PROCEDURE HApp (s: ARRAY OF CHAR);
  736. (* Appends to the header buffer (bounded: FormalParams cap it). *)
  737. VAR i, j : CARDINAL;
  738. BEGIN
  739. i := 0;
  740. WHILE (i <= HIGH(hbuf)) & (hbuf[i] # 0C) DO INC(i) END;
  741. j := 0;
  742. WHILE (i < HIGH(hbuf)) & (j <= HIGH(s)) & (s[j] # 0C) DO
  743. hbuf[i] := s[j]; INC(i); INC(j)
  744. END;
  745. IF i <= HIGH(hbuf) THEN hbuf[i] := 0C END
  746. END HApp;
  747. PROCEDURE FuncParam (name: ARRAY OF CHAR; isVar: BOOLEAN;
  748. t: INTEGER): BOOLEAN;
  749. VAR c : CHAR;
  750. tmp : QVal;
  751. buf : ARRAY [0 .. 71] OF CHAR;
  752. BEGIN
  753. IF noEmit THEN RETURN TRUE END;
  754. IF nPar > HIGH(parCls) THEN RETURN FALSE END;
  755. IF isVar THEN c := "l" ELSE c := ResClass(t) END;
  756. parCls[nPar] := c;
  757. NewTemp(tmp);
  758. Cpy(parTmp[nPar], tmp);
  759. Cpy(parNam[nPar], name);
  760. parVar[nPar] := isVar;
  761. parTyp[nPar] := t;
  762. IF hdrComma THEN HApp(", ") END;
  763. hdrComma := TRUE;
  764. buf[0] := c; buf[1] := " "; buf[2] := 0C;
  765. App(buf, tmp);
  766. HApp(buf);
  767. INC(nPar);
  768. RETURN TRUE
  769. END FuncParam;
  770. PROCEDURE EndFuncHeader;
  771. (* Flushes the buffered header + body label, allocates the link
  772. record ([0] = parent link), then emits entry copies. *)
  773. VAR i : CARDINAL;
  774. slot, nb, lk : QVal;
  775. cls : INTEGER;
  776. BEGIN
  777. W("export function "); Wc(funcRes); W(" $"); W(funcName); W("(");
  778. W(hbuf);
  779. WL(") {");
  780. WL("@start");
  781. inBody := TRUE;
  782. NewTemp(lk);
  783. Cpy(scopeLink[scopeTop - 1], lk);
  784. Revive;
  785. W(" "); W(lk); W(" =l alloc8 520"); WL("");
  786. W(" storel "); W(slTmp); W(", "); WL(lk);
  787. i := 0;
  788. WHILE i < nPar DO
  789. cls := SymTab.ClassOf(parTyp[i]);
  790. IF parVar[i] THEN
  791. LocAdd(parNam[i], 2, parTmp[i], parCls[i], parTyp[i])
  792. ELSE
  793. AllocLocal(parTyp[i], slot);
  794. LocAdd(parNam[i], 0, slot, parCls[i], parTyp[i]);
  795. IF cls = SymTab.ClArray THEN
  796. CopyArray(slot, parTmp[i], parTyp[i])
  797. ELSIF cls = SymTab.ClSet THEN
  798. CopySet(slot, parTmp[i],
  799. SymTab.SetWords(parTyp[i]), SymTab.SetWords(parTyp[i]))
  800. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  801. CopyRecord(slot, parTmp[i], parTyp[i])
  802. ELSIF cls = SymTab.ClReal THEN
  803. Revive;
  804. W(" stored "); W(parTmp[i]); W(", "); WL(slot)
  805. ELSIF cls = SymTab.ClPtr THEN
  806. Revive;
  807. W(" storel "); W(parTmp[i]); W(", "); WL(slot)
  808. ELSE
  809. Revive;
  810. W(" storew "); W(parTmp[i]); W(", "); WL(slot)
  811. END
  812. END;
  813. INC(i)
  814. END
  815. END EndFuncHeader;
  816. PROCEDURE AbortFunc;
  817. (* Discards function context without emitting (DefUnit headings,
  818. FORWARD, methods): pops the scope, restores the depth. *)
  819. BEGIN
  820. ScopeEnd;
  821. IF funcDepth > 0 THEN DEC(funcDepth) END;
  822. inFunc := funcDepth > 0;
  823. inBody := FALSE;
  824. nPar := 0;
  825. IF funcDepth > 1 THEN outSel := funcDepth - 1
  826. ELSE outSel := 0
  827. END
  828. END AbortFunc;
  829. PROCEDURE EndFunc (resT: INTEGER);
  830. VAR rc : CHAR;
  831. BEGIN
  832. rc := ResClass(resT);
  833. Revive;
  834. IF rc = "d" THEN WL(" ret d_0.0")
  835. ELSIF rc = "l" THEN WL(" ret 0")
  836. ELSE WL(" ret 0")
  837. END;
  838. WL("}");
  839. ScopeEnd;
  840. IF funcDepth > 0 THEN DEC(funcDepth) END;
  841. inFunc := funcDepth > 0;
  842. inBody := FALSE;
  843. IF funcDepth > 1 THEN outSel := funcDepth - 1
  844. ELSE outSel := 0
  845. END
  846. END EndFunc;
  847. PROCEDURE EmitRet (q: ARRAY OF CHAR; hasVal: BOOLEAN);
  848. BEGIN
  849. Revive;
  850. IF hasVal THEN W(" ret "); WL(q)
  851. ELSE WL(" ret 0")
  852. END;
  853. dead := TRUE
  854. END EmitRet;
  855. PROCEDURE CallBegin (mangled: ARRAY OF CHAR; resT: INTEGER;
  856. fdep: CARDINAL; isExt: BOOLEAN);
  857. (* Pushes a call level; the static link is resolved now (caller
  858. context cannot change mid-call): module callers pass 0, others
  859. walk the chain (inFuncDepth - fdep) from their link record.
  860. External callees take no static link. *)
  861. VAR walks : INTEGER;
  862. cur, t : QVal;
  863. BEGIN
  864. IF callDepth > HIGH(stkName) THEN RETURN END;
  865. Cpy(stkName[callDepth], mangled);
  866. stkRes[callDepth] := ResClass(resT);
  867. stkExt[callDepth] := isExt;
  868. stkArg[callDepth][0] := 0C;
  869. stkN[callDepth] := 0;
  870. IF isExt THEN
  871. Cpy(stkLink[callDepth], "0")
  872. ELSIF funcDepth = 0 THEN
  873. Cpy(stkLink[callDepth], "0")
  874. ELSE
  875. walks := VAL(INTEGER, funcDepth) - VAL(INTEGER, fdep);
  876. Cpy(cur, scopeLink[scopeTop - 1]);
  877. WHILE walks > 0 DO
  878. NewTemp(t);
  879. Revive;
  880. W(" "); W(t); W(" =l loadl "); WL(cur);
  881. Cpy(cur, t);
  882. DEC(walks)
  883. END;
  884. Cpy(stkLink[callDepth], cur)
  885. END;
  886. INC(callDepth)
  887. END CallBegin;
  888. PROCEDURE CallArg (q: ARRAY OF CHAR; cls: CHAR): BOOLEAN;
  889. (* Appends "c operand, " to the current level. FALSE when full. *)
  890. VAR need, have, i, j, d : CARDINAL;
  891. BEGIN
  892. d := callDepth - 1;
  893. IF callDepth = 0 THEN RETURN FALSE END;
  894. IF d > HIGH(stkArg) THEN d := HIGH(stkArg) END;
  895. need := Len(q) + 5;
  896. have := Len(stkArg[d]);
  897. IF (stkN[d] >= 64) OR (have + need > HIGH(stkArg[d])) THEN
  898. RETURN FALSE
  899. END;
  900. i := have; j := 0;
  901. stkArg[d][i] := cls; INC(i);
  902. stkArg[d][i] := " "; INC(i);
  903. WHILE q[j] # 0C DO
  904. stkArg[d][i] := q[j]; INC(i); INC(j)
  905. END;
  906. stkArg[d][i] := ","; INC(i);
  907. stkArg[d][i] := " "; INC(i);
  908. stkArg[d][i] := 0C;
  909. INC(stkN[d]);
  910. RETURN TRUE
  911. END CallArg;
  912. PROCEDURE CallEnd (wantRes: BOOLEAN; VAR q: QVal);
  913. VAR i, d : CARDINAL;
  914. rc : CHAR;
  915. body : ARRAY [0 .. 1023] OF CHAR;
  916. BEGIN
  917. IF callDepth = 0 THEN Cpy(q, "0"); RETURN END;
  918. DEC(callDepth);
  919. d := callDepth;
  920. IF d > HIGH(stkArg) THEN d := HIGH(stkArg) END;
  921. Cpy(funcName, stkName[d]);
  922. rc := stkRes[d];
  923. i := 0;
  924. WHILE (stkArg[d][i] # 0C) & (i < HIGH(body)) DO
  925. body[i] := stkArg[d][i]; INC(i)
  926. END;
  927. IF (i >= 2) & (body[i-2] = ",") THEN
  928. body[i-2] := 0C
  929. ELSE
  930. body[i] := 0C
  931. END;
  932. Revive;
  933. IF wantRes THEN
  934. NewTemp(q);
  935. W(" "); W(q); W(" ="); Wc(rc)
  936. ELSE
  937. W(" ")
  938. END;
  939. W(" call $"); W(funcName); W("(");
  940. IF stkExt[d] THEN
  941. W(body) (* C callee: no static link *)
  942. ELSE
  943. W("l "); W(stkLink[d]);
  944. IF body[0] # 0C THEN W(", "); W(body) END
  945. END;
  946. WL(")")
  947. END CallEnd;
  948. PROCEDURE InitStack (addr: ARRAY OF CHAR; t: INTEGER);
  949. BEGIN
  950. useStack := TRUE;
  951. InitHeap(addr, t);
  952. useStack := FALSE
  953. END InitStack;
  954. PROCEDURE ArgClass (t: INTEGER): CHAR;
  955. (* Formal/actual class for call emission. *)
  956. BEGIN
  957. RETURN ResClass(t)
  958. END ArgClass;
  959. (* ---------------- temporaries and operators ---------------- *)
  960. PROCEDURE NewTemp (VAR t: QVal);
  961. BEGIN
  962. Cpy(t, "%t");
  963. AppNum(t, nTemp);
  964. INC(nTemp)
  965. END NewTemp;
  966. PROCEDURE LocLoadFlat (idx: INTEGER; long: BOOLEAN; VAR q: QVal);
  967. (* Loads a same-scope entry: slots/data by class (or long for
  968. pointers), addr entries via ElemLoad. *)
  969. BEGIN
  970. IF locTag[idx] = 2 THEN
  971. ElemLoad(locRep[idx], locTyp[idx], q);
  972. RETURN
  973. END;
  974. NewTemp(q);
  975. Revive;
  976. W(" "); W(q);
  977. IF long THEN W(" =l loadl ")
  978. ELSIF locCls[idx] = "d" THEN W(" =d loadd ")
  979. ELSE W(" =w loadw ")
  980. END;
  981. IF locTag[idx] = 1 THEN W("$") END;
  982. WL(locRep[idx])
  983. END LocLoadFlat;
  984. PROCEDURE LocStoreFlat (idx: INTEGER; q: ARRAY OF CHAR; long: BOOLEAN);
  985. (* Stores a same-scope entry: slots/data by class (or long), addr
  986. via ElemStore. Data stores are grammar-unreachable (consts). *)
  987. BEGIN
  988. IF locTag[idx] = 2 THEN
  989. ElemStore(locRep[idx], q, locTyp[idx]);
  990. RETURN
  991. END;
  992. Revive;
  993. IF long THEN W(" storel ")
  994. ELSIF locCls[idx] = "d" THEN W(" stored ")
  995. ELSE W(" storew ")
  996. END;
  997. W(q); W(", ");
  998. IF locTag[idx] = 1 THEN W("$") END;
  999. WL(locRep[idx])
  1000. END LocStoreFlat;
  1001. PROCEDURE UpLoad (flat: INTEGER; levels: CARDINAL; long: BOOLEAN;
  1002. VAR q: QVal);
  1003. (* Up-level load: data entries live globally; otherwise the link
  1004. cell yields the address and ElemLoad reads through it. *)
  1005. VAR a : QVal;
  1006. rel : CARDINAL;
  1007. BEGIN
  1008. IF locTag[flat] = 1 THEN
  1009. NewTemp(q);
  1010. Revive;
  1011. W(" "); W(q);
  1012. IF long THEN W(" =l loadl $")
  1013. ELSIF locCls[flat] = "d" THEN W(" =d loadd $")
  1014. ELSE W(" =w loadw $")
  1015. END;
  1016. WL(locRep[flat]);
  1017. RETURN
  1018. END;
  1019. rel := VAL(CARDINAL, flat) - scopeBase[scopeTop - 1 - levels];
  1020. UpAddr(levels, rel, a);
  1021. ElemLoad(a, locTyp[flat], q)
  1022. END UpLoad;
  1023. PROCEDURE UpStore (flat: INTEGER; levels: CARDINAL; q: ARRAY OF CHAR;
  1024. long: BOOLEAN);
  1025. VAR a : QVal;
  1026. rel : CARDINAL;
  1027. BEGIN
  1028. IF locTag[flat] = 1 THEN
  1029. Revive;
  1030. IF long THEN W(" storel ")
  1031. ELSIF locCls[flat] = "d" THEN W(" stored ")
  1032. ELSE W(" storew ")
  1033. END;
  1034. W(q); W(", $"); WL(locRep[flat]);
  1035. RETURN
  1036. END;
  1037. rel := VAL(CARDINAL, flat) - scopeBase[scopeTop - 1 - levels];
  1038. UpAddr(levels, rel, a);
  1039. ElemStore(a, q, locTyp[flat])
  1040. END UpStore;
  1041. PROCEDURE UpAddrOf (flat: INTEGER; levels: CARDINAL; VAR q: QVal);
  1042. (* Up-level address: data entries name globals; otherwise the
  1043. link cell holds it (composites) or points at it. For scalars
  1044. the cell IS the usable address (slot or actual address). *)
  1045. VAR a : QVal;
  1046. rel : CARDINAL;
  1047. BEGIN
  1048. IF locTag[flat] = 1 THEN
  1049. Cpy(q, "$");
  1050. App(q, locRep[flat]);
  1051. RETURN
  1052. END;
  1053. rel := VAL(CARDINAL, flat) - scopeBase[scopeTop - 1 - levels];
  1054. UpAddr(levels, rel, q)
  1055. END UpAddrOf;
  1056. PROCEDURE LoadDesignator (name: ARRAY OF CHAR; t: INTEGER; k: INTEGER;
  1057. VAR q: QVal): BOOLEAN;
  1058. VAR cls : INTEGER;
  1059. BEGIN
  1060. cls := SymTab.ClassOf(t);
  1061. IF SymTab.Equal(name, "TRUE") THEN
  1062. Cpy(q, "1"); RETURN TRUE
  1063. ELSIF SymTab.Equal(name, "FALSE") THEN
  1064. Cpy(q, "0"); RETURN TRUE
  1065. ELSIF SymTab.Equal(name, "NIL") THEN
  1066. Cpy(q, "0"); RETURN TRUE
  1067. END;
  1068. IF (k = SymTab.KindVar) OR (k = SymTab.KindParam)
  1069. OR (k = SymTab.KindConst) THEN
  1070. IF (cls = SymTab.ClInt) OR (cls = SymTab.ClBool)
  1071. OR (cls = SymTab.ClChar) OR (cls = SymTab.ClReal) THEN
  1072. LoadVar(name, cls = SymTab.ClReal, q); RETURN TRUE
  1073. ELSIF cls = SymTab.ClPtr THEN
  1074. LoadPtr(name, q); RETURN TRUE
  1075. ELSIF (cls = SymTab.ClArray) OR (cls = SymTab.ClSet)
  1076. OR (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  1077. AddrOf(name, q); RETURN TRUE
  1078. END
  1079. END;
  1080. Cpy(q, "0");
  1081. RETURN FALSE
  1082. END LoadDesignator;
  1083. PROCEDURE LoadVar (name: ARRAY OF CHAR; isReal: BOOLEAN; VAR q: QVal);
  1084. VAR idx : INTEGER;
  1085. levels : CARDINAL;
  1086. BEGIN
  1087. IF LocFindUp(name, levels, idx) THEN
  1088. IF levels = 0 THEN LocLoadFlat(idx, FALSE, q)
  1089. ELSE UpLoad(idx, levels, FALSE, q)
  1090. END;
  1091. RETURN
  1092. END;
  1093. NewTemp(q);
  1094. Revive;
  1095. W(" "); W(q);
  1096. IF isReal THEN W(" =d loadd $") ELSE W(" =w loadw $") END;
  1097. WL(name)
  1098. END LoadVar;
  1099. PROCEDURE LoadPtr (name: ARRAY OF CHAR; VAR q: QVal);
  1100. VAR idx : INTEGER;
  1101. levels : CARDINAL;
  1102. BEGIN
  1103. IF LocFindUp(name, levels, idx) THEN
  1104. IF levels = 0 THEN LocLoadFlat(idx, TRUE, q)
  1105. ELSE UpLoad(idx, levels, TRUE, q)
  1106. END;
  1107. RETURN
  1108. END;
  1109. NewTemp(q);
  1110. Revive;
  1111. W(" "); W(q); W(" =l loadl $");
  1112. WL(name)
  1113. END LoadPtr;
  1114. PROCEDURE StoreVar (name: ARRAY OF CHAR; q: ARRAY OF CHAR; isReal: BOOLEAN);
  1115. VAR idx : INTEGER;
  1116. levels : CARDINAL;
  1117. BEGIN
  1118. IF LocFindUp(name, levels, idx) THEN
  1119. IF levels = 0 THEN LocStoreFlat(idx, q, FALSE)
  1120. ELSE UpStore(idx, levels, q, FALSE)
  1121. END;
  1122. RETURN
  1123. END;
  1124. Revive;
  1125. IF isReal THEN W(" stored ") ELSE W(" storew ") END;
  1126. W(q); W(", $"); WL(name)
  1127. END StoreVar;
  1128. PROCEDURE StorePtr (name: ARRAY OF CHAR; q: ARRAY OF CHAR);
  1129. VAR idx : INTEGER;
  1130. levels : CARDINAL;
  1131. BEGIN
  1132. IF LocFindUp(name, levels, idx) THEN
  1133. IF levels = 0 THEN LocStoreFlat(idx, q, TRUE)
  1134. ELSE UpStore(idx, levels, q, TRUE)
  1135. END;
  1136. RETURN
  1137. END;
  1138. Revive;
  1139. W(" storel "); W(q); W(", $"); WL(name)
  1140. END StorePtr;
  1141. PROCEDURE Op3 (mn: ARRAY OF CHAR; res, l, r: ARRAY OF CHAR;
  1142. isReal: BOOLEAN);
  1143. BEGIN
  1144. Revive;
  1145. W(" "); W(res);
  1146. IF isReal THEN W(" =d ") ELSE W(" =w ") END;
  1147. W(mn); W(" "); W(l); W(", "); WL(r)
  1148. END Op3;
  1149. PROCEDURE NegQ (a: ARRAY OF CHAR; VAR q: QVal; isReal: BOOLEAN);
  1150. BEGIN
  1151. NewTemp(q);
  1152. IF isReal THEN Op3("sub", q, "d_0.0", a, TRUE)
  1153. ELSE Op3("sub", q, "0", a, FALSE)
  1154. END
  1155. END NegQ;
  1156. PROCEDURE ConvIR (a: ARRAY OF CHAR; VAR q: QVal);
  1157. (* INTEGER -> REAL widening for assignments (swtof). *)
  1158. BEGIN
  1159. NewTemp(q);
  1160. Revive;
  1161. W(" "); W(q); W(" =d swtof "); WL(a)
  1162. END ConvIR;
  1163. PROCEDURE NotQ (a: ARRAY OF CHAR; VAR q: QVal);
  1164. BEGIN
  1165. NewTemp(q);
  1166. Op3("xor", q, "1", a, FALSE)
  1167. END NotQ;
  1168. PROCEDURE NewLabel (VAR l: QVal);
  1169. BEGIN
  1170. Cpy(l, "@L");
  1171. AppNum(l, nLab);
  1172. INC(nLab)
  1173. END NewLabel;
  1174. PROCEDURE Revive;
  1175. (* Opens an unreachable block if past a terminator. Keeps every
  1176. temporary defined and every instruction inside a block, even for
  1177. dead source tails (EXIT followed by more statements) and CASE
  1178. chains whose compares follow a Jmp. Counter-driven: fixpoint-safe. *)
  1179. VAR b: QVal;
  1180. BEGIN
  1181. IF opened & dead THEN
  1182. NewLabel(b);
  1183. WL(b);
  1184. dead := FALSE
  1185. END
  1186. END Revive;
  1187. PROCEDURE EmitLabel (l: ARRAY OF CHAR);
  1188. BEGIN
  1189. WL(l);
  1190. dead := FALSE
  1191. END EmitLabel;
  1192. PROCEDURE Jmp (l: ARRAY OF CHAR);
  1193. BEGIN
  1194. IF dead THEN RETURN END; (* unreachable: a terminator with no
  1195. intervening label can never be reached; emitting it would end
  1196. the block and orphan whatever follows. *)
  1197. W(" jmp "); WL(l);
  1198. dead := TRUE
  1199. END Jmp;
  1200. PROCEDURE Jnz (c, t, f: ARRAY OF CHAR);
  1201. BEGIN
  1202. IF dead THEN RETURN END;
  1203. W(" jnz "); W(c); W(", "); W(t); W(", "); WL(f);
  1204. dead := TRUE
  1205. END Jnz;
  1206. PROCEDURE Cmp (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal;
  1207. isReal: BOOLEAN);
  1208. VAR mn : ARRAY [0 .. 7] OF CHAR;
  1209. BEGIN
  1210. mn[0] := 0C;
  1211. IF isReal THEN
  1212. IF op = SymTab.OpEq THEN Cpy(mn, "ceqd")
  1213. ELSIF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN Cpy(mn, "cned")
  1214. ELSIF op = SymTab.OpLt THEN Cpy(mn, "cltd")
  1215. ELSIF op = SymTab.OpLe THEN Cpy(mn, "cled")
  1216. ELSIF op = SymTab.OpGt THEN Cpy(mn, "cgtd")
  1217. ELSE Cpy(mn, "cged")
  1218. END
  1219. ELSE
  1220. IF op = SymTab.OpEq THEN Cpy(mn, "ceqw")
  1221. ELSIF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN Cpy(mn, "cnew")
  1222. ELSIF op = SymTab.OpLt THEN Cpy(mn, "csltw")
  1223. ELSIF op = SymTab.OpLe THEN Cpy(mn, "cslew")
  1224. ELSIF op = SymTab.OpGt THEN Cpy(mn, "csgtw")
  1225. ELSE Cpy(mn, "csgew")
  1226. END
  1227. END;
  1228. NewTemp(q);
  1229. Op3(mn, q, l, r, FALSE)
  1230. END Cmp;
  1231. (* ---------------- arrays: length-prefixed layout ---------------- *)
  1232. (* Indexes and counts are LONGCARD (l) in emitted code; immediates
  1233. pass through, w-temps widen via extsw. Traps call $abort + hlt
  1234. (interim; runtime/syslib/Trap replaces them later). *)
  1235. PROCEDURE ElemCls (t: SymTab.TypeIndex): INTEGER;
  1236. BEGIN
  1237. RETURN SymTab.ClassOf(SymTab.ArrayElem(t))
  1238. END ElemCls;
  1239. PROCEDURE ElemSize (t: SymTab.TypeIndex): CARDINAL;
  1240. (* Storage size of t's elements: CHAR 1, REAL 8, nested/pointer 8,
  1241. else 4. t is an array (or string) descriptor. *)
  1242. VAR cls: INTEGER;
  1243. BEGIN
  1244. cls := SymTab.ClassOf(t);
  1245. IF cls = SymTab.ClStr THEN RETURN 1 END;
  1246. cls := ElemCls(t);
  1247. IF cls = SymTab.ClChar THEN RETURN 1
  1248. ELSIF cls = SymTab.ClReal THEN RETURN 8
  1249. ELSIF (cls = SymTab.ClArray) OR (cls = SymTab.ClPtr) THEN RETURN 8
  1250. ELSE RETURN 4
  1251. END
  1252. END ElemSize;
  1253. PROCEDURE Op3L (mn: ARRAY OF CHAR; res, l, r: ARRAY OF CHAR);
  1254. BEGIN
  1255. Revive;
  1256. W(" "); W(res);
  1257. W(" =l ");
  1258. W(mn); W(" "); W(l); W(", "); WL(r)
  1259. END Op3L;
  1260. PROCEDURE Trap;
  1261. BEGIN
  1262. Revive;
  1263. WL(" call $abort()");
  1264. WL(" hlt");
  1265. dead := TRUE
  1266. END Trap;
  1267. (* ---------------- records: flat blobs, pointer fields ---------------- *)
  1268. (* Scalars/sets inline, array fields as 8-byte pointers to static
  1269. descriptors, nested records inline. Static offsets throughout. *)
  1270. PROCEDURE RecStatics (recname: ARRAY OF CHAR; t: SymTab.TypeIndex);
  1271. (* Pre-pass: static array objects for array fields, recursive. *)
  1272. VAR n, i: CARDINAL;
  1273. fn: SymTab.Name;
  1274. ft: SymTab.TypeIndex;
  1275. cls: INTEGER;
  1276. sub: QVal;
  1277. BEGIN
  1278. n := SymTab.FieldCount(t);
  1279. i := 0;
  1280. WHILE i < n DO
  1281. SymTab.FieldName(t, i, fn);
  1282. ft := SymTab.FieldType(t, fn);
  1283. cls := SymTab.ClassOf(ft);
  1284. IF cls = SymTab.ClArray THEN
  1285. Cpy(sub, recname); App(sub, "_"); App(sub, fn);
  1286. ArrData(sub, ft)
  1287. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  1288. Cpy(sub, recname); App(sub, "_"); App(sub, fn);
  1289. RecStatics(sub, ft)
  1290. END;
  1291. INC(i)
  1292. END
  1293. END RecStatics;
  1294. PROCEDURE RecItems (t: SymTab.TypeIndex; prefix: ARRAY OF CHAR;
  1295. VAR first: BOOLEAN);
  1296. (* Comma-separated item list (no wrapper); nested records inline.
  1297. Emission order follows the (prepend-built) field chain, i.e.
  1298. reverse declaration; offsets (not positions) place everything. *)
  1299. VAR n, i, k, w: CARDINAL;
  1300. fn: SymTab.Name;
  1301. ft: SymTab.TypeIndex;
  1302. cls: INTEGER;
  1303. sub: QVal;
  1304. PROCEDURE Sep;
  1305. BEGIN
  1306. IF first THEN first := FALSE ELSE W(", ") END
  1307. END Sep;
  1308. BEGIN
  1309. n := SymTab.FieldCount(t);
  1310. i := 0;
  1311. WHILE i < n DO
  1312. SymTab.FieldName(t, i, fn);
  1313. ft := SymTab.FieldType(t, fn);
  1314. cls := SymTab.ClassOf(ft);
  1315. IF cls = SymTab.ClReal THEN Sep; W("d 0")
  1316. ELSIF cls = SymTab.ClChar THEN Sep; W("b 0")
  1317. ELSIF cls = SymTab.ClArray THEN
  1318. Sep;
  1319. Cpy(sub, prefix); App(sub, "_"); App(sub, fn);
  1320. W("l $"); W(sub)
  1321. ELSIF cls = SymTab.ClSet THEN
  1322. w := SymTab.SetWords(ft);
  1323. IF w = 0 THEN w := 1 END;
  1324. Sep; W("w 0");
  1325. k := 1;
  1326. WHILE k < w DO W(", w 0"); INC(k) END
  1327. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  1328. Cpy(sub, prefix); App(sub, "_"); App(sub, fn);
  1329. RecItems(ft, sub, first)
  1330. ELSE Sep; W("w 0")
  1331. END;
  1332. INC(i)
  1333. END
  1334. END RecItems;
  1335. PROCEDURE DeclRec (name: ARRAY OF CHAR; t: INTEGER);
  1336. VAR first: BOOLEAN;
  1337. BEGIN
  1338. IF ~opened THEN RETURN END;
  1339. RecStatics(name, t);
  1340. W("data $"); W(name);
  1341. W(" = { ");
  1342. first := TRUE;
  1343. RecItems(t, name, first);
  1344. IF first THEN W("w 0") END;
  1345. WL(" }")
  1346. END DeclRec;
  1347. PROCEDURE FieldAddr (base: ARRAY OF CHAR; off: INTEGER; VAR q: QVal);
  1348. VAR sb: QVal;
  1349. BEGIN
  1350. NewTemp(q);
  1351. IntStr(off, sb);
  1352. Op3L("add", q, base, sb)
  1353. END FieldAddr;
  1354. PROCEDURE PushWith (base: ARRAY OF CHAR);
  1355. BEGIN
  1356. IF withTop <= HIGH(withSt) THEN
  1357. Cpy(withSt[withTop], base); INC(withTop)
  1358. END
  1359. END PushWith;
  1360. PROCEDURE PopWith;
  1361. BEGIN
  1362. IF withTop > 0 THEN DEC(withTop) END
  1363. END PopWith;
  1364. PROCEDURE TopWith (VAR base: QVal): BOOLEAN;
  1365. BEGIN
  1366. IF withTop = 0 THEN RETURN FALSE END;
  1367. Cpy(base, withSt[withTop - 1]);
  1368. RETURN TRUE
  1369. END TopWith;
  1370. PROCEDURE CopyRecord (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  1371. t: INTEGER);
  1372. (* Deep whole-record copy: scalars/sets by load/store, arrays via
  1373. CopyArray on dereferenced fields, nested records recurse. *)
  1374. VAR n, i: CARDINAL;
  1375. fn: SymTab.Name;
  1376. ft: SymTab.TypeIndex;
  1377. cls: INTEGER;
  1378. dd, ds, di, si, v: QVal;
  1379. off: QVal;
  1380. BEGIN
  1381. n := SymTab.FieldCount(t);
  1382. i := 0;
  1383. WHILE i < n DO
  1384. SymTab.FieldName(t, i, fn);
  1385. ft := SymTab.FieldType(t, fn);
  1386. cls := SymTab.ClassOf(ft);
  1387. IntStr(SymTab.FieldOffset(t, fn), off);
  1388. NewTemp(dd); Op3L("add", dd, dst, off);
  1389. NewTemp(ds); Op3L("add", ds, src, off);
  1390. IF cls = SymTab.ClArray THEN
  1391. NewTemp(di);
  1392. W(" "); W(di); W(" =l loadl "); WL(dd);
  1393. NewTemp(si);
  1394. W(" "); W(si); W(" =l loadl "); WL(ds);
  1395. CopyArray(di, si, ft)
  1396. ELSIF cls = SymTab.ClSet THEN
  1397. CopySet(dd, ds, SymTab.SetWords(ft), SymTab.SetWords(ft))
  1398. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  1399. CopyRecord(dd, ds, ft)
  1400. ELSE
  1401. ElemLoad(ds, ft, v);
  1402. ElemStore(dd, v, ft)
  1403. END;
  1404. INC(i)
  1405. END
  1406. END CopyRecord;
  1407. PROCEDURE WordsBytes (words: CARDINAL): CARDINAL;
  1408. BEGIN
  1409. IF words = 0 THEN RETURN 8 END;
  1410. RETURN ((words * 4 + 7) DIV 8) * 8
  1411. END WordsBytes;
  1412. PROCEDURE DeclSet (name: ARRAY OF CHAR; t: INTEGER);
  1413. VAR w, i: CARDINAL;
  1414. BEGIN
  1415. IF ~opened THEN RETURN END;
  1416. w := SymTab.SetWords(t);
  1417. IF w = 0 THEN w := 1 END;
  1418. W("data $"); W(name);
  1419. W(" = { w 0");
  1420. i := 1;
  1421. WHILE i < w DO
  1422. W(", w 0");
  1423. INC(i)
  1424. END;
  1425. WL(" }")
  1426. END DeclSet;
  1427. PROCEDURE NewSetTemp (words: CARDINAL; VAR q: QVal);
  1428. VAR nb: QVal;
  1429. BEGIN
  1430. NewTemp(q);
  1431. Revive;
  1432. IntStr(VAL(INTEGER, WordsBytes(words)), nb);
  1433. W(" "); W(q); W(" =l alloc8 "); WL(nb)
  1434. END NewSetTemp;
  1435. PROCEDURE SetZero (addr: ARRAY OF CHAR; words: CARDINAL);
  1436. VAR i: CARDINAL;
  1437. a, z, off: QVal;
  1438. BEGIN
  1439. NewTemp(z);
  1440. Op3("xor", z, "0", "0", FALSE);
  1441. i := 0;
  1442. WHILE i < words DO
  1443. NewTemp(a);
  1444. IntStr(VAL(INTEGER, i * 4), off);
  1445. Op3L("add", a, addr, off);
  1446. Revive;
  1447. W(" storew "); W(z); W(", "); WL(a);
  1448. INC(i)
  1449. END
  1450. END SetZero;
  1451. PROCEDURE SetBit (addr: ARRAY OF CHAR; val: ARRAY OF CHAR;
  1452. lo: INTEGER; span: CARDINAL);
  1453. (* ORs one element in: off = val - lo trapped in [0, span). *)
  1454. VAR off, offL, hiS, loS: QVal;
  1455. wi, bi, wil, off4, wa, wcur, m, wn: QVal;
  1456. BEGIN
  1457. NewTemp(off);
  1458. IntStr(lo, loS);
  1459. Op3("sub", off, val, loS, FALSE);
  1460. WidenIndex(off, offL);
  1461. IntStr(VAL(INTEGER, span) - 1, hiS);
  1462. CheckRange(offL, "0", hiS);
  1463. NewTemp(wi);
  1464. Op3("shr", wi, off, "5", FALSE);
  1465. NewTemp(bi);
  1466. Op3("and", bi, off, "31", FALSE);
  1467. WidenIndex(wi, wil);
  1468. NewTemp(off4);
  1469. Op3L("mul", off4, wil, "4");
  1470. NewTemp(wa);
  1471. Op3L("add", wa, addr, off4);
  1472. NewTemp(m);
  1473. Op3("shl", m, "1", bi, FALSE);
  1474. NewTemp(wcur);
  1475. W(" "); W(wcur); W(" =w loadw "); WL(wa);
  1476. NewTemp(wn);
  1477. Op3("or", wn, wcur, m, FALSE);
  1478. Revive;
  1479. W(" storew "); W(wn); W(", "); WL(wa)
  1480. END SetBit;
  1481. PROCEDURE SetRange (addr: ARRAY OF CHAR; a: ARRAY OF CHAR;
  1482. b: ARRAY OF CHAR; lo: INTEGER; span: CARDINAL);
  1483. VAR al, bl, hiS: QVal;
  1484. cur, c: QVal;
  1485. ltop, lbody, lend: QVal;
  1486. BEGIN
  1487. WidenIndex(a, al);
  1488. WidenIndex(b, bl);
  1489. IntStr(VAL(INTEGER, span) - 1, hiS);
  1490. CheckRange(al, "0", hiS);
  1491. CheckRange(bl, "0", hiS);
  1492. NewTemp(cur);
  1493. Op3("add", cur, a, "0", FALSE);
  1494. NewLabel(ltop); NewLabel(lbody); NewLabel(lend);
  1495. EmitLabel(ltop);
  1496. NewTemp(c);
  1497. Op3("cslew", c, cur, b, FALSE);
  1498. Jnz(c, lbody, lend);
  1499. EmitLabel(lbody);
  1500. SetBit(addr, cur, lo, span);
  1501. Op3("add", cur, cur, "1", FALSE);
  1502. Jmp(ltop);
  1503. EmitLabel(lend)
  1504. END SetRange;
  1505. PROCEDURE SetBinOp (sel: INTEGER; l: ARRAY OF CHAR; r: ARRAY OF CHAR;
  1506. lw, rw: CARDINAL; VAR q: QVal);
  1507. (* Union/intersection/difference/symdiff over possibly different
  1508. spans: overlap via op, larger-side extras copied (union/symdiff/
  1509. left-diff) or zeroed. Result has max words. *)
  1510. VAR i, m, res: CARDINAL;
  1511. la, ra, ta, a, b, c, nb, z: QVal;
  1512. BEGIN
  1513. m := lw;
  1514. IF rw < m THEN m := rw END;
  1515. res := lw;
  1516. IF rw > res THEN res := rw END;
  1517. NewSetTemp(res, q);
  1518. NewTemp(z);
  1519. Op3("xor", z, "0", "0", FALSE);
  1520. i := 0;
  1521. WHILE i < m DO
  1522. IntStr(VAL(INTEGER, i * 4), nb);
  1523. NewTemp(la); Op3L("add", la, l, nb);
  1524. NewTemp(ra); Op3L("add", ra, r, nb);
  1525. NewTemp(ta); Op3L("add", ta, q, nb);
  1526. NewTemp(a);
  1527. W(" "); W(a); W(" =w loadw "); WL(la);
  1528. NewTemp(b);
  1529. W(" "); W(b); W(" =w loadw "); WL(ra);
  1530. NewTemp(c);
  1531. IF sel = 0 THEN Op3("or", c, a, b, FALSE)
  1532. ELSIF sel = 1 THEN Op3("and", c, a, b, FALSE)
  1533. ELSIF sel = 2 THEN
  1534. NewTemp(nb);
  1535. Op3("xor", nb, b, "-1", FALSE);
  1536. Op3("and", c, a, nb, FALSE)
  1537. ELSE Op3("xor", c, a, b, FALSE)
  1538. END;
  1539. Revive;
  1540. W(" storew "); W(c); W(", "); WL(ta);
  1541. INC(i)
  1542. END;
  1543. WHILE i < lw DO
  1544. IntStr(VAL(INTEGER, i * 4), nb);
  1545. NewTemp(la); Op3L("add", la, l, nb);
  1546. NewTemp(ta); Op3L("add", ta, q, nb);
  1547. IF (sel = 0) OR (sel = 2) OR (sel = 3) THEN
  1548. NewTemp(a);
  1549. W(" "); W(a); W(" =w loadw "); WL(la);
  1550. Revive;
  1551. W(" storew "); W(a); W(", "); WL(ta)
  1552. ELSE
  1553. Revive;
  1554. W(" storew "); W(z); W(", "); WL(ta)
  1555. END;
  1556. INC(i)
  1557. END;
  1558. WHILE i < rw DO
  1559. IntStr(VAL(INTEGER, i * 4), nb);
  1560. NewTemp(ra); Op3L("add", ra, r, nb);
  1561. NewTemp(ta); Op3L("add", ta, q, nb);
  1562. IF (sel = 0) OR (sel = 3) THEN
  1563. NewTemp(b);
  1564. W(" "); W(b); W(" =w loadw "); WL(ra);
  1565. Revive;
  1566. W(" storew "); W(b); W(", "); WL(ta)
  1567. ELSE
  1568. Revive;
  1569. W(" storew "); W(z); W(", "); WL(ta)
  1570. END;
  1571. INC(i)
  1572. END
  1573. END SetBinOp;
  1574. PROCEDURE CmpSet (op: INTEGER; l: ARRAY OF CHAR; r: ARRAY OF CHAR;
  1575. lw, rw: CARDINAL; VAR q: QVal);
  1576. VAR i, m: CARDINAL;
  1577. la, ra, a, b, c, acc, nb: QVal;
  1578. BEGIN
  1579. NewTemp(acc);
  1580. Op3("xor", acc, "1", "0", FALSE);
  1581. m := lw;
  1582. IF rw < m THEN m := rw END;
  1583. i := 0;
  1584. WHILE i < m DO
  1585. IntStr(VAL(INTEGER, i * 4), nb);
  1586. NewTemp(la); Op3L("add", la, l, nb);
  1587. NewTemp(ra); Op3L("add", ra, r, nb);
  1588. NewTemp(a);
  1589. W(" "); W(a); W(" =w loadw "); WL(la);
  1590. NewTemp(b);
  1591. W(" "); W(b); W(" =w loadw "); WL(ra);
  1592. NewTemp(c);
  1593. Op3("ceqw", c, a, b, FALSE);
  1594. NewTemp(q);
  1595. Op3("and", q, acc, c, FALSE);
  1596. CopyOp(q, acc);
  1597. INC(i)
  1598. END;
  1599. WHILE i < lw DO
  1600. IntStr(VAL(INTEGER, i * 4), nb);
  1601. NewTemp(la); Op3L("add", la, l, nb);
  1602. NewTemp(a);
  1603. W(" "); W(a); W(" =w loadw "); WL(la);
  1604. NewTemp(c);
  1605. Op3("ceqw", c, a, "0", FALSE);
  1606. NewTemp(q);
  1607. Op3("and", q, acc, c, FALSE);
  1608. CopyOp(q, acc);
  1609. INC(i)
  1610. END;
  1611. WHILE i < rw DO
  1612. IntStr(VAL(INTEGER, i * 4), nb);
  1613. NewTemp(ra); Op3L("add", ra, r, nb);
  1614. NewTemp(b);
  1615. W(" "); W(b); W(" =w loadw "); WL(ra);
  1616. NewTemp(c);
  1617. Op3("ceqw", c, b, "0", FALSE);
  1618. NewTemp(q);
  1619. Op3("and", q, acc, c, FALSE);
  1620. CopyOp(q, acc);
  1621. INC(i)
  1622. END;
  1623. IF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN
  1624. NewTemp(q);
  1625. Op3("xor", q, acc, "1", FALSE)
  1626. ELSE
  1627. CopyOp(acc, q)
  1628. END
  1629. END CmpSet;
  1630. PROCEDURE CopySet (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  1631. dw, sw: CARDINAL);
  1632. (* Copies min words via memcpy, zero-fills dst extras. Src extras
  1633. beyond dst must be zero (trap) — otherwise out-of-span bits
  1634. would vanish silently on narrowing assignment. *)
  1635. VAR m, i: CARDINAL;
  1636. n, da, sa, a, z, off, c: QVal;
  1637. qr, acc, lok, lbad: QVal;
  1638. BEGIN
  1639. m := dw;
  1640. IF sw < m THEN m := sw END;
  1641. IF sw > dw THEN
  1642. NewTemp(acc);
  1643. Op3("xor", acc, "1", "0", FALSE);
  1644. i := dw;
  1645. WHILE i < sw DO
  1646. IntStr(VAL(INTEGER, i * 4), off);
  1647. NewTemp(a); Op3L("add", a, src, off);
  1648. NewTemp(c);
  1649. W(" "); W(c); W(" =w loadw "); WL(a);
  1650. NewTemp(qr);
  1651. Op3("ceqw", qr, c, "0", FALSE);
  1652. NewTemp(c);
  1653. Op3("and", c, acc, qr, FALSE);
  1654. CopyOp(c, acc);
  1655. INC(i)
  1656. END;
  1657. NewLabel(lok); NewLabel(lbad);
  1658. Jnz(acc, lok, lbad);
  1659. EmitLabel(lbad);
  1660. Trap;
  1661. EmitLabel(lok)
  1662. END;;
  1663. IF m > 0 THEN
  1664. IntStr(VAL(INTEGER, m * 4), n);
  1665. NewTemp(qr);
  1666. W(" "); W(qr); W(" =l call $memcpy(l ");
  1667. W(dst); W(", l "); W(src); W(", l "); W(n); WL(")")
  1668. END;
  1669. NewTemp(z);
  1670. Op3("xor", z, "0", "0", FALSE);
  1671. i := m;
  1672. WHILE i < dw DO
  1673. NewTemp(a);
  1674. IntStr(VAL(INTEGER, i * 4), off);
  1675. Op3L("add", a, dst, off);
  1676. Revive;
  1677. W(" storew "); W(z); W(", "); WL(a);
  1678. INC(i)
  1679. END
  1680. END CopySet;
  1681. PROCEDURE InSet (x: ARRAY OF CHAR; s: ARRAY OF CHAR; lo: INTEGER;
  1682. span: CARDINAL; VAR q: QVal);
  1683. (* Membership bit test with span trap; q is fresh w 0/1. *)
  1684. VAR off, offL, hiS, loS: QVal;
  1685. wi, bi, wil, off4, wa, wcur, m, a: QVal;
  1686. spanS: QVal;
  1687. BEGIN
  1688. NewTemp(off);
  1689. IntStr(lo, loS);
  1690. Op3("sub", off, x, loS, FALSE);
  1691. WidenIndex(off, offL);
  1692. IntStr(VAL(INTEGER, span) - 1, spanS);
  1693. CheckRange(offL, "0", spanS);
  1694. NewTemp(wi);
  1695. Op3("shr", wi, off, "5", FALSE);
  1696. NewTemp(bi);
  1697. Op3("and", bi, off, "31", FALSE);
  1698. WidenIndex(wi, wil);
  1699. NewTemp(off4);
  1700. Op3L("mul", off4, wil, "4");
  1701. NewTemp(wa);
  1702. Op3L("add", wa, s, off4);
  1703. NewTemp(wcur);
  1704. W(" "); W(wcur); W(" =w loadw "); WL(wa);
  1705. NewTemp(m);
  1706. Op3("shl", m, "1", bi, FALSE);
  1707. NewTemp(a);
  1708. Op3("and", a, wcur, m, FALSE);
  1709. NewTemp(q);
  1710. Op3("cnew", q, a, "0", FALSE)
  1711. END InSet;
  1712. PROCEDURE WidenIndex (idx: ARRAY OF CHAR; VAR q: QVal);
  1713. BEGIN
  1714. IF IsImm(idx) THEN Cpy(q, idx)
  1715. ELSE
  1716. NewTemp(q);
  1717. Revive;
  1718. W(" "); W(q); W(" =l extsw "); WL(idx)
  1719. END
  1720. END WidenIndex;
  1721. PROCEDURE OpenHi (base: ARRAY OF CHAR; VAR q: QVal);
  1722. VAR c: QVal;
  1723. BEGIN
  1724. NewTemp(c);
  1725. Revive;
  1726. W(" "); W(c); W(" =l loadl "); WL(base);
  1727. NewTemp(q);
  1728. Op3L("sub", q, c, "1")
  1729. END OpenHi;
  1730. PROCEDURE CheckRange (idx, lo, hi: ARRAY OF CHAR);
  1731. (* l-domain operands (widened index, immediates, or open hi temp);
  1732. comparisons are long (result w). *)
  1733. VAR c1, c2, c: QVal;
  1734. lok, lbad: QVal;
  1735. BEGIN
  1736. NewTemp(c1);
  1737. Op3("csgel", c1, idx, lo, FALSE);
  1738. NewTemp(c2);
  1739. Op3("cslel", c2, idx, hi, FALSE);
  1740. NewTemp(c);
  1741. Op3("and", c, c1, c2, FALSE);
  1742. NewLabel(lok); NewLabel(lbad);
  1743. Jnz(c, lok, lbad);
  1744. EmitLabel(lbad);
  1745. Trap;
  1746. EmitLabel(lok)
  1747. END CheckRange;
  1748. PROCEDURE ElemAddr (base, idx, lo: ARRAY OF CHAR; elemT: INTEGER;
  1749. VAR q: QVal);
  1750. (* q := base + 8 + (idx - lo) * elemSize in l, fresh temp.
  1751. elemT is the array descriptor (open or fixed); all operands
  1752. l-domain (immediates pass, temps pre-widened). *)
  1753. VAR t1, t2, tb, sb: QVal;
  1754. BEGIN
  1755. NewTemp(t1);
  1756. Op3L("sub", t1, idx, lo);
  1757. IntStr(VAL(INTEGER, ElemSize(elemT)), sb);
  1758. NewTemp(t2);
  1759. Op3L("mul", t2, t1, sb);
  1760. NewTemp(tb);
  1761. Op3L("add", tb, base, "8");
  1762. NewTemp(q);
  1763. Op3L("add", q, tb, t2)
  1764. END ElemAddr;
  1765. PROCEDURE ElemLoad (addr: ARRAY OF CHAR; t: INTEGER; VAR q: QVal);
  1766. (* Loads one element of (element-)type t. Nested/pointer elements
  1767. are addresses (loadl). *)
  1768. VAR cls: INTEGER;
  1769. BEGIN
  1770. cls := SymTab.ClassOf(t);
  1771. NewTemp(q);
  1772. Revive;
  1773. W(" "); W(q);
  1774. IF cls = SymTab.ClReal THEN W(" =d loadd ")
  1775. ELSIF (cls = SymTab.ClArray) OR (cls = SymTab.ClPtr) THEN
  1776. W(" =l loadl ")
  1777. ELSIF cls = SymTab.ClChar THEN W(" =w loadub ")
  1778. ELSE W(" =w loadw ")
  1779. END;
  1780. WL(addr)
  1781. END ElemLoad;
  1782. PROCEDURE ElemStore (addr, v: ARRAY OF CHAR; t: INTEGER);
  1783. VAR cls: INTEGER;
  1784. BEGIN
  1785. cls := SymTab.ClassOf(t);
  1786. Revive;
  1787. IF cls = SymTab.ClReal THEN W(" stored ")
  1788. ELSIF (cls = SymTab.ClArray) OR (cls = SymTab.ClPtr) THEN
  1789. W(" storel ")
  1790. ELSIF cls = SymTab.ClChar THEN W(" storeb ")
  1791. ELSE W(" storew ")
  1792. END;
  1793. W(v); W(", "); WL(addr)
  1794. END ElemStore;
  1795. PROCEDURE CopyArray (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  1796. t: INTEGER);
  1797. (* Whole-array copy with runtime count check + blit. Nested levels
  1798. recurse through a runtime loop; counts mismatch traps. dst/src
  1799. are descriptor address operands; t is the destination type. *)
  1800. VAR dc, sc, ok: QVal;
  1801. lok, lbad: QVal;
  1802. ecls: INTEGER;
  1803. n, da, sa: QVal;
  1804. sb: QVal;
  1805. qr: QVal;
  1806. i, c, de, se, di, si, dd0, doff, sd0, soff: QVal;
  1807. ltop, lbody, lend: QVal;
  1808. BEGIN
  1809. NewTemp(dc);
  1810. Revive;
  1811. W(" "); W(dc); W(" =l loadl "); WL(dst);
  1812. NewTemp(sc);
  1813. W(" "); W(sc); W(" =l loadl "); WL(src);
  1814. NewTemp(ok);
  1815. Op3("ceql", ok, dc, sc, FALSE);
  1816. NewLabel(lok); NewLabel(lbad);
  1817. Jnz(ok, lok, lbad);
  1818. EmitLabel(lbad);
  1819. Trap;
  1820. EmitLabel(lok);
  1821. ecls := ElemCls(t);
  1822. IF (ecls = SymTab.ClArray) THEN
  1823. NewTemp(i);
  1824. W(" "); W(i); W(" =l copy 0"); WL("");
  1825. NewLabel(ltop); NewLabel(lbody); NewLabel(lend);
  1826. EmitLabel(ltop);
  1827. NewTemp(c);
  1828. Op3("csltl", c, i, dc, FALSE);
  1829. Jnz(c, lbody, lend);
  1830. EmitLabel(lbody);
  1831. NewTemp(dd0); Op3L("add", dd0, dst, "8");
  1832. NewTemp(doff); Op3L("mul", doff, i, "8");
  1833. NewTemp(de); Op3L("add", de, dd0, doff);
  1834. NewTemp(sd0); Op3L("add", sd0, src, "8");
  1835. NewTemp(soff); Op3L("mul", soff, i, "8");
  1836. NewTemp(se); Op3L("add", se, sd0, soff);
  1837. NewTemp(di);
  1838. W(" "); W(di); W(" =l loadl "); WL(de);
  1839. NewTemp(si);
  1840. W(" "); W(si); W(" =l loadl "); WL(se);
  1841. CopyArray(di, si, SymTab.ArrayElem(t));
  1842. Op3L("add", i, i, "1");
  1843. Jmp(ltop);
  1844. EmitLabel(lend)
  1845. ELSE
  1846. IntStr(VAL(INTEGER, ElemSize(t)), sb);
  1847. NewTemp(n);
  1848. Op3L("mul", n, dc, sb);
  1849. NewTemp(da);
  1850. Op3L("add", da, dst, "8");
  1851. NewTemp(sa);
  1852. Op3L("add", sa, src, "8");
  1853. NewTemp(qr);
  1854. W(" "); W(qr); W(" =l call $memcpy(l ");
  1855. W(da); W(", l "); W(sa); W(", l "); W(n); WL(")")
  1856. END
  1857. END CopyArray;
  1858. PROCEDURE DeclStr (text: ARRAY OF CHAR; VAR q: QVal);
  1859. (* Records a quoted literal for top-level emission at EndModule and
  1860. returns its address operand ($strN). Data definitions may only
  1861. appear outside functions, but literals occur mid-body. *)
  1862. VAR nm: QVal;
  1863. BEGIN
  1864. Cpy(nm, "str");
  1865. AppNum(nm, nStr);
  1866. IF nStr <= HIGH(strNams) THEN
  1867. Cpy(strNams[nStr], nm);
  1868. Cpy(strTexts[nStr], text);
  1869. INC(nStr)
  1870. END;
  1871. Cpy(q, "$");
  1872. App(q, nm)
  1873. END DeclStr;
  1874. PROCEDURE FlushStrings;
  1875. (* Emits all recorded string literals as top-level data. *)
  1876. VAR k, i, L: CARDINAL;
  1877. bv: QVal;
  1878. BEGIN
  1879. IF ~opened THEN RETURN END;
  1880. k := 0;
  1881. WHILE k < nStr DO
  1882. L := Len(strTexts[k]);
  1883. IF L >= 2 THEN
  1884. W("data $"); W(strNams[k]);
  1885. W(" = { l ");
  1886. IntStr(VAL(INTEGER, L - 2), bv);
  1887. W(bv);
  1888. i := 1;
  1889. WHILE i < L - 1 DO
  1890. W(", b ");
  1891. IntStr(ORD(strTexts[k][i]), bv);
  1892. W(bv);
  1893. INC(i)
  1894. END;
  1895. WL(" }")
  1896. END;
  1897. INC(k)
  1898. END
  1899. END FlushStrings;
  1900. PROCEDURE ArrData (name: ARRAY OF CHAR; t: SymTab.TypeIndex);
  1901. (* Recursive data emission; nested levels as $name_i. *)
  1902. VAR n, i: CARDINAL;
  1903. elem: SymTab.TypeIndex;
  1904. ecls: INTEGER;
  1905. cls: INTEGER;
  1906. bv: QVal;
  1907. sub: QVal;
  1908. BEGIN
  1909. IF ~opened THEN RETURN END;
  1910. n := SymTab.ArrayLen(t);
  1911. elem := SymTab.ArrayElem(t);
  1912. ecls := SymTab.ClassOf(elem);
  1913. W("data $"); W(name);
  1914. W(" = { l ");
  1915. IntStr(VAL(INTEGER, n), bv);
  1916. W(bv);
  1917. IF ecls = SymTab.ClArray THEN
  1918. i := 0;
  1919. WHILE i < n DO
  1920. W(", l $"); W(name); W("_");
  1921. IntStr(VAL(INTEGER, i), bv);
  1922. W(bv);
  1923. INC(i)
  1924. END;
  1925. WL(" }");
  1926. i := 0;
  1927. WHILE i < n DO
  1928. Cpy(sub, name); App(sub, "_");
  1929. IntStr(VAL(INTEGER, i), bv);
  1930. App(sub, bv);
  1931. ArrData(sub, elem);
  1932. INC(i)
  1933. END
  1934. ELSE
  1935. IF ecls = SymTab.ClChar THEN Cpy(bv, "b")
  1936. ELSIF ecls = SymTab.ClReal THEN Cpy(bv, "d")
  1937. ELSIF (ecls = SymTab.ClPtr) THEN Cpy(bv, "l")
  1938. ELSE Cpy(bv, "w")
  1939. END;
  1940. i := 0;
  1941. WHILE i < n DO
  1942. W(", "); W(bv); W(" 0");
  1943. INC(i)
  1944. END;
  1945. WL(" }")
  1946. END
  1947. END ArrData;
  1948. PROCEDURE DeclArr (name: ARRAY OF CHAR; t: INTEGER);
  1949. BEGIN
  1950. IF SymTab.IsOpenArray(t) OR (SymTab.ArrayDepth(t) = 0) THEN
  1951. DataLine(name, FALSE, "0"); RETURN
  1952. END;
  1953. ArrData(name, t)
  1954. END DeclArr;
  1955. PROCEDURE PushLoop (exit: ARRAY OF CHAR);
  1956. BEGIN
  1957. IF loopTop <= HIGH(loopSt) THEN
  1958. Cpy(loopSt[loopTop], exit); INC(loopTop)
  1959. END
  1960. END PushLoop;
  1961. PROCEDURE PopLoop;
  1962. BEGIN
  1963. IF loopTop > 0 THEN DEC(loopTop) END
  1964. END PopLoop;
  1965. PROCEDURE TopLoop (VAR exit: QVal): BOOLEAN;
  1966. BEGIN
  1967. IF loopTop = 0 THEN RETURN FALSE END;
  1968. Cpy(exit, loopSt[loopTop - 1]);
  1969. RETURN TRUE
  1970. END TopLoop;
  1971. PROCEDURE CmpL (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal);
  1972. VAR mn : ARRAY [0 .. 7] OF CHAR;
  1973. BEGIN
  1974. mn[0] := 0C;
  1975. IF op = SymTab.OpEq THEN Cpy(mn, "ceql")
  1976. ELSE Cpy(mn, "cnel")
  1977. END;
  1978. NewTemp(q);
  1979. Op3(mn, q, l, r, FALSE)
  1980. END CmpL;
  1981. PROCEDURE Remark (s: ARRAY OF CHAR);
  1982. BEGIN
  1983. Revive;
  1984. W("# "); WL(s)
  1985. END Remark;
  1986. (* ---------------- heap (step 3.6: extern malloc/free) ---------------- *)
  1987. (* Only the object skeleton is initialized (array counts); elements
  1988. and members stay garbage per Wirth, except nested objects which
  1989. are allocated recursively. DISPOSE is shallow (documented). *)
  1990. PROCEDURE HeapSize (t: SymTab.TypeIndex): CARDINAL;
  1991. VAR cls: INTEGER;
  1992. BEGIN
  1993. cls := SymTab.ClassOf(t);
  1994. IF cls = SymTab.ClArray THEN
  1995. RETURN 8 + SymTab.ArrayLen(t) * ElemSize(t)
  1996. END;
  1997. RETURN SymTab.TypeSize(t)
  1998. END HeapSize;
  1999. PROCEDURE NewHeap (t: SymTab.TypeIndex; VAR q: QVal);
  2000. VAR nb: QVal;
  2001. BEGIN
  2002. NewTemp(q);
  2003. Revive;
  2004. IntStr(VAL(INTEGER, HeapSize(t)), nb);
  2005. W(" "); W(q);
  2006. IF useStack THEN W(" =l alloc8 "); W(nb); WL("")
  2007. ELSE W(" =l call $malloc(l "); W(nb); WL(")")
  2008. END
  2009. END NewHeap;
  2010. PROCEDURE FreeHeap (v: ARRAY OF CHAR);
  2011. BEGIN
  2012. Revive;
  2013. W(" call $free(l "); W(v); WL(")")
  2014. END FreeHeap;
  2015. PROCEDURE InitHeap (addr: ARRAY OF CHAR; t: SymTab.TypeIndex);
  2016. VAR cls, ecls: INTEGER;
  2017. n, i: CARDINAL;
  2018. fn: SymTab.Name;
  2019. ft: SymTab.TypeIndex;
  2020. nb, ea, eb, fa, fb: QVal;
  2021. BEGIN
  2022. cls := SymTab.ClassOf(t);
  2023. IF cls = SymTab.ClArray THEN
  2024. IntStr(VAL(INTEGER, SymTab.ArrayLen(t)), nb);
  2025. Revive;
  2026. W(" storel "); W(nb); W(", "); WL(addr);
  2027. ecls := SymTab.ClassOf(SymTab.ArrayElem(t));
  2028. IF ecls = SymTab.ClArray THEN
  2029. n := SymTab.ArrayLen(t);
  2030. i := 0;
  2031. WHILE i < n DO
  2032. IntStr(VAL(INTEGER, 8 + i * 8), nb);
  2033. NewTemp(ea);
  2034. Op3L("add", ea, addr, nb);
  2035. NewHeap(SymTab.ArrayElem(t), eb);
  2036. Revive;
  2037. W(" storel "); W(eb); W(", "); WL(ea);
  2038. INC(i)
  2039. END
  2040. END
  2041. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  2042. n := SymTab.FieldCount(t);
  2043. i := 0;
  2044. WHILE i < n DO
  2045. SymTab.FieldName(t, i, fn);
  2046. ft := SymTab.FieldType(t, fn);
  2047. ecls := SymTab.ClassOf(ft);
  2048. IF ecls = SymTab.ClArray THEN
  2049. IntStr(SymTab.FieldOffset(t, fn), nb);
  2050. NewTemp(fa);
  2051. Op3L("add", fa, addr, nb);
  2052. NewHeap(ft, fb);
  2053. InitHeap(fb, ft);
  2054. Revive;
  2055. W(" storel "); W(fb); W(", "); WL(fa)
  2056. ELSIF (ecls = SymTab.ClRecord) OR (ecls = SymTab.ClClass) THEN
  2057. IntStr(SymTab.FieldOffset(t, fn), nb);
  2058. NewTemp(fa);
  2059. Op3L("add", fa, addr, nb);
  2060. InitHeap(fa, ft)
  2061. END;
  2062. INC(i)
  2063. END
  2064. END
  2065. END InitHeap;
  2066. BEGIN
  2067. opened := FALSE;
  2068. inBody := FALSE;
  2069. dead := FALSE;
  2070. nTemp := 0; nLab := 0; loopTop := 0; nR := 0; nStr := 0;
  2071. withTop := 0;
  2072. noEmit := FALSE; inFunc := FALSE; useStack := FALSE;
  2073. nLoc := 0; nPar := 0; nArg := 0; nn := 0; callDepth := 0;
  2074. funcDepth := 0; scopeTop := 0; scopeBase[0] := 0;
  2075. outSel := 0
  2076. END QbeGen.