Lower.mod 100 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680
  1. IMPLEMENTATION MODULE Lower;
  2. (* Scalar/boolean/control-flow walk (L0-L2): see Lower.def and
  3. docs/plan-lower.md. The mutually recursive walkers are declared in
  4. Lower.def (gm2's link pass rejects FORWARD, V3 has no whole-module
  5. pass, so a definition-visible declaration breaks the cycle). *)
  6. IMPORT AST, SymTab, QbeGen;
  7. (* ---------------- self-contained symbol tables (zero SymTab surface) ----
  8. Flat arrays only, no ARRAY OF RECORD: a record's array field loses its
  9. length word in static array data, and V3 miscompiles that when the
  10. field is passed as an open array (docs/wip/nested-array-field-bug.mod).
  11. Names live in flat CHAR arrays indexed manually at slot * 64. *)
  12. CONST
  13. MaxSym = 8192; (* whole-session: >4096 vars/consts/params *)
  14. MaxName = 63;
  15. MaxProc = 2048; (* whole-session: the compiler declares >1200 procs *)
  16. MaxImp = 512; (* per-unit imports *)
  17. MaxPar = 32;
  18. HashSize = 16384; (* power of two > MaxSym, MaxProc: open addressing *)
  19. MaxCFold = 256; (* named compile-time set constants per session *)
  20. MaxCFoldW = 16; (* mask words (512 bits); wider sets are a 230 *)
  21. VAR
  22. symName : ARRAY [0 .. MaxSym * 64 - 1] OF CHAR;
  23. symKind : ARRAY [0 .. MaxSym - 1] OF INTEGER;
  24. symTy : ARRAY [0 .. MaxSym - 1] OF SymTab.TypeIndex;
  25. symVal : ARRAY [0 .. MaxSym * 64 - 1] OF CHAR; (* const value, flat *)
  26. nSyms : CARDINAL;
  27. procName : ARRAY [0 .. MaxProc * 64 - 1] OF CHAR;
  28. procUid : ARRAY [0 .. MaxProc - 1] OF CARDINAL;
  29. procRes : ARRAY [0 .. MaxProc - 1] OF SymTab.TypeIndex;
  30. procDep : ARRAY [0 .. MaxProc - 1] OF CARDINAL;
  31. procExt : ARRAY [0 .. MaxProc - 1] OF BOOLEAN;
  32. procVa : ARRAY [0 .. MaxProc - 1] OF BOOLEAN; (* C varargs *)
  33. procNpar : ARRAY [0 .. MaxProc - 1] OF CARDINAL;
  34. parTy : ARRAY [0 .. MaxProc * MaxPar - 1] OF SymTab.TypeIndex;
  35. parVar : ARRAY [0 .. MaxProc * MaxPar - 1] OF BOOLEAN;
  36. parName : ARRAY [0 .. MaxProc * MaxPar * 64 - 1] OF CHAR;
  37. nProcs : CARDINAL;
  38. (* Open-addressing indexes into symName/procName: entry = index+1,
  39. 0 = empty. A whole-session linear scan is too slow (thousands of
  40. lookups over thousands of entries), so FindSym/FindProc hash. *)
  41. symHash : ARRAY [0 .. HashSize - 1] OF INTEGER;
  42. procHash : ARRAY [0 .. HashSize - 1] OF INTEGER;
  43. (* Per-unit imports (FROM M IMPORT P): the exact proc entry for a
  44. name, so an unqualified call resolves to the imported proc even
  45. when another module declares the same name. Reset each unit. *)
  46. impProc : ARRAY [0 .. MaxImp - 1] OF INTEGER;
  47. impName : ARRAY [0 .. MaxImp * 64 - 1] OF CHAR;
  48. nImps : CARDINAL;
  49. (* Record-array globals too large to expand inline: their template is
  50. emitted with their data and their elements are initialised by a
  51. run-time loop (QbeGen.InitRecArray) in the unit's init. Per unit. *)
  52. nCountInit : CARDINAL;
  53. countArr : ARRAY [0 .. 63] OF SymTab.Name;
  54. countTyp : ARRAY [0 .. 63] OF SymTab.TypeIndex;
  55. (* GOTO/labels: user label name -> QbeGen label, per procedure. *)
  56. nUserLab : CARDINAL;
  57. userLabNm : ARRAY [0 .. 255 * 64 - 1] OF CHAR;
  58. userLabQ : ARRAY [0 .. 255] OF QbeGen.QVal;
  59. (* Scoping: each symbol records the procedure that owns it (-1 =
  60. module level); FindSym searches the emitted procedure's chain
  61. innermost-first so common names (s, i, k) do not collide across
  62. procedures. *)
  63. symOwner : ARRAY [0 .. MaxSym - 1] OF INTEGER;
  64. procParent : ARRAY [0 .. MaxProc - 1] OF INTEGER;
  65. procSymBase : ARRAY [0 .. MaxProc - 1] OF CARDINAL;
  66. procSymTop : ARRAY [0 .. MaxProc - 1] OF CARDINAL;
  67. scopeStack : ARRAY [0 .. MaxProc - 1] OF INTEGER;
  68. scopeTop : CARDINAL;
  69. curScopeProc : INTEGER; (* owner while parsing: enclosing proc *)
  70. emitProc : INTEGER; (* owner while emitting: current proc *)
  71. qualUid : CARDINAL; (* uid of the last M.P alias resolved *)
  72. qualIsVar : BOOLEAN; (* last M.P alias is a proc-typed variable *)
  73. withRec : ARRAY [0 .. 15] OF SymTab.TypeIndex;
  74. withTop : CARDINAL;
  75. curMethCls : SymTab.TypeIndex; (* class bound by the last obj.Method *)
  76. curImplCls : SymTab.TypeIndex; (* class whose implementation is open *)
  77. curUnitName : SymTab.Name; (* unit being re-emitted (LowerSession) *)
  78. (* Compile-time set constants (SET CONSTs): masks the grammar computes
  79. and Lower re-emits as pooled static data. Name-keyed, latest wins,
  80. exactly like symVal. *)
  81. cfoldN : CARDINAL;
  82. cfoldName : ARRAY [0 .. MaxCFold * 64 - 1] OF CHAR;
  83. cfoldW : ARRAY [0 .. MaxCFold - 1] OF CARDINAL;
  84. cfoldLo : ARRAY [0 .. MaxCFold - 1] OF INTEGER;
  85. cfoldMask : ARRAY [0 .. MaxCFold * MaxCFoldW - 1] OF CARDINAL;
  86. PROCEDURE CopyN (src: ARRAY OF CHAR; VAR dst: ARRAY OF CHAR);
  87. VAR i: CARDINAL;
  88. BEGIN
  89. i := 0;
  90. WHILE (i < MaxName) AND (src[i] # CHR(0)) DO dst[i] := src[i]; INC(i) END;
  91. dst[i] := CHR(0)
  92. END CopyN;
  93. PROCEDURE CopySpan (VAR src: ARRAY OF CHAR; VAR dst: ARRAY OF CHAR;
  94. srcOff, dstOff: CARDINAL);
  95. (* src is a VAR open array on purpose: gm2 copies a value open-array
  96. formal to a stack VLA of its full length, which overflows the stack
  97. for the multi-megabyte tables below. *)
  98. VAR i: CARDINAL;
  99. BEGIN
  100. i := 0;
  101. WHILE (i < MaxName) AND (src[srcOff + i] # CHR(0)) DO
  102. dst[dstOff + i] := src[srcOff + i]; INC(i)
  103. END;
  104. dst[dstOff + i] := CHR(0)
  105. END CopySpan;
  106. PROCEDURE HashStr (name: ARRAY OF CHAR): CARDINAL;
  107. VAR h: CARDINAL; i: CARDINAL;
  108. BEGIN
  109. h := 5381; i := 0;
  110. WHILE (i <= HIGH(name)) AND (name[i] # CHR(0)) DO
  111. h := (h * 33 + VAL(CARDINAL, ORD(name[i]))) MOD HashSize; INC(i)
  112. END;
  113. RETURN h
  114. END HashStr;
  115. PROCEDURE SpanEq (VAR arr: ARRAY OF CHAR; off: CARDINAL;
  116. name: ARRAY OF CHAR): BOOLEAN;
  117. VAR j: CARDINAL;
  118. BEGIN
  119. j := 0;
  120. WHILE (j < MaxName) AND (name[j] # CHR(0)) DO
  121. IF arr[off + j] # name[j] THEN RETURN FALSE END;
  122. INC(j)
  123. END;
  124. RETURN arr[off + j] = name[j]
  125. END SpanEq;
  126. PROCEDURE HashPut (VAR htab: ARRAY OF INTEGER; VAR names: ARRAY OF CHAR;
  127. name: ARRAY OF CHAR; idx: CARDINAL);
  128. (* Insert idx, replacing an existing entry with the same name so the
  129. latest declaration wins (the linear scan used to search backward). *)
  130. VAR h: CARDINAL;
  131. BEGIN
  132. h := HashStr(name);
  133. LOOP
  134. IF htab[h] = 0 THEN htab[h] := VAL(INTEGER, idx) + 1; RETURN END;
  135. IF SpanEq(names, VAL(CARDINAL, htab[h] - 1) * 64, name) THEN
  136. htab[h] := VAL(INTEGER, idx) + 1; RETURN
  137. END;
  138. h := (h + 1) MOD HashSize
  139. END
  140. END HashPut;
  141. PROCEDURE HashGet (VAR htab: ARRAY OF INTEGER; VAR names: ARRAY OF CHAR;
  142. name: ARRAY OF CHAR): INTEGER;
  143. VAR h: CARDINAL;
  144. BEGIN
  145. h := HashStr(name);
  146. LOOP
  147. IF htab[h] = 0 THEN RETURN -1 END;
  148. IF SpanEq(names, VAL(CARDINAL, htab[h] - 1) * 64, name) THEN
  149. RETURN htab[h] - 1
  150. END;
  151. h := (h + 1) MOD HashSize
  152. END
  153. END HashGet;
  154. PROCEDURE Reset;
  155. VAR i: CARDINAL;
  156. BEGIN
  157. nSyms := 0; nProcs := 0;
  158. scopeTop := 0; curScopeProc := -1; emitProc := -1;
  159. i := 0;
  160. WHILE i < HashSize DO symHash[i] := 0; procHash[i] := 0; INC(i) END
  161. END Reset;
  162. PROCEDURE NoteVar (name: ARRAY OF CHAR; kind: INTEGER; t: SymTab.TypeIndex);
  163. BEGIN
  164. IF nSyms >= MaxSym THEN RETURN END;
  165. CopySpan(name, symName, 0, nSyms * 64);
  166. symKind[nSyms] := kind; symTy[nSyms] := t;
  167. symOwner[nSyms] := curScopeProc;
  168. HashPut(symHash, symName, name, nSyms);
  169. INC(nSyms)
  170. END NoteVar;
  171. PROCEDURE NoteConstVal (val: ARRAY OF CHAR);
  172. (* Records the evaluated value of the CONST just entered by NoteVar.
  173. Const values are per-unit and cross-module names collide (every
  174. module has EOL), so they live here, not in SymTab. *)
  175. BEGIN
  176. IF nSyms > 0 THEN CopySpan(val, symVal, 0, (nSyms - 1) * 64) END
  177. END NoteConstVal;
  178. PROCEDURE ScopeEnter;
  179. (* Called at a procedure heading, before NoteProc. Pushes the enclosing
  180. procedure as the parent scope. *)
  181. BEGIN
  182. IF scopeTop <= HIGH(scopeStack) THEN
  183. scopeStack[scopeTop] := curScopeProc;
  184. INC(scopeTop)
  185. END
  186. END ScopeEnter;
  187. PROCEDURE ScopeLeave;
  188. BEGIN
  189. IF curScopeProc >= 0 THEN procSymTop[curScopeProc] := nSyms END;
  190. IF scopeTop > 0 THEN
  191. DEC(scopeTop);
  192. curScopeProc := scopeStack[scopeTop]
  193. END
  194. END ScopeLeave;
  195. PROCEDURE ReenterScopeProc (ty: INTEGER);
  196. (* Restores a previously noted proc entry as current for the re-parse
  197. pass (its registration ran once in the skip pass): pushes the
  198. current owner and resumes ty, so the Block-end ScopeLeave pops back
  199. and nested NoteProc/NoteVar attach under the right parent. *)
  200. BEGIN
  201. IF (ty < 0) OR (ty >= VAL(INTEGER, nProcs)) THEN RETURN END;
  202. IF scopeTop <= HIGH(scopeStack) THEN
  203. scopeStack[scopeTop] := curScopeProc;
  204. INC(scopeTop)
  205. END;
  206. curScopeProc := ty
  207. END ReenterScopeProc;
  208. PROCEDURE CurScopeProc (): INTEGER;
  209. (* The proc entry NoteProc most recently made current (ty stamped on the
  210. NkProcDecl); captured by the parser's span table for the re-parse. *)
  211. BEGIN
  212. RETURN curScopeProc
  213. END CurScopeProc;
  214. PROCEDURE NoteProc (name: ARRAY OF CHAR; uid: CARDINAL;
  215. res: SymTab.TypeIndex; depth: CARDINAL; ext: BOOLEAN);
  216. BEGIN
  217. IF nProcs >= MaxProc THEN RETURN END;
  218. CopySpan(name, procName, 0, nProcs * 64);
  219. procUid[nProcs] := uid; procRes[nProcs] := res;
  220. procDep[nProcs] := depth; procExt[nProcs] := ext;
  221. procNpar[nProcs] := 0;
  222. procParent[nProcs] := curScopeProc;
  223. procSymBase[nProcs] := nSyms;
  224. curScopeProc := VAL(INTEGER, nProcs);
  225. HashPut(procHash, procName, name, nProcs);
  226. INC(nProcs)
  227. END NoteProc;
  228. PROCEDURE AliasProc (name: ARRAY OF CHAR; uid: CARDINAL;
  229. res: SymTab.TypeIndex; depth: CARDINAL; ext: BOOLEAN);
  230. (* A generic procedure formal bound to an actual procedure: add a
  231. proc-table entry so calls through the formal resolve to the actual,
  232. without disturbing the scope stack (unlike NoteProc). *)
  233. BEGIN
  234. IF nProcs >= MaxProc THEN RETURN END;
  235. CopySpan(name, procName, 0, nProcs * 64);
  236. procUid[nProcs] := uid; procRes[nProcs] := res;
  237. procDep[nProcs] := depth; procExt[nProcs] := ext;
  238. procNpar[nProcs] := 0;
  239. procParent[nProcs] := -1;
  240. procSymBase[nProcs] := nSyms;
  241. HashPut(procHash, procName, name, nProcs);
  242. INC(nProcs)
  243. END AliasProc;
  244. PROCEDURE MarkProcExternal;
  245. (* The grammar calls this from the EXTERNAL branch, after NoteProc, so
  246. the walk records that the callee takes no static link. *)
  247. BEGIN
  248. IF nProcs > 0 THEN procExt[nProcs - 1] := TRUE END
  249. END MarkProcExternal;
  250. PROCEDURE NoteCProc (name: ARRAY OF CHAR);
  251. (* FROM libc IMPORT P: a permissive C varargs external. NoteProc sets
  252. curScopeProc; restore it so the next import is not seen as nested. *)
  253. VAR save: INTEGER;
  254. BEGIN
  255. save := curScopeProc;
  256. curScopeProc := -1;
  257. NoteProc(name, 0, SymTab.InvalidType, 0, TRUE);
  258. curScopeProc := save;
  259. IF nProcs > 0 THEN
  260. procExt[nProcs - 1] := TRUE;
  261. procVa[nProcs - 1] := TRUE;
  262. procNpar[nProcs - 1] := 0;
  263. procParent[nProcs - 1] := -1
  264. END
  265. END NoteCProc;
  266. PROCEDURE NoteProcNode (n: AST.Node);
  267. (* Records the proc-table index in the NkProcDecl's ty field, so
  268. LowerDecls can find the exact entry. FindProc(name) would return the
  269. last duplicate (e.g. the two nested `Sep`s), giving the wrong uid and
  270. the wrong scope for its locals. *)
  271. BEGIN
  272. IF nProcs > 0 THEN AST.SetTy(n, VAL(INTEGER, nProcs - 1)) END
  273. END NoteProcNode;
  274. PROCEDURE ProcInfoIdx (pi: INTEGER; VAR uid: CARDINAL;
  275. VAR res: SymTab.TypeIndex; VAR depth: CARDINAL;
  276. VAR ext: BOOLEAN; VAR npar: CARDINAL): BOOLEAN;
  277. BEGIN
  278. IF (pi < 0) OR (pi >= VAL(INTEGER, nProcs)) THEN RETURN FALSE END;
  279. uid := procUid[pi]; res := procRes[pi]; depth := procDep[pi];
  280. ext := procExt[pi]; npar := procNpar[pi];
  281. IF npar > MaxPar THEN npar := MaxPar END;
  282. RETURN TRUE
  283. END ProcInfoIdx;
  284. PROCEDURE ParamInfoIdx (pi: INTEGER; i: CARDINAL;
  285. VAR t: SymTab.TypeIndex; VAR isVar: BOOLEAN;
  286. VAR pn: ARRAY OF CHAR): BOOLEAN;
  287. BEGIN
  288. IF (pi < 0) OR (pi >= MaxProc)
  289. OR (i >= procNpar[pi]) OR (procNpar[pi] > MaxPar) THEN
  290. RETURN FALSE
  291. END;
  292. t := parTy[VAL(CARDINAL, pi) * MaxPar + i];
  293. isVar := parVar[VAL(CARDINAL, pi) * MaxPar + i];
  294. CopySpan(parName, pn, VAL(CARDINAL, pi) * MaxPar * 64 + i * 64, 0);
  295. RETURN TRUE
  296. END ParamInfoIdx;
  297. PROCEDURE SetProcRes (t: SymTab.TypeIndex);
  298. BEGIN
  299. IF nProcs > 0 THEN procRes[nProcs - 1] := t END
  300. END SetProcRes;
  301. PROCEDURE NoteParam (name: ARRAY OF CHAR; t: SymTab.TypeIndex; isVar: BOOLEAN);
  302. VAR j: CARDINAL;
  303. BEGIN
  304. IF nProcs = 0 THEN RETURN END;
  305. j := procNpar[nProcs - 1];
  306. IF j >= MaxPar THEN RETURN END;
  307. CopySpan(name, parName, 0, (nProcs - 1) * MaxPar * 64 + j * 64);
  308. parTy[(nProcs - 1) * MaxPar + j] := t;
  309. parVar[(nProcs - 1) * MaxPar + j] := isVar;
  310. procNpar[nProcs - 1] := j + 1
  311. END NoteParam;
  312. PROCEDURE NameEq (i: CARDINAL; name: ARRAY OF CHAR): BOOLEAN;
  313. VAR j: CARDINAL;
  314. BEGIN
  315. j := 0;
  316. WHILE (j < MaxName) AND (name[j] # CHR(0)) DO
  317. IF symName[i * 64 + j] # name[j] THEN RETURN FALSE END;
  318. INC(j)
  319. END;
  320. RETURN symName[i * 64 + j] = name[j]
  321. END NameEq;
  322. PROCEDURE FindSym (name: ARRAY OF CHAR; VAR kind: INTEGER;
  323. VAR t: SymTab.TypeIndex): BOOLEAN;
  324. (* Locals/params of the emitted procedure (and its enclosing procedures)
  325. shadow module-level symbols, so walk the scope chain innermost-first
  326. and only then fall back to the hash for a module-level symbol. *)
  327. VAR i: INTEGER; owner: INTEGER;
  328. BEGIN
  329. owner := emitProc;
  330. WHILE owner >= 0 DO
  331. (* procSymTop is unset for headings that never ScopeLeave (class
  332. method declarations); fall back to the whole table then. *)
  333. IF procSymTop[owner] > 0 THEN
  334. i := VAL(INTEGER, procSymTop[owner]) - 1
  335. ELSE i := VAL(INTEGER, nSyms) - 1
  336. END;
  337. WHILE i >= VAL(INTEGER, procSymBase[owner]) DO
  338. IF (symOwner[i] = owner) AND NameEq(VAL(CARDINAL, i), name) THEN
  339. kind := symKind[i]; t := symTy[i]; RETURN TRUE
  340. END;
  341. DEC(i)
  342. END;
  343. owner := procParent[owner]
  344. END;
  345. i := HashGet(symHash, symName, name);
  346. IF (i >= 0) AND (symOwner[i] = -1) THEN
  347. kind := symKind[i]; t := symTy[i]; RETURN TRUE
  348. END;
  349. RETURN FALSE
  350. END FindSym;
  351. PROCEDURE GetConstVal (name: ARRAY OF CHAR; VAR v: ARRAY OF CHAR): BOOLEAN;
  352. VAR i: INTEGER;
  353. BEGIN
  354. i := HashGet(symHash, symName, name);
  355. IF (i >= 0) AND (symKind[i] = SymTab.KindConst) THEN
  356. CopySpan(symVal, v, VAL(CARDINAL, i) * 64, 0);
  357. IF v[0] # CHR(0) THEN RETURN TRUE END
  358. END;
  359. (* a literal propagated with its enum type lives only in SymTab *)
  360. v[0] := CHR(0);
  361. RETURN SymTab.GetSymVal(name, v)
  362. END GetConstVal;
  363. PROCEDURE SetConstVal (name: ARRAY OF CHAR; val: ARRAY OF CHAR);
  364. (* Refresh a CONST's recorded value after Lower re-emits its aggregate
  365. constructor (the grammar's value was suppressed under NoEmit). *)
  366. VAR i: INTEGER;
  367. BEGIN
  368. i := HashGet(symHash, symName, name);
  369. IF i >= 0 THEN CopySpan(val, symVal, 0, VAL(CARDINAL, i) * 64) END
  370. END SetConstVal;
  371. PROCEDURE ProcNameEq (i: CARDINAL; name: ARRAY OF CHAR): BOOLEAN;
  372. VAR j: CARDINAL;
  373. BEGIN
  374. j := 0;
  375. WHILE (j < MaxName) AND (name[j] # CHR(0)) DO
  376. IF procName[i * 64 + j] # name[j] THEN RETURN FALSE END;
  377. INC(j)
  378. END;
  379. RETURN procName[i * 64 + j] = name[j]
  380. END ProcNameEq;
  381. PROCEDURE ProcVisible (i: INTEGER): BOOLEAN;
  382. (* TRUE when proc i is nested directly in the emitted procedure or one
  383. of its enclosing procedures (or is module-level). *)
  384. VAR owner: INTEGER;
  385. BEGIN
  386. owner := emitProc;
  387. WHILE owner >= 0 DO
  388. IF procParent[i] = owner THEN RETURN TRUE END;
  389. owner := procParent[owner]
  390. END;
  391. RETURN procParent[i] = -1
  392. END ProcVisible;
  393. PROCEDURE ImpNameEq (i: CARDINAL; name: ARRAY OF CHAR): BOOLEAN;
  394. BEGIN
  395. RETURN SpanEq(impName, i * 64, name)
  396. END ImpNameEq;
  397. PROCEDURE FindProc (name: ARRAY OF CHAR): INTEGER;
  398. (* Scope-aware: a nested procedure (e.g. one of two `Sep`s) must resolve
  399. to the one in the emitted procedure's chain, not the last duplicate.
  400. The current unit's imports win over any same-named proc. *)
  401. VAR i: INTEGER; owner: INTEGER;
  402. BEGIN
  403. i := 0;
  404. WHILE i < VAL(INTEGER, nImps) DO
  405. IF ImpNameEq(VAL(CARDINAL, i), name) THEN RETURN impProc[i] END;
  406. INC(i)
  407. END;
  408. i := HashGet(procHash, procName, name);
  409. IF (i >= 0) AND ProcVisible(i) THEN RETURN i END;
  410. owner := emitProc;
  411. WHILE owner >= 0 DO
  412. i := VAL(INTEGER, nProcs) - 1;
  413. WHILE i > 0 DO
  414. DEC(i);
  415. IF (procParent[i] = owner) AND ProcNameEq(VAL(CARDINAL, i), name) THEN
  416. RETURN i
  417. END
  418. END;
  419. owner := procParent[owner]
  420. END;
  421. i := VAL(INTEGER, nProcs) - 1;
  422. WHILE i > 0 DO
  423. DEC(i);
  424. IF (procParent[i] = -1) AND ProcNameEq(VAL(CARDINAL, i), name) THEN
  425. RETURN i
  426. END
  427. END;
  428. RETURN -1
  429. END FindProc;
  430. PROCEDURE FindProcByUid (uid: CARDINAL): INTEGER;
  431. (* Exact proc entry for a module-qualified call (M.P): the base name may
  432. be duplicated across modules, but the uid is unique. *)
  433. VAR i: INTEGER;
  434. BEGIN
  435. i := VAL(INTEGER, nProcs);
  436. WHILE i > 0 DO
  437. DEC(i);
  438. IF procUid[i] = uid THEN RETURN i END
  439. END;
  440. RETURN -1
  441. END FindProcByUid;
  442. PROCEDURE NoteImportedProc (name: ARRAY OF CHAR);
  443. (* FROM M IMPORT P (a procedure): remember the exact proc entry so an
  444. unqualified call resolves to the imported proc, not a same-named
  445. proc declared in another module. Reset at each unit. *)
  446. VAR pi: INTEGER;
  447. BEGIN
  448. IF SymTab.SymKind(name) # SymTab.KindProc THEN RETURN END;
  449. pi := FindProcByUid(SymTab.ProcUid(name));
  450. IF pi < 0 THEN RETURN END;
  451. IF nImps >= MaxImp THEN RETURN END;
  452. impProc[nImps] := pi;
  453. CopySpan(name, impName, 0, nImps * 64);
  454. INC(nImps)
  455. END NoteImportedProc;
  456. PROCEDURE Resolve (nm: ARRAY OF CHAR; VAR k: INTEGER;
  457. VAR t: SymTab.TypeIndex): BOOLEAN;
  458. VAR kind: INTEGER; ti: SymTab.TypeIndex;
  459. BEGIN
  460. IF FindSym(nm, kind, ti) THEN k := kind; t := ti; RETURN TRUE END;
  461. IF SymTab.Lookup(nm) THEN k := SymTab.SymKind(nm); t := SymTab.SymType(nm);
  462. RETURN TRUE
  463. END;
  464. (* A bare procedure used as a value: it lives in the proc table.
  465. Sibling method names must fall through so LowerDesign can bind
  466. THIS, so exclude methods of the open class implementation. *)
  467. IF FindProc(nm) >= 0 THEN
  468. IF (curImplCls = SymTab.InvalidType)
  469. OR NOT SymTab.MethodExists(curImplCls, nm) THEN
  470. k := SymTab.KindProc; t := SymTab.InvalidType; RETURN TRUE
  471. END
  472. END;
  473. RETURN FALSE
  474. END Resolve;
  475. PROCEDURE ProcInfo (nm: ARRAY OF CHAR; VAR uid: CARDINAL;
  476. VAR res: SymTab.TypeIndex; VAR depth: CARDINAL;
  477. VAR ext: BOOLEAN; VAR npar: CARDINAL): BOOLEAN;
  478. VAR i: INTEGER;
  479. BEGIN
  480. i := FindProc(nm);
  481. IF (i < 0) OR (i >= MaxProc) THEN RETURN FALSE END;
  482. uid := procUid[i]; res := procRes[i]; depth := procDep[i];
  483. ext := procExt[i]; npar := procNpar[i];
  484. IF npar > MaxPar THEN npar := MaxPar END;
  485. RETURN TRUE
  486. END ProcInfo;
  487. PROCEDURE ParamInfo (nm: ARRAY OF CHAR; i: CARDINAL;
  488. VAR t: SymTab.TypeIndex; VAR isVar: BOOLEAN;
  489. VAR pn: ARRAY OF CHAR): BOOLEAN;
  490. VAR k: INTEGER;
  491. BEGIN
  492. k := FindProc(nm);
  493. IF (k < 0) OR (k >= MaxProc) THEN RETURN FALSE END;
  494. IF (i >= procNpar[k]) OR (procNpar[k] > MaxPar) THEN RETURN FALSE END;
  495. t := parTy[VAL(CARDINAL, k) * MaxPar + i];
  496. isVar := parVar[VAL(CARDINAL, k) * MaxPar + i];
  497. CopySpan(parName, pn, VAL(CARDINAL, k) * MaxPar * 64 + i * 64, 0);
  498. RETURN TRUE
  499. END ParamInfo;
  500. PROCEDURE WithField (nm: ARRAY OF CHAR; VAR k: INTEGER;
  501. VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal): BOOLEAN;
  502. (* Resolves a bare ident as a field of an open WITH record (innermost
  503. first), leaving the field address in q and k=KindField. *)
  504. VAR wt: CARDINAL; fo: INTEGER; qb: QbeGen.QVal;
  505. BEGIN
  506. wt := withTop;
  507. WHILE wt > 0 DO
  508. DEC(wt);
  509. IF SymTab.FieldExists(withRec[wt], nm) THEN
  510. t := SymTab.FieldType(withRec[wt], nm);
  511. fo := SymTab.FieldOffset(withRec[wt], nm);
  512. k := SymTab.KindField;
  513. IF QbeGen.TopWith(qb) THEN QbeGen.FieldAddr(qb, fo, q)
  514. ELSE QbeGen.CopyOp("0", q)
  515. END;
  516. RETURN TRUE
  517. END
  518. END;
  519. RETURN FALSE
  520. END WithField;
  521. PROCEDURE Name (n: AST.Node; VAR s: ARRAY OF CHAR);
  522. BEGIN
  523. IF n = AST.NoNode THEN s[0] := CHR(0)
  524. ELSE AST.Txt(AST.Child(n, 0), s)
  525. END
  526. END Name;
  527. (* ---------------- compile-time set constants ----------------
  528. A SET CONST's value must be static data. Set literals are emitted as
  529. runtime temporaries, so the grammar computes the bit mask here (where
  530. the element expressions are already validated) and Lower re-emits it
  531. as a pooled descriptor (`QbeGen.PoolSet`). Only masks up to MaxCFoldW
  532. words (512 bits) are folded; a wider SET CONST stays a clear 230. *)
  533. PROCEDURE Pow2 (b: INTEGER): CARDINAL;
  534. VAR p: CARDINAL; k: INTEGER;
  535. BEGIN
  536. p := 1; k := 0;
  537. WHILE k < b DO p := p * 2; INC(k) END;
  538. RETURN p
  539. END Pow2;
  540. PROCEDURE MaskZero (VAR mask: ARRAY OF CARDINAL; words: CARDINAL);
  541. VAR i: CARDINAL;
  542. BEGIN
  543. i := 0;
  544. WHILE (i < words) AND (i <= HIGH(mask)) DO mask[i] := 0; INC(i) END
  545. END MaskZero;
  546. PROCEDURE MaskSetBit (VAR mask: ARRAY OF CARDINAL; bit: INTEGER);
  547. VAR w, b: INTEGER; p: CARDINAL; idx: CARDINAL;
  548. BEGIN
  549. IF (bit < 0) OR (bit >= VAL(INTEGER, MaxCFoldW) * 32) THEN RETURN END;
  550. w := bit DIV 32; b := bit MOD 32;
  551. IF w > VAL(INTEGER, HIGH(mask)) THEN RETURN END;
  552. idx := VAL(CARDINAL, w); p := Pow2(b);
  553. IF (mask[idx] DIV p) MOD 2 = 0 THEN mask[idx] := mask[idx] + p END
  554. END MaskSetBit;
  555. PROCEDURE MaskGetBit (VAR mask: ARRAY OF CARDINAL; bit: INTEGER): INTEGER;
  556. VAR w, b: INTEGER; p: CARDINAL;
  557. BEGIN
  558. IF (bit < 0) OR (bit >= VAL(INTEGER, MaxCFoldW) * 32) THEN RETURN 0 END;
  559. w := bit DIV 32; b := bit MOD 32;
  560. IF w > VAL(INTEGER, HIGH(mask)) THEN RETURN 0 END;
  561. p := Pow2(b);
  562. IF (mask[VAL(CARDINAL, w)] DIV p) MOD 2 = 1 THEN RETURN 1 END;
  563. RETURN 0
  564. END MaskGetBit;
  565. PROCEDURE EvalOrdConst (n: AST.Node; VAR v: INTEGER): BOOLEAN;
  566. (* The integer value of a compile-time ordinal expression, matching the
  567. grammar's folding (literals, named CONSTs, unary +/-, + - * DIV MOD). *)
  568. VAR k: INTEGER; s, cv: QbeGen.QVal; nm: SymTab.Name;
  569. a, b: INTEGER; isCh: BOOLEAN;
  570. BEGIN
  571. IF n = AST.NoNode THEN RETURN FALSE END;
  572. k := AST.Kind(n);
  573. IF k = AST.NkIntLit THEN
  574. Name(n, s); QbeGen.NormInt(s, cv); RETURN SymTab.ConstInt(cv, v)
  575. ELSIF k = AST.NkCharLit THEN
  576. Name(n, s);
  577. IF (s[0] = "'") OR (s[0] = '"') THEN
  578. v := QbeGen.CharVal(s); RETURN TRUE
  579. END;
  580. QbeGen.NormLit(s, cv, isCh); RETURN SymTab.ConstInt(cv, v)
  581. ELSIF k = AST.NkStrLit THEN
  582. (* a 1-character string literal "c" is a CHAR constant *)
  583. Name(n, s);
  584. IF SymTab.StrLen(s) = 3 THEN v := QbeGen.CharVal(s); RETURN TRUE END;
  585. RETURN FALSE
  586. ELSIF k = AST.NkDesignator THEN
  587. IF (AST.NChild(n) # 1) OR (AST.Kind(AST.Child(n, 0)) # AST.NkIdent) THEN
  588. RETURN FALSE END;
  589. Name(AST.Child(n, 0), nm);
  590. IF SymTab.Equal(nm, "TRUE") THEN v := 1; RETURN TRUE END;
  591. IF SymTab.Equal(nm, "FALSE") THEN v := 0; RETURN TRUE END;
  592. IF SymTab.Lookup(nm) AND (SymTab.SymKind(nm) = SymTab.KindConst)
  593. AND SymTab.GetSymVal(nm, cv) AND QbeGen.IsImm(cv) THEN
  594. RETURN SymTab.ConstInt(cv, v)
  595. END;
  596. RETURN FALSE
  597. ELSIF k = AST.NkUnary THEN
  598. IF AST.Op(n) = AST.OpSub THEN
  599. IF EvalOrdConst(AST.Child(n, 0), v) THEN v := -v; RETURN TRUE END
  600. ELSIF AST.Op(n) = AST.OpAdd THEN
  601. RETURN EvalOrdConst(AST.Child(n, 0), v)
  602. END;
  603. RETURN FALSE
  604. ELSIF k = AST.NkBinExpr THEN
  605. IF EvalOrdConst(AST.Child(n, 0), a)
  606. AND EvalOrdConst(AST.Child(n, 1), b) THEN
  607. IF AST.Op(n) = AST.OpAdd THEN v := a + b
  608. ELSIF AST.Op(n) = AST.OpSub THEN v := a - b
  609. ELSIF AST.Op(n) = AST.OpMul THEN v := a * b
  610. ELSIF AST.Op(n) = AST.OpDiv THEN
  611. IF b = 0 THEN RETURN FALSE END; v := a DIV b
  612. ELSIF AST.Op(n) = AST.OpMod THEN
  613. IF b = 0 THEN RETURN FALSE END; v := a MOD b
  614. ELSE RETURN FALSE
  615. END;
  616. RETURN TRUE
  617. END;
  618. RETURN FALSE
  619. END;
  620. RETURN FALSE
  621. END EvalOrdConst;
  622. PROCEDURE EvalSetElem (el: AST.Node; VAR mask: ARRAY OF CARDINAL;
  623. lo: INTEGER; span: CARDINAL): BOOLEAN;
  624. VAR a, b: INTEGER;
  625. BEGIN
  626. IF AST.Kind(el) = AST.NkSubrange THEN
  627. IF NOT EvalOrdConst(AST.Child(el, 0), a)
  628. OR NOT EvalOrdConst(AST.Child(el, 1), b) THEN RETURN FALSE END;
  629. IF (a < lo) OR (b < lo) OR (a > b)
  630. OR (b >= lo + VAL(INTEGER, span)) THEN RETURN FALSE END;
  631. WHILE a <= b DO MaskSetBit(mask, a - lo); INC(a) END;
  632. RETURN TRUE
  633. END;
  634. IF NOT EvalOrdConst(el, a) THEN RETURN FALSE END;
  635. IF (a < lo) OR (a >= lo + VAL(INTEGER, span)) THEN RETURN FALSE END;
  636. MaskSetBit(mask, a - lo);
  637. RETURN TRUE
  638. END EvalSetElem;
  639. PROCEDURE NoteSetMask (name: ARRAY OF CHAR; mask: ARRAY OF CARDINAL;
  640. words: CARDINAL; lo: INTEGER);
  641. VAR i: CARDINAL;
  642. BEGIN
  643. IF cfoldN >= MaxCFold THEN RETURN END;
  644. CopySpan(name, cfoldName, 0, cfoldN * 64);
  645. cfoldW[cfoldN] := words; cfoldLo[cfoldN] := lo;
  646. i := 0;
  647. WHILE i < MaxCFoldW DO
  648. IF (i < words) AND (i <= HIGH(mask)) THEN
  649. cfoldMask[cfoldN * MaxCFoldW + i] := mask[i]
  650. ELSE cfoldMask[cfoldN * MaxCFoldW + i] := 0
  651. END;
  652. INC(i)
  653. END;
  654. INC(cfoldN)
  655. END NoteSetMask;
  656. PROCEDURE LookupSetMask (name: ARRAY OF CHAR; VAR mask: ARRAY OF CARDINAL;
  657. VAR words: CARDINAL; VAR lo: INTEGER): BOOLEAN;
  658. VAR i: INTEGER; k: CARDINAL;
  659. BEGIN
  660. i := VAL(INTEGER, cfoldN) - 1;
  661. WHILE i >= 0 DO
  662. IF SpanEq(cfoldName, VAL(CARDINAL, i) * 64, name) THEN
  663. words := cfoldW[i]; lo := cfoldLo[i];
  664. k := 0;
  665. WHILE (k < words) AND (k <= HIGH(mask)) DO
  666. mask[k] := cfoldMask[VAL(CARDINAL, i) * MaxCFoldW + k]; INC(k)
  667. END;
  668. RETURN TRUE
  669. END;
  670. DEC(i)
  671. END;
  672. RETURN FALSE
  673. END LookupSetMask;
  674. PROCEDURE EvalSetConst (n: AST.Node; VAR mask: ARRAY OF CARDINAL;
  675. VAR words: CARDINAL; VAR lo: INTEGER): BOOLEAN;
  676. VAR k, i, a, b, r: INTEGER;
  677. t: SymTab.TypeIndex;
  678. span: CARDINAL;
  679. seq, el, next: AST.Node;
  680. m1, m2: ARRAY [0 .. MaxCFoldW - 1] OF CARDINAL;
  681. w1, w2: CARDINAL;
  682. l1, l2: INTEGER;
  683. op: INTEGER;
  684. nm: SymTab.Name;
  685. BEGIN
  686. IF n = AST.NoNode THEN RETURN FALSE END;
  687. k := AST.Kind(n);
  688. IF (k = AST.NkSetLit) OR (k = AST.NkBraceLit) THEN
  689. t := AST.Ty(n);
  690. IF (k = AST.NkBraceLit) AND (SymTab.ClassOf(t) # SymTab.ClSet) THEN
  691. RETURN FALSE
  692. END;
  693. IF t = SymTab.InvalidType THEN
  694. lo := 0; words := 8; span := 256
  695. ELSE
  696. lo := SymTab.SetBaseLo(t); words := SymTab.SetWords(t);
  697. span := SymTab.SetCount(t);
  698. IF words = 0 THEN words := 8; span := 256; lo := 0 END
  699. END;
  700. IF words > MaxCFoldW THEN RETURN FALSE END;
  701. MaskZero(mask, words);
  702. IF k = AST.NkSetLit THEN
  703. i := 0;
  704. WHILE i < VAL(INTEGER, AST.NChild(n)) DO
  705. el := AST.Child(n, VAL(CARDINAL, i));
  706. IF NOT EvalSetElem(el, mask, lo, span) THEN RETURN FALSE END;
  707. INC(i)
  708. END
  709. ELSE
  710. seq := n;
  711. WHILE seq # AST.NoNode DO
  712. i := 0;
  713. WHILE i < VAL(INTEGER, AST.NChild(seq)) DO
  714. el := AST.Child(seq, VAL(CARDINAL, i));
  715. IF AST.Kind(el) # AST.NkBlock THEN
  716. IF NOT EvalSetElem(el, mask, lo, span) THEN RETURN FALSE END
  717. END;
  718. INC(i)
  719. END;
  720. next := AST.NoNode;
  721. IF AST.NChild(seq) > 0 THEN
  722. next := AST.Child(seq, AST.NChild(seq) - 1);
  723. IF AST.Kind(next) # AST.NkBlock THEN next := AST.NoNode END
  724. END;
  725. seq := next
  726. END
  727. END;
  728. RETURN TRUE
  729. ELSIF k = AST.NkDesignator THEN
  730. IF (AST.NChild(n) # 1) OR (AST.Kind(AST.Child(n, 0)) # AST.NkIdent) THEN
  731. RETURN FALSE END;
  732. Name(AST.Child(n, 0), nm);
  733. RETURN LookupSetMask(nm, mask, words, lo)
  734. ELSIF k = AST.NkBinExpr THEN
  735. op := AST.Op(n);
  736. IF (op # AST.OpAdd) AND (op # AST.OpSub)
  737. AND (op # AST.OpMul) AND (op # AST.OpDiv) THEN
  738. RETURN FALSE END;
  739. IF NOT EvalSetConst(AST.Child(n, 0), m1, w1, l1)
  740. OR NOT EvalSetConst(AST.Child(n, 1), m2, w2, l2) THEN
  741. RETURN FALSE END;
  742. IF l1 # l2 THEN RETURN FALSE END;
  743. lo := l1;
  744. words := w1; IF w2 > words THEN words := w2 END;
  745. IF words > MaxCFoldW THEN RETURN FALSE END;
  746. MaskZero(mask, words);
  747. i := 0;
  748. WHILE i < VAL(INTEGER, words) * 32 DO
  749. a := MaskGetBit(m1, i); b := MaskGetBit(m2, i);
  750. IF op = AST.OpAdd THEN r := a; IF b = 1 THEN r := 1 END
  751. ELSIF op = AST.OpMul THEN
  752. IF (a = 1) AND (b = 1) THEN r := 1 ELSE r := 0 END
  753. ELSIF op = AST.OpSub THEN r := a; IF b = 1 THEN r := 0 END
  754. ELSE r := (a + b) MOD 2
  755. END;
  756. IF r # 0 THEN MaskSetBit(mask, i) END;
  757. INC(i)
  758. END;
  759. RETURN TRUE
  760. END;
  761. RETURN FALSE
  762. END EvalSetConst;
  763. PROCEDURE SetConstMaskOf (n: AST.Node; VAR mask: ARRAY OF CARDINAL;
  764. VAR words: CARDINAL; VAR lo: INTEGER): BOOLEAN;
  765. BEGIN
  766. words := 0; lo := 0;
  767. RETURN EvalSetConst(n, mask, words, lo)
  768. END SetConstMaskOf;
  769. PROCEDURE ParamName (proc: ARRAY OF CHAR; i: CARDINAL;
  770. VAR s: ARRAY OF CHAR);
  771. VAR t: SymTab.TypeIndex; isV: BOOLEAN;
  772. BEGIN
  773. IF NOT ParamInfo(proc, i, t, isV, s) THEN s[0] := CHR(0) END
  774. END ParamName;
  775. PROCEDURE IsArith (op: INTEGER): BOOLEAN;
  776. BEGIN
  777. RETURN (op = AST.OpAdd) OR (op = AST.OpSub) OR (op = AST.OpMul)
  778. OR (op = AST.OpDiv) OR (op = AST.OpMod)
  779. END IsArith;
  780. PROCEDURE IsRel (op: INTEGER): BOOLEAN;
  781. BEGIN
  782. RETURN ((op >= AST.OpEq) AND (op <= AST.OpGe)) OR (op = AST.OpIn)
  783. END IsRel;
  784. PROCEDURE RelSym (a: INTEGER; VAR s: INTEGER): BOOLEAN;
  785. BEGIN
  786. IF a = AST.OpEq THEN s := SymTab.OpEq
  787. ELSIF a = AST.OpNe THEN s := SymTab.OpNeq1
  788. ELSIF a = AST.OpLt THEN s := SymTab.OpLt
  789. ELSIF a = AST.OpLe THEN s := SymTab.OpLe
  790. ELSIF a = AST.OpGt THEN s := SymTab.OpGt
  791. ELSIF a = AST.OpGe THEN s := SymTab.OpGe
  792. ELSE RETURN FALSE
  793. END;
  794. RETURN TRUE
  795. END RelSym;
  796. PROCEDURE IsScalarClass (cls: INTEGER): BOOLEAN;
  797. BEGIN
  798. RETURN (cls = SymTab.ClInt) OR (cls = SymTab.ClBool)
  799. OR (cls = SymTab.ClChar) OR (cls = SymTab.ClUChar)
  800. OR (cls = SymTab.ClEnum)
  801. END IsScalarClass;
  802. PROCEDURE IsSimpleScalar (n: AST.Node): BOOLEAN;
  803. VAR nm: SymTab.Name; k: INTEGER; t: SymTab.TypeIndex;
  804. BEGIN
  805. IF (AST.Kind(n) # AST.NkDesignator) OR (AST.NChild(n) # 1) THEN
  806. RETURN FALSE END;
  807. IF AST.Kind(AST.Child(n, 0)) # AST.NkIdent THEN RETURN FALSE END;
  808. Name(AST.Child(n, 0), nm);
  809. IF NOT Resolve(nm, k, t) THEN RETURN FALSE END;
  810. IF (k # SymTab.KindVar) AND (k # SymTab.KindParam)
  811. AND (k # SymTab.KindConst) THEN
  812. RETURN FALSE END;
  813. IF SymTab.Equal(nm, "TRUE") OR SymTab.Equal(nm, "FALSE") THEN
  814. RETURN TRUE END;
  815. RETURN IsScalarClass(SymTab.ClassOf(t))
  816. END IsSimpleScalar;
  817. PROCEDURE CalleeName (call: AST.Node; VAR nm: SymTab.Name);
  818. (* The callee of NkCall: child 0 is a designator (or bare ident). *)
  819. VAR d: AST.Node;
  820. BEGIN
  821. nm[0] := CHR(0);
  822. d := AST.Child(call, 0);
  823. IF d = AST.NoNode THEN RETURN END;
  824. IF AST.Kind(d) = AST.NkDesignator THEN d := AST.Child(d, 0) END;
  825. IF (d # AST.NoNode) AND (AST.Kind(d) = AST.NkIdent) THEN Name(d, nm) END
  826. END CalleeName;
  827. PROCEDURE CallResultType (call: AST.Node; VAR t: SymTab.TypeIndex): BOOLEAN;
  828. (* The result type of a call used as a designator base (F().M()). *)
  829. VAR nm: SymTab.Name; uid, depth, np: CARDINAL; res: SymTab.TypeIndex;
  830. ext: BOOLEAN; pi: INTEGER;
  831. BEGIN
  832. t := SymTab.InvalidType;
  833. CalleeName(call, nm);
  834. pi := FindProc(nm);
  835. IF pi >= 0 THEN
  836. IF ProcInfoIdx(pi, uid, res, depth, ext, np) THEN t := res; RETURN TRUE END;
  837. RETURN FALSE
  838. END;
  839. IF SymTab.Lookup(nm) AND (SymTab.SymKind(nm) = SymTab.KindProc) THEN
  840. t := SymTab.ProcRes(nm); RETURN TRUE
  841. END;
  842. RETURN FALSE
  843. END CallResultType;
  844. PROCEDURE IsMethodCall (n: AST.Node): BOOLEAN;
  845. (* n is a call whose callee resolves to a class method: `obj.Method`,
  846. `p^.Method`, or a bare sibling name inside an implementation. *)
  847. VAR d, sel: AST.Node; nm, fn: SymTab.Name; k: INTEGER; t: SymTab.TypeIndex;
  848. i: CARDINAL;
  849. BEGIN
  850. IF (AST.Kind(n) # AST.NkCall) OR (AST.NChild(n) < 1) THEN RETURN FALSE END;
  851. d := AST.Child(n, 0);
  852. IF AST.Kind(d) # AST.NkDesignator THEN RETURN FALSE END;
  853. IF AST.NChild(d) = 1 THEN
  854. (* bare name: a sibling method inside a class implementation? *)
  855. Name(AST.Child(d, 0), nm);
  856. RETURN (curImplCls # SymTab.InvalidType)
  857. AND SymTab.MethodExists(curImplCls, nm)
  858. END;
  859. IF AST.Kind(AST.Child(d, 0)) = AST.NkCall THEN
  860. (* F().M(): the base is a call; take its result type *)
  861. IF NOT CallResultType(AST.Child(d, 0), t) THEN RETURN FALSE END
  862. ELSE
  863. Name(AST.Child(d, 0), nm);
  864. IF NOT Resolve(nm, k, t) THEN RETURN FALSE END
  865. END;
  866. i := 1;
  867. WHILE i < AST.NChild(d) DO
  868. sel := AST.Child(d, i);
  869. IF AST.Op(sel) = AST.SelField THEN
  870. Name(AST.Child(sel, 0), fn);
  871. IF (t # SymTab.InvalidType) AND (SymTab.ClassOf(t) = SymTab.ClClass)
  872. AND SymTab.MethodExists(t, fn) THEN
  873. RETURN i = AST.NChild(d) - 1
  874. END;
  875. IF (t = SymTab.InvalidType) OR NOT SymTab.FieldExists(t, fn) THEN
  876. RETURN FALSE
  877. END;
  878. t := SymTab.FieldType(t, fn)
  879. ELSIF AST.Op(sel) = AST.SelIndex THEN
  880. IF (t = SymTab.InvalidType) OR (SymTab.ClassOf(t) # SymTab.ClArray) THEN
  881. RETURN FALSE
  882. END;
  883. t := SymTab.ArrayElem(t)
  884. ELSIF AST.Op(sel) = AST.SelDeref THEN
  885. IF (t = SymTab.InvalidType) OR (SymTab.ClassOf(t) # SymTab.ClPtr) THEN
  886. RETURN FALSE
  887. END;
  888. t := SymTab.PtrBase(t)
  889. ELSE RETURN FALSE
  890. END;
  891. INC(i)
  892. END;
  893. RETURN FALSE
  894. END IsMethodCall;
  895. PROCEDURE CalleeAlias (call: AST.Node; VAR mal: SymTab.Name): BOOLEAN;
  896. (* Callee is `M.P` (module-qualified): materialize the export alias. *)
  897. VAR d, sel: AST.Node; nm, fn, al: SymTab.Name; k: INTEGER;
  898. t: SymTab.TypeIndex;
  899. BEGIN
  900. d := AST.Child(call, 0);
  901. IF (AST.Kind(d) # AST.NkDesignator) OR (AST.NChild(d) # 2) THEN
  902. RETURN FALSE
  903. END;
  904. sel := AST.Child(d, 1);
  905. IF AST.Op(sel) # AST.SelField THEN RETURN FALSE END;
  906. Name(AST.Child(d, 0), nm);
  907. IF NOT Resolve(nm, k, t) THEN RETURN FALSE END;
  908. IF k # SymTab.KindModule THEN RETURN FALSE END;
  909. Name(AST.Child(sel, 0), fn);
  910. IF NOT SymTab.MaterializeAlias(nm, fn, al) THEN RETURN FALSE END;
  911. (* Lower's proc table is keyed by the base name (the mangled symbol
  912. is <base>_<uid>), so return fn, not the materialized alias. The
  913. uid comes from the alias, which is module-exact. *)
  914. qualIsVar := SymTab.SymKind(al) # SymTab.KindProc;
  915. qualUid := SymTab.ProcUid(al);
  916. CopyN(fn, mal);
  917. RETURN TRUE
  918. END CalleeAlias;
  919. PROCEDURE FinalLoad (t: SymTab.TypeIndex; sfx: BOOLEAN; VAR q: QbeGen.QVal);
  920. (* Fact's final load after a designator/result suffix: scalars/pointers
  921. are loaded from their address; aggregates keep the address. *)
  922. VAR cls: INTEGER; q2: QbeGen.QVal;
  923. BEGIN
  924. IF NOT sfx THEN RETURN END;
  925. IF t = SymTab.InvalidType THEN QbeGen.CopyOp("0", q); RETURN END;
  926. cls := SymTab.ClassOf(t);
  927. IF (cls # SymTab.ClRecord) AND (cls # SymTab.ClSet)
  928. AND (cls # SymTab.ClArray) AND (cls # SymTab.ClClass) THEN
  929. QbeGen.ElemLoad(q, t, q2); QbeGen.CopyOp(q2, q)
  930. END
  931. END FinalLoad;
  932. PROCEDURE LowerDesign (n: AST.Node; VAR t: SymTab.TypeIndex; VAR k: INTEGER;
  933. VAR q: QbeGen.QVal; VAR qn: SymTab.Name;
  934. VAR sfx: BOOLEAN);
  935. (* Base ident then selectors (mirrors the grammar's Design). Leaves the
  936. address in q with sfx=TRUE for selectors; base vars/consts load. *)
  937. VAR nm, fn, mal: SymTab.Name; cv: QbeGen.QVal; cls, op: INTEGER;
  938. i: CARDINAL; sel: AST.Node; eT, it: SymTab.TypeIndex;
  939. iq, ql, qlo, qhi, qe: QbeGen.QVal;
  940. lo, hi, fo: INTEGER; isOpen: BOOLEAN;
  941. BEGIN
  942. IF AST.Kind(AST.Child(n, 0)) = AST.NkCall THEN
  943. (* a call result used as a designator base: P()^, P()^.field,
  944. A()[i]. The call yields a value (a pointer/record address);
  945. sfx=FALSE so a following ^ does not reload it. *)
  946. LowerExpr(AST.Child(n, 0), t, q);
  947. k := -1; qn[0] := CHR(0); sfx := FALSE
  948. ELSE
  949. Name(AST.Child(n, 0), nm);
  950. QbeGen.CopyOp(nm, qn);
  951. sfx := FALSE;
  952. IF NOT Resolve(nm, k, t) THEN
  953. IF WithField(nm, k, t, q) THEN
  954. sfx := TRUE
  955. ELSIF (curImplCls # SymTab.InvalidType)
  956. AND SymTab.MethodExists(curImplCls, nm) THEN
  957. (* bare sibling method name inside a class implementation *)
  958. QbeGen.ThisBase(q);
  959. QbeGen.ArmRecv(q);
  960. curMethCls := curImplCls; k := SymTab.KindProc;
  961. t := SymTab.InvalidType; sfx := FALSE
  962. ELSE
  963. t := SymTab.InvalidType; k := -1; QbeGen.CopyOp("0", q); RETURN
  964. END
  965. END;
  966. IF k = SymTab.KindConst THEN
  967. IF SymTab.Equal(nm, "TRUE") THEN
  968. t := SymTab.BoolType(); QbeGen.CopyOp("1", q)
  969. ELSIF SymTab.Equal(nm, "FALSE") THEN
  970. t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
  971. ELSIF SymTab.Equal(nm, "NIL") THEN
  972. QbeGen.CopyOp("0", q)
  973. ELSE
  974. cls := SymTab.ClassOf(t);
  975. IF (cls = SymTab.ClArray) OR (cls = SymTab.ClRecord)
  976. OR (cls = SymTab.ClClass) OR (cls = SymTab.ClStr)
  977. OR (cls = SymTab.ClUStr) OR (cls = SymTab.ClSet) THEN
  978. (* aggregate/string const: its value IS the descriptor address *)
  979. IF GetConstVal(nm, cv) THEN QbeGen.CopyOp(cv, q)
  980. ELSE QbeGen.CopyOp("0", q)
  981. END
  982. ELSIF (cls = SymTab.ClInt) OR (cls = SymTab.ClChar)
  983. OR (cls = SymTab.ClEnum) OR (cls = SymTab.ClLong)
  984. OR (cls = SymTab.ClBool) THEN
  985. IF GetConstVal(nm, cv) AND QbeGen.IsImm(cv) THEN
  986. QbeGen.CopyOp(cv, q)
  987. ELSE QbeGen.CopyOp("0", q)
  988. END
  989. ELSIF cls = SymTab.ClReal THEN
  990. (* a real CONST lives in its data symbol; load it *)
  991. QbeGen.LoadVar(nm, TRUE, q)
  992. ELSE QbeGen.CopyOp("0", q)
  993. END
  994. END
  995. ELSIF (k = SymTab.KindVar) OR (k = SymTab.KindParam) THEN
  996. cls := SymTab.ClassOf(t);
  997. IF AST.Op(n) = 1 THEN
  998. (* a forward module-level reference: the grammar's FwdAddrOper
  999. leaves an address (sfx=TRUE), not a loaded value *)
  1000. QbeGen.AddrOf(nm, q); sfx := TRUE
  1001. ELSIF (cls = SymTab.ClInt) OR (cls = SymTab.ClBool)
  1002. OR (cls = SymTab.ClChar) OR (cls = SymTab.ClUChar)
  1003. OR (cls = SymTab.ClEnum) OR (cls = SymTab.ClReal) THEN
  1004. QbeGen.LoadVar(nm, cls = SymTab.ClReal, q)
  1005. ELSIF (cls = SymTab.ClPtr) OR (cls = SymTab.ClProc) THEN
  1006. QbeGen.LoadPtr(nm, q)
  1007. ELSIF cls = SymTab.ClLong THEN
  1008. QbeGen.LoadLong(nm, q)
  1009. ELSE QbeGen.AddrOf(nm, q)
  1010. END
  1011. ELSIF k = SymTab.KindField THEN
  1012. (* q already holds the field address (WithField) *)
  1013. ELSE QbeGen.CopyOp("0", q)
  1014. END;
  1015. END;
  1016. i := 1;
  1017. WHILE i < AST.NChild(n) DO
  1018. sel := AST.Child(n, i);
  1019. op := AST.Op(sel);
  1020. IF op = AST.SelField THEN
  1021. Name(AST.Child(sel, 0), fn);
  1022. IF k = SymTab.KindModule THEN
  1023. (* qualified L.x: materialize the export, then load it *)
  1024. IF SymTab.MaterializeAlias(nm, fn, mal) THEN
  1025. QbeGen.CopyOp(mal, qn);
  1026. t := SymTab.SymType(mal); k := SymTab.SymKind(mal); sfx := FALSE;
  1027. IF k = SymTab.KindProc THEN QbeGen.CopyOp("0", q)
  1028. ELSIF NOT QbeGen.LoadDesignator(mal, t, k, q) THEN
  1029. t := SymTab.InvalidType; QbeGen.CopyOp("0", q)
  1030. END
  1031. ELSE t := SymTab.InvalidType; QbeGen.CopyOp("0", q)
  1032. END
  1033. ELSIF t = SymTab.InvalidType THEN
  1034. ELSIF (SymTab.ClassOf(t) = SymTab.ClClass)
  1035. AND SymTab.MethodExists(t, fn) THEN
  1036. (* obj.Method: bind the receiver; the call supplies the value *)
  1037. QbeGen.ArmRecv(q);
  1038. QbeGen.CopyOp(fn, qn);
  1039. curMethCls := t; k := SymTab.KindProc; t := SymTab.InvalidType
  1040. ELSIF NOT SymTab.FieldExists(t, fn) THEN t := SymTab.InvalidType
  1041. ELSE
  1042. fo := SymTab.FieldOffset(t, fn);
  1043. t := SymTab.FieldType(t, fn);
  1044. QbeGen.FieldAddr(q, fo, qe);
  1045. QbeGen.CopyOp(qe, q);
  1046. sfx := TRUE
  1047. END
  1048. ELSIF op = AST.SelIndex THEN
  1049. LowerExpr(AST.Child(sel, 0), it, iq);
  1050. IF t = SymTab.InvalidType THEN
  1051. ELSE
  1052. QbeGen.WidenIndex(iq, ql);
  1053. isOpen := SymTab.IsOpenArray(t);
  1054. IF isOpen THEN
  1055. QbeGen.CopyOp("0", qlo);
  1056. IF SymTab.IsCharArray(t) OR SymTab.IsUCharArray(t) THEN
  1057. QbeGen.OpenHiChar(q, qhi)
  1058. ELSE QbeGen.OpenHi(q, qhi)
  1059. END
  1060. ELSE
  1061. lo := SymTab.ArrayLo(t); hi := SymTab.ArrayHi(t);
  1062. IF SymTab.IsCharArray(t) OR SymTab.IsUCharArray(t) THEN
  1063. hi := hi + 1
  1064. END;
  1065. QbeGen.IntStr(lo, qlo); QbeGen.IntStr(hi, qhi)
  1066. END;
  1067. QbeGen.CheckRange(ql, qlo, qhi);
  1068. eT := SymTab.ArrayElem(t);
  1069. QbeGen.ElemAddr(q, ql, qlo, t, qe);
  1070. IF SymTab.ClassOf(eT) = SymTab.ClArray THEN
  1071. QbeGen.ElemLoad(qe, eT, q)
  1072. ELSE QbeGen.CopyOp(qe, q)
  1073. END;
  1074. t := eT; sfx := TRUE
  1075. END
  1076. ELSIF op = AST.SelDeref THEN
  1077. IF t = SymTab.InvalidType THEN
  1078. ELSIF SymTab.ClassOf(t) # SymTab.ClPtr THEN t := SymTab.InvalidType
  1079. ELSE
  1080. IF sfx THEN QbeGen.ElemLoad(q, t, qe); QbeGen.CopyOp(qe, q) END;
  1081. t := SymTab.PtrBase(t); sfx := TRUE
  1082. END
  1083. END;
  1084. INC(i)
  1085. END
  1086. END LowerDesign;
  1087. PROCEDURE CompositeRes (t: SymTab.TypeIndex): BOOLEAN;
  1088. (* TRUE for a composite (by-value) function result: record/array/set.
  1089. Such results use a hidden destination pointer (sret). *)
  1090. VAR cls: INTEGER;
  1091. BEGIN
  1092. IF t = SymTab.InvalidType THEN RETURN FALSE END;
  1093. cls := SymTab.ClassOf(t);
  1094. RETURN (cls = SymTab.ClRecord) OR (cls = SymTab.ClArray)
  1095. OR (cls = SymTab.ClSet) OR (cls = SymTab.ClClass)
  1096. END CompositeRes;
  1097. PROCEDURE UserLabel (name: ARRAY OF CHAR; VAR q: QbeGen.QVal);
  1098. (* The QbeGen label for a user label/goto name (per procedure). *)
  1099. VAR i: CARDINAL;
  1100. BEGIN
  1101. i := 0;
  1102. WHILE i < nUserLab DO
  1103. IF SpanEq(userLabNm, i * 64, name) THEN q := userLabQ[i]; RETURN END;
  1104. INC(i)
  1105. END;
  1106. QbeGen.NewLabel(q);
  1107. IF nUserLab <= HIGH(userLabQ) THEN
  1108. CopySpan(name, userLabNm, 0, nUserLab * 64);
  1109. userLabQ[nUserLab] := q;
  1110. INC(nUserLab)
  1111. END
  1112. END UserLabel;
  1113. PROCEDURE LowerCall (n: AST.Node; VAR t: SymTab.TypeIndex;
  1114. VAR q: QbeGen.QVal; want: BOOLEAN);
  1115. VAR nm, pn, cqn: SymTab.Name; i, ai: CARDINAL; at, ft, res: SymTab.TypeIndex;
  1116. qa, qt, qe, mg, qres: QbeGen.QVal; conv, isV, qual, ind, isC, va: BOOLEAN;
  1117. uid, depth, np: CARDINAL; ext: BOOLEAN; ck: INTEGER; pi: INTEGER;
  1118. ct: SymTab.TypeIndex; csfx: BOOLEAN; cl: CHAR;
  1119. seq, next, arg: AST.Node;
  1120. BEGIN
  1121. qual := CalleeAlias(n, nm);
  1122. ind := FALSE; isC := FALSE; va := FALSE; pi := -1; ext := FALSE;
  1123. IF qual AND qualIsVar THEN
  1124. (* M.Error where Error is a procedure-typed variable: indirect. *)
  1125. LowerDesign(AST.Child(n, 0), ct, ck, qa, cqn, csfx);
  1126. IF (ct # SymTab.InvalidType)
  1127. AND (SymTab.ClassOf(ct) = SymTab.ClProc) THEN
  1128. ind := TRUE;
  1129. res := SymTab.ProcTypeRes(ct);
  1130. np := SymTab.ProcTypeNPar(ct);
  1131. QbeGen.CallBeginInd(qa, res, FALSE)
  1132. ELSE
  1133. res := SymTab.InvalidType;
  1134. QbeGen.CallBegin(nm, res, 0, FALSE)
  1135. END
  1136. ELSIF qual THEN
  1137. (* M.P: the base name may be duplicated across modules, so select
  1138. the exact proc entry by the alias's uid. *)
  1139. pi := FindProcByUid(qualUid);
  1140. IF ProcInfoIdx(pi, uid, res, depth, ext, np) THEN
  1141. IF ext THEN QbeGen.CopyOp(nm, mg) ELSE QbeGen.Mangled(nm, uid, mg) END;
  1142. QbeGen.CallBegin(mg, res, depth, ext)
  1143. ELSE
  1144. res := SymTab.InvalidType;
  1145. QbeGen.CallBegin(nm, res, 0, FALSE)
  1146. END
  1147. ELSE
  1148. CalleeName(n, nm);
  1149. IF FindSym(nm, ck, ct)
  1150. AND ((ck = SymTab.KindVar) OR (ck = SymTab.KindParam))
  1151. AND (SymTab.ClassOf(ct) = SymTab.ClProc) THEN
  1152. (* indirect call through a procedure-typed variable *)
  1153. ind := TRUE;
  1154. LowerDesign(AST.Child(n, 0), ct, ck, qa, cqn, csfx);
  1155. res := SymTab.ProcTypeRes(ct);
  1156. np := SymTab.ProcTypeNPar(ct);
  1157. QbeGen.CallBeginInd(qa, res, FALSE)
  1158. ELSIF ProcInfo(nm, uid, res, depth, ext, np) THEN
  1159. pi := FindProc(nm);
  1160. IF ext THEN
  1161. (* External callee: bind to its C link name (the procedure's
  1162. own name); SymTab.ProcLink cannot be consulted after
  1163. EndUnit. *)
  1164. QbeGen.CopyOp(nm, mg)
  1165. ELSE
  1166. QbeGen.Mangled(nm, uid, mg)
  1167. END;
  1168. QbeGen.CallBegin(mg, res, depth, ext)
  1169. ELSE
  1170. (* not in Lower's table: a predef C proc (SYSTEM.TRANSFER,
  1171. NEWPROCESS, ...) lives in SymTab with a C link name *)
  1172. IF SymTab.Lookup(nm) AND (SymTab.SymKind(nm) = SymTab.KindProc) THEN
  1173. isC := TRUE;
  1174. res := SymTab.ProcRes(nm);
  1175. np := SymTab.ProcNPar(nm);
  1176. IF SymTab.ProcLink(nm, pn) THEN
  1177. QbeGen.CallBegin(pn, res, 0, TRUE)
  1178. ELSE
  1179. QbeGen.CallBegin(nm, res, 0, FALSE)
  1180. END
  1181. ELSE
  1182. res := SymTab.InvalidType;
  1183. QbeGen.CallBegin(nm, res, 0, FALSE)
  1184. END
  1185. END
  1186. END;
  1187. IF CompositeRes(res) THEN
  1188. (* composite result: pass a hidden destination pointer first *)
  1189. QbeGen.AllocLocal(res, qres);
  1190. IF NOT QbeGen.CallArg(qres, "l") THEN END
  1191. END;
  1192. va := (pi >= 0) AND (pi < VAL(INTEGER, nProcs)) AND procVa[pi];
  1193. (* actuals are a chunked sequence (AstCallNode): follow the NkBlock
  1194. continuations so a call with >MaxChild-1 arguments is complete *)
  1195. ai := 0;
  1196. seq := n;
  1197. WHILE seq # AST.NoNode DO
  1198. i := 0;
  1199. IF seq = n THEN i := 1 END; (* skip the callee in the head *)
  1200. WHILE i < AST.NChild(seq) DO
  1201. arg := AST.Child(seq, i);
  1202. IF AST.Kind(arg) # AST.NkBlock THEN
  1203. LowerExpr(arg, at, qe);
  1204. IF ind THEN
  1205. ft := SymTab.ProcTypeParamType(ct, ai);
  1206. isV := SymTab.ProcTypeParamIsVar(ct, ai)
  1207. ELSIF va THEN
  1208. ft := at; isV := FALSE
  1209. ELSIF isC THEN
  1210. ft := SymTab.ParamType(nm, ai);
  1211. isV := SymTab.ParamIsVar(nm, ai)
  1212. ELSE
  1213. IF NOT ParamInfoIdx(pi, ai, ft, isV, pn) THEN END
  1214. END;
  1215. IF va THEN
  1216. (* permissive C variadic argument *)
  1217. QbeGen.CArgAdd(qe, at, qa, cl)
  1218. ELSIF isV THEN
  1219. IF (SymTab.ClassOf(at) = SymTab.ClChar)
  1220. AND (SymTab.ClassOf(ft) = SymTab.ClArray)
  1221. AND (SymTab.ClassOf(SymTab.ArrayElem(ft)) = SymTab.ClChar)
  1222. AND QbeGen.IsImm(qe) THEN
  1223. (* 1-char string literal passed to a VAR ARRAY OF CHAR:
  1224. pass its static descriptor *)
  1225. QbeGen.DeclCharStr(qe, qa);
  1226. IF NOT QbeGen.CallArg(qa, "l") THEN END
  1227. ELSIF QbeGen.AddrOfVal(qe, qa) THEN
  1228. IF NOT QbeGen.CallArg(qa, "l") THEN END
  1229. END
  1230. ELSE
  1231. IF (SymTab.ClassOf(at) = SymTab.ClChar)
  1232. AND (SymTab.ClassOf(ft) = SymTab.ClArray)
  1233. AND (SymTab.ClassOf(SymTab.ArrayElem(ft)) = SymTab.ClChar)
  1234. AND QbeGen.IsImm(qe) THEN
  1235. (* 1-char string literal passed to ARRAY OF CHAR: pass its
  1236. static descriptor, not the char code *)
  1237. QbeGen.DeclCharStr(qe, qa);
  1238. IF NOT QbeGen.CallArg(qa, "l") THEN END
  1239. ELSE
  1240. conv := (SymTab.ClassOf(ft) = SymTab.ClReal)
  1241. AND SymTab.IsIntFamily(at);
  1242. IF conv THEN
  1243. QbeGen.ConvIR(qe, qt);
  1244. IF NOT QbeGen.CallArg(qt, "d") THEN END
  1245. ELSE
  1246. IF NOT QbeGen.CallArg(qe, QbeGen.ArgClass(ft)) THEN END
  1247. END
  1248. END
  1249. END;
  1250. INC(ai)
  1251. END;
  1252. INC(i)
  1253. END;
  1254. next := AST.NoNode;
  1255. IF AST.NChild(seq) > 0 THEN
  1256. next := AST.Child(seq, AST.NChild(seq) - 1);
  1257. IF AST.Kind(next) # AST.NkBlock THEN next := AST.NoNode END
  1258. END;
  1259. seq := next
  1260. END;
  1261. IF want THEN
  1262. t := res; QbeGen.CallEnd(TRUE, q);
  1263. IF CompositeRes(res) THEN QbeGen.CopyOp(qres, q) END
  1264. ELSE
  1265. t := SymTab.InvalidType; QbeGen.CopyOp("0", q); QbeGen.CallEnd(FALSE, q)
  1266. END
  1267. END LowerCall;
  1268. PROCEDURE IsBuiltin (nm: ARRAY OF CHAR): BOOLEAN;
  1269. BEGIN
  1270. RETURN SymTab.Equal(nm, "ABS") OR SymTab.Equal(nm, "ODD")
  1271. OR SymTab.Equal(nm, "CAP")
  1272. OR SymTab.Equal(nm, "CHR") OR SymTab.Equal(nm, "ORD")
  1273. OR SymTab.Equal(nm, "UCHR") OR SymTab.Equal(nm, "CHR8")
  1274. OR SymTab.Equal(nm, "UORD")
  1275. OR SymTab.Equal(nm, "SIZE") OR SymTab.Equal(nm, "TSIZE")
  1276. OR SymTab.Equal(nm, "LEN") OR SymTab.Equal(nm, "HIGH")
  1277. OR SymTab.Equal(nm, "VAL")
  1278. OR SymTab.Equal(nm, "MIN") OR SymTab.Equal(nm, "MAX")
  1279. OR SymTab.Equal(nm, "SHIFT") OR SymTab.Equal(nm, "ROTATE")
  1280. OR SymTab.Equal(nm, "ADR")
  1281. OR SymTab.Equal(nm, "INC") OR SymTab.Equal(nm, "DEC")
  1282. OR SymTab.Equal(nm, "INCL") OR SymTab.Equal(nm, "EXCL")
  1283. OR SymTab.Equal(nm, "NEW") OR SymTab.Equal(nm, "DISPOSE")
  1284. END IsBuiltin;
  1285. PROCEDURE LowerBuiltinExpr (n: AST.Node; nm: SymTab.Name;
  1286. VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal);
  1287. (* Value builtins (Fact). *)
  1288. VAR et, et2, dt, vt: SymTab.TypeIndex; qa, qt, q2, qd, qr: QbeGen.QVal;
  1289. k, lo, hi, c1, c2, ucp: INTEGER; qn, vn: SymTab.Name; sfx: BOOLEAN;
  1290. isMax, isU, uok: BOOLEAN;
  1291. BEGIN
  1292. IF SymTab.Equal(nm, "ODD") THEN
  1293. LowerExpr(AST.Child(n, 1), et, q);
  1294. QbeGen.NewTemp(qt);
  1295. QbeGen.Op3("and", qt, q, "1", FALSE); (* x & 1 *)
  1296. QbeGen.NewTemp(qa);
  1297. QbeGen.Cmp(SymTab.OpNeq1, qt, "0", qa, FALSE); (* <> 0 *)
  1298. QbeGen.CopyOp(qa, q); t := SymTab.BoolType()
  1299. ELSIF SymTab.Equal(nm, "ABS") THEN
  1300. LowerExpr(AST.Child(n, 1), et, q);
  1301. QbeGen.AbsQ(q, qa, SymTab.ClassOf(et) = SymTab.ClReal);
  1302. QbeGen.CopyOp(qa, q); t := et
  1303. ELSIF SymTab.Equal(nm, "CAP") THEN
  1304. LowerExpr(AST.Child(n, 1), et, q);
  1305. QbeGen.CapQ(q, qa); QbeGen.CopyOp(qa, q); t := SymTab.CharType()
  1306. ELSIF SymTab.Equal(nm, "CHR") THEN
  1307. LowerExpr(AST.Child(n, 1), et, q); t := SymTab.CharType()
  1308. ELSIF SymTab.Equal(nm, "ORD") THEN
  1309. LowerExpr(AST.Child(n, 1), et, q); t := SymTab.IntType()
  1310. ELSIF SymTab.Equal(nm, "UCHR") THEN
  1311. LowerExpr(AST.Child(n, 1), et, q); t := SymTab.UCharType()
  1312. ELSIF SymTab.Equal(nm, "CHR8") THEN
  1313. LowerExpr(AST.Child(n, 1), et, q);
  1314. QbeGen.WidenLong(q, qa); QbeGen.CheckRange(qa, "0", "255");
  1315. t := SymTab.CharType()
  1316. ELSIF SymTab.Equal(nm, "UORD") THEN
  1317. LowerExpr(AST.Child(n, 1), et, q); t := SymTab.IntType()
  1318. ELSIF SymTab.Equal(nm, "SIZE") OR SymTab.Equal(nm, "TSIZE") THEN
  1319. LowerDesign(AST.Child(n, 1), dt, k, qd, qn, sfx);
  1320. QbeGen.IntStr(VAL(INTEGER, SymTab.ObjectSize(dt)), q);
  1321. t := SymTab.IntType()
  1322. ELSIF SymTab.Equal(nm, "MIN") OR SymTab.Equal(nm, "MAX") THEN
  1323. isMax := SymTab.Equal(nm, "MAX");
  1324. LowerDesign(AST.Child(n, 1), dt, k, qd, qn, sfx);
  1325. IF SymTab.ClassOf(dt) = SymTab.ClReal THEN
  1326. IF isMax THEN QbeGen.NormReal("3.402823e38", q)
  1327. ELSE QbeGen.NormReal("-3.402823e38", q) END;
  1328. t := SymTab.RealType()
  1329. ELSIF SymTab.ClassOf(dt) = SymTab.ClLong THEN
  1330. IF isMax THEN QbeGen.CopyOp("9223372036854775807", q)
  1331. ELSE QbeGen.CopyOp("-9223372036854775808", q) END;
  1332. t := SymTab.LongType()
  1333. ELSIF SymTab.TypeBounds(dt, lo, hi) THEN
  1334. IF isMax THEN QbeGen.IntStr(hi, q) ELSE QbeGen.IntStr(lo, q) END;
  1335. t := SymTab.IntType()
  1336. ELSE t := SymTab.InvalidType; QbeGen.CopyOp("0", q)
  1337. END
  1338. ELSIF SymTab.Equal(nm, "LEN") OR SymTab.Equal(nm, "HIGH") THEN
  1339. IF AST.Kind(AST.Child(n, 1)) = AST.NkStrLit THEN
  1340. (* LEN("literal"): the content length of the literal; a real
  1341. string literal is still declared, as the grammar does *)
  1342. Name(AST.Child(n, 1), qn);
  1343. IF (qn[0] = "U") OR (qn[0] = "u") THEN
  1344. QbeGen.DeclUStr(qn, qd, isU, ucp, uok);
  1345. IF NOT uok THEN t := SymTab.InvalidType; QbeGen.CopyOp("0", q)
  1346. ELSIF isU THEN
  1347. IF SymTab.Equal(nm, "HIGH") THEN QbeGen.CopyOp("0", q)
  1348. ELSE QbeGen.CopyOp("1", q)
  1349. END;
  1350. t := SymTab.IntType()
  1351. ELSE
  1352. QbeGen.UStrLen(qd, qr);
  1353. IF SymTab.Equal(nm, "HIGH") THEN QbeGen.DecQ(qr) END;
  1354. QbeGen.CopyOp(qr, q); t := SymTab.IntType()
  1355. END
  1356. ELSE
  1357. IF SymTab.StrLen(qn) = 3 THEN c1 := 1
  1358. ELSE QbeGen.DeclStr(qn, qd); c1 := SymTab.StrLen(qn) - 2
  1359. END;
  1360. IF SymTab.Equal(nm, "HIGH") THEN DEC(c1) END;
  1361. QbeGen.IntStr(c1, q); t := SymTab.IntType()
  1362. END
  1363. ELSE
  1364. LowerDesign(AST.Child(n, 1), dt, k, qd, qn, sfx);
  1365. IF dt = SymTab.InvalidType THEN
  1366. t := SymTab.InvalidType; QbeGen.CopyOp("0", q)
  1367. ELSIF SymTab.ClassOf(dt) = SymTab.ClArray THEN
  1368. IF SymTab.Equal(nm, "HIGH") THEN
  1369. IF SymTab.IsOpenArray(dt) THEN QbeGen.OpenHi(qd, q)
  1370. ELSE QbeGen.IntStr(SymTab.ArrayHi(dt), q) END
  1371. ELSE
  1372. IF SymTab.IsOpenArray(dt) THEN QbeGen.LoadCount(qd, q)
  1373. ELSE QbeGen.IntStr(VAL(INTEGER, SymTab.ArrayLen(dt)), q) END
  1374. END;
  1375. t := SymTab.IntType()
  1376. ELSE
  1377. t := SymTab.InvalidType; QbeGen.CopyOp("0", q)
  1378. END
  1379. END;
  1380. ELSIF SymTab.Equal(nm, "VAL") THEN
  1381. Name(AST.Child(n, 1), vn);
  1382. IF NOT SymTab.Lookup(vn) THEN
  1383. t := SymTab.InvalidType; QbeGen.CopyOp("0", q)
  1384. ELSE
  1385. vt := SymTab.SymType(vn);
  1386. LowerExpr(AST.Child(n, 2), et, q);
  1387. c1 := SymTab.ClassOf(et); c2 := SymTab.ClassOf(vt);
  1388. IF (c1 = SymTab.ClInt) AND (c2 = SymTab.ClLong) THEN
  1389. QbeGen.WidenLong(q, qa); QbeGen.CopyOp(qa, q); t := vt
  1390. ELSIF (c1 = SymTab.ClLong) AND (c2 = SymTab.ClInt) THEN
  1391. QbeGen.NarrowLong(q, qa); QbeGen.CopyOp(qa, q); t := vt
  1392. ELSIF (c1 = SymTab.ClInt) AND (c2 = SymTab.ClReal) THEN
  1393. QbeGen.ConvIR(q, qa); QbeGen.CopyOp(qa, q); t := vt
  1394. ELSIF (c1 = SymTab.ClLong) AND (c2 = SymTab.ClReal) THEN
  1395. QbeGen.ConvLR(q, qa); QbeGen.CopyOp(qa, q); t := vt
  1396. ELSIF (c1 = SymTab.ClReal) AND (c2 = SymTab.ClInt) THEN
  1397. QbeGen.ConvRI(q, qa); QbeGen.CopyOp(qa, q); t := vt
  1398. ELSIF (c1 = SymTab.ClReal) AND (c2 = SymTab.ClLong) THEN
  1399. QbeGen.ConvRL(q, qa); QbeGen.CopyOp(qa, q); t := vt
  1400. ELSIF (c1 = SymTab.ClSet) AND (c2 = SymTab.ClInt) THEN
  1401. (* a set as its (first) machine word *)
  1402. QbeGen.LoadW(q, qa); QbeGen.CopyOp(qa, q); t := vt
  1403. ELSIF (c1 = SymTab.ClInt) AND (c2 = SymTab.ClSet) THEN
  1404. (* a word as a set value: zero-filled one-word temp *)
  1405. c2 := SymTab.SetWords(vt);
  1406. IF c2 = 0 THEN c2 := 1 END;
  1407. QbeGen.NewSetTemp(VAL(CARDINAL, c2), qa);
  1408. QbeGen.SetZero(qa, VAL(CARDINAL, c2));
  1409. QbeGen.StoreW(qa, q); QbeGen.CopyOp(qa, q); t := vt
  1410. ELSE t := vt (* same representation: no-op *)
  1411. END
  1412. END
  1413. ELSIF SymTab.Equal(nm, "SHIFT") OR SymTab.Equal(nm, "ROTATE") THEN
  1414. LowerExpr(AST.Child(n, 1), et, q);
  1415. LowerExpr(AST.Child(n, 2), et2, q2);
  1416. QbeGen.SetShift(q, q2, SymTab.SetWords(et), SymTab.SetCount(et),
  1417. SymTab.Equal(nm, "ROTATE"), qt);
  1418. t := et; QbeGen.CopyOp(qt, q)
  1419. ELSIF SymTab.Equal(nm, "ADR") THEN
  1420. LowerDesign(AST.Child(n, 1), dt, k, qd, qn, sfx);
  1421. IF k = SymTab.KindProc THEN
  1422. (* ADR of a procedure is its code address *)
  1423. LowerProcAddr(qn, q)
  1424. ELSIF sfx THEN QbeGen.CopyOp(qd, q)
  1425. ELSIF (k = SymTab.KindVar) OR (k = SymTab.KindParam) THEN
  1426. QbeGen.AddrOf(qn, q)
  1427. ELSE QbeGen.CopyOp("0", q)
  1428. END;
  1429. t := SymTab.AddrType()
  1430. ELSE t := SymTab.InvalidType; QbeGen.CopyOp("0", q)
  1431. END
  1432. END LowerBuiltinExpr;
  1433. PROCEDURE LowerBuiltinStmt (n: AST.Node; nm: SymTab.Name);
  1434. (* Statement builtins (AssOrCall): INC/DEC, INCL/EXCL, NEW/DISPOSE. *)
  1435. VAR dt, at, et2, bt: SymTab.TypeIndex; dk: INTEGER;
  1436. qd, qv, qe, qn2, qstep, qm: QbeGen.QVal;
  1437. qn: SymTab.Name; sfx, isInc: BOOLEAN;
  1438. BEGIN
  1439. IF SymTab.Equal(nm, "INC") OR SymTab.Equal(nm, "DEC") THEN
  1440. isInc := SymTab.Equal(nm, "INC");
  1441. QbeGen.CopyOp("1", qstep);
  1442. LowerDesign(AST.Child(n, 1), dt, dk, qd, qn, sfx);
  1443. IF AST.NChild(n) > 2 THEN LowerExpr(AST.Child(n, 2), et2, qstep) END;
  1444. IF dt = SymTab.InvalidType THEN
  1445. ELSE
  1446. IF sfx OR (dk = SymTab.KindField) THEN QbeGen.ElemLoad(qd, dt, qv)
  1447. ELSE QbeGen.LoadVar(qn, FALSE, qv)
  1448. END;
  1449. QbeGen.NewTemp(qn2);
  1450. IF isInc THEN QbeGen.Op3("add", qn2, qv, qstep, FALSE)
  1451. ELSE QbeGen.Op3("sub", qn2, qv, qstep, FALSE)
  1452. END;
  1453. IF sfx OR (dk = SymTab.KindField) THEN QbeGen.ElemStore(qd, qn2, dt)
  1454. ELSE QbeGen.StoreVar(qn, qn2, FALSE)
  1455. END
  1456. END
  1457. ELSIF SymTab.Equal(nm, "INCL") OR SymTab.Equal(nm, "EXCL") THEN
  1458. isInc := SymTab.Equal(nm, "INCL");
  1459. LowerDesign(AST.Child(n, 1), at, dk, qd, qn, sfx);
  1460. LowerExpr(AST.Child(n, 2), et2, qe);
  1461. IF at = SymTab.InvalidType THEN
  1462. ELSIF SymTab.ClassOf(at) # SymTab.ClSet THEN
  1463. ELSE
  1464. IF isInc THEN QbeGen.SetBit(qd, qe, SymTab.SetBaseLo(at), SymTab.SetCount(at))
  1465. ELSE QbeGen.SetClearBit(qd, qe, SymTab.SetBaseLo(at), SymTab.SetCount(at))
  1466. END
  1467. END
  1468. ELSIF SymTab.Equal(nm, "NEW") THEN
  1469. LowerDesign(AST.Child(n, 1), dt, dk, qd, qn, sfx);
  1470. IF dt = SymTab.InvalidType THEN
  1471. ELSIF SymTab.ClassOf(dt) # SymTab.ClPtr THEN
  1472. ELSE
  1473. bt := SymTab.PtrBase(dt);
  1474. IF bt # SymTab.InvalidType THEN
  1475. QbeGen.NewHeap(bt, qm); QbeGen.InitHeap(qm, bt);
  1476. IF sfx OR (dk = SymTab.KindField) THEN QbeGen.ElemStore(qd, qm, dt)
  1477. ELSE QbeGen.StorePtr(qn, qm)
  1478. END
  1479. END
  1480. END
  1481. ELSIF SymTab.Equal(nm, "DISPOSE") THEN
  1482. LowerDesign(AST.Child(n, 1), dt, dk, qd, qn, sfx);
  1483. IF dt = SymTab.InvalidType THEN
  1484. ELSIF SymTab.ClassOf(dt) # SymTab.ClPtr THEN
  1485. ELSE
  1486. IF sfx OR (dk = SymTab.KindField) THEN QbeGen.ElemLoad(qd, dt, qv)
  1487. ELSE QbeGen.LoadPtr(qn, qv)
  1488. END;
  1489. QbeGen.FreeHeap(qv);
  1490. IF sfx OR (dk = SymTab.KindField) THEN QbeGen.ElemStore(qd, "0", dt)
  1491. ELSE QbeGen.StorePtr(qn, "0")
  1492. END
  1493. END
  1494. END
  1495. END LowerBuiltinStmt;
  1496. PROCEDURE LowerMethod (m: AST.Node; ct: SymTab.TypeIndex);
  1497. (* A class method: hidden THIS receiver, then declared formals; the body
  1498. runs with THIS pushed as the WITH base (bare field names resolve). *)
  1499. VAR nm, txt: SymTab.Name; mg, thisQ: QbeGen.QVal;
  1500. uid, depth, np: CARDINAL; res, pt: SymTab.TypeIndex;
  1501. pv, ext: BOOLEAN; j: CARDINAL; saveCls: SymTab.TypeIndex;
  1502. savedProc: INTEGER;
  1503. BEGIN
  1504. IF (AST.Op(m) # 0) AND (AST.Op(m) # 3) THEN RETURN END;
  1505. Name(AST.Child(m, 0), nm);
  1506. IF NOT ProcInfo(nm, uid, res, depth, ext, np) THEN RETURN END;
  1507. QbeGen.Mangled(nm, SymTab.ClassMethodUid(ct, nm), mg);
  1508. QbeGen.BeginFunc(mg);
  1509. IF NOT QbeGen.FuncParam("THIS", TRUE, ct) THEN END;
  1510. IF CompositeRes(res) THEN
  1511. IF NOT QbeGen.FuncParam("__res", TRUE, res) THEN END
  1512. END;
  1513. j := 0;
  1514. WHILE j < np DO
  1515. IF NOT ParamInfo(nm, j, pt, pv, txt) THEN END;
  1516. IF NOT QbeGen.FuncParam(txt, pv OR SymTab.IsOpenArray(pt), pt) THEN END;
  1517. INC(j)
  1518. END;
  1519. QbeGen.SetFuncRes(res);
  1520. QbeGen.EndFuncHeader;
  1521. QbeGen.ThisBase(thisQ);
  1522. saveCls := curImplCls;
  1523. curImplCls := ct;
  1524. QbeGen.PushWith(thisQ);
  1525. IF withTop <= HIGH(withRec) THEN withRec[withTop] := ct; INC(withTop) END;
  1526. savedProc := emitProc;
  1527. emitProc := FindProc(nm);
  1528. LowerDecls(AST.Child(m, 2));
  1529. nUserLab := 0;
  1530. LowerStmt(AST.Child(m, 1));
  1531. emitProc := savedProc;
  1532. IF withTop > 0 THEN DEC(withTop) END;
  1533. curImplCls := saveCls;
  1534. QbeGen.PopWith;
  1535. QbeGen.EndFunc(res)
  1536. END LowerMethod;
  1537. PROCEDURE LowerMethods (seq: AST.Node; ct: SymTab.TypeIndex);
  1538. VAR i: CARDINAL; m: AST.Node;
  1539. BEGIN
  1540. IF seq = AST.NoNode THEN RETURN END;
  1541. i := 0;
  1542. WHILE i < AST.NChild(seq) DO
  1543. m := AST.Child(seq, i);
  1544. IF i = AST.MaxChild - 1 THEN LowerMethods(m, ct)
  1545. ELSIF AST.Kind(m) = AST.NkFieldDecl THEN LowerMethods(m, ct)
  1546. ELSIF AST.Kind(m) = AST.NkProcDecl THEN LowerMethod(m, ct)
  1547. END;
  1548. INC(i)
  1549. END
  1550. END LowerMethods;
  1551. PROCEDURE LowerMethodHeadings (seq: AST.Node; ct: SymTab.TypeIndex);
  1552. (* Class-declaration method headings: emit+discard a function header per
  1553. method so the backend temp counters advance exactly as the legacy
  1554. parse did (the implementation's temps then line up). *)
  1555. VAR i, j: CARDINAL; m: AST.Node; nm, txt: SymTab.Name;
  1556. mg: QbeGen.QVal; uid, depth, np: CARDINAL; res, pt: SymTab.TypeIndex;
  1557. pv, ext: BOOLEAN;
  1558. BEGIN
  1559. IF seq = AST.NoNode THEN RETURN END;
  1560. i := 0;
  1561. WHILE i < AST.NChild(seq) DO
  1562. m := AST.Child(seq, i);
  1563. IF i = AST.MaxChild - 1 THEN LowerMethodHeadings(m, ct)
  1564. ELSIF AST.Kind(m) = AST.NkFieldDecl THEN LowerMethodHeadings(m, ct)
  1565. ELSIF AST.Kind(m) = AST.NkProcDecl THEN
  1566. Name(AST.Child(m, 0), nm);
  1567. IF ProcInfo(nm, uid, res, depth, ext, np) THEN
  1568. QbeGen.Mangled(nm, SymTab.ClassMethodUid(ct, nm), mg);
  1569. QbeGen.BeginFunc(mg);
  1570. j := 0;
  1571. WHILE j < np DO
  1572. IF NOT ParamInfo(nm, j, pt, pv, txt) THEN END;
  1573. IF NOT QbeGen.FuncParam(txt, pv OR SymTab.IsOpenArray(pt), pt) THEN END;
  1574. INC(j)
  1575. END;
  1576. QbeGen.SetFuncRes(res);
  1577. QbeGen.AbortFunc
  1578. END
  1579. END;
  1580. INC(i)
  1581. END
  1582. END LowerMethodHeadings;
  1583. PROCEDURE LowerMethodCall (n: AST.Node; VAR t: SymTab.TypeIndex;
  1584. VAR q: QbeGen.QVal; want: BOOLEAN);
  1585. VAR d: AST.Node; ct, res, ft, at: SymTab.TypeIndex;
  1586. cq, mg, qa, qt, qe, qres: QbeGen.QVal; fn, pn: SymTab.Name;
  1587. k, vs: INTEGER; i: CARDINAL; sfx, isV, conv: BOOLEAN;
  1588. BEGIN
  1589. d := AST.Child(n, 0);
  1590. curMethCls := SymTab.InvalidType;
  1591. LowerDesign(d, ct, k, cq, pn, sfx);
  1592. ct := curMethCls;
  1593. IF ct = SymTab.InvalidType THEN
  1594. t := SymTab.InvalidType; QbeGen.CopyOp("0", q); RETURN
  1595. END;
  1596. IF AST.NChild(d) = 1 THEN
  1597. Name(AST.Child(d, 0), fn)
  1598. ELSE
  1599. Name(AST.Child(AST.Child(d, AST.NChild(d) - 1), 0), fn)
  1600. END;
  1601. res := SymTab.ClassMethodRes(ct, fn);
  1602. vs := SymTab.VirtSlot(ct, fn);
  1603. IF vs >= 0 THEN QbeGen.VirtCallBegin(cq, vs, res)
  1604. ELSE
  1605. QbeGen.Mangled(fn, SymTab.ClassMethodUid(ct, fn), mg);
  1606. QbeGen.CallBegin(mg, res, 0, FALSE)
  1607. END;
  1608. IF CompositeRes(res) THEN
  1609. QbeGen.AllocLocal(res, qres);
  1610. IF NOT QbeGen.CallArg(qres, "l") THEN END
  1611. END;
  1612. i := 1;
  1613. WHILE i < AST.NChild(n) DO
  1614. LowerExpr(AST.Child(n, i), at, qe);
  1615. ft := SymTab.ClassMethodParamType(ct, fn, i - 1);
  1616. isV := SymTab.ClassMethodParamIsVar(ct, fn, i - 1);
  1617. IF isV THEN
  1618. IF QbeGen.AddrOfVal(qe, qa) THEN
  1619. IF NOT QbeGen.CallArg(qa, "l") THEN END
  1620. END
  1621. ELSE
  1622. conv := (SymTab.ClassOf(ft) = SymTab.ClReal) AND SymTab.IsIntFamily(at);
  1623. IF conv THEN
  1624. QbeGen.ConvIR(qe, qt);
  1625. IF NOT QbeGen.CallArg(qt, "d") THEN END
  1626. ELSE
  1627. IF NOT QbeGen.CallArg(qe, QbeGen.ArgClass(ft)) THEN END
  1628. END
  1629. END;
  1630. INC(i)
  1631. END;
  1632. IF want THEN t := res; QbeGen.CallEnd(TRUE, q);
  1633. IF CompositeRes(res) THEN QbeGen.CopyOp(qres, q) END
  1634. ELSE t := SymTab.InvalidType; QbeGen.CopyOp("0", q); QbeGen.CallEnd(FALSE, q)
  1635. END
  1636. END LowerMethodCall;
  1637. PROCEDURE LowerCase (n: AST.Node);
  1638. (* CASE as a compare-chain (mirrors CaseStat/CaseAlt/CaseLabel). The
  1639. arm list is chunked (AstAppend) so a CASE with more than MaxChild
  1640. alternatives is not truncated. *)
  1641. VAR i, j: CARDINAL; arm, lab, seq, next: AST.Node;
  1642. tsel, t2, t3: SymTab.TypeIndex;
  1643. qsel, q2, q3, qc, qd, qe, lEnd, lBody, lAfter, lNext: QbeGen.QVal;
  1644. BEGIN
  1645. LowerExpr(AST.Child(n, 0), tsel, qsel);
  1646. QbeGen.NewLabel(lEnd);
  1647. (* pass 1: alternatives (ELSE arms come after) *)
  1648. seq := AST.Child(n, 1);
  1649. WHILE seq # AST.NoNode DO
  1650. i := 0;
  1651. WHILE i < AST.NChild(seq) DO
  1652. arm := AST.Child(seq, i);
  1653. IF AST.Kind(arm) = AST.NkBlock THEN
  1654. (* continuation chunk *)
  1655. ELSIF AST.Op(arm) = 1 THEN
  1656. (* ELSE arm: emitted in pass 2 *)
  1657. ELSE
  1658. QbeGen.NewLabel(lBody); QbeGen.NewLabel(lAfter);
  1659. j := 0;
  1660. WHILE j + 1 < AST.NChild(arm) DO
  1661. lab := AST.Child(arm, j);
  1662. IF AST.Kind(lab) = AST.NkSubrange THEN
  1663. LowerExpr(AST.Child(lab, 0), t2, q2);
  1664. QbeGen.NewLabel(lNext);
  1665. QbeGen.Cmp(SymTab.OpEq, qsel, q2, qc, FALSE);
  1666. QbeGen.Jnz(qc, lBody, lNext);
  1667. QbeGen.EmitLabel(lNext);
  1668. LowerExpr(AST.Child(lab, 1), t3, q3);
  1669. QbeGen.Cmp(SymTab.OpGe, qsel, q2, qc, FALSE);
  1670. QbeGen.Cmp(SymTab.OpLe, qsel, q3, qd, FALSE);
  1671. QbeGen.NewTemp(qe);
  1672. QbeGen.Op3("and", qe, qc, qd, FALSE);
  1673. QbeGen.NewLabel(lNext);
  1674. QbeGen.Jnz(qe, lBody, lNext);
  1675. QbeGen.EmitLabel(lNext)
  1676. ELSE
  1677. LowerExpr(lab, t2, q2);
  1678. QbeGen.NewLabel(lNext);
  1679. QbeGen.Cmp(SymTab.OpEq, qsel, q2, qc, FALSE);
  1680. QbeGen.Jnz(qc, lBody, lNext);
  1681. QbeGen.EmitLabel(lNext)
  1682. END;
  1683. INC(j)
  1684. END;
  1685. QbeGen.Jmp(lAfter);
  1686. QbeGen.EmitLabel(lBody);
  1687. LowerStmt(AST.Child(arm, AST.NChild(arm) - 1));
  1688. QbeGen.Jmp(lEnd);
  1689. QbeGen.EmitLabel(lAfter)
  1690. END;
  1691. INC(i)
  1692. END;
  1693. next := AST.NoNode;
  1694. IF AST.NChild(seq) > 0 THEN
  1695. next := AST.Child(seq, AST.NChild(seq) - 1);
  1696. IF AST.Kind(next) # AST.NkBlock THEN next := AST.NoNode END
  1697. END;
  1698. seq := next
  1699. END;
  1700. (* pass 2: ELSE arms *)
  1701. seq := AST.Child(n, 1);
  1702. WHILE seq # AST.NoNode DO
  1703. i := 0;
  1704. WHILE i < AST.NChild(seq) DO
  1705. arm := AST.Child(seq, i);
  1706. IF (AST.Kind(arm) # AST.NkBlock) AND (AST.Op(arm) = 1) THEN
  1707. LowerStmt(AST.Child(arm, 0))
  1708. END;
  1709. INC(i)
  1710. END;
  1711. next := AST.NoNode;
  1712. IF AST.NChild(seq) > 0 THEN
  1713. next := AST.Child(seq, AST.NChild(seq) - 1);
  1714. IF AST.Kind(next) # AST.NkBlock THEN next := AST.NoNode END
  1715. END;
  1716. seq := next
  1717. END;
  1718. QbeGen.EmitLabel(lEnd)
  1719. END LowerCase;
  1720. PROCEDURE LowerWith (n: AST.Node);
  1721. (* WITH: push each record's base address, lower the body, pop only the
  1722. levels this WITH pushed (a nested WITH must restore the outer one). *)
  1723. VAR i, base: CARDINAL; dt: SymTab.TypeIndex; dk: INTEGER;
  1724. qd: QbeGen.QVal; qn: SymTab.Name; sfx: BOOLEAN;
  1725. BEGIN
  1726. base := withTop;
  1727. i := 0;
  1728. WHILE i + 1 < AST.NChild(n) DO
  1729. LowerDesign(AST.Child(n, i), dt, dk, qd, qn, sfx);
  1730. QbeGen.PushWith(qd);
  1731. IF withTop <= HIGH(withRec) THEN
  1732. withRec[withTop] := dt; INC(withTop)
  1733. END;
  1734. INC(i)
  1735. END;
  1736. LowerStmt(AST.Child(n, AST.NChild(n) - 1));
  1737. WHILE withTop > base DO DEC(withTop); QbeGen.PopWith END
  1738. END LowerWith;
  1739. PROCEDURE LowerProcAddr (nm: ARRAY OF CHAR; VAR q: QbeGen.QVal);
  1740. (* Code address of a procedure used as a value (assign to a procedure
  1741. variable): $<base>_<uid>, or the plain C link for external procs. *)
  1742. VAR uid, depth, np: CARDINAL; res: SymTab.TypeIndex; ext: BOOLEAN;
  1743. mg: QbeGen.QVal;
  1744. base: SymTab.Name; ok: BOOLEAN;
  1745. BEGIN
  1746. ok := ProcInfo(nm, uid, res, depth, ext, np);
  1747. IF NOT ok THEN
  1748. (* a qualified/imported procedure appears under its base symbol
  1749. name in the proc table *)
  1750. IF SymTab.SymBase(nm, base) THEN
  1751. ok := ProcInfo(base, uid, res, depth, ext, np)
  1752. END
  1753. END;
  1754. IF ok THEN
  1755. IF ext THEN QbeGen.CopyOp(nm, mg) ELSE QbeGen.Mangled(nm, uid, mg) END;
  1756. QbeGen.ProcAddr(mg, q)
  1757. ELSE QbeGen.CopyOp("0", q)
  1758. END
  1759. END LowerProcAddr;
  1760. PROCEDURE LowerExprFull (n: AST.Node; VAR t: SymTab.TypeIndex;
  1761. VAR q: QbeGen.QVal; VAR k: INTEGER;
  1762. VAR qn: SymTab.Name; VAR sfx: BOOLEAN;
  1763. asAddr: BOOLEAN);
  1764. VAR t2: SymTab.TypeIndex; q2, qt, qf, qs, qr, qaddr, qa, qb: QbeGen.QVal;
  1765. lNext, lFalse, lTrue, lDone: QbeGen.QVal;
  1766. kind, op, rop, ucp: INTEGER;
  1767. folded, isR, isCh, isU, uok: BOOLEAN;
  1768. i: CARDINAL; el, seq, next: AST.Node;
  1769. lw, rw, mw: CARDINAL; idx: INTEGER; fok, isL: BOOLEAN;
  1770. lt, rt: SymTab.TypeIndex; qw: QbeGen.QVal;
  1771. BEGIN
  1772. IF AST.Kind(n) = AST.NkDesignator THEN
  1773. LowerDesign(n, t, k, q, qn, sfx);
  1774. IF k = SymTab.KindProc THEN
  1775. (* bare procedure used as a value: its code address *)
  1776. LowerProcAddr(qn, q);
  1777. RETURN
  1778. END;
  1779. (* Record value->address for VAR actuals, mirroring the grammar's
  1780. Design. AddrOfVal cannot rely on the grammar's notes: its ring
  1781. (256) wraps long before a whole-session emit finishes. *)
  1782. IF sfx THEN QbeGen.CopyOp(q, qaddr) ELSE QbeGen.AddrOf(qn, qaddr) END;
  1783. IF NOT asAddr THEN FinalLoad(t, sfx, q) END;
  1784. IF (k = SymTab.KindVar) OR (k = SymTab.KindParam)
  1785. OR (k = SymTab.KindField) THEN
  1786. QbeGen.NoteAddr(q, qaddr)
  1787. ELSIF sfx AND (t # SymTab.InvalidType)
  1788. AND ((SymTab.ClassOf(t) = SymTab.ClArray)
  1789. OR (SymTab.ClassOf(t) = SymTab.ClSet)
  1790. OR (SymTab.ClassOf(t) = SymTab.ClRecord)) THEN
  1791. QbeGen.NoteAddr(q, qaddr)
  1792. END;
  1793. RETURN
  1794. END;
  1795. k := -1; qn[0] := CHR(0); sfx := FALSE;
  1796. IF AST.Kind(n) = AST.NkIntLit THEN
  1797. Name(n, qn); QbeGen.NormInt(qn, q); t := SymTab.IntType()
  1798. ELSIF AST.Kind(n) = AST.NkCharLit THEN
  1799. Name(n, qn); QbeGen.NormLit(qn, q, isCh); t := SymTab.CharType()
  1800. ELSIF AST.Kind(n) = AST.NkRealLit THEN
  1801. Name(n, qn); QbeGen.NormReal(qn, q); t := SymTab.RealType()
  1802. ELSIF AST.Kind(n) = AST.NkStrLit THEN
  1803. Name(n, qn);
  1804. IF (qn[0] = "U") OR (qn[0] = "u") THEN
  1805. (* U"..." / U'...': one codepoint -> UCHAR, else a ustring *)
  1806. QbeGen.DeclUStr(qn, q, isU, ucp, uok);
  1807. IF NOT uok THEN
  1808. t := SymTab.InvalidType; QbeGen.CopyOp("0", q)
  1809. ELSIF isU THEN
  1810. t := SymTab.UCharType(); QbeGen.IntStr(ucp, q)
  1811. ELSE
  1812. t := AST.Ty(n); IF t = -1 THEN t := SymTab.NewUStr() END; QbeGen.NoteAddr(q, q)
  1813. END
  1814. ELSIF SymTab.StrLen(qn) = 3 THEN
  1815. t := SymTab.CharType(); QbeGen.IntStr(QbeGen.CharVal(qn), q)
  1816. ELSE
  1817. t := AST.Ty(n); IF t = -1 THEN t := SymTab.NewStr() END; QbeGen.DeclStr(qn, q); QbeGen.NoteAddr(q, q)
  1818. END
  1819. ELSIF AST.Kind(n) = AST.NkSetLit THEN
  1820. t := AST.Ty(n); IF t = -1 THEN t := SymTab.NewSet(SymTab.NewSubR(0, 255)) END;
  1821. QbeGen.NewSetTemp(8, q); QbeGen.SetZero(q, 8);
  1822. i := 0;
  1823. WHILE i < AST.NChild(n) DO
  1824. el := AST.Child(n, i);
  1825. IF AST.Kind(el) = AST.NkSubrange THEN
  1826. LowerExpr(AST.Child(el, 0), t2, q2);
  1827. LowerExpr(AST.Child(el, 1), t2, qt);
  1828. QbeGen.SetRange(q, q2, qt, SymTab.SetBaseLo(t), SymTab.SetCount(t))
  1829. ELSE
  1830. LowerExpr(el, t2, q2);
  1831. QbeGen.SetBit(q, q2, SymTab.SetBaseLo(t), SymTab.SetCount(t))
  1832. END;
  1833. INC(i)
  1834. END
  1835. ELSIF AST.Kind(n) = AST.NkBraceLit THEN
  1836. (* T{...} typed brace literal: a set here (the type was recorded by
  1837. the grammar in the node's ty field). Array/record/class
  1838. constructors are not lowered here yet. *)
  1839. t := AST.Ty(n);
  1840. IF (t # SymTab.InvalidType) AND (SymTab.ClassOf(t) = SymTab.ClSet) THEN
  1841. IF SymTab.SetWords(t) = 0 THEN
  1842. QbeGen.NewSetTemp(8, q); QbeGen.SetZero(q, 8)
  1843. ELSE
  1844. QbeGen.NewSetTemp(SymTab.SetWords(t), q);
  1845. QbeGen.SetZero(q, SymTab.SetWords(t))
  1846. END;
  1847. seq := n;
  1848. WHILE seq # AST.NoNode DO
  1849. i := 0;
  1850. WHILE i < AST.NChild(seq) DO
  1851. el := AST.Child(seq, i);
  1852. IF AST.Kind(el) # AST.NkBlock THEN
  1853. IF AST.Kind(el) = AST.NkSubrange THEN
  1854. LowerExpr(AST.Child(el, 0), t2, q2);
  1855. LowerExpr(AST.Child(el, 1), t2, qt);
  1856. QbeGen.SetRange(q, q2, qt, SymTab.SetBaseLo(t),
  1857. SymTab.SetCount(t))
  1858. ELSE
  1859. LowerExpr(el, t2, q2);
  1860. QbeGen.SetBit(q, q2, SymTab.SetBaseLo(t), SymTab.SetCount(t))
  1861. END
  1862. END;
  1863. INC(i)
  1864. END;
  1865. next := AST.NoNode;
  1866. IF AST.NChild(seq) > 0 THEN
  1867. next := AST.Child(seq, AST.NChild(seq) - 1);
  1868. IF AST.Kind(next) # AST.NkBlock THEN next := AST.NoNode END
  1869. END;
  1870. seq := next
  1871. END
  1872. ELSIF (t # SymTab.InvalidType)
  1873. AND ((SymTab.ClassOf(t) = SymTab.ClArray)
  1874. OR (SymTab.ClassOf(t) = SymTab.ClRecord)
  1875. OR (SymTab.ClassOf(t) = SymTab.ClClass)) THEN
  1876. (* T{...} aggregate constructor *)
  1877. QbeGen.CtorBegin(t);
  1878. seq := n;
  1879. WHILE seq # AST.NoNode DO
  1880. i := 0;
  1881. WHILE i < AST.NChild(seq) DO
  1882. el := AST.Child(seq, i);
  1883. IF AST.Kind(el) # AST.NkBlock THEN
  1884. LowerExpr(el, t2, q2);
  1885. QbeGen.CtorElem(q2)
  1886. END;
  1887. INC(i)
  1888. END;
  1889. next := AST.NoNode;
  1890. IF AST.NChild(seq) > 0 THEN
  1891. next := AST.Child(seq, AST.NChild(seq) - 1);
  1892. IF AST.Kind(next) # AST.NkBlock THEN next := AST.NoNode END
  1893. END;
  1894. seq := next
  1895. END;
  1896. QbeGen.CtorEnd(q)
  1897. ELSE
  1898. t := SymTab.InvalidType; QbeGen.CopyOp("0", q)
  1899. END
  1900. ELSIF AST.Kind(n) = AST.NkDesignator THEN
  1901. LowerDesign(n, t, k, q, qn, sfx)
  1902. ELSIF AST.Kind(n) = AST.NkCall THEN
  1903. IF IsMethodCall(n) THEN LowerMethodCall(n, t, q, TRUE)
  1904. ELSE
  1905. CalleeName(n, qn);
  1906. IF IsBuiltin(qn) THEN LowerBuiltinExpr(n, qn, t, q)
  1907. ELSE LowerCall(n, t, q, TRUE)
  1908. END
  1909. END
  1910. ELSIF AST.Kind(n) = AST.NkUnary THEN
  1911. LowerExpr(AST.Child(n, 0), t, q);
  1912. IF AST.Op(n) = AST.OpSub THEN
  1913. IF QbeGen.IsImm(q) THEN QbeGen.NegFold(q, q)
  1914. ELSE QbeGen.NewTemp(qt);
  1915. QbeGen.NegQ(q, qt, SymTab.ClassOf(t) = SymTab.ClReal);
  1916. QbeGen.CopyOp(qt, q)
  1917. END
  1918. ELSE
  1919. QbeGen.NotQ(q, qt); QbeGen.CopyOp(qt, q); t := SymTab.BoolType()
  1920. END
  1921. ELSIF AST.Kind(n) = AST.NkBinExpr THEN
  1922. op := AST.Op(n);
  1923. IF IsRel(op) THEN
  1924. LowerExpr(AST.Child(n, 0), t, q);
  1925. LowerExpr(AST.Child(n, 1), t2, q2);
  1926. rop := SymTab.OpEq; folded := RelSym(op, rop);
  1927. IF op = AST.OpIn THEN
  1928. QbeGen.InSet(q, q2, SymTab.SetBaseLo(t2), SymTab.SetCount(t2), qt);
  1929. t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
  1930. ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
  1931. OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN
  1932. QbeGen.CmpL(rop, q, q2, qt);
  1933. t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
  1934. ELSIF (SymTab.ClassOf(t) = SymTab.ClSet)
  1935. OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
  1936. QbeGen.CmpSet(rop, q, q2, SymTab.SetWords(t), SymTab.SetWords(t2), qt);
  1937. t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
  1938. ELSIF SymTab.StrCompat(t, t2) THEN
  1939. QbeGen.StrEq(rop, q, q2, qt);
  1940. t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
  1941. ELSIF SymTab.IsLongFamily(t) OR SymTab.IsLongFamily(t2) THEN
  1942. IF SymTab.IsIntFamily(t) THEN QbeGen.WidenLong(q, qf); QbeGen.CopyOp(qf, q) END;
  1943. IF SymTab.IsIntFamily(t2) THEN QbeGen.WidenLong(q2, qf); QbeGen.CopyOp(qf, q2) END;
  1944. QbeGen.CmpLong(rop, q, q2, qt);
  1945. t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
  1946. ELSE
  1947. isR := (t # SymTab.InvalidType) AND (SymTab.ClassOf(t) = SymTab.ClReal);
  1948. t := SymTab.BoolType();
  1949. QbeGen.Cmp(rop, q, q2, qt, isR);
  1950. QbeGen.CopyOp(qt, q)
  1951. END
  1952. ELSIF op = AST.OpAnd THEN
  1953. LowerExpr(AST.Child(n, 0), t, q);
  1954. QbeGen.DelayBegin;
  1955. LowerExpr(AST.Child(n, 1), t2, q2);
  1956. QbeGen.DelayEnd;
  1957. QbeGen.Slot4(qs);
  1958. QbeGen.NewLabel(lNext); QbeGen.NewLabel(lFalse); QbeGen.NewLabel(lDone);
  1959. QbeGen.Jnz(q, lNext, lFalse);
  1960. QbeGen.EmitLabel(lNext);
  1961. QbeGen.DelayFlush;
  1962. QbeGen.StoreW(qs, q2);
  1963. QbeGen.Jmp(lDone);
  1964. QbeGen.EmitLabel(lFalse);
  1965. QbeGen.StoreW(qs, "0");
  1966. QbeGen.Jmp(lDone);
  1967. QbeGen.EmitLabel(lDone);
  1968. QbeGen.LoadW(qs, qr);
  1969. QbeGen.CopyOp(qr, q);
  1970. t := SymTab.BoolType()
  1971. ELSIF op = AST.OpOr THEN
  1972. LowerExpr(AST.Child(n, 0), t, q);
  1973. QbeGen.DelayBegin;
  1974. LowerExpr(AST.Child(n, 1), t2, q2);
  1975. QbeGen.DelayEnd;
  1976. QbeGen.Slot4(qs);
  1977. QbeGen.NewLabel(lTrue); QbeGen.NewLabel(lNext); QbeGen.NewLabel(lDone);
  1978. QbeGen.Jnz(q, lTrue, lNext);
  1979. QbeGen.EmitLabel(lTrue);
  1980. QbeGen.StoreW(qs, "1");
  1981. QbeGen.Jmp(lDone);
  1982. QbeGen.EmitLabel(lNext);
  1983. QbeGen.DelayFlush;
  1984. QbeGen.StoreW(qs, q2);
  1985. QbeGen.Jmp(lDone);
  1986. QbeGen.EmitLabel(lDone);
  1987. QbeGen.LoadW(qs, qr);
  1988. QbeGen.CopyOp(qr, q);
  1989. t := SymTab.BoolType()
  1990. ELSE
  1991. LowerExpr(AST.Child(n, 0), t, q);
  1992. LowerExpr(AST.Child(n, 1), t2, q2);
  1993. IF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
  1994. AND (SymTab.ClassOf(t) = SymTab.ClSet)
  1995. AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
  1996. (* set union/diff (Add/Sub) or intersection/symdiff (Mul/Div) *)
  1997. lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
  1998. mw := lw; IF rw > mw THEN mw := rw END;
  1999. IF op = AST.OpAdd THEN idx := 0
  2000. ELSIF op = AST.OpSub THEN idx := 2
  2001. ELSIF op = AST.OpMul THEN idx := 1
  2002. ELSE idx := 3
  2003. END;
  2004. QbeGen.SetBinOp(idx, q, q2, lw, rw, qt);
  2005. t := SymTab.NewSet(SymTab.NewSubR(0, VAL(INTEGER, mw) * 32 - 1));
  2006. QbeGen.CopyOp(qt, q)
  2007. ELSIF (op = AST.OpAdd)
  2008. AND (SymTab.StrCompat(t, t2)
  2009. OR (SymTab.IsStrType(t) AND (SymTab.ClassOf(t2) = SymTab.ClChar))
  2010. OR ((SymTab.ClassOf(t) = SymTab.ClChar) AND SymTab.IsStrType(t2))) THEN
  2011. QbeGen.StrFold(q, q2, SymTab.ClassOf(t), SymTab.ClassOf(t2), qt, fok);
  2012. IF NOT fok THEN
  2013. IF SymTab.StrCompat(t, t2) THEN QbeGen.StrCat(q, q2, qt)
  2014. ELSIF SymTab.IsStrType(t) THEN
  2015. QbeGen.DeclCharStr(q2, qs); QbeGen.StrCat(q, qs, qt)
  2016. ELSE
  2017. QbeGen.DeclCharStr(q, qs); QbeGen.StrCat(qs, q2, qt)
  2018. END
  2019. END;
  2020. t := SymTab.NewStr(); QbeGen.CopyOp(qt, q)
  2021. ELSIF (op = AST.OpAdd)
  2022. AND (SymTab.UStrCompat(t, t2)
  2023. OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
  2024. AND (SymTab.ClassOf(t2) = SymTab.ClUStr))
  2025. OR ((SymTab.ClassOf(t) = SymTab.ClUStr)
  2026. AND (SymTab.ClassOf(t2) = SymTab.ClUChar))
  2027. OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
  2028. AND (SymTab.ClassOf(t2) = SymTab.ClUChar))) THEN
  2029. (* UString concatenation: a UCHAR operand becomes a
  2030. 1-codepoint UString; the result is a descriptor *)
  2031. IF SymTab.ClassOf(t) = SymTab.ClUStr THEN QbeGen.CopyOp(q, qa)
  2032. ELSE QbeGen.UStrFrom(q, qa)
  2033. END;
  2034. IF SymTab.ClassOf(t2) = SymTab.ClUStr THEN QbeGen.UStrCat(qa, q2, qt)
  2035. ELSE QbeGen.UStrFrom(q2, qb); QbeGen.UStrCat(qa, qb, qt)
  2036. END;
  2037. t := SymTab.NewUStr(); QbeGen.CopyOp(qt, q)
  2038. ELSE
  2039. lt := t; rt := t2;
  2040. IF (SymTab.ClassOf(lt) = SymTab.ClReal)
  2041. OR (SymTab.ClassOf(rt) = SymTab.ClReal) THEN
  2042. t := SymTab.RealType()
  2043. ELSIF SymTab.IsLongFamily(lt) OR SymTab.IsLongFamily(rt) THEN
  2044. t := SymTab.LongType()
  2045. ELSE t := SymTab.IntType()
  2046. END;
  2047. isL := SymTab.IsLongFamily(t);
  2048. isR := SymTab.ClassOf(t) = SymTab.ClReal;
  2049. kind := 0;
  2050. IF op = AST.OpSub THEN kind := 1
  2051. ELSIF op = AST.OpMul THEN kind := 2
  2052. ELSIF op = AST.OpDiv THEN kind := 3
  2053. ELSIF op = AST.OpMod THEN kind := 4
  2054. END;
  2055. folded := FALSE;
  2056. IF (NOT isL) AND (NOT isR) AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
  2057. folded := QbeGen.Fold2(kind, q, q2, qf)
  2058. END;
  2059. IF folded THEN QbeGen.CopyOp(qf, q)
  2060. ELSE
  2061. IF isL THEN
  2062. IF SymTab.IsIntFamily(lt) THEN
  2063. QbeGen.WidenLong(q, qw); QbeGen.CopyOp(qw, q)
  2064. END;
  2065. IF SymTab.IsIntFamily(rt) THEN
  2066. QbeGen.WidenLong(q2, qw); QbeGen.CopyOp(qw, q2)
  2067. END;
  2068. QbeGen.NewTemp(qt);
  2069. IF op = AST.OpAdd THEN QbeGen.Op3L("add", qt, q, q2)
  2070. ELSIF op = AST.OpSub THEN QbeGen.Op3L("sub", qt, q, q2)
  2071. ELSIF op = AST.OpMul THEN QbeGen.Op3L("mul", qt, q, q2)
  2072. ELSE QbeGen.Op3L("div", qt, q, q2)
  2073. END
  2074. ELSE
  2075. QbeGen.NewTemp(qt);
  2076. IF op = AST.OpAdd THEN QbeGen.Op3("add", qt, q, q2, isR)
  2077. ELSIF op = AST.OpSub THEN QbeGen.Op3("sub", qt, q, q2, isR)
  2078. ELSIF op = AST.OpMul THEN QbeGen.Op3("mul", qt, q, q2, isR)
  2079. ELSIF op = AST.OpDiv THEN QbeGen.Op3("div", qt, q, q2, isR)
  2080. ELSE QbeGen.Op3("rem", qt, q, q2, isR)
  2081. END
  2082. END;
  2083. QbeGen.CopyOp(qt, q)
  2084. END
  2085. END
  2086. END
  2087. END
  2088. END LowerExprFull;
  2089. PROCEDURE LowerExpr (n: AST.Node; VAR t: SymTab.TypeIndex;
  2090. VAR q: QbeGen.QVal);
  2091. VAR k: INTEGER; qn: SymTab.Name; sfx: BOOLEAN;
  2092. BEGIN
  2093. LowerExprFull(n, t, q, k, qn, sfx, FALSE)
  2094. END LowerExpr;
  2095. PROCEDURE LowerStmt (seq: AST.Node);
  2096. VAR i: CARDINAL; c, els, by: AST.Node; k: INTEGER;
  2097. t, t2, t3, dt, et: SymTab.TypeIndex;
  2098. q, q2, qt, qf, qd, qe: QbeGen.QVal;
  2099. qlo, qhi, qk, qb, ql, qby: QbeGen.QVal; step: INTEGER;
  2100. lTop, lBody, lEnd, lThen, lElse, lNext, lFalse, lDone, lx: QbeGen.QVal;
  2101. qn, lv: SymTab.Name;
  2102. kind, op, rop, cls: INTEGER;
  2103. sfx, folded, isR, conv, wconv, hasElse: BOOLEAN;
  2104. BEGIN
  2105. IF seq = AST.NoNode THEN RETURN END;
  2106. k := AST.Kind(seq);
  2107. IF k = AST.NkBlock THEN
  2108. i := 0;
  2109. WHILE i < AST.NChild(seq) DO
  2110. LowerStmt(AST.Child(seq, i)); INC(i)
  2111. END
  2112. ELSIF k = AST.NkAssign THEN
  2113. LowerDesign(AST.Child(seq, 0), dt, cls, qd, qn, sfx);
  2114. LowerExpr(AST.Child(seq, 1), et, qe);
  2115. isR := (dt # SymTab.InvalidType) AND (SymTab.ClassOf(dt) = SymTab.ClReal);
  2116. conv := isR AND SymTab.IsIntFamily(et);
  2117. wconv := (dt # SymTab.InvalidType) AND SymTab.IsLongFamily(dt)
  2118. AND SymTab.IsIntFamily(et);
  2119. IF sfx OR (cls = SymTab.KindField) THEN
  2120. IF SymTab.ClassOf(dt) = SymTab.ClArray THEN
  2121. IF (et # SymTab.InvalidType) AND (SymTab.ClassOf(et) = SymTab.ClUStr)
  2122. AND SymTab.IsUCharArray(dt) THEN QbeGen.UAssign(qd, qe)
  2123. ELSIF SymTab.StrCompat(dt, et) THEN QbeGen.StrAssign(qd, qe)
  2124. ELSE QbeGen.CopyArray(qd, qe, dt)
  2125. END
  2126. ELSIF SymTab.ClassOf(dt) = SymTab.ClSet THEN
  2127. QbeGen.CopySet(qd, qe, SymTab.SetWords(dt), SymTab.SetWords(et))
  2128. ELSIF SymTab.ClassOf(dt) = SymTab.ClRecord THEN
  2129. QbeGen.CopyRecord(qd, qe, dt)
  2130. ELSIF SymTab.IsLongFamily(dt) THEN
  2131. IF wconv THEN QbeGen.WidenLong(qe, ql); QbeGen.ElemStore(qd, ql, dt)
  2132. ELSE QbeGen.ElemStore(qd, qe, dt)
  2133. END
  2134. ELSIF conv THEN QbeGen.ConvIR(qe, qt); QbeGen.ElemStore(qd, qt, dt)
  2135. ELSE QbeGen.ElemStore(qd, qe, dt)
  2136. END
  2137. ELSE
  2138. IF SymTab.ClassOf(dt) = SymTab.ClArray THEN
  2139. IF (et # SymTab.InvalidType) AND (SymTab.ClassOf(et) = SymTab.ClUStr)
  2140. AND SymTab.IsUCharArray(dt) THEN QbeGen.UAssign(qd, qe)
  2141. ELSIF SymTab.StrCompat(dt, et) THEN QbeGen.StrAssign(qd, qe)
  2142. ELSE QbeGen.CopyArray(qd, qe, dt)
  2143. END
  2144. ELSIF SymTab.ClassOf(dt) = SymTab.ClSet THEN
  2145. QbeGen.CopySet(qd, qe, SymTab.SetWords(dt), SymTab.SetWords(et))
  2146. ELSIF SymTab.ClassOf(dt) = SymTab.ClRecord THEN
  2147. QbeGen.CopyRecord(qd, qe, dt)
  2148. ELSIF (SymTab.ClassOf(dt) = SymTab.ClPtr)
  2149. OR (SymTab.ClassOf(dt) = SymTab.ClProc) THEN
  2150. QbeGen.StorePtr(qn, qe)
  2151. ELSIF SymTab.IsLongFamily(dt) THEN
  2152. IF wconv THEN QbeGen.WidenLong(qe, ql); QbeGen.StoreLong(qn, ql)
  2153. ELSE QbeGen.StoreLong(qn, qe)
  2154. END
  2155. ELSIF conv THEN QbeGen.ConvIR(qe, qt); QbeGen.StoreVar(qn, qt, TRUE)
  2156. ELSE QbeGen.StoreVar(qn, qe, isR)
  2157. END
  2158. END
  2159. ELSIF k = AST.NkIf THEN
  2160. LowerExpr(AST.Child(seq, 0), t, q);
  2161. QbeGen.NewLabel(lThen); QbeGen.NewLabel(lElse); QbeGen.NewLabel(lEnd);
  2162. QbeGen.Jnz(q, lThen, lElse); QbeGen.EmitLabel(lThen);
  2163. LowerStmt(AST.Child(seq, 1));
  2164. QbeGen.Jmp(lEnd);
  2165. els := AST.Child(seq, 2); hasElse := FALSE;
  2166. WHILE (els # AST.NoNode) AND (AST.Kind(els) = AST.NkIf) DO
  2167. QbeGen.EmitLabel(lElse); QbeGen.NewLabel(lElse);
  2168. LowerExpr(AST.Child(els, 0), t, q);
  2169. QbeGen.NewLabel(lThen); QbeGen.Jnz(q, lThen, lElse);
  2170. QbeGen.EmitLabel(lThen);
  2171. LowerStmt(AST.Child(els, 1));
  2172. QbeGen.Jmp(lEnd);
  2173. els := AST.Child(els, 2)
  2174. END;
  2175. IF els # AST.NoNode THEN
  2176. QbeGen.EmitLabel(lElse); hasElse := TRUE; LowerStmt(els)
  2177. END;
  2178. IF hasElse THEN QbeGen.EmitLabel(lEnd)
  2179. ELSE QbeGen.EmitLabel(lElse); QbeGen.EmitLabel(lEnd)
  2180. END
  2181. ELSIF k = AST.NkWhile THEN
  2182. QbeGen.NewLabel(lTop); QbeGen.NewLabel(lBody); QbeGen.NewLabel(lEnd);
  2183. QbeGen.EmitLabel(lTop);
  2184. LowerExpr(AST.Child(seq, 0), t, q);
  2185. QbeGen.Jnz(q, lBody, lEnd); QbeGen.EmitLabel(lBody);
  2186. LowerStmt(AST.Child(seq, 1));
  2187. QbeGen.Jmp(lTop); QbeGen.EmitLabel(lEnd)
  2188. ELSIF k = AST.NkRepeat THEN
  2189. QbeGen.NewLabel(lTop); QbeGen.NewLabel(lEnd); QbeGen.EmitLabel(lTop);
  2190. LowerStmt(AST.Child(seq, 0));
  2191. LowerExpr(AST.Child(seq, 1), t, q);
  2192. QbeGen.Jnz(q, lEnd, lTop); QbeGen.EmitLabel(lEnd)
  2193. ELSIF k = AST.NkLoop THEN
  2194. QbeGen.NewLabel(lTop); QbeGen.NewLabel(lEnd);
  2195. QbeGen.PushLoop(lEnd); QbeGen.EmitLabel(lTop);
  2196. LowerStmt(AST.Child(seq, 0));
  2197. QbeGen.Jmp(lTop); QbeGen.PopLoop; QbeGen.EmitLabel(lEnd)
  2198. ELSIF k = AST.NkExit THEN
  2199. IF QbeGen.TopLoop(lx) THEN QbeGen.Jmp(lx) END
  2200. ELSIF k = AST.NkFor THEN
  2201. Name(AST.Child(seq, 0), lv);
  2202. LowerExpr(AST.Child(seq, 1), t, qlo);
  2203. LowerExpr(AST.Child(seq, 2), t2, qhi);
  2204. (* optional BY step: a constant, default +1; its sign also
  2205. selects the termination comparison *)
  2206. step := 1;
  2207. IF AST.Child(seq, 3) # AST.NoNode THEN
  2208. LowerExpr(AST.Child(seq, 3), t3, qby);
  2209. IF NOT SymTab.ConstInt(qby, step) THEN step := 1
  2210. ELSIF step = 0 THEN step := 1
  2211. END
  2212. END;
  2213. QbeGen.StoreVar(lv, qlo, FALSE);
  2214. QbeGen.NewLabel(lTop); QbeGen.NewLabel(lBody); QbeGen.NewLabel(lEnd);
  2215. QbeGen.EmitLabel(lTop);
  2216. QbeGen.LoadVar(lv, FALSE, qt);
  2217. QbeGen.NewTemp(qk);
  2218. IF step > 0 THEN QbeGen.Op3("cslew", qk, qt, qhi, FALSE)
  2219. ELSE QbeGen.Op3("csgew", qk, qt, qhi, FALSE)
  2220. END;
  2221. QbeGen.Jnz(qk, lBody, lEnd);
  2222. QbeGen.EmitLabel(lBody);
  2223. LowerStmt(AST.Child(seq, 4));
  2224. QbeGen.LoadVar(lv, FALSE, qt);
  2225. QbeGen.IntStr(step, qb);
  2226. QbeGen.NewTemp(qk);
  2227. QbeGen.Op3("add", qk, qt, qb, FALSE);
  2228. QbeGen.StoreVar(lv, qk, FALSE);
  2229. QbeGen.Jmp(lTop); QbeGen.EmitLabel(lEnd)
  2230. ELSIF k = AST.NkHalt THEN
  2231. IF AST.Child(seq, 0) # AST.NoNode THEN
  2232. LowerExpr(AST.Child(seq, 0), t, q) END;
  2233. QbeGen.HaltQ
  2234. ELSIF k = AST.NkGoto THEN
  2235. Name(AST.Child(seq, 0), qn);
  2236. UserLabel(qn, q);
  2237. QbeGen.Jmp(q)
  2238. ELSIF k = AST.NkLabel THEN
  2239. Name(AST.Child(seq, 0), qn);
  2240. UserLabel(qn, q);
  2241. QbeGen.EmitLabel(q)
  2242. ELSIF k = AST.NkReturn THEN
  2243. IF AST.Child(seq, 0) = AST.NoNode THEN
  2244. QbeGen.EmitRet(q, FALSE)
  2245. ELSE
  2246. LowerExpr(AST.Child(seq, 0), t, q);
  2247. IF (emitProc >= 0) AND (emitProc < VAL(INTEGER, nProcs))
  2248. AND CompositeRes(procRes[emitProc]) THEN
  2249. (* composite result: copy into the hidden destination *)
  2250. QbeGen.AddrOf("__res", qt);
  2251. IF SymTab.ClassOf(procRes[emitProc]) = SymTab.ClArray THEN
  2252. QbeGen.CopyArray(qt, q, procRes[emitProc])
  2253. ELSIF SymTab.ClassOf(procRes[emitProc]) = SymTab.ClSet THEN
  2254. QbeGen.CopySet(qt, q, SymTab.SetWords(procRes[emitProc]),
  2255. SymTab.SetWords(procRes[emitProc]))
  2256. ELSE QbeGen.CopyRecord(qt, q, procRes[emitProc])
  2257. END;
  2258. QbeGen.EmitRet("0", FALSE)
  2259. ELSE
  2260. conv := (SymTab.ClassOf(SymTab.CurRes()) = SymTab.ClReal)
  2261. AND SymTab.IsIntFamily(t);
  2262. IF conv THEN QbeGen.ConvIR(q, qt); QbeGen.EmitRet(qt, TRUE)
  2263. ELSE QbeGen.EmitRet(q, TRUE)
  2264. END
  2265. END
  2266. END
  2267. ELSIF k = AST.NkCase THEN LowerCase(seq)
  2268. ELSIF k = AST.NkWith THEN LowerWith(seq)
  2269. ELSIF k = AST.NkCall THEN
  2270. IF IsMethodCall(seq) THEN LowerMethodCall(seq, t, q, FALSE)
  2271. ELSE
  2272. CalleeName(seq, qn);
  2273. IF IsBuiltin(qn) THEN LowerBuiltinStmt(seq, qn)
  2274. ELSE LowerCall(seq, t, q, FALSE)
  2275. END
  2276. END
  2277. END
  2278. END LowerStmt;
  2279. PROCEDURE ReenterGlobals (seq: AST.Node);
  2280. (* Re-registers a nested module's non-exported globals in the enclosing
  2281. (still-open) module scope, so QbeGen.GlobalRef can resolve their
  2282. "<outer>_<name>" symbols after the nested scope has been popped. *)
  2283. VAR i, j: CARDINAL; c: AST.Node; nm: SymTab.Name; chunk, vn: AST.Node;
  2284. BEGIN
  2285. IF seq = AST.NoNode THEN RETURN END;
  2286. i := 0;
  2287. WHILE i < AST.NChild(seq) DO
  2288. c := AST.Child(seq, i);
  2289. IF i = AST.MaxChild - 1 THEN ReenterGlobals(c)
  2290. ELSIF AST.Kind(c) = AST.NkDeclSeq THEN ReenterGlobals(c)
  2291. ELSIF AST.Kind(c) = AST.NkVarDecl THEN
  2292. chunk := c;
  2293. WHILE chunk # AST.NoNode DO
  2294. j := 0;
  2295. WHILE j < AST.NChild(chunk) DO
  2296. vn := AST.Child(chunk, j);
  2297. IF AST.Kind(vn) = AST.NkIdent THEN
  2298. Name(vn, nm);
  2299. IF SymTab.ReenterModGlobal(nm, SymTab.KindVar, curUnitName) THEN
  2300. SymTab.SetSymType(nm, AST.Ty(c))
  2301. END
  2302. END;
  2303. INC(j)
  2304. END;
  2305. IF AST.NChild(chunk) > 0 THEN
  2306. vn := AST.Child(chunk, AST.NChild(chunk) - 1);
  2307. IF AST.Kind(vn) = AST.NkBlock THEN chunk := vn
  2308. ELSE chunk := AST.NoNode END
  2309. ELSE chunk := AST.NoNode END
  2310. END
  2311. ELSIF (AST.Kind(c) = AST.NkTypeDecl)
  2312. OR (AST.Kind(c) = AST.NkClassDecl) THEN
  2313. (* a nested module's TYPE/CLASS: re-register it so ObjectSize and
  2314. GlobalRef can resolve it after the nested scope is popped *)
  2315. IF AST.NChild(c) >= 1 THEN
  2316. Name(AST.Child(c, 0), nm);
  2317. IF SymTab.ReenterModGlobal(nm, SymTab.KindType, curUnitName) THEN
  2318. SymTab.SetSymType(nm, AST.Ty(c))
  2319. END
  2320. END
  2321. END;
  2322. INC(i)
  2323. END
  2324. END ReenterGlobals;
  2325. PROCEDURE EmitVarNames (c: AST.Node);
  2326. (* Emit DeclVar for each name of an NkVarDecl; the names are a chunked
  2327. sequence (AstAppend), so follow NkBlock continuations. *)
  2328. VAR j: CARDINAL; chunk, vn: AST.Node; nm: SymTab.Name;
  2329. BEGIN
  2330. chunk := c;
  2331. WHILE chunk # AST.NoNode DO
  2332. j := 0;
  2333. WHILE j < AST.NChild(chunk) DO
  2334. vn := AST.Child(chunk, j);
  2335. IF AST.Kind(vn) = AST.NkIdent THEN
  2336. Name(vn, nm);
  2337. QbeGen.DeclVar(nm, AST.Ty(c));
  2338. IF (NOT QbeGen.InFunction())
  2339. AND (SymTab.ClassOf(AST.Ty(c)) = SymTab.ClArray)
  2340. AND QbeGen.RecArrayNeedsInit(SymTab.ArrayLen(AST.Ty(c)),
  2341. AST.Ty(c))
  2342. AND (nCountInit <= HIGH(countArr)) THEN
  2343. QbeGen.DeclRecTemplate(nm, SymTab.ArrayElem(AST.Ty(c)));
  2344. countArr[nCountInit] := nm;
  2345. countTyp[nCountInit] := AST.Ty(c);
  2346. INC(nCountInit)
  2347. END
  2348. END;
  2349. INC(j)
  2350. END;
  2351. IF AST.NChild(chunk) > 0 THEN
  2352. vn := AST.Child(chunk, AST.NChild(chunk) - 1);
  2353. IF AST.Kind(vn) = AST.NkBlock THEN chunk := vn
  2354. ELSE chunk := AST.NoNode END
  2355. ELSE chunk := AST.NoNode END
  2356. END
  2357. END EmitVarNames;
  2358. PROCEDURE EmitCountInits;
  2359. (* Initialise the length words of record-array globals that were emitted
  2360. compactly (recorded by EmitVarNames). *)
  2361. VAR k: CARDINAL;
  2362. BEGIN
  2363. k := 0;
  2364. WHILE k < nCountInit DO
  2365. QbeGen.InitRecArray(countArr[k], countTyp[k]);
  2366. INC(k)
  2367. END
  2368. END EmitCountInits;
  2369. PROCEDURE LowerDecls (seq: AST.Node);
  2370. VAR i, j: CARDINAL; c: AST.Node; nm, txt: SymTab.Name; qv: QbeGen.QVal;
  2371. mg: QbeGen.QVal; uid, depth, np: CARDINAL; res, pt: SymTab.TypeIndex;
  2372. ext, pv: BOOLEAN; kk: INTEGER; ct: SymTab.TypeIndex; savedProc: INTEGER;
  2373. chunk, vn: AST.Node; pi: INTEGER;
  2374. mk: ARRAY [0 .. MaxCFoldW - 1] OF CARDINAL; mw: CARDINAL; mlo: INTEGER;
  2375. BEGIN
  2376. IF seq = AST.NoNode THEN RETURN END;
  2377. i := 0;
  2378. WHILE i < AST.NChild(seq) DO
  2379. c := AST.Child(seq, i);
  2380. IF i = AST.MaxChild - 1 THEN LowerDecls(c)
  2381. ELSIF AST.Kind(c) = AST.NkDeclSeq THEN LowerDecls(c)
  2382. ELSIF AST.Kind(c) = AST.NkClassDecl THEN
  2383. Name(AST.Child(c, 0), nm);
  2384. IF Resolve(nm, kk, ct) THEN
  2385. IF SymTab.ClassOf(ct) = SymTab.ClClass THEN
  2386. IF AST.Op(c) = 1 THEN
  2387. LowerMethods(AST.Child(c, 3), ct);
  2388. IF AST.Child(c, 2) # AST.NoNode THEN
  2389. QbeGen.BeginInit(nm);
  2390. LowerStmt(AST.Child(c, 2));
  2391. QbeGen.EndInit
  2392. END
  2393. ELSE
  2394. LowerMethodHeadings(AST.Child(c, 3), ct)
  2395. END
  2396. END
  2397. END
  2398. ELSIF AST.Kind(c) = AST.NkUnit THEN
  2399. Name(AST.Child(c, 0), nm);
  2400. ReenterGlobals(AST.Child(c, 1));
  2401. LowerDecls(AST.Child(c, 1));
  2402. IF AST.Child(c, 2) # AST.NoNode THEN
  2403. QbeGen.BeginInit(nm);
  2404. LowerStmt(AST.Child(c, 2));
  2405. QbeGen.EndInit
  2406. END
  2407. ELSIF AST.Kind(c) = AST.NkVarDecl THEN
  2408. (* op=1 marks a forward-typed global: emit it after the rest,
  2409. as the grammar's FlushPend does *)
  2410. IF AST.Op(c) # 1 THEN EmitVarNames(c) END
  2411. ELSIF AST.Kind(c) = AST.NkConstDecl THEN
  2412. Name(AST.Child(c, 0), nm);
  2413. kk := SymTab.ClassOf(AST.Ty(c));
  2414. IF kk = SymTab.ClSet THEN
  2415. (* SET CONST: static data from the mask the grammar computed *)
  2416. IF LookupSetMask(nm, mk, mw, mlo) THEN
  2417. QbeGen.PoolSet(mk, mw, qv); SetConstVal(nm, qv)
  2418. ELSE SetConstVal(nm, "0")
  2419. END
  2420. ELSIF (kk = SymTab.ClArray) OR (kk = SymTab.ClRecord)
  2421. OR (kk = SymTab.ClClass) OR (kk = SymTab.ClStr)
  2422. OR (kk = SymTab.ClUStr) THEN
  2423. (* aggregate/string CONST: re-emit the constructor/string so
  2424. its static data is produced (the grammar's CtorEnd/DeclStr
  2425. are suppressed under NoEmit), then refresh the value *)
  2426. LowerExpr(AST.Child(c, 1), ct, qv);
  2427. SetConstVal(nm, qv)
  2428. ELSIF GetConstVal(nm, qv) AND QbeGen.IsImm(qv) THEN
  2429. (* scalar: use the evaluated value recorded by NoteConstVal *)
  2430. QbeGen.DeclConst(nm, qv, AST.Ty(c))
  2431. END
  2432. ELSIF AST.Kind(c) = AST.NkProcDecl THEN
  2433. Name(AST.Child(c, 0), nm);
  2434. pi := AST.Ty(c); (* proc-table index recorded by NoteProcNode *)
  2435. IF (pi < 0) OR (pi >= VAL(INTEGER, nProcs)) THEN pi := FindProc(nm) END;
  2436. IF ProcInfoIdx(pi, uid, res, depth, ext, np) THEN
  2437. QbeGen.Mangled(nm, uid, mg);
  2438. QbeGen.BeginFunc(mg);
  2439. IF CompositeRes(res) THEN
  2440. IF NOT QbeGen.FuncParam("__res", TRUE, res) THEN END
  2441. END;
  2442. j := 0;
  2443. WHILE j < np DO
  2444. IF ParamInfoIdx(pi, j, pt, pv, txt) THEN
  2445. IF NOT QbeGen.FuncParam(txt, pv OR SymTab.IsOpenArray(pt), pt) THEN END
  2446. END;
  2447. INC(j)
  2448. END;
  2449. QbeGen.SetFuncRes(res);
  2450. IF AST.Child(c, 1) = AST.NoNode THEN
  2451. (* declaration-only (definition module): replay the heading *)
  2452. QbeGen.AbortFunc
  2453. ELSE
  2454. QbeGen.EndFuncHeader;
  2455. savedProc := emitProc;
  2456. emitProc := pi;
  2457. LowerDecls(AST.Child(c, 2));
  2458. nUserLab := 0;
  2459. LowerStmt(AST.Child(c, 1));
  2460. emitProc := savedProc;
  2461. QbeGen.EndFunc(res)
  2462. END
  2463. END
  2464. END;
  2465. INC(i)
  2466. END
  2467. END LowerDecls;
  2468. PROCEDURE MaterializeGlobals (unitName: ARRAY OF CHAR; decls: AST.Node);
  2469. (* Make a unit's module-level VAR/CONST visible in the (global) scope
  2470. Lower runs in at session end, so GlobalRef resolves "<unit>_<name>". *)
  2471. VAR i, j: CARDINAL; c: AST.Node; nm: SymTab.Name; chunk, vn: AST.Node;
  2472. BEGIN
  2473. IF decls = AST.NoNode THEN RETURN END;
  2474. i := 0;
  2475. WHILE i < AST.NChild(decls) DO
  2476. c := AST.Child(decls, i);
  2477. IF i = AST.MaxChild - 1 THEN MaterializeGlobals(unitName, c)
  2478. ELSIF AST.Kind(c) = AST.NkDeclSeq THEN MaterializeGlobals(unitName, c)
  2479. ELSIF (AST.Kind(c) = AST.NkVarDecl) OR (AST.Kind(c) = AST.NkConstDecl) THEN
  2480. chunk := c;
  2481. WHILE chunk # AST.NoNode DO
  2482. j := 0;
  2483. WHILE j < AST.NChild(chunk) DO
  2484. vn := AST.Child(chunk, j);
  2485. IF AST.Kind(vn) = AST.NkIdent THEN
  2486. Name(vn, nm);
  2487. IF NOT SymTab.MaterializeReplace(unitName, nm) THEN END
  2488. END;
  2489. INC(j)
  2490. END;
  2491. IF AST.NChild(chunk) > 0 THEN
  2492. vn := AST.Child(chunk, AST.NChild(chunk) - 1);
  2493. IF AST.Kind(vn) = AST.NkBlock THEN chunk := vn
  2494. ELSE chunk := AST.NoNode END
  2495. ELSE chunk := AST.NoNode END
  2496. END
  2497. ELSIF (AST.Kind(c) = AST.NkTypeDecl) OR (AST.Kind(c) = AST.NkClassDecl) THEN
  2498. IF AST.NChild(c) >= 1 THEN
  2499. Name(AST.Child(c, 0), nm);
  2500. IF NOT SymTab.MaterializeReplace(unitName, nm) THEN END
  2501. END
  2502. END;
  2503. INC(i)
  2504. END
  2505. END MaterializeGlobals;
  2506. PROCEDURE LowerDeferredVars (seq: AST.Node);
  2507. (* Emit the forward-typed globals (NkVarDecl op=1) after the rest of the
  2508. unit's declarations, matching the grammar's FlushPend ordering. *)
  2509. VAR i: CARDINAL; c: AST.Node;
  2510. BEGIN
  2511. IF seq = AST.NoNode THEN RETURN END;
  2512. i := 0;
  2513. WHILE i < AST.NChild(seq) DO
  2514. c := AST.Child(seq, i);
  2515. IF i = AST.MaxChild - 1 THEN LowerDeferredVars(c)
  2516. ELSIF AST.Kind(c) = AST.NkDeclSeq THEN LowerDeferredVars(c)
  2517. ELSIF (AST.Kind(c) = AST.NkVarDecl) AND (AST.Op(c) = 1) THEN
  2518. EmitVarNames(c)
  2519. END;
  2520. INC(i)
  2521. END
  2522. END LowerDeferredVars;
  2523. PROCEDURE LowerOneUnit (u: AST.Node; isProg: BOOLEAN);
  2524. VAR nm: SymTab.Name;
  2525. BEGIN
  2526. nCountInit := 0;
  2527. Name(AST.Child(u, 0), nm);
  2528. CopySpan(nm, curUnitName, 0, 0);
  2529. QbeGen.SetModule(nm);
  2530. MaterializeGlobals(nm, AST.Child(u, 1));
  2531. LowerDecls(AST.Child(u, 1));
  2532. LowerDeferredVars(AST.Child(u, 1));
  2533. IF isProg THEN
  2534. QbeGen.BeginBody;
  2535. EmitCountInits;
  2536. nUserLab := 0;
  2537. LowerStmt(AST.Child(u, 2))
  2538. ELSIF AST.Child(u, 2) # AST.NoNode THEN
  2539. QbeGen.BeginInit(nm);
  2540. EmitCountInits;
  2541. nUserLab := 0;
  2542. LowerStmt(AST.Child(u, 2));
  2543. QbeGen.EndInit
  2544. ELSIF nCountInit > 0 THEN
  2545. QbeGen.BeginInit(nm);
  2546. EmitCountInits;
  2547. QbeGen.EndInit
  2548. END
  2549. END LowerOneUnit;
  2550. PROCEDURE BeginSession (progName: ARRAY OF CHAR);
  2551. (* Per-unit Lower emission. The grammar still runs its inline emit while
  2552. parsing, but under NoEmit it only mutates QbeGen's counters (nothing
  2553. reaches the buffer). For each unit: BeginUnit snapshots the state
  2554. *before* parsing; after parsing, LowerUnitNow restores that snapshot
  2555. and lets Lower re-emit the unit from the same counter values the
  2556. legacy inline path would have used, so the image stays byte-identical.
  2557. EndSession writes the accumulated session image. *)
  2558. BEGIN
  2559. withTop := 0;
  2560. curImplCls := SymTab.InvalidType;
  2561. scopeTop := 0; curScopeProc := -1; emitProc := -1;
  2562. QbeGen.OpenModule(progName);
  2563. QbeGen.SetNoEmit(TRUE)
  2564. END BeginSession;
  2565. PROCEDURE BeginUnit;
  2566. (* Snapshot the pre-parse state so Lower can discard the grammar's
  2567. suppressed inline mutations for this unit. *)
  2568. BEGIN
  2569. nImps := 0;
  2570. QbeGen.SaveSession
  2571. END BeginUnit;
  2572. PROCEDURE LowerUnitNow (unit: AST.Node; isProg: BOOLEAN);
  2573. BEGIN
  2574. IF unit = AST.NoNode THEN RETURN END;
  2575. QbeGen.RestoreSession;
  2576. QbeGen.SetNoEmit(FALSE);
  2577. LowerOneUnit(unit, isProg);
  2578. QbeGen.SetNoEmit(TRUE)
  2579. END LowerUnitNow;
  2580. PROCEDURE EndSession;
  2581. BEGIN
  2582. QbeGen.SetNoEmit(FALSE);
  2583. QbeGen.EndModule(curUnitName)
  2584. END EndSession;
  2585. BEGIN
  2586. scopeTop := 0; curScopeProc := -1; emitProc := -1
  2587. END Lower.