QbeGen.mod 154 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107
  1. IMPLEMENTATION MODULE QbeGen;
  2. IMPORT FileIO, SymTab;
  3. VAR
  4. out : FileIO.File;
  5. opened : BOOLEAN;
  6. inBody : BOOLEAN;
  7. dead : BOOLEAN; (* TRUE past a terminator: next instruction opens
  8. an unreachable block with a fresh label, so
  9. the .ssa stays valid QBE (no dangling temps,
  10. no instruction outside a block). *)
  11. nTemp : CARDINAL;
  12. nLab : CARDINAL;
  13. loopTop : CARDINAL;
  14. loopSt : ARRAY [0 .. 15] OF QVal;
  15. nR : CARDINAL; (* non-zero REAL consts flushed at BeginBody *)
  16. rNames : ARRAY [0 .. 31] OF QVal;
  17. rVals : ARRAY [0 .. 31] OF QVal;
  18. nStr : CARDINAL; (* string-literal data counter *)
  19. strNams : ARRAY [0 .. 4095] OF QVal;
  20. strTexts : ARRAY [0 .. 4095] OF ARRAY [0 .. 255] OF CHAR;
  21. (* UString literals: decoded codepoints, recorded for EndModule. *)
  22. ustrN : CARDINAL;
  23. ustrNams : ARRAY [0 .. 255] OF QVal;
  24. ustrStart : ARRAY [0 .. 255] OF CARDINAL;
  25. ustrCount : ARRAY [0 .. 255] OF CARDINAL;
  26. ustrPool : ARRAY [0 .. 8191] OF INTEGER;
  27. ustrUsed : CARDINAL;
  28. (* array constructors: pooled static descriptors *)
  29. ctorN : CARDINAL;
  30. ctorNam : ARRAY [0 .. 255] OF QVal;
  31. ctorTxt : ARRAY [0 .. 255] OF ARRAY [0 .. 4095] OF CHAR;
  32. ctorUse : ARRAY [0 .. 255] OF BOOLEAN; (* FALSE once inlined as a field *)
  33. ctorTop : CARDINAL;
  34. ctorTyp : ARRAY [0 .. 7] OF INTEGER;
  35. ctorCnt : ARRAY [0 .. 7] OF CARDINAL;
  36. ctorBuf : ARRAY [0 .. 7] OF ARRAY [0 .. 4095] OF CHAR;
  37. ctorEv : ARRAY [0 .. 7] OF ARRAY [0 .. 255] OF QVal;
  38. ctorEk : ARRAY [0 .. 7] OF ARRAY [0 .. 255] OF INTEGER;
  39. (* compile-time set constants: pooled static masks (Lower's PoolSet) *)
  40. setN : CARDINAL;
  41. setNam : ARRAY [0 .. 255] OF QVal; (* "setN" (no $) *)
  42. setW : ARRAY [0 .. 255] OF CARDINAL; (* words per entry *)
  43. setMask : ARRAY [0 .. 255] OF ARRAY [0 .. 15] OF CARDINAL;
  44. withTop : CARDINAL;
  45. withSt : ARRAY [0 .. 7] OF QVal;
  46. noEmit : BOOLEAN; (* TRUE while parsing nested procedures in 4.1:
  47. SymTab tracks, QbeGen suppresses output *)
  48. inFunc : BOOLEAN; (* TRUE inside an emitted function body *)
  49. useStack : BOOLEAN;(* TRUE: NewHeap allocates stack slots *)
  50. funcRes : CHAR; (* current function result class *)
  51. nLoc : CARDINAL; (* function-local name table entries *)
  52. locNames : ARRAY [0 .. 255] OF SymTab.Name;
  53. locTag : ARRAY [0 .. 255] OF INTEGER; (* 0 slot, 1 data, 2 addr *)
  54. locRep : ARRAY [0 .. 255] OF QVal; (* slot temp / mangled / addr *)
  55. locCls : ARRAY [0 .. 255] OF CHAR;
  56. locTyp : ARRAY [0 .. 255] OF INTEGER;
  57. funcDepth : CARDINAL; (* open BeginFuncs; main body = 0 *)
  58. excHas : ARRAY [0 .. 16] OF BOOLEAN;
  59. excBodyL, excHandlerL, excAfterL : ARRAY [0 .. 16] OF QVal;
  60. scopeTop : CARDINAL; (* open procedure scopes *)
  61. scopeBase : ARRAY [0 .. 16] OF CARDINAL;
  62. scopeLink : ARRAY [0 .. 15] OF QVal; (* per-scope link records *)
  63. slTmp : QVal; (* current static-link param temp *)
  64. hdrComma : BOOLEAN;
  65. stkLink : ARRAY [0 .. 15] OF QVal; (* per-call static links *)
  66. stkExt : ARRAY [0 .. 15] OF BOOLEAN; (* per-call external flag *)
  67. stkInd : ARRAY [0 .. 15] OF BOOLEAN; (* per-call indirect flag *)
  68. outSel : CARDINAL; (* 0 = file, else nestBufs[outSel-1] *)
  69. nInit : CARDINAL;
  70. initNames : ARRAY [0 .. 31] OF QVal;
  71. nExtInit : CARDINAL;
  72. extInitNames : ARRAY [0 .. 31] OF QVal;
  73. programMode : BOOLEAN; (* separate objects: FALSE emits no main *)
  74. separateMode : BOOLEAN; (* per-object mode (no def code, empty inits) *)
  75. nFini : CARDINAL;
  76. finiNames : ARRAY [0 .. 31] OF QVal;
  77. sessBuf : ARRAY [0 .. 8388607] OF CHAR; (* whole image, buffered (8 MiB:
  78. must hold the compiler's own
  79. image text when self-hosting) *)
  80. sessUsed : CARDINAL;
  81. nestBufs : ARRAY [0 .. 15] OF ARRAY [0 .. 131071] OF CHAR;
  82. nestUsed : ARRAY [0 .. 15] OF CARDINAL;
  83. (* Short-circuit AND/OR: the RHS operand's code is buffered here
  84. (delayTop > 0) and replayed inside the branch. *)
  85. delayBuf : ARRAY [0 .. 15] OF ARRAY [0 .. 8191] OF CHAR;
  86. delayUsed : ARRAY [0 .. 15] OF CARDINAL;
  87. delayTop : CARDINAL;
  88. (* one buffer per nesting depth: each nested function stays
  89. contiguous no matter how deep the parse interleaves *)
  90. nPar : CARDINAL; (* recorded formal params for the header *)
  91. parCls : ARRAY [0 .. 63] OF CHAR;
  92. parTmp : ARRAY [0 .. 63] OF QVal;
  93. parNam : ARRAY [0 .. 63] OF SymTab.Name;
  94. parVar : ARRAY [0 .. 63] OF BOOLEAN;
  95. parTyp : ARRAY [0 .. 63] OF INTEGER;
  96. argBuf : ARRAY [0 .. 4095] OF CHAR; (* accumulated call args *)
  97. hbuf : ARRAY [0 .. 2047] OF CHAR; (* buffered function header *)
  98. nArg : CARDINAL;
  99. recvQ : QVal; (* armed class-method receiver *)
  100. recvArmed : BOOLEAN;
  101. callDepth : CARDINAL; (* nested-call stack *)
  102. stkName : ARRAY [0 .. 15] OF QVal;
  103. stkRes : ARRAY [0 .. 15] OF CHAR;
  104. stkArg : ARRAY [0 .. 15] OF ARRAY [0 .. 1023] OF CHAR;
  105. stkN : ARRAY [0 .. 15] OF CARDINAL;
  106. funcName : QVal; (* current function / call target *)
  107. curModName : SymTab.Name; (* module being compiled (global names) *)
  108. outName : SymTab.Name; (* image-file override (Lower compare) *)
  109. hasOutName : BOOLEAN;
  110. nVal : ARRAY [0 .. 255] OF QVal; (* VAR-actual note keys *)
  111. nAddr : ARRAY [0 .. 255] OF QVal; (* VAR-actual note addresses *)
  112. nn : CARDINAL;
  113. (* Session-state snapshot: Lower runs per unit while the grammar's
  114. suppressed inline emit still mutates these, so Lower saves/restores
  115. its own values around each unit. *)
  116. sav_nTemp, sav_nLab, sav_loopTop, sav_nR, sav_nStr, sav_nLoc,
  117. sav_nPar, sav_nArg, sav_nn, sav_nInit, sav_nFini, sav_sessUsed, sav_delayTop,
  118. sav_ustrN, sav_ustrUsed, sav_ctorN, sav_ctorTop, sav_funcDepth,
  119. sav_scopeTop, sav_callDepth, sav_outSel, sav_withTop,
  120. sav_setN : CARDINAL;
  121. sav_inBody, sav_inFunc, sav_useStack, sav_recvArmed : BOOLEAN;
  122. PROCEDURE SaveSession;
  123. BEGIN
  124. sav_nTemp := nTemp; sav_nLab := nLab; sav_loopTop := loopTop;
  125. sav_nR := nR; sav_nStr := nStr; sav_nLoc := nLoc; sav_nPar := nPar;
  126. sav_nArg := nArg; sav_nn := nn; sav_nInit := nInit;
  127. sav_nFini := nFini;
  128. sav_sessUsed := sessUsed; sav_delayTop := delayTop;
  129. sav_ustrN := ustrN; sav_ustrUsed := ustrUsed;
  130. sav_ctorN := ctorN; sav_ctorTop := ctorTop;
  131. sav_setN := setN;
  132. sav_funcDepth := funcDepth; sav_scopeTop := scopeTop;
  133. sav_callDepth := callDepth; sav_outSel := outSel;
  134. sav_withTop := withTop;
  135. sav_inBody := inBody; sav_inFunc := inFunc;
  136. sav_useStack := useStack; sav_recvArmed := recvArmed
  137. END SaveSession;
  138. PROCEDURE RestoreSession;
  139. VAR i : CARDINAL;
  140. BEGIN
  141. nTemp := sav_nTemp; nLab := sav_nLab; loopTop := sav_loopTop;
  142. nR := sav_nR; nStr := sav_nStr; nLoc := sav_nLoc; nPar := sav_nPar;
  143. nArg := sav_nArg; nInit := sav_nInit; nFini := sav_nFini;
  144. sessUsed := sav_sessUsed; delayTop := sav_delayTop;
  145. ustrN := sav_ustrN; ustrUsed := sav_ustrUsed;
  146. ctorN := sav_ctorN; ctorTop := sav_ctorTop;
  147. setN := sav_setN;
  148. funcDepth := sav_funcDepth; scopeTop := sav_scopeTop;
  149. callDepth := sav_callDepth; outSel := sav_outSel;
  150. withTop := sav_withTop;
  151. inBody := sav_inBody; inFunc := sav_inFunc;
  152. useStack := sav_useStack; recvArmed := sav_recvArmed;
  153. (* Clear the VAR-actual note ring. The grammar's suppressed
  154. parse-time emit never reaches the buffer, but its NoteAddr calls
  155. do fill this ring; AddrOfVal scans the whole ring and the keys
  156. are temps that restart per function, so a stale grammar entry can
  157. false-match Lower's own key. Lower re-notes its own VAR
  158. actuals, so starting from an empty ring is correct. *)
  159. nn := 0;
  160. i := 0;
  161. WHILE i <= HIGH(nVal) DO
  162. nVal[i][0] := CHR(0); nAddr[i][0] := CHR(0); INC(i)
  163. END
  164. END RestoreSession;
  165. (* ---------------- small string utilities ---------------- *)
  166. PROCEDURE Len (s: ARRAY OF CHAR): CARDINAL;
  167. VAR i : CARDINAL;
  168. BEGIN
  169. i := 0;
  170. WHILE (i <= HIGH(s)) AND (s[i] # CHR(0)) DO INC(i) END;
  171. RETURN i
  172. END Len;
  173. PROCEDURE Cpy (VAR d: ARRAY OF CHAR; s: ARRAY OF CHAR);
  174. VAR i : CARDINAL;
  175. BEGIN
  176. i := 0;
  177. WHILE (i <= HIGH(d)) AND (i <= HIGH(s)) AND (s[i] # CHR(0)) DO
  178. d[i] := s[i]; INC(i)
  179. END;
  180. IF i <= HIGH(d) THEN d[i] := CHR(0) END
  181. END Cpy;
  182. PROCEDURE App (VAR d: ARRAY OF CHAR; s: ARRAY OF CHAR);
  183. VAR i, j : CARDINAL;
  184. BEGIN
  185. i := 0;
  186. WHILE (i <= HIGH(d)) AND (d[i] # CHR(0)) DO INC(i) END;
  187. j := 0;
  188. WHILE (i <= HIGH(d)) AND (j <= HIGH(s)) AND (s[j] # CHR(0)) DO
  189. d[i] := s[j]; INC(i); INC(j)
  190. END;
  191. IF i <= HIGH(d) THEN d[i] := CHR(0) END
  192. END App;
  193. PROCEDURE BufApp (VAR buf: ARRAY OF CHAR; VAR used: CARDINAL;
  194. s: ARRAY OF CHAR; eol: BOOLEAN);
  195. VAR j : CARDINAL;
  196. BEGIN
  197. j := 0;
  198. WHILE (used < HIGH(buf)) AND (j <= HIGH(s)) AND (s[j] # CHR(0)) DO
  199. buf[used] := s[j]; INC(used); INC(j)
  200. END;
  201. IF eol AND (used < HIGH(buf)) THEN
  202. buf[used] := CHR(10); INC(used)
  203. END;
  204. IF used <= HIGH(buf) THEN buf[used] := CHR(0) END
  205. END BufApp;
  206. PROCEDURE WEmit (s: ARRAY OF CHAR; eol: BOOLEAN);
  207. (* Single output sink: the session buffer, or a nesting-depth
  208. buffer for nested functions (QBE rejects definitions inside
  209. functions, so nested bodies hoist until EndModule). *)
  210. VAR b, u, j : CARDINAL;
  211. BEGIN
  212. IF NOT opened OR noEmit THEN RETURN END;
  213. IF delayTop > 0 THEN
  214. b := delayTop - 1;
  215. u := delayUsed[b]; j := 0;
  216. WHILE (u < HIGH(delayBuf[b])) AND (j <= HIGH(s))
  217. AND (s[j] # CHR(0)) DO
  218. delayBuf[b][u] := s[j]; INC(u); INC(j)
  219. END;
  220. IF eol AND (u < HIGH(delayBuf[b])) THEN
  221. delayBuf[b][u] := CHR(10); INC(u)
  222. END;
  223. IF u <= HIGH(delayBuf[b]) THEN delayBuf[b][u] := CHR(0) END;
  224. delayUsed[b] := u;
  225. RETURN
  226. END;
  227. IF outSel = 0 THEN
  228. BufApp(sessBuf, sessUsed, s, eol);
  229. RETURN
  230. END;
  231. b := outSel - 1;
  232. IF b > HIGH(nestBufs) THEN b := HIGH(nestBufs) END;
  233. u := nestUsed[b];
  234. j := 0;
  235. WHILE (u < HIGH(nestBufs[b])) AND (j <= HIGH(s)) AND (s[j] # CHR(0)) DO
  236. nestBufs[b][u] := s[j]; INC(u); INC(j)
  237. END;
  238. IF eol AND (u < HIGH(nestBufs[b])) THEN
  239. nestBufs[b][u] := CHR(10); INC(u)
  240. END;
  241. IF u <= HIGH(nestBufs[b]) THEN nestBufs[b][u] := CHR(0) END;
  242. nestUsed[b] := u
  243. END WEmit;
  244. PROCEDURE W (s: ARRAY OF CHAR);
  245. BEGIN
  246. WEmit(s, FALSE)
  247. END W;
  248. PROCEDURE WL (s: ARRAY OF CHAR);
  249. BEGIN
  250. WEmit(s, TRUE)
  251. END WL;
  252. PROCEDURE SetNoEmit (b: BOOLEAN);
  253. BEGIN
  254. noEmit := b
  255. END SetNoEmit;
  256. PROCEDURE DelayBegin;
  257. (* Start buffering output (the RHS operand of a short-circuit AND/OR). *)
  258. BEGIN
  259. IF delayTop <= HIGH(delayBuf) THEN
  260. delayUsed[delayTop] := 0;
  261. delayBuf[delayTop][0] := CHR(0);
  262. INC(delayTop)
  263. END
  264. END DelayBegin;
  265. PROCEDURE DelayEnd;
  266. (* Stop buffering (restore the previous output sink). *)
  267. BEGIN
  268. IF delayTop > 0 THEN DEC(delayTop) END
  269. END DelayEnd;
  270. PROCEDURE DelayFlush;
  271. (* Emit the buffered RHS operand's code into the current sink.
  272. DelayEnd already popped delayTop, so the just-used buffer index is
  273. delayTop itself. *)
  274. VAR b: CARDINAL;
  275. BEGIN
  276. b := delayTop;
  277. IF b <= HIGH(delayBuf) THEN WEmit(delayBuf[b], FALSE) END
  278. END DelayFlush;
  279. PROCEDURE Slot4 (VAR s: QVal);
  280. BEGIN
  281. NewTemp(s);
  282. Revive;
  283. W(" "); W(s); W(" =l alloc4 4"); WL("")
  284. END Slot4;
  285. PROCEDURE StoreW (slot: ARRAY OF CHAR; val: ARRAY OF CHAR);
  286. BEGIN
  287. Revive;
  288. W(" storew "); W(val); W(", "); WL(slot)
  289. END StoreW;
  290. PROCEDURE LoadW (slot: ARRAY OF CHAR; VAR q: QVal);
  291. BEGIN
  292. NewTemp(q);
  293. Revive;
  294. W(" "); W(q); W(" =w loadw "); WL(slot)
  295. END LoadW;
  296. PROCEDURE SetModule (name: ARRAY OF CHAR);
  297. (* Names the module whose globals are being emitted (QBE symbols
  298. become "<mod>_<name>" so separate modules never collide). *)
  299. BEGIN
  300. Cpy(curModName, name)
  301. END SetModule;
  302. PROCEDURE SetProgramMode (isProgram: BOOLEAN);
  303. (* Separate compilation: FALSE makes EndModule emit a library object
  304. (no main, no ExitCode return); TRUE keeps the program image. *)
  305. BEGIN
  306. programMode := isProgram
  307. END SetProgramMode;
  308. PROCEDURE SetSeparateMode (b: BOOLEAN);
  309. (* TRUE for M2 -c: Lower emits an empty init for bodyless modules and
  310. the driver skips lowering definition units. *)
  311. BEGIN
  312. separateMode := b
  313. END SetSeparateMode;
  314. PROCEDURE NoteExternalInit (mod: ARRAY OF CHAR);
  315. (* Program object: call an imported module's <mod>_init before the
  316. target module's init. The driver adds one per imported DEFINITION. *)
  317. VAR sym : QVal;
  318. BEGIN
  319. IF nExtInit > HIGH(extInitNames) THEN RETURN END;
  320. Cpy(sym, mod);
  321. App(sym, "_init");
  322. Cpy(extInitNames[nExtInit], sym);
  323. INC(nExtInit)
  324. END NoteExternalInit;
  325. PROCEDURE SymRef (name: ARRAY OF CHAR; VAR ref: QVal);
  326. (* "$<mod>_<sym>" for module-level entries (avoids cross-module
  327. collisions); "$<name>" fallback otherwise. *)
  328. VAR g : SymTab.Name;
  329. BEGIN
  330. Cpy(ref, "$");
  331. IF SymTab.GlobalRef(name, g) THEN App(ref, g)
  332. ELSE App(ref, name)
  333. END
  334. END SymRef;
  335. PROCEDURE Wc (c: CHAR);
  336. (* Writes a single class character (w/d/l). *)
  337. VAR s : ARRAY [0 .. 1] OF CHAR;
  338. BEGIN
  339. s[0] := c; s[1] := CHR(0);
  340. W(s)
  341. END Wc;
  342. PROCEDURE AppNum (VAR d: ARRAY OF CHAR; v: CARDINAL);
  343. (* Appends v in decimal to d. *)
  344. VAR buf : ARRAY [0 .. 15] OF CHAR;
  345. n, i, L : CARDINAL;
  346. BEGIN
  347. n := 0;
  348. IF v = 0 THEN buf[0] := "0"; n := 1 END;
  349. WHILE (v > 0) AND (n <= HIGH(buf)) DO
  350. buf[n] := CHR(ORD("0") + v MOD 10); v := v DIV 10; INC(n)
  351. END;
  352. i := n;
  353. WHILE i > 0 DO
  354. DEC(i);
  355. L := Len(d);
  356. IF L < HIGH(d) THEN d[L] := buf[i]; d[L + 1] := CHR(0) END
  357. END
  358. END AppNum;
  359. (* ---------------- exported helpers ---------------- *)
  360. PROCEDURE CopyOp (s: ARRAY OF CHAR; VAR d: ARRAY OF CHAR);
  361. BEGIN
  362. Cpy(d, s)
  363. END CopyOp;
  364. PROCEDURE NoteAddr (val: ARRAY OF CHAR; addr: ARRAY OF CHAR);
  365. (* Records value-temp → address mapping for VAR actuals. Ring of
  366. 256: safe because SSA temps are never reused (stale entries can
  367. never false-match, only age out on pathological expressions). *)
  368. BEGIN
  369. Cpy(nVal[nn], val);
  370. Cpy(nAddr[nn], addr);
  371. nn := nn + 1;
  372. IF nn > HIGH(nVal) THEN nn := 0 END
  373. END NoteAddr;
  374. PROCEDURE AddrOfVal (val: ARRAY OF CHAR; VAR addr: QVal): BOOLEAN;
  375. VAR i : CARDINAL;
  376. BEGIN
  377. i := 0;
  378. WHILE i <= HIGH(nVal) DO
  379. IF SymTab.Equal(nVal[i], val) THEN
  380. Cpy(addr, nAddr[i]);
  381. RETURN TRUE
  382. END;
  383. INC(i)
  384. END;
  385. RETURN FALSE
  386. END AddrOfVal;
  387. PROCEDURE AddrOf (name: ARRAY OF CHAR; VAR q: QVal);
  388. VAR idx : INTEGER;
  389. levels : CARDINAL;
  390. BEGIN
  391. IF LocFindUp(name, levels, idx) THEN
  392. IF levels = 0 THEN
  393. IF locTag[idx] = 1 THEN
  394. Cpy(q, "$");
  395. App(q, locRep[idx])
  396. ELSE
  397. Cpy(q, locRep[idx])
  398. END
  399. ELSE
  400. UpAddrOf(idx, levels, q)
  401. END;
  402. RETURN
  403. END;
  404. SymRef(name, q)
  405. END AddrOf;
  406. PROCEDURE IntStr (v: INTEGER; VAR s: QVal);
  407. VAR neg : BOOLEAN;
  408. mag : CARDINAL;
  409. buf : ARRAY [0 .. 15] OF CHAR;
  410. n, i, L : CARDINAL;
  411. t : CHAR;
  412. BEGIN
  413. neg := v < 0;
  414. IF neg THEN mag := VAL(CARDINAL, -v) ELSE mag := VAL(CARDINAL, v) END;
  415. n := 0;
  416. IF mag = 0 THEN buf[0] := "0"; n := 1 END;
  417. WHILE (mag > 0) AND (n < HIGH(buf)) DO
  418. buf[n] := CHR(ORD("0") + mag MOD 10); mag := mag DIV 10; INC(n)
  419. END;
  420. i := 0;
  421. WHILE i < n DIV 2 DO
  422. t := buf[i]; buf[i] := buf[n - 1 - i]; buf[n - 1 - i] := t; INC(i)
  423. END;
  424. s[0] := CHR(0);
  425. IF neg THEN App(s, "-") END;
  426. i := 0;
  427. WHILE i < n DO
  428. L := Len(s);
  429. IF L < HIGH(s) THEN s[L] := buf[i]; s[L + 1] := CHR(0) END;
  430. INC(i)
  431. END
  432. END IntStr;
  433. PROCEDURE HexVal (ch: CHAR): INTEGER;
  434. BEGIN
  435. IF (ch >= "0") AND (ch <= "9") THEN RETURN ORD(ch) - ORD("0") END;
  436. IF (ch >= "A") AND (ch <= "F") THEN RETURN ORD(ch) - ORD("A") + 10 END;
  437. IF (ch >= "a") AND (ch <= "f") THEN RETURN ORD(ch) - ORD("a") + 10 END;
  438. RETURN 0
  439. END HexVal;
  440. PROCEDURE NormInt (s: ARRAY OF CHAR; VAR d: QVal);
  441. (* "0xFF" -> "255", plain decimals are copied through. *)
  442. VAR n, i : CARDINAL;
  443. v : INTEGER;
  444. BEGIN
  445. n := Len(s);
  446. IF (n > 2) AND (s[0] = "0")
  447. AND ((s[1] = "x") OR (s[1] = "X")) THEN
  448. v := 0; i := 2;
  449. WHILE i < n DO v := v * 16 + HexVal(s[i]); INC(i) END;
  450. IntStr(v, d)
  451. ELSE
  452. Cpy(d, s)
  453. END
  454. END NormInt;
  455. PROCEDURE NormLit (s: ARRAY OF CHAR; VAR d: QVal; VAR isCh: BOOLEAN);
  456. (* Full V3 integer literal: octal B/b, hex H/h and C/c suffixes plus
  457. the 0x/0X prefix; C marks a character constant. The suffix letter
  458. is excluded from the digit run (HexVal would read 'B' as 11).
  459. A 0x/0X prefix takes priority over any trailing B/C/H (C-style
  460. hex digits, so 0xB is 11, never an octal suffix). *)
  461. VAR n, i, hi, base : CARDINAL;
  462. v : INTEGER;
  463. ch : CHAR;
  464. BEGIN
  465. n := Len(s);
  466. isCh := FALSE;
  467. IF n = 0 THEN Cpy(d, "0"); RETURN END;
  468. i := 0;
  469. IF (n >= 3) AND (s[0] = "0") AND ((s[1] = "x") OR (s[1] = "X")) THEN
  470. base := 16; hi := n; i := 2
  471. ELSE
  472. ch := s[n - 1];
  473. IF (ch = "B") OR (ch = "b") THEN
  474. base := 8; hi := n - 1
  475. ELSIF (ch = "H") OR (ch = "h") THEN
  476. base := 16; hi := n - 1
  477. ELSIF (ch = "C") OR (ch = "c") THEN
  478. base := 16; hi := n - 1; isCh := TRUE
  479. ELSE
  480. base := 10; hi := n
  481. END
  482. END;
  483. v := 0;
  484. WHILE i < hi DO
  485. v := v * VAL(INTEGER, base) + HexVal(s[i]); INC(i)
  486. END;
  487. IntStr(v, d)
  488. END NormLit;
  489. PROCEDURE NormReal (s: ARRAY OF CHAR; VAR d: QVal);
  490. (* "3.14" -> "d_3.14" (QBE double immediates carry a d_ prefix). *)
  491. BEGIN
  492. Cpy(d, "d_");
  493. App(d, s)
  494. END NormReal;
  495. PROCEDURE CharVal (s: ARRAY OF CHAR): INTEGER;
  496. BEGIN
  497. IF Len(s) >= 2 THEN RETURN ORD(s[1]) END;
  498. RETURN 0
  499. END CharVal;
  500. PROCEDURE NegFold (a: ARRAY OF CHAR; VAR q: QVal);
  501. (* Safe for a and q being the same variable. *)
  502. VAR i, j, L : CARDINAL;
  503. tmp : QVal;
  504. BEGIN
  505. Cpy(tmp, a);
  506. IF Len(tmp) = 0 THEN Cpy(q, "0"); RETURN END;
  507. IF tmp[0] = "-" THEN
  508. i := 1; j := 0;
  509. WHILE (tmp[i] # CHR(0)) AND (j < HIGH(q)) DO
  510. q[j] := tmp[i]; INC(i); INC(j)
  511. END;
  512. IF j <= HIGH(q) THEN q[j] := CHR(0) END
  513. ELSIF (tmp[0] = "d") AND (Len(tmp) > 1) AND (tmp[1] = "_") THEN
  514. Cpy(q, "d_-");
  515. i := 2;
  516. WHILE tmp[i] # CHR(0) DO
  517. L := Len(q);
  518. IF L < HIGH(q) THEN q[L] := tmp[i]; q[L + 1] := CHR(0) END;
  519. INC(i)
  520. END
  521. ELSE
  522. Cpy(q, "-");
  523. App(q, tmp)
  524. END
  525. END NegFold;
  526. PROCEDURE IsImm (s: ARRAY OF CHAR): BOOLEAN;
  527. BEGIN
  528. IF Len(s) = 0 THEN RETURN FALSE END;
  529. RETURN ((s[0] >= "0") AND (s[0] <= "9")) OR (s[0] = "-")
  530. OR (s[0] = "d")
  531. END IsImm;
  532. PROCEDURE ParseInt (s: ARRAY OF CHAR; VAR v: INTEGER): BOOLEAN;
  533. VAR i, nd, d: CARDINAL;
  534. neg: BOOLEAN;
  535. BEGIN
  536. v := 0; i := 0; neg := FALSE; nd := 0;
  537. IF (i <= HIGH(s)) AND (s[i] = "-") THEN neg := TRUE; INC(i) END;
  538. IF (i > HIGH(s)) OR (s[i] = CHR(0)) THEN RETURN FALSE END;
  539. WHILE (i <= HIGH(s)) AND (s[i] # CHR(0)) DO
  540. d := ORD(s[i]);
  541. IF (d < ORD("0")) OR (d > ORD("9")) THEN RETURN FALSE END;
  542. v := v * 10 + VAL(INTEGER, d - ORD("0"));
  543. INC(i); INC(nd)
  544. END;
  545. IF nd = 0 THEN RETURN FALSE END;
  546. IF neg THEN v := -v END;
  547. RETURN TRUE
  548. END ParseInt;
  549. PROCEDURE Fold2 (kind: INTEGER; a, b: ARRAY OF CHAR; VAR r: QVal): BOOLEAN;
  550. VAR x, y, z: INTEGER;
  551. BEGIN
  552. IF NOT ParseInt(a, x) THEN RETURN FALSE END;
  553. IF NOT ParseInt(b, y) THEN RETURN FALSE END;
  554. IF kind = 0 THEN z := x + y
  555. ELSIF kind = 1 THEN z := x - y
  556. ELSIF kind = 2 THEN z := x * y
  557. ELSIF kind = 3 THEN
  558. IF y = 0 THEN RETURN FALSE END;
  559. z := x DIV y
  560. ELSE
  561. IF y = 0 THEN RETURN FALSE END;
  562. z := x MOD y
  563. END;
  564. IntStr(z, r);
  565. RETURN TRUE
  566. END Fold2;
  567. (* ---------------- module / data section ---------------- *)
  568. PROCEDURE OpenModule (name: ARRAY OF CHAR);
  569. VAR i : CARDINAL;
  570. BEGIN
  571. opened := TRUE;
  572. inBody := FALSE;
  573. dead := FALSE;
  574. hasOutName := FALSE;
  575. nTemp := 0; nLab := 0; loopTop := 0; nR := 0; nStr := 0;
  576. withTop := 0;
  577. noEmit := FALSE; inFunc := FALSE; useStack := FALSE;
  578. ctorN := 0; ctorTop := 0;
  579. setN := 0;
  580. nLoc := 0; nPar := 0; nArg := 0; nn := 0; callDepth := 0;
  581. recvArmed := FALSE;
  582. funcDepth := 0; scopeTop := 0; scopeBase[0] := 0;
  583. nInit := 0; nFini := 0; nExtInit := 0;
  584. programMode := TRUE;
  585. outSel := 0;
  586. sessUsed := 0; sessBuf[0] := CHR(0);
  587. delayTop := 0;
  588. ustrN := 0; ustrUsed := 0;
  589. i := 0;
  590. WHILE i <= HIGH(nestBufs) DO
  591. nestBufs[i][0] := CHR(0); nestUsed[i] := 0; INC(i)
  592. END;
  593. WL("# QBE IR generated by the V3 step-1 backend");
  594. WL("")
  595. END OpenModule;
  596. PROCEDURE DataLine (name: ARRAY OF CHAR; isReal: BOOLEAN;
  597. init: ARRAY OF CHAR);
  598. BEGIN
  599. IF NOT opened THEN RETURN END;
  600. W("export data $"); W(name);
  601. IF isReal THEN W(" = { d ") ELSE W(" = { w ") END;
  602. W(init);
  603. WL(" }")
  604. END DataLine;
  605. PROCEDURE DataLineB (name: ARRAY OF CHAR; init: ARRAY OF CHAR);
  606. (* A one-byte global (BYTE/SBYTE). *)
  607. BEGIN
  608. IF NOT opened THEN RETURN END;
  609. W("export data $"); W(name);
  610. W(" = { b ");
  611. W(init);
  612. WL(" }")
  613. END DataLineB;
  614. PROCEDURE DataLineH (name: ARRAY OF CHAR; init: ARRAY OF CHAR);
  615. (* A 16-bit global (WORD16/INTEGER16). *)
  616. BEGIN
  617. IF NOT opened THEN RETURN END;
  618. W("export data $"); W(name);
  619. W(" = { h ");
  620. W(init);
  621. WL(" }")
  622. END DataLineH;
  623. PROCEDURE DataLinePacked (name: ARRAY OF CHAR; t: INTEGER);
  624. (* A PACKEDSET global: 1/2/4 bytes, zero-initialised. *)
  625. VAR nb: CARDINAL;
  626. BEGIN
  627. IF NOT opened THEN RETURN END;
  628. nb := SymTab.SetBytes(t);
  629. W("export data $"); W(name);
  630. W(" = { ");
  631. IF nb = 1 THEN W("b 0")
  632. ELSIF nb = 2 THEN W("h 0")
  633. ELSE W("w 0")
  634. END;
  635. WL(" }")
  636. END DataLinePacked;
  637. PROCEDURE DataLineL (name: ARRAY OF CHAR; init: ARRAY OF CHAR);
  638. BEGIN
  639. IF NOT opened THEN RETURN END;
  640. W("export data $"); W(name);
  641. W(" = { l ");
  642. W(init);
  643. WL(" }")
  644. END DataLineL;
  645. PROCEDURE DeclLocal (name: ARRAY OF CHAR; t: INTEGER);
  646. (* Function-local variable: stack slot + static init, recorded. *)
  647. VAR slot : QVal;
  648. BEGIN
  649. AllocLocal(t, slot);
  650. LocAdd(name, 0, slot, ResClass(t), t)
  651. END DeclLocal;
  652. PROCEDURE DeclVar (name: ARRAY OF CHAR; t: INTEGER);
  653. (* Module-level variable: emitted as data "$<mod>_<name>". *)
  654. VAR g : QVal;
  655. BEGIN
  656. IF inFunc THEN DeclLocal(name, t); RETURN END;
  657. Cpy(g, curModName); App(g, "_"); App(g, name);
  658. IF SymTab.ClassOf(t) = SymTab.ClReal THEN DataLine(g, TRUE, "0")
  659. ELSIF SymTab.IsByteType(t) THEN DataLineB(g, "0")
  660. ELSIF SymTab.IsWord16Type(t) THEN DataLineH(g, "0")
  661. ELSIF SymTab.ClassOf(t) = SymTab.ClArray THEN DeclArr(g, t)
  662. ELSIF SymTab.IsPackedSet(t) THEN DataLinePacked(g, t)
  663. ELSIF SymTab.ClassOf(t) = SymTab.ClSet THEN DeclSet(g, t)
  664. ELSIF (SymTab.ClassOf(t) = SymTab.ClRecord)
  665. OR (SymTab.ClassOf(t) = SymTab.ClClass) THEN
  666. DeclRec(g, t)
  667. ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
  668. OR (SymTab.ClassOf(t) = SymTab.ClLong)
  669. OR (SymTab.ClassOf(t) = SymTab.ClProc) THEN DataLineL(g, "0")
  670. ELSE DataLine(g, FALSE, "0")
  671. END
  672. END DeclVar;
  673. PROCEDURE IsZeroReal (val: ARRAY OF CHAR): BOOLEAN;
  674. (* TRUE when the "d_..." literal denotes zero (checked textually). *)
  675. VAR i : CARDINAL;
  676. seen : BOOLEAN;
  677. ch : CHAR;
  678. BEGIN
  679. i := 0;
  680. IF (Len(val) > 1) AND (val[0] = "d") AND (val[1] = "_") THEN i := 2 END;
  681. IF (Len(val) > i) AND (val[i] = "-") THEN INC(i) END;
  682. seen := FALSE;
  683. WHILE val[i] # CHR(0) DO
  684. ch := val[i];
  685. IF (ch >= "0") AND (ch <= "9") THEN
  686. seen := TRUE;
  687. IF ch # "0" THEN RETURN FALSE END
  688. ELSIF (ch # ".") AND (ch # "E") AND (ch # "e")
  689. AND (ch # "+") AND (ch # "-") THEN
  690. RETURN FALSE
  691. END;
  692. INC(i)
  693. END;
  694. RETURN seen
  695. END IsZeroReal;
  696. PROCEDURE DeclConst (name: ARRAY OF CHAR; val: ARRAY OF CHAR; t: INTEGER);
  697. VAR cls : INTEGER;
  698. mang : QVal;
  699. BEGIN
  700. cls := SymTab.ClassOf(t);
  701. IF inFunc THEN
  702. Cpy(mang, funcName); App(mang, "_"); App(mang, name);
  703. LocAdd(name, 1, mang, ResClass(t), t)
  704. ELSE
  705. Cpy(mang, curModName); App(mang, "_"); App(mang, name)
  706. END;
  707. IF (cls = SymTab.ClStr) OR NOT IsImm(val) THEN
  708. DataLine(mang, FALSE, "0"); RETURN
  709. END;
  710. IF cls = SymTab.ClLong THEN
  711. DataLineL(mang, val)
  712. ELSIF cls = SymTab.ClReal THEN
  713. (* This qbe accepts only integer/zero literals in "data":
  714. non-zero REALs flush at BeginBody. *)
  715. DataLine(mang, TRUE, "0");
  716. IF NOT IsZeroReal(val) AND (nR <= HIGH(rNames)) THEN
  717. Cpy(rNames[nR], mang); Cpy(rVals[nR], val); INC(nR)
  718. END
  719. ELSE DataLine(mang, FALSE, val)
  720. END
  721. END DeclConst;
  722. (* ---------------- function body ---------------- *)
  723. PROCEDURE BeginInit (mod: ARRAY OF CHAR);
  724. (* Module BEGIN body as `<mod>_init`; main calls it at startup. *)
  725. VAR sym : QVal;
  726. BEGIN
  727. IF NOT opened THEN RETURN END;
  728. excHas[0] := FALSE;
  729. Cpy(sym, mod);
  730. App(sym, "_init");
  731. WL("");
  732. W("export function w $"); W(sym); WL("() {");
  733. WL("@start");
  734. IF nInit <= HIGH(initNames) THEN
  735. Cpy(initNames[nInit], sym); INC(nInit)
  736. END
  737. END BeginInit;
  738. PROCEDURE EndInit;
  739. BEGIN
  740. Revive;
  741. WL(" ret 0");
  742. WL("}")
  743. END EndInit;
  744. PROCEDURE BeginFini (mod: ARRAY OF CHAR);
  745. (* Module FINALLY body as `<mod>_fini`; main calls it at termination. *)
  746. VAR sym : QVal;
  747. BEGIN
  748. IF NOT opened THEN RETURN END;
  749. excHas[0] := FALSE;
  750. Cpy(sym, mod);
  751. App(sym, "_fini");
  752. WL("");
  753. W("export function w $"); W(sym); WL("() {");
  754. WL("@start");
  755. IF nFini <= HIGH(finiNames) THEN
  756. Cpy(finiNames[nFini], sym); INC(nFini)
  757. END
  758. END BeginFini;
  759. PROCEDURE EndFini;
  760. BEGIN
  761. Revive;
  762. WL(" ret 0");
  763. WL("}")
  764. END EndFini;
  765. PROCEDURE BeginBody;
  766. VAR i : CARDINAL;
  767. t : QVal;
  768. BEGIN
  769. IF NOT opened OR inBody THEN RETURN END;
  770. WL("");
  771. WL("export function w $main() {");
  772. WL("@start");
  773. excHas[0] := FALSE;
  774. WL(" call $m2_exc_init()");
  775. inBody := TRUE;
  776. i := 0;
  777. WHILE i < nR DO
  778. NewTemp(t);
  779. W(" "); W(t); W(" =d copy "); WL(rVals[i]);
  780. StoreVar(rNames[i], t, TRUE);
  781. INC(i)
  782. END;
  783. i := 0;
  784. WHILE i < nExtInit DO
  785. W(" call $"); W(extInitNames[i]); WL("()");
  786. INC(i)
  787. END;
  788. i := 0;
  789. WHILE i < nInit DO
  790. W(" call $"); W(initNames[i]); WL("()");
  791. INC(i)
  792. END
  793. END BeginBody;
  794. PROCEDURE FlushSets;
  795. (* Pooled set constants. Declared before EndModule, which calls it. *)
  796. VAR k, i: CARDINAL;
  797. w: CARDINAL;
  798. sv: QVal;
  799. BEGIN
  800. IF NOT opened THEN RETURN END;
  801. k := 0;
  802. WHILE k < setN DO
  803. W("export data $"); W(setNam[k]); W(" = { ");
  804. w := setW[k];
  805. IF w = 0 THEN w := 1 END;
  806. i := 0;
  807. WHILE i < w DO
  808. IF i > 0 THEN W(", ") END;
  809. IntStr(VAL(INTEGER, setMask[k][i]), sv);
  810. W("w "); W(sv);
  811. INC(i)
  812. END;
  813. WL(" }");
  814. INC(k)
  815. END
  816. END FlushSets;
  817. PROCEDURE FiniExists (name: ARRAY OF CHAR): BOOLEAN;
  818. VAR i: CARDINAL;
  819. BEGIN
  820. i := 0;
  821. WHILE i < nFini DO
  822. IF SymTab.Equal(finiNames[i], name) THEN RETURN TRUE END;
  823. INC(i)
  824. END;
  825. RETURN FALSE
  826. END FiniExists;
  827. PROCEDURE EmitFiniCalls (prog: ARRAY OF CHAR);
  828. (* Program finalizer first, then imported/local finalizers in reverse
  829. initialization order. *)
  830. VAR i: CARDINAL; p: QVal;
  831. BEGIN
  832. Cpy(p, prog); App(p, "_fini");
  833. IF FiniExists(p) THEN
  834. W(" call $"); W(p); WL("()")
  835. END;
  836. i := nFini;
  837. WHILE i > 0 DO
  838. DEC(i);
  839. IF NOT SymTab.Equal(finiNames[i], p) THEN
  840. W(" call $"); W(finiNames[i]); WL("()")
  841. END
  842. END
  843. END EmitFiniCalls;
  844. PROCEDURE EndModule (name: ARRAY OF CHAR);
  845. VAR i : CARDINAL;
  846. fname : ARRAY [0 .. 127] OF CHAR;
  847. ref : QVal;
  848. BEGIN
  849. IF NOT opened THEN RETURN END;
  850. (* Per-unit Lower emission: the grammar's own unit-end EndModule must
  851. not flush/close/write while the legacy emit is suppressed. The
  852. real session image is written by Lower.EndSession. *)
  853. IF noEmit THEN RETURN END;
  854. IF programMode THEN
  855. IF NOT inBody THEN BeginBody END;
  856. EmitFiniCalls(name);
  857. IF SymTab.Lookup("ExitCode")
  858. AND (SymTab.SymKind("ExitCode") = SymTab.KindVar)
  859. AND SymTab.IsIntFamily(SymTab.SymType("ExitCode")) THEN
  860. Cpy(ref, "$"); App(ref, name); App(ref, "_ExitCode");
  861. W(" %ec =w loadw "); WL(ref);
  862. WL(" ret %ec")
  863. ELSE
  864. WL(" ret 0")
  865. END;
  866. WL("}")
  867. END;
  868. (* hoisted nested functions, then deferred data *)
  869. i := 0;
  870. WHILE i <= HIGH(nestBufs) DO
  871. IF nestUsed[i] > 0 THEN
  872. BufApp(sessBuf, sessUsed, nestBufs[i], FALSE)
  873. END;
  874. INC(i)
  875. END;
  876. FlushStrings;
  877. FlushUStrings;
  878. FlushCtors;
  879. FlushSets;
  880. EmitVTables;
  881. (* the image is named after the program module *)
  882. fname[0] := CHR(0);
  883. App(fname, "gen_ssa/");
  884. IF hasOutName THEN App(fname, outName) ELSE App(fname, name) END;
  885. App(fname, ".ssa");
  886. FileIO.Open(out, fname, TRUE);
  887. IF FileIO.Okay THEN
  888. (* Flush exactly sessUsed bytes. FileIO.WriteString scans for a
  889. NUL and misbehaves for multi-megabyte buffers, so write the
  890. image byte by byte up to sessUsed. *)
  891. i := 0;
  892. WHILE i < sessUsed DO
  893. FileIO.Write(out, sessBuf[i]); INC(i)
  894. END
  895. END;
  896. FileIO.Close(out);
  897. opened := FALSE
  898. END EndModule;
  899. (* ---------------- functions and calls (step 4.1) ---------------- *)
  900. (* Module-level procedures only (nested → NoEmit until 4.2).
  901. Value params arrive as SSA values and are copied to slots;
  902. composite value params arrive as addresses and are copied;
  903. VAR params stay addresses. Locals live in stack slots. *)
  904. PROCEDURE LocFind (name: ARRAY OF CHAR): INTEGER;
  905. VAR i : CARDINAL;
  906. BEGIN
  907. i := 0;
  908. WHILE i < nLoc DO
  909. IF SymTab.Equal(locNames[i], name) THEN RETURN VAL(INTEGER, i) END;
  910. INC(i)
  911. END;
  912. RETURN -1
  913. END LocFind;
  914. PROCEDURE ScopeBegin;
  915. (* Pushes a procedure scope (always balanced, even under NoEmit). *)
  916. BEGIN
  917. IF scopeTop > HIGH(scopeLink) THEN RETURN END;
  918. scopeBase[scopeTop] := nLoc;
  919. INC(scopeTop);
  920. scopeBase[scopeTop] := nLoc
  921. END ScopeBegin;
  922. PROCEDURE ScopeEnd;
  923. BEGIN
  924. IF scopeTop > 0 THEN
  925. DEC(scopeTop);
  926. nLoc := scopeBase[scopeTop]
  927. END
  928. END ScopeEnd;
  929. PROCEDURE LocFindUp (name: ARRAY OF CHAR; VAR levels: CARDINAL;
  930. VAR flat: INTEGER): BOOLEAN;
  931. (* Innermost procedure scope holding name; levels = scopes crossed,
  932. flat = table index. FALSE when purely global. *)
  933. VAR s, top, lo, hi, j : CARDINAL;
  934. BEGIN
  935. levels := 0; flat := -1;
  936. IF scopeTop = 0 THEN RETURN FALSE END;
  937. top := scopeTop - 1;
  938. s := top;
  939. LOOP
  940. lo := scopeBase[s];
  941. IF s = top THEN hi := nLoc ELSE hi := scopeBase[s + 1] END;
  942. j := lo;
  943. WHILE j < hi DO
  944. IF SymTab.Equal(locNames[j], name) THEN
  945. levels := top - s;
  946. flat := VAL(INTEGER, j);
  947. RETURN TRUE
  948. END;
  949. INC(j)
  950. END;
  951. IF s = 0 THEN RETURN FALSE END;
  952. DEC(s)
  953. END
  954. END LocFindUp;
  955. PROCEDURE LocAdd (name: ARRAY OF CHAR; tag: INTEGER; rep: ARRAY OF CHAR;
  956. cls: CHAR; typ: INTEGER);
  957. VAR idx : CARDINAL;
  958. off : QVal;
  959. lk : QVal;
  960. BEGIN
  961. IF (scopeTop = 0) OR (nLoc > HIGH(locNames)) THEN RETURN END;
  962. idx := nLoc - scopeBase[scopeTop - 1];
  963. IF idx > 63 THEN RETURN END;
  964. Cpy(locNames[nLoc], name);
  965. locTag[nLoc] := tag;
  966. Cpy(locRep[nLoc], rep);
  967. locCls[nLoc] := cls;
  968. locTyp[nLoc] := typ;
  969. INC(nLoc);
  970. IF tag = 1 THEN RETURN END;
  971. Cpy(lk, scopeLink[scopeTop - 1]);
  972. IntStr(VAL(INTEGER, 8 * (idx + 1)), off);
  973. NewTemp(lk);
  974. Op3L("add", lk, scopeLink[scopeTop - 1], off);
  975. Revive;
  976. W(" storel "); W(rep); W(", "); WL(lk)
  977. END LocAdd;
  978. PROCEDURE LocFull (): BOOLEAN;
  979. (* TRUE past 64 locals in the current scope (→ 233). *)
  980. BEGIN
  981. IF scopeTop = 0 THEN RETURN FALSE END;
  982. RETURN nLoc - scopeBase[scopeTop - 1] > 63
  983. END LocFull;
  984. PROCEDURE UpAddr (levels: CARDINAL; rel: CARDINAL; VAR q: QVal);
  985. (* Address of an up-level local: walks the static chain, then
  986. loads the link cell (slot address or actual address). *)
  987. VAR cur, t, off : QVal;
  988. L : CARDINAL;
  989. BEGIN
  990. Cpy(cur, scopeLink[scopeTop - 1]);
  991. L := levels;
  992. WHILE L > 0 DO
  993. NewTemp(t);
  994. Revive;
  995. W(" "); W(t); W(" =l loadl "); WL(cur);
  996. Cpy(cur, t);
  997. DEC(L)
  998. END;
  999. IntStr(VAL(INTEGER, 8 * (rel + 1)), off);
  1000. NewTemp(t);
  1001. Op3L("add", t, cur, off);
  1002. NewTemp(q);
  1003. Revive;
  1004. W(" "); W(q); W(" =l loadl "); WL(t)
  1005. END UpAddr;
  1006. PROCEDURE ResClass (t: INTEGER): CHAR;
  1007. VAR cls : INTEGER;
  1008. BEGIN
  1009. cls := SymTab.ClassOf(t);
  1010. IF cls = SymTab.ClReal THEN RETURN "d" END;
  1011. IF (cls = SymTab.ClArray) OR (cls = SymTab.ClSet)
  1012. OR (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass)
  1013. OR (cls = SymTab.ClPtr) OR (cls = SymTab.ClLong)
  1014. OR (cls = SymTab.ClProc) THEN
  1015. RETURN "l"
  1016. END;
  1017. RETURN "w"
  1018. END ResClass;
  1019. PROCEDURE Mangled (pname: ARRAY OF CHAR; uid: CARDINAL; VAR q: QVal);
  1020. (* External procedures bind to their C link name. Module-level
  1021. procedures get a stable, module-qualified name (<module>__<name>)
  1022. so objects compiled in separate sessions agree. Nested procedures
  1023. are local to their module object; they keep a deterministic uid
  1024. suffix, prefixed by the module to avoid cross-object collisions. *)
  1025. VAR link, base, mod : SymTab.Name;
  1026. depth : CARDINAL; classIdx : INTEGER; num : QVal;
  1027. BEGIN
  1028. IF SymTab.ProcLink(pname, link) THEN
  1029. Cpy(q, link);
  1030. RETURN
  1031. END;
  1032. IF NOT SymTab.SymBase(pname, base) THEN
  1033. IF NOT SymTab.ProcBaseByUid(uid, base) THEN Cpy(base, pname) END
  1034. END;
  1035. IF SymTab.SymBase(pname, base) THEN
  1036. IF SymTab.ProcLink(base, link) THEN
  1037. Cpy(q, link);
  1038. RETURN
  1039. END
  1040. END;
  1041. IF SymTab.ProcModuleByUid(uid, mod, depth)
  1042. AND (mod[0] # CHR(0)) THEN
  1043. Cpy(q, mod);
  1044. App(q, "__");
  1045. App(q, base);
  1046. classIdx := SymTab.ProcClassByUid(uid);
  1047. IF classIdx # SymTab.InvalidType THEN
  1048. IF SymTab.TypeStableName(classIdx, link, base) THEN
  1049. App(q, "_"); App(q, link); App(q, "__"); App(q, base)
  1050. ELSE
  1051. App(q, "_c");
  1052. IntStr(classIdx, num);
  1053. App(q, num)
  1054. END
  1055. END;
  1056. IF depth > 0 THEN
  1057. App(q, "_");
  1058. AppNum(q, uid)
  1059. END
  1060. ELSE
  1061. Cpy(q, base);
  1062. App(q, "_");
  1063. AppNum(q, uid)
  1064. END
  1065. END Mangled;
  1066. PROCEDURE AllocLocal (t: INTEGER; VAR slot: QVal);
  1067. (* Stack slot sized for t's inline footprint; arrays/records get
  1068. full objects + static init. Scalar/pointer/set slots are
  1069. zero-initialized: QBE rejects reads of never-stored slots, and
  1070. the frontend emits a dead load for assignment targets (Test2
  1071. heritage, harmless for zero-initialized globals). Locals match
  1072. the globals' zero-init convention. *)
  1073. VAR cls : INTEGER;
  1074. nb : QVal;
  1075. BEGIN
  1076. cls := SymTab.ClassOf(t);
  1077. NewTemp(slot);
  1078. Revive;
  1079. W(" "); W(slot);
  1080. IF (cls = SymTab.ClArray) THEN
  1081. IntStr(VAL(INTEGER, HeapSize(t)), nb);
  1082. W(" =l alloc8 "); WL(nb);
  1083. InitStack(slot, t)
  1084. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  1085. IntStr(VAL(INTEGER, SymTab.TypeSize(t)), nb);
  1086. W(" =l alloc8 "); WL(nb);
  1087. InitStack(slot, t)
  1088. ELSIF SymTab.IsPackedSet(t) THEN
  1089. W(" =l alloc4 4"); WL("");
  1090. IF SymTab.SetBytes(t) = 1 THEN W(" storeb 0, "); WL(slot)
  1091. ELSIF SymTab.SetBytes(t) = 2 THEN W(" storeh 0, "); WL(slot)
  1092. ELSE W(" storew 0, "); WL(slot)
  1093. END
  1094. ELSIF cls = SymTab.ClSet THEN
  1095. IntStr(VAL(INTEGER, SymTab.SetWords(t) * 4), nb);
  1096. W(" =l alloc8 "); WL(nb);
  1097. SetZero(slot, SymTab.SetWords(t))
  1098. ELSIF cls = SymTab.ClReal THEN
  1099. W(" =l alloc8 8"); WL("");
  1100. W(" stored d_0.0, "); WL(slot)
  1101. ELSIF (cls = SymTab.ClPtr) OR (cls = SymTab.ClLong)
  1102. OR (cls = SymTab.ClProc) THEN
  1103. W(" =l alloc8 8"); WL("");
  1104. W(" storel 0, "); WL(slot)
  1105. ELSIF (cls = SymTab.ClByte) OR (cls = SymTab.ClSByte) THEN
  1106. W(" =l alloc4 4"); WL("");
  1107. W(" storeb 0, "); WL(slot)
  1108. ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN
  1109. W(" =l alloc4 4"); WL("");
  1110. W(" storeh 0, "); WL(slot)
  1111. ELSE
  1112. W(" =l alloc4 4"); WL("");
  1113. W(" storew 0, "); WL(slot)
  1114. END
  1115. END AllocLocal;
  1116. PROCEDURE OpenScalarDesc (val: ARRAY OF CHAR; t, ft: INTEGER; VAR desc: QVal);
  1117. (* gm2 compatibility: wrap a scalar actual as an `ARRAY OF BYTE`
  1118. descriptor in the frame. Layout is the usual [count][data]; the
  1119. count is ObjectSize(actual), so HIGH matches gm2's SIZE-1, and the
  1120. payload is a copy of the value (writes do not reach the actual). *)
  1121. VAR cnt, off, nb: QVal;
  1122. cls: INTEGER;
  1123. sz, esz: CARDINAL;
  1124. BEGIN
  1125. sz := SymTab.ObjectSize(t);
  1126. esz := SymTab.ObjectSize(SymTab.ArrayElem(ft));
  1127. IF esz = 0 THEN esz := 1 END;
  1128. NewTemp(desc); Revive;
  1129. W(" "); W(desc); W(" =l alloc8 ");
  1130. IntStr(VAL(INTEGER, 8 + sz * esz), nb); WL(nb);
  1131. NewTemp(cnt); IntStr(VAL(INTEGER, sz), cnt);
  1132. W(" storel "); W(cnt); W(", "); W(desc); WL("");
  1133. NewTemp(off); Op3L("add", off, desc, "8");
  1134. cls := SymTab.ClassOf(t);
  1135. IF cls = SymTab.ClReal THEN
  1136. W(" stored "); W(val); W(", "); W(off); WL("")
  1137. ELSIF (cls = SymTab.ClPtr) OR (cls = SymTab.ClLong) OR (sz > 4) THEN
  1138. W(" storel "); W(val); W(", "); W(off); WL("")
  1139. ELSIF (cls = SymTab.ClByte) OR (cls = SymTab.ClSByte) THEN
  1140. W(" storeb "); W(val); W(", "); W(off); WL("")
  1141. ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN
  1142. W(" storeh "); W(val); W(", "); W(off); WL("")
  1143. ELSE
  1144. W(" storew "); W(val); W(", "); W(off); WL("")
  1145. END
  1146. END OpenScalarDesc;
  1147. PROCEDURE BeginFunc (mangled: ARRAY OF CHAR);
  1148. (* Opens function context and scope; the header (with a leading
  1149. static-link param) buffers until EndFuncHeader. FORWARD/DefUnit
  1150. paths discard via AbortFunc. *)
  1151. BEGIN
  1152. ScopeBegin;
  1153. INC(funcDepth);
  1154. IF funcDepth <= HIGH(excHas) THEN excHas[funcDepth] := FALSE END;
  1155. inFunc := TRUE;
  1156. nPar := 0;
  1157. funcRes := "w";
  1158. Cpy(funcName, mangled);
  1159. hbuf[0] := CHR(0);
  1160. NewTemp(slTmp);
  1161. HApp("l ");
  1162. HApp(slTmp);
  1163. hdrComma := TRUE;
  1164. IF funcDepth > 1 THEN
  1165. outSel := funcDepth - 1;
  1166. IF outSel > HIGH(nestBufs) + 1 THEN
  1167. outSel := HIGH(nestBufs) + 1
  1168. END
  1169. ELSE
  1170. outSel := 0
  1171. END
  1172. END BeginFunc;
  1173. PROCEDURE SetFuncRes (t: INTEGER);
  1174. BEGIN
  1175. funcRes := ResClass(t)
  1176. END SetFuncRes;
  1177. PROCEDURE HApp (s: ARRAY OF CHAR);
  1178. (* Appends to the header buffer (bounded: FormalParams cap it). *)
  1179. VAR i, j : CARDINAL;
  1180. BEGIN
  1181. i := 0;
  1182. WHILE (i <= HIGH(hbuf)) AND (hbuf[i] # CHR(0)) DO INC(i) END;
  1183. j := 0;
  1184. WHILE (i < HIGH(hbuf)) AND (j <= HIGH(s)) AND (s[j] # CHR(0)) DO
  1185. hbuf[i] := s[j]; INC(i); INC(j)
  1186. END;
  1187. IF i <= HIGH(hbuf) THEN hbuf[i] := CHR(0) END
  1188. END HApp;
  1189. PROCEDURE FuncParam (name: ARRAY OF CHAR; isVar: BOOLEAN;
  1190. t: INTEGER): BOOLEAN;
  1191. VAR c : CHAR;
  1192. tmp : QVal;
  1193. buf : ARRAY [0 .. 71] OF CHAR;
  1194. BEGIN
  1195. IF nPar > HIGH(parCls) THEN RETURN FALSE END;
  1196. IF isVar THEN c := "l" ELSE c := ResClass(t) END;
  1197. parCls[nPar] := c;
  1198. NewTemp(tmp);
  1199. Cpy(parTmp[nPar], tmp);
  1200. Cpy(parNam[nPar], name);
  1201. parVar[nPar] := isVar;
  1202. parTyp[nPar] := t;
  1203. IF hdrComma THEN HApp(", ") END;
  1204. hdrComma := TRUE;
  1205. buf[0] := c; buf[1] := " "; buf[2] := CHR(0);
  1206. App(buf, tmp);
  1207. HApp(buf);
  1208. INC(nPar);
  1209. RETURN TRUE
  1210. END FuncParam;
  1211. PROCEDURE EndFuncHeader;
  1212. (* Flushes the buffered header + body label, allocates the link
  1213. record ([0] = parent link), then emits entry copies. *)
  1214. VAR i : CARDINAL;
  1215. slot, nb, lk : QVal;
  1216. cls : INTEGER;
  1217. BEGIN
  1218. W("export function "); Wc(funcRes); W(" $"); W(funcName); W("(");
  1219. W(hbuf);
  1220. WL(") {");
  1221. WL("@start");
  1222. inBody := TRUE;
  1223. NewTemp(lk);
  1224. Cpy(scopeLink[scopeTop - 1], lk);
  1225. Revive;
  1226. W(" "); W(lk); W(" =l alloc8 520"); WL("");
  1227. W(" storel "); W(slTmp); W(", "); WL(lk);
  1228. i := 0;
  1229. WHILE i < nPar DO
  1230. cls := SymTab.ClassOf(parTyp[i]);
  1231. IF parVar[i] THEN
  1232. LocAdd(parNam[i], 2, parTmp[i], parCls[i], parTyp[i])
  1233. ELSE
  1234. AllocLocal(parTyp[i], slot);
  1235. LocAdd(parNam[i], 0, slot, parCls[i], parTyp[i]);
  1236. IF cls = SymTab.ClArray THEN
  1237. CopyArray(slot, parTmp[i], parTyp[i])
  1238. ELSIF cls = SymTab.ClSet THEN
  1239. CopySetVal(slot, parTyp[i], parTmp[i], parTyp[i])
  1240. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  1241. CopyRecord(slot, parTmp[i], parTyp[i])
  1242. ELSIF cls = SymTab.ClReal THEN
  1243. Revive;
  1244. W(" stored "); W(parTmp[i]); W(", "); WL(slot)
  1245. ELSIF (cls = SymTab.ClPtr) OR (cls = SymTab.ClProc)
  1246. OR (cls = SymTab.ClLong) THEN
  1247. Revive;
  1248. W(" storel "); W(parTmp[i]); W(", "); WL(slot)
  1249. ELSIF (cls = SymTab.ClByte) OR (cls = SymTab.ClSByte) THEN
  1250. Revive;
  1251. W(" storeb "); W(parTmp[i]); W(", "); WL(slot)
  1252. ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN
  1253. Revive;
  1254. W(" storeh "); W(parTmp[i]); W(", "); WL(slot)
  1255. ELSE
  1256. Revive;
  1257. W(" storew "); W(parTmp[i]); W(", "); WL(slot)
  1258. END
  1259. END;
  1260. INC(i)
  1261. END
  1262. END EndFuncHeader;
  1263. PROCEDURE AbortFunc;
  1264. (* Discards function context without emitting (DefUnit headings,
  1265. FORWARD, methods): pops the scope, restores the depth. *)
  1266. BEGIN
  1267. ScopeEnd;
  1268. IF funcDepth <= HIGH(excHas) THEN excHas[funcDepth] := FALSE END;
  1269. IF funcDepth > 0 THEN DEC(funcDepth) END;
  1270. inFunc := funcDepth > 0;
  1271. inBody := FALSE;
  1272. nPar := 0;
  1273. IF funcDepth > 1 THEN outSel := funcDepth - 1
  1274. ELSE outSel := 0
  1275. END
  1276. END AbortFunc;
  1277. PROCEDURE EndFunc (resT: INTEGER);
  1278. VAR rc : CHAR;
  1279. BEGIN
  1280. rc := ResClass(resT);
  1281. Revive;
  1282. IF resT # SymTab.InvalidType THEN
  1283. (* A function that reaches its end without RETURN raises the
  1284. language functionException instead of silently returning 0. *)
  1285. TrapCode(4)
  1286. ELSIF rc = "d" THEN WL(" ret d_0.0")
  1287. ELSIF rc = "l" THEN WL(" ret 0")
  1288. ELSE WL(" ret 0")
  1289. END;
  1290. WL("}");
  1291. ScopeEnd;
  1292. IF funcDepth <= HIGH(excHas) THEN excHas[funcDepth] := FALSE END;
  1293. IF funcDepth > 0 THEN DEC(funcDepth) END;
  1294. inFunc := funcDepth > 0;
  1295. inBody := FALSE;
  1296. IF funcDepth > 1 THEN outSel := funcDepth - 1
  1297. ELSE outSel := 0
  1298. END
  1299. END EndFunc;
  1300. PROCEDURE EmitRet (q: ARRAY OF CHAR; hasVal: BOOLEAN);
  1301. BEGIN
  1302. Revive;
  1303. IF (funcDepth <= HIGH(excHas)) AND excHas[funcDepth] THEN
  1304. WL(" call $m2_exc_leave()")
  1305. END;
  1306. IF hasVal THEN W(" ret "); WL(q)
  1307. ELSE WL(" ret 0")
  1308. END;
  1309. dead := TRUE
  1310. END EmitRet;
  1311. PROCEDURE ExcBegin;
  1312. (* M2: emit the handler prologue for the current function/module body.
  1313. The QBE frame owns a 512-byte sigjmp_buf; the runtime handler stores
  1314. that address. Dispatch: 0 = body, 2 = RETRY/body, 1 = handler. *)
  1315. VAR env, r, z, chk: QVal;
  1316. BEGIN
  1317. IF funcDepth > HIGH(excHas) THEN RETURN END;
  1318. Revive;
  1319. NewTemp(env);
  1320. W(" "); W(env); WL(" =l alloc8 512");
  1321. W(" call $m2_exc_push(l "); W(env); WL(")");
  1322. NewTemp(r);
  1323. W(" "); W(r); W(" =w call $__sigsetjmp(l "); W(env);
  1324. W(", w 1)"); WL("");
  1325. NewLabel(excBodyL[funcDepth]);
  1326. NewLabel(excHandlerL[funcDepth]);
  1327. NewLabel(excAfterL[funcDepth]);
  1328. NewLabel(chk);
  1329. NewTemp(z);
  1330. Op3("ceqw", z, r, "0", FALSE);
  1331. Jnz(z, excBodyL[funcDepth], chk);
  1332. EmitLabel(chk);
  1333. NewTemp(z);
  1334. Op3("ceqw", z, r, "2", FALSE);
  1335. Jnz(z, excBodyL[funcDepth], excHandlerL[funcDepth]);
  1336. EmitLabel(excBodyL[funcDepth]);
  1337. excHas[funcDepth] := TRUE
  1338. END ExcBegin;
  1339. PROCEDURE ExcBodyDone;
  1340. BEGIN
  1341. IF funcDepth > HIGH(excHas) THEN RETURN END;
  1342. Revive;
  1343. WL(" call $m2_exc_leave()");
  1344. Jmp(excAfterL[funcDepth])
  1345. END ExcBodyDone;
  1346. PROCEDURE ExcHandlerBegin;
  1347. BEGIN
  1348. IF funcDepth > HIGH(excHas) THEN RETURN END;
  1349. EmitLabel(excHandlerL[funcDepth])
  1350. END ExcHandlerBegin;
  1351. PROCEDURE ExcEnd;
  1352. BEGIN
  1353. IF funcDepth > HIGH(excHas) THEN RETURN END;
  1354. Revive;
  1355. WL(" call $m2_exc_leave()");
  1356. EmitLabel(excAfterL[funcDepth])
  1357. END ExcEnd;
  1358. PROCEDURE ExcRetry;
  1359. BEGIN
  1360. IF dead THEN RETURN END;
  1361. WL(" call $m2_exc_retry()");
  1362. dead := TRUE
  1363. END ExcRetry;
  1364. PROCEDURE ProcAddr (mangled: ARRAY OF CHAR; VAR q: QVal);
  1365. BEGIN
  1366. Cpy(q, "$");
  1367. App(q, mangled)
  1368. END ProcAddr;
  1369. PROCEDURE CallBeginInd (callee: ARRAY OF CHAR; resT: INTEGER;
  1370. isExt: BOOLEAN);
  1371. (* Indirect call through the code pointer in `callee`. *)
  1372. BEGIN
  1373. IF callDepth > HIGH(stkName) THEN RETURN END;
  1374. Cpy(stkName[callDepth], callee);
  1375. stkRes[callDepth] := ResClass(resT);
  1376. stkExt[callDepth] := isExt;
  1377. stkInd[callDepth] := TRUE;
  1378. Cpy(stkLink[callDepth], "0");
  1379. stkArg[callDepth][0] := CHR(0);
  1380. stkN[callDepth] := 0;
  1381. INC(callDepth);
  1382. IF recvArmed THEN
  1383. IF NOT CallArg(recvQ, "l") THEN
  1384. END;
  1385. recvArmed := FALSE
  1386. END
  1387. END CallBeginInd;
  1388. PROCEDURE VirtCallBegin (obj: ARRAY OF CHAR; slot: INTEGER; resT: INTEGER);
  1389. (* Virtual dispatch: load obj's vtable pointer, fetch slot `slot`,
  1390. and begin an indirect call through it. The receiver (obj) must be
  1391. armed (ArmRecv). *)
  1392. VAR vt, off, ea, fp: QVal;
  1393. BEGIN
  1394. NewTemp(vt);
  1395. W(" "); W(vt); W(" =l loadl "); WL(obj);
  1396. IntStr(slot * 8, off);
  1397. NewTemp(ea);
  1398. Op3L("add", ea, vt, off);
  1399. NewTemp(fp);
  1400. W(" "); W(fp); W(" =l loadl "); WL(ea);
  1401. CallBeginInd(fp, resT, FALSE)
  1402. END VirtCallBegin;
  1403. PROCEDURE ArmRecv (q: ARRAY OF CHAR);
  1404. (* Arms the receiver for the next class-method call: CallBegin passes
  1405. it as the hidden first argument. *)
  1406. BEGIN
  1407. Cpy(recvQ, q);
  1408. recvArmed := TRUE
  1409. END ArmRecv;
  1410. PROCEDURE CallBegin (mangled: ARRAY OF CHAR; resT: INTEGER;
  1411. fdep: CARDINAL; isExt: BOOLEAN);
  1412. (* Pushes a call level; the static link is resolved now (caller
  1413. context cannot change mid-call): module callers pass 0, others
  1414. walk the chain (inFuncDepth - fdep) from their link record.
  1415. External callees take no static link. *)
  1416. VAR walks : INTEGER;
  1417. cur, t : QVal;
  1418. BEGIN
  1419. IF callDepth > HIGH(stkName) THEN RETURN END;
  1420. Cpy(stkName[callDepth], mangled);
  1421. stkRes[callDepth] := ResClass(resT);
  1422. stkExt[callDepth] := isExt;
  1423. stkInd[callDepth] := FALSE;
  1424. stkArg[callDepth][0] := CHR(0);
  1425. stkN[callDepth] := 0;
  1426. IF isExt THEN
  1427. Cpy(stkLink[callDepth], "0")
  1428. ELSIF funcDepth = 0 THEN
  1429. Cpy(stkLink[callDepth], "0")
  1430. ELSE
  1431. walks := VAL(INTEGER, funcDepth) - VAL(INTEGER, fdep);
  1432. Cpy(cur, scopeLink[scopeTop - 1]);
  1433. WHILE walks > 0 DO
  1434. NewTemp(t);
  1435. Revive;
  1436. W(" "); W(t); W(" =l loadl "); WL(cur);
  1437. Cpy(cur, t);
  1438. DEC(walks)
  1439. END;
  1440. Cpy(stkLink[callDepth], cur)
  1441. END;
  1442. INC(callDepth);
  1443. IF recvArmed THEN
  1444. (* class method: the receiver is the hidden first argument *)
  1445. IF NOT CallArg(recvQ, "l") THEN
  1446. END;
  1447. recvArmed := FALSE
  1448. END
  1449. END CallBegin;
  1450. PROCEDURE CallArg (q: ARRAY OF CHAR; cls: CHAR): BOOLEAN;
  1451. (* Appends "c operand, " to the current level. FALSE when full. *)
  1452. VAR need, have, i, j, d : CARDINAL;
  1453. BEGIN
  1454. d := callDepth - 1;
  1455. IF callDepth = 0 THEN RETURN FALSE END;
  1456. IF d > HIGH(stkArg) THEN d := HIGH(stkArg) END;
  1457. need := Len(q) + 5;
  1458. have := Len(stkArg[d]);
  1459. IF (stkN[d] >= 64) OR (have + need > HIGH(stkArg[d])) THEN
  1460. RETURN FALSE
  1461. END;
  1462. i := have; j := 0;
  1463. stkArg[d][i] := cls; INC(i);
  1464. stkArg[d][i] := " "; INC(i);
  1465. WHILE q[j] # CHR(0) DO
  1466. stkArg[d][i] := q[j]; INC(i); INC(j)
  1467. END;
  1468. stkArg[d][i] := ","; INC(i);
  1469. stkArg[d][i] := " "; INC(i);
  1470. stkArg[d][i] := CHR(0);
  1471. INC(stkN[d]);
  1472. RETURN TRUE
  1473. END CallArg;
  1474. PROCEDURE CallEnd (wantRes: BOOLEAN; VAR q: QVal);
  1475. VAR i, d : CARDINAL;
  1476. rc : CHAR;
  1477. body : ARRAY [0 .. 1023] OF CHAR;
  1478. BEGIN
  1479. IF callDepth = 0 THEN Cpy(q, "0"); RETURN END;
  1480. DEC(callDepth);
  1481. d := callDepth;
  1482. IF d > HIGH(stkArg) THEN d := HIGH(stkArg) END;
  1483. Cpy(funcName, stkName[d]);
  1484. rc := stkRes[d];
  1485. i := 0;
  1486. WHILE (stkArg[d][i] # CHR(0)) AND (i < HIGH(body)) DO
  1487. body[i] := stkArg[d][i]; INC(i)
  1488. END;
  1489. IF (i >= 2) AND (body[i-2] = ",") THEN
  1490. body[i-2] := CHR(0)
  1491. ELSE
  1492. body[i] := CHR(0)
  1493. END;
  1494. Revive;
  1495. IF wantRes THEN
  1496. NewTemp(q);
  1497. W(" "); W(q); W(" ="); Wc(rc)
  1498. ELSE
  1499. W(" ")
  1500. END;
  1501. IF stkInd[d] THEN
  1502. W(" call "); W(funcName); W("(") (* callee operand already %-prefixed *)
  1503. ELSE
  1504. W(" call $"); W(funcName); W("(")
  1505. END;
  1506. IF stkExt[d] THEN
  1507. W(body) (* C callee: no static link *)
  1508. ELSE
  1509. W("l "); W(stkLink[d]);
  1510. IF body[0] # CHR(0) THEN W(", "); W(body) END
  1511. END;
  1512. WL(")")
  1513. END CallEnd;
  1514. PROCEDURE InitStack (addr: ARRAY OF CHAR; t: INTEGER);
  1515. BEGIN
  1516. useStack := TRUE;
  1517. InitHeap(addr, t);
  1518. useStack := FALSE
  1519. END InitStack;
  1520. PROCEDURE ArgClass (t: INTEGER): CHAR;
  1521. (* Formal/actual class for call emission. *)
  1522. BEGIN
  1523. RETURN ResClass(t)
  1524. END ArgClass;
  1525. PROCEDURE CArg (q: ARRAY OF CHAR; t: INTEGER; VAR out: QVal;
  1526. VAR cls: CHAR);
  1527. BEGIN
  1528. cls := ArgClass(t);
  1529. IF SymTab.ClassOf(t) = SymTab.ClStr THEN
  1530. NewTemp(out); Op3L("add", out, q, "8"); cls := "l"
  1531. ELSIF (SymTab.ClassOf(t) = SymTab.ClArray)
  1532. AND SymTab.IsCharArray(t) THEN
  1533. NewTemp(out); Op3L("add", out, q, "8"); cls := "l"
  1534. ELSE Cpy(out, q)
  1535. END
  1536. END CArg;
  1537. PROCEDURE CArgAdd (q: ARRAY OF CHAR; t: INTEGER; VAR out: QVal;
  1538. VAR cls: CHAR);
  1539. BEGIN
  1540. CArg(q, t, out, cls);
  1541. IF NOT CallArg(out, cls) THEN END
  1542. END CArgAdd;
  1543. (* ---------------- temporaries and operators ---------------- *)
  1544. PROCEDURE NewTemp (VAR t: QVal);
  1545. BEGIN
  1546. Cpy(t, "%t");
  1547. AppNum(t, nTemp);
  1548. INC(nTemp)
  1549. END NewTemp;
  1550. PROCEDURE LocLoadFlat (idx: INTEGER; long: BOOLEAN; VAR q: QVal);
  1551. (* Loads a same-scope entry: slots/data by class (or long for
  1552. pointers), addr entries via ElemLoad. *)
  1553. BEGIN
  1554. IF locTag[idx] = 2 THEN
  1555. ElemLoad(locRep[idx], locTyp[idx], q);
  1556. RETURN
  1557. END;
  1558. NewTemp(q);
  1559. Revive;
  1560. W(" "); W(q);
  1561. IF long THEN W(" =l loadl ")
  1562. ELSIF locCls[idx] = "d" THEN W(" =d loadd ")
  1563. ELSIF SymTab.IsByteType(locTyp[idx]) THEN
  1564. IF SymTab.IsSignedByte(locTyp[idx]) THEN W(" =w loadsb ")
  1565. ELSE W(" =w loadub ")
  1566. END
  1567. ELSIF SymTab.IsWord16Type(locTyp[idx]) THEN
  1568. IF SymTab.IsSignedWord16(locTyp[idx]) THEN W(" =w loadsh ")
  1569. ELSE W(" =w loaduh ")
  1570. END
  1571. ELSE W(" =w loadw ")
  1572. END;
  1573. IF locTag[idx] = 1 THEN W("$") END;
  1574. WL(locRep[idx])
  1575. END LocLoadFlat;
  1576. PROCEDURE LocStoreFlat (idx: INTEGER; q: ARRAY OF CHAR; long: BOOLEAN);
  1577. (* Stores a same-scope entry: slots/data by class (or long), addr
  1578. via ElemStore. Data stores are grammar-unreachable (consts). *)
  1579. BEGIN
  1580. IF locTag[idx] = 2 THEN
  1581. ElemStore(locRep[idx], q, locTyp[idx]);
  1582. RETURN
  1583. END;
  1584. Revive;
  1585. IF long THEN W(" storel ")
  1586. ELSIF locCls[idx] = "d" THEN W(" stored ")
  1587. ELSIF SymTab.IsByteType(locTyp[idx]) THEN W(" storeb ")
  1588. ELSIF SymTab.IsWord16Type(locTyp[idx]) THEN W(" storeh ")
  1589. ELSE W(" storew ")
  1590. END;
  1591. W(q); W(", ");
  1592. IF locTag[idx] = 1 THEN W("$") END;
  1593. WL(locRep[idx])
  1594. END LocStoreFlat;
  1595. PROCEDURE UpLoad (flat: INTEGER; levels: CARDINAL; long: BOOLEAN;
  1596. VAR q: QVal);
  1597. (* Up-level load: data entries live globally; otherwise the link
  1598. cell yields the address and ElemLoad reads through it. *)
  1599. VAR a : QVal;
  1600. rel : CARDINAL;
  1601. BEGIN
  1602. IF locTag[flat] = 1 THEN
  1603. NewTemp(q);
  1604. Revive;
  1605. W(" "); W(q);
  1606. IF long THEN W(" =l loadl $")
  1607. ELSIF locCls[flat] = "d" THEN W(" =d loadd $")
  1608. ELSIF SymTab.IsByteType(locTyp[flat]) THEN
  1609. IF SymTab.IsSignedByte(locTyp[flat]) THEN W(" =w loadsb $")
  1610. ELSE W(" =w loadub $")
  1611. END
  1612. ELSIF SymTab.IsWord16Type(locTyp[flat]) THEN
  1613. IF SymTab.IsSignedWord16(locTyp[flat]) THEN W(" =w loadsh $")
  1614. ELSE W(" =w loaduh $")
  1615. END
  1616. ELSE W(" =w loadw $")
  1617. END;
  1618. WL(locRep[flat]);
  1619. RETURN
  1620. END;
  1621. rel := VAL(CARDINAL, flat) - scopeBase[scopeTop - 1 - levels];
  1622. UpAddr(levels, rel, a);
  1623. ElemLoad(a, locTyp[flat], q)
  1624. END UpLoad;
  1625. PROCEDURE UpStore (flat: INTEGER; levels: CARDINAL; q: ARRAY OF CHAR;
  1626. long: BOOLEAN);
  1627. VAR a : QVal;
  1628. rel : CARDINAL;
  1629. BEGIN
  1630. IF locTag[flat] = 1 THEN
  1631. Revive;
  1632. IF long THEN W(" storel ")
  1633. ELSIF locCls[flat] = "d" THEN W(" stored ")
  1634. ELSIF SymTab.IsByteType(locTyp[flat]) THEN W(" storeb ")
  1635. ELSIF SymTab.IsWord16Type(locTyp[flat]) THEN W(" storeh ")
  1636. ELSE W(" storew ")
  1637. END;
  1638. W(q); W(", $"); WL(locRep[flat]);
  1639. RETURN
  1640. END;
  1641. rel := VAL(CARDINAL, flat) - scopeBase[scopeTop - 1 - levels];
  1642. UpAddr(levels, rel, a);
  1643. ElemStore(a, q, locTyp[flat])
  1644. END UpStore;
  1645. PROCEDURE UpAddrOf (flat: INTEGER; levels: CARDINAL; VAR q: QVal);
  1646. (* Up-level address: data entries name globals; otherwise the
  1647. link cell holds it (composites) or points at it. For scalars
  1648. the cell IS the usable address (slot or actual address). *)
  1649. VAR a : QVal;
  1650. rel : CARDINAL;
  1651. BEGIN
  1652. IF locTag[flat] = 1 THEN
  1653. Cpy(q, "$");
  1654. App(q, locRep[flat]);
  1655. RETURN
  1656. END;
  1657. rel := VAL(CARDINAL, flat) - scopeBase[scopeTop - 1 - levels];
  1658. UpAddr(levels, rel, q)
  1659. END UpAddrOf;
  1660. PROCEDURE LoadDesignator (name: ARRAY OF CHAR; t: INTEGER; k: INTEGER;
  1661. VAR q: QVal): BOOLEAN;
  1662. VAR cls : INTEGER;
  1663. cv : QVal;
  1664. BEGIN
  1665. cls := SymTab.ClassOf(t);
  1666. IF SymTab.Equal(name, "TRUE") THEN
  1667. Cpy(q, "1"); RETURN TRUE
  1668. ELSIF SymTab.Equal(name, "FALSE") THEN
  1669. Cpy(q, "0"); RETURN TRUE
  1670. ELSIF SymTab.Equal(name, "NIL") THEN
  1671. Cpy(q, "0"); RETURN TRUE
  1672. END;
  1673. (* an immediate CONST (incl. an enumeration literal) is its value *)
  1674. IF k = SymTab.KindConst THEN
  1675. IF SymTab.GetSymVal(name, cv) AND IsImm(cv) THEN
  1676. Cpy(q, cv); RETURN TRUE
  1677. END
  1678. END;
  1679. IF (k = SymTab.KindVar) OR (k = SymTab.KindParam)
  1680. OR (k = SymTab.KindConst) THEN
  1681. IF SymTab.IsSmallInt(t) THEN
  1682. LoadShortVar(name, SymTab.IsSignedSmallInt(t),
  1683. SymTab.SmallIntBytes(t), q); RETURN TRUE
  1684. ELSIF (cls = SymTab.ClInt) OR (cls = SymTab.ClBool)
  1685. OR (cls = SymTab.ClChar) OR (cls = SymTab.ClEnum)
  1686. OR (cls = SymTab.ClReal) THEN
  1687. LoadVar(name, cls = SymTab.ClReal, q); RETURN TRUE
  1688. ELSIF (cls = SymTab.ClPtr) OR (cls = SymTab.ClProc) THEN
  1689. LoadPtr(name, q); RETURN TRUE
  1690. ELSIF (cls = SymTab.ClArray) OR (cls = SymTab.ClSet)
  1691. OR (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  1692. AddrOf(name, q); RETURN TRUE
  1693. END
  1694. END;
  1695. Cpy(q, "0");
  1696. RETURN FALSE
  1697. END LoadDesignator;
  1698. PROCEDURE LoadVar (name: ARRAY OF CHAR; isReal: BOOLEAN; VAR q: QVal);
  1699. VAR idx : INTEGER;
  1700. levels : CARDINAL;
  1701. ref : QVal;
  1702. BEGIN
  1703. IF LocFindUp(name, levels, idx) THEN
  1704. IF levels = 0 THEN LocLoadFlat(idx, FALSE, q)
  1705. ELSE UpLoad(idx, levels, FALSE, q)
  1706. END;
  1707. RETURN
  1708. END;
  1709. NewTemp(q);
  1710. Revive;
  1711. SymRef(name, ref);
  1712. W(" "); W(q);
  1713. IF isReal THEN W(" =d loadd ") ELSE W(" =w loadw ") END;
  1714. WL(ref)
  1715. END LoadVar;
  1716. PROCEDURE LoadShortVar (name: ARRAY OF CHAR; signed: BOOLEAN;
  1717. bytes: CARDINAL; VAR q: QVal);
  1718. VAR idx : INTEGER;
  1719. levels : CARDINAL;
  1720. ref : QVal;
  1721. BEGIN
  1722. IF LocFindUp(name, levels, idx) THEN
  1723. IF levels = 0 THEN LocLoadFlat(idx, FALSE, q)
  1724. ELSE UpLoad(idx, levels, FALSE, q)
  1725. END;
  1726. RETURN
  1727. END;
  1728. NewTemp(q);
  1729. Revive;
  1730. SymRef(name, ref);
  1731. W(" "); W(q);
  1732. IF bytes = 1 THEN
  1733. IF signed THEN W(" =w loadsb ") ELSE W(" =w loadub ") END
  1734. ELSE
  1735. IF signed THEN W(" =w loadsh ") ELSE W(" =w loaduh ") END
  1736. END;
  1737. WL(ref)
  1738. END LoadShortVar;
  1739. PROCEDURE StoreShortVar (name: ARRAY OF CHAR; bytes: CARDINAL;
  1740. q: ARRAY OF CHAR);
  1741. VAR idx : INTEGER;
  1742. levels : CARDINAL;
  1743. ref : QVal;
  1744. BEGIN
  1745. IF LocFindUp(name, levels, idx) THEN
  1746. IF levels = 0 THEN LocStoreFlat(idx, q, FALSE)
  1747. ELSE UpStore(idx, levels, q, FALSE)
  1748. END;
  1749. RETURN
  1750. END;
  1751. Revive;
  1752. SymRef(name, ref);
  1753. IF bytes = 1 THEN W(" storeb ") ELSE W(" storeh ") END;
  1754. W(q); W(", "); WL(ref)
  1755. END StoreShortVar;
  1756. PROCEDURE LoadPtr (name: ARRAY OF CHAR; VAR q: QVal);
  1757. VAR idx : INTEGER;
  1758. levels : CARDINAL;
  1759. ref : QVal;
  1760. BEGIN
  1761. IF LocFindUp(name, levels, idx) THEN
  1762. IF levels = 0 THEN LocLoadFlat(idx, TRUE, q)
  1763. ELSE UpLoad(idx, levels, TRUE, q)
  1764. END;
  1765. RETURN
  1766. END;
  1767. NewTemp(q);
  1768. Revive;
  1769. SymRef(name, ref);
  1770. W(" "); W(q); W(" =l loadl ");
  1771. WL(ref)
  1772. END LoadPtr;
  1773. PROCEDURE LoadLong (name: ARRAY OF CHAR; VAR q: QVal);
  1774. VAR idx : INTEGER;
  1775. levels : CARDINAL;
  1776. ref : QVal;
  1777. BEGIN
  1778. IF LocFindUp(name, levels, idx) THEN
  1779. IF levels = 0 THEN LocLoadFlat(idx, TRUE, q)
  1780. ELSE UpLoad(idx, levels, TRUE, q)
  1781. END;
  1782. RETURN
  1783. END;
  1784. NewTemp(q);
  1785. Revive;
  1786. SymRef(name, ref);
  1787. W(" "); W(q); W(" =l loadl ");
  1788. WL(ref)
  1789. END LoadLong;
  1790. PROCEDURE StoreLong (name: ARRAY OF CHAR; q: ARRAY OF CHAR);
  1791. VAR idx : INTEGER;
  1792. levels : CARDINAL;
  1793. ref : QVal;
  1794. BEGIN
  1795. IF LocFindUp(name, levels, idx) THEN
  1796. IF levels = 0 THEN LocStoreFlat(idx, q, TRUE)
  1797. ELSE UpStore(idx, levels, q, TRUE)
  1798. END;
  1799. RETURN
  1800. END;
  1801. Revive;
  1802. SymRef(name, ref);
  1803. W(" storel "); W(q); W(", "); WL(ref)
  1804. END StoreLong;
  1805. PROCEDURE WidenLong (a: ARRAY OF CHAR; VAR q: QVal);
  1806. (* INTEGER (w) -> LONGINT (l) via extsw. *)
  1807. BEGIN
  1808. NewTemp(q);
  1809. Revive;
  1810. W(" "); W(q); W(" =l extsw "); WL(a)
  1811. END WidenLong;
  1812. PROCEDURE CmpLong (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal);
  1813. (* 64-bit comparison (result w). *)
  1814. VAR mn : ARRAY [0 .. 7] OF CHAR;
  1815. BEGIN
  1816. mn[0] := CHR(0);
  1817. IF op = SymTab.OpEq THEN Cpy(mn, "ceql")
  1818. ELSIF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN Cpy(mn, "cnel")
  1819. ELSIF op = SymTab.OpLt THEN Cpy(mn, "csltl")
  1820. ELSIF op = SymTab.OpLe THEN Cpy(mn, "cslel")
  1821. ELSIF op = SymTab.OpGt THEN Cpy(mn, "csgtl")
  1822. ELSE Cpy(mn, "csgel")
  1823. END;
  1824. NewTemp(q);
  1825. Op3(mn, q, l, r, FALSE)
  1826. END CmpLong;
  1827. PROCEDURE StoreVar (name: ARRAY OF CHAR; q: ARRAY OF CHAR; isReal: BOOLEAN);
  1828. VAR idx : INTEGER;
  1829. levels : CARDINAL;
  1830. ref : QVal;
  1831. BEGIN
  1832. IF LocFindUp(name, levels, idx) THEN
  1833. IF levels = 0 THEN LocStoreFlat(idx, q, FALSE)
  1834. ELSE UpStore(idx, levels, q, FALSE)
  1835. END;
  1836. RETURN
  1837. END;
  1838. Revive;
  1839. SymRef(name, ref);
  1840. IF isReal THEN W(" stored ") ELSE W(" storew ") END;
  1841. W(q); W(", "); WL(ref)
  1842. END StoreVar;
  1843. PROCEDURE StorePtr (name: ARRAY OF CHAR; q: ARRAY OF CHAR);
  1844. VAR idx : INTEGER;
  1845. levels : CARDINAL;
  1846. ref : QVal;
  1847. BEGIN
  1848. IF LocFindUp(name, levels, idx) THEN
  1849. IF levels = 0 THEN LocStoreFlat(idx, q, TRUE)
  1850. ELSE UpStore(idx, levels, q, TRUE)
  1851. END;
  1852. RETURN
  1853. END;
  1854. Revive;
  1855. SymRef(name, ref);
  1856. W(" storel "); W(q); W(", "); WL(ref)
  1857. END StorePtr;
  1858. PROCEDURE Op3 (mn: ARRAY OF CHAR; res, l, r: ARRAY OF CHAR;
  1859. isReal: BOOLEAN);
  1860. BEGIN
  1861. Revive;
  1862. W(" "); W(res);
  1863. IF isReal THEN W(" =d ") ELSE W(" =w ") END;
  1864. W(mn); W(" "); W(l); W(", "); WL(r)
  1865. END Op3;
  1866. PROCEDURE AbsQ (a: ARRAY OF CHAR; VAR q: QVal; isReal: BOOLEAN);
  1867. VAR c, neg : QVal;
  1868. lNeg, lPos, lDone : QVal;
  1869. BEGIN
  1870. IF isReal THEN Cmp(SymTab.OpLt, a, "d_0.0", c, TRUE)
  1871. ELSE Cmp(SymTab.OpLt, a, "0", c, FALSE)
  1872. END;
  1873. NewLabel(lNeg); NewLabel(lPos); NewLabel(lDone);
  1874. NewTemp(neg);
  1875. NegQ(a, neg, isReal);
  1876. Jnz(c, lNeg, lPos);
  1877. EmitLabel(lNeg);
  1878. CopyOp(neg, q);
  1879. Jmp(lDone);
  1880. EmitLabel(lPos);
  1881. CopyOp(a, q);
  1882. EmitLabel(lDone)
  1883. END AbsQ;
  1884. PROCEDURE NegQ (a: ARRAY OF CHAR; VAR q: QVal; isReal: BOOLEAN);
  1885. BEGIN
  1886. NewTemp(q);
  1887. IF isReal THEN Op3("sub", q, "d_0.0", a, TRUE)
  1888. ELSE Op3("sub", q, "0", a, FALSE)
  1889. END
  1890. END NegQ;
  1891. PROCEDURE ConvIR (a: ARRAY OF CHAR; VAR q: QVal);
  1892. (* INTEGER -> REAL widening for assignments (swtof). *)
  1893. BEGIN
  1894. NewTemp(q);
  1895. Revive;
  1896. W(" "); W(q); W(" =d swtof "); WL(a)
  1897. END ConvIR;
  1898. PROCEDURE NarrowLong (a: ARRAY OF CHAR; VAR q: QVal);
  1899. (* LONGINT (l) -> INTEGER (w): keep the low 32 bits. *)
  1900. BEGIN
  1901. NewTemp(q);
  1902. Revive;
  1903. W(" "); W(q); W(" =w copy "); WL(a)
  1904. END NarrowLong;
  1905. PROCEDURE ConvRI (a: ARRAY OF CHAR; VAR q: QVal);
  1906. (* REAL -> INTEGER (truncate toward zero). *)
  1907. BEGIN
  1908. NewTemp(q);
  1909. Revive;
  1910. W(" "); W(q); W(" =w dtosi "); WL(a)
  1911. END ConvRI;
  1912. PROCEDURE ConvRL (a: ARRAY OF CHAR; VAR q: QVal);
  1913. (* REAL -> LONGINT (truncate toward zero). *)
  1914. BEGIN
  1915. NewTemp(q);
  1916. Revive;
  1917. W(" "); W(q); W(" =l dtosi "); WL(a)
  1918. END ConvRL;
  1919. PROCEDURE ConvLR (a: ARRAY OF CHAR; VAR q: QVal);
  1920. (* LONGINT -> REAL. *)
  1921. BEGIN
  1922. NewTemp(q);
  1923. Revive;
  1924. W(" "); W(q); W(" =d sltof "); WL(a)
  1925. END ConvLR;
  1926. PROCEDURE NotQ (a: ARRAY OF CHAR; VAR q: QVal);
  1927. BEGIN
  1928. NewTemp(q);
  1929. Op3("xor", q, "1", a, FALSE)
  1930. END NotQ;
  1931. PROCEDURE CapQ (a: ARRAY OF CHAR; VAR q: QVal);
  1932. (* Branchless UPCASE: q := a - 32 * (a >= 'a' AND a <= 'z'). *)
  1933. VAR lo, hi, in1, delta: QVal;
  1934. BEGIN
  1935. NewTemp(lo); Op3("csgew", lo, a, "97", FALSE);
  1936. NewTemp(hi); Op3("cslew", hi, a, "122", FALSE);
  1937. NewTemp(in1); Op3("and", in1, lo, hi, FALSE);
  1938. NewTemp(delta); Op3("mul", delta, in1, "32", FALSE);
  1939. NewTemp(q); Op3("sub", q, a, delta, FALSE)
  1940. END CapQ;
  1941. PROCEDURE NewLabel (VAR l: QVal);
  1942. BEGIN
  1943. Cpy(l, "@L");
  1944. AppNum(l, nLab);
  1945. INC(nLab)
  1946. END NewLabel;
  1947. PROCEDURE Revive;
  1948. (* Opens an unreachable block if past a terminator. Keeps every
  1949. temporary defined and every instruction inside a block, even for
  1950. dead source tails (EXIT followed by more statements) and CASE
  1951. chains whose compares follow a Jmp. Counter-driven: fixpoint-safe. *)
  1952. VAR b: QVal;
  1953. BEGIN
  1954. IF opened AND dead THEN
  1955. NewLabel(b);
  1956. WL(b);
  1957. dead := FALSE
  1958. END
  1959. END Revive;
  1960. PROCEDURE EmitLabel (l: ARRAY OF CHAR);
  1961. BEGIN
  1962. WL(l);
  1963. dead := FALSE
  1964. END EmitLabel;
  1965. PROCEDURE Jmp (l: ARRAY OF CHAR);
  1966. BEGIN
  1967. IF dead THEN RETURN END; (* unreachable: a terminator with no
  1968. intervening label can never be reached; emitting it would end
  1969. the block and orphan whatever follows. *)
  1970. W(" jmp "); WL(l);
  1971. dead := TRUE
  1972. END Jmp;
  1973. PROCEDURE Jnz (c, t, f: ARRAY OF CHAR);
  1974. BEGIN
  1975. IF dead THEN RETURN END;
  1976. W(" jnz "); W(c); W(", "); W(t); W(", "); WL(f);
  1977. dead := TRUE
  1978. END Jnz;
  1979. PROCEDURE Cmp (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal;
  1980. isReal: BOOLEAN);
  1981. VAR mn : ARRAY [0 .. 7] OF CHAR;
  1982. BEGIN
  1983. mn[0] := CHR(0);
  1984. IF isReal THEN
  1985. IF op = SymTab.OpEq THEN Cpy(mn, "ceqd")
  1986. ELSIF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN Cpy(mn, "cned")
  1987. ELSIF op = SymTab.OpLt THEN Cpy(mn, "cltd")
  1988. ELSIF op = SymTab.OpLe THEN Cpy(mn, "cled")
  1989. ELSIF op = SymTab.OpGt THEN Cpy(mn, "cgtd")
  1990. ELSE Cpy(mn, "cged")
  1991. END
  1992. ELSE
  1993. IF op = SymTab.OpEq THEN Cpy(mn, "ceqw")
  1994. ELSIF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN Cpy(mn, "cnew")
  1995. ELSIF op = SymTab.OpLt THEN Cpy(mn, "csltw")
  1996. ELSIF op = SymTab.OpLe THEN Cpy(mn, "cslew")
  1997. ELSIF op = SymTab.OpGt THEN Cpy(mn, "csgtw")
  1998. ELSE Cpy(mn, "csgew")
  1999. END
  2000. END;
  2001. NewTemp(q);
  2002. Op3(mn, q, l, r, FALSE)
  2003. END Cmp;
  2004. PROCEDURE StrEq (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal);
  2005. (* String equality via the shim: q := (l = r) as a BOOLEAN, negated for
  2006. OpNeq. Operands are descriptor addresses; the shim strcmps the
  2007. NUL-terminated contents. *)
  2008. VAR t: QVal;
  2009. BEGIN
  2010. NewTemp(q);
  2011. W(" "); W(q); W(" =w call $m2streq(l ");
  2012. W(l); W(", l "); W(r); WL(")");
  2013. IF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN
  2014. NewTemp(t);
  2015. W(" "); W(t); W(" =w xor "); W(q); WL(", 1");
  2016. Cpy(q, t)
  2017. END
  2018. END StrEq;
  2019. PROCEDURE StrAssign (dst, src: ARRAY OF CHAR);
  2020. (* Copy the string src into the CHAR array at dst (content copy,
  2021. truncated to the destination capacity, NUL-terminated). *)
  2022. BEGIN
  2023. W(" call $m2strassign(l "); W(dst); W(", l "); W(src); WL(")")
  2024. END StrAssign;
  2025. PROCEDURE UAssign (dst, src: ARRAY OF CHAR);
  2026. (* Copy a U"..." descriptor (count + 4-byte codepoints) into the UCHAR
  2027. array at dst: min(count, capacity) codepoints + a 0 terminator. *)
  2028. BEGIN
  2029. W(" call $m2uassign(l "); W(dst); W(", l "); W(src); WL(")")
  2030. END UAssign;
  2031. PROCEDURE UStrLen (s: ARRAY OF CHAR; VAR q: QVal);
  2032. (* q := the UString codepoint count (INTEGER). *)
  2033. VAR t: QVal;
  2034. BEGIN
  2035. NewTemp(t);
  2036. W(" "); W(t); W(" =w call $m2ustrlen(l "); W(s); WL(")");
  2037. Cpy(q, t)
  2038. END UStrLen;
  2039. PROCEDURE DecQ (VAR q: QVal);
  2040. (* q := q - 1 (w domain; q is an INTEGER count). *)
  2041. VAR t: QVal;
  2042. BEGIN
  2043. NewTemp(t);
  2044. Op3("sub", t, q, "1", FALSE);
  2045. Cpy(q, t)
  2046. END DecQ;
  2047. PROCEDURE UStrCat (a, b: ARRAY OF CHAR; VAR q: QVal);
  2048. (* q := a + b (a UString descriptor in the shim's concat buffer). *)
  2049. BEGIN
  2050. NewTemp(q);
  2051. W(" "); W(q); W(" =l call $m2ustrcat(l "); W(a); W(", l "); W(b); WL(")")
  2052. END UStrCat;
  2053. PROCEDURE UStrFrom (cp: ARRAY OF CHAR; VAR q: QVal);
  2054. (* q := a 1-codepoint UString descriptor for the UCHAR value cp. *)
  2055. BEGIN
  2056. NewTemp(q);
  2057. W(" "); W(q); W(" =l call $m2ustrfrom(l "); W(cp); WL(")")
  2058. END UStrFrom;
  2059. PROCEDURE StrCat (a, b: ARRAY OF CHAR; VAR q: QVal);
  2060. (* q := a + b (a descriptor in the shim's concat buffer). *)
  2061. BEGIN
  2062. NewTemp(q);
  2063. W(" "); W(q); W(" =l call $m2strcat(l "); W(a); W(", l "); W(b); WL(")")
  2064. END StrCat;
  2065. (* ---------------- arrays: length-prefixed layout ---------------- *)
  2066. (* Indexes and counts are LONGCARD (l) in emitted code; immediates
  2067. pass through, w-temps widen via extsw. Traps call $abort + hlt
  2068. (interim; runtime/syslib/Trap replaces them later). *)
  2069. PROCEDURE ElemCls (t: SymTab.TypeIndex): INTEGER;
  2070. BEGIN
  2071. RETURN SymTab.ClassOf(SymTab.ArrayElem(t))
  2072. END ElemCls;
  2073. PROCEDURE ElemSize (t: SymTab.TypeIndex): CARDINAL;
  2074. (* Storage size of t's elements: CHAR 1, REAL 8, nested/pointer/long 8,
  2075. records/classes/sets their inline footprint, else 4. t is an array
  2076. (or string) descriptor. *)
  2077. VAR cls: INTEGER; et: SymTab.TypeIndex;
  2078. BEGIN
  2079. cls := SymTab.ClassOf(t);
  2080. IF cls = SymTab.ClStr THEN RETURN 1 END;
  2081. et := SymTab.ArrayElem(t);
  2082. cls := SymTab.ClassOf(et);
  2083. IF (cls = SymTab.ClChar) OR (cls = SymTab.ClByte)
  2084. OR (cls = SymTab.ClSByte) THEN RETURN 1
  2085. ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN RETURN 2
  2086. ELSIF cls = SymTab.ClReal THEN RETURN 8
  2087. ELSIF (cls = SymTab.ClArray) OR (cls = SymTab.ClPtr)
  2088. OR (cls = SymTab.ClLong) THEN RETURN 8
  2089. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass)
  2090. OR (cls = SymTab.ClSet) THEN
  2091. RETURN SymTab.TypeSize(et)
  2092. ELSE RETURN 4
  2093. END
  2094. END ElemSize;
  2095. PROCEDURE Op3L (mn: ARRAY OF CHAR; res, l, r: ARRAY OF CHAR);
  2096. BEGIN
  2097. Revive;
  2098. W(" "); W(res);
  2099. W(" =l ");
  2100. W(mn); W(" "); W(l); W(", "); WL(r)
  2101. END Op3L;
  2102. PROCEDURE HaltQ;
  2103. BEGIN
  2104. Revive;
  2105. WL(" call $exit(w 1)");
  2106. WL(" hlt");
  2107. dead := TRUE
  2108. END HaltQ;
  2109. PROCEDURE TrapCode (code: CARDINAL);
  2110. VAR q: QVal;
  2111. BEGIN
  2112. Revive;
  2113. IntStr(VAL(INTEGER, code), q);
  2114. W(" call $m2_exc_raise_lang(w "); W(q); WL(")");
  2115. WL(" hlt");
  2116. dead := TRUE
  2117. END TrapCode;
  2118. PROCEDURE Trap;
  2119. BEGIN
  2120. TrapCode(12) (* sysException *)
  2121. END Trap;
  2122. (* ---------------- records: flat blobs, pointer fields ---------------- *)
  2123. (* Scalars/sets inline, array fields as inline descriptors (8-byte length
  2124. word + data), nested records inline. Static offsets throughout. *)
  2125. PROCEDURE HasArrayField (t: SymTab.TypeIndex): BOOLEAN;
  2126. (* TRUE when record type t (recursively) has any ARRAY field. Such
  2127. record arrays need per-element expansion so each inline array field's
  2128. descriptor length word is initialised; a compact zero blob would
  2129. leave the count 0 and trap when the field is passed as an open array.
  2130. Records with no array field still stay a compact blob. *)
  2131. VAR i: CARDINAL; fn: SymTab.Name; ft: SymTab.TypeIndex; cls: INTEGER;
  2132. BEGIN
  2133. i := 0;
  2134. WHILE i < SymTab.FieldCount(t) DO
  2135. SymTab.FieldName(t, i, fn);
  2136. ft := SymTab.FieldType(t, fn);
  2137. cls := SymTab.ClassOf(ft);
  2138. IF cls = SymTab.ClArray THEN RETURN TRUE
  2139. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  2140. IF HasArrayField(ft) THEN RETURN TRUE END
  2141. END;
  2142. INC(i)
  2143. END;
  2144. RETURN FALSE
  2145. END HasArrayField;
  2146. PROCEDURE HasMultiArrayField (t: SymTab.TypeIndex): BOOLEAN;
  2147. (* TRUE when a record/class contains a rank-2/3 array field, directly
  2148. or in a nested record. Such record constructors need the runtime
  2149. path so the flat field payload is handled by a view. *)
  2150. VAR i: CARDINAL; fn: SymTab.Name; ft: SymTab.TypeIndex; cls: INTEGER;
  2151. BEGIN
  2152. i := 0;
  2153. WHILE i < SymTab.FieldCount(t) DO
  2154. SymTab.FieldName(t, i, fn);
  2155. ft := SymTab.FieldType(t, fn);
  2156. cls := SymTab.ClassOf(ft);
  2157. IF (cls = SymTab.ClArray) AND SymTab.IsMultiArray(ft) THEN
  2158. RETURN TRUE
  2159. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  2160. IF HasMultiArrayField(ft) THEN RETURN TRUE END
  2161. END;
  2162. INC(i)
  2163. END;
  2164. RETURN FALSE
  2165. END HasMultiArrayField;
  2166. PROCEDURE RecArrayExpanded (n: CARDINAL; t: INTEGER): BOOLEAN;
  2167. (* TRUE when a record-/class-array's per-element expansion fits the image
  2168. budget. Larger tables keep the compact zero blob and are instead
  2169. initialised at run time (RecArrayNeedsInit/InitRecArray). The budget
  2170. keeps the compiler's own huge tables (AST.arena: 262144 records) from
  2171. inflating the 4 MiB image. *)
  2172. BEGIN
  2173. RETURN VAL(INTEGER, n) * VAL(INTEGER, SymTab.TypeSize(t)) <= 131072
  2174. END RecArrayExpanded;
  2175. PROCEDURE ArrBodyItems (prefix: ARRAY OF CHAR; t: INTEGER);
  2176. (* Inline contents of an array descriptor (no "data $name = {" wrapper
  2177. and no closing brace): "l <n>[, <elem>...]". Nested levels are
  2178. referenced as $prefix_i (emitted by ArrData). Record/class elements
  2179. with nested-array fields are expanded per element (EmitRec) so their
  2180. sub-descriptors are referenced; others stay a compact zero blob. *)
  2181. VAR n, i: CARDINAL;
  2182. elem: SymTab.TypeIndex;
  2183. ecls: INTEGER;
  2184. esz: CARDINAL;
  2185. bv, sub: QVal;
  2186. first: BOOLEAN;
  2187. (* One inline record: mirrors RecItems (same field order and comma
  2188. handling), but array fields recurse into the enclosing
  2189. ArrBodyItems. Nested here so no FORWARD declaration is needed. *)
  2190. PROCEDURE EmitRec (rt: SymTab.TypeIndex; rpre: ARRAY OF CHAR;
  2191. VAR first: BOOLEAN);
  2192. VAR i, k, w: CARDINAL;
  2193. fn: SymTab.Name;
  2194. ft: SymTab.TypeIndex;
  2195. cls: INTEGER;
  2196. rsub: QVal;
  2197. PROCEDURE Sep;
  2198. BEGIN
  2199. IF first THEN first := FALSE ELSE W(", ") END
  2200. END Sep;
  2201. BEGIN
  2202. i := 0;
  2203. WHILE i < SymTab.FieldCount(rt) DO
  2204. SymTab.FieldName(rt, i, fn);
  2205. ft := SymTab.FieldType(rt, fn);
  2206. cls := SymTab.ClassOf(ft);
  2207. IF cls = SymTab.ClReal THEN Sep; W("d 0")
  2208. ELSIF (cls = SymTab.ClChar) OR (cls = SymTab.ClByte)
  2209. OR (cls = SymTab.ClSByte) THEN Sep; W("b 0")
  2210. ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN
  2211. Sep; W("h 0")
  2212. ELSIF cls = SymTab.ClArray THEN
  2213. Sep;
  2214. IF SymTab.IsMultiArray(ft) THEN
  2215. W("z "); IntStr(VAL(INTEGER, SymTab.ArrayPayloadSize(ft)), rsub);
  2216. W(rsub)
  2217. ELSE
  2218. Cpy(rsub, rpre); App(rsub, "_"); App(rsub, fn);
  2219. ArrBodyItems(rsub, ft)
  2220. END
  2221. ELSIF cls = SymTab.ClSet THEN
  2222. w := SymTab.SetWords(ft);
  2223. IF w = 0 THEN w := 1 END;
  2224. Sep; W("w 0");
  2225. k := 1;
  2226. WHILE k < w DO W(", w 0"); INC(k) END
  2227. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  2228. Cpy(rsub, rpre); App(rsub, "_"); App(rsub, fn);
  2229. EmitRec(ft, rsub, first)
  2230. ELSE Sep; W("w 0")
  2231. END;
  2232. INC(i)
  2233. END
  2234. END EmitRec;
  2235. BEGIN
  2236. n := SymTab.ArrayLen(t);
  2237. elem := SymTab.ArrayElem(t);
  2238. ecls := SymTab.ClassOf(elem);
  2239. W("l ");
  2240. IntStr(VAL(INTEGER, n), bv);
  2241. W(bv);
  2242. IF ecls = SymTab.ClArray THEN
  2243. i := 0;
  2244. WHILE i < n DO
  2245. W(", l $"); W(prefix); W("_");
  2246. IntStr(VAL(INTEGER, i), bv);
  2247. W(bv);
  2248. INC(i)
  2249. END
  2250. ELSIF ((ecls = SymTab.ClRecord) OR (ecls = SymTab.ClClass))
  2251. AND HasArrayField(elem)
  2252. AND RecArrayExpanded(n, elem) THEN
  2253. i := 0;
  2254. WHILE i < n DO
  2255. Cpy(sub, prefix); App(sub, "_");
  2256. IntStr(VAL(INTEGER, i), bv); App(sub, bv);
  2257. first := FALSE;
  2258. EmitRec(elem, sub, first);
  2259. INC(i)
  2260. END
  2261. ELSE
  2262. IF ecls = SymTab.ClChar THEN
  2263. (* CHAR: n data bytes + one NUL terminator slot *)
  2264. W(", z ");
  2265. IntStr(VAL(INTEGER, n + 1), bv);
  2266. W(bv)
  2267. ELSIF ecls = SymTab.ClUChar THEN
  2268. (* UCHAR: n codepoints + one 0-codepoint terminator slot *)
  2269. W(", z ");
  2270. IntStr(VAL(INTEGER, (n + 1) * 4), bv);
  2271. W(bv)
  2272. ELSE
  2273. IF (ecls = SymTab.ClByte) OR (ecls = SymTab.ClSByte) THEN esz := 1
  2274. ELSIF (ecls = SymTab.ClWord16) OR (ecls = SymTab.ClSWord16) THEN esz := 2
  2275. ELSIF (ecls = SymTab.ClReal) OR (ecls = SymTab.ClPtr)
  2276. OR (ecls = SymTab.ClProc) OR (ecls = SymTab.ClLong) THEN esz := 8
  2277. ELSIF (ecls = SymTab.ClRecord) OR (ecls = SymTab.ClClass)
  2278. OR (ecls = SymTab.ClSet) THEN
  2279. (* inline footprint, not a fixed 4 (same fix as ElemSize) *)
  2280. esz := SymTab.TypeSize(elem)
  2281. ELSE esz := 4
  2282. END;
  2283. IF n > 0 THEN
  2284. W(", z ");
  2285. IntStr(VAL(INTEGER, n * esz), bv);
  2286. W(bv)
  2287. END
  2288. END
  2289. END
  2290. END ArrBodyItems;
  2291. PROCEDURE ArrData (name: ARRAY OF CHAR; t: INTEGER);
  2292. (* "data $name = { <items> }" plus, for nested levels, the recursive
  2293. sub-descriptor data $name_i. *)
  2294. VAR n, i: CARDINAL;
  2295. elem: SymTab.TypeIndex;
  2296. bv: QVal;
  2297. sub: QVal;
  2298. (* Mirrors RecStatics, but nested-array sub-descriptors recurse into
  2299. the enclosing ArrData. Nested here so no FORWARD is needed. *)
  2300. PROCEDURE EmitRecStatics (rpre: ARRAY OF CHAR; rt: SymTab.TypeIndex);
  2301. VAR k, j, an: CARDINAL;
  2302. fn: SymTab.Name;
  2303. ft, et: SymTab.TypeIndex;
  2304. cls: INTEGER;
  2305. rsub, bv2: QVal;
  2306. BEGIN
  2307. k := 0;
  2308. WHILE k < SymTab.FieldCount(rt) DO
  2309. SymTab.FieldName(rt, k, fn);
  2310. ft := SymTab.FieldType(rt, fn);
  2311. cls := SymTab.ClassOf(ft);
  2312. IF (cls = SymTab.ClArray) AND NOT SymTab.IsMultiArray(ft) THEN
  2313. et := SymTab.ArrayElem(ft);
  2314. IF SymTab.ClassOf(et) = SymTab.ClArray THEN
  2315. an := SymTab.ArrayLen(ft);
  2316. j := 0;
  2317. WHILE j < an DO
  2318. Cpy(rsub, rpre); App(rsub, "_"); App(rsub, fn);
  2319. App(rsub, "_");
  2320. IntStr(VAL(INTEGER, j), bv2);
  2321. App(rsub, bv2);
  2322. ArrData(rsub, et);
  2323. INC(j)
  2324. END
  2325. END
  2326. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  2327. Cpy(rsub, rpre); App(rsub, "_"); App(rsub, fn);
  2328. EmitRecStatics(rsub, ft)
  2329. END;
  2330. INC(k)
  2331. END
  2332. END EmitRecStatics;
  2333. BEGIN
  2334. IF NOT opened THEN RETURN END;
  2335. W("export data $"); W(name);
  2336. W(" = { ");
  2337. ArrBodyItems(name, t);
  2338. WL(" }");
  2339. elem := SymTab.ArrayElem(t);
  2340. IF SymTab.ClassOf(elem) = SymTab.ClArray THEN
  2341. n := SymTab.ArrayLen(t);
  2342. i := 0;
  2343. WHILE i < n DO
  2344. Cpy(sub, name); App(sub, "_");
  2345. IntStr(VAL(INTEGER, i), bv);
  2346. App(sub, bv);
  2347. ArrData(sub, elem);
  2348. INC(i)
  2349. END
  2350. ELSIF ((SymTab.ClassOf(elem) = SymTab.ClRecord)
  2351. OR (SymTab.ClassOf(elem) = SymTab.ClClass))
  2352. AND HasArrayField(elem)
  2353. AND RecArrayExpanded(SymTab.ArrayLen(t), elem) THEN
  2354. (* Sub-descriptors referenced (as $name_i_field_k) from the inline
  2355. items emitted by ArrBodyItems; one set per element. *)
  2356. n := SymTab.ArrayLen(t);
  2357. i := 0;
  2358. WHILE i < n DO
  2359. Cpy(sub, name); App(sub, "_");
  2360. IntStr(VAL(INTEGER, i), bv);
  2361. App(sub, bv);
  2362. EmitRecStatics(sub, elem);
  2363. INC(i)
  2364. END
  2365. END
  2366. END ArrData;
  2367. PROCEDURE RecStatics (recname: ARRAY OF CHAR; t: SymTab.TypeIndex);
  2368. (* Pre-pass: static sub-descriptors for NESTED array fields (the
  2369. top-level array field is now inline in the record), recursive. *)
  2370. VAR n, i, k, an: CARDINAL;
  2371. fn: SymTab.Name;
  2372. ft, et: SymTab.TypeIndex;
  2373. cls: INTEGER;
  2374. sub, bv: QVal;
  2375. BEGIN
  2376. n := SymTab.FieldCount(t);
  2377. i := 0;
  2378. WHILE i < n DO
  2379. SymTab.FieldName(t, i, fn);
  2380. ft := SymTab.FieldType(t, fn);
  2381. cls := SymTab.ClassOf(ft);
  2382. IF (cls = SymTab.ClArray) AND NOT SymTab.IsMultiArray(ft) THEN
  2383. et := SymTab.ArrayElem(ft);
  2384. IF SymTab.ClassOf(et) = SymTab.ClArray THEN
  2385. an := SymTab.ArrayLen(ft);
  2386. k := 0;
  2387. WHILE k < an DO
  2388. Cpy(sub, recname); App(sub, "_"); App(sub, fn);
  2389. App(sub, "_");
  2390. IntStr(VAL(INTEGER, k), bv);
  2391. App(sub, bv);
  2392. ArrData(sub, et);
  2393. INC(k)
  2394. END
  2395. END
  2396. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  2397. Cpy(sub, recname); App(sub, "_"); App(sub, fn);
  2398. RecStatics(sub, ft)
  2399. END;
  2400. INC(i)
  2401. END
  2402. END RecStatics;
  2403. PROCEDURE RecItems (t: SymTab.TypeIndex; prefix: ARRAY OF CHAR;
  2404. VAR first: BOOLEAN);
  2405. (* Comma-separated item list (no wrapper); nested records inline.
  2406. Emission order follows the (prepend-built) field chain, i.e.
  2407. reverse declaration; offsets (not positions) place everything. *)
  2408. VAR n, i, k, w: CARDINAL;
  2409. fn: SymTab.Name;
  2410. ft: SymTab.TypeIndex;
  2411. cls: INTEGER;
  2412. sub: QVal;
  2413. PROCEDURE Sep;
  2414. BEGIN
  2415. IF first THEN first := FALSE ELSE W(", ") END
  2416. END Sep;
  2417. BEGIN
  2418. n := SymTab.FieldCount(t);
  2419. i := 0;
  2420. WHILE i < n DO
  2421. SymTab.FieldName(t, i, fn);
  2422. ft := SymTab.FieldType(t, fn);
  2423. cls := SymTab.ClassOf(ft);
  2424. IF cls = SymTab.ClReal THEN Sep; W("d 0")
  2425. ELSIF (cls = SymTab.ClChar) OR (cls = SymTab.ClByte)
  2426. OR (cls = SymTab.ClSByte) THEN Sep; W("b 0")
  2427. ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN
  2428. Sep; W("h 0")
  2429. ELSIF cls = SymTab.ClArray THEN
  2430. Sep;
  2431. IF SymTab.IsMultiArray(ft) THEN
  2432. W("z "); IntStr(VAL(INTEGER, SymTab.ArrayPayloadSize(ft)), sub);
  2433. W(sub)
  2434. ELSE
  2435. Cpy(sub, prefix); App(sub, "_"); App(sub, fn);
  2436. ArrBodyItems(sub, ft)
  2437. END
  2438. ELSIF cls = SymTab.ClSet THEN
  2439. w := SymTab.SetWords(ft);
  2440. IF w = 0 THEN w := 1 END;
  2441. Sep; W("w 0");
  2442. k := 1;
  2443. WHILE k < w DO W(", w 0"); INC(k) END
  2444. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  2445. Cpy(sub, prefix); App(sub, "_"); App(sub, fn);
  2446. RecItems(ft, sub, first)
  2447. ELSIF (cls = SymTab.ClPtr) OR (cls = SymTab.ClLong)
  2448. OR (cls = SymTab.ClProc) THEN
  2449. (* 8-byte fields: match the layout's pointer/long size (a `w 0`
  2450. here would shrink the global and clobber the next symbol) *)
  2451. Sep; W("l 0")
  2452. ELSE Sep; W("w 0")
  2453. END;
  2454. INC(i)
  2455. END
  2456. END RecItems;
  2457. PROCEDURE VtRef (t: INTEGER; VAR q: QVal);
  2458. (* Stable vtable symbol: $<module>__<class>__vt. Fall back to a
  2459. module-qualified type index for anonymous types. *)
  2460. VAR bv: QVal; mod, nm: SymTab.Name;
  2461. BEGIN
  2462. IF SymTab.TypeStableName(t, mod, nm) THEN
  2463. Cpy(q, "$"); App(q, mod); App(q, "__"); App(q, nm); App(q, "__vt")
  2464. ELSE
  2465. Cpy(q, "$");
  2466. App(q, curModName);
  2467. App(q, "_vt_");
  2468. IntStr(t, bv);
  2469. App(q, bv)
  2470. END
  2471. END VtRef;
  2472. PROCEDURE EmitVTables;
  2473. (* One data array per class with a vtable: slots (inherited first) as
  2474. method code addresses. *)
  2475. VAR k, j, n: CARDINAL;
  2476. t: INTEGER;
  2477. nm, cname, cmod: SymTab.Name;
  2478. mg, vt: QVal;
  2479. own: BOOLEAN;
  2480. BEGIN
  2481. IF NOT opened THEN RETURN END;
  2482. k := 0;
  2483. WHILE k < SymTab.VtClassCount() DO
  2484. t := SymTab.VtClassAt(k);
  2485. own := TRUE;
  2486. IF SymTab.TypeStableName(t, cmod, cname) THEN
  2487. own := SymTab.Equal(cmod, curModName) OR NOT separateMode
  2488. END;
  2489. IF own THEN
  2490. n := SymTab.VtCount(t);
  2491. VtRef(t, vt);
  2492. W("export data "); W(vt); W(" = { ");
  2493. j := 0;
  2494. WHILE j < n DO
  2495. IF SymTab.VtName(t, j, nm) THEN
  2496. IF j > 0 THEN W(", ") END;
  2497. IF SymTab.VtHasBody(t, j) THEN
  2498. Mangled(nm, SymTab.VtUid(t, j), mg);
  2499. W("l $"); W(mg)
  2500. ELSE
  2501. W("l 0") (* declared but never implemented *)
  2502. END
  2503. END;
  2504. INC(j)
  2505. END;
  2506. IF n = 0 THEN W("l 0") END;
  2507. WL(" }")
  2508. END;
  2509. INC(k)
  2510. END
  2511. END EmitVTables;
  2512. PROCEDURE DeclRec (name: ARRAY OF CHAR; t: INTEGER);
  2513. VAR first: BOOLEAN;
  2514. vt, sz: QVal;
  2515. BEGIN
  2516. IF NOT opened THEN RETURN END;
  2517. IF SymTab.IsVariant(t) AND (SymTab.ClassOf(t) = SymTab.ClRecord) THEN
  2518. (* variant record: fields overlay, so emit one zero-filled blob
  2519. of the record's (max) size *)
  2520. IntStr(VAL(INTEGER, SymTab.TypeSize(t)), sz);
  2521. W("export data $"); W(name); W(" = { z "); W(sz); WL(" }");
  2522. RETURN
  2523. END;
  2524. RecStatics(name, t);
  2525. W("export data $"); W(name);
  2526. W(" = { ");
  2527. first := TRUE;
  2528. (* a class with a vtable stores its vtable pointer at offset 0 *)
  2529. IF (SymTab.ClassOf(t) = SymTab.ClClass) AND SymTab.HasVTable(t) THEN
  2530. VtRef(t, vt);
  2531. W("l "); W(vt);
  2532. first := FALSE
  2533. END;
  2534. RecItems(t, name, first);
  2535. IF first THEN W("w 0") END;
  2536. WL(" }")
  2537. END DeclRec;
  2538. PROCEDURE FieldAddr (base: ARRAY OF CHAR; off: INTEGER; VAR q: QVal);
  2539. VAR sb: QVal;
  2540. BEGIN
  2541. NewTemp(q);
  2542. IntStr(off, sb);
  2543. Op3L("add", q, base, sb)
  2544. END FieldAddr;
  2545. PROCEDURE ThisBase (VAR q: QVal);
  2546. (* The current method's receiver address (the hidden THIS VAR param). *)
  2547. BEGIN
  2548. AddrOf("THIS", q)
  2549. END ThisBase;
  2550. PROCEDURE PushWith (base: ARRAY OF CHAR);
  2551. BEGIN
  2552. IF withTop <= HIGH(withSt) THEN
  2553. Cpy(withSt[withTop], base); INC(withTop)
  2554. END
  2555. END PushWith;
  2556. PROCEDURE PopWith;
  2557. BEGIN
  2558. IF withTop > 0 THEN DEC(withTop) END
  2559. END PopWith;
  2560. PROCEDURE TopWith (VAR base: QVal): BOOLEAN;
  2561. BEGIN
  2562. IF withTop = 0 THEN RETURN FALSE END;
  2563. Cpy(base, withSt[withTop - 1]);
  2564. RETURN TRUE
  2565. END TopWith;
  2566. PROCEDURE CopyRecord (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  2567. t: INTEGER);
  2568. (* Whole-record copy: a flat byte blit of the record's (max) size.
  2569. Records are flat blobs (scalars/sets/pointers inline, arrays and
  2570. nested records inline), so this is correct — and the only correct
  2571. choice for variant records, whose fields overlay. *)
  2572. VAR n: QVal;
  2573. BEGIN
  2574. IntStr(VAL(INTEGER, SymTab.TypeSize(t)), n);
  2575. Revive;
  2576. W(" call $memcpy(l "); W(dst); W(", l "); W(src);
  2577. W(", l "); W(n); WL(")")
  2578. END CopyRecord;
  2579. PROCEDURE WordsBytes (words: CARDINAL): CARDINAL;
  2580. BEGIN
  2581. IF words = 0 THEN RETURN 8 END;
  2582. RETURN ((words * 4 + 7) DIV 8) * 8
  2583. END WordsBytes;
  2584. PROCEDURE DeclSet (name: ARRAY OF CHAR; t: INTEGER);
  2585. VAR w, i: CARDINAL;
  2586. BEGIN
  2587. IF NOT opened THEN RETURN END;
  2588. w := SymTab.SetWords(t);
  2589. IF w = 0 THEN w := 1 END;
  2590. W("export data $"); W(name);
  2591. W(" = { w 0");
  2592. i := 1;
  2593. WHILE i < w DO
  2594. W(", w 0");
  2595. INC(i)
  2596. END;
  2597. WL(" }")
  2598. END DeclSet;
  2599. PROCEDURE PoolSet (mask: ARRAY OF CARDINAL; words: CARDINAL; VAR q: QVal);
  2600. VAR k: CARDINAL;
  2601. BEGIN
  2602. IF NOT opened OR noEmit THEN Cpy(q, "0"); RETURN END;
  2603. IF setN > HIGH(setW) THEN Cpy(q, "0"); RETURN END;
  2604. k := 0;
  2605. WHILE (k < words) AND (k <= HIGH(mask)) AND (k <= 15) DO
  2606. setMask[setN][k] := mask[k]; INC(k)
  2607. END;
  2608. WHILE k <= 15 DO setMask[setN][k] := 0; INC(k) END;
  2609. setW[setN] := words;
  2610. Cpy(setNam[setN], curModName); App(setNam[setN], "_set");
  2611. AppNum(setNam[setN], setN);
  2612. Cpy(q, "$"); App(q, setNam[setN]);
  2613. INC(setN)
  2614. END PoolSet;
  2615. PROCEDURE PoolSetNamed (name: ARRAY OF CHAR; mask: ARRAY OF CARDINAL;
  2616. words: CARDINAL; VAR q: QVal);
  2617. (* Like PoolSet but registers the descriptor as `data $<name>` — used for
  2618. a module-level set CONST, whose global name (<unit>_<const>) is what a
  2619. client's qualified reference emits. *)
  2620. VAR k: CARDINAL;
  2621. BEGIN
  2622. IF NOT opened OR noEmit THEN Cpy(q, "0"); RETURN END;
  2623. IF setN > HIGH(setW) THEN Cpy(q, "0"); RETURN END;
  2624. k := 0;
  2625. WHILE (k < words) AND (k <= HIGH(mask)) AND (k <= 15) DO
  2626. setMask[setN][k] := mask[k]; INC(k)
  2627. END;
  2628. WHILE k <= 15 DO setMask[setN][k] := 0; INC(k) END;
  2629. setW[setN] := words;
  2630. Cpy(setNam[setN], name);
  2631. Cpy(q, "$"); App(q, name);
  2632. INC(setN)
  2633. END PoolSetNamed;
  2634. PROCEDURE NewSetTemp (words: CARDINAL; VAR q: QVal);
  2635. VAR nb: QVal;
  2636. BEGIN
  2637. NewTemp(q);
  2638. Revive;
  2639. IntStr(VAL(INTEGER, WordsBytes(words)), nb);
  2640. W(" "); W(q); W(" =l alloc8 "); WL(nb)
  2641. END NewSetTemp;
  2642. PROCEDURE SetZero (addr: ARRAY OF CHAR; words: CARDINAL);
  2643. VAR i: CARDINAL;
  2644. a, z, off: QVal;
  2645. BEGIN
  2646. NewTemp(z);
  2647. Op3("xor", z, "0", "0", FALSE);
  2648. i := 0;
  2649. WHILE i < words DO
  2650. NewTemp(a);
  2651. IntStr(VAL(INTEGER, i * 4), off);
  2652. Op3L("add", a, addr, off);
  2653. Revive;
  2654. W(" storew "); W(z); W(", "); WL(a);
  2655. INC(i)
  2656. END
  2657. END SetZero;
  2658. PROCEDURE SetBit (addr: ARRAY OF CHAR; val: ARRAY OF CHAR;
  2659. lo: INTEGER; span: CARDINAL);
  2660. (* ORs one element in: off = val - lo trapped in [0, span). *)
  2661. VAR off, offL, hiS, loS: QVal;
  2662. wi, bi, wil, off4, wa, wcur, m, wn: QVal;
  2663. BEGIN
  2664. NewTemp(off);
  2665. IntStr(lo, loS);
  2666. Op3("sub", off, val, loS, FALSE);
  2667. WidenIndex(off, offL);
  2668. IntStr(VAL(INTEGER, span) - 1, hiS);
  2669. CheckRange(offL, "0", hiS);
  2670. NewTemp(wi);
  2671. Op3("shr", wi, off, "5", FALSE);
  2672. NewTemp(bi);
  2673. Op3("and", bi, off, "31", FALSE);
  2674. WidenIndex(wi, wil);
  2675. NewTemp(off4);
  2676. Op3L("mul", off4, wil, "4");
  2677. NewTemp(wa);
  2678. Op3L("add", wa, addr, off4);
  2679. NewTemp(m);
  2680. Op3("shl", m, "1", bi, FALSE);
  2681. NewTemp(wcur);
  2682. W(" "); W(wcur); W(" =w loadw "); WL(wa);
  2683. NewTemp(wn);
  2684. Op3("or", wn, wcur, m, FALSE);
  2685. Revive;
  2686. W(" storew "); W(wn); W(", "); WL(wa)
  2687. END SetBit;
  2688. PROCEDURE SetClearBit (addr: ARRAY OF CHAR; val: ARRAY OF CHAR;
  2689. lo: INTEGER; span: CARDINAL);
  2690. (* ANDs one element out: off = val - lo trapped in [0, span). *)
  2691. VAR off, offL, hiS, loS: QVal;
  2692. wi, bi, wil, off4, wa, wcur, m, nm, wn: QVal;
  2693. BEGIN
  2694. NewTemp(off);
  2695. IntStr(lo, loS);
  2696. Op3("sub", off, val, loS, FALSE);
  2697. WidenIndex(off, offL);
  2698. IntStr(VAL(INTEGER, span) - 1, hiS);
  2699. CheckRange(offL, "0", hiS);
  2700. NewTemp(wi);
  2701. Op3("shr", wi, off, "5", FALSE);
  2702. NewTemp(bi);
  2703. Op3("and", bi, off, "31", FALSE);
  2704. WidenIndex(wi, wil);
  2705. NewTemp(off4);
  2706. Op3L("mul", off4, wil, "4");
  2707. NewTemp(wa);
  2708. Op3L("add", wa, addr, off4);
  2709. NewTemp(m);
  2710. Op3("shl", m, "1", bi, FALSE);
  2711. NewTemp(nm);
  2712. Op3("xor", nm, m, "-1", FALSE);
  2713. NewTemp(wcur);
  2714. W(" "); W(wcur); W(" =w loadw "); WL(wa);
  2715. NewTemp(wn);
  2716. Op3("and", wn, wcur, nm, FALSE);
  2717. Revive;
  2718. W(" storew "); W(wn); W(", "); WL(wa)
  2719. END SetClearBit;
  2720. PROCEDURE SetShift (src: ARRAY OF CHAR; n: ARRAY OF CHAR;
  2721. words: CARDINAL; span: CARDINAL; isRot: BOOLEAN;
  2722. VAR q: QVal);
  2723. (* Bit-by-bit shift/rotate by a runtime amount n over [0, span);
  2724. bits that leave the span are dropped (SHIFT) or wrapped (ROTATE). *)
  2725. VAR out, nn, sp, hi, i: QVal;
  2726. wi, bi, wil, off4, wa, m, t, bit, nzb: QVal;
  2727. j, c, cs, jw: QVal;
  2728. ok1, ok2, ok, sj, wj, bj, wjl, o2, wb2, mm, mm2, mm3: QVal;
  2729. wcur, wn, ip1: QVal;
  2730. ltop, lbody, lend: QVal;
  2731. BEGIN
  2732. NewSetTemp(words, out);
  2733. SetZero(out, words);
  2734. Cpy(nn, n);
  2735. IntStr(VAL(INTEGER, span), sp);
  2736. IntStr(VAL(INTEGER, span) - 1, hi);
  2737. IF isRot THEN
  2738. NewTemp(j); Op3("rem", j, n, sp, FALSE);
  2739. NewTemp(ok1); Op3("add", ok1, j, sp, FALSE);
  2740. NewTemp(cs); Op3("rem", cs, ok1, sp, FALSE);
  2741. Cpy(nn, cs)
  2742. END;
  2743. NewTemp(i); Op3("add", i, "0", "0", FALSE);
  2744. NewLabel(ltop); NewLabel(lbody); NewLabel(lend);
  2745. EmitLabel(ltop);
  2746. NewTemp(c); Op3("cslew", c, i, hi, FALSE);
  2747. Jnz(c, lbody, lend);
  2748. EmitLabel(lbody);
  2749. NewTemp(wi); Op3("shr", wi, i, "5", FALSE);
  2750. NewTemp(bi); Op3("and", bi, i, "31", FALSE);
  2751. WidenIndex(wi, wil);
  2752. NewTemp(off4); Op3L("mul", off4, wil, "4");
  2753. NewTemp(wa); Op3L("add", wa, src, off4);
  2754. NewTemp(m); Op3("shl", m, "1", bi, FALSE);
  2755. NewTemp(t); W(" "); W(t); W(" =w loadw "); WL(wa);
  2756. NewTemp(bit); Op3("and", bit, t, m, FALSE);
  2757. NewTemp(nzb); Op3("cnew", nzb, bit, "0", FALSE);
  2758. NewTemp(j); Op3("add", j, i, nn, FALSE);
  2759. IF isRot THEN
  2760. NewTemp(c); Op3("csgew", c, j, sp, FALSE);
  2761. NewTemp(cs); Op3("mul", cs, c, sp, FALSE);
  2762. NewTemp(jw); Op3("sub", jw, j, cs, FALSE);
  2763. Cpy(j, jw)
  2764. END;
  2765. NewTemp(ok1); Op3("csgew", ok1, j, "0", FALSE);
  2766. NewTemp(ok2); Op3("cslew", ok2, j, hi, FALSE);
  2767. NewTemp(ok); Op3("and", ok, ok1, ok2, FALSE);
  2768. (* a dropped bit must still address a *valid* word: clamp the index
  2769. to 0 when out of range, so the load below cannot fault (the store
  2770. is already masked to a no-op by ok via mm3) *)
  2771. NewTemp(sj); Op3("mul", sj, j, ok, FALSE);
  2772. NewTemp(wj); Op3("shr", wj, sj, "5", FALSE);
  2773. NewTemp(bj); Op3("and", bj, sj, "31", FALSE);
  2774. WidenIndex(wj, wjl);
  2775. NewTemp(o2); Op3L("mul", o2, wjl, "4");
  2776. NewTemp(wb2); Op3L("add", wb2, out, o2);
  2777. NewTemp(mm); Op3("shl", mm, "1", bj, FALSE);
  2778. NewTemp(mm2); Op3("mul", mm2, mm, nzb, FALSE);
  2779. NewTemp(mm3); Op3("mul", mm3, mm2, ok, FALSE);
  2780. NewTemp(wcur); W(" "); W(wcur); W(" =w loadw "); WL(wb2);
  2781. NewTemp(wn); Op3("or", wn, wcur, mm3, FALSE);
  2782. Revive;
  2783. W(" storew "); W(wn); W(", "); WL(wb2);
  2784. Op3("add", i, i, "1", FALSE);
  2785. Jmp(ltop);
  2786. EmitLabel(lend);
  2787. Cpy(q, out)
  2788. END SetShift;
  2789. PROCEDURE SetRange (addr: ARRAY OF CHAR; a: ARRAY OF CHAR;
  2790. b: ARRAY OF CHAR; lo: INTEGER; span: CARDINAL);
  2791. VAR al, bl, hiS: QVal;
  2792. cur, c: QVal;
  2793. ltop, lbody, lend: QVal;
  2794. BEGIN
  2795. WidenIndex(a, al);
  2796. WidenIndex(b, bl);
  2797. IntStr(VAL(INTEGER, span) - 1, hiS);
  2798. CheckRange(al, "0", hiS);
  2799. CheckRange(bl, "0", hiS);
  2800. NewTemp(cur);
  2801. Op3("add", cur, a, "0", FALSE);
  2802. NewLabel(ltop); NewLabel(lbody); NewLabel(lend);
  2803. EmitLabel(ltop);
  2804. NewTemp(c);
  2805. Op3("cslew", c, cur, b, FALSE);
  2806. Jnz(c, lbody, lend);
  2807. EmitLabel(lbody);
  2808. SetBit(addr, cur, lo, span);
  2809. Op3("add", cur, cur, "1", FALSE);
  2810. Jmp(ltop);
  2811. EmitLabel(lend)
  2812. END SetRange;
  2813. PROCEDURE SetBinOp (sel: INTEGER; l: ARRAY OF CHAR; r: ARRAY OF CHAR;
  2814. lw, rw: CARDINAL; VAR q: QVal);
  2815. (* Union/intersection/difference/symdiff over possibly different
  2816. spans: overlap via op, larger-side extras copied (union/symdiff/
  2817. left-diff) or zeroed. Result has max words. *)
  2818. VAR i, m, res: CARDINAL;
  2819. la, ra, ta, a, b, c, nb, z: QVal;
  2820. BEGIN
  2821. m := lw;
  2822. IF rw < m THEN m := rw END;
  2823. res := lw;
  2824. IF rw > res THEN res := rw END;
  2825. NewSetTemp(res, q);
  2826. NewTemp(z);
  2827. Op3("xor", z, "0", "0", FALSE);
  2828. i := 0;
  2829. WHILE i < m DO
  2830. IntStr(VAL(INTEGER, i * 4), nb);
  2831. NewTemp(la); Op3L("add", la, l, nb);
  2832. NewTemp(ra); Op3L("add", ra, r, nb);
  2833. NewTemp(ta); Op3L("add", ta, q, nb);
  2834. NewTemp(a);
  2835. W(" "); W(a); W(" =w loadw "); WL(la);
  2836. NewTemp(b);
  2837. W(" "); W(b); W(" =w loadw "); WL(ra);
  2838. NewTemp(c);
  2839. IF sel = 0 THEN Op3("or", c, a, b, FALSE)
  2840. ELSIF sel = 1 THEN Op3("and", c, a, b, FALSE)
  2841. ELSIF sel = 2 THEN
  2842. NewTemp(nb);
  2843. Op3("xor", nb, b, "-1", FALSE);
  2844. Op3("and", c, a, nb, FALSE)
  2845. ELSE Op3("xor", c, a, b, FALSE)
  2846. END;
  2847. Revive;
  2848. W(" storew "); W(c); W(", "); WL(ta);
  2849. INC(i)
  2850. END;
  2851. WHILE i < lw DO
  2852. IntStr(VAL(INTEGER, i * 4), nb);
  2853. NewTemp(la); Op3L("add", la, l, nb);
  2854. NewTemp(ta); Op3L("add", ta, q, nb);
  2855. IF (sel = 0) OR (sel = 2) OR (sel = 3) THEN
  2856. NewTemp(a);
  2857. W(" "); W(a); W(" =w loadw "); WL(la);
  2858. Revive;
  2859. W(" storew "); W(a); W(", "); WL(ta)
  2860. ELSE
  2861. Revive;
  2862. W(" storew "); W(z); W(", "); WL(ta)
  2863. END;
  2864. INC(i)
  2865. END;
  2866. WHILE i < rw DO
  2867. IntStr(VAL(INTEGER, i * 4), nb);
  2868. NewTemp(ra); Op3L("add", ra, r, nb);
  2869. NewTemp(ta); Op3L("add", ta, q, nb);
  2870. IF (sel = 0) OR (sel = 3) THEN
  2871. NewTemp(b);
  2872. W(" "); W(b); W(" =w loadw "); WL(ra);
  2873. Revive;
  2874. W(" storew "); W(b); W(", "); WL(ta)
  2875. ELSE
  2876. Revive;
  2877. W(" storew "); W(z); W(", "); WL(ta)
  2878. END;
  2879. INC(i)
  2880. END
  2881. END SetBinOp;
  2882. PROCEDURE CmpSet (op: INTEGER; l: ARRAY OF CHAR; r: ARRAY OF CHAR;
  2883. lw, rw: CARDINAL; VAR q: QVal);
  2884. VAR i, m: CARDINAL;
  2885. la, ra, a, b, c, acc, nb: QVal;
  2886. BEGIN
  2887. NewTemp(acc);
  2888. Op3("xor", acc, "1", "0", FALSE);
  2889. m := lw;
  2890. IF rw < m THEN m := rw END;
  2891. i := 0;
  2892. WHILE i < m DO
  2893. IntStr(VAL(INTEGER, i * 4), nb);
  2894. NewTemp(la); Op3L("add", la, l, nb);
  2895. NewTemp(ra); Op3L("add", ra, r, nb);
  2896. NewTemp(a);
  2897. W(" "); W(a); W(" =w loadw "); WL(la);
  2898. NewTemp(b);
  2899. W(" "); W(b); W(" =w loadw "); WL(ra);
  2900. NewTemp(c);
  2901. Op3("ceqw", c, a, b, FALSE);
  2902. NewTemp(q);
  2903. Op3("and", q, acc, c, FALSE);
  2904. CopyOp(q, acc);
  2905. INC(i)
  2906. END;
  2907. WHILE i < lw DO
  2908. IntStr(VAL(INTEGER, i * 4), nb);
  2909. NewTemp(la); Op3L("add", la, l, nb);
  2910. NewTemp(a);
  2911. W(" "); W(a); W(" =w loadw "); WL(la);
  2912. NewTemp(c);
  2913. Op3("ceqw", c, a, "0", FALSE);
  2914. NewTemp(q);
  2915. Op3("and", q, acc, c, FALSE);
  2916. CopyOp(q, acc);
  2917. INC(i)
  2918. END;
  2919. WHILE i < rw DO
  2920. IntStr(VAL(INTEGER, i * 4), nb);
  2921. NewTemp(ra); Op3L("add", ra, r, nb);
  2922. NewTemp(b);
  2923. W(" "); W(b); W(" =w loadw "); WL(ra);
  2924. NewTemp(c);
  2925. Op3("ceqw", c, b, "0", FALSE);
  2926. NewTemp(q);
  2927. Op3("and", q, acc, c, FALSE);
  2928. CopyOp(q, acc);
  2929. INC(i)
  2930. END;
  2931. IF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN
  2932. NewTemp(q);
  2933. Op3("xor", q, acc, "1", FALSE)
  2934. ELSE
  2935. CopyOp(acc, q)
  2936. END
  2937. END CmpSet;
  2938. PROCEDURE LoadPacked (addr: ARRAY OF CHAR; t: INTEGER; VAR q: QVal);
  2939. VAR nb: CARDINAL;
  2940. BEGIN
  2941. nb := SymTab.SetBytes(t);
  2942. NewTemp(q);
  2943. Revive;
  2944. W(" "); W(q);
  2945. IF nb = 1 THEN W(" =w loadub ")
  2946. ELSIF nb = 2 THEN W(" =w loaduh ")
  2947. ELSE W(" =w loadw ")
  2948. END;
  2949. WL(addr)
  2950. END LoadPacked;
  2951. PROCEDURE StorePacked (addr: ARRAY OF CHAR; t: INTEGER;
  2952. v: ARRAY OF CHAR);
  2953. VAR nb: CARDINAL;
  2954. BEGIN
  2955. nb := SymTab.SetBytes(t);
  2956. Revive;
  2957. IF nb = 1 THEN W(" storeb ")
  2958. ELSIF nb = 2 THEN W(" storeh ")
  2959. ELSE W(" storew ")
  2960. END;
  2961. W(v); W(", "); WL(addr)
  2962. END StorePacked;
  2963. PROCEDURE CopySetVal (dst: ARRAY OF CHAR; dt: INTEGER;
  2964. src: ARRAY OF CHAR; et: INTEGER);
  2965. VAR q: QVal;
  2966. BEGIN
  2967. IF SymTab.IsPackedSet(dt) THEN
  2968. IF SymTab.IsPackedSet(et) THEN LoadPacked(src, et, q)
  2969. ELSE LoadW(src, q)
  2970. END;
  2971. StorePacked(dst, dt, q)
  2972. ELSIF SymTab.IsPackedSet(et) THEN
  2973. SetZero(dst, SymTab.SetWords(dt));
  2974. LoadPacked(src, et, q);
  2975. StoreW(dst, q)
  2976. ELSE CopySet(dst, src, SymTab.SetWords(dt), SymTab.SetWords(et))
  2977. END
  2978. END CopySetVal;
  2979. PROCEDURE PackedSetBit (addr: ARRAY OF CHAR; t: INTEGER;
  2980. val: ARRAY OF CHAR; lo: INTEGER; span: CARDINAL);
  2981. VAR off, offL, hiS, loS, m, old, nv: QVal;
  2982. BEGIN
  2983. NewTemp(off);
  2984. IntStr(lo, loS);
  2985. Op3("sub", off, val, loS, FALSE);
  2986. WidenIndex(off, offL);
  2987. IntStr(VAL(INTEGER, span) - 1, hiS);
  2988. CheckRange(offL, "0", hiS);
  2989. NewTemp(m);
  2990. Op3("shl", m, "1", off, FALSE);
  2991. LoadPacked(addr, t, old);
  2992. NewTemp(nv);
  2993. Op3("or", nv, old, m, FALSE);
  2994. StorePacked(addr, t, nv)
  2995. END PackedSetBit;
  2996. PROCEDURE PackedSetClearBit (addr: ARRAY OF CHAR; t: INTEGER;
  2997. val: ARRAY OF CHAR; lo: INTEGER;
  2998. span: CARDINAL);
  2999. VAR off, offL, hiS, loS, m, nm, old, nv: QVal;
  3000. BEGIN
  3001. NewTemp(off);
  3002. IntStr(lo, loS);
  3003. Op3("sub", off, val, loS, FALSE);
  3004. WidenIndex(off, offL);
  3005. IntStr(VAL(INTEGER, span) - 1, hiS);
  3006. CheckRange(offL, "0", hiS);
  3007. NewTemp(m);
  3008. Op3("shl", m, "1", off, FALSE);
  3009. NewTemp(nm);
  3010. Op3("xor", nm, m, "-1", FALSE);
  3011. LoadPacked(addr, t, old);
  3012. NewTemp(nv);
  3013. Op3("and", nv, old, nm, FALSE);
  3014. StorePacked(addr, t, nv)
  3015. END PackedSetClearBit;
  3016. PROCEDURE PackedInSet (x: ARRAY OF CHAR; s: ARRAY OF CHAR;
  3017. lo: INTEGER; span: CARDINAL; t: INTEGER;
  3018. VAR q: QVal);
  3019. VAR off, offL, hiS, loS, word, sh, bit: QVal;
  3020. BEGIN
  3021. NewTemp(off);
  3022. IntStr(lo, loS);
  3023. Op3("sub", off, x, loS, FALSE);
  3024. WidenIndex(off, offL);
  3025. IntStr(VAL(INTEGER, span) - 1, hiS);
  3026. CheckRange(offL, "0", hiS);
  3027. LoadPacked(s, t, word);
  3028. NewTemp(sh);
  3029. Op3("shr", sh, word, off, FALSE);
  3030. NewTemp(bit);
  3031. Op3("and", bit, sh, "1", FALSE);
  3032. Cmp(SymTab.OpNeq1, bit, "0", q, FALSE)
  3033. END PackedInSet;
  3034. PROCEDURE PackedCmpSet (op: INTEGER; l: ARRAY OF CHAR; lt: INTEGER;
  3035. r: ARRAY OF CHAR; rt: INTEGER; VAR q: QVal);
  3036. VAR q1, q2: QVal;
  3037. BEGIN
  3038. IF SymTab.IsPackedSet(lt) THEN LoadPacked(l, lt, q1)
  3039. ELSE LoadW(l, q1)
  3040. END;
  3041. IF SymTab.IsPackedSet(rt) THEN LoadPacked(r, rt, q2)
  3042. ELSE LoadW(r, q2)
  3043. END;
  3044. Cmp(op, q1, q2, q, FALSE)
  3045. END PackedCmpSet;
  3046. PROCEDURE PackedSetBinOp (sel: INTEGER; l: ARRAY OF CHAR; lt: INTEGER;
  3047. r: ARRAY OF CHAR; rt: INTEGER; VAR q: QVal);
  3048. VAR tl, tr, w: QVal;
  3049. BEGIN
  3050. NewSetTemp(1, tl); NewSetTemp(1, tr);
  3051. IF SymTab.IsPackedSet(lt) THEN LoadPacked(l, lt, w)
  3052. ELSE LoadW(l, w)
  3053. END;
  3054. StoreW(tl, w);
  3055. IF SymTab.IsPackedSet(rt) THEN LoadPacked(r, rt, w)
  3056. ELSE LoadW(r, w)
  3057. END;
  3058. StoreW(tr, w);
  3059. SetBinOp(sel, tl, tr, 1, 1, q)
  3060. END PackedSetBinOp;
  3061. PROCEDURE CopySet (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  3062. dw, sw: CARDINAL);
  3063. (* Copies min words via memcpy, zero-fills dst extras. Src extras
  3064. beyond dst must be zero (trap) — otherwise out-of-span bits
  3065. would vanish silently on narrowing assignment. *)
  3066. VAR m, i: CARDINAL;
  3067. n, da, sa, a, z, off, c: QVal;
  3068. qr, acc, lok, lbad: QVal;
  3069. BEGIN
  3070. m := dw;
  3071. IF sw < m THEN m := sw END;
  3072. IF sw > dw THEN
  3073. NewTemp(acc);
  3074. Op3("xor", acc, "1", "0", FALSE);
  3075. i := dw;
  3076. WHILE i < sw DO
  3077. IntStr(VAL(INTEGER, i * 4), off);
  3078. NewTemp(a); Op3L("add", a, src, off);
  3079. NewTemp(c);
  3080. W(" "); W(c); W(" =w loadw "); WL(a);
  3081. NewTemp(qr);
  3082. Op3("ceqw", qr, c, "0", FALSE);
  3083. NewTemp(c);
  3084. Op3("and", c, acc, qr, FALSE);
  3085. CopyOp(c, acc);
  3086. INC(i)
  3087. END;
  3088. NewLabel(lok); NewLabel(lbad);
  3089. Jnz(acc, lok, lbad);
  3090. EmitLabel(lbad);
  3091. Trap;
  3092. EmitLabel(lok)
  3093. END;
  3094. IF m > 0 THEN
  3095. IntStr(VAL(INTEGER, m * 4), n);
  3096. NewTemp(qr);
  3097. W(" "); W(qr); W(" =l call $memcpy(l ");
  3098. W(dst); W(", l "); W(src); W(", l "); W(n); WL(")")
  3099. END;
  3100. NewTemp(z);
  3101. Op3("xor", z, "0", "0", FALSE);
  3102. i := m;
  3103. WHILE i < dw DO
  3104. NewTemp(a);
  3105. IntStr(VAL(INTEGER, i * 4), off);
  3106. Op3L("add", a, dst, off);
  3107. Revive;
  3108. W(" storew "); W(z); W(", "); WL(a);
  3109. INC(i)
  3110. END
  3111. END CopySet;
  3112. PROCEDURE InSet (x: ARRAY OF CHAR; s: ARRAY OF CHAR; lo: INTEGER;
  3113. span: CARDINAL; VAR q: QVal);
  3114. (* Membership bit test with span trap; q is fresh w 0/1. *)
  3115. VAR off, offL, hiS, loS: QVal;
  3116. wi, bi, wil, off4, wa, wcur, m, a: QVal;
  3117. spanS: QVal;
  3118. BEGIN
  3119. NewTemp(off);
  3120. IntStr(lo, loS);
  3121. Op3("sub", off, x, loS, FALSE);
  3122. WidenIndex(off, offL);
  3123. IntStr(VAL(INTEGER, span) - 1, spanS);
  3124. CheckRange(offL, "0", spanS);
  3125. NewTemp(wi);
  3126. Op3("shr", wi, off, "5", FALSE);
  3127. NewTemp(bi);
  3128. Op3("and", bi, off, "31", FALSE);
  3129. WidenIndex(wi, wil);
  3130. NewTemp(off4);
  3131. Op3L("mul", off4, wil, "4");
  3132. NewTemp(wa);
  3133. Op3L("add", wa, s, off4);
  3134. NewTemp(wcur);
  3135. W(" "); W(wcur); W(" =w loadw "); WL(wa);
  3136. NewTemp(m);
  3137. Op3("shl", m, "1", bi, FALSE);
  3138. NewTemp(a);
  3139. Op3("and", a, wcur, m, FALSE);
  3140. NewTemp(q);
  3141. Op3("cnew", q, a, "0", FALSE)
  3142. END InSet;
  3143. PROCEDURE WidenIndex (idx: ARRAY OF CHAR; VAR q: QVal);
  3144. BEGIN
  3145. IF IsImm(idx) THEN Cpy(q, idx)
  3146. ELSE
  3147. NewTemp(q);
  3148. Revive;
  3149. W(" "); W(q); W(" =l extsw "); WL(idx)
  3150. END
  3151. END WidenIndex;
  3152. PROCEDURE OpenHi (base: ARRAY OF CHAR; VAR q: QVal);
  3153. VAR c: QVal;
  3154. BEGIN
  3155. NewTemp(c);
  3156. Revive;
  3157. W(" "); W(c); W(" =l loadl "); WL(base);
  3158. NewTemp(q);
  3159. Op3L("sub", q, c, "1")
  3160. END OpenHi;
  3161. PROCEDURE OpenHiChar (base: ARRAY OF CHAR; VAR q: QVal);
  3162. (* q := loadl(base) — the open-array count, i.e. the index of the NUL
  3163. terminator slot that CHAR arrays reserve. *)
  3164. BEGIN
  3165. NewTemp(q);
  3166. Revive;
  3167. W(" "); W(q); W(" =l loadl "); WL(base)
  3168. END OpenHiChar;
  3169. PROCEDURE LoadCount (base: ARRAY OF CHAR; VAR q: QVal);
  3170. BEGIN
  3171. NewTemp(q);
  3172. Revive;
  3173. W(" "); W(q); W(" =l loadl "); WL(base)
  3174. END LoadCount;
  3175. PROCEDURE CheckCode (idx, lo, hi: ARRAY OF CHAR; code: CARDINAL);
  3176. (* l-domain operands (widened index, immediates, or open hi temp);
  3177. comparisons are long (result w). *)
  3178. VAR c1, c2, c: QVal;
  3179. lok, lbad: QVal;
  3180. BEGIN
  3181. NewTemp(c1);
  3182. Op3("csgel", c1, idx, lo, FALSE);
  3183. NewTemp(c2);
  3184. Op3("cslel", c2, idx, hi, FALSE);
  3185. NewTemp(c);
  3186. Op3("and", c, c1, c2, FALSE);
  3187. NewLabel(lok); NewLabel(lbad);
  3188. Jnz(c, lok, lbad);
  3189. EmitLabel(lbad);
  3190. TrapCode(code);
  3191. EmitLabel(lok)
  3192. END CheckCode;
  3193. PROCEDURE CheckRange (idx, lo, hi: ARRAY OF CHAR);
  3194. BEGIN
  3195. CheckCode(idx, lo, hi, 1) (* rangeException *)
  3196. END CheckRange;
  3197. PROCEDURE CheckIndex (idx, lo, hi: ARRAY OF CHAR);
  3198. BEGIN
  3199. CheckCode(idx, lo, hi, 0) (* indexException *)
  3200. END CheckIndex;
  3201. PROCEDURE ElemAddr (base, idx, lo: ARRAY OF CHAR; elemT: INTEGER;
  3202. VAR q: QVal);
  3203. (* q := base + 8 + (idx - lo) * elemSize in l, fresh temp.
  3204. elemT is the array descriptor (open or fixed); all operands
  3205. l-domain (immediates pass, temps pre-widened). *)
  3206. VAR t1, t2, tb, sb: QVal;
  3207. BEGIN
  3208. NewTemp(t1);
  3209. Op3L("sub", t1, idx, lo);
  3210. IntStr(VAL(INTEGER, ElemSize(elemT)), sb);
  3211. NewTemp(t2);
  3212. Op3L("mul", t2, t1, sb);
  3213. NewTemp(tb);
  3214. Op3L("add", tb, base, "8");
  3215. NewTemp(q);
  3216. Op3L("add", q, tb, t2)
  3217. END ElemAddr;
  3218. PROCEDURE ViewField (view: ARRAY OF CHAR; off: CARDINAL; VAR q: QVal);
  3219. (* q := loadl(view + off), off one of 0,8,16,24,32. *)
  3220. VAR a, s: QVal;
  3221. BEGIN
  3222. NewTemp(a);
  3223. IntStr(VAL(INTEGER, off), s);
  3224. Op3L("add", a, view, s);
  3225. NewTemp(q);
  3226. Revive;
  3227. W(" "); W(q); W(" =l loadl "); WL(a)
  3228. END ViewField;
  3229. PROCEDURE ViewIndex (view, idx, lo: ARRAY OF CHAR;
  3230. nextIsArray: BOOLEAN; VAR q: QVal);
  3231. VAR t1, stride, off, base, addr, nv, next, tmp: QVal;
  3232. BEGIN
  3233. NewTemp(t1);
  3234. Op3L("sub", t1, idx, lo);
  3235. ViewField(view, 16, stride);
  3236. NewTemp(off);
  3237. Op3L("mul", off, t1, stride);
  3238. ViewField(view, 24, base);
  3239. NewTemp(addr);
  3240. Op3L("add", addr, base, off);
  3241. IF NOT nextIsArray THEN
  3242. CopyOp(addr, q)
  3243. ELSE
  3244. ViewField(view, 32, next);
  3245. NewTemp(nv);
  3246. Revive;
  3247. W(" "); W(nv); WL(" =l alloc8 40");
  3248. (* copy count, elemBytes, stride and next from the template *)
  3249. ViewField(next, 0, tmp);
  3250. Revive; W(" storel "); W(tmp); W(", "); WL(nv);
  3251. IntStr(8, off);
  3252. NewTemp(t1); Op3L("add", t1, nv, off);
  3253. ViewField(next, 8, tmp);
  3254. Revive; W(" storel "); W(tmp); W(", "); WL(t1);
  3255. IntStr(16, off);
  3256. NewTemp(t1); Op3L("add", t1, nv, off);
  3257. ViewField(next, 16, tmp);
  3258. Revive; W(" storel "); W(tmp); W(", "); WL(t1);
  3259. IntStr(32, off);
  3260. NewTemp(t1); Op3L("add", t1, nv, off);
  3261. ViewField(next, 32, tmp);
  3262. Revive; W(" storel "); W(tmp); W(", "); WL(t1);
  3263. IntStr(24, off);
  3264. NewTemp(t1); Op3L("add", t1, nv, off);
  3265. Revive; W(" storel "); W(addr); W(", "); WL(t1);
  3266. CopyOp(nv, q)
  3267. END
  3268. END ViewIndex;
  3269. PROCEDURE MakeOpen1DView (src: ARRAY OF CHAR; at, ft: INTEGER;
  3270. srcIsView: BOOLEAN; VAR q: QVal);
  3271. VAR cnt, esz, st, base, nv, total, x: QVal;
  3272. byteFormal: BOOLEAN;
  3273. BEGIN
  3274. byteFormal := SymTab.IsByteBuf(ft);
  3275. IF srcIsView THEN
  3276. IF byteFormal THEN
  3277. ViewField(src, 0, cnt);
  3278. ViewField(src, 8, esz);
  3279. NewTemp(total); Op3L("mul", total, cnt, esz);
  3280. CopyOp(total, cnt);
  3281. NewTemp(esz); CopyOp("1", esz);
  3282. NewTemp(st); CopyOp("1", st)
  3283. ELSIF SymTab.IsOpenArray(at) AND (SymTab.ArrayDepth(at) = 1) THEN
  3284. CopyOp(src, q); RETURN
  3285. ELSE
  3286. ViewField(src, 0, cnt);
  3287. ViewField(src, 8, esz);
  3288. ViewField(src, 16, st)
  3289. END;
  3290. ViewField(src, 24, base)
  3291. ELSE
  3292. NewTemp(cnt);
  3293. W(" "); W(cnt); W(" =l loadl "); WL(src);
  3294. IF byteFormal THEN
  3295. IF SymTab.ClassOf(at) = SymTab.ClArray THEN
  3296. IntStr(VAL(INTEGER, SymTab.ArrayLeafBytes(at)), esz)
  3297. ELSIF SymTab.ClassOf(at) = SymTab.ClUStr THEN CopyOp("4", esz)
  3298. ELSE CopyOp("1", esz) END;
  3299. NewTemp(total); Op3L("mul", total, cnt, esz);
  3300. CopyOp(total, cnt);
  3301. NewTemp(esz); CopyOp("1", esz);
  3302. NewTemp(st); CopyOp("1", st)
  3303. ELSE
  3304. IF SymTab.ClassOf(at) = SymTab.ClArray THEN
  3305. IntStr(VAL(INTEGER, SymTab.ArrayLeafBytes(at)), esz)
  3306. ELSIF SymTab.ClassOf(at) = SymTab.ClUStr THEN CopyOp("4", esz)
  3307. ELSE CopyOp("1", esz) END;
  3308. NewTemp(st); CopyOp(esz, st)
  3309. END;
  3310. NewTemp(base); Op3L("add", base, src, "8")
  3311. END;
  3312. NewTemp(nv);
  3313. Revive;
  3314. W(" "); W(nv); WL(" =l alloc8 40");
  3315. Revive; W(" storel "); W(cnt); W(", "); WL(nv);
  3316. NewTemp(x); Op3L("add", x, nv, "8");
  3317. Revive; W(" storel "); W(esz); W(", "); WL(x);
  3318. NewTemp(x); Op3L("add", x, nv, "16");
  3319. Revive; W(" storel "); W(st); W(", "); WL(x);
  3320. NewTemp(x); Op3L("add", x, nv, "24");
  3321. Revive; W(" storel "); W(base); W(", "); WL(x);
  3322. NewTemp(x); Op3L("add", x, nv, "32");
  3323. Revive; W(" storel 0, "); WL(x);
  3324. CopyOp(nv, q)
  3325. END MakeOpen1DView;
  3326. PROCEDURE MakeFieldView (addr: ARRAY OF CHAR; t: INTEGER; VAR q: QVal);
  3327. VAR rank, k, count, stride: CARDINAL;
  3328. cur: SymTab.TypeIndex;
  3329. v, a, nb, off: QVal;
  3330. BEGIN
  3331. rank := SymTab.ArrayDepth(t);
  3332. IF rank <= 1 THEN CopyOp(addr, q); RETURN END;
  3333. IntStr(VAL(INTEGER, rank * 40), nb);
  3334. NewTemp(q);
  3335. Revive;
  3336. W(" "); W(q); W(" =l alloc8 "); WL(nb);
  3337. cur := t; k := 0;
  3338. WHILE k < rank DO
  3339. IntStr(VAL(INTEGER, k * 40), off);
  3340. NewTemp(v); Op3L("add", v, q, off);
  3341. count := SymTab.ArrayLen(cur);
  3342. stride := SymTab.ArrayStride(t, k);
  3343. IntStr(VAL(INTEGER, count), nb);
  3344. Revive; W(" storel "); W(nb); W(", "); WL(v);
  3345. IntStr(VAL(INTEGER, stride), nb);
  3346. NewTemp(a); Op3L("add", a, v, "8");
  3347. Revive; W(" storel "); W(nb); W(", "); WL(a);
  3348. NewTemp(a); Op3L("add", a, v, "16");
  3349. Revive; W(" storel "); W(nb); W(", "); WL(a);
  3350. IF k = 0 THEN
  3351. NewTemp(a); Op3L("add", a, v, "24");
  3352. Revive; W(" storel "); W(addr); W(", "); WL(a)
  3353. ELSE
  3354. NewTemp(a); Op3L("add", a, v, "24");
  3355. Revive; W(" storel 0, "); WL(a)
  3356. END;
  3357. IF k + 1 < rank THEN
  3358. NewTemp(a); Op3L("add", a, v, "32");
  3359. IntStr(VAL(INTEGER, (k + 1) * 40), off);
  3360. NewTemp(nb); Op3L("add", nb, q, off);
  3361. Revive; W(" storel "); W(nb); W(", "); WL(a)
  3362. ELSE
  3363. NewTemp(a); Op3L("add", a, v, "32");
  3364. Revive; W(" storel 0, "); WL(a)
  3365. END;
  3366. cur := SymTab.ArrayElem(cur);
  3367. INC(k)
  3368. END
  3369. END MakeFieldView;
  3370. PROCEDURE ViewToOpen1D (view: ARRAY OF CHAR; ft: INTEGER;
  3371. VAR q, base, nbytes: QVal);
  3372. VAR count, elem, total, n, desc, p, p2, eoff: QVal;
  3373. cls, extra: INTEGER;
  3374. BEGIN
  3375. ViewField(view, 0, count);
  3376. ViewField(view, 8, elem);
  3377. NewTemp(total);
  3378. Op3L("mul", total, count, elem);
  3379. cls := SymTab.ClassOf(SymTab.ArrayElem(ft));
  3380. IF (cls = SymTab.ClByte) OR (cls = SymTab.ClSByte) THEN
  3381. CopyOp(total, count)
  3382. END;
  3383. extra := 0;
  3384. IF cls = SymTab.ClChar THEN extra := 1
  3385. ELSIF cls = SymTab.ClUChar THEN extra := 4
  3386. END;
  3387. NewTemp(n);
  3388. Op3L("add", n, total, "8");
  3389. IF extra > 0 THEN
  3390. IntStr(VAL(INTEGER, extra), eoff);
  3391. NewTemp(p); Op3L("add", p, n, eoff); CopyOp(p, n)
  3392. END;
  3393. NewTemp(desc);
  3394. W(" "); W(desc); W(" =l call $malloc(l "); W(n); WL(")");
  3395. Revive;
  3396. W(" storel "); W(count); W(", "); WL(desc);
  3397. ViewField(view, 24, base);
  3398. CopyOp(total, nbytes);
  3399. NewTemp(p);
  3400. Op3L("add", p, desc, "8");
  3401. Revive;
  3402. W(" "); W(n); W(" =l call $memcpy(l ");
  3403. W(p); W(", l "); W(base); W(", l "); W(total); WL(")");
  3404. IF extra > 0 THEN
  3405. NewTemp(p); Op3L("add", p, desc, "8");
  3406. NewTemp(p2); Op3L("add", p2, p, total);
  3407. Revive;
  3408. IF extra = 1 THEN W(" storeb 0, "); WL(p2)
  3409. ELSE W(" storew 0, "); WL(p2) END
  3410. END;
  3411. CopyOp(desc, q)
  3412. END ViewToOpen1D;
  3413. PROCEDURE ViewCopyBack (desc, base, nbytes: ARRAY OF CHAR);
  3414. VAR p, r: QVal;
  3415. BEGIN
  3416. NewTemp(p);
  3417. Op3L("add", p, desc, "8");
  3418. NewTemp(r);
  3419. W(" "); W(r); W(" =l call $memcpy(l ");
  3420. W(base); W(", l "); W(p); W(", l "); W(nbytes); WL(")")
  3421. END ViewCopyBack;
  3422. PROCEDURE ViewFree (desc: ARRAY OF CHAR);
  3423. BEGIN
  3424. Revive;
  3425. W(" call $free(l "); W(desc); WL(")")
  3426. END ViewFree;
  3427. PROCEDURE ViewBase (view: ARRAY OF CHAR; VAR q: QVal);
  3428. BEGIN
  3429. ViewField(view, 24, q)
  3430. END ViewBase;
  3431. PROCEDURE ViewSize (view: ARRAY OF CHAR; VAR q: QVal);
  3432. VAR cnt, esz, r: QVal;
  3433. BEGIN
  3434. ViewField(view, 0, cnt);
  3435. ViewField(view, 8, esz);
  3436. NewTemp(r);
  3437. Op3L("mul", r, cnt, esz);
  3438. CopyOp(r, q)
  3439. END ViewSize;
  3440. PROCEDURE DescData (desc: ARRAY OF CHAR; VAR q: QVal);
  3441. BEGIN
  3442. NewTemp(q);
  3443. Op3L("add", q, desc, "8")
  3444. END DescData;
  3445. PROCEDURE OpenSize (desc: ARRAY OF CHAR; ft: INTEGER; VAR q: QVal);
  3446. VAR cnt, esz, r: QVal;
  3447. BEGIN
  3448. NewTemp(q);
  3449. Revive;
  3450. W(" "); W(q); W(" =l loadl "); WL(desc);
  3451. IntStr(VAL(INTEGER, SymTab.ArrayLeafBytes(ft)), esz);
  3452. NewTemp(r);
  3453. Op3L("mul", r, q, esz);
  3454. CopyOp(r, q)
  3455. END OpenSize;
  3456. PROCEDURE ElemLoad (addr: ARRAY OF CHAR; t: INTEGER; VAR q: QVal);
  3457. (* Loads one element of (element-)type t. Nested/pointer elements
  3458. are addresses (loadl). *)
  3459. VAR cls: INTEGER;
  3460. BEGIN
  3461. cls := SymTab.ClassOf(t);
  3462. NewTemp(q);
  3463. Revive;
  3464. W(" "); W(q);
  3465. IF cls = SymTab.ClReal THEN W(" =d loadd ")
  3466. ELSIF (cls = SymTab.ClArray) OR (cls = SymTab.ClPtr)
  3467. OR (cls = SymTab.ClLong) OR (cls = SymTab.ClProc)
  3468. OR (cls = SymTab.ClClass) THEN
  3469. W(" =l loadl ")
  3470. ELSIF cls = SymTab.ClChar THEN W(" =w loadub ")
  3471. ELSIF cls = SymTab.ClSet THEN
  3472. IF SymTab.IsPackedSet(t) AND (SymTab.SetBytes(t) = 1) THEN
  3473. W(" =w loadub ")
  3474. ELSIF SymTab.IsPackedSet(t) AND (SymTab.SetBytes(t) = 2) THEN
  3475. W(" =w loaduh ")
  3476. ELSE W(" =w loadw ")
  3477. END
  3478. ELSIF cls = SymTab.ClByte THEN W(" =w loadub ")
  3479. ELSIF cls = SymTab.ClSByte THEN W(" =w loadsb ")
  3480. ELSIF cls = SymTab.ClWord16 THEN W(" =w loaduh ")
  3481. ELSIF cls = SymTab.ClSWord16 THEN W(" =w loadsh ")
  3482. ELSE W(" =w loadw ")
  3483. END;
  3484. WL(addr)
  3485. END ElemLoad;
  3486. PROCEDURE ElemStore (addr, v: ARRAY OF CHAR; t: INTEGER);
  3487. VAR cls: INTEGER;
  3488. BEGIN
  3489. cls := SymTab.ClassOf(t);
  3490. Revive;
  3491. IF cls = SymTab.ClReal THEN W(" stored ")
  3492. ELSIF (cls = SymTab.ClArray) OR (cls = SymTab.ClPtr)
  3493. OR (cls = SymTab.ClLong) OR (cls = SymTab.ClProc)
  3494. OR (cls = SymTab.ClClass) THEN
  3495. W(" storel ")
  3496. ELSIF cls = SymTab.ClChar THEN W(" storeb ")
  3497. ELSIF cls = SymTab.ClSet THEN
  3498. IF SymTab.IsPackedSet(t) AND (SymTab.SetBytes(t) = 1) THEN
  3499. W(" storeb ")
  3500. ELSIF SymTab.IsPackedSet(t) AND (SymTab.SetBytes(t) = 2) THEN
  3501. W(" storeh ")
  3502. ELSE W(" storew ")
  3503. END
  3504. ELSIF (cls = SymTab.ClByte) OR (cls = SymTab.ClSByte) THEN W(" storeb ")
  3505. ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN W(" storeh ")
  3506. ELSE W(" storew ")
  3507. END;
  3508. W(v); W(", "); WL(addr)
  3509. END ElemStore;
  3510. PROCEDURE CopyOldNestedToView (dst, src: ARRAY OF CHAR;
  3511. t: INTEGER; rank: CARDINAL);
  3512. (* Adapt an old nested-descriptor constructor (e.g. names{"Thu","Fri"})
  3513. into a flat multi-dimensional view payload. Only static constructor
  3514. sources use this path. *)
  3515. VAR count, base, esz, row, a, off, off2, child, i, c: QVal;
  3516. ltop, lbody, lend: QVal;
  3517. BEGIN
  3518. IF rank <= 1 THEN
  3519. ViewField(dst, 24, base);
  3520. ViewField(dst, 0, count);
  3521. ViewField(dst, 8, esz);
  3522. NewTemp(a);
  3523. Op3L("mul", a, count, esz);
  3524. NewTemp(off); Op3L("add", off, src, "8");
  3525. NewTemp(c);
  3526. W(" "); W(c); W(" =l call $memcpy(l ");
  3527. W(base); W(", l "); W(off); W(", l "); W(a); WL(")")
  3528. ELSE
  3529. ViewField(dst, 0, count);
  3530. NewTemp(i);
  3531. W(" "); W(i); W(" =l copy 0"); WL("");
  3532. NewLabel(ltop); NewLabel(lbody); NewLabel(lend);
  3533. EmitLabel(ltop);
  3534. NewTemp(c); Op3("csltl", c, i, count, FALSE);
  3535. Jnz(c, lbody, lend);
  3536. EmitLabel(lbody);
  3537. ViewIndex(dst, i, "0", TRUE, row);
  3538. NewTemp(off); Op3L("mul", off, i, "8");
  3539. NewTemp(a); Op3L("add", a, src, "8");
  3540. NewTemp(off2); Op3L("add", off2, a, off);
  3541. NewTemp(child); W(" "); W(child); W(" =l loadl "); WL(off2);
  3542. CopyOldNestedToView(row, child, SymTab.ArrayElem(t), rank - 1);
  3543. Op3L("add", i, i, "1");
  3544. Jmp(ltop);
  3545. EmitLabel(lend)
  3546. END
  3547. END CopyOldNestedToView;
  3548. PROCEDURE IsCtorRef (v: ARRAY OF CHAR): BOOLEAN;
  3549. (* TRUE for $ctoN and $<module>_ctoN. *)
  3550. VAR i: CARDINAL;
  3551. BEGIN
  3552. IF (v[0] # "$") OR (v[1] = CHR(0)) THEN RETURN FALSE END;
  3553. IF (v[1] = "c") AND (v[2] = "t") AND (v[3] = "o") THEN RETURN TRUE END;
  3554. i := 1;
  3555. WHILE (i <= HIGH(v)) AND (v[i] # CHR(0)) AND (v[i] # "_") DO INC(i) END;
  3556. RETURN (i + 3 <= HIGH(v)) AND (v[i] = "_")
  3557. AND (v[i + 1] = "c") AND (v[i + 2] = "t") AND (v[i + 3] = "o")
  3558. END IsCtorRef;
  3559. PROCEDURE IsStrRef (v: ARRAY OF CHAR): BOOLEAN;
  3560. (* TRUE when v names a recorded string literal ($strN or $<mod>_strN). *)
  3561. VAR j: CARDINAL;
  3562. sv: QVal;
  3563. BEGIN
  3564. j := 0;
  3565. WHILE j < nStr DO
  3566. Cpy(sv, "$"); App(sv, strNams[j]);
  3567. IF SymTab.Equal(sv, v) THEN RETURN TRUE END;
  3568. INC(j)
  3569. END;
  3570. RETURN FALSE
  3571. END IsStrRef;
  3572. PROCEDURE CopyArray (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  3573. t: INTEGER);
  3574. (* Whole-array copy with runtime count check + blit. Nested levels
  3575. recurse through a runtime loop; counts mismatch traps. dst/src
  3576. are descriptor address operands; t is the destination type. *)
  3577. VAR dc, sc, ok: QVal;
  3578. lok, lbad: QVal;
  3579. ecls: INTEGER;
  3580. n, da, sa: QVal;
  3581. sb: QVal;
  3582. qr: QVal;
  3583. i, c, de, se, di, si, dd0, doff, sd0, soff: QVal;
  3584. ltop, lbody, lend: QVal;
  3585. BEGIN
  3586. IF SymTab.IsMultiArray(t) THEN
  3587. IF IsCtorRef(src) THEN
  3588. CopyOldNestedToView(dst, src, t, SymTab.ArrayDepth(t))
  3589. ELSE
  3590. (* src/dst are ArrayView pointers; copy the flat payload only. *)
  3591. ViewField(dst, 24, da);
  3592. ViewField(src, 24, sa);
  3593. ViewField(dst, 0, n);
  3594. ViewField(dst, 8, sb);
  3595. NewTemp(qr);
  3596. Op3L("mul", qr, n, sb);
  3597. NewTemp(n);
  3598. W(" "); W(n); W(" =l call $memcpy(l ");
  3599. W(da); W(", l "); W(sa); W(", l "); W(qr); WL(")")
  3600. END;
  3601. RETURN
  3602. END;
  3603. NewTemp(dc);
  3604. Revive;
  3605. W(" "); W(dc); W(" =l loadl "); WL(dst);
  3606. NewTemp(sc);
  3607. W(" "); W(sc); W(" =l loadl "); WL(src);
  3608. NewTemp(ok);
  3609. Op3("ceql", ok, dc, sc, FALSE);
  3610. NewLabel(lok); NewLabel(lbad);
  3611. Jnz(ok, lok, lbad);
  3612. EmitLabel(lbad);
  3613. Trap;
  3614. EmitLabel(lok);
  3615. ecls := ElemCls(t);
  3616. IF (ecls = SymTab.ClArray) THEN
  3617. NewTemp(i);
  3618. W(" "); W(i); W(" =l copy 0"); WL("");
  3619. NewLabel(ltop); NewLabel(lbody); NewLabel(lend);
  3620. EmitLabel(ltop);
  3621. NewTemp(c);
  3622. Op3("csltl", c, i, dc, FALSE);
  3623. Jnz(c, lbody, lend);
  3624. EmitLabel(lbody);
  3625. NewTemp(dd0); Op3L("add", dd0, dst, "8");
  3626. NewTemp(doff); Op3L("mul", doff, i, "8");
  3627. NewTemp(de); Op3L("add", de, dd0, doff);
  3628. NewTemp(sd0); Op3L("add", sd0, src, "8");
  3629. NewTemp(soff); Op3L("mul", soff, i, "8");
  3630. NewTemp(se); Op3L("add", se, sd0, soff);
  3631. NewTemp(di);
  3632. W(" "); W(di); W(" =l loadl "); WL(de);
  3633. NewTemp(si);
  3634. W(" "); W(si); W(" =l loadl "); WL(se);
  3635. CopyArray(di, si, SymTab.ArrayElem(t));
  3636. Op3L("add", i, i, "1");
  3637. Jmp(ltop);
  3638. EmitLabel(lend)
  3639. ELSE
  3640. IntStr(VAL(INTEGER, ElemSize(t)), sb);
  3641. NewTemp(n);
  3642. Op3L("mul", n, dc, sb);
  3643. NewTemp(da);
  3644. Op3L("add", da, dst, "8");
  3645. NewTemp(sa);
  3646. Op3L("add", sa, src, "8");
  3647. NewTemp(qr);
  3648. W(" "); W(qr); W(" =l call $memcpy(l ");
  3649. W(da); W(", l "); W(sa); W(", l "); W(n); WL(")")
  3650. END
  3651. END CopyArray;
  3652. PROCEDURE CopyArrayEx (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
  3653. t: INTEGER; dstIsView, srcIsView: BOOLEAN);
  3654. VAR db, dc, de, sb, sc, se, total, srcData, dstData, r: QVal;
  3655. BEGIN
  3656. IF SymTab.IsMultiArray(t) THEN
  3657. CopyArray(dst, src, t); RETURN
  3658. END;
  3659. IF dstIsView THEN
  3660. ViewField(dst, 24, db);
  3661. ViewField(dst, 0, dc);
  3662. ViewField(dst, 8, de);
  3663. NewTemp(total); Op3L("mul", total, dc, de);
  3664. IF srcIsView THEN
  3665. ViewField(src, 24, sb)
  3666. ELSE
  3667. NewTemp(srcData); Op3L("add", srcData, src, "8"); CopyOp(srcData, sb)
  3668. END;
  3669. NewTemp(r);
  3670. W(" "); W(r); W(" =l call $memcpy(l ");
  3671. W(db); W(", l "); W(sb); W(", l "); W(total); WL(")")
  3672. ELSIF srcIsView THEN
  3673. ViewField(src, 24, sb);
  3674. ViewField(src, 0, sc);
  3675. ViewField(src, 8, se);
  3676. NewTemp(total); Op3L("mul", total, sc, se);
  3677. NewTemp(dstData); Op3L("add", dstData, dst, "8");
  3678. NewTemp(r);
  3679. W(" "); W(r); W(" =l call $memcpy(l ");
  3680. W(dstData); W(", l "); W(sb); W(", l "); W(total); WL(")")
  3681. ELSE
  3682. CopyArray(dst, src, t)
  3683. END
  3684. END CopyArrayEx;
  3685. PROCEDURE DeclStr (text: ARRAY OF CHAR; VAR q: QVal);
  3686. (* Records a quoted literal for top-level emission at EndModule and
  3687. returns its address operand ($strN). Data definitions may only
  3688. appear outside functions, but literals occur mid-body. *)
  3689. VAR nm: QVal;
  3690. BEGIN
  3691. Cpy(nm, curModName);
  3692. App(nm, "_str");
  3693. AppNum(nm, nStr);
  3694. IF nStr <= HIGH(strNams) THEN
  3695. Cpy(strNams[nStr], nm);
  3696. Cpy(strTexts[nStr], text);
  3697. INC(nStr)
  3698. END;
  3699. Cpy(q, "$");
  3700. App(q, nm)
  3701. END DeclStr;
  3702. PROCEDURE DeclUStr (text: ARRAY OF CHAR; VAR q: QVal;
  3703. VAR single: BOOLEAN; VAR cp: INTEGER;
  3704. VAR ok: BOOLEAN);
  3705. (* text is the raw lexeme U'...' / U"..." Strict RFC3629-decode the
  3706. bytes between the quotes. Exactly one codepoint -> single:=TRUE,
  3707. cp:=it. Otherwise record a UString descriptor and q := "$ustrN".
  3708. ok:=FALSE for invalid UTF-8 (overlong / surrogate / >10FFFF /
  3709. truncation). *)
  3710. VAR L, i, cnt, base: CARDINAL;
  3711. b0, b1, b2, b3, ch: INTEGER;
  3712. nm: QVal;
  3713. PROCEDURE Cont (VAR b: INTEGER): BOOLEAN;
  3714. (* consume a continuation byte, or fail *)
  3715. BEGIN
  3716. IF i >= L - 1 THEN RETURN FALSE END;
  3717. b := ORD(text[i]); INC(i);
  3718. RETURN (b >= 128) AND (b <= 191)
  3719. END Cont;
  3720. BEGIN
  3721. single := FALSE; cp := 0; ok := TRUE;
  3722. q[0] := "0"; q[1] := CHR(0);
  3723. L := Len(text);
  3724. IF (L < 3) OR (text[0] # "U") THEN ok := FALSE; RETURN END;
  3725. i := 2; cnt := 0; base := ustrUsed;
  3726. WHILE i < L - 1 DO
  3727. b0 := ORD(text[i]); INC(i);
  3728. ch := -1;
  3729. IF b0 <= 127 THEN
  3730. ch := b0
  3731. ELSIF (b0 >= 194) AND (b0 <= 223) THEN
  3732. IF Cont(b1) THEN ch := ((b0 - 192) * 64) + (b1 - 128) END
  3733. ELSIF (b0 >= 224) AND (b0 <= 239) THEN
  3734. IF Cont(b1) AND Cont(b2) THEN
  3735. ch := ((b0 - 224) * 4096) + ((b1 - 128) * 64) + (b2 - 128);
  3736. IF ch < 2048 THEN ch := -1 END
  3737. END
  3738. ELSIF (b0 >= 240) AND (b0 <= 244) THEN
  3739. IF Cont(b1) AND Cont(b2) AND Cont(b3) THEN
  3740. ch := ((b0 - 240) * 262144) + ((b1 - 128) * 4096)
  3741. + ((b2 - 128) * 64) + (b3 - 128);
  3742. IF ch < 65536 THEN ch := -1 END
  3743. END
  3744. ELSE ok := FALSE
  3745. END;
  3746. IF ok AND (ch < 0) THEN ok := FALSE END;
  3747. IF ok AND (ch >= 55296) AND (ch <= 57343) THEN ok := FALSE END;
  3748. IF ok AND (ch > 1114111) THEN ok := FALSE END;
  3749. IF NOT ok THEN RETURN END;
  3750. IF ustrUsed <= HIGH(ustrPool) THEN
  3751. ustrPool[ustrUsed] := ch; INC(ustrUsed)
  3752. END;
  3753. INC(cnt)
  3754. END;
  3755. IF cnt = 1 THEN
  3756. single := TRUE; cp := ustrPool[base]
  3757. ELSE
  3758. Cpy(nm, curModName); App(nm, "_ustr"); AppNum(nm, ustrN);
  3759. IF ustrN <= HIGH(ustrNams) THEN
  3760. Cpy(ustrNams[ustrN], nm);
  3761. ustrStart[ustrN] := base; ustrCount[ustrN] := cnt; INC(ustrN)
  3762. END;
  3763. Cpy(q, "$"); App(q, nm)
  3764. END
  3765. END DeclUStr;
  3766. PROCEDURE FlushUStrings;
  3767. VAR k, i: CARDINAL;
  3768. bv: QVal;
  3769. BEGIN
  3770. IF NOT opened THEN RETURN END;
  3771. k := 0;
  3772. WHILE k < ustrN DO
  3773. W("export data $"); W(ustrNams[k]); W(" = { l ");
  3774. IntStr(VAL(INTEGER, ustrCount[k]), bv); W(bv);
  3775. i := 0;
  3776. WHILE i < ustrCount[k] DO
  3777. W(", w ");
  3778. IntStr(ustrPool[ustrStart[k] + i], bv); W(bv);
  3779. INC(i)
  3780. END;
  3781. WL(" }");
  3782. INC(k)
  3783. END
  3784. END FlushUStrings;
  3785. PROCEDURE DeclCharStr (ch: ARRAY OF CHAR; VAR q: QVal);
  3786. VAR v: INTEGER;
  3787. txt: ARRAY [0 .. 3] OF CHAR;
  3788. BEGIN
  3789. IF ParseInt(ch, v) AND (v >= 0) AND (v < 256) THEN
  3790. txt[0] := '"'; txt[1] := CHR(v); txt[2] := '"'; txt[3] := CHR(0);
  3791. DeclStr(txt, q)
  3792. ELSE Cpy(q, "0")
  3793. END
  3794. END DeclCharStr;
  3795. PROCEDURE FindStrPos (v: ARRAY OF CHAR; VAR k: CARDINAL): BOOLEAN;
  3796. VAR j: CARDINAL;
  3797. sv: QVal;
  3798. BEGIN
  3799. j := 0;
  3800. WHILE j < nStr DO
  3801. Cpy(sv, "$"); App(sv, strNams[j]);
  3802. IF SymTab.Equal(sv, v) THEN k := j; RETURN TRUE END;
  3803. INC(j)
  3804. END;
  3805. RETURN FALSE
  3806. END FindStrPos;
  3807. PROCEDURE StrLitLen (v: ARRAY OF CHAR; VAR n: INTEGER): BOOLEAN;
  3808. VAR k: CARDINAL;
  3809. BEGIN
  3810. n := 0;
  3811. IF NOT FindStrPos(v, k) THEN RETURN FALSE END;
  3812. n := VAL(INTEGER, SymTab.StrLen(strTexts[k]) - 2);
  3813. RETURN TRUE
  3814. END StrLitLen;
  3815. PROCEDURE StrFold (a, b: ARRAY OF CHAR; clsA, clsB: INTEGER;
  3816. VAR q: QVal; VAR ok: BOOLEAN);
  3817. (* Constant-fold `a + b` into one string literal descriptor. *)
  3818. VAR ka, kb: CARDINAL;
  3819. ta, tb, joined: ARRAY [0 .. 1023] OF CHAR;
  3820. oa, ob, ord: INTEGER;
  3821. i, L: CARDINAL;
  3822. isCharA, isCharB: BOOLEAN;
  3823. PROCEDURE AppendInner (VAR s: ARRAY OF CHAR; txt: ARRAY OF CHAR);
  3824. VAR n: CARDINAL;
  3825. c2: ARRAY [0 .. 1] OF CHAR;
  3826. BEGIN
  3827. n := Len(txt);
  3828. IF n >= 2 THEN
  3829. i := 1;
  3830. WHILE i < n - 1 DO
  3831. c2[0] := txt[i]; c2[1] := CHR(0);
  3832. App(s, c2);
  3833. INC(i)
  3834. END
  3835. END
  3836. END AppendInner;
  3837. BEGIN
  3838. ok := FALSE;
  3839. isCharA := (clsA = SymTab.ClChar) OR (clsA = SymTab.ClEnum)
  3840. OR (clsA = SymTab.ClBool);
  3841. isCharB := (clsB = SymTab.ClChar) OR (clsB = SymTab.ClEnum)
  3842. OR (clsB = SymTab.ClBool);
  3843. IF isCharA THEN
  3844. IF NOT ParseInt(a, oa) THEN RETURN END
  3845. ELSIF NOT FindStrPos(a, ka) THEN RETURN
  3846. END;
  3847. IF isCharB THEN
  3848. IF NOT ParseInt(b, ob) THEN RETURN END
  3849. ELSIF NOT FindStrPos(b, kb) THEN RETURN
  3850. END;
  3851. joined[0] := '"'; joined[1] := CHR(0);
  3852. IF isCharA THEN
  3853. IF (oa < 0) OR (oa > 255) THEN RETURN END;
  3854. joined[1] := CHR(oa); joined[2] := CHR(0)
  3855. ELSE AppendInner(joined, strTexts[ka])
  3856. END;
  3857. IF isCharB THEN
  3858. IF (ob < 0) OR (ob > 255) THEN RETURN END;
  3859. L := Len(joined); joined[L] := CHR(ob); joined[L + 1] := CHR(0)
  3860. ELSE AppendInner(joined, strTexts[kb])
  3861. END;
  3862. L := Len(joined); joined[L] := '"'; joined[L + 1] := CHR(0);
  3863. DeclStr(joined, q);
  3864. ok := TRUE
  3865. END StrFold;
  3866. PROCEDURE FlushStrings;
  3867. (* Emits all recorded string literals as top-level data. *)
  3868. VAR k, i, L: CARDINAL;
  3869. bv: QVal;
  3870. BEGIN
  3871. IF NOT opened THEN RETURN END;
  3872. k := 0;
  3873. WHILE k < nStr DO
  3874. L := Len(strTexts[k]);
  3875. IF L >= 2 THEN
  3876. W("export data $"); W(strNams[k]);
  3877. W(" = { l ");
  3878. IntStr(VAL(INTEGER, L - 2), bv);
  3879. W(bv);
  3880. i := 1;
  3881. WHILE i < L - 1 DO
  3882. W(", b ");
  3883. IntStr(ORD(strTexts[k][i]), bv);
  3884. W(bv);
  3885. INC(i)
  3886. END;
  3887. W(", b 0"); (* NUL terminator (count excludes it) *)
  3888. WL(" }")
  3889. END;
  3890. INC(k)
  3891. END
  3892. END FlushStrings;
  3893. PROCEDURE DeclMultiArr (name: ARRAY OF CHAR; t: INTEGER);
  3894. (* Static fixed multi-dimensional array: a chain of view descriptors
  3895. plus one contiguous payload block. One-dimensional arrays still use
  3896. ArrData. *)
  3897. VAR rank, k, count, stride, payload: CARDINAL;
  3898. cur: SymTab.TypeIndex;
  3899. lab, base, nxt, bv, sv, pv: QVal;
  3900. BEGIN
  3901. IF NOT opened THEN RETURN END;
  3902. rank := SymTab.ArrayDepth(t);
  3903. IF rank < 2 THEN ArrData(name, t); RETURN END;
  3904. payload := SymTab.ArrayPayloadSize(t);
  3905. cur := t;
  3906. k := 0;
  3907. WHILE k < rank DO
  3908. count := SymTab.ArrayLen(cur);
  3909. stride := SymTab.ArrayStride(t, k);
  3910. Cpy(lab, name);
  3911. IF k > 0 THEN
  3912. App(lab, "_t"); IntStr(VAL(INTEGER, k), bv); App(lab, bv)
  3913. END;
  3914. IF k = 0 THEN
  3915. Cpy(base, "$"); App(base, name); App(base, "_data")
  3916. ELSE
  3917. Cpy(base, "0")
  3918. END;
  3919. IF k + 1 < rank THEN
  3920. Cpy(nxt, "$"); App(nxt, name); App(nxt, "_t");
  3921. IntStr(VAL(INTEGER, k + 1), bv); App(nxt, bv)
  3922. ELSE
  3923. Cpy(nxt, "0")
  3924. END;
  3925. W("export data $"); W(lab); W(" = { l ");
  3926. IntStr(VAL(INTEGER, count), bv); W(bv);
  3927. W(", l "); IntStr(VAL(INTEGER, stride), sv); W(sv);
  3928. W(", l "); W(sv);
  3929. W(", l "); W(base);
  3930. W(", l "); W(nxt); WL(" }");
  3931. cur := SymTab.ArrayElem(cur);
  3932. INC(k)
  3933. END;
  3934. W("export data $"); W(name); W("_data = { z ");
  3935. IntStr(VAL(INTEGER, payload), pv); W(pv); WL(" }")
  3936. END DeclMultiArr;
  3937. PROCEDURE DeclArr (name: ARRAY OF CHAR; t: INTEGER);
  3938. BEGIN
  3939. IF SymTab.IsOpenArray(t) OR (SymTab.ArrayDepth(t) = 0) THEN
  3940. DataLine(name, FALSE, "0"); RETURN
  3941. END;
  3942. IF SymTab.IsMultiArray(t) THEN DeclMultiArr(name, t)
  3943. ELSE ArrData(name, t)
  3944. END
  3945. END DeclArr;
  3946. (* ---------------- array constructors (step: `T{...}`) ---------------- *)
  3947. (* A constructor becomes a pooled static descriptor with the same
  3948. layout as a declared array: "l <ArrayLen>, <items>" (CHAR/UCHAR
  3949. get a trailing zero terminator slot, like ArrBodyItems). Nested
  3950. arrays are emitted as their own pooled descriptors and referenced
  3951. by `l $ctoK` so the runtime descriptor pointers stay valid. *)
  3952. PROCEDURE IsBakeOp (v: ARRAY OF CHAR): BOOLEAN;
  3953. (* TRUE when v may be embedded in a static descriptor: an immediate,
  3954. or a pooled constructor/label reference ($ctoN / $<mod>_ctoN).
  3955. A plain global address ($mod_var) is NOT bakeable into an inline
  3956. field. *)
  3957. VAR i: CARDINAL;
  3958. BEGIN
  3959. IF (v[0] = CHR(0)) OR (v[0] = "%") THEN RETURN FALSE END;
  3960. IF v[0] # "$" THEN RETURN TRUE END;
  3961. RETURN IsCtorRef(v)
  3962. END IsBakeOp;
  3963. PROCEDURE CtorItem (VAR buf: ARRAY OF CHAR; v: ARRAY OF CHAR;
  3964. cls: INTEGER);
  3965. BEGIN
  3966. App(buf, ", ");
  3967. IF (cls = SymTab.ClChar) OR (cls = SymTab.ClByte)
  3968. OR (cls = SymTab.ClSByte) THEN
  3969. App(buf, "b ")
  3970. ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN
  3971. App(buf, "h ")
  3972. ELSIF cls = SymTab.ClReal THEN
  3973. App(buf, "d ")
  3974. ELSIF (cls = SymTab.ClPtr) OR (cls = SymTab.ClProc)
  3975. OR (cls = SymTab.ClLong) OR (cls = SymTab.ClArray) THEN
  3976. App(buf, "l ")
  3977. ELSE
  3978. App(buf, "w ")
  3979. END;
  3980. App(buf, v)
  3981. END CtorItem;
  3982. PROCEDURE RecItem (VAR s: ARRAY OF CHAR; VAR first: BOOLEAN;
  3983. v: ARRAY OF CHAR; cls: INTEGER);
  3984. (* Record field item with a leading separator when not first. *)
  3985. BEGIN
  3986. IF first THEN first := FALSE ELSE App(s, ", ") END;
  3987. IF cls = SymTab.ClChar THEN App(s, "b ")
  3988. ELSIF cls = SymTab.ClReal THEN App(s, "d ")
  3989. ELSIF (cls = SymTab.ClPtr) OR (cls = SymTab.ClProc)
  3990. OR (cls = SymTab.ClLong) OR (cls = SymTab.ClArray) THEN
  3991. App(s, "l ")
  3992. ELSE
  3993. App(s, "w ")
  3994. END;
  3995. App(s, v)
  3996. END RecItem;
  3997. PROCEDURE ArrZeroBody (VAR s: ARRAY OF CHAR; t: INTEGER);
  3998. (* "l <n>, z <bytes>" — an all-zero array body (used for a record's
  3999. unprovided array field). *)
  4000. VAR n: CARDINAL;
  4001. elem: SymTab.TypeIndex;
  4002. ecls: INTEGER;
  4003. esz: CARDINAL;
  4004. bv: QVal;
  4005. BEGIN
  4006. n := SymTab.ArrayLen(t);
  4007. elem := SymTab.ArrayElem(t);
  4008. ecls := SymTab.ClassOf(elem);
  4009. App(s, "l ");
  4010. IntStr(VAL(INTEGER, n), bv);
  4011. App(s, bv);
  4012. IF ecls = SymTab.ClChar THEN
  4013. App(s, ", z "); IntStr(VAL(INTEGER, n + 1), bv); App(s, bv)
  4014. ELSIF ecls = SymTab.ClUChar THEN
  4015. App(s, ", z "); IntStr(VAL(INTEGER, (n + 1) * 4), bv); App(s, bv)
  4016. ELSE
  4017. IF (ecls = SymTab.ClReal) OR (ecls = SymTab.ClPtr)
  4018. OR (ecls = SymTab.ClProc) OR (ecls = SymTab.ClArray)
  4019. OR (ecls = SymTab.ClLong) THEN esz := 8
  4020. ELSE esz := 4
  4021. END;
  4022. IF n > 0 THEN
  4023. App(s, ", z "); IntStr(VAL(INTEGER, n * esz), bv); App(s, bv)
  4024. END
  4025. END
  4026. END ArrZeroBody;
  4027. PROCEDURE FindCtor (v: ARRAY OF CHAR): INTEGER;
  4028. VAR k: CARDINAL;
  4029. sv: QVal;
  4030. BEGIN
  4031. k := 0;
  4032. WHILE k < ctorN DO
  4033. Cpy(sv, "$"); App(sv, ctorNam[k]);
  4034. IF SymTab.Equal(sv, v) THEN RETURN VAL(INTEGER, k) END;
  4035. INC(k)
  4036. END;
  4037. RETURN -1
  4038. END FindCtor;
  4039. (* default items for a nested record field, appended to s *)
  4040. PROCEDURE RecItemDefaults (VAR s: ARRAY OF CHAR; VAR first: BOOLEAN;
  4041. prefix: ARRAY OF CHAR; t: INTEGER);
  4042. VAR i, n, cls, w: INTEGER;
  4043. fn: SymTab.Name;
  4044. ft: SymTab.TypeIndex;
  4045. sub: QVal;
  4046. BEGIN
  4047. n := VAL(INTEGER, SymTab.FieldCount(t));
  4048. i := 0;
  4049. WHILE i < n DO
  4050. SymTab.FieldName(t, i, fn);
  4051. ft := SymTab.FieldType(t, fn);
  4052. cls := SymTab.ClassOf(ft);
  4053. IF first THEN first := FALSE ELSE App(s, ", ") END;
  4054. IF cls = SymTab.ClReal THEN App(s, "d 0")
  4055. ELSIF cls = SymTab.ClChar THEN App(s, "b 0")
  4056. ELSIF cls = SymTab.ClArray THEN ArrZeroBody(s, ft)
  4057. ELSIF cls = SymTab.ClSet THEN
  4058. w := VAL(INTEGER, SymTab.SetWords(ft));
  4059. IF w = 0 THEN w := 1 END;
  4060. App(s, "w 0");
  4061. WHILE w > 1 DO App(s, ", w 0"); DEC(w) END
  4062. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  4063. Cpy(sub, prefix); App(sub, "_"); App(sub, fn);
  4064. RecItemDefaults(s, first, sub, ft)
  4065. ELSE App(s, "w 0")
  4066. END;
  4067. INC(i)
  4068. END
  4069. END RecItemDefaults;
  4070. PROCEDURE CtorBegin (t: INTEGER);
  4071. BEGIN
  4072. IF ctorTop > HIGH(ctorTyp) THEN RETURN END;
  4073. ctorTyp[ctorTop] := t;
  4074. ctorCnt[ctorTop] := 0;
  4075. ctorBuf[ctorTop][0] := CHR(0);
  4076. INC(ctorTop)
  4077. END CtorBegin;
  4078. PROCEDURE CtorElemType (t: INTEGER; cnt: CARDINAL): SymTab.TypeIndex;
  4079. (* the type of the cnt-th constructor element: array element, or the
  4080. cnt-th record field in declaration order. *)
  4081. VAR fn: SymTab.Name;
  4082. BEGIN
  4083. IF SymTab.ClassOf(t) = SymTab.ClArray THEN
  4084. RETURN SymTab.ArrayElem(t)
  4085. END;
  4086. SymTab.FieldName(t, cnt, fn);
  4087. IF fn[0] = CHR(0) THEN RETURN SymTab.InvalidType END;
  4088. RETURN SymTab.FieldType(t, fn)
  4089. END CtorElemType;
  4090. PROCEDURE StrDesc (v: ARRAY OF CHAR; elemT: INTEGER; VAR out: QVal);
  4091. (* v is a $strN descriptor; build a CHAR-array descriptor of type
  4092. elemT from its text (padded/NUL-terminated) and return "$ctoM". *)
  4093. VAR k: CARDINAL;
  4094. found: BOOLEAN;
  4095. txt, bv, sv: QVal;
  4096. buf: ARRAY [0 .. 4095] OF CHAR;
  4097. n, i, L: CARDINAL;
  4098. BEGIN
  4099. Cpy(out, v);
  4100. IF (ctorN > HIGH(ctorNam)) THEN RETURN END;
  4101. found := FALSE; k := 0;
  4102. WHILE (k < nStr) AND NOT found DO
  4103. Cpy(sv, "$"); App(sv, strNams[k]);
  4104. IF SymTab.Equal(sv, v) THEN
  4105. Cpy(txt, strTexts[k]); found := TRUE
  4106. ELSE INC(k)
  4107. END
  4108. END;
  4109. IF NOT found THEN RETURN END;
  4110. L := Len(txt);
  4111. n := SymTab.ArrayLen(elemT);
  4112. buf[0] := CHR(0);
  4113. App(buf, "l ");
  4114. IntStr(VAL(INTEGER, n), bv);
  4115. App(buf, bv);
  4116. i := 0;
  4117. WHILE i < n DO
  4118. IF (i + 1 < L - 1) AND ((i + 1) <= HIGH(txt)) THEN
  4119. IntStr(ORD(txt[i + 1]), bv)
  4120. ELSE Cpy(bv, "0")
  4121. END;
  4122. CtorItem(buf, bv, SymTab.ClChar);
  4123. INC(i)
  4124. END;
  4125. App(buf, ", b 0");
  4126. Cpy(ctorNam[ctorN], curModName); App(ctorNam[ctorN], "_cto");
  4127. AppNum(ctorNam[ctorN], ctorN);
  4128. Cpy(ctorTxt[ctorN], buf);
  4129. ctorUse[ctorN] := TRUE;
  4130. INC(ctorN);
  4131. Cpy(out, "$"); App(out, ctorNam[ctorN - 1])
  4132. END StrDesc;
  4133. PROCEDURE AppCtorElem (v: ARRAY OF CHAR; cls: INTEGER);
  4134. VAR cnt: CARDINAL;
  4135. BEGIN
  4136. IF ctorTop = 0 THEN RETURN END;
  4137. cnt := ctorCnt[ctorTop - 1];
  4138. IF cnt > HIGH(ctorEv[0]) THEN RETURN END;
  4139. Cpy(ctorEv[ctorTop - 1][cnt], v);
  4140. ctorEk[ctorTop - 1][cnt] := cls;
  4141. INC(ctorCnt[ctorTop - 1])
  4142. END AppCtorElem;
  4143. PROCEDURE CtorElem (v: ARRAY OF CHAR);
  4144. (* Record the next constructor element. The element type is derived
  4145. from the constructor's type and the element index. A string literal
  4146. filling a CHAR element expands into consecutive elements. *)
  4147. VAR t, elemT, cls, k, si: INTEGER;
  4148. cnt: CARDINAL;
  4149. vv, bv: QVal;
  4150. isStr: BOOLEAN;
  4151. BEGIN
  4152. IF ctorTop = 0 THEN RETURN END;
  4153. t := ctorTyp[ctorTop - 1];
  4154. elemT := CtorElemType(t, ctorCnt[ctorTop - 1]);
  4155. cls := SymTab.ClassOf(elemT);
  4156. isStr := IsStrRef(v);
  4157. IF cls = SymTab.ClChar THEN
  4158. IF isStr AND FindStrPos(v, cnt) THEN
  4159. k := 1;
  4160. WHILE k < VAL(INTEGER, Len(strTexts[cnt])) - 1 DO
  4161. IntStr(ORD(strTexts[cnt][k]), bv);
  4162. AppCtorElem(bv, SymTab.ClChar);
  4163. INC(k)
  4164. END;
  4165. RETURN
  4166. END;
  4167. AppCtorElem(v, SymTab.ClChar);
  4168. RETURN
  4169. END;
  4170. Cpy(vv, v);
  4171. IF (cls = SymTab.ClArray) AND isStr
  4172. AND (SymTab.ClassOf(SymTab.ArrayElem(elemT)) = SymTab.ClChar) THEN
  4173. StrDesc(v, elemT, vv)
  4174. END;
  4175. AppCtorElem(vv, cls)
  4176. END CtorElem;
  4177. PROCEDURE NewCtorTemp (t: INTEGER; VAR q: QVal);
  4178. VAR nb: QVal;
  4179. BEGIN
  4180. NewTemp(q);
  4181. Revive;
  4182. IntStr(VAL(INTEGER, HeapSize(t)), nb);
  4183. W(" "); W(q); W(" =l alloc8 "); WL(nb)
  4184. END NewCtorTemp;
  4185. PROCEDURE InitArrHeader (addr: ARRAY OF CHAR; t: INTEGER);
  4186. (* Store an inline array's count header (and CHAR/UCHAR terminator
  4187. slot) at addr, so a following CopyArray sees matching counts. *)
  4188. VAR nb, ea: QVal;
  4189. BEGIN
  4190. IF SymTab.ClassOf(t) # SymTab.ClArray THEN RETURN END;
  4191. IntStr(VAL(INTEGER, SymTab.ArrayLen(t)), nb);
  4192. Revive; W(" storel "); W(nb); W(", "); WL(addr);
  4193. IF SymTab.IsCharArray(t) THEN
  4194. IntStr(VAL(INTEGER, 8 + SymTab.ArrayLen(t)), nb);
  4195. NewTemp(ea); Op3L("add", ea, addr, nb);
  4196. Revive; W(" storeb 0, "); WL(ea)
  4197. END;
  4198. IF SymTab.IsUCharArray(t) THEN
  4199. IntStr(VAL(INTEGER, 8 + SymTab.ArrayLen(t) * 4), nb);
  4200. NewTemp(ea); Op3L("add", ea, addr, nb);
  4201. Revive; W(" storew 0, "); WL(ea)
  4202. END
  4203. END InitArrHeader;
  4204. PROCEDURE CtorArrStatic (VAR s: ARRAY OF CHAR; lvl: CARDINAL;
  4205. t: INTEGER; cnt: CARDINAL);
  4206. VAR elem, ecls, n, k, ci: INTEGER;
  4207. v: QVal;
  4208. BEGIN
  4209. elem := SymTab.ArrayElem(t);
  4210. ecls := SymTab.ClassOf(elem);
  4211. n := VAL(INTEGER, SymTab.ArrayLen(t));
  4212. App(s, "l ");
  4213. IntStr(n, v);
  4214. App(s, v);
  4215. k := 0;
  4216. WHILE k < n DO
  4217. IF k < VAL(INTEGER, cnt) THEN
  4218. Cpy(v, ctorEv[lvl][k])
  4219. ELSE Cpy(v, "0")
  4220. END;
  4221. IF (ecls = SymTab.ClRecord) OR (ecls = SymTab.ClClass) THEN
  4222. ci := FindCtor(v);
  4223. IF ci >= 0 THEN
  4224. App(s, ", "); App(s, ctorTxt[ci]);
  4225. ctorUse[ci] := FALSE
  4226. ELSE
  4227. AppFlatZero(s, SymTab.TypeSize(elem))
  4228. END
  4229. ELSE
  4230. CtorItem(s, v, ecls)
  4231. END;
  4232. INC(k)
  4233. END;
  4234. IF ecls = SymTab.ClChar THEN App(s, ", b 0")
  4235. ELSIF ecls = SymTab.ClUChar THEN App(s, ", w 0")
  4236. END
  4237. END CtorArrStatic;
  4238. PROCEDURE NextCtorTok (txt: ARRAY OF CHAR; VAR pos: CARDINAL;
  4239. VAR kind: CHAR; VAR val: QVal): BOOLEAN;
  4240. VAR L, j: CARDINAL;
  4241. BEGIN
  4242. val[0] := CHR(0); kind := CHR(0);
  4243. L := Len(txt);
  4244. WHILE (pos < L) AND ((txt[pos] = " ") OR (txt[pos] = ",")) DO
  4245. INC(pos)
  4246. END;
  4247. IF (pos >= L) OR (txt[pos] = "}") THEN RETURN FALSE END;
  4248. kind := txt[pos]; INC(pos);
  4249. WHILE (pos < L) AND (txt[pos] = " ") DO INC(pos) END;
  4250. j := 0;
  4251. WHILE (pos < L) AND (txt[pos] # ",") AND (txt[pos] # " ")
  4252. AND (txt[pos] # "}") DO
  4253. IF j <= HIGH(val) THEN val[j] := txt[pos] END;
  4254. INC(j); INC(pos)
  4255. END;
  4256. IF j <= HIGH(val) THEN val[j] := CHR(0) END;
  4257. RETURN TRUE
  4258. END NextCtorTok;
  4259. PROCEDURE AppFlat (VAR out: ARRAY OF CHAR; kind: CHAR; val: ARRAY OF CHAR);
  4260. VAR n: CARDINAL;
  4261. BEGIN
  4262. IF out[0] # CHR(0) THEN App(out, ", ") END;
  4263. IF kind # CHR(0) THEN
  4264. n := Len(out);
  4265. out[n] := kind;
  4266. out[n + 1] := CHR(0);
  4267. App(out, " ")
  4268. END;
  4269. App(out, val)
  4270. END AppFlat;
  4271. PROCEDURE AppFlatZero (VAR out: ARRAY OF CHAR; n: CARDINAL);
  4272. VAR bv: QVal;
  4273. BEGIN
  4274. IF n = 0 THEN RETURN END;
  4275. IF out[0] # CHR(0) THEN App(out, ", ") END;
  4276. App(out, "z ");
  4277. IntStr(VAL(INTEGER, n), bv); App(out, bv)
  4278. END AppFlatZero;
  4279. PROCEDURE AppZeroItem (VAR out: ARRAY OF CHAR; n: CARDINAL);
  4280. VAR bv: QVal;
  4281. BEGIN
  4282. IF n = 0 THEN RETURN END;
  4283. App(out, "z ");
  4284. IntStr(VAL(INTEGER, n), bv); App(out, bv)
  4285. END AppZeroItem;
  4286. PROCEDURE FlattenArrayText (txt: ARRAY OF CHAR; t: INTEGER;
  4287. VAR out: ARRAY OF CHAR);
  4288. VAR pos: CARDINAL; kind: CHAR; val: QVal; n, i, elemN, ci: INTEGER;
  4289. elem: SymTab.TypeIndex;
  4290. BEGIN
  4291. pos := 0;
  4292. IF (NOT NextCtorTok(txt, pos, kind, val)) OR (kind # "l")
  4293. OR (NOT ParseInt(val, n)) OR (n < 0) THEN
  4294. AppFlatZero(out, SymTab.ArrayPayloadSize(t)); RETURN
  4295. END;
  4296. elem := SymTab.ArrayElem(t);
  4297. elemN := VAL(INTEGER, SymTab.ArrayPayloadSize(elem));
  4298. i := 0;
  4299. WHILE i < n DO
  4300. IF NOT NextCtorTok(txt, pos, kind, val) THEN
  4301. AppFlatZero(out, VAL(CARDINAL, elemN))
  4302. ELSIF SymTab.ClassOf(elem) = SymTab.ClArray THEN
  4303. ci := FindCtor(val);
  4304. IF (kind = "l") AND (val[0] = "$") AND (ci >= 0) THEN
  4305. FlattenArrayText(ctorTxt[ci], elem, out)
  4306. ELSE
  4307. AppFlatZero(out, VAL(CARDINAL, elemN))
  4308. END
  4309. ELSE
  4310. AppFlat(out, kind, val)
  4311. END;
  4312. INC(i)
  4313. END
  4314. END FlattenArrayText;
  4315. PROCEDURE FlattenCtorText (v: ARRAY OF CHAR; t: INTEGER;
  4316. VAR out: ARRAY OF CHAR);
  4317. VAR ci: INTEGER;
  4318. BEGIN
  4319. ci := FindCtor(v);
  4320. IF ci < 0 THEN
  4321. AppFlatZero(out, SymTab.ArrayPayloadSize(t))
  4322. ELSE
  4323. FlattenArrayText(ctorTxt[ci], t, out)
  4324. END
  4325. END FlattenCtorText;
  4326. PROCEDURE CtorRecStatic (VAR s: ARRAY OF CHAR; lvl: CARDINAL;
  4327. t: INTEGER; cnt: CARDINAL);
  4328. (* Static record body: fields in declaration order; an array/record
  4329. field given as a nested constructor is inlined (and that child
  4330. descriptor is marked consumed). *)
  4331. VAR i, n, cls, ci, w: INTEGER;
  4332. fn: SymTab.Name;
  4333. ft: SymTab.TypeIndex;
  4334. v, bv: QVal;
  4335. flat: ARRAY [0 .. 4095] OF CHAR;
  4336. first: BOOLEAN;
  4337. BEGIN
  4338. first := TRUE;
  4339. IF (SymTab.ClassOf(t) = SymTab.ClClass) AND SymTab.HasVTable(t) THEN
  4340. VtRef(t, bv);
  4341. App(s, "l "); App(s, bv);
  4342. first := FALSE
  4343. END;
  4344. n := VAL(INTEGER, SymTab.FieldCount(t));
  4345. i := 0;
  4346. WHILE i < n DO
  4347. SymTab.FieldName(t, i, fn);
  4348. ft := SymTab.FieldType(t, fn);
  4349. cls := SymTab.ClassOf(ft);
  4350. v[0] := CHR(0);
  4351. IF i < VAL(INTEGER, cnt) THEN Cpy(v, ctorEv[lvl][i]) END;
  4352. IF (v[0] # CHR(0)) AND (cls = SymTab.ClArray)
  4353. AND SymTab.IsMultiArray(ft) THEN
  4354. flat[0] := CHR(0);
  4355. IF IsCtorRef(v) THEN
  4356. FlattenCtorText(v, ft, flat)
  4357. END;
  4358. IF first THEN first := FALSE ELSE App(s, ", ") END;
  4359. IF flat[0] # CHR(0) THEN App(s, flat)
  4360. ELSE AppZeroItem(s, SymTab.ArrayPayloadSize(ft))
  4361. END
  4362. ELSIF (v[0] # CHR(0)) AND (v[0] = "$")
  4363. AND ((cls = SymTab.ClArray) OR (cls = SymTab.ClRecord)
  4364. OR (cls = SymTab.ClClass)) THEN
  4365. ci := FindCtor(v);
  4366. IF first THEN first := FALSE ELSE App(s, ", ") END;
  4367. IF ci >= 0 THEN
  4368. App(s, ctorTxt[ci]);
  4369. ctorUse[ci] := FALSE
  4370. ELSIF cls = SymTab.ClArray THEN
  4371. IF SymTab.IsMultiArray(ft) THEN
  4372. AppZeroItem(s, SymTab.ArrayPayloadSize(ft))
  4373. ELSE ArrZeroBody(s, ft)
  4374. END
  4375. ELSE App(s, "w 0")
  4376. END
  4377. ELSIF v[0] # CHR(0) THEN
  4378. RecItem(s, first, v, cls)
  4379. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  4380. IF first THEN first := FALSE ELSE App(s, ", ") END;
  4381. Cpy(bv, ctorNam[ctorN]); App(bv, "_"); App(bv, fn);
  4382. RecItemDefaults(s, first, bv, ft)
  4383. ELSE
  4384. IF first THEN first := FALSE ELSE App(s, ", ") END;
  4385. IF cls = SymTab.ClReal THEN App(s, "d 0")
  4386. ELSIF cls = SymTab.ClChar THEN App(s, "b 0")
  4387. ELSIF cls = SymTab.ClArray THEN
  4388. IF SymTab.IsMultiArray(ft) THEN
  4389. AppZeroItem(s, SymTab.ArrayPayloadSize(ft))
  4390. ELSE ArrZeroBody(s, ft)
  4391. END
  4392. ELSIF cls = SymTab.ClSet THEN
  4393. w := VAL(INTEGER, SymTab.SetWords(ft));
  4394. IF w = 0 THEN w := 1 END;
  4395. App(s, "w 0");
  4396. WHILE w > 1 DO App(s, ", w 0"); DEC(w) END
  4397. ELSE App(s, "w 0")
  4398. END
  4399. END;
  4400. INC(i)
  4401. END;
  4402. IF first THEN App(s, "w 0") END
  4403. END CtorRecStatic;
  4404. PROCEDURE ClearBytes (addr: ARRAY OF CHAR; n: CARDINAL);
  4405. VAR nb, a: QVal;
  4406. BEGIN
  4407. IF n = 0 THEN RETURN END;
  4408. IntStr(VAL(INTEGER, n), nb);
  4409. NewTemp(a);
  4410. W(" "); W(a); W(" =l call $memset(l "); W(addr);
  4411. W(", w 0, l "); W(nb); WL(")")
  4412. END ClearBytes;
  4413. PROCEDURE ClearMultiField (addr: ARRAY OF CHAR; t: SymTab.TypeIndex);
  4414. VAR nb, a: QVal;
  4415. BEGIN
  4416. IntStr(VAL(INTEGER, SymTab.ArrayPayloadSize(t)), nb);
  4417. NewTemp(a);
  4418. W(" "); W(a); W(" =l call $memset(l "); W(addr);
  4419. W(", w 0, l "); W(nb); WL(")")
  4420. END ClearMultiField;
  4421. PROCEDURE CtorEnd (VAR q: QVal);
  4422. VAR t, cls, lvl, k, n, cnt, esz, off, ci: INTEGER;
  4423. allc: BOOLEAN;
  4424. bv, a, v, qview: QVal;
  4425. s: ARRAY [0 .. 4095] OF CHAR;
  4426. ft, elem: SymTab.TypeIndex;
  4427. nm: SymTab.Name;
  4428. BEGIN
  4429. IF ctorTop = 0 THEN Cpy(q, "0"); RETURN END;
  4430. DEC(ctorTop);
  4431. lvl := VAL(INTEGER, ctorTop);
  4432. IF noEmit THEN Cpy(q, "0"); RETURN END;
  4433. t := ctorTyp[ctorTop];
  4434. cnt := VAL(INTEGER, ctorCnt[ctorTop]);
  4435. cls := SymTab.ClassOf(t);
  4436. IF (cls # SymTab.ClArray) AND (cls # SymTab.ClRecord)
  4437. AND (cls # SymTab.ClClass) THEN
  4438. Cpy(q, "0"); RETURN
  4439. END;
  4440. allc := TRUE; k := 0;
  4441. WHILE k < cnt DO
  4442. IF NOT IsBakeOp(ctorEv[lvl][k]) THEN allc := FALSE END;
  4443. INC(k)
  4444. END;
  4445. IF allc AND (ctorN <= HIGH(ctorNam)) THEN
  4446. s[0] := CHR(0);
  4447. IF cls = SymTab.ClArray THEN
  4448. CtorArrStatic(s, ctorTop, t, ctorCnt[ctorTop])
  4449. ELSE
  4450. CtorRecStatic(s, ctorTop, t, ctorCnt[ctorTop])
  4451. END;
  4452. Cpy(ctorNam[ctorN], curModName); App(ctorNam[ctorN], "_cto");
  4453. AppNum(ctorNam[ctorN], ctorN);
  4454. Cpy(ctorTxt[ctorN], s);
  4455. ctorUse[ctorN] := TRUE;
  4456. INC(ctorN);
  4457. Cpy(q, "$"); App(q, ctorNam[ctorN - 1])
  4458. ELSE
  4459. (* runtime construction: an all-zero descriptor filled in place *)
  4460. NewCtorTemp(t, q);
  4461. IF cls = SymTab.ClArray THEN
  4462. IntStr(VAL(INTEGER, SymTab.ArrayLen(t)), bv);
  4463. Revive; W(" storel "); W(bv); W(", "); WL(q);
  4464. elem := SymTab.ArrayElem(t);
  4465. esz := VAL(INTEGER, ElemSize(t));
  4466. n := VAL(INTEGER, SymTab.ArrayLen(t));
  4467. k := 0;
  4468. WHILE k < n DO
  4469. off := 8 + k * esz;
  4470. FieldAddr(q, off, a);
  4471. IF (SymTab.ClassOf(elem) = SymTab.ClRecord)
  4472. OR (SymTab.ClassOf(elem) = SymTab.ClClass) THEN
  4473. IF k < cnt THEN
  4474. Cpy(v, ctorEv[lvl][k]);
  4475. CopyRecord(a, v, elem)
  4476. ELSE
  4477. ClearBytes(a, SymTab.TypeSize(elem))
  4478. END
  4479. ELSIF k < cnt THEN
  4480. Cpy(v, ctorEv[lvl][k]);
  4481. ElemStore(a, v, elem)
  4482. ELSE ElemStore(a, "0", elem)
  4483. END;
  4484. INC(k)
  4485. END;
  4486. IF SymTab.ClassOf(elem) = SymTab.ClChar THEN
  4487. off := 8 + n;
  4488. FieldAddr(q, off, a);
  4489. Revive; W(" storeb 0, "); WL(a)
  4490. ELSIF SymTab.ClassOf(elem) = SymTab.ClUChar THEN
  4491. off := 8 + n * 4;
  4492. FieldAddr(q, off, a);
  4493. Revive; W(" storew 0, "); WL(a)
  4494. END
  4495. ELSE
  4496. (* record / class *)
  4497. IF (cls = SymTab.ClClass) AND SymTab.HasVTable(t) THEN
  4498. VtRef(t, bv);
  4499. off := SymTab.VptrOffset(t);
  4500. FieldAddr(q, off, a);
  4501. Revive; W(" storel "); W(bv); W(", "); WL(a)
  4502. END;
  4503. n := VAL(INTEGER, SymTab.FieldCount(t));
  4504. k := 0;
  4505. WHILE k < n DO
  4506. SymTab.FieldName(t, k, nm);
  4507. ft := SymTab.FieldType(t, nm);
  4508. off := SymTab.FieldOffset(t, nm);
  4509. FieldAddr(q, off, a);
  4510. IF k < cnt THEN
  4511. Cpy(v, ctorEv[lvl][k]);
  4512. IF SymTab.ClassOf(ft) = SymTab.ClArray THEN
  4513. IF SymTab.IsMultiArray(ft) THEN
  4514. MakeFieldView(a, ft, qview);
  4515. CopyArray(qview, v, ft)
  4516. ELSE
  4517. InitArrHeader(a, ft);
  4518. CopyArray(a, v, ft)
  4519. END
  4520. ELSIF (SymTab.ClassOf(ft) = SymTab.ClRecord)
  4521. OR (SymTab.ClassOf(ft) = SymTab.ClClass) THEN
  4522. CopyRecord(a, v, ft)
  4523. ELSIF SymTab.ClassOf(ft) = SymTab.ClSet THEN
  4524. CopySet(a, v, SymTab.SetWords(ft), SymTab.SetWords(ft))
  4525. ELSE ElemStore(a, v, ft)
  4526. END
  4527. ELSIF (SymTab.ClassOf(ft) = SymTab.ClArray)
  4528. AND SymTab.IsMultiArray(ft) THEN
  4529. ClearMultiField(a, ft)
  4530. ELSIF (SymTab.ClassOf(ft) = SymTab.ClReal)
  4531. OR (SymTab.ClassOf(ft) = SymTab.ClChar)
  4532. OR (SymTab.ClassOf(ft) = SymTab.ClInt)
  4533. OR (SymTab.ClassOf(ft) = SymTab.ClBool)
  4534. OR (SymTab.ClassOf(ft) = SymTab.ClEnum)
  4535. OR (SymTab.ClassOf(ft) = SymTab.ClLong)
  4536. OR (SymTab.ClassOf(ft) = SymTab.ClPtr)
  4537. OR (SymTab.ClassOf(ft) = SymTab.ClProc) THEN
  4538. ElemStore(a, "0", ft)
  4539. END;
  4540. INC(k)
  4541. END
  4542. END
  4543. END
  4544. END CtorEnd;
  4545. PROCEDURE FlushCtors;
  4546. VAR k: CARDINAL;
  4547. BEGIN
  4548. IF NOT opened THEN RETURN END;
  4549. k := 0;
  4550. WHILE k < ctorN DO
  4551. IF ctorUse[k] THEN
  4552. W("export data $"); W(ctorNam[k]); W(" = { "); W(ctorTxt[k]); WL(" }")
  4553. END;
  4554. INC(k)
  4555. END
  4556. END FlushCtors;
  4557. PROCEDURE PushLoop (exit: ARRAY OF CHAR);
  4558. BEGIN
  4559. IF loopTop <= HIGH(loopSt) THEN
  4560. Cpy(loopSt[loopTop], exit); INC(loopTop)
  4561. END
  4562. END PushLoop;
  4563. PROCEDURE PopLoop;
  4564. BEGIN
  4565. IF loopTop > 0 THEN DEC(loopTop) END
  4566. END PopLoop;
  4567. PROCEDURE TopLoop (VAR exit: QVal): BOOLEAN;
  4568. BEGIN
  4569. IF loopTop = 0 THEN RETURN FALSE END;
  4570. Cpy(exit, loopSt[loopTop - 1]);
  4571. RETURN TRUE
  4572. END TopLoop;
  4573. PROCEDURE CmpL (op: INTEGER; l, r: ARRAY OF CHAR; VAR q: QVal);
  4574. VAR mn : ARRAY [0 .. 7] OF CHAR;
  4575. BEGIN
  4576. mn[0] := CHR(0);
  4577. IF op = SymTab.OpEq THEN Cpy(mn, "ceql")
  4578. ELSE Cpy(mn, "cnel")
  4579. END;
  4580. NewTemp(q);
  4581. Op3(mn, q, l, r, FALSE)
  4582. END CmpL;
  4583. (* ---------------- heap (step 3.6: extern malloc/free) ---------------- *)
  4584. (* Only the object skeleton is initialized (array counts); elements
  4585. and members stay garbage per Wirth, except nested objects which
  4586. are allocated recursively. DISPOSE is shallow (documented). *)
  4587. PROCEDURE HeapSize (t: INTEGER): CARDINAL;
  4588. VAR cls: INTEGER;
  4589. n: CARDINAL;
  4590. BEGIN
  4591. cls := SymTab.ClassOf(t);
  4592. IF (cls = SymTab.ClArray) AND SymTab.IsMultiArray(t) THEN
  4593. RETURN SymTab.ArrayDepth(t) * 40 + SymTab.ArrayPayloadSize(t)
  4594. ELSIF cls = SymTab.ClArray THEN
  4595. n := SymTab.ArrayLen(t) * ElemSize(t);
  4596. IF SymTab.IsCharArray(t) THEN n := n + 1 END;
  4597. IF SymTab.IsUCharArray(t) THEN n := n + 4 END;
  4598. RETURN 8 + n
  4599. END;
  4600. RETURN SymTab.TypeSize(t)
  4601. END HeapSize;
  4602. PROCEDURE NewHeap (t: SymTab.TypeIndex; VAR q: QVal);
  4603. VAR nb: QVal;
  4604. BEGIN
  4605. NewTemp(q);
  4606. Revive;
  4607. IntStr(VAL(INTEGER, HeapSize(t)), nb);
  4608. W(" "); W(q);
  4609. IF useStack THEN W(" =l alloc8 "); W(nb); WL("")
  4610. ELSE W(" =l call $malloc(l "); W(nb); WL(")")
  4611. END
  4612. END NewHeap;
  4613. PROCEDURE FreeHeap (v: ARRAY OF CHAR);
  4614. BEGIN
  4615. Revive;
  4616. W(" call $free(l "); W(v); WL(")")
  4617. END FreeHeap;
  4618. PROCEDURE InitMultiHeap (addr: ARRAY OF CHAR; t: SymTab.TypeIndex);
  4619. (* Initialise the per-level view chain and zero the flat payload. *)
  4620. VAR rank, k, count, stride, payload: CARDINAL;
  4621. cur: SymTab.TypeIndex;
  4622. v, a, nb, off, pay: QVal;
  4623. BEGIN
  4624. rank := SymTab.ArrayDepth(t);
  4625. payload := SymTab.ArrayPayloadSize(t);
  4626. cur := t;
  4627. k := 0;
  4628. WHILE k < rank DO
  4629. IntStr(VAL(INTEGER, k * 40), off);
  4630. NewTemp(v); Op3L("add", v, addr, off);
  4631. count := SymTab.ArrayLen(cur);
  4632. IntStr(VAL(INTEGER, count), nb);
  4633. Revive; W(" storel "); W(nb); W(", "); WL(v);
  4634. stride := SymTab.ArrayStride(t, k);
  4635. IntStr(VAL(INTEGER, stride), nb);
  4636. NewTemp(a); Op3L("add", a, v, "8");
  4637. Revive; W(" storel "); W(nb); W(", "); WL(a);
  4638. NewTemp(a); Op3L("add", a, v, "16");
  4639. Revive; W(" storel "); W(nb); W(", "); WL(a);
  4640. IF k = 0 THEN
  4641. IntStr(VAL(INTEGER, rank * 40), off);
  4642. NewTemp(pay); Op3L("add", pay, addr, off);
  4643. NewTemp(a); Op3L("add", a, v, "24");
  4644. Revive; W(" storel "); W(pay); W(", "); WL(a)
  4645. ELSE
  4646. NewTemp(a); Op3L("add", a, v, "24");
  4647. Revive; W(" storel 0, "); WL(a)
  4648. END;
  4649. IF k + 1 < rank THEN
  4650. IntStr(VAL(INTEGER, (k + 1) * 40), off);
  4651. NewTemp(a); Op3L("add", a, addr, off);
  4652. NewTemp(nb); Op3L("add", nb, v, "32");
  4653. Revive; W(" storel "); W(a); W(", "); WL(nb)
  4654. ELSE
  4655. NewTemp(a); Op3L("add", a, v, "32");
  4656. Revive; W(" storel 0, "); WL(a)
  4657. END;
  4658. cur := SymTab.ArrayElem(cur);
  4659. INC(k)
  4660. END;
  4661. IntStr(VAL(INTEGER, rank * 40), off);
  4662. NewTemp(pay); Op3L("add", pay, addr, off);
  4663. IntStr(VAL(INTEGER, payload), nb);
  4664. NewTemp(a); W(" "); W(a); W(" =l call $memset(l ");
  4665. W(pay); W(", w 0, l "); W(nb); WL(")")
  4666. END InitMultiHeap;
  4667. PROCEDURE InitMultiField (addr: ARRAY OF CHAR; t: SymTab.TypeIndex);
  4668. BEGIN
  4669. ClearMultiField(addr, t)
  4670. END InitMultiField;
  4671. PROCEDURE InitHeap (addr: ARRAY OF CHAR; t: SymTab.TypeIndex);
  4672. VAR cls, ecls: INTEGER;
  4673. n, i: CARDINAL;
  4674. fn: SymTab.Name;
  4675. ft: SymTab.TypeIndex;
  4676. nb, ea, eb, fa, fb: QVal;
  4677. BEGIN
  4678. cls := SymTab.ClassOf(t);
  4679. IF (cls = SymTab.ClClass) AND SymTab.HasVTable(t) THEN
  4680. (* install the class's vtable pointer *)
  4681. VtRef(t, eb);
  4682. IntStr(SymTab.VptrOffset(t), nb);
  4683. NewTemp(ea);
  4684. Op3L("add", ea, addr, nb);
  4685. Revive;
  4686. W(" storel "); W(eb); W(", "); WL(ea)
  4687. END;
  4688. IF (cls = SymTab.ClArray) AND SymTab.IsMultiArray(t) THEN
  4689. InitMultiHeap(addr, t)
  4690. ELSIF cls = SymTab.ClArray THEN
  4691. IntStr(VAL(INTEGER, SymTab.ArrayLen(t)), nb);
  4692. Revive;
  4693. W(" storel "); W(nb); W(", "); WL(addr);
  4694. IF SymTab.IsCharArray(t) THEN
  4695. (* NUL terminator slot at index = count *)
  4696. IntStr(VAL(INTEGER, 8 + SymTab.ArrayLen(t)), nb);
  4697. NewTemp(ea);
  4698. Op3L("add", ea, addr, nb);
  4699. Revive;
  4700. W(" storeb 0, "); WL(ea)
  4701. END;
  4702. IF SymTab.IsUCharArray(t) THEN
  4703. (* 0-codepoint terminator at index = count (4-byte element) *)
  4704. IntStr(VAL(INTEGER, 8 + SymTab.ArrayLen(t) * 4), nb);
  4705. NewTemp(ea);
  4706. Op3L("add", ea, addr, nb);
  4707. Revive;
  4708. W(" storew 0, "); WL(ea)
  4709. END;
  4710. ecls := SymTab.ClassOf(SymTab.ArrayElem(t));
  4711. IF ecls = SymTab.ClArray THEN
  4712. n := SymTab.ArrayLen(t);
  4713. i := 0;
  4714. WHILE i < n DO
  4715. IntStr(VAL(INTEGER, 8 + i * 8), nb);
  4716. NewTemp(ea);
  4717. Op3L("add", ea, addr, nb);
  4718. NewHeap(SymTab.ArrayElem(t), eb);
  4719. InitHeap(eb, SymTab.ArrayElem(t)); (* init the sub-array *)
  4720. Revive;
  4721. W(" storel "); W(eb); W(", "); WL(ea);
  4722. INC(i)
  4723. END
  4724. END
  4725. ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
  4726. n := SymTab.FieldCount(t);
  4727. i := 0;
  4728. WHILE i < n DO
  4729. SymTab.FieldName(t, i, fn);
  4730. ft := SymTab.FieldType(t, fn);
  4731. ecls := SymTab.ClassOf(ft);
  4732. IF ecls = SymTab.ClArray THEN
  4733. IntStr(SymTab.FieldOffset(t, fn), nb);
  4734. NewTemp(fa);
  4735. Op3L("add", fa, addr, nb);
  4736. IF SymTab.IsMultiArray(ft) THEN
  4737. InitMultiField(fa, ft)
  4738. ELSE
  4739. InitHeap(fa, ft)
  4740. END
  4741. ELSIF (ecls = SymTab.ClRecord) OR (ecls = SymTab.ClClass) THEN
  4742. IntStr(SymTab.FieldOffset(t, fn), nb);
  4743. NewTemp(fa);
  4744. Op3L("add", fa, addr, nb);
  4745. InitHeap(fa, ft)
  4746. END;
  4747. INC(i)
  4748. END
  4749. END
  4750. END InitHeap;
  4751. PROCEDURE InFunction (): BOOLEAN;
  4752. (* TRUE while a function body is open (module-level test). *)
  4753. BEGIN
  4754. RETURN inFunc
  4755. END InFunction;
  4756. PROCEDURE RecArrayNeedsInit (n: CARDINAL; t: INTEGER): BOOLEAN;
  4757. (* TRUE for an array of records/classes that (recursively) has array
  4758. fields and is too large to expand inline: its inline length words
  4759. must be initialised at run time (InitRecArray). *)
  4760. VAR elem: INTEGER;
  4761. BEGIN
  4762. IF SymTab.ClassOf(t) # SymTab.ClArray THEN RETURN FALSE END;
  4763. elem := SymTab.ArrayElem(t);
  4764. IF (SymTab.ClassOf(elem) # SymTab.ClRecord)
  4765. AND (SymTab.ClassOf(elem) # SymTab.ClClass) THEN RETURN FALSE END;
  4766. IF NOT HasArrayField(elem) THEN RETURN FALSE END;
  4767. RETURN NOT RecArrayExpanded(n, elem)
  4768. END RecArrayNeedsInit;
  4769. PROCEDURE DeclRecTemplate (varName: ARRAY OF CHAR; rec: INTEGER);
  4770. (* "data $<mod>_<varName>_tmpl = { <one record with counts set> }" plus
  4771. any nested sub-descriptors; InitRecArray copies it over each element
  4772. of the compact array-of-record blob. *)
  4773. VAR g: QVal; first: BOOLEAN;
  4774. BEGIN
  4775. IF NOT opened THEN RETURN END;
  4776. Cpy(g, curModName); App(g, "_"); App(g, varName); App(g, "_tmpl");
  4777. RecStatics(g, rec);
  4778. W("export data $"); W(g); W(" = { ");
  4779. first := TRUE;
  4780. RecItems(rec, g, first);
  4781. WL(" }")
  4782. END DeclRecTemplate;
  4783. PROCEDURE InitRecArray (varName: ARRAY OF CHAR; arrT: INTEGER);
  4784. (* value-initialise $<mod>_<varName>'s element length words: copy the
  4785. template record over each element (element i is at base + 8 +
  4786. i*stride). *)
  4787. VAR base, tmpl, slot, i, il, off, tb, p, c, one, two, nStr, stStr: QVal;
  4788. elem: INTEGER; lTop, lBody, lDone: QVal;
  4789. BEGIN
  4790. IF NOT opened THEN RETURN END;
  4791. elem := SymTab.ArrayElem(arrT);
  4792. Cpy(base, "$"); App(base, curModName); App(base, "_"); App(base, varName);
  4793. Cpy(tmpl, base); App(tmpl, "_tmpl");
  4794. IntStr(VAL(INTEGER, SymTab.ArrayLen(arrT)), nStr);
  4795. IntStr(VAL(INTEGER, SymTab.TypeSize(elem)), stStr);
  4796. Slot4(slot);
  4797. StoreW(slot, "0");
  4798. NewLabel(lTop); NewLabel(lBody); NewLabel(lDone);
  4799. EmitLabel(lTop);
  4800. LoadW(slot, i);
  4801. NewTemp(c); Op3("csltw", c, i, nStr, FALSE);
  4802. Jnz(c, lBody, lDone);
  4803. EmitLabel(lBody);
  4804. LoadW(slot, i);
  4805. WidenIndex(i, il);
  4806. NewTemp(off); Op3L("mul", off, il, stStr);
  4807. NewTemp(tb); Op3L("add", tb, base, "8");
  4808. NewTemp(p); Op3L("add", p, tb, off);
  4809. CopyRecord(p, tmpl, elem);
  4810. LoadW(slot, i);
  4811. NewTemp(one); CopyOp("1", one);
  4812. NewTemp(two); Op3("add", two, i, one, FALSE);
  4813. StoreW(slot, two);
  4814. Jmp(lTop);
  4815. EmitLabel(lDone)
  4816. END InitRecArray;
  4817. BEGIN
  4818. opened := FALSE;
  4819. inBody := FALSE;
  4820. dead := FALSE;
  4821. nTemp := 0; nLab := 0; loopTop := 0; nR := 0; nStr := 0;
  4822. withTop := 0;
  4823. noEmit := FALSE; inFunc := FALSE; useStack := FALSE;
  4824. nLoc := 0; nPar := 0; nArg := 0; nn := 0; callDepth := 0;
  4825. recvArmed := FALSE;
  4826. funcDepth := 0; scopeTop := 0; scopeBase[0] := 0;
  4827. outSel := 0
  4828. END QbeGen.