FoxAMDBackend.Mod 133 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472
  1. MODULE FoxAMDBackend; (** AUTHOR ""; PURPOSE ""; *)
  2. IMPORT
  3. Basic := FoxBasic, Scanner := FoxScanner, SyntaxTree := FoxSyntaxTree, Global := FoxGlobal, Backend := FoxBackend, Sections := FoxSections,
  4. IntermediateCode := FoxIntermediateCode, IntermediateBackend := FoxIntermediateBackend, BinaryCode := FoxBinaryCode,
  5. InstructionSet := FoxAMD64InstructionSet, Assembler := FoxAMD64Assembler, SemanticChecker := FoxSemanticChecker, Formats := FoxFormats,
  6. Diagnostics, Streams, Options, Strings, ObjectFileFormat := FoxBinaryObjectFile, ActiveCells := FoxActiveCells
  7. , Machine, D := Debugging, CodeGenerators := FoxCodeGenerators, ObjectFile;
  8. CONST
  9. (* constants for the register allocator *)
  10. none=-1;
  11. RAX=InstructionSet.regRAX; RCX=InstructionSet.regRCX; RDX=InstructionSet.regRDX; RBX=InstructionSet.regRBX;
  12. RSP=InstructionSet.regRSP; RBP=InstructionSet.regRBP; RSI=InstructionSet.regRSI; RDI=InstructionSet.regRDI;
  13. R8=InstructionSet.regR8; R9=InstructionSet.regR9; R10=InstructionSet.regR10; R11=InstructionSet.regR11;
  14. R12=InstructionSet.regR12; R13=InstructionSet.regR13; R14=InstructionSet.regR14; R15=InstructionSet.regR15;
  15. EAX=InstructionSet.regEAX; ECX=InstructionSet.regECX; EDX=InstructionSet.regEDX; EBX=InstructionSet.regEBX;
  16. ESP=InstructionSet.regESP; EBP=InstructionSet.regEBP; ESI=InstructionSet.regESI; EDI=InstructionSet.regEDI;
  17. R8D=InstructionSet.regR8D; R9D=InstructionSet.regR9D; R10D=InstructionSet.regR10D; R11D=InstructionSet.regR11D;
  18. R12D=InstructionSet.regR12D; R13D=InstructionSet.regR13D; R14D=InstructionSet.regR14D; R15D=InstructionSet.regR15D;
  19. AX=InstructionSet.regAX; CX=InstructionSet.regCX; DX=InstructionSet.regDX; BX=InstructionSet.regBX;
  20. SI=InstructionSet.regSI; DI=InstructionSet.regDI; BP=InstructionSet.regBP; SP=InstructionSet.regSP;
  21. R8W=InstructionSet.regR8W; R9W=InstructionSet.regR9W; R10W=InstructionSet.regR10W; R11W=InstructionSet.regR11W;
  22. R12W=InstructionSet.regR12W; R13W=InstructionSet.regR13W; R14W=InstructionSet.regR14W; R15W=InstructionSet.regR15W;
  23. AL=InstructionSet.regAL; CL=InstructionSet.regCL; DL=InstructionSet.regDL; BL=InstructionSet.regBL; SIL=InstructionSet.regSIL;
  24. DIL=InstructionSet.regDIL; BPL=InstructionSet.regBPL; SPL=InstructionSet.regSPL;
  25. R8B=InstructionSet.regR8B; R9B=InstructionSet.regR9B; R10B=InstructionSet.regR10B; R11B=InstructionSet.regR11B;
  26. R12B=InstructionSet.regR12B; R13B=InstructionSet.regR13B; R14B=InstructionSet.regR14B; R15B=InstructionSet.regR15B;
  27. AH=InstructionSet.regAH; CH=InstructionSet.regCH; DH=InstructionSet.regDH; BH=InstructionSet.regBH;
  28. ST0=InstructionSet.regST0;
  29. XMM0 = InstructionSet.regXMM0;
  30. XMM7 = InstructionSet.regXMM7;
  31. Low=0; High=1;
  32. FrameSpillStack=TRUE;
  33. VAR registerOperands: ARRAY InstructionSet.numberRegisters OF Assembler.Operand;
  34. usePool: BOOLEAN;
  35. opEAX, opECX, opEDX, opEBX, opESP, opEBP,
  36. opESI, opEDI, opAX, opCX, opDX, opBX, opSI, opDI, opAL, opCL, opDL, opBL, opAH, opCH, opDH, opBH,opST0
  37. , opRSP, opRBP: Assembler.Operand;
  38. unusable,split,blocked,free: CodeGenerators.Ticket;
  39. traceStackSize: LONGINT;
  40. TYPE
  41. Ticket=CodeGenerators.Ticket;
  42. PhysicalRegisters*=OBJECT (CodeGenerators.PhysicalRegisters)
  43. VAR
  44. toVirtual: ARRAY InstructionSet.numberRegisters OF Ticket; (* registers real register -> none / reserved / split / blocked / virtual register (>0) *)
  45. reserved: ARRAY InstructionSet.numberRegisters OF BOOLEAN;
  46. hint: LONGINT;
  47. useFPU: BOOLEAN;
  48. PROCEDURE &InitPhysicalRegisters(fpu,cooperative: BOOLEAN);
  49. VAR i: LONGINT;
  50. BEGIN
  51. FOR i := 0 TO LEN(toVirtual)-1 DO
  52. toVirtual[i] := NIL;
  53. reserved[i] := FALSE;
  54. END;
  55. (* reserve stack and base pointer registers *)
  56. toVirtual[BPL] := unusable;
  57. toVirtual[SPL] := unusable;
  58. toVirtual[BP] := unusable;
  59. toVirtual[SP] := unusable;
  60. toVirtual[EBP] := unusable;
  61. toVirtual[ESP] := unusable;
  62. toVirtual[RBP] := unusable;
  63. toVirtual[RSP] := unusable;
  64. hint := none;
  65. useFPU := fpu
  66. END InitPhysicalRegisters;
  67. PROCEDURE AllocationHint(index: LONGINT);
  68. BEGIN hint := index
  69. END AllocationHint;
  70. PROCEDURE NumberRegisters(): LONGINT;
  71. BEGIN
  72. RETURN LEN(toVirtual)
  73. END NumberRegisters;
  74. END PhysicalRegisters;
  75. PhysicalRegisters32=OBJECT (PhysicalRegisters) (* 32 bit implementation *)
  76. PROCEDURE & InitPhysicalRegisters32(fpu,cooperative: BOOLEAN);
  77. VAR i: LONGINT;
  78. BEGIN
  79. InitPhysicalRegisters(fpu,cooperative);
  80. (* disable registers that are only usable in 64 bit mode *)
  81. FOR i := 0 TO 31 DO
  82. toVirtual[i+RAX] := unusable;
  83. END;
  84. FOR i := 8 TO 15 DO
  85. toVirtual[i+AL] := unusable;
  86. toVirtual[i+AH] := unusable;
  87. toVirtual[i+EAX] := unusable;
  88. toVirtual[i+AX] := unusable;
  89. END;
  90. FOR i := 4 TO 7 DO
  91. toVirtual[i+AL] := unusable;
  92. toVirtual[i+AH] := unusable;
  93. END;
  94. FOR i := 0 TO LEN(reserved)-1 DO reserved[i] := FALSE END;
  95. END InitPhysicalRegisters32;
  96. PROCEDURE Allocate(index: LONGINT; virtualRegister: Ticket);
  97. BEGIN
  98. (*
  99. D.String("allocate register x : index="); D.Int(index,1); D.Ln;
  100. *)
  101. Assert(toVirtual[index] = free,"register already allocated");
  102. toVirtual[index] := virtualRegister;
  103. IF index DIV 32 = 2 THEN (* 32 bit *)
  104. Assert(toVirtual[index MOD 32 + AX] = free,"free register split");
  105. toVirtual[index MOD 32 + AX] := blocked;
  106. IF index MOD 32 < 4 THEN
  107. Assert(toVirtual[index MOD 32 + AL] = free,"register already allocated");
  108. Assert(toVirtual[index MOD 32 + AH] = free,"register already allocated");
  109. toVirtual[index MOD 32 + AL] := blocked;
  110. toVirtual[index MOD 32 + AH] := blocked;
  111. END;
  112. ELSIF index DIV 32 = 1 THEN (* 16 bit *)
  113. Assert(toVirtual[index MOD 8 + EAX] = free,"free register split");
  114. toVirtual[index MOD 32 + EAX] := split;
  115. IF index MOD 32 < 4 THEN
  116. Assert(toVirtual[index MOD 32 + AL] = free,"register already allocated");
  117. Assert(toVirtual[index MOD 32 + AH] = free,"register already allocated");
  118. toVirtual[index MOD 32 + AL] := blocked;
  119. toVirtual[index MOD 32 + AH] := blocked;
  120. END;
  121. ELSIF index DIV 32 = 0 THEN (* 8 bit *)
  122. Assert((toVirtual[index MOD 4 + EAX] = free) OR (toVirtual[index MOD 4 + EAX] = split),"free register blocked");
  123. Assert((toVirtual[index MOD 4 + AX] = free) OR (toVirtual[index MOD 4 + AX] = split),"free register blocked");
  124. toVirtual[index MOD 4 + EAX] := split;
  125. toVirtual[index MOD 4 + AX] := split;
  126. ELSIF (index >= XMM0) & (index <= XMM7) THEN (* vector register *)
  127. ELSE Assert( (index >=InstructionSet.regST0) & (index <= InstructionSet.regST7 ),"not a float register"); (* floats *)
  128. END;
  129. END Allocate;
  130. PROCEDURE SetReserved(index: LONGINT; res: BOOLEAN);
  131. BEGIN
  132. IF index DIV 32 <=2 THEN
  133. index := index MOD 16;
  134. reserved[index+AH] := res;
  135. reserved[index+AL] := res;
  136. reserved[index+AX] := res;
  137. reserved[index+EAX] := res;
  138. ELSE
  139. reserved[index] := res;
  140. END;
  141. END SetReserved;
  142. PROCEDURE Reserved(index: LONGINT): BOOLEAN;
  143. BEGIN
  144. RETURN (index>0) & reserved[index]
  145. END Reserved;
  146. PROCEDURE Free(index: LONGINT);
  147. VAR x: Ticket;
  148. BEGIN
  149. (*
  150. D.String("free register x : index="); D.Int(index,1); D.Ln;
  151. *)
  152. x := toVirtual[index];
  153. Assert((toVirtual[index] # NIL),"register not reserved");
  154. toVirtual[index] := free;
  155. IF index DIV 32 =2 THEN (* 32 bit *)
  156. Assert(toVirtual[index MOD 32 + AX] = blocked,"reserved register did not block");
  157. toVirtual[index MOD 32 + AX] := free;
  158. IF index MOD 32 < 4 THEN
  159. Assert(toVirtual[index MOD 32 + AL] = blocked,"reserved register did not block");
  160. Assert(toVirtual[index MOD 32 + AH] = blocked,"reserved register did not block");
  161. toVirtual[index MOD 32 + AL] := free;
  162. toVirtual[index MOD 32 + AH] := free;
  163. END;
  164. ELSIF index DIV 32 = 1 THEN (* 16 bit *)
  165. Assert(toVirtual[index MOD 32 + EAX] = split,"reserved register did not split");
  166. toVirtual[index MOD 32 + EAX] := free;
  167. IF index MOD 32 < 4 THEN
  168. Assert(toVirtual[index MOD 32 + AL] = blocked,"reserved register did not block");
  169. Assert(toVirtual[index MOD 32 + AH] = blocked,"reserved register did not block");
  170. toVirtual[index MOD 32 + AL] := free;
  171. toVirtual[index MOD 32 + AH] := free;
  172. END;
  173. ELSIF index DIV 32 = 0 THEN (* 8 bit *)
  174. IF (toVirtual[index MOD 4 + AL] = free) & (toVirtual[index MOD 4 + AH] = free) THEN
  175. Assert(toVirtual[index MOD 4 + EAX] = split,"reserved register did not split");
  176. Assert(toVirtual[index MOD 4 + AX] = split,"reserved register did not split");
  177. toVirtual[index MOD 4 + EAX] := free;
  178. toVirtual[index MOD 4 + AX] := free;
  179. END;
  180. ELSIF (index >= XMM0) & (index <= XMM7) THEN (* vector register *)
  181. ELSE Assert( (index >=InstructionSet.regST0) & (index <= InstructionSet.regST7 ),"not a float register"); (* floats *)
  182. END;
  183. END Free;
  184. PROCEDURE NextFree(CONST type: IntermediateCode.Type):LONGINT;
  185. VAR i,sizeInBits,length, form: LONGINT;
  186. PROCEDURE GetGPHint(offset: LONGINT): LONGINT;
  187. VAR res: LONGINT;
  188. BEGIN
  189. IF (hint # none) & (hint >= AL) & (hint <= EDI) & (toVirtual[hint MOD 32 + offset]=free) & ~Reserved(hint) THEN res := hint MOD 32 + offset ELSE res := none END;
  190. hint := none;
  191. RETURN res
  192. END GetGPHint;
  193. PROCEDURE GetHint(from,to: LONGINT): LONGINT;
  194. VAR res: LONGINT;
  195. BEGIN
  196. IF (hint # none) & (hint >= from) & (hint <= to) & (toVirtual[hint]=free) & ~Reserved(hint) THEN res := hint ELSE res := none END;
  197. hint := none;
  198. RETURN res
  199. END GetHint;
  200. PROCEDURE Get(from,to: LONGINT): LONGINT;
  201. VAR i: LONGINT;
  202. BEGIN
  203. i := from;
  204. IF from <= to THEN
  205. WHILE (i <= to) & ((toVirtual[i]#free) OR Reserved(i)) DO INC(i) END;
  206. IF i > to THEN i := none END;
  207. ELSE
  208. WHILE (i >=to) & ((toVirtual[i]#free) OR Reserved(i)) DO DEC(i) END;
  209. IF i < to THEN i := none END;
  210. END;
  211. RETURN i
  212. END Get;
  213. BEGIN
  214. length := type.length;
  215. sizeInBits := type.sizeInBits;
  216. form := type.form;
  217. IF (type.length > 1) THEN
  218. IF (* (type.form = IntermediateCode.Float) &*) (type.sizeInBits=32) & (type.length =4) THEN
  219. i := Get(XMM7, XMM0);
  220. ELSE
  221. HALT(100)
  222. END
  223. ELSIF type.form IN IntermediateCode.Integer THEN
  224. sizeInBits := type.sizeInBits;
  225. IF type.sizeInBits = IntermediateCode.Bits8 THEN
  226. i := GetGPHint(AL);
  227. IF i = none THEN i := Get(BL, AL) END;
  228. IF i = none THEN i := Get(BH, AH) END;
  229. ELSIF type.sizeInBits = IntermediateCode.Bits16 THEN
  230. i := GetGPHint(AX);
  231. IF i = none THEN i := Get(DI, SI) END;
  232. IF i = none THEN i := Get(BX, AX) END;
  233. ELSIF type.sizeInBits = IntermediateCode.Bits32 THEN
  234. i := GetGPHint(EAX);
  235. IF i = none THEN i := Get(EDI,ESI) END;
  236. IF i = none THEN i := Get(EBX,EAX) END;
  237. ELSE HALT(100)
  238. END;
  239. ELSE
  240. ASSERT(type.form = IntermediateCode.Float);
  241. IF useFPU THEN
  242. i := Get(InstructionSet.regST0, InstructionSet.regST6);
  243. (* ST7 unusable as it is overwritten during arithmetic instructions *)
  244. ELSE
  245. i := GetHint(XMM0, XMM7);
  246. IF i = none THEN i := Get(XMM7, XMM0) END
  247. END;
  248. END;
  249. hint := none; (* reset *)
  250. RETURN i
  251. END NextFree;
  252. PROCEDURE Mapped(physical: LONGINT): Ticket;
  253. VAR virtual: Ticket;
  254. BEGIN
  255. virtual := toVirtual[physical];
  256. IF virtual = blocked THEN virtual := Mapped(physical+32)
  257. ELSIF virtual = split THEN
  258. IF physical < 32 THEN virtual := Mapped(physical+16 MOD 32)
  259. ELSE virtual := Mapped(physical-32)
  260. END;
  261. END;
  262. ASSERT((virtual = free) OR (virtual = unusable) OR (toVirtual[virtual.register] = virtual));
  263. RETURN virtual
  264. END Mapped;
  265. PROCEDURE Dump(w: Streams.Writer);
  266. VAR i: LONGINT; virtual: Ticket;
  267. BEGIN
  268. w.String("; ---- registers ----"); w.Ln;
  269. FOR i := 0 TO LEN(toVirtual)-1 DO
  270. virtual := toVirtual[i];
  271. IF virtual # unusable THEN
  272. w.String("reg "); w.Int(i,1); w.String(": ");
  273. IF virtual = free THEN w.String("free")
  274. ELSIF virtual = blocked THEN w.String("blocked")
  275. ELSIF virtual = split THEN w.String("split")
  276. ELSE w.String(" r"); w.Int(virtual.register,1);
  277. END;
  278. IF reserved[i] THEN w.String("reserved") END;
  279. w.Ln;
  280. END;
  281. END;
  282. END Dump;
  283. END PhysicalRegisters32;
  284. PhysicalRegisters64=OBJECT (PhysicalRegisters) (* 64 bit implementation *)
  285. PROCEDURE & InitPhysicalRegisters64(fpu,cooperative: BOOLEAN);
  286. BEGIN
  287. InitPhysicalRegisters(fpu,cooperative);
  288. END InitPhysicalRegisters64;
  289. PROCEDURE SetReserved(index: LONGINT; res: BOOLEAN);
  290. BEGIN
  291. (*
  292. IF res THEN D.String("reserve ") ELSE D.String("unreserve ") END;
  293. D.String("register: index="); D.Int(index,1); D.Ln;
  294. *)
  295. IF index DIV 32 <=2 THEN
  296. index := index MOD 16;
  297. reserved[index+AH] := res;
  298. reserved[index+AL] := res;
  299. reserved[index+AX] := res;
  300. reserved[index+EAX] := res;
  301. reserved[index+RAX] := res;
  302. ELSE
  303. reserved[index] := res
  304. END;
  305. END SetReserved;
  306. PROCEDURE Reserved(index: LONGINT): BOOLEAN;
  307. BEGIN
  308. RETURN reserved[index]
  309. END Reserved;
  310. PROCEDURE Allocate(index: LONGINT; virtualRegister: Ticket);
  311. BEGIN
  312. (*
  313. D.String("allocate register x : index="); D.Int(index,1); D.Ln;
  314. *)
  315. Assert(toVirtual[index] = free,"register already allocated");
  316. toVirtual[index] := virtualRegister;
  317. IF index DIV 32 = 3 THEN (* 64 bit *)
  318. Assert(toVirtual[index MOD 32 + EAX] = free,"free register split");
  319. toVirtual[index MOD 32 + EAX] := blocked;
  320. toVirtual[index MOD 32 + AX] := blocked;
  321. toVirtual[index MOD 32 + AL] := blocked;
  322. ELSIF index DIV 32 = 2 THEN (* 32 bit *)
  323. Assert(toVirtual[index MOD 32 + AX] = free,"free register split");
  324. toVirtual[index MOD 32 + RAX] := split;
  325. toVirtual[index MOD 32 + AX] := blocked;
  326. toVirtual[index MOD 32 + AL] := blocked;
  327. ELSIF index DIV 32 = 1 THEN (* 16 bit *)
  328. toVirtual[index MOD 32 + RAX] := split;
  329. toVirtual[index MOD 32 + EAX] := split;
  330. toVirtual[index MOD 32 + AL] := blocked;
  331. ELSIF index DIV 32 = 0 THEN (* 8 bit *)
  332. toVirtual[index MOD 32 + RAX] := split;
  333. toVirtual[index MOD 32 + EAX] := split;
  334. toVirtual[index MOD 32 + AX] := split;
  335. ELSE Assert( (index >=InstructionSet.regST0) & (index <= InstructionSet.regST7 ),"not a float register"); (* floats *)
  336. END;
  337. END Allocate;
  338. PROCEDURE Free(index: LONGINT);
  339. BEGIN
  340. (*
  341. D.String("release register x : index="); D.Int(index,1); D.Ln;
  342. *)
  343. Assert(toVirtual[index]#NIL,"register not reserved");
  344. toVirtual[index] := free;
  345. IF index DIV 32 =3 THEN (* 64 bit *)
  346. Assert(toVirtual[index MOD 32 + EAX] = blocked,"reserved register did not block");
  347. toVirtual[index MOD 32 + EAX] := free;
  348. toVirtual[index MOD 32 + AX] := free;
  349. toVirtual[index MOD 32 + AL] := free;
  350. ELSIF index DIV 32 =2 THEN (* 32 bit *)
  351. Assert(toVirtual[index MOD 32 + RAX] = split,"reserved register did not split");
  352. Assert(toVirtual[index MOD 32 + AX] = blocked,"reserved register did not block");
  353. Assert(toVirtual[index MOD 32 + AL] = blocked,"reserved register did not block");
  354. toVirtual[index MOD 32 + RAX] := free;
  355. toVirtual[index MOD 32 + AX] := free;
  356. toVirtual[index MOD 32 + AL] := free;
  357. ELSIF index DIV 32 = 1 THEN (* 16 bit *)
  358. Assert(toVirtual[index MOD 32 + RAX] = split,"reserved register did not split");
  359. Assert(toVirtual[index MOD 32 + EAX] = split,"reserved register did not split");
  360. Assert(toVirtual[index MOD 32 + AL] = blocked,"reserved register did not split");
  361. toVirtual[index MOD 32 + RAX] := free;
  362. toVirtual[index MOD 32 + EAX] := free;
  363. toVirtual[index MOD 32 + AL] := free;
  364. ELSIF index DIV 32 = 0 THEN (* 8 bit *)
  365. Assert(toVirtual[index MOD 32 + RAX] = split,"reserved register did not split");
  366. Assert(toVirtual[index MOD 32 + EAX] = split,"reserved register did not split");
  367. Assert(toVirtual[index MOD 32 + AX] = split,"reserved register did not split");
  368. toVirtual[index MOD 32 + RAX] := free;
  369. toVirtual[index MOD 32 + EAX] := free;
  370. toVirtual[index MOD 32 + AX] := free;
  371. ELSE Assert( (index >=InstructionSet.regST0) & (index <= InstructionSet.regST7 ),"not a float register"); (* floats *)
  372. END;
  373. END Free;
  374. PROCEDURE NextFree(CONST type: IntermediateCode.Type): LONGINT;
  375. VAR i: LONGINT;
  376. PROCEDURE GetHint(offset: LONGINT): LONGINT;
  377. VAR res: LONGINT;
  378. BEGIN
  379. IF (hint # none) & (toVirtual[hint MOD 32 + offset]=free) & ~Reserved(hint) THEN res := hint ELSE res := none END;
  380. hint := none;
  381. RETURN res
  382. END GetHint;
  383. PROCEDURE Get(from,to: LONGINT): LONGINT;
  384. VAR i: LONGINT;
  385. BEGIN
  386. i := from;
  387. IF from <= to THEN
  388. WHILE (i <= to) & ((toVirtual[i]#free) OR Reserved(i)) DO INC(i) END;
  389. IF i > to THEN i := none END;
  390. ELSE
  391. WHILE (i >=to) & ((toVirtual[i]#free) OR Reserved(i)) DO DEC(i) END;
  392. IF i < to THEN i := none END;
  393. END;
  394. RETURN i
  395. END Get;
  396. BEGIN
  397. IF type.form IN IntermediateCode.Integer THEN
  398. IF type.sizeInBits = IntermediateCode.Bits8 THEN
  399. i := GetHint(AL);
  400. IF i = none THEN
  401. i := Get(AL,R15B)
  402. END;
  403. ELSIF type.sizeInBits = IntermediateCode.Bits16 THEN
  404. i := GetHint(AX);
  405. IF i = none THEN
  406. i := Get(AX,R15W);
  407. END;
  408. ELSIF type.sizeInBits = IntermediateCode.Bits32 THEN
  409. i := GetHint(EAX);
  410. IF i = none THEN
  411. i := Get(EAX,R15D);
  412. END;
  413. ELSIF type.sizeInBits = IntermediateCode.Bits64 THEN
  414. i := GetHint(RAX);
  415. IF i = none THEN
  416. i := Get(RAX, R15)
  417. END;
  418. ELSE HALT(100)
  419. END;
  420. ELSE
  421. ASSERT(type.form = IntermediateCode.Float);
  422. IF useFPU THEN
  423. i := Get(InstructionSet.regST0, InstructionSet.regST6);
  424. (* ST7 unusable as it is overwritten during arithmetic instructions *)
  425. ELSE
  426. i := Get(XMM7, XMM0)
  427. END;
  428. END;
  429. RETURN i;
  430. END NextFree;
  431. PROCEDURE Mapped(physical: LONGINT): Ticket;
  432. VAR virtual: Ticket;
  433. BEGIN
  434. virtual := toVirtual[physical];
  435. IF virtual = blocked THEN RETURN Mapped(physical+32) END;
  436. IF virtual = split THEN RETURN Mapped(physical-32) END;
  437. RETURN virtual
  438. END Mapped;
  439. END PhysicalRegisters64;
  440. CodeGeneratorAMD64 = OBJECT (CodeGenerators.GeneratorWithTickets)
  441. VAR
  442. (* static generator state variables, considered constant during generation *)
  443. runtimeModuleName: SyntaxTree.IdentifierString;
  444. cpuBits: LONGINT;
  445. opBP, opSP, opRA, opRB, opRC, opRD, opRS, opR8, opR9: Assembler.Operand; (* base pointer, stack pointer, register A, depends on cpuBits*)
  446. BP, SP, RA, RD, RS, RC: LONGINT; (* base pointer and stack pointer register index, depends on cpuBits *)
  447. emitter: Assembler.Emitter; (* assembler generating and containing the machine code *)
  448. backend: BackendAMD64;
  449. (* register spill state *)
  450. stackSize: LONGINT;
  451. spillStackStart: LONGINT;
  452. (* floating point stack state *)
  453. fpStackPointer: LONGINT; (* floating point stack pointer, increases with allocation, decreases with releasing, used to determine current relative position on stack (as is necessary for intel FP instructions) *)
  454. (*
  455. FP register usage scheme:
  456. sp=1> FP0 - temp
  457. sp=0> FP0 - reg0 FP1 - reg0 sp=0> FP0 - reg0
  458. FP1 - reg1 FP2 - reg1 FP1 - reg1
  459. FP2 - reg2 FP3 - reg2 FP2 - reg2
  460. FP3 - reg3 = load op1 => FP4 - reg3 = op => FP3 - reg3
  461. FP4 - reg4 FP5 - reg4 FP4 - reg4
  462. FP5 - reg5 FP6 - reg5 FP5 - reg5
  463. FP6 - reg6 FP7 - reg6 FP6 - reg6
  464. FP7 - reg7 (reg7 lost) FP7 - reg7
  465. *)
  466. ap: Ticket;
  467. (* -------------------------- constructor -------------------------------*)
  468. PROCEDURE &InitGeneratorAMD64(CONST runtime: SyntaxTree.IdentifierString; diagnostics: Diagnostics.Diagnostics; backend: BackendAMD64);
  469. VAR physicalRegisters: PhysicalRegisters; physicalRegisters32: PhysicalRegisters32; physicalRegisters64: PhysicalRegisters64;
  470. BEGIN
  471. SELF.backend := backend;
  472. runtimeModuleName := runtime;
  473. SELF.cpuBits := backend.bits;
  474. NEW(emitter,diagnostics);
  475. IF cpuBits=32 THEN
  476. NEW(physicalRegisters32, backend.forceFPU, backend.cooperative); physicalRegisters := physicalRegisters32; error := ~emitter.SetBits(32);
  477. opBP := opEBP; opSP := opESP; opRA := opEAX; opRB := opEBX; opRD := opEDI; opRS := opESI; opRC := opECX;
  478. SP := ESP; BP := EBP; RA := EAX;
  479. RD := EDI; RS := ESI; RC := ECX;
  480. ASSERT(~error);
  481. ELSIF cpuBits=64 THEN
  482. NEW(physicalRegisters64, backend.forceFPU, backend.cooperative); physicalRegisters := physicalRegisters64; error := ~emitter.SetBits(64);
  483. opBP := opRBP; opSP := opRSP; opRA := registerOperands[RAX]; opRB := registerOperands[RBX]; opRD := registerOperands[RDI];
  484. opRS := registerOperands[RSI]; opRC := registerOperands[RCX];
  485. opR8 := registerOperands[R8]; opR9 := registerOperands[R9];
  486. SP := RSP; BP := RBP; RA := RAX;
  487. RD := RDI; RS := RSI; RC := RCX;
  488. ASSERT(~error);
  489. ELSE Halt("no register allocator for bits other than 32 / 64 ");
  490. END;
  491. fpStackPointer := 0;
  492. InitTicketGenerator(diagnostics,backend.optimize,2,physicalRegisters);
  493. END InitGeneratorAMD64;
  494. (*------------------- overwritten methods ----------------------*)
  495. PROCEDURE Section(in: IntermediateCode.Section; out: BinaryCode.Section);
  496. VAR oldSpillStackSize: LONGINT;
  497. PROCEDURE CheckEmptySpillStack;
  498. BEGIN
  499. IF spillStack.Size()#0 THEN Error(inPC,"implementation error, spill stack not cleared") END;
  500. END CheckEmptySpillStack;
  501. BEGIN
  502. spillStack.Init;
  503. IF backend.cooperative THEN
  504. ap := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.UnsignedIntegerType(cpuBits),RC,in.pc);
  505. ap.spillable := FALSE;
  506. END;
  507. emitter.SetCode(out);
  508. Section^(in,out);
  509. IF FrameSpillStack & (spillStack.MaxSize() >0) THEN
  510. oldSpillStackSize := spillStack.MaxSize();
  511. out.Reset;
  512. CheckEmptySpillStack;
  513. Section^(in,out);
  514. ASSERT(spillStack.MaxSize() = oldSpillStackSize);
  515. END;
  516. ASSERT(fpStackPointer = 0);
  517. CheckEmptySpillStack;
  518. IF backend.cooperative THEN
  519. UnmapTicket(ap);
  520. END;
  521. error := error OR emitter.error;
  522. END Section;
  523. PROCEDURE Supported(CONST instruction: IntermediateCode.Instruction; VAR moduleName, procedureName: ARRAY OF CHAR): BOOLEAN;
  524. BEGIN
  525. COPY(runtimeModuleName, moduleName);
  526. IF (cpuBits=32) & (instruction.op2.type.sizeInBits = IntermediateCode.Bits64) & (instruction.op2.type.form IN IntermediateCode.Integer) THEN
  527. CASE instruction.opcode OF
  528. IntermediateCode.div:
  529. procedureName := "DivH"; RETURN FALSE
  530. | IntermediateCode.mul:
  531. procedureName := "MulH"; RETURN FALSE
  532. | IntermediateCode.mod :
  533. procedureName := "ModH"; RETURN FALSE
  534. | IntermediateCode.abs :
  535. procedureName := "AbsH"; RETURN FALSE;
  536. | IntermediateCode.shl :
  537. IF instruction.op1.type.form = IntermediateCode.SignedInteger THEN
  538. procedureName := "AslH"; RETURN FALSE;
  539. ELSE
  540. procedureName := "LslH"; RETURN FALSE;
  541. END;
  542. | IntermediateCode.shr :
  543. IF instruction.op1.type.form = IntermediateCode.SignedInteger THEN
  544. procedureName := "AsrH"; RETURN FALSE;
  545. ELSE
  546. procedureName := "LsrH"; RETURN FALSE;
  547. END;
  548. | IntermediateCode.ror :
  549. procedureName := "RorH"; RETURN FALSE;
  550. | IntermediateCode.rol :
  551. procedureName := "RolH"; RETURN FALSE;
  552. | IntermediateCode.cas :
  553. procedureName := "CasH"; RETURN FALSE;
  554. ELSE RETURN TRUE
  555. END;
  556. ELSIF ~backend.forceFPU & (instruction.opcode = IntermediateCode.conv) & (instruction.op1.type.form IN IntermediateCode.Integer) & (instruction.op2.type.form = IntermediateCode.Float) & IsComplex(instruction.op1) THEN
  557. IF instruction.op2.type.sizeInBits=32 THEN
  558. procedureName := "EntierRH"
  559. ELSE
  560. procedureName := "EntierXH"
  561. END;
  562. RETURN FALSE
  563. END;
  564. RETURN TRUE
  565. END Supported;
  566. (* input: type (such as that of an intermediate operand), output: low and high type (such as in low and high type of an operand) *)
  567. PROCEDURE GetPartType(CONST type: IntermediateCode.Type; part: LONGINT; VAR typePart: IntermediateCode.Type);
  568. BEGIN
  569. ASSERT(type.sizeInBits >0);
  570. IF (type.sizeInBits > cpuBits) & (type.form IN IntermediateCode.Integer) THEN
  571. IntermediateCode.InitType(typePart,type.form,32);
  572. ELSE ASSERT((type.form IN IntermediateCode.Integer) OR (type.form = IntermediateCode.Float));
  573. IF part=Low THEN typePart := type ELSE typePart := IntermediateCode.undef END;
  574. END;
  575. END GetPartType;
  576. (* simple move without conversion *)
  577. PROCEDURE Move(VAR dest, src: Assembler.Operand; CONST type: IntermediateCode.Type);
  578. BEGIN
  579. IF type.length > 1 THEN
  580. IF type.length = 4 THEN
  581. (*ASSERT(type.form = IntermediateCode.Float);*)
  582. ASSERT(type.sizeInBits = 32);
  583. SpecialMove(InstructionSet.opMOVUPS, InstructionSet.opMOVUPS, TRUE, dest, src, type);
  584. ELSE
  585. (*
  586. ASSERT(type.form = IntermediateCode.Float);
  587. *)
  588. ASSERT(type.sizeInBits = 64);
  589. SpecialMove(InstructionSet.opMOVUPD, InstructionSet.opMOVUPS, TRUE, dest, src, type);
  590. END;
  591. ELSIF type.form = IntermediateCode.Float THEN
  592. IF type.sizeInBits = 32 THEN
  593. SpecialMove(InstructionSet.opMOVSS, InstructionSet.opMOVSS, TRUE, dest, src, type);
  594. ELSE
  595. SpecialMove(InstructionSet.opMOVSD, InstructionSet.opMOVSD, TRUE, dest, src, type);
  596. END;
  597. ELSE
  598. SpecialMove(InstructionSet.opMOV, InstructionSet.opMOV, TRUE, dest, src, type);
  599. END;
  600. END Move;
  601. PROCEDURE ToSpillStack(ticket: Ticket);
  602. VAR op: Assembler.Operand;
  603. BEGIN
  604. IF (ticket.type.form = IntermediateCode.Float) & backend.forceFPU THEN
  605. emitter.Emit1(InstructionSet.opFLD,registerOperands[ticket.register]);
  606. INC(fpStackPointer);
  607. GetSpillOperand(ticket,op);
  608. emitter.Emit1(InstructionSet.opFSTP,op);
  609. DEC(fpStackPointer);
  610. ELSE
  611. GetSpillOperand(ticket,op);
  612. Move(op, registerOperands[ticket.register], ticket.type)
  613. END;
  614. END ToSpillStack;
  615. PROCEDURE AllocateSpillStack(size: LONGINT);
  616. BEGIN
  617. IF ~FrameSpillStack THEN
  618. AllocateStack(cpuBits DIV 8*size)
  619. END;
  620. END AllocateSpillStack;
  621. PROCEDURE ToRegister(ticket: Ticket);
  622. VAR op: Assembler.Operand;
  623. BEGIN
  624. GetSpillOperand(ticket,op);
  625. emitter.Emit2(InstructionSet.opMOV,registerOperands[ticket.register],op);
  626. END ToRegister;
  627. PROCEDURE ExchangeTickets(ticket1,ticket2: Ticket);
  628. VAR op1,op2: Assembler.Operand;
  629. BEGIN
  630. TicketToOperand(ticket1, op1);
  631. TicketToOperand(ticket2, op2);
  632. emitter.Emit2(InstructionSet.opXCHG, op1,op2);
  633. END ExchangeTickets;
  634. (*------------------- particular register mappings / operands ----------------------*)
  635. (* returns if a virtual register is mapped to the register set described by virtualRegisterMapping*)
  636. PROCEDURE MappedTo(CONST virtualRegister: LONGINT; part:LONGINT; physicalRegister: LONGINT): BOOLEAN;
  637. VAR ticket: Ticket;
  638. BEGIN
  639. IF (virtualRegister > 0) THEN
  640. ticket := virtualRegisters.Mapped(virtualRegister,part);
  641. RETURN (ticket # NIL) & ~(ticket.spilled) & (ticket.register = physicalRegister)
  642. ELSIF (virtualRegister = IntermediateCode.FP) THEN
  643. RETURN physicalRegister= BP
  644. ELSIF (virtualRegister = IntermediateCode.SP) THEN
  645. RETURN physicalRegister = SP
  646. ELSIF (virtualRegister = IntermediateCode.AP) THEN
  647. ASSERT(backend.cooperative);
  648. RETURN ~(ap.spilled) & (ap.register = physicalRegister)
  649. ELSE
  650. RETURN FALSE
  651. END;
  652. END MappedTo;
  653. PROCEDURE ResultRegister(CONST type: IntermediateCode.Type; part: LONGINT): LONGINT;
  654. BEGIN
  655. IF type.form IN IntermediateCode.Integer THEN
  656. CASE type.sizeInBits OF
  657. | 64:
  658. IF cpuBits = 32 THEN
  659. IF part = Low THEN RETURN EAX
  660. ELSE RETURN EDX
  661. END;
  662. ELSE
  663. ASSERT(part = Low);
  664. RETURN RAX
  665. END;
  666. | 32: ASSERT(part=Low); RETURN EAX
  667. | 16: ASSERT(part=Low); RETURN AX
  668. | 8: ASSERT(part=Low); RETURN AL
  669. END;
  670. ELSIF ~backend.forceFPU THEN
  671. RETURN XMM0
  672. ELSE ASSERT(type.form = IntermediateCode.Float);ASSERT(part=Low);
  673. RETURN ST0
  674. END;
  675. END ResultRegister;
  676. (*------------------- operand reflection ----------------------*)
  677. PROCEDURE IsMemoryOperand(vop: IntermediateCode.Operand; part: LONGINT): BOOLEAN;
  678. VAR ticket: Ticket;
  679. BEGIN
  680. IF vop.mode = IntermediateCode.ModeMemory THEN RETURN TRUE
  681. ELSIF vop.mode = IntermediateCode.ModeRegister THEN
  682. ticket := virtualRegisters.Mapped(vop.register,part);
  683. RETURN (ticket # NIL) & (ticket.spilled);
  684. ELSE RETURN FALSE
  685. END;
  686. END IsMemoryOperand;
  687. PROCEDURE IsRegister(CONST vop: IntermediateCode.Operand): BOOLEAN;
  688. BEGIN
  689. RETURN (vop.mode = IntermediateCode.ModeRegister) & (vop.offset = 0)
  690. END IsRegister;
  691. (* infer intermediate code type from physical operand as far as possible *)
  692. PROCEDURE PhysicalOperandType(CONST op:Assembler.Operand): IntermediateCode.Type;
  693. VAR type:IntermediateCode.Type;
  694. BEGIN
  695. IF op.type = Assembler.sti THEN
  696. IntermediateCode.InitType(type, IntermediateCode.Float, op.sizeInBytes*8)
  697. ELSE
  698. IntermediateCode.InitType(type, IntermediateCode.SignedInteger, op.sizeInBytes*8)
  699. END;
  700. RETURN type
  701. END PhysicalOperandType;
  702. (*------------------- operand generation ----------------------*)
  703. PROCEDURE GetSpillOperand(ticket: Ticket; VAR op: Assembler.Operand);
  704. BEGIN
  705. IF FrameSpillStack THEN
  706. op := Assembler.NewMem(SHORTINT(ticket.type.sizeInBits*ticket.type.length DIV 8), BP , -(spillStackStart + cpuBits DIV 8 + ticket.offset*cpuBits DIV 8));
  707. ELSE
  708. op := Assembler.NewMem(SHORTINT(ticket.type.sizeInBits*ticket.type.length DIV 8),SP , (spillStack.Size()-ticket.offset)*cpuBits DIV 8);
  709. END;
  710. END GetSpillOperand;
  711. PROCEDURE TicketToOperand(ticket: Ticket; VAR op: Assembler.Operand);
  712. BEGIN
  713. IF (ticket = NIL) THEN
  714. Assembler.InitOperand(op)
  715. ELSIF ticket.spilled THEN
  716. GetSpillOperand(ticket,op)
  717. ELSE
  718. IF ticket.register = none THEN physicalRegisters.Dump(D.Log); tickets.Dump(D.Log); virtualRegisters.Dump(D.Log); D.Update; END;
  719. ASSERT(ticket.register # none);
  720. IF (ticket.type.form = IntermediateCode.Float) & backend.forceFPU THEN
  721. op := registerOperands[ticket.register+fpStackPointer]
  722. ELSE
  723. op := registerOperands[ticket.register];
  724. END;
  725. END;
  726. END TicketToOperand;
  727. PROCEDURE GetTemporaryRegister(type: IntermediateCode.Type; VAR op: Assembler.Operand);
  728. BEGIN
  729. TicketToOperand(TemporaryTicket(IntermediateCode.GeneralPurposeRegister,type),op)
  730. END GetTemporaryRegister;
  731. PROCEDURE GetImmediateMem(CONST vop: IntermediateCode.Operand; part: LONGINT; VAR imm: Assembler.Operand);
  732. VAR data: IntermediateCode.Section;pc: LONGINT;
  733. BEGIN
  734. data := GetDataSection();
  735. pc := IntermediateBackend.EnterImmediate(data,vop);
  736. Assembler.InitMem(imm, SHORT(vop.type.sizeInBits DIV 8) , Assembler.none,0);
  737. Assembler.SetSymbol(imm,data.name,0,pc,0);
  738. END GetImmediateMem;
  739. PROCEDURE GetImmediate(CONST virtual: IntermediateCode.Operand; part: LONGINT; VAR physical: Assembler.Operand; forbidden16Bit: BOOLEAN);
  740. VAR type: IntermediateCode.Type; temp: Assembler.Operand; size: SHORTINT; value: HUGEINT;
  741. PROCEDURE IsImm8(value: HUGEINT): BOOLEAN;
  742. BEGIN
  743. RETURN (value >= -80H) & (value < 80H)
  744. END IsImm8;
  745. PROCEDURE IsImm16(value: HUGEINT): BOOLEAN;
  746. BEGIN
  747. RETURN (value >= -8000H) & (value < 10000H)
  748. END IsImm16;
  749. PROCEDURE IsImm32(value: HUGEINT): BOOLEAN;
  750. BEGIN
  751. value := value DIV 10000H DIV 10000H;
  752. RETURN (value = 0) OR (value=-1);
  753. END IsImm32;
  754. BEGIN
  755. ASSERT(virtual.mode = IntermediateCode.ModeImmediate);
  756. GetPartType(virtual.type,part,type);
  757. IF virtual.type.form IN IntermediateCode.Integer THEN
  758. IF IsComplex(virtual) THEN
  759. IF part = High THEN value := SHORT(virtual.intValue DIV 10000H DIV 10000H)
  760. ELSE value := virtual.intValue
  761. END;
  762. ELSE value := virtual.intValue
  763. END;
  764. IF virtual.symbol.name # "" THEN size := SHORT(type.sizeInBits DIV 8);
  765. ELSIF forbidden16Bit & IsImm16(value) & ~(IsImm8(value)) THEN size := Assembler.bits32;
  766. ELSE size := 0
  767. END;
  768. Assembler.InitImm(physical,size ,value);
  769. IF virtual.symbol.name # "" THEN Assembler.SetSymbol(physical,virtual.symbol.name,virtual.symbol.fingerprint,virtual.symbolOffset,virtual.offset+part*Assembler.bits32) END;
  770. IF (cpuBits=64) & ((physical.sizeInBytes=8) OR ~IsImm32(value)) THEN
  771. ASSERT(cpuBits=64);
  772. GetTemporaryRegister(IntermediateCode.int64,temp);
  773. emitter.Emit2(InstructionSet.opMOV,temp,physical);
  774. physical := temp;
  775. END;
  776. ELSE
  777. GetImmediateMem(virtual,part,physical);
  778. END;
  779. END GetImmediate;
  780. PROCEDURE GetMemory(CONST virtual: IntermediateCode.Operand; part: LONGINT; VAR physical: Assembler.Operand);
  781. VAR type: IntermediateCode.Type; virtualRegister, physicalRegister,offset: LONGINT; ticket,orig: Ticket; dest, source: Assembler.Operand;
  782. BEGIN
  783. ASSERT(virtual.mode = IntermediateCode.ModeMemory);
  784. GetPartType(virtual.type,part,type);
  785. IF virtual.register # IntermediateCode.None THEN
  786. virtualRegister := virtual.register;
  787. IF virtualRegister = IntermediateCode.FP THEN physicalRegister := BP;
  788. ELSIF virtualRegister = IntermediateCode.SP THEN physicalRegister := SP;
  789. ELSE
  790. IF virtualRegister = IntermediateCode.AP THEN
  791. ticket := ap;
  792. ELSE
  793. ticket := virtualRegisters.Mapped(virtualRegister,Low);
  794. END;
  795. IF ticket.spilled THEN
  796. IF physicalRegisters.Reserved(ticket.register) THEN
  797. orig := ticket;
  798. ticket := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,IntermediateBackend.GetType(module.system,module.system.addressType));
  799. TicketToOperand(orig,source);
  800. TicketToOperand(ticket,dest);
  801. Move(dest,source,PhysicalOperandType(dest));
  802. physicalRegister := ticket.register;
  803. ELSE
  804. UnSpill(ticket);
  805. physicalRegister := ticket.register;
  806. END;
  807. ELSE
  808. physicalRegister := ticket.register;
  809. END;
  810. END;
  811. offset := virtual.offset;
  812. ASSERT(virtual.intValue = 0);
  813. ELSIF virtual.symbol.name # "" THEN
  814. physicalRegister := Assembler.none;
  815. offset := virtual.offset;
  816. ASSERT(virtual.intValue = 0);
  817. ELSE
  818. physicalRegister := Assembler.none;
  819. offset := SHORT(virtual.intValue);
  820. ASSERT(virtual.offset = 0);
  821. END;
  822. Assembler.InitMem(physical, SHORTINT(type.length * type.sizeInBits DIV 8) , physicalRegister, offset+4*part);
  823. IF virtual.symbol.name # "" THEN
  824. Assembler.SetSymbol(physical,virtual.symbol.name,virtual.symbol.fingerprint,virtual.symbolOffset,virtual.offset+4*part);
  825. END;
  826. END GetMemory;
  827. PROCEDURE HardwareIntegerRegister(index: LONGINT; sizeInBits: LONGINT): LONGINT;
  828. BEGIN
  829. index := index MOD 32;
  830. sizeInBits := sizeInBits DIV 8;
  831. WHILE sizeInBits > 1 DO (* jump to register section that corresponds to the number of bits *)
  832. INC(index,32);
  833. sizeInBits := sizeInBits DIV 2;
  834. END;
  835. RETURN index
  836. END HardwareIntegerRegister;
  837. PROCEDURE HardwareFloatRegister(index: LONGINT; sizeInBits: LONGINT): LONGINT;
  838. BEGIN HALT(200); (* not yet implemented *)
  839. END HardwareFloatRegister;
  840. PROCEDURE GetTypedHardwareRegister(index: LONGINT; type: IntermediateCode.Type): LONGINT;
  841. VAR size: LONGINT;
  842. BEGIN
  843. IF type.form IN IntermediateCode.Integer THEN
  844. RETURN HardwareIntegerRegister(index, type.sizeInBits)
  845. ELSIF type.form = IntermediateCode.Float THEN
  846. RETURN HardwareFloatRegister(index, type.sizeInBits)
  847. ELSE
  848. HALT(100);
  849. END;
  850. END GetTypedHardwareRegister;
  851. PROCEDURE ParameterRegister(CONST type: IntermediateCode.Type; index: LONGINT): LONGINT;
  852. VAR physical: LONGINT;
  853. BEGIN
  854. CASE index OF
  855. 0: RETURN GetTypedHardwareRegister(RCX,type)
  856. |1: RETURN GetTypedHardwareRegister(RDX,type)
  857. |2: RETURN GetTypedHardwareRegister(R8,type)
  858. |3: RETURN GetTypedHardwareRegister(R9,type)
  859. END;
  860. RETURN physical;
  861. END ParameterRegister;
  862. PROCEDURE GetRegister(CONST virtual: IntermediateCode.Operand; part:LONGINT; VAR physical: Assembler.Operand; VAR ticket: Ticket);
  863. VAR type: IntermediateCode.Type; virtualRegister, tempReg: LONGINT;
  864. tmp,imm: Assembler.Operand; index: LONGINT;
  865. BEGIN
  866. ASSERT(virtual.mode = IntermediateCode.ModeRegister);
  867. GetPartType(virtual.type,part,type);
  868. virtualRegister := virtual.register;
  869. IF (virtual.register > 0) THEN
  870. TicketToOperand(virtualRegisters.Mapped(virtual.register,part), physical);
  871. ELSIF virtual.register = IntermediateCode.FP THEN
  872. Assert(part=Low,"forbidden partitioned register on BP");
  873. physical := opBP;
  874. ELSIF virtual.register = IntermediateCode.SP THEN
  875. Assert(part=Low,"forbidden partitioned register on SP");
  876. physical := opSP;
  877. (*! done by generic part:
  878. ELSIF virtual.register <= IntermediateCode.ParameterRegister THEN
  879. index := IntermediateCode.ParameterRegister - virtualRegister;
  880. physical := registerOperands[ParameterRegister(index, type)];
  881. *)
  882. ELSIF virtual.register = IntermediateCode.AP THEN
  883. ASSERT(backend.cooperative);
  884. Assert(part=Low,"forbidden partitioned register on AP");
  885. TicketToOperand(ap, physical);
  886. ELSE HALT(100);
  887. END;
  888. IF virtual.offset # 0 THEN
  889. Assert(type.form # IntermediateCode.Float,"forbidden offset on float");
  890. IF ticket = NIL THEN
  891. tempReg := ForceFreeRegister(type);
  892. TicketToOperand(ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,type,tempReg,inPC),tmp);
  893. ELSE
  894. TicketToOperand(ticket, tmp);
  895. ticket := NIL;
  896. END;
  897. IF Assembler.IsRegisterOperand(physical) THEN
  898. Assembler.InitMem(physical,SHORTINT(type.length * type.sizeInBits DIV 8) , physical.register, virtual.offset);
  899. emitter.Emit2(InstructionSet.opLEA, tmp,physical);
  900. ELSE
  901. emitter.Emit2(InstructionSet.opMOV,tmp,physical);
  902. Assembler.InitImm(imm,0 ,virtual.offset);
  903. emitter.Emit2(InstructionSet.opADD,tmp,imm);
  904. END;
  905. physical := tmp;
  906. END;
  907. END GetRegister;
  908. (* make physical operand from virtual operand, if ticket given then write result into phyiscal register represented by ticket *)
  909. PROCEDURE MakeOperand(CONST vop: IntermediateCode.Operand; part: LONGINT; VAR op: Assembler.Operand; ticket: Ticket);
  910. VAR tmp: Assembler.Operand;
  911. BEGIN
  912. TryAllocate(vop,part);
  913. CASE vop.mode OF
  914. IntermediateCode.ModeMemory: GetMemory(vop,part,op);
  915. |IntermediateCode.ModeRegister: GetRegister(vop,part,op,ticket);
  916. |IntermediateCode.ModeImmediate: GetImmediate(vop,part,op,FALSE);
  917. END;
  918. IF ticket # NIL THEN
  919. TicketToOperand(ticket, tmp);
  920. emitter.Emit2(InstructionSet.opMOV, tmp, op);
  921. (* should work but does not
  922. IF Assembler.IsRegisterOperand(op) THEN ReleaseHint(op.register) END;
  923. *)
  924. op := tmp;
  925. END;
  926. END MakeOperand;
  927. (* make physical register operand from virtual operand *)
  928. PROCEDURE MakeRegister(CONST vop: IntermediateCode.Operand; part: LONGINT; VAR op: Assembler.Operand);
  929. VAR previous: Assembler.Operand; temp: Ticket;
  930. BEGIN
  931. MakeOperand(vop,part,op,NIL);
  932. IF ~Assembler.IsRegisterOperand(op) THEN
  933. previous := op;
  934. temp := TemporaryTicket(vop.registerClass,vop.type);
  935. TicketToOperand(temp,op);
  936. IF vop.type.length > 1 THEN
  937. emitter.Emit2(InstructionSet.opMOVUPS, op, previous);
  938. ELSE
  939. Move(op, previous, vop.type);
  940. END;
  941. END;
  942. END MakeRegister;
  943. (*------------------- helpers for code generation ----------------------*)
  944. (* move, potentially with conversion. parameter back used for moving back from temporary operand*)
  945. PROCEDURE SpecialMove(op, back: LONGINT; canStoreToMemory: BOOLEAN; VAR dest,src: Assembler.Operand; type: IntermediateCode.Type);
  946. VAR temp: Assembler.Operand; ticket: Ticket;
  947. BEGIN
  948. IF Assembler.SameOperand(src,dest) THEN (* do nothing *)
  949. ELSIF ~Assembler.IsMemoryOperand(dest) OR (~Assembler.IsMemoryOperand(src) & canStoreToMemory) THEN
  950. emitter.Emit2(op,dest,src);
  951. ELSE
  952. ticket := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,type);
  953. TicketToOperand(ticket,temp);
  954. emitter.Emit2(op,temp,src);
  955. emitter.Emit2(back,dest,temp);
  956. UnmapTicket(ticket);
  957. END;
  958. END SpecialMove;
  959. PROCEDURE AllocateStack(sizeInBytes: LONGINT);
  960. VAR sizeOp: Assembler.Operand; opcode: LONGINT;
  961. BEGIN
  962. ASSERT(sizeInBytes MOD 4 (* (cpuBits DIV 8) *) = 0);
  963. IF sizeInBytes < 0 THEN
  964. sizeInBytes := -sizeInBytes; opcode := InstructionSet.opADD;
  965. ELSIF sizeInBytes > 0 THEN
  966. opcode := InstructionSet.opSUB;
  967. ELSE RETURN
  968. END;
  969. IF sizeInBytes < 128 THEN sizeOp := Assembler.NewImm8(sizeInBytes);
  970. ELSE sizeOp := Assembler.NewImm32(sizeInBytes);
  971. END;
  972. emitter.Emit2(opcode,opSP,sizeOp);
  973. END AllocateStack;
  974. (*------------------- generation = emit dispatch / emit procedures ----------------------*)
  975. PROCEDURE IsFloat(CONST operand: IntermediateCode.Operand): BOOLEAN;
  976. BEGIN RETURN operand.type.form = IntermediateCode.Float
  977. END IsFloat;
  978. PROCEDURE IsComplex(CONST operand: IntermediateCode.Operand): BOOLEAN;
  979. BEGIN RETURN (operand.type.form IN IntermediateCode.Integer) & (operand.type.sizeInBits > cpuBits)
  980. END IsComplex;
  981. PROCEDURE Generate(VAR instruction: IntermediateCode.Instruction);
  982. VAR opcode: SHORTINT; ticket: Ticket; hwreg, lastUse, i, part: LONGINT;
  983. BEGIN
  984. (*!IF ((instruction.opcode = IntermediateCode.mov) OR (instruction.opcode = IntermediateCode.pop)) & (instruction.op1.register <= IntermediateCode.ParameterRegister) THEN
  985. hwreg := ParameterRegister(IntermediateCode.ParameterRegister-instruction.op1.register, instruction.op1.type);
  986. Spill(physicalRegisters.Mapped(hwreg));
  987. lastUse := inPC+1;
  988. WHILE (lastUse < in.pc) &
  989. ((in.instructions[lastUse].opcode # IntermediateCode.push) OR (in.instructions[lastUse].op1.register # instruction.op1.register)) & (in.instructions[lastUse].opcode # IntermediateCode.call) DO
  990. INC(lastUse)
  991. END;
  992. ticket := ReservePhysicalRegister(instruction.op1.type,hwreg,lastUse);
  993. END;
  994. *)
  995. ReserveOperandRegisters(instruction.op1,TRUE); ReserveOperandRegisters(instruction.op2,TRUE);ReserveOperandRegisters(instruction.op3,TRUE);
  996. (*TryAllocate(instruction.op1,Low);
  997. IF IsComplex(instruction.op1) THEN TryAllocate(instruction.op1,High) END;
  998. *)
  999. opcode := instruction.opcode;
  1000. CASE opcode OF
  1001. IntermediateCode.nop: (* do nothing *)
  1002. |IntermediateCode.mov:
  1003. IF IsFloat(instruction.op1) OR IsFloat(instruction.op2) THEN
  1004. EmitMovFloat(instruction.op1,instruction.op2)
  1005. ELSE EmitMov(instruction.op1,instruction.op2,Low);
  1006. IF IsComplex(instruction.op1) THEN EmitMov(instruction.op1,instruction.op2, High) END;
  1007. END;
  1008. |IntermediateCode.conv:
  1009. IF IsFloat(instruction.op1) OR IsFloat(instruction.op2) THEN
  1010. EmitConvertFloat(instruction)
  1011. ELSE
  1012. EmitConvert(instruction.op1,instruction.op2,Low);
  1013. IF IsComplex(instruction.op1) THEN EmitConvert(instruction.op1,instruction.op2,High) END;
  1014. END;
  1015. |IntermediateCode.call: EmitCall(instruction);
  1016. |IntermediateCode.enter: EmitEnter(instruction);
  1017. |IntermediateCode.leave: EmitLeave(instruction);
  1018. |IntermediateCode.exit: EmitExit(instruction);
  1019. |IntermediateCode.result:
  1020. IF IsFloat(instruction.op1) & backend.forceFPU THEN
  1021. EmitResultFPU(instruction)
  1022. ELSE
  1023. EmitResult(instruction,Low);
  1024. IF IsComplex(instruction.op1) THEN EmitResult(instruction,High) END;
  1025. END;
  1026. |IntermediateCode.return:
  1027. IF IsFloat(instruction.op1) & backend.forceFPU THEN
  1028. EmitReturnFPU(instruction)
  1029. ELSE
  1030. EmitReturn(instruction,Low);
  1031. IF IsComplex(instruction.op1) THEN EmitReturn(instruction, High) END;
  1032. END;
  1033. |IntermediateCode.trap: EmitTrap(instruction);
  1034. |IntermediateCode.br .. IntermediateCode.brlt: EmitBr(instruction)
  1035. |IntermediateCode.pop:
  1036. IF IsFloat(instruction.op1) THEN
  1037. EmitPopFloat(instruction.op1)
  1038. ELSE
  1039. EmitPop(instruction.op1,Low);
  1040. IF IsComplex(instruction.op1) THEN
  1041. EmitPop(instruction.op1,High)
  1042. END;
  1043. END;
  1044. |IntermediateCode.push:
  1045. IF IsFloat(instruction.op1) THEN
  1046. EmitPushFloat(instruction.op1)
  1047. ELSE
  1048. IF IsComplex(instruction.op1) THEN
  1049. EmitPush(instruction.op1,High);
  1050. END;
  1051. EmitPush(instruction.op1,Low)
  1052. END;
  1053. |IntermediateCode.neg:
  1054. IF IsFloat(instruction.op1) THEN
  1055. IF backend.forceFPU THEN
  1056. EmitArithmetic2FPU(instruction,InstructionSet.opFCHS)
  1057. ELSE
  1058. EmitNegXMM(instruction)
  1059. END;
  1060. ELSE EmitNeg(instruction);
  1061. END;
  1062. |IntermediateCode.not:
  1063. Assert(~IsFloat(instruction.op1),"instruction not supported for float");
  1064. EmitArithmetic2(instruction,Low,InstructionSet.opNOT);
  1065. IF IsComplex(instruction.op1) THEN EmitArithmetic2(instruction, High, InstructionSet.opNOT) END;
  1066. |IntermediateCode.abs:
  1067. IF IsFloat(instruction.op1) THEN
  1068. IF backend.forceFPU THEN
  1069. EmitArithmetic2FPU(instruction,InstructionSet.opFABS)
  1070. ELSE
  1071. EmitAbsXMM(instruction)
  1072. END;
  1073. ELSE EmitAbs(instruction);
  1074. END;
  1075. |IntermediateCode.mul:
  1076. IF IsFloat(instruction.op1) THEN
  1077. IF backend.forceFPU THEN
  1078. EmitArithmetic3FPU(instruction,InstructionSet.opFMUL)
  1079. ELSE
  1080. EmitArithmetic3XMM(instruction, InstructionSet.opMULSS, InstructionSet.opMULSD)
  1081. END;
  1082. ELSE
  1083. EmitMul(instruction);
  1084. END;
  1085. |IntermediateCode.div:
  1086. IF IsFloat(instruction.op1 )THEN
  1087. IF backend.forceFPU THEN
  1088. EmitArithmetic3FPU(instruction,InstructionSet.opFDIV)
  1089. ELSE
  1090. EmitArithmetic3XMM(instruction, InstructionSet.opDIVSS, InstructionSet.opDIVSD)
  1091. END;
  1092. ELSE
  1093. EmitDivMod(instruction);
  1094. END;
  1095. |IntermediateCode.mod:
  1096. Assert(~IsFloat(instruction.op1),"instruction not supported for float");
  1097. EmitDivMod(instruction);
  1098. |IntermediateCode.sub:
  1099. IF IsFloat(instruction.op1) THEN
  1100. IF backend.forceFPU THEN
  1101. EmitArithmetic3FPU(instruction,InstructionSet.opFSUB)
  1102. ELSE
  1103. EmitArithmetic3XMM(instruction, InstructionSet.opSUBSS, InstructionSet.opSUBSD)
  1104. END;
  1105. ELSE EmitArithmetic3(instruction,Low,InstructionSet.opSUB);
  1106. IF IsComplex(instruction.op1) THEN EmitArithmetic3(instruction, High, InstructionSet.opSBB) END;
  1107. END;
  1108. |IntermediateCode.add:
  1109. IF IsFloat(instruction.op1) THEN
  1110. IF backend.forceFPU THEN
  1111. EmitArithmetic3FPU(instruction,InstructionSet.opFADD)
  1112. ELSE
  1113. EmitArithmetic3XMM(instruction, InstructionSet.opADDSS, InstructionSet.opADDSD)
  1114. END;
  1115. ELSE EmitArithmetic3(instruction,Low,InstructionSet.opADD);
  1116. IF IsComplex(instruction.op1) THEN EmitArithmetic3(instruction, High, InstructionSet.opADC) END;
  1117. END;
  1118. |IntermediateCode.and:
  1119. Assert(~IsFloat(instruction.op1),"operation not defined on float");
  1120. EmitArithmetic3(instruction,Low,InstructionSet.opAND);
  1121. IF IsComplex(instruction.op1) THEN EmitArithmetic3(instruction, High, InstructionSet.opAND) END;
  1122. |IntermediateCode.or:
  1123. Assert(~IsFloat(instruction.op1),"operation not defined on float");
  1124. EmitArithmetic3(instruction,Low,InstructionSet.opOR);
  1125. IF IsComplex(instruction.op1) THEN EmitArithmetic3(instruction, High, InstructionSet.opOR) END;
  1126. |IntermediateCode.xor:
  1127. Assert(~IsFloat(instruction.op1),"operation not defined on float");
  1128. EmitArithmetic3(instruction,Low,InstructionSet.opXOR);
  1129. IF IsComplex(instruction.op1) THEN EmitArithmetic3(instruction, High, InstructionSet.opXOR) END;
  1130. |IntermediateCode.shl: EmitShift(instruction);
  1131. |IntermediateCode.shr: EmitShift(instruction);
  1132. |IntermediateCode.rol: EmitShift(instruction);
  1133. |IntermediateCode.ror: EmitShift(instruction);
  1134. |IntermediateCode.cas: EmitCas(instruction);
  1135. |IntermediateCode.copy: EmitCopy(instruction);
  1136. |IntermediateCode.fill: EmitFill(instruction,FALSE);
  1137. |IntermediateCode.asm: EmitAsm(instruction);
  1138. END;
  1139. ReserveOperandRegisters(instruction.op3,FALSE); ReserveOperandRegisters(instruction.op2,FALSE); ReserveOperandRegisters(instruction.op1,FALSE);
  1140. END Generate;
  1141. PROCEDURE PostGenerate(CONST instruction: IntermediateCode.Instruction);
  1142. VAR ticket: Ticket;
  1143. BEGIN
  1144. TryUnmap(instruction.op3); TryUnmap(instruction.op2); TryUnmap(instruction.op1);
  1145. ticket := tickets.live;
  1146. WHILE (ticket # NIL) & (ticket.lastuse = inPC) DO
  1147. UnmapTicket(ticket);
  1148. ticket := tickets.live
  1149. END;
  1150. END PostGenerate;
  1151. (* enter procedure: generate PAF and clear stack *)
  1152. PROCEDURE EmitEnter(CONST instruction: IntermediateCode.Instruction);
  1153. VAR op1,imm,target: Assembler.Operand; cc,size,numberMachineWords,destPC,firstPC,secondPC,x: LONGINT; body: SyntaxTree.Body; name: Basic.SegmentedName;
  1154. parametersSize: SIZE;
  1155. CONST initialize=TRUE; FirstOffset = 5; SecondOffset = 11;
  1156. BEGIN
  1157. stackSize := SHORT(instruction.op2.intValue);
  1158. size := stackSize;
  1159. INC(traceStackSize, stackSize);
  1160. IF initialize THEN
  1161. (* always including this instruction make trace insertion possible *)
  1162. IF backend.traceable THEN
  1163. emitter.Emit2(InstructionSet.opXOR,opRA,opRA);
  1164. END;
  1165. ASSERT(size MOD opRA.sizeInBytes = 0);
  1166. numberMachineWords := size DIV opRA.sizeInBytes;
  1167. IF numberMachineWords >0 THEN
  1168. IF ~backend.traceable THEN
  1169. emitter.Emit2(InstructionSet.opXOR,opRA,opRA);
  1170. END;
  1171. WHILE numberMachineWords MOD 4 # 0 DO
  1172. emitter.Emit1(InstructionSet.opPUSH, opRA);
  1173. DEC(numberMachineWords);
  1174. END;
  1175. IF numberMachineWords >4 THEN
  1176. Assembler.InitImm(imm, 0, numberMachineWords DIV 4);
  1177. emitter.Emit2(InstructionSet.opMOV, opRB, imm);
  1178. destPC := out.pc;
  1179. emitter.Emit1(InstructionSet.opDEC, opRB);
  1180. emitter.Emit1(InstructionSet.opPUSH, opRA);
  1181. emitter.Emit1(InstructionSet.opPUSH, opRA);
  1182. emitter.Emit1(InstructionSet.opPUSH, opRA);
  1183. emitter.Emit1(InstructionSet.opPUSH, opRA);
  1184. Assembler.InitOffset8(target,destPC);
  1185. emitter.Emit1(InstructionSet.opJNZ, target)
  1186. ELSE
  1187. WHILE numberMachineWords >0 DO
  1188. emitter.Emit1(InstructionSet.opPUSH, opRA);
  1189. DEC(numberMachineWords);
  1190. END;
  1191. END;
  1192. END;
  1193. IF spillStack.MaxSize()>0 THEN (* register spill stack, does not have to be initialized *)
  1194. op1 := Assembler.NewImm32(spillStack.MaxSize()*cpuBits DIV 8);
  1195. emitter.Emit2(InstructionSet.opSUB,opSP,op1);
  1196. END;
  1197. ELSE
  1198. op1 := Assembler.NewImm32(size+ spillStack.MaxSize());
  1199. emitter.Emit2(InstructionSet.opSUB,opSP,op1);
  1200. END;
  1201. IF (cc = SyntaxTree.WinAPICallingConvention) OR (cc = SyntaxTree.CCallingConvention) THEN
  1202. (* the winapi calling convention presumes that all registers except EAX, EDX and ECX are retained by the callee *)
  1203. emitter.Emit1(InstructionSet.opPUSH,opEBX);
  1204. emitter.Emit1(InstructionSet.opPUSH,opEDI);
  1205. emitter.Emit1(InstructionSet.opPUSH,opESI);
  1206. END;
  1207. spillStackStart := stackSize;
  1208. END EmitEnter;
  1209. PROCEDURE EmitLeave(CONST instruction: IntermediateCode.Instruction);
  1210. VAR cc: LONGINT; offset: Assembler.Operand;
  1211. BEGIN
  1212. cc := SHORT(instruction.op1.intValue);
  1213. IF (cc = SyntaxTree.WinAPICallingConvention) OR (cc = SyntaxTree.CCallingConvention) THEN
  1214. emitter.Emit1(InstructionSet.opPOP,opESI);
  1215. emitter.Emit1(InstructionSet.opPOP,opEDI);
  1216. emitter.Emit1(InstructionSet.opPOP,opEBX);
  1217. END;
  1218. END EmitLeave;
  1219. PROCEDURE EmitExit(CONST instruction: IntermediateCode.Instruction);
  1220. BEGIN
  1221. emitter.Emit0(InstructionSet.opRET);
  1222. IF fpStackPointer # 0 THEN Error(instruction.textPosition,"compiler implementation error: fp stack not cleared") END;
  1223. END EmitExit;
  1224. PROCEDURE EmitReturnFPU(CONST instruction: IntermediateCode.Instruction);
  1225. VAR operand: Assembler.Operand;
  1226. BEGIN
  1227. IF IsRegister(instruction.op1) & MappedTo(instruction.op1.register,Low, ST0) THEN
  1228. (* nothing to do: result is already in return register *)
  1229. ELSE
  1230. MakeOperand(instruction.op1, Low, operand,NIL);
  1231. emitter.Emit1(InstructionSet.opFLD,operand);
  1232. (*
  1233. not necessary to clear from top of stack as callee will clear
  1234. INC(fpStackPointer);
  1235. emitter.Emit1(InstructionSet.opFSTP,registerOperands[ST0+1]);
  1236. DEC(fpStackPointer);
  1237. *)
  1238. END;
  1239. END EmitReturnFPU;
  1240. (* return operand
  1241. store operand in return register or on fp stack
  1242. *)
  1243. PROCEDURE EmitReturn(CONST instruction: IntermediateCode.Instruction; part: LONGINT);
  1244. VAR return,operand: Assembler.Operand; register: LONGINT; ticket: Ticket; type: IntermediateCode.Type;
  1245. BEGIN
  1246. register := ResultRegister(instruction.op1.type, part);
  1247. IF IsRegister(instruction.op1) & MappedTo(instruction.op1.register,part, register) THEN
  1248. (* nothing to do: result is already in return register *)
  1249. ELSE
  1250. GetPartType(instruction.op1.type,part, type);
  1251. MakeOperand(instruction.op1, part, operand,NIL);
  1252. Spill(physicalRegisters.Mapped(register));
  1253. ticket := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,type,register,inPC);
  1254. TicketToOperand(ticket, return);
  1255. (* Mov takes care of potential register overlaps *)
  1256. Move(return, operand, type);
  1257. UnmapTicket(ticket);
  1258. END;
  1259. END EmitReturn;
  1260. PROCEDURE EmitMovFloat(CONST vdest,vsrc:IntermediateCode.Operand);
  1261. VAR dest,src, espm: Assembler.Operand; sizeInBytes: SHORTINT; vcopy: IntermediateCode.Operand;
  1262. BEGIN
  1263. sizeInBytes := SHORTINT(vdest.type.sizeInBits DIV 8);
  1264. IF vdest.type.form IN IntermediateCode.Integer THEN
  1265. (* e.g. in SYSTEM.VAL(LONGINT, r) *)
  1266. IF vsrc.mode = IntermediateCode.ModeMemory THEN
  1267. vcopy := vsrc; IntermediateCode.SetType(vcopy,vdest.type);
  1268. EmitMov(vdest, vcopy,Low);
  1269. IF IsComplex(vdest) THEN
  1270. EmitMov(vdest,vcopy,High);
  1271. END;
  1272. ELSE
  1273. IF backend.forceFPU THEN
  1274. MakeOperand(vsrc,Low,src,NIL);
  1275. emitter.Emit1(InstructionSet.opFLD,src);
  1276. INC(fpStackPointer);
  1277. IF vdest.mode = IntermediateCode.ModeMemory THEN
  1278. MakeOperand(vdest,Low,dest,NIL);
  1279. Assembler.SetSize(dest,sizeInBytes);
  1280. emitter.Emit1(InstructionSet.opFSTP,dest);
  1281. DEC(fpStackPointer);
  1282. ELSE
  1283. AllocateStack(sizeInBytes);
  1284. Assembler.InitMem(espm, sizeInBytes,SP,0);
  1285. emitter.Emit1(InstructionSet.opFSTP,espm);
  1286. DEC(fpStackPointer);
  1287. MakeOperand(vdest,Low,dest,NIL);
  1288. EmitPop(vdest,Low);
  1289. IF IsComplex(vdest) THEN
  1290. EmitPop(vdest,High);
  1291. END;
  1292. END;
  1293. ELSE
  1294. MakeOperand(vsrc, Low, src, NIL);
  1295. IF vdest.mode = IntermediateCode.ModeMemory THEN
  1296. MakeOperand(vdest, Low, dest, NIL);
  1297. Move(dest, src, vsrc.type);
  1298. ELSE (* need temporary stack argument *)
  1299. AllocateStack(sizeInBytes);
  1300. Assembler.InitMem(espm, sizeInBytes,SP,0);
  1301. Move(espm, src, vsrc.type);
  1302. MakeOperand(vdest,Low,dest,NIL);
  1303. EmitPop(vdest,Low);
  1304. IF IsComplex(vdest) THEN
  1305. EmitPop(vdest,High);
  1306. END;
  1307. END;
  1308. END;
  1309. END;
  1310. ELSIF vsrc.type.form IN IntermediateCode.Integer THEN
  1311. (* e.g. in SYSTEM.VAL(REAL, i) *)
  1312. IF vdest.mode = IntermediateCode.ModeMemory THEN
  1313. vcopy := vdest; IntermediateCode.SetType(vcopy,vsrc.type);
  1314. EmitMov(vcopy, vsrc,Low);
  1315. IF IsComplex(vsrc) THEN
  1316. EmitMov(vcopy,vsrc,High);
  1317. END;
  1318. ELSE
  1319. IF backend.forceFPU THEN
  1320. IF vsrc.mode = IntermediateCode.ModeMemory THEN
  1321. MakeOperand(vsrc,Low,src,NIL);
  1322. Assembler.SetSize(src,sizeInBytes);
  1323. emitter.Emit1(InstructionSet.opFLD,src);
  1324. ELSE
  1325. IF IsComplex(vsrc) THEN
  1326. EmitPush(vsrc,High);
  1327. END;
  1328. EmitPush(vsrc,Low);
  1329. Assembler.InitMem(espm, sizeInBytes,SP,0);
  1330. emitter.Emit1(InstructionSet.opFLD,espm);
  1331. ASSERT(sizeInBytes >0);
  1332. AllocateStack(-sizeInBytes);
  1333. END;
  1334. INC(fpStackPointer);
  1335. MakeOperand(vdest,Low,dest,NIL);
  1336. emitter.Emit1(InstructionSet.opFSTP,dest);
  1337. DEC(fpStackPointer);
  1338. ELSE
  1339. IF vsrc.mode = IntermediateCode.ModeMemory THEN
  1340. MakeOperand(vsrc,Low,src,NIL);
  1341. Assembler.SetSize(src,sizeInBytes);
  1342. MakeOperand(vdest,Low,dest,NIL);
  1343. Move(dest, src, vdest.type);
  1344. ELSE
  1345. IF IsComplex(vsrc) THEN
  1346. EmitPush(vsrc,High);
  1347. END;
  1348. EmitPush(vsrc,Low);
  1349. Assembler.InitMem(espm, sizeInBytes,SP,0);
  1350. MakeOperand(vdest, Low, dest, NIL);
  1351. Move(dest, espm, vdest.type);
  1352. AllocateStack(-sizeInBytes);
  1353. END;
  1354. END;
  1355. END;
  1356. ELSE
  1357. IF backend.forceFPU THEN
  1358. MakeOperand(vsrc,Low,src,NIL);
  1359. emitter.Emit1(InstructionSet.opFLD,src);
  1360. INC(fpStackPointer);
  1361. MakeOperand(vdest,Low,dest,NIL);
  1362. emitter.Emit1(InstructionSet.opFSTP,dest);
  1363. DEC(fpStackPointer);
  1364. ELSE
  1365. MakeOperand(vsrc, Low, src, NIL);
  1366. MakeOperand(vdest, Low, dest, NIL);
  1367. Move(dest, src, vdest.type)
  1368. END;
  1369. END;
  1370. END EmitMovFloat;
  1371. PROCEDURE EmitMov(CONST vdest,vsrc: IntermediateCode.Operand; part: LONGINT);
  1372. VAR op1,op2: Assembler.Operand; tmp: IntermediateCode.Operand;
  1373. t: CodeGenerators.Ticket;
  1374. type: IntermediateCode.Type;
  1375. BEGIN
  1376. IF (vdest.mode = IntermediateCode.ModeRegister) & (vsrc.mode = IntermediateCode.ModeRegister) & (vsrc.offset # 0) THEN
  1377. (* MOV R1, R2+offset => LEA EAX, [EBX+offset] *)
  1378. tmp := vsrc;
  1379. IntermediateCode.MakeMemory(tmp,vsrc.type);
  1380. MakeOperand(tmp,part,op2,NIL);
  1381. (*
  1382. ReleaseHint(op2.register);
  1383. *)
  1384. MakeOperand(vdest,part,op1,NIL);
  1385. t := virtualRegisters.Mapped(vdest.register,part);
  1386. IF (t # NIL) & (t.spilled) THEN
  1387. UnSpill(t); (* make sure this has not spilled *)
  1388. MakeOperand(vdest,part, op1,NIL);
  1389. END;
  1390. emitter.Emit2(InstructionSet.opLEA,op1,op2);
  1391. ELSE
  1392. MakeOperand(vsrc,part,op2,NIL);
  1393. MakeOperand(vdest,part,op1,NIL);
  1394. GetPartType(vsrc.type, part, type);
  1395. Move(op1,op2, type);
  1396. END;
  1397. END EmitMov;
  1398. PROCEDURE EmitConvertFloat(CONST instruction: IntermediateCode.Instruction);
  1399. VAR destType, srcType, dtype: IntermediateCode.Type; dest,src,espm,imm: Assembler.Operand; sizeInBytes, index: LONGINT;
  1400. temp, temp2, temp3, temp4: Assembler.Operand; ticket: Ticket; vdest, vsrc: IntermediateCode.Operand;
  1401. BEGIN
  1402. vdest := instruction.op1; vsrc := instruction.op2;
  1403. srcType := vsrc.type;
  1404. destType := vdest.type;
  1405. IF destType.form = IntermediateCode.Float THEN
  1406. CASE srcType.form OF
  1407. |IntermediateCode.Float: (* just a move *)
  1408. IF backend.forceFPU THEN
  1409. EmitMovFloat(vdest, vsrc);
  1410. ELSE
  1411. MakeOperand(vsrc,Low,src,NIL);
  1412. MakeOperand(vdest, Low, dest, NIL);
  1413. IF srcType.sizeInBits = 32 THEN
  1414. SpecialMove(InstructionSet.opCVTSS2SD, InstructionSet.opMOVSS, FALSE, dest, src, destType)
  1415. ELSE
  1416. SpecialMove(InstructionSet.opCVTSD2SS, InstructionSet.opMOVSD, FALSE, dest, src, destType)
  1417. END;
  1418. END;
  1419. |IntermediateCode.SignedInteger:
  1420. (* put value to stack and then read from stack via Float *)
  1421. IF vsrc.type.sizeInBits < IntermediateCode.Bits32 THEN
  1422. MakeOperand(vsrc,Low,src,NIL);
  1423. ticket := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32);
  1424. TicketToOperand(ticket,temp);
  1425. emitter.Emit2(InstructionSet.opMOVSX,temp,src);
  1426. IF backend.forceFPU THEN (* via stack *)
  1427. emitter.Emit1(InstructionSet.opPUSH,temp);
  1428. UnmapTicket(ticket);
  1429. sizeInBytes := temp.sizeInBytes;
  1430. ELSE (* via register *)
  1431. espm := temp;
  1432. sizeInBytes := 0
  1433. END;
  1434. ELSIF IsComplex(vsrc) THEN (* via stack *)
  1435. EmitPush(vsrc,High);
  1436. EmitPush(vsrc,Low);
  1437. sizeInBytes := 8
  1438. ELSE
  1439. IF backend.forceFPU THEN (* via stack *)
  1440. EmitPush(vsrc,Low);
  1441. sizeInBytes := SHORTINT(4 (* cpuBits DIV 8*)) (*SHORT(srcType.sizeInBits DIV 8)*);
  1442. ELSE (* via memory or register *)
  1443. sizeInBytes := 0;
  1444. MakeOperand(vsrc,Low,src,NIL);
  1445. IF Assembler.IsImmediateOperand(src) THEN (* use temporary register *)
  1446. ticket := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32);
  1447. TicketToOperand(ticket,temp);
  1448. emitter.Emit2(InstructionSet.opMOVSX,temp,src);
  1449. espm := temp
  1450. ELSE
  1451. espm := src
  1452. END;
  1453. END
  1454. END;
  1455. IF sizeInBytes > 0 THEN
  1456. Assembler.InitMem(espm, SHORTINT(sizeInBytes),SP,0);
  1457. END;
  1458. IF backend.forceFPU THEN
  1459. emitter.Emit1(InstructionSet.opFILD,espm);
  1460. INC(fpStackPointer);
  1461. ASSERT(sizeInBytes >0);
  1462. Basic.Align(sizeInBytes, 4 (* cpuBits DIV 8*));
  1463. AllocateStack(-sizeInBytes);
  1464. MakeOperand(vdest,Low,dest,NIL);
  1465. emitter.Emit1(InstructionSet.opFSTP,dest);
  1466. DEC(fpStackPointer);
  1467. ELSIF IsComplex(vsrc) THEN
  1468. emitter.Emit1(InstructionSet.opFILD,espm);
  1469. MakeOperand(vdest,Low,dest,NIL);
  1470. IF Assembler.IsMemoryOperand(dest) THEN
  1471. emitter.Emit1(InstructionSet.opFSTP,dest);
  1472. ELSE (* must be register *)
  1473. emitter.Emit1(InstructionSet.opFSTP,espm);
  1474. emitter.Emit2(InstructionSet.opMOVQ,dest,espm);
  1475. IF destType.sizeInBits = 32 THEN
  1476. emitter.Emit2(InstructionSet.opCVTSD2SS, dest,dest);
  1477. END;
  1478. END;
  1479. AllocateStack(-sizeInBytes);
  1480. ELSE
  1481. MakeOperand(vdest,Low,dest,NIL);
  1482. IF destType.sizeInBits = 32 THEN
  1483. emitter.Emit2(InstructionSet.opCVTSI2SS, dest, espm)
  1484. ELSE
  1485. emitter.Emit2(InstructionSet.opCVTSI2SD, dest, espm)
  1486. END;
  1487. AllocateStack(-sizeInBytes);
  1488. END;
  1489. END;
  1490. ELSE
  1491. ASSERT(destType.form IN IntermediateCode.Integer);
  1492. ASSERT(srcType.form = IntermediateCode.Float);
  1493. Assert(vdest.type.form = IntermediateCode.SignedInteger, "no entier as result for unsigned integer");
  1494. MakeOperand(vsrc,Low,src,NIL);
  1495. IF ~backend.forceFPU THEN
  1496. MakeOperand(vdest,Low,dest,ticket);
  1497. GetTemporaryRegister(srcType, temp);
  1498. GetTemporaryRegister(srcType, temp3);
  1499. IF destType.sizeInBits < 32 THEN
  1500. IntermediateCode.InitType(dtype, destType.form, 32);
  1501. GetTemporaryRegister(dtype, temp4);
  1502. ELSE
  1503. dtype := destType;
  1504. temp4 := dest;
  1505. END;
  1506. GetTemporaryRegister(dtype, temp2);
  1507. IF srcType.sizeInBits = 32 THEN
  1508. (* convert truncated -> negative numbers round up !*)
  1509. emitter.Emit2(InstructionSet.opCVTTSS2SI, temp4, src);
  1510. (* back to temporary mmx register *)
  1511. emitter.Emit2(InstructionSet.opCVTSI2SS, temp, temp4);
  1512. (* subtract *)
  1513. emitter.Emit2(InstructionSet.opMOVSS, temp3, src);
  1514. emitter.Emit2(InstructionSet.opSUBSS, temp3, temp);
  1515. (* back to a GP register in order to determine the sign bit *)
  1516. ELSE
  1517. emitter.Emit2(InstructionSet.opCVTTSD2SI, temp4, src);
  1518. emitter.Emit2(InstructionSet.opCVTSI2SD, temp, temp4);
  1519. emitter.Emit2(InstructionSet.opMOVSD, temp3, src);
  1520. emitter.Emit2(InstructionSet.opSUBSD, temp3, temp);
  1521. emitter.Emit2(InstructionSet.opCVTSD2SS, temp3, temp3);
  1522. END;
  1523. emitter.Emit2(InstructionSet.opMOVD, temp2, temp3);
  1524. Assembler.InitImm(imm, 0 ,srcType.sizeInBits-1);
  1525. emitter.Emit2(InstructionSet.opBT, temp2, imm);
  1526. Assembler.InitImm(imm, 0 ,0);
  1527. emitter.Emit2(InstructionSet.opSBB, temp4, imm);
  1528. IF dtype.sizeInBits # destType.sizeInBits THEN
  1529. index := temp4.register;
  1530. CASE destType.sizeInBits OF (* choose low part accordingly *)
  1531. IntermediateCode.Bits8: index := index MOD 32 + AL;
  1532. |IntermediateCode.Bits16: index := index MOD 32 + AX;
  1533. |IntermediateCode.Bits32: index := index MOD 32 + EAX;
  1534. END;
  1535. temp4 := registerOperands[index];
  1536. emitter.Emit2(InstructionSet.opMOV, dest, temp4);
  1537. END
  1538. ELSE
  1539. emitter.Emit1(InstructionSet.opFLD,src); INC(fpStackPointer);
  1540. MakeOperand(vdest,Low,dest,NIL);
  1541. IF destType.sizeInBits = IntermediateCode.Bits64 THEN AllocateStack(12) ELSE AllocateStack(8) END;
  1542. Assembler.InitMem(espm,IntermediateCode.Bits16 DIV 8,SP,0);
  1543. emitter.Emit1(InstructionSet.opFNSTCW,espm);
  1544. emitter.Emit0(InstructionSet.opFWAIT);
  1545. Assembler.InitMem(espm,IntermediateCode.Bits32 DIV 8,SP,0);
  1546. ticket := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32);
  1547. TicketToOperand(ticket,temp);
  1548. emitter.Emit2(InstructionSet.opMOV,temp,espm);
  1549. imm := Assembler.NewImm32(0F3FFH);
  1550. emitter.Emit2(InstructionSet.opAND,temp,imm);
  1551. imm := Assembler.NewImm32(0400H);
  1552. emitter.Emit2(InstructionSet.opOR,temp,imm);
  1553. Assembler.InitMem(espm,IntermediateCode.Bits32 DIV 8,SP,4);
  1554. emitter.Emit2(InstructionSet.opMOV,espm,temp);
  1555. Assembler.InitMem(espm,IntermediateCode.Bits16 DIV 8,SP,4);
  1556. emitter.Emit1(InstructionSet.opFLDCW,espm);
  1557. IF destType.sizeInBits = IntermediateCode.Bits64 THEN
  1558. Assembler.InitMem(espm,IntermediateCode.Bits64 DIV 8,SP,4);
  1559. emitter.Emit1(InstructionSet.opFISTP,espm);DEC(fpStackPointer);
  1560. emitter.Emit0(InstructionSet.opFWAIT);
  1561. ELSE
  1562. Assembler.InitMem(espm,IntermediateCode.Bits32 DIV 8,SP,4);
  1563. emitter.Emit1(InstructionSet.opFISTP,espm); DEC(fpStackPointer);
  1564. emitter.Emit0(InstructionSet.opFWAIT);
  1565. END;
  1566. Assembler.InitMem(espm,IntermediateCode.Bits16 DIV 8,SP,0);
  1567. emitter.Emit1(InstructionSet.opFLDCW,espm);
  1568. emitter.Emit1(InstructionSet.opPOP,temp);
  1569. UnmapTicket(ticket);
  1570. emitter.Emit1(InstructionSet.opPOP,dest);
  1571. IF IsComplex(vdest) THEN
  1572. MakeOperand(vdest,High,dest,NIL);
  1573. emitter.Emit1(InstructionSet.opPOP,dest);
  1574. END;
  1575. END;
  1576. END;
  1577. END EmitConvertFloat;
  1578. PROCEDURE EmitConvert(CONST vdest, vsrc: IntermediateCode.Operand; part: LONGINT);
  1579. VAR destType, srcType: IntermediateCode.Type; op1,op2: Assembler.Operand; index: LONGINT; nul: Assembler.Operand;
  1580. ticket: Ticket; vop: IntermediateCode.Operand; ediReserved, esiReserved: BOOLEAN;
  1581. eax, edx: Ticket; symbol: ObjectFile.Identifier; offset: LONGINT;
  1582. BEGIN
  1583. GetPartType(vdest.type,part, destType);
  1584. GetPartType(vsrc.type,part,srcType);
  1585. ASSERT(vdest.type.form IN IntermediateCode.Integer);
  1586. ASSERT(destType.form IN IntermediateCode.Integer);
  1587. IF destType.sizeInBits < srcType.sizeInBits THEN (* SHORT *)
  1588. ASSERT(part # High);
  1589. MakeOperand(vdest,part,op1,NIL);
  1590. IF vsrc.mode = IntermediateCode.ModeImmediate THEN
  1591. vop := vsrc;
  1592. IntermediateCode.SetType(vop,destType);
  1593. MakeOperand(vop,part,op2,NIL);
  1594. ELSE
  1595. MakeOperand(vsrc,part,op2,NIL);
  1596. IF Assembler.IsRegisterOperand(op1) & ((op1.register DIV 32 >0) (* not 8 bit register *) OR (op1.register DIV 16 = 0) & (physicalRegisters.Mapped(op1.register MOD 16 + AH)=free) (* low 8 bit register with free upper part *)) THEN
  1597. (* try EAX <- EDI for dest = AL or AX, src=EDI *)
  1598. index := op1.register;
  1599. CASE srcType.sizeInBits OF
  1600. IntermediateCode.Bits16: index := index MOD 32 + AX;
  1601. |IntermediateCode.Bits32: index := index MOD 32 + EAX;
  1602. |IntermediateCode.Bits64: index := index MOD 32 + RAX;
  1603. END;
  1604. op1 := registerOperands[index];
  1605. ELSE
  1606. (* reserve register with a low part *)
  1607. IF destType.sizeInBits=8 THEN (* make sure that allocated temporary register has a low part with 8 bits, i.e. exclude ESI or EDI *)
  1608. ediReserved := physicalRegisters.Reserved(EDI);
  1609. esiReserved := physicalRegisters.Reserved(ESI);
  1610. physicalRegisters.SetReserved(EDI,TRUE); physicalRegisters.SetReserved(ESI,TRUE);
  1611. ticket := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,srcType); (* register with low part *)
  1612. physicalRegisters.SetReserved(EDI,ediReserved); physicalRegisters.SetReserved(ESI,esiReserved);
  1613. ELSE
  1614. ticket := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,srcType); (* any register with low part *)
  1615. END;
  1616. MakeOperand(vsrc,part,op2,ticket); (* stores op2 in ticket register *)
  1617. index := op2.register;
  1618. CASE destType.sizeInBits OF (* choose low part accordingly *)
  1619. IntermediateCode.Bits8: index := index MOD 32 + AL;
  1620. |IntermediateCode.Bits16: index := index MOD 32 + AX;
  1621. |IntermediateCode.Bits32: index := index MOD 32 + EAX;
  1622. END;
  1623. op2 := registerOperands[index];
  1624. END;
  1625. Move(op1,op2,PhysicalOperandType(op1));
  1626. END;
  1627. ELSIF destType.sizeInBits > srcType.sizeInBits THEN (* (implicit) LONG *)
  1628. IF part = High THEN
  1629. IF destType.form = IntermediateCode.SignedInteger THEN
  1630. Spill(physicalRegisters.Mapped(EAX));
  1631. eax := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32,EAX,inPC);
  1632. Spill(physicalRegisters.Mapped(EDX));
  1633. edx := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32,EDX,inPC);
  1634. IF vsrc.type.sizeInBits < 32 THEN
  1635. MakeOperand(vsrc,Low,op2,NIL);
  1636. SpecialMove(InstructionSet.opMOVSX,InstructionSet.opMOV, FALSE, opEAX,op2,PhysicalOperandType(opEAX));
  1637. ELSE
  1638. MakeOperand(vsrc,Low,op2,eax);
  1639. END;
  1640. emitter.Emit0(InstructionSet.opCDQ);
  1641. MakeOperand(vdest,High,op1,NIL);
  1642. emitter.Emit2(InstructionSet.opMOV,op1,opEDX);
  1643. UnmapTicket(eax); UnmapTicket(edx);
  1644. ELSE
  1645. MakeOperand(vdest,part,op1,NIL);
  1646. IF (vdest.mode = IntermediateCode.ModeRegister) THEN
  1647. emitter.Emit2(InstructionSet.opXOR,op1,op1)
  1648. ELSE
  1649. Assembler.InitImm(nul,0,0);
  1650. emitter.Emit2(InstructionSet.opMOV,op1,nul);
  1651. END;
  1652. END;
  1653. ELSE
  1654. ASSERT(part=Low);
  1655. MakeOperand(vdest,part,op1,NIL);
  1656. MakeOperand(vsrc,part,op2,NIL);
  1657. IF srcType.sizeInBits = destType.sizeInBits THEN
  1658. Move(op1,op2,PhysicalOperandType(op1));
  1659. ELSIF srcType.form = IntermediateCode.SignedInteger THEN
  1660. IF srcType.sizeInBits=32 THEN (* 64 bits only *)
  1661. ASSERT(cpuBits=64);
  1662. SpecialMove(InstructionSet.opMOVSXD,InstructionSet.opMOV, FALSE, op1,op2,PhysicalOperandType(op1));
  1663. ELSE
  1664. SpecialMove(InstructionSet.opMOVSX,InstructionSet.opMOV, FALSE, op1,op2,PhysicalOperandType(op1));
  1665. END;
  1666. ELSE
  1667. ASSERT(srcType.form = IntermediateCode.UnsignedInteger);
  1668. IF srcType.sizeInBits=32 THEN (* 64 bits only *)
  1669. ASSERT(cpuBits=64);
  1670. IF Assembler.IsRegisterOperand(op1) THEN
  1671. Move( registerOperands[op1.register MOD 32 + EAX], op2,srcType);
  1672. ELSE
  1673. ASSERT(Assembler.IsMemoryOperand(op1));
  1674. symbol := op1.symbol; offset := op1.offset;
  1675. Assembler.InitMem(op1,Assembler.bits32,op1.register, op1.displacement);
  1676. Assembler.SetSymbol(op1,symbol.name,symbol.fingerprint,offset,op1.displacement);
  1677. Move( op1, op2, srcType);
  1678. Assembler.InitMem(op1,Assembler.bits32,op1.register, op1.displacement+Assembler.bits32);
  1679. Assembler.SetSymbol(op1,symbol.name, symbol.fingerprint,offset,op1.displacement);
  1680. Assembler.InitImm(op2,0,0);
  1681. Move( op1, op2,srcType);
  1682. END;
  1683. ELSE
  1684. SpecialMove(InstructionSet.opMOVZX, InstructionSet.opMOV, FALSE, op1, op2,PhysicalOperandType(op1))
  1685. END;
  1686. END;
  1687. END;
  1688. ELSE (* destType.sizeInBits = srcType.sizeInBits) *)
  1689. EmitMov(vdest,vsrc,part);
  1690. END;
  1691. END EmitConvert;
  1692. PROCEDURE EmitResult(CONST instruction: IntermediateCode.Instruction; part: LONGINT);
  1693. VAR result,op: Assembler.Operand; register, highRegister: LONGINT; highReserved: BOOLEAN; type: IntermediateCode.Type;
  1694. BEGIN
  1695. register := ResultRegister(instruction.op1.type,part);
  1696. IF (part = Low) & IsComplex(instruction.op1) THEN
  1697. (* protect upper result (EDX) register *)
  1698. highRegister := ResultRegister(instruction.op1.type, High);
  1699. highReserved := physicalRegisters.Reserved(highRegister);
  1700. physicalRegisters.SetReserved(highRegister,TRUE);
  1701. END;
  1702. result := registerOperands[register];
  1703. MakeOperand(instruction.op1,part,op,NIL);
  1704. GetPartType(instruction.op1.type, part, type);
  1705. Move(op,result,type);
  1706. IF (part = Low) & IsComplex(instruction.op1) THEN
  1707. physicalRegisters.SetReserved(highRegister, highReserved);
  1708. END
  1709. END EmitResult;
  1710. PROCEDURE EmitResultFPU(CONST instruction: IntermediateCode.Instruction);
  1711. VAR op: Assembler.Operand;
  1712. BEGIN
  1713. INC(fpStackPointer); (* callee has left the result on top of stack, don't have to allocate here *)
  1714. MakeOperand(instruction.op1,Low,op,NIL);
  1715. emitter.Emit1(InstructionSet.opFSTP,op);
  1716. DEC(fpStackPointer);
  1717. (*
  1718. UnmapTicket(ticket);
  1719. *)
  1720. END EmitResultFPU;
  1721. PROCEDURE EmitCall(CONST instruction: IntermediateCode.Instruction);
  1722. VAR fixup: Sections.Section; target, op, parSize: Assembler.Operand;
  1723. code: SyntaxTree.Code; emitterFixup,newFixup: BinaryCode.Fixup; resolved: BinaryCode.Section; pc: LONGINT;
  1724. BEGIN
  1725. IF fpStackPointer # 0 THEN Error(instruction.textPosition,"compiler implementation error: fp stack not cleared before call") END;
  1726. IF instruction.op1.mode = IntermediateCode.ModeImmediate THEN
  1727. fixup := module.allSections.FindByName(instruction.op1.symbol.name);
  1728. IF (fixup # NIL) & (fixup.type = Sections.InlineCodeSection) THEN
  1729. pc := out.pc;
  1730. (* resolved must be available at this point ! *)
  1731. resolved := fixup(IntermediateCode.Section).resolved;
  1732. IF resolved # NIL THEN
  1733. emitter.code.CopyBits(resolved.os.bits,0,resolved.os.bits.GetSize());
  1734. emitterFixup := resolved.fixupList.firstFixup;
  1735. WHILE (emitterFixup # NIL) DO
  1736. newFixup := BinaryCode.NewFixup(emitterFixup.mode,emitterFixup.offset+pc,emitterFixup.symbol,emitterFixup.symbolOffset,emitterFixup.displacement,emitterFixup.scale,emitterFixup.pattern);
  1737. out.fixupList.AddFixup(newFixup);
  1738. emitterFixup := emitterFixup.nextFixup;
  1739. END;
  1740. END;
  1741. ELSE
  1742. Assembler.InitOffset32(target,instruction.op1.intValue);
  1743. Assembler.SetSymbol(target,instruction.op1.symbol.name,instruction.op1.symbol.fingerprint,instruction.op1.offset,0);
  1744. emitter.Emit1(InstructionSet.opCALL,target);
  1745. Assembler.InitOffset32(parSize,instruction.op2.intValue);
  1746. IF parSize.val # 0 THEN emitter.Emit2(InstructionSet.opADD,opSP,parSize) END;
  1747. END;
  1748. ELSE
  1749. MakeOperand(instruction.op1,Low,op,NIL);
  1750. emitter.Emit1(InstructionSet.opCALL,op);
  1751. Assembler.InitOffset32(parSize,instruction.op2.intValue);
  1752. IF parSize.val # 0 THEN emitter.Emit2(InstructionSet.opADD,opSP,parSize) END;
  1753. END;
  1754. END EmitCall;
  1755. (*
  1756. register allocation
  1757. instruction dest, src1, src2
  1758. preconditions
  1759. dest is memory operand or dest is register with offset = 0
  1760. src1 and src2 may be immediates, registers with or without offset and memory operands
  1761. 1.) translation into two-operand code
  1762. a) dest = src1 (no assumption on src2, src2=src1 is permitted )
  1763. i) dest and src2 are both memory operands or src2 is a register with offset # 0
  1764. alloc temp register
  1765. mov temp, src2
  1766. instruction2 dest, temp
  1767. ii) dest or src2 is not a memory operand
  1768. instruction2 dest, src2
  1769. b) dest = src2
  1770. => src2 is not a register with offset # 0
  1771. alloc temp register
  1772. mov dest, src1
  1773. mov temp, src2
  1774. instruction2 dest, temp
  1775. c) dest # src2
  1776. mov dest, src1
  1777. i) dest and src2 are both memory operands or src2 is a register with offset # 0
  1778. allocate temp register
  1779. mov temp, src2
  1780. instruction2 dest, temp
  1781. ii)
  1782. instruction2 dest, src2
  1783. 1'.) translation into one operand code
  1784. instruction dest, src1
  1785. a) dest = src1
  1786. => src1 is not a register with offset # 0
  1787. instruction1 dest
  1788. b) dest # src1
  1789. mov dest, src1
  1790. instruction1 dest
  1791. 2.) register allocation
  1792. precondition: src1 and src2 are already allocated
  1793. a) dest is already allocated
  1794. go on according to 1.
  1795. b) dest needs to be allocated
  1796. check if register is free
  1797. i) yes: allocate free register and go on with 1.
  1798. ii) no: spill last register in livelist, map register and go on with 1.
  1799. *)
  1800. PROCEDURE PrepareOp3(CONST instruction: IntermediateCode.Instruction;part: LONGINT; VAR left, right: Assembler.Operand; VAR ticket: Ticket);
  1801. VAR vop1,vop2, vop3: IntermediateCode.Operand; op1,op2,op3,temp: Assembler.Operand; type: IntermediateCode.Type;
  1802. t: Ticket;
  1803. BEGIN
  1804. ticket := NIL;
  1805. GetPartType(instruction.op1.type,part,type);
  1806. vop1 := instruction.op1; vop2 := instruction.op2; vop3 := instruction.op3;
  1807. IF IntermediateCode.OperandEquals(vop1,vop3) & (IntermediateCode.Commute23 IN IntermediateCode.instructionFormat[instruction.opcode].flags) THEN
  1808. vop3 := instruction.op2; vop2 := instruction.op3;
  1809. END;
  1810. MakeOperand(vop3,part, op3,NIL);
  1811. IF (vop1.mode = IntermediateCode.ModeRegister) & (~IsMemoryOperand(vop1,part)) & (vop1.register # vop3.register) THEN
  1812. IF (vop2.mode = IntermediateCode.ModeRegister) & (vop2.register = vop1.register) & (vop2.offset = 0) THEN
  1813. (* same register *)
  1814. MakeOperand(vop1,part, op1,NIL);
  1815. ELSE
  1816. MakeOperand(vop2,part, op2,NIL);
  1817. (*
  1818. ReleaseHint(op2.register);
  1819. *)
  1820. MakeOperand(vop1,part, op1,NIL);
  1821. Move(op1, op2, type);
  1822. t := virtualRegisters.Mapped(vop1.register,part);
  1823. IF (t # NIL) & (t.spilled) THEN
  1824. UnSpill(t); (* make sure this has not spilled *)
  1825. MakeOperand(vop1,part, op1,NIL);
  1826. END;
  1827. END;
  1828. left := op1; right := op3;
  1829. ELSIF IntermediateCode.OperandEquals(vop1,vop2) & (~IsMemoryOperand(vop1,part) OR ~IsMemoryOperand(vop3,part)) THEN
  1830. MakeOperand(vop1,part, op1,NIL);
  1831. left := op1; right := op3;
  1832. ELSE
  1833. MakeOperand(vop1,part, op1,NIL);
  1834. MakeOperand(vop2,part, op2,NIL);
  1835. (*ReleaseHint(op2.register);*)
  1836. ticket := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,type);
  1837. TicketToOperand(ticket,temp);
  1838. Move(temp, op2, type);
  1839. left := temp; right := op3;
  1840. END;
  1841. END PrepareOp3;
  1842. PROCEDURE PrepareOp2(CONST instruction: IntermediateCode.Instruction; part: LONGINT; VAR left: Assembler.Operand;VAR ticket: Ticket);
  1843. VAR op2: Assembler.Operand; imm: Assembler.Operand; sizeInBits: INTEGER; type: IntermediateCode.Type;
  1844. BEGIN
  1845. ticket := NIL;
  1846. GetPartType(instruction.op1.type,part,type);
  1847. IF (instruction.op1.mode = IntermediateCode.ModeRegister) THEN
  1848. MakeOperand(instruction.op1,part,left,NIL);
  1849. MakeOperand(instruction.op2,part,op2,NIL);
  1850. IF (instruction.op2.mode = IntermediateCode.ModeRegister) & (instruction.op2.register = instruction.op1.register) & (instruction.op2.offset = 0) THEN
  1851. ELSE
  1852. Move(left, op2, type);
  1853. IF (instruction.op2.offset # 0) & ~IsMemoryOperand(instruction.op2,part) THEN
  1854. GetPartType(instruction.op2.type,part,type);
  1855. sizeInBits := type.sizeInBits;
  1856. Assembler.InitImm(imm,0,instruction.op2.offset);
  1857. emitter.Emit2(InstructionSet.opADD,left,imm);
  1858. END;
  1859. END;
  1860. ELSIF IntermediateCode.OperandEquals(instruction.op1,instruction.op2) & ((instruction.op1.mode # IntermediateCode.ModeMemory) OR (instruction.op3.mode # IntermediateCode.ModeMemory)) THEN
  1861. MakeOperand(instruction.op1,part,left,NIL);
  1862. ELSE
  1863. MakeOperand(instruction.op2,part, op2,NIL);
  1864. ticket := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,type);
  1865. TicketToOperand(ticket,left);
  1866. Move(left, op2, type);
  1867. END;
  1868. END PrepareOp2;
  1869. PROCEDURE FinishOp(CONST vop: IntermediateCode.Operand; part: LONGINT; left: Assembler.Operand; ticket: Ticket);
  1870. VAR op1: Assembler.Operand;
  1871. BEGIN
  1872. IF ticket # NIL THEN
  1873. MakeOperand(vop,part, op1,NIL);
  1874. Move(op1,left,vop.type);
  1875. UnmapTicket(ticket);
  1876. END;
  1877. END FinishOp;
  1878. PROCEDURE EmitArithmetic3(CONST instruction: IntermediateCode.Instruction; part: LONGINT; opcode: LONGINT);
  1879. VAR left,right: Assembler.Operand; ticket: Ticket;
  1880. BEGIN
  1881. PrepareOp3(instruction, part, left,right,ticket);
  1882. emitter.Emit2(opcode,left,right);
  1883. FinishOp(instruction.op1,part,left,ticket);
  1884. END EmitArithmetic3;
  1885. PROCEDURE EmitArithmetic3XMM(CONST instruction: IntermediateCode.Instruction; op32, op64: LONGINT);
  1886. VAR op: LONGINT;
  1887. BEGIN
  1888. IF instruction.op1.type.sizeInBits = 32 THEN op := op32 ELSE op := op64 END;
  1889. EmitArithmetic3(instruction, Low, op);
  1890. END EmitArithmetic3XMM;
  1891. PROCEDURE EmitArithmetic2(CONST instruction: IntermediateCode.Instruction; part: LONGINT; opcode: LONGINT);
  1892. VAR left:Assembler.Operand;ticket: Ticket;
  1893. BEGIN
  1894. PrepareOp2(instruction,part,left,ticket);
  1895. emitter.Emit1(opcode,left);
  1896. FinishOp(instruction.op1,part,left,ticket);
  1897. END EmitArithmetic2;
  1898. PROCEDURE EmitArithmetic2XMM(CONST instruction: IntermediateCode.Instruction; op32, op64: LONGINT);
  1899. VAR op: LONGINT;
  1900. BEGIN
  1901. IF instruction.op1.type.sizeInBits = 32 THEN op := op32 ELSE op := op64 END;
  1902. EmitArithmetic2(instruction, Low, op);
  1903. END EmitArithmetic2XMM;
  1904. PROCEDURE EmitArithmetic3FPU(CONST instruction: IntermediateCode.Instruction; op: LONGINT);
  1905. VAR op1,op2,op3: Assembler.Operand;
  1906. BEGIN
  1907. MakeOperand(instruction.op2,Low,op2,NIL);
  1908. emitter.Emit1(InstructionSet.opFLD,op2);
  1909. INC(fpStackPointer);
  1910. MakeOperand(instruction.op3,Low,op3,NIL);
  1911. IF instruction.op3.mode = IntermediateCode.ModeRegister THEN
  1912. emitter.Emit2(op,opST0,op3);
  1913. ELSE
  1914. emitter.Emit1(op,op3);
  1915. END;
  1916. MakeOperand(instruction.op1,Low,op1,NIL);
  1917. emitter.Emit1(InstructionSet.opFSTP,op1);
  1918. DEC(fpStackPointer);
  1919. END EmitArithmetic3FPU;
  1920. PROCEDURE EmitArithmetic2FPU(CONST instruction: IntermediateCode.Instruction; opcode: LONGINT);
  1921. VAR op1,op2: Assembler.Operand;
  1922. BEGIN
  1923. MakeOperand(instruction.op2,Low,op2,NIL);
  1924. emitter.Emit1(InstructionSet.opFLD,op2);
  1925. INC(fpStackPointer);
  1926. emitter.Emit0(opcode);
  1927. MakeOperand(instruction.op1,Low,op1,NIL);
  1928. emitter.Emit1(InstructionSet.opFSTP,op1);
  1929. DEC(fpStackPointer);
  1930. END EmitArithmetic2FPU;
  1931. PROCEDURE EmitMul(CONST instruction: IntermediateCode.Instruction);
  1932. VAR op1,op2,op3,temp: Assembler.Operand; ra,rd: Ticket;
  1933. BEGIN
  1934. ASSERT(~IsComplex(instruction.op1));
  1935. ASSERT(instruction.op1.type.form IN IntermediateCode.Integer);
  1936. IF (instruction.op1.type.sizeInBits = IntermediateCode.Bits8) THEN
  1937. Spill(physicalRegisters.Mapped(AL));
  1938. Spill(physicalRegisters.Mapped(AH));
  1939. ra := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int8,AL,inPC);
  1940. rd := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int8,AH,inPC);
  1941. MakeOperand(instruction.op1,Low,op1,NIL);
  1942. MakeOperand(instruction.op2,Low,op2,ra);
  1943. IF instruction.op3.mode = IntermediateCode.ModeImmediate THEN
  1944. MakeOperand(instruction.op3,Low,op3,rd);
  1945. ELSE
  1946. MakeOperand(instruction.op3,Low,op3,NIL);
  1947. END;
  1948. emitter.Emit1(InstructionSet.opIMUL,op3);
  1949. emitter.Emit2(InstructionSet.opMOV,op1,opAL);
  1950. UnmapTicket(ra);
  1951. UnmapTicket(rd);
  1952. ELSE
  1953. MakeOperand(instruction.op1,Low,op1,NIL);
  1954. MakeOperand(instruction.op2,Low,op2,NIL);
  1955. MakeOperand(instruction.op3,Low,op3,NIL);
  1956. IF ~Assembler.IsRegisterOperand(op1) THEN
  1957. temp := op1;
  1958. ra := TemporaryTicket(instruction.op1.registerClass,instruction.op1.type);
  1959. TicketToOperand(ra,op1);
  1960. END;
  1961. IF Assembler.SameOperand(op1,op3) THEN temp := op2; op2 := op3; op3 := temp END;
  1962. IF Assembler.IsRegisterOperand(op2) OR Assembler.IsMemoryOperand(op2) THEN
  1963. IF Assembler.IsImmediateOperand(op3) THEN
  1964. emitter.Emit3(InstructionSet.opIMUL,op1,op2,op3);
  1965. ELSIF Assembler.IsRegisterOperand(op2) & (op2.register = op1.register) THEN
  1966. IF Assembler.IsRegisterOperand(op3) OR Assembler.IsMemoryOperand(op3) THEN
  1967. emitter.Emit2(InstructionSet.opIMUL,op1,op3);
  1968. ELSE
  1969. rd := TemporaryTicket(instruction.op1.registerClass,instruction.op1.type);
  1970. TicketToOperand(rd,temp);
  1971. Move(temp,op3,instruction.op1.type);
  1972. emitter.Emit2(InstructionSet.opIMUL,op1,temp);
  1973. UnmapTicket(rd);
  1974. END;
  1975. ELSE
  1976. Move(op1,op3,PhysicalOperandType(op1));
  1977. emitter.Emit2(InstructionSet.opIMUL,op1,op2);
  1978. END
  1979. ELSIF Assembler.IsRegisterOperand(op3) OR Assembler.IsMemoryOperand(op3) THEN
  1980. IF Assembler.IsImmediateOperand(op2) THEN
  1981. emitter.Emit3(InstructionSet.opIMUL,op1,op3,op2);
  1982. ELSIF Assembler.IsRegisterOperand(op3) & (op2.register = op1.register) THEN
  1983. IF Assembler.IsRegisterOperand(op2) OR Assembler.IsMemoryOperand(op2) THEN
  1984. emitter.Emit2(InstructionSet.opIMUL,op1,op2);
  1985. ELSE
  1986. rd := TemporaryTicket(instruction.op1.registerClass,instruction.op1.type);
  1987. TicketToOperand(rd,temp);
  1988. Move(temp,op2,instruction.op1.type);
  1989. emitter.Emit2(InstructionSet.opIMUL,op1,temp);
  1990. UnmapTicket(rd);
  1991. END;
  1992. ELSE
  1993. Move(op1,op2,PhysicalOperandType(op1));
  1994. emitter.Emit2(InstructionSet.opIMUL,op1,op3);
  1995. END;
  1996. END;
  1997. IF ra # NIL THEN
  1998. Move(temp,op1,PhysicalOperandType(op1));
  1999. UnmapTicket(ra);
  2000. END;
  2001. END;
  2002. END EmitMul;
  2003. PROCEDURE EmitDivMod(CONST instruction: IntermediateCode.Instruction);
  2004. VAR
  2005. dividend,quotient,remainder,imm,target,memop: Assembler.Operand;
  2006. op1,op2,op3: Assembler.Operand; ra,rd: Ticket;
  2007. size: LONGINT;
  2008. BEGIN
  2009. (*
  2010. In general it must obviously hold that
  2011. a = (a div b) * b + a mod b and
  2012. for all integers a,b#0, and c.
  2013. For positive numbers a and b this holds if
  2014. a div b = max{integer i: i*b <= b} = Entier(a/b)
  2015. and
  2016. a mod b = a-(a div b)*b = min{c >=0: c = a-i*b, integer i}
  2017. Example
  2018. 11 div 3 = 3 (3*3 = 9)
  2019. 11 mod 3 = 2 (=11-9)
  2020. for negative a there are two definitions for mod possible:
  2021. (i) mathematical definition with
  2022. a mod b >= 0:
  2023. a mod b = min{ c >=0: c = a-i*b, integer i} >= 0
  2024. this corresponds with rounding down
  2025. a div b = Entier(a/b) <= a/b
  2026. (ii) symmetric definition with
  2027. (-a) mod' b = -(a mod' b) and
  2028. (-a) div' b = -(a div' b)
  2029. corresponding with rounding to zero
  2030. a div' b = RoundToZero(a/b)
  2031. Examples
  2032. (i) -11 div 3 = -4 (3*(-4) = -12)
  2033. -11 mod 3 = 1 (=-11-(-12))
  2034. (ii) -11 div' 3 = -(11 div 3) = -3 (3*(-3)= -9)
  2035. -11 mod' 3 = -2 (=-11-(-9))
  2036. The behaviour for negative b can, in the symmetrical case, be deduced as
  2037. (ii) symmetric definition
  2038. a div' (-b) = (-a) div' b = -(a div' b)
  2039. a mod' (-b) = a- a div' (-b) * (-b) = a mod' b
  2040. In the mathematical case it is not so easy. It turns out that the definitions
  2041. a DIV b = Entier(a/b) = max{integer i: i*b <= b}
  2042. and
  2043. a MOD b = min { c >=0 : c = a-i*b, integer i} >= 0
  2044. are not compliant with
  2045. a = (a DIV b) * b + a MOD b
  2046. if b <= 0.
  2047. Proof: assume that b<0, then
  2048. a - Entier(a/b) * b >= 0
  2049. <=_> a >= Entier(a/b) * b
  2050. <=> Entier(a/b) >= a/b (contradiction to definition of Entier).
  2051. OBERON ADOPTS THE MATHEMATICAL DEFINITION !
  2052. For integers a and b (b>0) it holds that
  2053. a DIV b = Entier(a/b) <= a/b
  2054. a MOD b = min{ c >=0: c = b-i*a, integer i} = a - a DIV b * b
  2055. The behaviour for b < 0 is explicitely undefined.
  2056. *)
  2057. (*
  2058. AX / regMem8 = AL (remainder AH)
  2059. DX:AX / regmem16 = AX (remainder DX)
  2060. EDX:EAX / regmem32 = EAX (remainder EDX)
  2061. RDX:EAX / regmem64 = RAX (remainder RDX)
  2062. 1.) EAX <- source1
  2063. 2.) CDQ
  2064. 3.) IDIV source2
  2065. 3.) SHL EDX
  2066. 4.) SBB EAX,1
  2067. result is in EAX
  2068. *)
  2069. MakeOperand(instruction.op2,Low,op2,NIL);
  2070. CASE instruction.op1.type.sizeInBits OF
  2071. IntermediateCode.Bits8:
  2072. Spill(physicalRegisters.Mapped(AL)); ra := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int8,AL,inPC);
  2073. emitter.Emit2(InstructionSet.opMOV,opAL,op2);
  2074. dividend := opAX;
  2075. quotient := opAL;
  2076. remainder := opAH;
  2077. emitter.Emit0(InstructionSet.opCBW);
  2078. | IntermediateCode.Bits16:
  2079. Spill(physicalRegisters.Mapped(AX)); ra := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int16,AX,inPC);
  2080. emitter.Emit2(InstructionSet.opMOV,opAX,op2);
  2081. Spill(physicalRegisters.Mapped(DX)); rd := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int16,DX,inPC);
  2082. dividend := opAX;
  2083. quotient := dividend;
  2084. remainder := opDX;
  2085. emitter.Emit0(InstructionSet.opCWD);
  2086. | IntermediateCode.Bits32:
  2087. Spill(physicalRegisters.Mapped(EAX)); ra := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32,EAX,inPC);
  2088. emitter.Emit2(InstructionSet.opMOV,opEAX,op2);
  2089. Spill(physicalRegisters.Mapped(EDX)); rd := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32,EDX,inPC);
  2090. dividend := opEAX;
  2091. quotient := dividend;
  2092. remainder := opEDX;
  2093. emitter.Emit0(InstructionSet.opCDQ);
  2094. | IntermediateCode.Bits64:
  2095. Spill(physicalRegisters.Mapped(RAX)); ra := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int64,RAX,inPC);
  2096. emitter.Emit2(InstructionSet.opMOV,opRA,op2);
  2097. Spill(physicalRegisters.Mapped(RDX)); rd := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int64,RDX,inPC);
  2098. dividend := opRA;
  2099. quotient := dividend;
  2100. remainder := registerOperands[RDX];
  2101. emitter.Emit0(InstructionSet.opCQO);
  2102. END;
  2103. (* registers might have been changed, so we make the operands now *)
  2104. MakeOperand(instruction.op1,Low,op1,NIL);
  2105. MakeOperand(instruction.op2,Low,op2,NIL);
  2106. MakeOperand(instruction.op3,Low,op3,NIL);
  2107. IF instruction.op3.mode = IntermediateCode.ModeImmediate THEN
  2108. size := instruction.op3.type.sizeInBits DIV 8;
  2109. Basic.Align(size, 4 (* cpuBits DIV 8 *) );
  2110. AllocateStack(size);
  2111. Assembler.InitMem(memop,SHORT(instruction.op3.type.sizeInBits DIV 8),SP,0);
  2112. emitter.Emit2(InstructionSet.opMOV,memop,op3);
  2113. op3 := memop;
  2114. END;
  2115. emitter.Emit1(InstructionSet.opIDIV,op3);
  2116. IF instruction.opcode = IntermediateCode.mod THEN
  2117. imm := Assembler.NewImm8 (0);
  2118. emitter.Emit2(InstructionSet.opCMP, remainder, imm);
  2119. Assembler.InitImm8(target,0);
  2120. emitter.Emit1(InstructionSet.opJGE, target);
  2121. emitter.Emit2( InstructionSet.opADD, remainder, op3);
  2122. emitter.code.PutByteAt(target.pc,(emitter.code.pc -target.pc )-1);
  2123. emitter.Emit2(InstructionSet.opMOV, op1, remainder);
  2124. ELSE
  2125. imm := Assembler.NewImm8 (1);
  2126. emitter.Emit2(InstructionSet.opSHL, remainder, imm);
  2127. imm := Assembler.NewImm8 (0);
  2128. emitter.Emit2(InstructionSet.opSBB, quotient, imm);
  2129. emitter.Emit2(InstructionSet.opMOV, op1, quotient);
  2130. END;
  2131. IF instruction.op3.mode = IntermediateCode.ModeImmediate THEN
  2132. size := instruction.op3.type.sizeInBits DIV 8;
  2133. Basic.Align(size, 4 (* cpuBits DIV 8*) );
  2134. AllocateStack(-size);
  2135. END;
  2136. END EmitDivMod;
  2137. PROCEDURE EmitShift(CONST instruction: IntermediateCode.Instruction);
  2138. VAR
  2139. shift: Assembler.Operand;
  2140. op: LONGINT;
  2141. op1,op2,op3,dest,temporary,op1High,op2High: Assembler.Operand;
  2142. index: SHORTINT; temp: Assembler.Operand;
  2143. left: BOOLEAN;
  2144. ecx,ticket: Ticket;
  2145. BEGIN
  2146. Assert(instruction.op1.type.form IN IntermediateCode.Integer,"must be integer operand");
  2147. IF instruction.op1.type.form = IntermediateCode.UnsignedInteger THEN
  2148. IF instruction.opcode = IntermediateCode.shr THEN op := InstructionSet.opSHR; left := FALSE;
  2149. ELSIF instruction.opcode = IntermediateCode.shl THEN op := InstructionSet.opSHL; left := TRUE;
  2150. ELSIF instruction.opcode = IntermediateCode.ror THEN op := InstructionSet.opROR; left := FALSE;
  2151. ELSIF instruction.opcode = IntermediateCode.rol THEN op := InstructionSet.opROL; left := TRUE;
  2152. END;
  2153. ELSE
  2154. IF instruction.opcode = IntermediateCode.shr THEN op := InstructionSet.opSAR; left := FALSE;
  2155. ELSIF instruction.opcode = IntermediateCode.shl THEN op := InstructionSet.opSAL; left := TRUE;
  2156. ELSIF instruction.opcode = IntermediateCode.ror THEN op := InstructionSet.opROR; left := FALSE;
  2157. ELSIF instruction.opcode = IntermediateCode.rol THEN op := InstructionSet.opROL; left := TRUE;
  2158. END;
  2159. END;
  2160. IF instruction.op3.mode # IntermediateCode.ModeImmediate THEN
  2161. IF backend.cooperative THEN ap.spillable := TRUE END;
  2162. Spill(physicalRegisters.Mapped(ECX));
  2163. ecx := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32,ECX,inPC);
  2164. END;
  2165. (*GetTemporaryRegister(instruction.op2.type,dest);*)
  2166. MakeOperand(instruction.op1,Low,op1,NIL);
  2167. IF ~Assembler.IsRegisterOperand(op1) THEN GetTemporaryRegister(instruction.op2.type,dest) ELSE dest := op1 END;
  2168. MakeOperand(instruction.op2,Low,op2,NIL);
  2169. MakeOperand(instruction.op3,Low,op3,NIL);
  2170. IF instruction.op3.mode = IntermediateCode.ModeImmediate THEN
  2171. Assembler.InitImm8(shift,instruction.op3.intValue);
  2172. ELSE
  2173. CASE instruction.op3.type.sizeInBits OF
  2174. IntermediateCode.Bits8: index := CL;
  2175. |IntermediateCode.Bits16: index := CX;
  2176. |IntermediateCode.Bits32: index := ECX;
  2177. |IntermediateCode.Bits64: index := RCX;
  2178. END;
  2179. (*
  2180. IF (physicalRegisters.toVirtual[index] # free) & ((physicalRegisters.toVirtual[index] # instruction.op1.register) OR (instruction.op1.mode # IntermediateCode.ModeRegister)) THEN
  2181. Spill();
  2182. (*
  2183. emitter.Emit1(InstructionSet.opPUSH,opECX);
  2184. ecxPushed := TRUE;
  2185. *)
  2186. END;
  2187. *)
  2188. ticket := virtualRegisters.Mapped(instruction.op3.register,Low);
  2189. IF (instruction.op3.mode # IntermediateCode.ModeRegister) OR (ticket = NIL) OR (ticket.spilled) OR (ticket.register # index) THEN
  2190. emitter.Emit2(InstructionSet.opMOV,registerOperands[index],op3);
  2191. END;
  2192. shift := opCL;
  2193. END;
  2194. IF ~IsComplex(instruction.op1) THEN
  2195. Move(dest,op2,PhysicalOperandType(dest));
  2196. emitter.Emit2 (op, dest,shift);
  2197. Move(op1,dest,PhysicalOperandType(op1));
  2198. ELSIF left THEN
  2199. MakeOperand(instruction.op1,High,op1High,NIL);
  2200. MakeOperand(instruction.op2,High,op2High,NIL);
  2201. IF ~IntermediateCode.OperandEquals(instruction.op1,instruction.op2) THEN
  2202. Move(op1,op2,PhysicalOperandType(op1));
  2203. Move(op1High,op2High,PhysicalOperandType(op1High))
  2204. END;
  2205. IF (instruction.opcode=IntermediateCode.rol) THEN
  2206. (* |high| <- |low| <- |temp=high| *)
  2207. ticket := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32);
  2208. TicketToOperand(ticket,temp);
  2209. emitter.Emit2( InstructionSet.opMOV, temp, op1High);
  2210. emitter.Emit3( InstructionSet.opSHLD,op1High, op1, shift);
  2211. emitter.Emit3( InstructionSet.opSHLD, op1, temp, shift);
  2212. UnmapTicket(ticket);
  2213. ELSE
  2214. (* |high| <- |low| *)
  2215. emitter.Emit3( InstructionSet.opSHLD, op1,op1High,shift);
  2216. emitter.Emit2( op, op1,shift);
  2217. END;
  2218. ELSE
  2219. IF ~IntermediateCode.OperandEquals(instruction.op1,instruction.op2) THEN
  2220. Move(op1,op2,PhysicalOperandType(op1))
  2221. END;
  2222. IF instruction.opcode=IntermediateCode.ror THEN
  2223. (* |temp=low| -> |high| -> |low| *)
  2224. ticket := TemporaryTicket(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32);
  2225. TicketToOperand(ticket,temp);
  2226. emitter.Emit2( InstructionSet.opMOV, temporary, op1);
  2227. emitter.Emit3( InstructionSet.opSHRD,op1, op1High, shift);
  2228. emitter.Emit3( InstructionSet.opSHRD, op1High, temporary, shift);
  2229. UnmapTicket(ticket);
  2230. ELSE
  2231. (* |high| -> |low| *)
  2232. emitter.Emit3( InstructionSet.opSHRD, op1,op1High,shift);
  2233. emitter.Emit2( op, op1High, shift);
  2234. END;
  2235. END;
  2236. IF backend.cooperative & (instruction.op3.mode # IntermediateCode.ModeImmediate) THEN
  2237. UnmapTicket(ecx);
  2238. UnSpill(ap);
  2239. ap.spillable := FALSE;
  2240. END;
  2241. END EmitShift;
  2242. PROCEDURE EmitCas(CONST instruction: IntermediateCode.Instruction);
  2243. VAR ra: Ticket; op1,op2,op3,mem: Assembler.Operand; register: LONGINT;
  2244. BEGIN
  2245. CASE instruction.op2.type.sizeInBits OF
  2246. | IntermediateCode.Bits8: register := AL;
  2247. | IntermediateCode.Bits16: register := AX;
  2248. | IntermediateCode.Bits32: register := EAX;
  2249. | IntermediateCode.Bits64: register := RAX;
  2250. END;
  2251. Spill(physicalRegisters.Mapped(register));
  2252. ra := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,instruction.op2.type,register,inPC);
  2253. IF IntermediateCode.OperandEquals (instruction.op2,instruction.op3) THEN
  2254. MakeOperand(instruction.op1,Low,op1,ra);
  2255. Assembler.InitMem(mem,SHORT(instruction.op1.type.sizeInBits DIV 8),op1.register,0);
  2256. emitter.Emit2(InstructionSet.opMOV,op1,mem);
  2257. ELSE
  2258. MakeOperand(instruction.op2,Low,op2,ra);
  2259. MakeRegister(instruction.op1,Low,op1);
  2260. Assembler.InitMem(mem,SHORT(instruction.op2.type.sizeInBits DIV 8),op1.register,0);
  2261. MakeRegister(instruction.op3,Low,op3);
  2262. emitter.EmitPrefix (InstructionSet.prfLOCK);
  2263. emitter.Emit2(InstructionSet.opCMPXCHG,mem,op3);
  2264. END;
  2265. END EmitCas;
  2266. PROCEDURE EmitCopy(CONST instruction: IntermediateCode.Instruction);
  2267. VAR op1,op2,op3: Assembler.Operand; esi, edi, ecx, t: Ticket; temp,imm: Assembler.Operand; source, dest: IntermediateCode.Operand; size: HUGEINT;
  2268. BEGIN
  2269. IF IntermediateCode.IsConstantInteger(instruction.op3, size) & (size = 4) THEN
  2270. Spill(physicalRegisters.Mapped(ESI));
  2271. Spill(physicalRegisters.Mapped(EDI));
  2272. esi := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32,RS,inPC);
  2273. edi := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32,RD,inPC);
  2274. MakeOperand(instruction.op1,Low,op1,edi);
  2275. MakeOperand(instruction.op2,Low,op2,esi);
  2276. emitter.Emit0(InstructionSet.opMOVSD);
  2277. UnmapTicket(esi);
  2278. UnmapTicket(edi);
  2279. ELSE
  2280. Spill(physicalRegisters.Mapped(ESI));
  2281. Spill(physicalRegisters.Mapped(EDI));
  2282. IF backend.cooperative THEN ap.spillable := TRUE END;
  2283. Spill(physicalRegisters.Mapped(ECX));
  2284. esi := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32,RS,inPC);
  2285. edi := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32,RD,inPC);
  2286. ecx := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32,RC,inPC);
  2287. MakeOperand(instruction.op1,Low,op1,edi);
  2288. MakeOperand(instruction.op2,Low,op2,esi);
  2289. IF (instruction.op1.mode = IntermediateCode.ModeRegister) & (instruction.op1.register = IntermediateCode.SP) & IntermediateCode.IsConstantInteger(instruction.op3, size) & (size >= 4096) THEN
  2290. (* special case on stack: copy downwards for possible stack allocation *)
  2291. IF size MOD 4 # 0 THEN
  2292. imm := Assembler.NewImm32(size-1);
  2293. emitter.Emit2(InstructionSet.opADD, opEDI, imm);
  2294. emitter.Emit2(InstructionSet.opADD, opESI, imm);
  2295. imm := Assembler.NewImm32(size MOD 4);
  2296. emitter.Emit2(InstructionSet.opMOV, opECX, imm);
  2297. emitter.Emit0(InstructionSet.opSTD); (* copy down *)
  2298. emitter.EmitPrefix (InstructionSet.prfREP);
  2299. emitter.Emit0(InstructionSet.opMOVSB);
  2300. imm := Assembler.NewImm32(size DIV 4);
  2301. emitter.Emit2(InstructionSet.opMOV, opECX, imm);
  2302. emitter.EmitPrefix (InstructionSet.prfREP);
  2303. emitter.Emit0(InstructionSet.opMOVSD);
  2304. ELSE
  2305. imm := Assembler.NewImm32(size-4);
  2306. emitter.Emit2(InstructionSet.opADD, opEDI, imm);
  2307. emitter.Emit2(InstructionSet.opADD, opESI, imm);
  2308. imm := Assembler.NewImm32(size DIV 4);
  2309. emitter.Emit2(InstructionSet.opMOV, opECX, imm);
  2310. emitter.Emit0(InstructionSet.opSTD); (* copy down *)
  2311. emitter.EmitPrefix (InstructionSet.prfREP);
  2312. emitter.Emit0(InstructionSet.opMOVSD);
  2313. END
  2314. ELSIF IntermediateCode.IsConstantInteger(instruction.op3, size) THEN
  2315. imm := Assembler.NewImm32(size DIV 4);
  2316. emitter.Emit2(InstructionSet.opMOV, opECX, imm);
  2317. emitter.Emit0(InstructionSet.opCLD); (* copy upwards *)
  2318. emitter.EmitPrefix (InstructionSet.prfREP);
  2319. emitter.Emit0(InstructionSet.opMOVSD);
  2320. IF size MOD 4 # 0 THEN
  2321. imm := Assembler.NewImm32(size MOD 4);
  2322. emitter.Emit2(InstructionSet.opMOV, opECX, imm);
  2323. emitter.EmitPrefix (InstructionSet.prfREP);
  2324. emitter.Emit0(InstructionSet.opMOVSB);
  2325. END;
  2326. (* this does not work in the kernel -- for whatever reasons *)
  2327. ELSIF (instruction.op1.mode = IntermediateCode.ModeRegister) & (instruction.op1.register = IntermediateCode.SP) THEN
  2328. MakeOperand(instruction.op3,Low,op3,ecx);
  2329. t := TemporaryTicket(IntermediateCode.GeneralPurposeRegister, IntermediateCode.int32);
  2330. TicketToOperand(t, temp);
  2331. emitter.Emit2(InstructionSet.opADD, opESI, opECX);
  2332. emitter.Emit2(InstructionSet.opADD, opEDI, opECX);
  2333. imm := Assembler.NewImm8(1);
  2334. emitter.Emit2(InstructionSet.opSUB, opESI, imm);
  2335. emitter.Emit2(InstructionSet.opSUB, opEDI, imm);
  2336. emitter.Emit2(InstructionSet.opMOV, temp, opECX);
  2337. imm := Assembler.NewImm8(3);
  2338. emitter.Emit2(InstructionSet.opAND, opECX, imm);
  2339. emitter.Emit0(InstructionSet.opSTD); (* copy downwards *)
  2340. emitter.EmitPrefix (InstructionSet.prfREP);
  2341. emitter.Emit0(InstructionSet.opMOVSB);
  2342. imm := Assembler.NewImm8(2);
  2343. emitter.Emit2(InstructionSet.opMOV, opECX, temp);
  2344. emitter.Emit2(InstructionSet.opSHR, opECX, imm);
  2345. imm := Assembler.NewImm8(3);
  2346. emitter.Emit2(InstructionSet.opSUB, opESI, imm);
  2347. emitter.Emit2(InstructionSet.opSUB, opEDI, imm);
  2348. emitter.EmitPrefix (InstructionSet.prfREP);
  2349. emitter.Emit0(InstructionSet.opMOVSD);
  2350. emitter.Emit0(InstructionSet.opCLD);
  2351. ELSE
  2352. MakeOperand(instruction.op3,Low,op3,ecx);
  2353. t := TemporaryTicket(IntermediateCode.GeneralPurposeRegister, IntermediateCode.int32);
  2354. TicketToOperand(t, temp);
  2355. emitter.Emit2(InstructionSet.opMOV, temp, opECX);
  2356. imm := Assembler.NewImm8(3);
  2357. emitter.Emit2(InstructionSet.opAND, temp, imm);
  2358. imm := Assembler.NewImm8(2);
  2359. emitter.Emit2(InstructionSet.opSHR, opECX, imm);
  2360. emitter.Emit0(InstructionSet.opCLD); (* copy upwards *)
  2361. emitter.EmitPrefix (InstructionSet.prfREP);
  2362. emitter.Emit0(InstructionSet.opMOVSD);
  2363. emitter.Emit2(InstructionSet.opMOV, opECX, temp);
  2364. emitter.EmitPrefix (InstructionSet.prfREP);
  2365. emitter.Emit0(InstructionSet.opMOVSB);
  2366. END;
  2367. UnmapTicket(esi);
  2368. UnmapTicket(edi);
  2369. UnmapTicket(ecx);
  2370. IF backend.cooperative THEN
  2371. UnSpill(ap);
  2372. ap.spillable := FALSE;
  2373. END;
  2374. END;
  2375. END EmitCopy;
  2376. PROCEDURE EmitFill(CONST instruction: IntermediateCode.Instruction; down: BOOLEAN);
  2377. VAR reg,sizeInBits,i: LONGINT;val, value, size, dest: Assembler.Operand;
  2378. op: LONGINT;
  2379. edi, ecx: Ticket;
  2380. BEGIN
  2381. IF FALSE & (instruction.op2.mode = IntermediateCode.ModeImmediate) & (instruction.op2.symbol.name = "") & (instruction.op2.intValue < 5) THEN
  2382. sizeInBits := instruction.op3.type.sizeInBits;
  2383. IF sizeInBits = IntermediateCode.Bits8 THEN value := opAL;
  2384. ELSIF sizeInBits = IntermediateCode.Bits16 THEN value := opAX;
  2385. ELSIF sizeInBits = IntermediateCode.Bits32 THEN value := opEAX;
  2386. ELSE HALT(200)
  2387. END;
  2388. MakeOperand(instruction.op1,Low,dest,NIL);
  2389. IF instruction.op1.mode = IntermediateCode.ModeRegister THEN reg := dest.register
  2390. ELSE emitter.Emit2(InstructionSet.opMOV,opEDX,dest); reg := EDX;
  2391. END;
  2392. IF (instruction.op3.mode = IntermediateCode.ModeImmediate) & (instruction.op3.type.form IN IntermediateCode.Integer) & (instruction.op3.intValue = 0) THEN
  2393. emitter.Emit2(InstructionSet.opXOR,opEAX,opEAX);
  2394. ELSE
  2395. MakeOperand(instruction.op3,Low,value,NIL);
  2396. END;
  2397. FOR i := 0 TO SHORT(instruction.op2.intValue)-1 DO
  2398. IF down THEN
  2399. Assembler.InitMem(dest,SHORT(SHORT(sizeInBits DIV 8)),reg,-i*sizeInBits DIV 8);
  2400. ELSE
  2401. Assembler.InitMem(dest,SHORT(SHORT(sizeInBits DIV 8 )),reg,i*sizeInBits DIV 8);
  2402. END;
  2403. emitter.Emit2(InstructionSet.opMOV,dest,value);
  2404. END;
  2405. ELSE
  2406. Spill(physicalRegisters.Mapped(EDI));
  2407. IF backend.cooperative THEN ap.spillable := TRUE END;
  2408. Spill(physicalRegisters.Mapped(ECX));
  2409. edi := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32,EDI,inPC);
  2410. ecx := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32,ECX,inPC);
  2411. MakeOperand(instruction.op1,Low,dest,edi);
  2412. MakeOperand(instruction.op2,Low,size,ecx);
  2413. MakeOperand(instruction.op3,Low,value,NIL);
  2414. (*
  2415. emitter.Emit2(InstructionSet.opMOV,opEDI, op1[Low]);
  2416. emitter.Emit2(InstructionSet.opMOV,opECX, op3[Low]);
  2417. *)
  2418. CASE instruction.op3.type.sizeInBits OF
  2419. IntermediateCode.Bits8: val := opAL; op := InstructionSet.opSTOSB;
  2420. |IntermediateCode.Bits16: val := opAX; op := InstructionSet.opSTOSW;
  2421. |IntermediateCode.Bits32: val := opEAX; op := InstructionSet.opSTOSD;
  2422. ELSE Halt("only supported for upto 32 bit integers ");
  2423. END;
  2424. IF (instruction.op3.mode = IntermediateCode.ModeImmediate) & (instruction.op3.type.form IN IntermediateCode.Integer) & (instruction.op3.intValue = 0) THEN
  2425. emitter.Emit2(InstructionSet.opXOR,opEAX,opEAX);
  2426. ELSE
  2427. emitter.Emit2(InstructionSet.opMOV,val,value);
  2428. END;
  2429. IF down THEN
  2430. emitter.Emit0(InstructionSet.opSTD); (* fill downwards *)
  2431. ELSE
  2432. emitter.Emit0(InstructionSet.opCLD); (* fill upwards *)
  2433. END;
  2434. emitter.EmitPrefix (InstructionSet.prfREP);
  2435. emitter.Emit0(op);
  2436. IF down THEN (* needed as calls to windows crash otherwise *)
  2437. emitter.Emit0(InstructionSet.opCLD);
  2438. END;
  2439. UnmapTicket(ecx);
  2440. IF backend.cooperative THEN
  2441. UnSpill(ap);
  2442. ap.spillable := FALSE;
  2443. END;
  2444. END;
  2445. END EmitFill;
  2446. PROCEDURE EmitBr (CONST instruction: IntermediateCode.Instruction);
  2447. VAR dest,destPC,offset: LONGINT; target: Assembler.Operand;hit,fail: LONGINT; reverse: BOOLEAN;
  2448. (* jump operands *) left,right,temp: Assembler.Operand;
  2449. failOp: Assembler.Operand; failPC: LONGINT;
  2450. PROCEDURE JmpDest(brop: LONGINT);
  2451. BEGIN
  2452. IF instruction.op1.mode = IntermediateCode.ModeImmediate THEN
  2453. IF instruction.op1.symbol.name # in.name THEN
  2454. Assembler.InitOffset32(target,instruction.op1.intValue);
  2455. Assembler.SetSymbol(target,instruction.op1.symbol.name,instruction.op1.symbol.fingerprint,instruction.op1.symbolOffset,instruction.op1.offset);
  2456. emitter.Emit1(brop,target);
  2457. ELSE
  2458. dest := (instruction.op1.symbolOffset); (* this is the offset in the in-data section (intermediate code), it is not byte- *)
  2459. destPC := (in.instructions[dest].pc );
  2460. offset := destPC - (out.pc );
  2461. IF dest > inPC THEN (* forward jump *)
  2462. Assembler.InitOffset32(target,0);
  2463. Assembler.SetSymbol(target,instruction.op1.symbol.name,instruction.op1.symbol.fingerprint,instruction.op1.symbolOffset,instruction.op1.offset);
  2464. emitter.Emit1(brop,target);
  2465. ELSIF ABS(offset) <= 126 THEN
  2466. Assembler.InitOffset8(target,destPC);
  2467. emitter.Emit1(brop,target);
  2468. ELSE
  2469. Assembler.InitOffset32(target,destPC);
  2470. emitter.Emit1(brop,target);
  2471. END;
  2472. END;
  2473. ELSE
  2474. MakeOperand(instruction.op1,Low,target,NIL);
  2475. emitter.Emit1(brop,target);
  2476. END;
  2477. END JmpDest;
  2478. PROCEDURE CmpFloat;
  2479. BEGIN
  2480. IF backend.forceFPU THEN
  2481. MakeOperand(instruction.op2,Low,left,NIL);
  2482. emitter.Emit1(InstructionSet.opFLD,left); INC(fpStackPointer);
  2483. MakeOperand(instruction.op3,Low,right,NIL);
  2484. emitter.Emit1(InstructionSet.opFCOMP,right); DEC(fpStackPointer);
  2485. emitter.Emit1(InstructionSet.opFNSTSW,opAX);
  2486. emitter.Emit0(InstructionSet.opSAHF);
  2487. ELSE
  2488. MakeRegister(instruction.op2,Low,left);
  2489. MakeOperand(instruction.op3,Low,right,NIL);
  2490. IF instruction.op2.type.sizeInBits = 32 THEN
  2491. emitter.Emit2(InstructionSet.opCOMISS, left, right);
  2492. ELSE
  2493. emitter.Emit2(InstructionSet.opCOMISD, left, right);
  2494. END
  2495. END;
  2496. END CmpFloat;
  2497. PROCEDURE Cmp(part: LONGINT; VAR reverse: BOOLEAN);
  2498. VAR type: IntermediateCode.Type; left,right: Assembler.Operand;
  2499. BEGIN
  2500. IF (instruction.op2.mode = IntermediateCode.ModeImmediate) & (instruction.op3.mode = IntermediateCode.ModeImmediate) THEN
  2501. reverse := FALSE;
  2502. GetPartType(instruction.op2.type,part,type);
  2503. GetTemporaryRegister(type,temp);
  2504. MakeOperand(instruction.op2,part,left,NIL);
  2505. MakeOperand(instruction.op3,part,right,NIL);
  2506. Move(temp,left, type);
  2507. left := temp;
  2508. ELSIF instruction.op2.mode = IntermediateCode.ModeImmediate THEN
  2509. reverse := TRUE;
  2510. MakeOperand(instruction.op2,part,right,NIL);
  2511. MakeOperand(instruction.op3,part,left,NIL);
  2512. ELSIF IsMemoryOperand(instruction.op2,part) & IsMemoryOperand(instruction.op3,part) THEN
  2513. reverse := FALSE;
  2514. GetPartType(instruction.op2.type,part,type);
  2515. GetTemporaryRegister(type,temp);
  2516. MakeOperand(instruction.op2,part,left,NIL);
  2517. MakeOperand(instruction.op3,part,right,NIL);
  2518. Move(temp,right,type);
  2519. right := temp;
  2520. ELSE
  2521. reverse := FALSE;
  2522. MakeOperand(instruction.op2,part,left,NIL);
  2523. MakeOperand(instruction.op3,part,right,NIL);
  2524. END;
  2525. emitter.Emit2(InstructionSet.opCMP,left,right);
  2526. END Cmp;
  2527. BEGIN
  2528. IF (instruction.op1.symbol.name = in.name) & (instruction.op1.symbolOffset = inPC +1) THEN (* jump to next instruction can be ignored *)
  2529. IF dump # NIL THEN dump.String("jump to next instruction ignored"); dump.Ln END;
  2530. RETURN
  2531. END;
  2532. failPC := 0;
  2533. IF instruction.opcode = IntermediateCode.br THEN
  2534. hit := InstructionSet.opJMP
  2535. ELSIF instruction.op2.type.form = IntermediateCode.Float THEN
  2536. CmpFloat;
  2537. CASE instruction.opcode OF
  2538. IntermediateCode.breq: hit := InstructionSet.opJE;
  2539. |IntermediateCode.brne:hit := InstructionSet.opJNE;
  2540. |IntermediateCode.brge: hit := InstructionSet.opJAE
  2541. |IntermediateCode.brlt: hit := InstructionSet.opJB
  2542. END;
  2543. ELSE
  2544. IF ~IsComplex(instruction.op2) THEN
  2545. Cmp(Low,reverse);
  2546. CASE instruction.opcode OF
  2547. IntermediateCode.breq: hit := InstructionSet.opJE;
  2548. |IntermediateCode.brne: hit := InstructionSet.opJNE;
  2549. |IntermediateCode.brge:
  2550. IF instruction.op2.type.form = IntermediateCode.SignedInteger THEN
  2551. IF reverse THEN hit := InstructionSet.opJLE ELSE hit := InstructionSet.opJGE END;
  2552. ELSIF instruction.op2.type.form = IntermediateCode.UnsignedInteger THEN
  2553. IF reverse THEN hit := InstructionSet.opJBE ELSE hit := InstructionSet.opJAE END;
  2554. END;
  2555. |IntermediateCode.brlt:
  2556. IF instruction.op2.type.form = IntermediateCode.SignedInteger THEN
  2557. IF reverse THEN hit := InstructionSet.opJG ELSE hit := InstructionSet.opJL END;
  2558. ELSIF instruction.op2.type.form = IntermediateCode.UnsignedInteger THEN
  2559. IF reverse THEN hit := InstructionSet.opJA ELSE hit := InstructionSet.opJB END;
  2560. END;
  2561. END;
  2562. ELSE
  2563. Assert(instruction.op2.type.form = IntermediateCode.SignedInteger,"no unsigned integer64");
  2564. Cmp(High,reverse);
  2565. CASE instruction.opcode OF
  2566. IntermediateCode.breq: hit := 0; fail := InstructionSet.opJNE;
  2567. |IntermediateCode.brne: hit := InstructionSet.opJNE; fail := 0;
  2568. |IntermediateCode.brge:
  2569. IF reverse THEN hit := InstructionSet.opJL; fail := InstructionSet.opJG;
  2570. ELSE hit := InstructionSet.opJG; fail := InstructionSet.opJL
  2571. END;
  2572. |IntermediateCode.brlt:
  2573. IF reverse THEN hit := InstructionSet.opJG; fail := InstructionSet.opJL
  2574. ELSE hit := InstructionSet.opJL; fail := InstructionSet.opJG
  2575. END;
  2576. END;
  2577. IF hit # 0 THEN JmpDest(hit) END;
  2578. IF fail # 0 THEN
  2579. failPC := out.pc; (* to avoid potential value overflow problem, will be patched anyway *)
  2580. Assembler.InitOffset8(failOp,failPC );
  2581. emitter.Emit1(fail,failOp);
  2582. failPC := failOp.pc;
  2583. END;
  2584. Cmp(Low,reverse);
  2585. CASE instruction.opcode OF
  2586. IntermediateCode.breq: hit := InstructionSet.opJE
  2587. |IntermediateCode.brne: hit := InstructionSet.opJNE
  2588. |IntermediateCode.brge:
  2589. IF reverse THEN hit := InstructionSet.opJBE ELSE hit := InstructionSet.opJAE END;
  2590. |IntermediateCode.brlt:
  2591. IF reverse THEN hit := InstructionSet.opJA ELSE hit := InstructionSet.opJB END;
  2592. END;
  2593. END;
  2594. END;
  2595. JmpDest(hit);
  2596. IF failPC > 0 THEN out.PutByteAt(failPC,(out.pc-failPC)-1); END;
  2597. END EmitBr;
  2598. PROCEDURE EmitPush(CONST vop: IntermediateCode.Operand; part: LONGINT);
  2599. VAR index: LONGINT; type,cpuType: IntermediateCode.Type; op1: Assembler.Operand; ra: Ticket;
  2600. BEGIN
  2601. GetPartType(vop.type,part,type);
  2602. ASSERT(type.form IN IntermediateCode.Integer);
  2603. IF vop.mode = IntermediateCode.ModeImmediate THEN (* may not push 16 bit immediate: strange instruction in 32 / 64 bit mode *)
  2604. GetImmediate(vop,part,op1,TRUE);
  2605. emitter.Emit1(InstructionSet.opPUSH,op1);
  2606. ELSIF (type.sizeInBits = cpuBits) THEN
  2607. MakeOperand(vop,part,op1,NIL);
  2608. emitter.Emit1(InstructionSet.opPUSH,op1);
  2609. ELSE
  2610. ASSERT(type.sizeInBits < cpuBits);
  2611. MakeOperand(vop,part,op1,NIL);
  2612. IF Assembler.IsRegisterOperand(op1) & ~((cpuBits=32) & (type.sizeInBits=8) & (op1.register >= AH)) THEN
  2613. index := op1.register MOD 32 + opRA.register;
  2614. emitter.Emit1(InstructionSet.opPUSH, registerOperands[index]);
  2615. ELSE
  2616. WHILE physicalRegisters.Mapped(opRA.register) # free DO Spill(physicalRegisters.Mapped(opRA.register)) END;
  2617. IntermediateCode.InitType(cpuType,IntermediateCode.SignedInteger,SHORT(cpuBits));
  2618. ra := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,cpuType,opRA.register,inPC);
  2619. CASE type.sizeInBits OF
  2620. 8: index := AL
  2621. |16: index := AX
  2622. |32: index := EAX
  2623. |64: index := RAX
  2624. END;
  2625. emitter.Emit2(InstructionSet.opMOV,registerOperands[index],op1);
  2626. emitter.Emit1(InstructionSet.opPUSH,opRA);
  2627. UnmapTicket(ra);
  2628. END;
  2629. END;
  2630. END EmitPush;
  2631. PROCEDURE EmitPop(CONST vop: IntermediateCode.Operand; part: LONGINT);
  2632. VAR index: LONGINT; type,cpuType: IntermediateCode.Type; op1: Assembler.Operand; ra: Ticket;
  2633. BEGIN
  2634. GetPartType(vop.type,part,type);
  2635. ASSERT(type.form IN IntermediateCode.Integer);
  2636. IF (type.sizeInBits = cpuBits) THEN
  2637. MakeOperand(vop,part,op1,NIL);
  2638. emitter.Emit1(InstructionSet.opPOP,op1);
  2639. ELSE
  2640. ASSERT(type.sizeInBits < cpuBits);
  2641. MakeOperand(vop,part,op1,NIL);
  2642. IF Assembler.IsRegisterOperand(op1) & ~((cpuBits=32) & (type.sizeInBits=8) & (op1.register >= AH)) THEN
  2643. index := op1.register MOD 32 + opRA.register;
  2644. emitter.Emit1(InstructionSet.opPOP, registerOperands[index]);
  2645. ELSE
  2646. WHILE physicalRegisters.Mapped(opRA.register) # free DO Spill(physicalRegisters.Mapped(opRA.register)) END;
  2647. IntermediateCode.InitType(cpuType, IntermediateCode.SignedInteger, SHORT(cpuBits));
  2648. ra := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,cpuType,opRA.register,inPC);
  2649. emitter.Emit1(InstructionSet.opPOP,opRA);
  2650. CASE type.sizeInBits OF
  2651. 8: index := AL
  2652. |16: index := AX
  2653. |32: index := EAX
  2654. |64: index := RAX
  2655. END;
  2656. emitter.Emit2(InstructionSet.opMOV, op1, registerOperands[index]);
  2657. UnmapTicket(ra);
  2658. END;
  2659. END;
  2660. END EmitPop;
  2661. PROCEDURE EmitPushFloat(CONST vop: IntermediateCode.Operand);
  2662. VAR sizeInBytes,length: LONGINT; memop: Assembler.Operand; op: Assembler.Operand;
  2663. BEGIN
  2664. MakeOperand(vop,Low,op,NIL);
  2665. length := vop.type.length;
  2666. IF (vop.mode = IntermediateCode.ModeMemory) & (vop.type.sizeInBits*length =cpuBits) THEN
  2667. emitter.Emit1(InstructionSet.opPUSH,op);
  2668. ELSE
  2669. sizeInBytes := vop.type.sizeInBits DIV 8;
  2670. length := vop.type.length;
  2671. AllocateStack(sizeInBytes*length);
  2672. Assembler.InitMem(memop, SHORTINT(sizeInBytes*length),SP,0);
  2673. IF backend.forceFPU THEN
  2674. emitter.Emit1(InstructionSet.opFLD,op); INC(fpStackPointer);
  2675. emitter.Emit1(InstructionSet.opFSTP,memop); DEC(fpStackPointer);
  2676. ELSE
  2677. Move(memop, op, vop.type)
  2678. END
  2679. END;
  2680. END EmitPushFloat;
  2681. PROCEDURE EmitPopFloat(CONST vop: IntermediateCode.Operand);
  2682. VAR sizeInBytes,length: LONGINT; memop: Assembler.Operand; op: Assembler.Operand;
  2683. BEGIN
  2684. sizeInBytes := vop.type.sizeInBits DIV 8;
  2685. length := vop.type.length;
  2686. IF (vop.mode = IntermediateCode.ModeMemory) & (vop.type.sizeInBits*length =cpuBits) THEN
  2687. MakeOperand(vop,Low,op,NIL);
  2688. emitter.Emit1(InstructionSet.opPOP,op);
  2689. ELSE
  2690. Assembler.InitMem(memop, SHORTINT(sizeInBytes*length),SP,0);
  2691. IF backend.forceFPU THEN
  2692. emitter.Emit1(InstructionSet.opFLD,memop);
  2693. INC(fpStackPointer);
  2694. MakeOperand(vop,Low,op,NIL);
  2695. emitter.Emit1(InstructionSet.opFSTP,op);
  2696. DEC(fpStackPointer);
  2697. ASSERT(sizeInBytes > 0);
  2698. ELSE
  2699. MakeOperand(vop,Low,op,NIL);
  2700. Move(op, memop, vop.type)
  2701. END;
  2702. AllocateStack(-sizeInBytes*length);
  2703. END;
  2704. END EmitPopFloat;
  2705. PROCEDURE EmitNeg(CONST instruction: IntermediateCode.Instruction);
  2706. VAR opLow,opHigh: Assembler.Operand; minusOne: Assembler.Operand; ticketLow,ticketHigh: Ticket;
  2707. BEGIN
  2708. IF IsComplex(instruction.op1) THEN
  2709. PrepareOp2(instruction,High,opHigh,ticketHigh);
  2710. PrepareOp2(instruction,Low,opLow,ticketLow);
  2711. emitter.Emit1(InstructionSet.opNOT,opHigh);
  2712. emitter.Emit1(InstructionSet.opNEG,opLow);
  2713. Assembler.InitImm8(minusOne,-1);
  2714. emitter.Emit2(InstructionSet.opSBB,opHigh,minusOne);
  2715. FinishOp(instruction.op1,High,opHigh,ticketHigh);
  2716. FinishOp(instruction.op1,Low,opLow,ticketLow);
  2717. ELSE
  2718. EmitArithmetic2(instruction,Low,InstructionSet.opNEG);
  2719. END;
  2720. END EmitNeg;
  2721. PROCEDURE EmitNegXMM(CONST instruction: IntermediateCode.Instruction);
  2722. VAR temp, op: Assembler.Operand; ticket: Ticket;
  2723. BEGIN
  2724. PrepareOp2(instruction, Low, op, ticket);
  2725. GetTemporaryRegister(instruction.op1.type,temp);
  2726. IF instruction.op1.type.sizeInBits = 32 THEN
  2727. emitter.Emit2(InstructionSet.opXORPS, temp, temp);
  2728. emitter.Emit2(InstructionSet.opSUBPS, temp, op);
  2729. emitter.Emit2(InstructionSet.opMOVAPS, op, temp);
  2730. ELSE
  2731. emitter.Emit2(InstructionSet.opXORPD, temp, temp);
  2732. emitter.Emit2(InstructionSet.opSUBPD, temp, op);
  2733. emitter.Emit2(InstructionSet.opMOVAPS, op, temp);
  2734. END;
  2735. FinishOp(instruction.op1, Low, op, ticket);
  2736. END EmitNegXMM;
  2737. PROCEDURE EmitAbs(CONST instruction: IntermediateCode.Instruction);
  2738. VAR op1,op2: Assembler.Operand; source,imm: Assembler.Operand; eax: Ticket;
  2739. BEGIN
  2740. Assert(~IsComplex(instruction.op1),"complex Abs not supported");
  2741. IF instruction.op1.type.form = IntermediateCode.SignedInteger THEN
  2742. Spill(physicalRegisters.Mapped(EAX));
  2743. eax := ReservePhysicalRegister(IntermediateCode.GeneralPurposeRegister,IntermediateCode.int32,EAX,inPC);
  2744. MakeOperand(instruction.op1,Low,op1,NIL);
  2745. MakeOperand(instruction.op2,Low,op2,NIL);
  2746. CASE instruction.op1.type.sizeInBits OF
  2747. | IntermediateCode.Bits8: imm := Assembler.NewImm8 (7); source := opAL;
  2748. | IntermediateCode.Bits16: imm := Assembler.NewImm8 (15); source := opAX;
  2749. | IntermediateCode.Bits32: imm := Assembler.NewImm8 (31); source := opEAX;
  2750. END;
  2751. emitter.Emit2 (InstructionSet.opMOV, source,op2);
  2752. emitter.Emit2 (InstructionSet.opMOV, op1,source);
  2753. emitter.Emit2 (InstructionSet.opSAR, source, imm);
  2754. emitter.Emit2 (InstructionSet.opXOR, op1, source);
  2755. emitter.Emit2 (InstructionSet.opSUB, op1, source);
  2756. UnmapTicket(eax);
  2757. ELSE Halt("Abs does not make sense on unsigned integer")
  2758. END;
  2759. END EmitAbs;
  2760. PROCEDURE EmitAbsXMM(CONST instruction: IntermediateCode.Instruction);
  2761. VAR temp, op: Assembler.Operand; ticket: Ticket;
  2762. BEGIN
  2763. PrepareOp2(instruction, Low, op, ticket);
  2764. GetTemporaryRegister(instruction.op1.type,temp);
  2765. IF instruction.op1.type.sizeInBits = 32 THEN
  2766. emitter.Emit2(InstructionSet.opXORPS, temp, temp);
  2767. emitter.Emit2(InstructionSet.opSUBPS, temp, op);
  2768. emitter.Emit2(InstructionSet.opMAXPS, op, temp);
  2769. ELSE
  2770. emitter.Emit2(InstructionSet.opXORPD, temp, temp);
  2771. emitter.Emit2(InstructionSet.opSUBPD, temp, op);
  2772. emitter.Emit2(InstructionSet.opMAXPD, op, temp);
  2773. END;
  2774. FinishOp(instruction.op1, Low, op, ticket);
  2775. END EmitAbsXMM;
  2776. PROCEDURE EmitTrap(CONST instruction: IntermediateCode.Instruction);
  2777. VAR operand: Assembler.Operand;
  2778. BEGIN
  2779. IF instruction.op1.intValue < 80H THEN
  2780. operand := Assembler.NewImm8(instruction.op1.intValue);
  2781. ELSE
  2782. operand := Assembler.NewImm32(instruction.op1.intValue);
  2783. END;
  2784. emitter.Emit1(InstructionSet.opPUSH, operand);
  2785. emitter.Emit0(InstructionSet.opINT3);
  2786. END EmitTrap;
  2787. PROCEDURE EmitAsm(CONST instruction: IntermediateCode.Instruction);
  2788. VAR reader: Streams.StringReader; procedure: SyntaxTree.Procedure; scope: SyntaxTree.Scope;
  2789. len: LONGINT; symbol: SyntaxTree.Symbol; assembler: Assembler.Assembly;
  2790. inr, outr: IntermediateCode.Rules;
  2791. string: SyntaxTree.SourceCode;
  2792. i: LONGINT;
  2793. reg, dest: Assembler.Operand;
  2794. map: Assembler.RegisterMap;
  2795. register: LONGINT;
  2796. ticket: Ticket;
  2797. BEGIN
  2798. IF instruction.op2.mode = IntermediateCode.ModeRule THEN inr := instruction.op2.rule ELSE inr := NIL END;
  2799. IF instruction.op3.mode = IntermediateCode.ModeRule THEN outr := instruction.op3.rule ELSE outr := NIL END;
  2800. string := instruction.op1.string;
  2801. NEW(map);
  2802. IF inr # NIL THEN
  2803. FOR i := 0 TO LEN(inr)-1 DO
  2804. MakeRegister(inr[i], 0, reg);
  2805. ASSERT(map.Find(inr[i].string^) < 0);
  2806. map.Add(inr[i].string, reg.register)
  2807. END;
  2808. END;
  2809. IF outr # NIL THEN
  2810. FOR i := 0 TO LEN(outr)-1 DO
  2811. IF (map.Find(outr[i].string^) < 0) THEN
  2812. GetTemporaryRegister(outr[i].type,reg);
  2813. map.Add(outr[i].string, reg.register)
  2814. END;
  2815. END;
  2816. END;
  2817. len := Strings.Length(string^);
  2818. NEW(reader,len);
  2819. reader.Set(string^);
  2820. symbol := in.symbol;
  2821. procedure := symbol(SyntaxTree.Procedure);
  2822. scope := procedure.procedureScope;
  2823. NEW(assembler,diagnostics,emitter);
  2824. assembler.Assemble(reader,SHORT(instruction.op1.intValue),scope,in,in,module,procedure.access * SyntaxTree.Public # {}, procedure.isInline, map) ;
  2825. error := error OR assembler.error;
  2826. IF outr # NIL THEN
  2827. FOR i := 0 TO LEN(outr)-1 DO
  2828. IF outr[i].mode # IntermediateCode.Undefined THEN
  2829. register := map.Find(outr[i].string^);
  2830. ticket := physicalRegisters.Mapped(register);
  2831. IF ticket.lastuse = inPC THEN UnmapTicket(ticket); physicalRegisters.AllocationHint(register) END; (* try to reuse register here *)
  2832. Assembler.InitRegister(reg, register);
  2833. MakeOperand(outr[i], Low, dest, NIL);
  2834. IF outr[i].type.length > 1 THEN
  2835. SpecialMove(InstructionSet.opMOVUPS,InstructionSet.opMOVUPS, TRUE, dest, reg, outr[i].type)
  2836. ELSE
  2837. Move( dest, reg,outr[i].type)
  2838. END;
  2839. END;
  2840. END;
  2841. END;
  2842. (*
  2843. IntermediateCode.SetString(instruction.op1, string);
  2844. *)
  2845. END EmitAsm;
  2846. END CodeGeneratorAMD64;
  2847. BackendAMD64= OBJECT (IntermediateBackend.IntermediateBackend)
  2848. VAR
  2849. cg: CodeGeneratorAMD64;
  2850. bits: LONGINT;
  2851. traceable: BOOLEAN;
  2852. forceFPU: BOOLEAN;
  2853. PROCEDURE &InitBackendAMD64;
  2854. BEGIN
  2855. InitIntermediateBackend;
  2856. bits := 32;
  2857. forceFPU := FALSE;
  2858. END InitBackendAMD64;
  2859. PROCEDURE Initialize(diagnostics: Diagnostics.Diagnostics; log: Streams.Writer; flags: SET; checker: SemanticChecker.Checker; system: Global.System; activeCells: ActiveCells.Specification);
  2860. BEGIN
  2861. Initialize^(diagnostics,log, flags,checker,system,activeCells); NEW(cg, runtimeModuleName, diagnostics, SELF);
  2862. END Initialize;
  2863. PROCEDURE GetSystem(): Global.System;
  2864. VAR system: Global.System;
  2865. PROCEDURE AddRegister(CONST name: Scanner.IdentifierString; val: LONGINT);
  2866. BEGIN
  2867. Global.NewConstant(name,val,system.shortintType,system.systemScope)
  2868. END AddRegister;
  2869. PROCEDURE AddRegisters;
  2870. BEGIN
  2871. (* system constants *)
  2872. AddRegister("EAX",InstructionSet.regEAX); AddRegister("ECX", InstructionSet.regECX);
  2873. AddRegister( "EDX", InstructionSet.regEDX); AddRegister( "EBX", InstructionSet.regEBX);
  2874. AddRegister( "ESP", InstructionSet.regESP); AddRegister( "EBP", InstructionSet.regEBP);
  2875. AddRegister( "ESI", InstructionSet.regESI); AddRegister( "EDI", InstructionSet.regEDI);
  2876. AddRegister( "AX", InstructionSet.regAX); AddRegister( "CX", InstructionSet.regCX);
  2877. AddRegister( "DX", InstructionSet.regDX); AddRegister( "BX", InstructionSet.regBX);
  2878. AddRegister( "AL", InstructionSet.regAL); AddRegister( "CL", InstructionSet.regCL);
  2879. AddRegister( "DL", InstructionSet.regDL); AddRegister( "BL", InstructionSet.regBL);
  2880. AddRegister( "AH", InstructionSet.regAH); AddRegister( "CH", InstructionSet.regCH);
  2881. AddRegister( "DH", InstructionSet.regDH); AddRegister( "BH", InstructionSet.regBH);
  2882. AddRegister( "RAX", InstructionSet.regRAX); AddRegister( "RCX", InstructionSet.regRCX);
  2883. AddRegister( "RDX", InstructionSet.regRDX); AddRegister( "RBX", InstructionSet.regRBX);
  2884. AddRegister( "RSP", InstructionSet.regRSP); AddRegister( "RBP", InstructionSet.regRBP);
  2885. AddRegister( "RSI", InstructionSet.regRSI); AddRegister( "RDI", InstructionSet.regRDI);
  2886. AddRegister( "R8", InstructionSet.regR8); AddRegister( "R9", InstructionSet.regR9);
  2887. AddRegister( "R10", InstructionSet.regR10); AddRegister( "R11", InstructionSet.regR11);
  2888. AddRegister( "R12", InstructionSet.regR12); AddRegister( "R13", InstructionSet.regR13);
  2889. AddRegister( "R14", InstructionSet.regR14); AddRegister( "R15", InstructionSet.regR15);
  2890. AddRegister( "R8D", InstructionSet.regR8D); AddRegister( "R9D", InstructionSet.regR9D);
  2891. AddRegister( "R10D", InstructionSet.regR10D); AddRegister( "R11D", InstructionSet.regR11D);
  2892. AddRegister( "R12D", InstructionSet.regR12D); AddRegister( "R13D", InstructionSet.regR13D);
  2893. AddRegister( "R14D", InstructionSet.regR14D); AddRegister( "R15D", InstructionSet.regR15D);
  2894. AddRegister( "R8W", InstructionSet.regR8W); AddRegister( "R9W", InstructionSet.regR9W);
  2895. AddRegister( "R10W", InstructionSet.regR10W); AddRegister( "R11W", InstructionSet.regR11W);
  2896. AddRegister( "R12W", InstructionSet.regR12W); AddRegister( "R13W", InstructionSet.regR13W);
  2897. AddRegister( "R14W", InstructionSet.regR14W); AddRegister( "R15W", InstructionSet.regR15W);
  2898. AddRegister( "R8B", InstructionSet.regR8B); AddRegister( "R9B", InstructionSet.regR9B);
  2899. AddRegister( "R10B", InstructionSet.regR10B); AddRegister( "R11B", InstructionSet.regR11B);
  2900. AddRegister( "R12B", InstructionSet.regR12B); AddRegister( "R13B", InstructionSet.regR13B);
  2901. AddRegister( "R14B", InstructionSet.regR14B); AddRegister( "R15B", InstructionSet.regR15B);
  2902. END AddRegisters;
  2903. BEGIN
  2904. IF system = NIL THEN
  2905. IF bits=32 THEN
  2906. NEW(system,8,8,32, 8,32,32,32,64,0,cooperative);
  2907. Global.SetDefaultDeclarations(system,8);
  2908. Global.SetDefaultOperators(system);
  2909. ELSE
  2910. NEW(system,8,8,64,8,64,64,64,128,4 (* parameter registers *),cooperative);
  2911. Global.SetDefaultDeclarations(system,8);
  2912. Global.SetDefaultOperators(system);
  2913. END;
  2914. system.SetRegisterPassCallback(CanPassInRegister);
  2915. AddRegisters
  2916. END;
  2917. RETURN system
  2918. END GetSystem;
  2919. PROCEDURE SupportedInstruction(CONST instruction: IntermediateCode.Instruction; VAR moduleName, procedureName: ARRAY OF CHAR): BOOLEAN;
  2920. BEGIN
  2921. RETURN cg.Supported(instruction,moduleName,procedureName);
  2922. END SupportedInstruction;
  2923. PROCEDURE GenerateBinary(module: Sections.Module; dump: Streams.Writer);
  2924. VAR
  2925. in: Sections.Section;
  2926. out: BinaryCode.Section;
  2927. name: Basic.SegmentedName;
  2928. procedure: SyntaxTree.Procedure;
  2929. i, j, initialSectionCount: LONGINT;
  2930. (* recompute fixup positions and assign binary sections *)
  2931. PROCEDURE PatchFixups(section: BinaryCode.Section);
  2932. VAR resolved: BinaryCode.Section; fixup: BinaryCode.Fixup; displacement,symbolOffset: LONGINT; in: IntermediateCode.Section;
  2933. symbol: Sections.Section;
  2934. BEGIN
  2935. fixup := section.fixupList.firstFixup;
  2936. WHILE fixup # NIL DO
  2937. symbol := module.allSections.FindByName(fixup.symbol.name);
  2938. IF (symbol # NIL) & (symbol(IntermediateCode.Section).resolved # NIL) THEN
  2939. resolved := symbol(IntermediateCode.Section).resolved(BinaryCode.Section);
  2940. in := symbol(IntermediateCode.Section);
  2941. symbolOffset := fixup.symbolOffset;
  2942. IF symbolOffset = in.pc THEN
  2943. displacement := resolved.pc
  2944. ELSIF (symbolOffset # 0) THEN
  2945. ASSERT(in.pc > symbolOffset);
  2946. displacement := in.instructions[symbolOffset].pc;
  2947. ELSE
  2948. displacement := 0;
  2949. END;
  2950. fixup.SetSymbol(fixup.symbol.name,fixup.symbol.fingerprint,0,fixup.displacement+displacement);
  2951. END;
  2952. fixup := fixup.nextFixup;
  2953. END;
  2954. END PatchFixups;
  2955. BEGIN
  2956. cg.SetModule(module);
  2957. FOR i := 0 TO module.allSections.Length() - 1 DO
  2958. in := module.allSections.GetSection(i);
  2959. IF in.type = Sections.InlineCodeSection THEN
  2960. name := in.name;
  2961. out := ResolvedSection(in(IntermediateCode.Section));
  2962. cg.Section(in(IntermediateCode.Section),out);
  2963. procedure := in.symbol(SyntaxTree.Procedure);
  2964. IF procedure.procedureScope.body.code # NIL THEN
  2965. procedure.procedureScope.body.code.SetBinaryCode(out.os.bits);
  2966. END;
  2967. END
  2968. END;
  2969. initialSectionCount := 0;
  2970. REPEAT
  2971. j := initialSectionCount;
  2972. initialSectionCount := module.allSections.Length() ;
  2973. FOR i := j TO initialSectionCount - 1 DO
  2974. in := module.allSections.GetSection(i);
  2975. IF (in.type # Sections.InlineCodeSection) & (in(IntermediateCode.Section).resolved = NIL) THEN
  2976. name := in.name;
  2977. out := ResolvedSection(in(IntermediateCode.Section));
  2978. cg.Section(in(IntermediateCode.Section),out);
  2979. IF out.os.type = Sections.VarSection THEN
  2980. IF out.pc = 1 THEN out.SetAlignment(FALSE,1)
  2981. ELSIF out.pc = 2 THEN out.SetAlignment(FALSE,2)
  2982. ELSIF out.pc > 2 THEN out.SetAlignment(FALSE,4)
  2983. END;
  2984. ELSIF out.os.type = Sections.ConstSection THEN
  2985. out.SetAlignment(FALSE,4);
  2986. END;
  2987. END
  2988. END
  2989. UNTIL initialSectionCount = module.allSections.Length(); (* process remaining sections that have been added during traversal of sections *)
  2990. (*
  2991. FOR i := 0 TO module.allSections.Length() - 1 DO
  2992. in := module.allSections.GetSection(i);
  2993. IF in.kind = Sections.CaseTableKind THEN
  2994. IF in(IntermediateCode.Section).resolved = NIL THEN
  2995. out := ResolvedSection(in(IntermediateCode.Section));
  2996. cg.Section(in(IntermediateCode.Section),out);
  2997. END
  2998. END
  2999. END;
  3000. *)
  3001. FOR i := 0 TO module.allSections.Length() - 1 DO
  3002. in := module.allSections.GetSection(i);
  3003. PatchFixups(in(IntermediateCode.Section).resolved)
  3004. END;
  3005. (*
  3006. FOR i := 0 TO module.allSections.Length() - 1 DO
  3007. in := module.allSections.GetSection(i);
  3008. IF in.kind = Sections.CaseTableKind THEN
  3009. PatchFixups(in(IntermediateCode.Section).resolved)
  3010. END
  3011. END;
  3012. *)
  3013. IF cg.error THEN Error("",Diagnostics.Invalid, Diagnostics.Invalid,"") END;
  3014. END GenerateBinary;
  3015. (* genasm *)
  3016. PROCEDURE ProcessIntermediateCodeModule*(intermediateCodeModule: Formats.GeneratedModule): Formats.GeneratedModule;
  3017. VAR
  3018. result: Formats.GeneratedModule;
  3019. BEGIN
  3020. ASSERT(intermediateCodeModule IS Sections.Module);
  3021. result := ProcessIntermediateCodeModule^(intermediateCodeModule);
  3022. IF ~error THEN
  3023. GenerateBinary(result(Sections.Module),dump);
  3024. IF dump # NIL THEN
  3025. dump.Ln; dump.Ln;
  3026. dump.String(";------------------ binary code -------------------"); dump.Ln;
  3027. IF (traceString="") OR (traceString="*") THEN
  3028. result.Dump(dump);
  3029. dump.Update
  3030. ELSE
  3031. Sections.DumpFiltered(dump, result(Sections.Module), traceString);
  3032. dump.Update;
  3033. END
  3034. END;
  3035. END;
  3036. RETURN result
  3037. FINALLY
  3038. IF dump # NIL THEN
  3039. dump.Ln; dump.Ln;
  3040. dump.String("; ------------------ rescued code (code generation trapped) -------------------"); dump.Ln;
  3041. IF (traceString="") OR (traceString="*") THEN
  3042. result.Dump(dump);
  3043. dump.Update
  3044. ELSE
  3045. Sections.DumpFiltered(dump, result(Sections.Module), traceString);
  3046. dump.Update;
  3047. END
  3048. END;
  3049. HALT(100); (* do not continue compiling after trap *)
  3050. RETURN result
  3051. END ProcessIntermediateCodeModule;
  3052. PROCEDURE FindPC(x: SyntaxTree.Module; CONST sectionName: ARRAY OF CHAR; sectionOffset: LONGINT);
  3053. VAR
  3054. section: Sections.Section; binarySection: BinaryCode.Section; label: BinaryCode.LabelList; module: Formats.GeneratedModule;
  3055. i: LONGINT; pooledName: Basic.SegmentedName;
  3056. BEGIN
  3057. module := ProcessSyntaxTreeModule(x);
  3058. Basic.ToSegmentedName(sectionName, pooledName);
  3059. i := 0;
  3060. REPEAT
  3061. section := module(Sections.Module).allSections.GetSection(i);
  3062. INC(i);
  3063. UNTIL (i = module(Sections.Module).allSections.Length()) OR (section.name = pooledName);
  3064. IF section.name # pooledName THEN
  3065. diagnostics.Error(module.module.sourceName,Diagnostics.Invalid,Diagnostics.Invalid," could not locate pc");
  3066. ELSE
  3067. binarySection := section(IntermediateCode.Section).resolved;
  3068. label := binarySection.labels;
  3069. WHILE (label # NIL) & (label.offset >= sectionOffset) DO
  3070. label := label.prev;
  3071. END;
  3072. IF label # NIL THEN
  3073. diagnostics.Information(module.module.sourceName,label.position,Diagnostics.Invalid," pc position");
  3074. ELSE
  3075. diagnostics.Error(module.module.sourceName,Diagnostics.Invalid,Diagnostics.Invalid," could not locate pc");
  3076. END;
  3077. END;
  3078. END FindPC;
  3079. PROCEDURE CanPassInRegister*(type: SyntaxTree.Type): BOOLEAN;
  3080. VAR length: LONGINT; baseType: SyntaxTree.Type; b: BOOLEAN;
  3081. BEGIN
  3082. b := SemanticChecker.IsStaticMathArray(type, length, baseType) & (baseType IS SyntaxTree.FloatType) & (baseType.sizeInBits = 32) & (length = 4);
  3083. RETURN b
  3084. END CanPassInRegister;
  3085. PROCEDURE GetDescription*(VAR instructionSet: ARRAY OF CHAR);
  3086. BEGIN instructionSet := "AMD";
  3087. END GetDescription;
  3088. PROCEDURE DefineOptions(options: Options.Options);
  3089. BEGIN
  3090. options.Add(0X,"bits",Options.Integer);
  3091. options.Add(0X,"traceable", Options.Flag);
  3092. options.Add(0X,"useFPU", Options.Flag);
  3093. DefineOptions^(options);
  3094. END DefineOptions;
  3095. PROCEDURE GetOptions(options: Options.Options);
  3096. BEGIN
  3097. IF ~options.GetInteger("bits",bits) THEN bits := 32 END;
  3098. traceable := options.GetFlag("traceable");
  3099. forceFPU := options.GetFlag("useFPU");
  3100. GetOptions^(options);
  3101. END GetOptions;
  3102. PROCEDURE DefaultObjectFileFormat(): Formats.ObjectFileFormat;
  3103. BEGIN RETURN ObjectFileFormat.Get();
  3104. END DefaultObjectFileFormat;
  3105. PROCEDURE DefaultSymbolFileFormat(): Formats.SymbolFileFormat;
  3106. BEGIN
  3107. RETURN NIL
  3108. END DefaultSymbolFileFormat;
  3109. END BackendAMD64;
  3110. (** the number of regular sections in a section list **)
  3111. PROCEDURE RegularSectionCount(sectionList: Sections.SectionList): LONGINT;
  3112. VAR
  3113. section: Sections.Section;
  3114. i, result: LONGINT;
  3115. BEGIN
  3116. result := 0;
  3117. FOR i := 0 TO sectionList.Length() - 1 DO
  3118. section := sectionList.GetSection(i);
  3119. INC(result)
  3120. END;
  3121. RETURN result
  3122. END RegularSectionCount;
  3123. PROCEDURE Assert(b: BOOLEAN; CONST s: ARRAY OF CHAR);
  3124. BEGIN
  3125. ASSERT(b,100);
  3126. END Assert;
  3127. PROCEDURE Halt(CONST s: ARRAY OF CHAR);
  3128. BEGIN
  3129. HALT(100);
  3130. END Halt;
  3131. PROCEDURE ResolvedSection(in: IntermediateCode.Section): BinaryCode.Section;
  3132. VAR section: BinaryCode.Section;
  3133. BEGIN
  3134. IF in.resolved = NIL THEN
  3135. NEW(section,in.type, in.priority, 8, in.name,in.comments # NIL,FALSE);
  3136. section.SetAlignment(in.fixed, in.positionOrAlignment);
  3137. in.SetResolved(section);
  3138. ELSE
  3139. section := in.resolved
  3140. END;
  3141. RETURN section
  3142. END ResolvedSection;
  3143. PROCEDURE Init;
  3144. VAR i: LONGINT;
  3145. BEGIN
  3146. FOR i := 0 TO LEN(registerOperands)-1 DO
  3147. Assembler.InitRegister(registerOperands[i],i);
  3148. END;
  3149. opEAX := registerOperands[EAX];
  3150. opEBX := registerOperands[EBX];
  3151. opECX := registerOperands[ECX];
  3152. opEDX := registerOperands[EDX];
  3153. opESI := registerOperands[ESI];
  3154. opEDI := registerOperands[EDI];
  3155. opEBP := registerOperands[EBP];
  3156. opESP := registerOperands[ESP];
  3157. opRSP := registerOperands[RSP];
  3158. opRBP := registerOperands[RBP];
  3159. opAX := registerOperands[AX];
  3160. opBX := registerOperands[BX];
  3161. opCX := registerOperands[CX];
  3162. opDX := registerOperands[DX];
  3163. opSI := registerOperands[SI];
  3164. opDI := registerOperands[DI];
  3165. opAL := registerOperands[AL];
  3166. opBL := registerOperands[BL];
  3167. opCL := registerOperands[CL];
  3168. opDL := registerOperands[DL];
  3169. opAH := registerOperands[AH];
  3170. opBH := registerOperands[BH];
  3171. opCH := registerOperands[CH];
  3172. opDH := registerOperands[DH];
  3173. opST0 := registerOperands[ST0];
  3174. NEW(unusable); NEW(blocked); NEW(split); free := NIL;
  3175. END Init;
  3176. PROCEDURE Get*(): Backend.Backend;
  3177. VAR backend: BackendAMD64;
  3178. BEGIN NEW(backend); RETURN backend
  3179. END Get;
  3180. PROCEDURE Trace*;
  3181. BEGIN
  3182. TRACE(traceStackSize);
  3183. END Trace;
  3184. BEGIN
  3185. traceStackSize := 0;
  3186. Init;
  3187. usePool := Machine.NumberOfProcessors()>1;
  3188. END FoxAMDBackend.