PCG386.Mod 114 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256
  1. (* Paco, Copyright 2000 - 2002, Patrik Reali, ETH Zurich *)
  2. MODULE PCG386; (** AUTHOR "prk / be"; PURPOSE "Parallel Compiler: Intel 386 code generator"; *)
  3. (**
  4. Code Emission for i386 Processors
  5. *)
  6. IMPORT
  7. SYSTEM, KernelLog, PCM, PCO, PCLIR, PCBT;
  8. CONST
  9. TraceReg = FALSE;
  10. Experimental = FALSE;
  11. Huge = TRUE;
  12. (* i386 Registers, taken from PCO*)
  13. EAX = 0; ECX = 1; EDX = 2; EBX = 3; ESP = 4; EBP = 5; ESI = 6; EDI = 7; (* 32 bit register *)
  14. AX = 8; CX = 9; DX = 10; BX = 11; SI = 14; DI = 15; (* 16 bit register *)
  15. AL = 16; CL = 17; DL = 18; BL = 19; AH = 20; CH = 21; DH = 22; BH = 23; (* 8 bit register *)
  16. (* Register Groups *)
  17. Reg32 = {EAX .. EDI}; Reg16 = {AX .. BX, SI, DI}; Reg8L = {AL .. BL}; Reg8H = {AH .. BH}; Reg8 = Reg8L+Reg8H;
  18. RegI = Reg32 + Reg16 + Reg8;
  19. RegFP = {24..31};
  20. Regs = RegI + RegFP;
  21. (* Register allocation mode *)
  22. Free = 0; Splitted = MAX(LONGINT); Blocked = Splitted-1;
  23. (* Address.mode *)
  24. register = 1; relative = 2; indexed = 3; scaled = 4; absolute = 5; immediate = 6;
  25. (*
  26. mode value
  27. 0 Rpc
  28. Register Rbase
  29. Relative [offset + Rbase]
  30. Indexed [offset + Rbase + Rindex]
  31. Scaled [offset + Rbase + scale*Rindex]
  32. Absolute offset + addr (to be patched by the linker)
  33. Immediate value
  34. offset and value are 32-bit if addr is set (will be patched by the linker)
  35. *)
  36. (* PCO Definitions, cached *)
  37. noScale = PCO.noScale; noBase = PCO.noBase; noInx = PCO.noInx; noDisp = PCO.noDisp; noImm = PCO.noImm;
  38. none = -1;
  39. (* Constants for Opcode Tables *)
  40. left = 0; right = 1; (*shifts*)
  41. intMode = 0; floatMode = 1; (*index for JccTable*)
  42. TYPE
  43. Register = SHORTINT; (* i386 Register*)
  44. (*
  45. Address describes the value used by the instruction in terms of a complex addressing mode.
  46. instr.addr is the addressing mode that can be used instead of generating addr. In other words,
  47. a given PCLIR.Register is implemented by the addressing mode instr[vreg].addr.
  48. Exceptions to this rule:
  49. 1) formM1: instr.addr is the M address (destination). This is no problem, since it is never
  50. used as source for other instructions.
  51. 2) form1M: if the instruction is not suppressed (i.e. the instruction loads a register with a value,
  52. because no other instruction could integrate it in a better addressing mode), instr.addr is the
  53. addressing mode for the source (M). This holds only between the FSM and the code generation,
  54. after emission of the instruction, instr.addr must be resetted to mode=0.
  55. 3) form1C: same as 2)
  56. Structure Life:
  57. InstructionInit
  58. * form1X to mode=0 (special case meaning register mode with base=pc)
  59. * initilializes formM1 to the
  60. Optimize/FSM modify
  61. * merging instructions into the addressing mode
  62. * form1M (see above)
  63. Gen*
  64. * use addressing mode and set / decrease count
  65. * use form1M exception (if done) and reset it
  66. *)
  67. (*
  68. Describe the register saved on the stack (e.g. during a call to another procedure)
  69. * vreg0 = 32-bit / 16-bit register or first 8-bit register
  70. * vreg1 = second 8-bit register
  71. * -1 => not used
  72. The register are pushed in the order given by the array
  73. Structure used by SaveRegs / RestoreRegs
  74. *)
  75. SavedRegistersDesc = ARRAY 8 OF RECORD vreg0, vreg1, freg: PCLIR.Register END;
  76. SavedRegistersType = POINTER TO ARRAY OF SavedRegistersDesc;
  77. AliveSet = ARRAY 8 OF RECORD
  78. reg: PCLIR.Register;
  79. mask: SET
  80. END;
  81. AliveSetPtr = POINTER TO AliveSet;
  82. (*
  83. Address:
  84. Label:
  85. imm = real pc
  86. disp = embedded fixup chain
  87. *)
  88. Address = OBJECT (PCLIR.InstructionAttribute)
  89. VAR
  90. mode, scale: SHORTINT;
  91. base, index: PCLIR.Register;
  92. imm, imm2, disp: LONGINT;
  93. addr: PCM.Attribute;
  94. alias: PCLIR.Register; (* the current register is an alias of this one *)
  95. count: LONGINT; (* emission only - use count; when it reaches 0, it can be deallocated *)
  96. i386: Register;
  97. i3862: Register; (*Huge, second register for 64bit values*)
  98. (*
  99. alive: AliveSet
  100. *)
  101. END Address;
  102. (* RealAddress - Similar to address, used to represent a real addressing mode during code emission *)
  103. RealAddress = RECORD
  104. mode: SHORTINT; (* PCO.Regs / Mem / Imme / MemA *)
  105. base, index: Register;
  106. scale: SHORTINT;
  107. imm, imm2, disp: LONGINT;
  108. addr: PCM.Attribute;
  109. size: PCLIR.Size;
  110. base2: Register; (*Huge, second register for 64bit values*)
  111. END;
  112. VAR
  113. SavedRegisters: SavedRegistersType; (* ARRAY 800 OF SavedRegistersDesc; *)
  114. SaveLevel: LONGINT;
  115. CCTableSwitch: SHORTINT; (*0=Int/1=Float; remind last cmp operation, used for jcc/jncc/setcc because flags are different*)
  116. (* Conversion Tables *)
  117. FPSize: ARRAY 7 OF SHORTINT;
  118. TccOpcode: ARRAY 2 OF SHORTINT; (*maps Tcc to a Jcc jump that skips the trap*)
  119. JccOpcode: ARRAY 16, 2 OF SHORTINT; (* maps PCLIR.jcc to i386 jcc *)
  120. Jcc2Opcode: ARRAY 16, 3 OF SHORTINT; (* maps PCLIR.jcc to i386 jcc for HUGEINTS comparisons*)
  121. Typ1Opcode: ARRAY 5 OF SHORTINT;
  122. Typ1Opcode2: ARRAY 5 OF SHORTINT; (*opcodes for the msb of Typ1Operations (Huge) *)
  123. Group3Opcode: ARRAY 2 OF SHORTINT; (*maps to neg/not*)
  124. BitOpcode: ARRAY 2 OF SHORTINT; (*maps to bts/btc*)
  125. ShiftOpcode: ARRAY 6, 2 OF SHORTINT; (*maps to ash/bsh/rot*)
  126. (* Debug *)
  127. RegName: ARRAY 8 OF CHAR;
  128. IReg: ARRAY 24, 4 OF CHAR;
  129. TYPE
  130. RegSet = ARRAY 8 OF LONGINT;
  131. VAR
  132. reg32, reg8: RegSet;
  133. regFP: RegSet;
  134. FSP: SHORTINT; (*F-Stack Top Pointer *)
  135. (*
  136. reg8:
  137. Free: register not used
  138. > 0: allocated as 8-bit reg for a PCLIR.Register
  139. reg32:
  140. Free: register not used (=> both reg8 are also free)
  141. Splitted: one of both reg8 is in use
  142. < 0: allocated as 16-bit reg for a PCLIR.Register
  143. > 0: allocated as 32-bit reg for a PCLIR.Register
  144. regFP:
  145. Free: register not used
  146. > 0: allocated for a PCLIR.Register
  147. *)
  148. PROCEDURE Assert(cond: BOOLEAN; reason: LONGINT);
  149. VAR r32, r8, rFP: RegSet;
  150. BEGIN
  151. IF ~cond THEN
  152. r32 := reg32; r8 := reg8; rFP := regFP; (* Debug *)
  153. HALT(100)
  154. END
  155. END Assert;
  156. (* CheckAllFree - Check that all registers are free *)
  157. (*
  158. PROCEDURE CheckAllFree;
  159. VAR i: LONGINT;
  160. BEGIN
  161. FOR i := 0 TO 7 DO
  162. Assert(reg32[i] = Free, 1000);
  163. Assert(regFP[i] = Free, 1001);
  164. END
  165. END CheckAllFree;
  166. *)
  167. (* FreeAll - Free all the registers *)
  168. PROCEDURE FreeAll;
  169. VAR i: LONGINT;
  170. BEGIN
  171. FOR i := 0 TO 7 DO
  172. reg32[i] := Free; reg8[i] := Free; regFP[i] := Free; FSP := -1
  173. END
  174. END FreeAll;
  175. (* GetThisReg - allocate given register (Int only) *)
  176. PROCEDURE GetThisReg(reg: Register; pc: LONGINT);
  177. VAR off8, off32: Register;
  178. BEGIN
  179. Assert(reg IN RegI, 1002);
  180. Assert(pc # 0 , 1003);
  181. IF reg IN Reg8 THEN
  182. off8 := reg - AL; off32 := reg MOD 4;
  183. Assert((reg32[off32] = Free) OR (reg32[off32] = Splitted), 1004);
  184. Assert(reg8[off8] = Free, 1005);
  185. reg32[off32] := Splitted; reg8[off8] := pc
  186. ELSE
  187. off32 := reg MOD 8;
  188. Assert(reg32[off32] = Free, 1006);
  189. IF reg IN Reg16 THEN pc := -pc END;
  190. reg32[off32] := pc;
  191. IF off32 < ESP THEN (*off32 IN {EAX..EBX}*)
  192. Assert(reg8[off32+0] = Free, 1007);
  193. Assert(reg8[off32+4] = Free, 1008);
  194. reg8[off32+0] := Blocked;
  195. reg8[off32+4] := Blocked;
  196. END
  197. END
  198. END GetThisReg;
  199. (* GetReg - Reserve a reg of given size for use by virtual register pc *)
  200. PROCEDURE GetReg(VAR reg: Register; size: SHORTINT; pc: LONGINT; mask: SET);
  201. PROCEDURE GetReg8;
  202. VAR p: Register;
  203. BEGIN
  204. p := BH; reg := 0;
  205. WHILE p >= AL DO
  206. IF (p IN mask) & (reg8[p- AL] = Free) THEN
  207. IF (reg32[p MOD 4] = Splitted) THEN
  208. reg := p; p := AL
  209. ELSIF (reg32[p MOD 4] = Free) & (reg = 0) THEN
  210. reg := p
  211. END
  212. END;
  213. DEC(p)
  214. END;
  215. Assert((reg IN Reg8) & (reg IN mask), 1009);
  216. reg32[reg MOD 4] := Splitted; reg8[reg - AL] := pc
  217. END GetReg8;
  218. PROCEDURE GetReg32;
  219. BEGIN
  220. reg := EBX;
  221. WHILE ~((reg IN mask) & (reg32[reg] = Free)) & (reg # ESI) DO
  222. reg := (reg-1) MOD 8
  223. END;
  224. GetThisReg(reg, pc)
  225. END GetReg32;
  226. BEGIN
  227. Assert(size IN {1, 2, 4}, 1010);
  228. Assert(pc # 0 , 1011);
  229. IF size = 1 THEN GetReg8
  230. ELSIF size = 2 THEN pc := -pc; GetReg32; INC(reg, AX)
  231. ELSIF size = 4 THEN GetReg32
  232. END;
  233. Assert(reg IN RegI, 1012);
  234. END GetReg;
  235. PROCEDURE GetTempReg32(VAR reg: Register);
  236. BEGIN
  237. reg := EBX;
  238. WHILE (reg32[reg] # Free) & (reg # ESI) DO
  239. reg := (reg-1) MOD 8
  240. END;
  241. Assert(reg32[reg] = Free, 1013)
  242. END GetTempReg32;
  243. PROCEDURE GetTempReg8(VAR reg: Register; mask: SET);
  244. BEGIN
  245. reg := 7;
  246. WHILE (reg >= 0) & ((reg8[reg] # Free) OR ~(reg+AL IN mask)) DO DEC(reg) END;
  247. (*
  248. Assert(reg8[reg] = Free, 1014);
  249. *)
  250. IF reg >= 0 THEN INC(reg, AL) END;
  251. END GetTempReg8;
  252. PROCEDURE GetFPReg(VAR reg: Register; pc: LONGINT);
  253. BEGIN
  254. INC(FSP);
  255. Assert(FSP < 8, 1015);
  256. regFP[FSP] := pc;
  257. reg := 24 + FSP;
  258. END GetFPReg;
  259. (* FreeReg - Free a register *)
  260. PROCEDURE FreeReg(reg: Register);
  261. VAR off8, off32: SHORTINT;
  262. BEGIN
  263. Assert(reg IN Regs, 1017);
  264. IF reg IN {ESP, EBP} THEN (*skip, never allocated*)
  265. ELSIF reg IN Reg32+Reg16 THEN
  266. off32 := reg MOD 8;
  267. Assert(reg32[off32] # Free, 1017);
  268. Assert(reg32[off32] # Splitted, 1018);
  269. reg32[off32] := Free;
  270. IF off32 < ESP THEN (* off32 IN {EAX..EDX} *)
  271. reg8[off32] := Free;
  272. reg8[off32+4] := Free
  273. END
  274. ELSIF reg IN Reg8 THEN
  275. off8 := reg - AL; off32 := off8 MOD 4;
  276. Assert(reg8[off8] # Free, 1019);
  277. Assert(reg32[off32] # Free, 1020);
  278. reg8[reg MOD 8] := Free;
  279. IF reg8[(reg+4) MOD 8] = Free THEN reg32[off32] := Free END
  280. ELSIF reg IN RegFP THEN
  281. reg := reg MOD 8;
  282. Assert((reg = FSP) OR (reg = FSP-1), 1021);
  283. Assert(regFP[FSP] # Free, 1022);
  284. regFP[reg] := Free;
  285. IF reg = FSP THEN
  286. DEC(FSP);
  287. IF (FSP >= 0) & (regFP[FSP] = Free) THEN DEC(FSP) END
  288. END
  289. ELSE
  290. HALT(99)
  291. END
  292. END FreeReg;
  293. (* Owner - return virtual reg owning reg or free *)
  294. PROCEDURE Owner(reg: Register): LONGINT;
  295. BEGIN
  296. Assert(reg IN RegI, 1023);
  297. IF reg IN Reg32+Reg16 THEN
  298. RETURN ABS(reg32[reg MOD 8])
  299. ELSIF reg IN Reg8 THEN
  300. RETURN reg8[reg-AL]
  301. END;
  302. HALT(99);
  303. END Owner;
  304. (* ---------- Helper Procedures -------------- *)
  305. PROCEDURE Dump(VAR instr: PCLIR.Instruction; info: Address);
  306. BEGIN
  307. KernelLog.String("instr ="); KernelLog.Ln; KernelLog.Memory(ADDRESSOF(instr.op), 64);
  308. KernelLog.String("info ="); KernelLog.Ln; KernelLog.Memory(ADDRESSOF(info.mode), 64+32);
  309. END Dump;
  310. PROCEDURE RegisterOverlaps(reg1, reg2: Register): BOOLEAN;
  311. BEGIN
  312. IF reg1 IN Reg8 THEN reg1 := reg1 MOD 4 ELSE reg1 := reg1 MOD 8 END;
  313. IF reg2 IN Reg8 THEN reg2 := reg2 MOD 4 ELSE reg2 := reg2 MOD 8 END;
  314. RETURN reg1 = reg2
  315. END RegisterOverlaps;
  316. PROCEDURE RegisterSize(reg: Register): SHORTINT;
  317. BEGIN
  318. IF reg IN Reg32 THEN RETURN 4
  319. ELSIF reg IN Reg16 THEN RETURN 2
  320. ELSIF reg IN Reg8 THEN RETURN 1
  321. END
  322. END RegisterSize;
  323. PROCEDURE MakeMask(reg: Register): SET;
  324. BEGIN
  325. IF reg = none THEN
  326. RETURN {}
  327. ELSIF reg IN {ESI, EDI} THEN
  328. RETURN {reg}
  329. ELSIF reg IN RegI THEN
  330. reg := reg MOD 4;
  331. RETURN {reg, AX+reg, AL+reg, AH+reg}
  332. END
  333. END MakeMask;
  334. (* Special Registers *)
  335. (* RegisterA - Return EAX/AX/AL, depending on the size *)
  336. PROCEDURE RegisterA(size: PCLIR.Size): Register;
  337. BEGIN
  338. CASE size OF
  339. | PCLIR.Int32: RETURN EAX
  340. | PCLIR.Int16: RETURN AX
  341. | PCLIR.Int8: RETURN AL
  342. END
  343. END RegisterA;
  344. (* RegisterD - Return EDX / DX / AH, depending on the size (complementary reg) *)
  345. PROCEDURE RegisterD(size: PCLIR.Size): Register;
  346. BEGIN
  347. CASE size OF
  348. | PCLIR.Int8: RETURN AH
  349. | PCLIR.Int16: RETURN DX
  350. | PCLIR.Int32: RETURN EDX
  351. END
  352. END RegisterD;
  353. PROCEDURE ConstSize(c: LONGINT; allow16: BOOLEAN): SHORTINT;
  354. BEGIN
  355. IF (c >= MIN(SHORTINT)) & (c <= MAX(SHORTINT)) THEN
  356. RETURN 1
  357. ELSIF allow16 & (c >= MIN(INTEGER)) & (c <= MAX(INTEGER)) THEN
  358. RETURN 2
  359. ELSE
  360. RETURN 4
  361. END
  362. END ConstSize;
  363. (* Instruction Initialization, plug-in for PCLIR.InstructionInit *)
  364. PROCEDURE InstructionInit(VAR instr: PCLIR.Instruction);
  365. VAR info: Address; op: PCLIR.Opcode;
  366. BEGIN
  367. op := instr.op;
  368. IF (PCLIR.InstructionSet[op].format IN PCLIR.form1X) OR (op = PCLIR.case) THEN
  369. NEW(info); instr.info := info; instr.suppress := FALSE; info.alias := none; info.i386 := none;
  370. ELSIF (op = PCLIR.label) OR (op = PCLIR.finallylabel) THEN
  371. NEW(info); instr.info := info; instr.suppress := FALSE; info.disp := none; info.imm := 0
  372. ELSIF PCLIR.InstructionSet[op].format = PCLIR.formM1 THEN
  373. NEW(info); instr.info := info; instr.suppress := FALSE;
  374. IF instr.src1 = PCLIR.Absolute THEN
  375. info.mode := absolute; info.disp := instr.val; info.addr := instr.adr
  376. ELSE
  377. info.mode := relative; info.disp := instr.val; info.base := instr.src1
  378. END
  379. END
  380. END InstructionInit;
  381. (* Code Optimization Procedures *)
  382. (* FSM (Finite State Machine) - Try to remove the current instruction by using a complex addressing mode *)
  383. PROCEDURE FSM(code: PCLIR.Code; pc: LONGINT; VAR instr: PCLIR.Instruction; addr: Address);
  384. VAR p: PCLIR.Piece; op: PCLIR.Opcode; thisreg, nextreg: PCLIR.Register; i: LONGINT; info: Address;
  385. BEGIN
  386. IF thisreg < 0 THEN RETURN END; (* FP/SP/HwReg terminate search*)
  387. thisreg := pc;
  388. nextreg := none; (* next register to be optimized *)
  389. op := instr.op;
  390. IF addr.mode = 0 THEN (* complete initialization *)
  391. addr.mode := register; addr.base := pc
  392. END;
  393. IF (instr.dstCount # 1) THEN op := PCLIR.nop END; (*instruction is used more than once: don't simplify; but try other opts*)
  394. IF (PCLIR.convs<=op) & (op<=PCLIR.copy) & (instr.dstSize = PCLIR.Address) & (instr.src1 >= instr.barrier) THEN
  395. pc := instr.src1; code.GetPiece(pc, p);
  396. IF PCLIR.Int32 = p.instr[pc].dstSize THEN
  397. instr.suppress := TRUE;
  398. IF addr.base = thisreg THEN addr.base := instr.src1 ELSE addr.index := instr.src1 END;
  399. FSM(code, instr.src1, p.instr[pc], addr);
  400. RETURN
  401. END
  402. END;
  403. CASE addr.mode OF
  404. | register:
  405. IF (op = PCLIR.load) & (instr.src1 = PCLIR.Absolute) THEN (*register -> absolute*)
  406. instr.suppress := TRUE;
  407. addr.mode := absolute; addr.disp := instr.val; addr.addr := instr.adr
  408. ELSIF (op = PCLIR.loadc) THEN (*register -> immediate*)
  409. instr.suppress := TRUE;
  410. addr.mode := immediate; addr.imm := instr.val; addr.addr := instr.adr
  411. ELSIF (op = PCLIR.load) THEN (*register -> relative*)
  412. instr.suppress := TRUE;
  413. addr.mode := relative; addr.disp := instr.val; addr.base := instr.src1;
  414. nextreg := addr.base;
  415. END
  416. | relative:
  417. IF (op = PCLIR.loadc) THEN (*relative -> absolute*)
  418. instr.suppress := TRUE;
  419. addr.mode := absolute; addr.disp := addr.disp + instr.val; addr.addr := instr.adr
  420. ELSIF (op = PCLIR.add) THEN (*relative -> indexed*)
  421. instr.suppress := TRUE;
  422. addr.mode := indexed; addr.base := instr.src1; addr.index := instr.src2;
  423. nextreg := addr.index
  424. ELSIF (op = PCLIR.mul) OR (op = PCLIR.ash) THEN (*relative -> scaled, iff const mult*)
  425. Optimize(code, instr, pc, NIL);
  426. pc := instr.src2; code.GetPiece(pc, p);
  427. info := SYSTEM.VAL(Address, p.instr[pc].info);
  428. IF (info # NIL) & (info.mode = immediate) & (info.addr = NIL) THEN
  429. i := info.imm;
  430. IF op = PCLIR.ash THEN i := ASH(LONG(LONG(1)), i) END;
  431. IF i=1 THEN (*relative -> relative*)
  432. instr.suppress := TRUE;
  433. addr.base := instr.src1;
  434. nextreg := instr.src1
  435. ELSIF (i=2) OR (i=4) OR (i=8) THEN
  436. instr.suppress := TRUE;
  437. addr.mode := scaled; addr.base := none; addr.index := instr.src1; addr.scale := SHORT(SHORT(i));
  438. nextreg := instr.src1
  439. END
  440. END
  441. END
  442. | indexed:
  443. IF (op = PCLIR.loadc) THEN (*indexed -> relative*)
  444. instr.suppress := TRUE;
  445. IF thisreg = addr.base THEN addr.base := addr.index END;
  446. addr.mode := relative; addr.disp := addr.disp + instr.val; addr.index := none; addr.addr := instr.adr;
  447. nextreg := addr.base
  448. ELSIF (op = PCLIR.add) THEN (*special case, because of lea removal*)
  449. Optimize(code, instr, pc, NIL);
  450. pc := instr.src2; code.GetPiece(pc, p);
  451. info := SYSTEM.VAL(Address, p.instr[pc].info);
  452. IF (info # NIL) & (info.mode = immediate) & (info.addr = NIL) THEN
  453. addr.disp := addr.disp + info.imm;
  454. IF thisreg = addr.base THEN
  455. addr.base := instr.src1; nextreg := addr.base
  456. ELSE
  457. ASSERT(addr.index = thisreg);
  458. addr.index := instr.src1; nextreg := addr.index
  459. END;
  460. instr.suppress := TRUE
  461. END
  462. ELSIF (op = PCLIR.mul) OR (op = PCLIR.ash) THEN (*indexed -> scaled, iff const mult*)
  463. Optimize(code, instr, pc, NIL);
  464. pc := instr.src2; code.GetPiece(pc, p);
  465. info := SYSTEM.VAL(Address, p.instr[pc].info);
  466. IF (info # NIL) & (info.mode = immediate) & (info.addr = NIL) THEN
  467. i := info.imm;
  468. IF op = PCLIR.ash THEN i := ASH(LONG(LONG(1)), i) END;
  469. IF (i=1) OR (i=2) OR (i=4) OR (i=8) THEN
  470. instr.suppress := TRUE;
  471. IF i#1 THEN addr.mode := scaled; addr.scale := SHORT(SHORT(i)) END;
  472. IF thisreg = addr.base THEN addr.base := addr.index END;
  473. addr.index := instr.src1;
  474. IF (addr.index >= instr.barrier) THEN
  475. pc := addr.index; code.GetPiece(pc, p); FSM(code, addr.index, p.instr[pc], addr)
  476. ELSIF (addr.base >= instr.barrier) THEN
  477. pc := addr.base; code.GetPiece(pc, p); FSM(code, addr.index, p.instr[pc], addr)
  478. END
  479. ELSIF thisreg = addr.index THEN nextreg := addr.base
  480. END
  481. END
  482. ELSIF thisreg = addr.index THEN nextreg := addr.base
  483. END
  484. | scaled:
  485. IF (op = PCLIR.loadc) THEN (*scaled -> relative*)
  486. instr.suppress := TRUE;
  487. IF thisreg = addr.base THEN
  488. addr.addr := instr.adr; addr.disp := addr.disp + instr.val; addr.base := none
  489. ELSIF instr.adr # NIL THEN
  490. instr.suppress := FALSE (*undo*)
  491. ELSIF addr.base # none THEN
  492. addr.mode := relative; addr.disp := addr.disp + instr.val * addr.scale; addr.index := none;
  493. nextreg := addr.base
  494. ELSE
  495. addr.mode := absolute; addr.disp := addr.disp + instr.val * addr.scale
  496. END
  497. ELSIF (op = PCLIR.add) THEN (*special case, because of lea removal*)
  498. Optimize(code, instr, pc, NIL);
  499. pc := instr.src2; code.GetPiece(pc, p);
  500. info := SYSTEM.VAL(Address, p.instr[pc].info);
  501. IF (info # NIL) & (info.mode = immediate) & (info.addr = NIL) THEN
  502. IF thisreg = addr.base THEN
  503. addr.disp := addr.disp + info.imm;
  504. addr.base := instr.src1; nextreg := addr.base;
  505. instr.suppress := TRUE
  506. ELSIF addr.scale = 1 THEN
  507. ASSERT(addr.index = thisreg);
  508. addr.disp := addr.disp + info.imm;
  509. addr.index := instr.src1; nextreg := addr.index;
  510. instr.suppress := TRUE
  511. END
  512. END
  513. ELSIF thisreg = addr.index THEN nextreg := addr.base
  514. END
  515. END;
  516. IF (nextreg >= instr.barrier) THEN
  517. pc := nextreg; code.GetPiece(pc, p); FSM(code, nextreg, p.instr[pc], addr)
  518. END
  519. END FSM;
  520. PROCEDURE AliveSetInit(VAR set: AliveSet);
  521. VAR i: LONGINT;
  522. BEGIN
  523. FOR i := 0 TO LEN(set)-1 DO
  524. set[i].reg := none
  525. END
  526. END AliveSetInit;
  527. PROCEDURE AliveAdd(VAR set: AliveSet; reg: LONGINT; size: PCLIR.Size);
  528. VAR i, j: LONGINT; mask: SET;
  529. BEGIN
  530. IF reg <= 0 THEN RETURN END;
  531. IF (reg = 0) THEN HALT(MAX(INTEGER)) END;
  532. (*PCM.LogWLn; PCM.LogWStr("Add "); PCM.LogWNum(reg);*)
  533. i := 0; j := -1;
  534. WHILE (i < LEN(set)) & (set[i].reg # reg) DO
  535. IF set[i].reg = none THEN j := i END;
  536. INC(i)
  537. END;
  538. IF (j = -1) THEN
  539. PCM.LogWLn; PCM.LogWStr("AliveSet.Add: no free space")
  540. ELSIF (i = LEN(set)) THEN
  541. set[j].reg := reg;
  542. CASE size OF
  543. | PCLIR.Int8: mask := Reg8
  544. | PCLIR.Int16: mask := Reg16
  545. | PCLIR.Int32: mask := Reg32
  546. END;
  547. set[j].mask := mask
  548. END;
  549. (*FOR i := 0 TO LEN(set)-1 DO
  550. PCM.LogWNum(set[i].reg)
  551. END;*)
  552. END AliveAdd;
  553. PROCEDURE AliveAddComplex(VAR set: AliveSet; code: PCLIR.Code; reg: LONGINT);
  554. VAR pos: LONGINT; p: PCLIR.Piece; info: Address;
  555. BEGIN
  556. IF reg <= 0 THEN RETURN END;
  557. pos := reg; code.GetPiece(pos, p);
  558. info := SYSTEM.VAL(Address, p.instr[pos].info);
  559. CASE info.mode OF
  560. | 0:
  561. (*PCM.LogWLn; PCM.LogWStr("AddComplex / 0 "); PCM.LogWNum(reg);*)
  562. AliveAdd(set, reg, p.instr[pos].dstSize)
  563. | register:
  564. AliveAdd(set, info.base, p.instr[pos].dstSize)
  565. | relative:
  566. (*PCM.LogWLn; PCM.LogWStr("AddComplex / reg+rel "); PCM.LogWNum(reg); PCM.LogWNum(info.base);*)
  567. AliveAdd(set, info.base, PCLIR.Address)
  568. | indexed, scaled:
  569. AliveAdd(set, info.base, PCLIR.Address); AliveAdd(set, info.index, PCLIR.Address)
  570. ELSE
  571. END
  572. END AliveAddComplex;
  573. PROCEDURE AliveRemove(VAR set: AliveSet; reg: LONGINT);
  574. VAR i: LONGINT;
  575. BEGIN
  576. (*PCM.LogWLn; PCM.LogWStr("Rem "); PCM.LogWNum(reg);*)
  577. i := 0;
  578. WHILE (i < LEN(set)) & (set[i].reg # reg) DO INC(i) END;
  579. IF i < LEN(set) THEN set[i].reg := none END;
  580. END AliveRemove;
  581. (* SetRegisterHint - vreg should be implemented by ireg *)
  582. PROCEDURE SetRegisterHint(code: PCLIR.Code; barrier: LONGINT; vreg: PCLIR.Register; ireg: Register);
  583. VAR p: PCLIR.Piece; op: PCLIR.Opcode; info: Address; size: PCLIR.Size;
  584. BEGIN
  585. IF (vreg >= 0) & (vreg >= barrier) THEN
  586. code.GetPiece(vreg, p);
  587. info := SYSTEM.VAL(Address, p.instr[vreg].info); ASSERT(info # NIL);
  588. IF info.i386 = none THEN
  589. info.i386 := ireg;
  590. op := p.instr[vreg].op;
  591. size := PCLIR.SizeOf(code, p.instr[vreg].src1);
  592. IF size IN PCLIR.FloatSize THEN
  593. (*skip*)
  594. ELSIF (PCLIR.convs<=op) & (op<=PCLIR.copy) (*& (PCLIR.NofBytes(p.instr[vreg].dstSize) <= PCLIR.NofBytes(size))*) THEN (*reduction*)
  595. IF size = PCLIR.Int64 THEN
  596. SetRegisterHint2(code, barrier, p.instr[vreg].src1, (ireg MOD 8) + EAX, none)
  597. ELSE
  598. SetRegisterHint(code, barrier, p.instr[vreg].src1, (ireg MOD 8) + RegisterA(size))
  599. END;
  600. ELSIF (PCLIR.InstructionSet[op].format IN {PCLIR.form11, PCLIR.form12}) & ((op < PCLIR.sete) OR (op > PCLIR.setnf)) THEN
  601. (* (op >= PCLIR.mul) & (op <= PCLIR.or) THEN (*ops with dst = src1*) *)
  602. SetRegisterHint(code, barrier, p.instr[vreg].src1, ireg)
  603. END
  604. END
  605. END
  606. END SetRegisterHint;
  607. PROCEDURE SetRegisterHint2(code: PCLIR.Code; barrier: LONGINT; vreg: PCLIR.Register; ireg, ireg2: Register);
  608. VAR p: PCLIR.Piece; op: PCLIR.Opcode; info: Address; size: PCLIR.Size;
  609. BEGIN
  610. IF (vreg >= 0) & (vreg >= barrier) THEN
  611. code.GetPiece(vreg, p);
  612. info := SYSTEM.VAL(Address, p.instr[vreg].info); ASSERT(info # NIL);
  613. ASSERT(p.instr[vreg].dstSize = PCLIR.Int64);
  614. IF info.i386 = none THEN
  615. info.i386 := ireg; info.i3862 := ireg2;
  616. op := p.instr[vreg].op;
  617. size := PCLIR.SizeOf(code, p.instr[vreg].src1);
  618. IF size IN PCLIR.FloatSize THEN
  619. (*skip*)
  620. ELSIF (PCLIR.convs<=op) & (op<=PCLIR.copy) THEN (*reduction*)
  621. SetRegisterHint(code, barrier, p.instr[vreg].src1, (ireg MOD 8) + RegisterA(size))
  622. ELSIF (PCLIR.InstructionSet[op].format IN {PCLIR.form11, PCLIR.form12}) & ((op < PCLIR.sete) OR (op > PCLIR.setnf)) THEN
  623. (* (op >= PCLIR.mul) & (op <= PCLIR.or) THEN (*ops with dst = src1*) *)
  624. SetRegisterHint2(code, barrier, p.instr[vreg].src1, ireg, ireg2)
  625. END
  626. END
  627. END
  628. END SetRegisterHint2;
  629. (** Optimize - Perform some code optimizations; must be a reverse traversal *)
  630. PROCEDURE Optimize(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT; context: ANY);
  631. CONST Full = 1; Const = 2; NoConst = 3; (*Optimization Mode*)
  632. VAR p: PCLIR.Piece; copy, pos: LONGINT; op: PCLIR.Opcode; debSrc1, debSrc2: PCLIR.Register; mode: SHORTINT;
  633. info: Address; format: LONGINT; size1: PCLIR.Size;
  634. alive: AliveSetPtr; hint1, hint2: Register;
  635. PROCEDURE Compact(reg: PCLIR.Register; mode: SHORTINT): SHORTINT;
  636. VAR p: PCLIR.Piece; pos: LONGINT; info: Address; op: PCLIR.Opcode; mode0: SHORTINT;
  637. BEGIN
  638. IF reg >= instr.barrier THEN
  639. pos := reg; code.GetPiece(pos, p);
  640. op := p.instr[pos].op;
  641. info := SYSTEM.VAL(Address, p.instr[pos].info);
  642. IF (info.mode = 0) &
  643. ((mode = Full) OR ((mode = Const) & (op = PCLIR.loadc)) OR ((mode = NoConst) & (op # PCLIR.loadc))) THEN
  644. FSM(code, reg, p.instr[pos], info)
  645. END;
  646. mode0 := info.mode;
  647. ASSERT((mode = Full) OR (mode = Const)&(mode0 IN {0, register, immediate}) OR (mode = NoConst)&(mode0#immediate));
  648. RETURN info.mode
  649. ELSE
  650. RETURN register
  651. END
  652. END Compact;
  653. PROCEDURE Unuse(reg: PCLIR.Register);
  654. VAR p: PCLIR.Piece; pos: LONGINT;
  655. BEGIN
  656. IF reg >= 0 THEN
  657. pos := reg; code.GetPiece(pos, p);
  658. DEC(p.instr[pos].dstCount)
  659. END
  660. END Unuse;
  661. BEGIN
  662. op := instr.op; format := PCLIR.InstructionSet[op].format;
  663. IF instr.suppress THEN RETURN END;
  664. copy := pc;
  665. debSrc1 := instr.src1; debSrc2 := instr.src2; (* Debug *)
  666. IF Experimental & (context # NIL) THEN
  667. alive := SYSTEM.VAL(AliveSetPtr, context);
  668. (*
  669. IF (instr.info # NIL) THEN
  670. info := SYSTEM.VAL(Address, instr.info);
  671. info.alive := alive^
  672. END
  673. *)
  674. END;
  675. CASE format OF
  676. | PCLIR.form00, PCLIR.form0C, PCLIR.formXX:
  677. (* no optimization *)
  678. | PCLIR.form10:
  679. IF instr.op # PCLIR.pop THEN
  680. instr.suppress := instr.dstCount = 0
  681. END;
  682. IF Experimental & (alive # NIL) THEN AliveRemove(alive^, pc) END;
  683. | PCLIR.form1M, PCLIR.form1C:
  684. (* if this is reached, the instruction is not suppressed -> exception 1 *)
  685. info := SYSTEM.VAL(Address, instr.info);
  686. IF ~(info.mode IN {0, register}) THEN Dump(instr, info) END;
  687. ASSERT(info.mode IN {0, register});
  688. IF instr.dstCount = 0 THEN
  689. IF (format = PCLIR.form1M) & (instr.src1 >= 0) THEN
  690. Unuse(instr.src1)
  691. END;
  692. instr.suppress := TRUE
  693. ELSIF format = PCLIR.form1C THEN
  694. info.mode := immediate; info.imm := instr.val; info.addr := instr.adr
  695. ELSIF instr.src1 = PCLIR.Absolute THEN
  696. info.mode := absolute; info.disp := instr.val; info.addr := instr.adr
  697. ELSE
  698. info.mode := relative; info.disp := instr.val; info.base := instr.src1;
  699. IF instr.src1 >= instr.barrier THEN
  700. pc := instr.src1; code.GetPiece(pc, p); FSM(code, instr.src1, p.instr[pc], info)
  701. END
  702. END;
  703. IF Experimental & (alive # NIL) THEN
  704. AliveRemove(alive^, copy);
  705. IF ~(info.mode IN {immediate, absolute}) THEN
  706. AliveAdd(alive^, info.base, PCLIR.Address);
  707. AliveAdd(alive^, info.index, PCLIR.Address)
  708. END
  709. END;
  710. (*instr.suppress := instr.dstCount = 0*)
  711. | PCLIR.formM1:
  712. info := SYSTEM.VAL(Address, instr.info);
  713. IF instr.src1 >= instr.barrier THEN
  714. pc := instr.src1; code.GetPiece(pc, p); FSM(code, instr.src1, p.instr[pc], info);
  715. mode := Compact(instr.src2, Const);
  716. IF Experimental & (alive # NIL) THEN
  717. AliveAdd(alive^, info.base, PCLIR.Address);
  718. AliveAdd(alive^, info.index, PCLIR.Address);
  719. AliveAdd(alive^, instr.src2, PCLIR.SizeOf(code, instr.src2))
  720. END
  721. ELSIF instr.src1 <= PCLIR.HwReg THEN
  722. info.mode := register; info.base := instr.src1;
  723. mode := Compact(instr.src2, Full);
  724. IF Experimental & (alive # NIL) THEN
  725. AliveAddComplex(alive^, code, instr.src2)
  726. END
  727. ELSE
  728. mode := Compact(instr.src2, Const);
  729. IF Experimental & (alive # NIL) THEN
  730. AliveAdd(alive^, instr.src1, PCLIR.Address);
  731. AliveAdd(alive^, instr.src2, PCLIR.SizeOf(code, instr.src2))
  732. END
  733. END
  734. | PCLIR.form11:
  735. size1 := PCLIR.SizeOf(code, instr.src1);
  736. hint1 := none; hint2 := none;
  737. IF (instr.dstCount = 0) & (instr.src1 >= 0) THEN
  738. Unuse(instr.src1); instr.suppress := TRUE
  739. ELSIF (op = PCLIR.in) THEN
  740. hint1 := DX;
  741. ELSIF (op = PCLIR.convs) OR (op = PCLIR.convu) OR (op = PCLIR.copy) THEN
  742. IF size1 < instr.dstSize THEN
  743. mode := Compact(instr.src1, NoConst);
  744. IF (instr.dstSize = PCLIR.Int64) & (size1 = PCLIR.Int32) THEN hint1 := EAX END
  745. END
  746. ELSIF (op = PCLIR.abs) THEN
  747. IF size1 IN PCLIR.IntSize THEN hint1 := RegisterA(size1) END
  748. END;
  749. IF Experimental & (alive # NIL) THEN
  750. AliveRemove(alive^, pc);
  751. IF mode = 0 THEN
  752. AliveAdd(alive^, instr.src1, size1)
  753. ELSE
  754. AliveAddComplex(alive^, code, instr.src1)
  755. END
  756. END;
  757. IF hint1 # none THEN
  758. SetRegisterHint(code, instr.barrier, instr.src1, hint1)
  759. END
  760. | PCLIR.form01:
  761. hint1 := none;
  762. size1 := PCLIR.SizeOf(code, instr.src1);
  763. IF op = PCLIR.kill THEN
  764. (*skip*)
  765. ELSIF op = PCLIR.ret THEN
  766. IF size1 = PCLIR.Int64 THEN
  767. hint1 := EAX; hint2 := EDX
  768. ELSIF size1 IN PCLIR.IntSize-{PCLIR.Int64} THEN
  769. hint1 := RegisterA(size1)
  770. END
  771. ELSIF op = PCLIR.ret2 THEN
  772. ASSERT(size1 IN PCLIR.IntSize);
  773. hint1 := RegisterD(size1)
  774. ELSIF op = PCLIR.loadsp THEN
  775. hint1 := ESP
  776. ELSIF op = PCLIR.loadfp THEN
  777. hint1 := EBP
  778. ELSE
  779. mode := Compact(instr.src1, Full)
  780. END;
  781. IF Experimental & (alive # NIL) THEN
  782. IF mode = 0 THEN
  783. AliveAdd(alive^, instr.src1, size1)
  784. ELSE
  785. AliveAddComplex(alive^, code, instr.src1)
  786. END
  787. END;
  788. IF hint1 # none THEN
  789. IF size1 = PCLIR.Int64 THEN
  790. SetRegisterHint2(code, instr.barrier, instr.src1, hint1, hint2)
  791. ELSE
  792. SetRegisterHint(code, instr.barrier, instr.src1, hint1)
  793. END
  794. END
  795. | PCLIR.form02, PCLIR.form12, PCLIR.form02C:
  796. hint1 := none; hint2 := none;
  797. IF (op = PCLIR.phi) THEN
  798. IF instr.src1 > instr.src2 THEN PCLIR.SwapSources(instr) END;
  799. info := SYSTEM.VAL(Address, instr.info); info.alias := instr.src1;
  800. pos := instr.src2; code.GetPiece(pos, p);
  801. info := SYSTEM.VAL(Address, p.instr[pos].info); info.alias := instr.src1;
  802. ELSIF (format = PCLIR.form12) & (instr.dstCount = 0) & (instr.src1 >= 0) & (instr.src2 >= 0)THEN
  803. Unuse(instr.src1); Unuse(instr.src2);
  804. instr.suppress := TRUE
  805. ELSIF (op >= PCLIR.ash) & (op <= PCLIR.rot) THEN
  806. ASSERT(PCLIR.NofBytes(PCLIR.SizeOf(code, instr.src2)) = 1);
  807. IF Compact(instr.src2, Const) # immediate THEN hint2 := CL END
  808. ELSIF (op = PCLIR.bts) OR (op = PCLIR.btc) THEN
  809. mode := Compact(instr.src2, Const)
  810. ELSIF (op = PCLIR.jf) OR (op = PCLIR.jnf) OR (op = PCLIR.setf) OR (op = PCLIR.setnf) THEN
  811. mode := Compact(instr.src1, NoConst);
  812. mode := Compact(instr.src2, Const)
  813. ELSIF (op = PCLIR.div) OR (op = PCLIR.mod) THEN
  814. mode := Compact(instr.src2, NoConst);
  815. IF instr.dstSize IN PCLIR.IntSize THEN hint1 := RegisterA(instr.dstSize) (*dividend*) END
  816. ELSIF (op = PCLIR.out) THEN
  817. hint1 := DX;
  818. hint2 := RegisterA(PCLIR.SizeOf(code, instr.src2))
  819. ELSE
  820. mode := Compact(instr.src2, Full);
  821. IF (instr.dstSize = PCLIR.Int64) & (op = PCLIR.mul) THEN
  822. mode := Compact(instr.src1, NoConst)
  823. ELSIF (mode IN {0, register}) & (PCLIR.commutative IN PCLIR.InstructionSet[op].flags) THEN
  824. IF ~(Compact(instr.src1, Full) IN {0, register}) THEN PCLIR.SwapSources(instr) END
  825. ELSIF (mode = immediate) & ((format=PCLIR.form02) OR (op = PCLIR.mul) OR ((op >= PCLIR.sete) & (op <= PCLIR.setnf))) THEN
  826. mode := Compact(instr.src1, NoConst);
  827. IF (mode IN {0, register}) & ((op >= PCLIR.je) & (op <= PCLIR.jnf) OR (op >= PCLIR.sete) & (op <= PCLIR.setnf)) THEN
  828. size1 := PCLIR.SizeOf(code, instr.src1);
  829. IF size1 IN PCLIR.IntSize / {PCLIR.Int64} THEN hint1 := RegisterA(size1) END
  830. END
  831. END;
  832. IF (op = PCLIR.mul) & (instr.dstSize IN PCLIR.IntSize-{PCLIR.Int64}) THEN
  833. hint1 := RegisterA(instr.dstSize) (*dividend*)
  834. END
  835. END;
  836. IF Experimental & (context # NIL) THEN
  837. IF format = PCLIR.form12 THEN AliveRemove(alive^, pc) END;
  838. AliveAddComplex(alive^, code, instr.src1);
  839. AliveAddComplex(alive^, code, instr.src2)
  840. END;
  841. IF hint1 # none THEN SetRegisterHint(code, instr.barrier, instr.src1, hint1) END;
  842. IF hint2 # none THEN SetRegisterHint(code, instr.barrier, instr.src2, hint2) END
  843. | PCLIR.form03:
  844. mode := Compact(instr.src3, Const);
  845. IF Experimental & (context # NIL) THEN
  846. AliveAdd(alive^, instr.src1, PCLIR.Address);
  847. AliveAdd(alive^, instr.src2, PCLIR.Address);
  848. IF mode # immediate THEN
  849. AliveAdd(alive^, instr.src3, PCLIR.Int32)
  850. END
  851. END;
  852. SetRegisterHint(code, instr.barrier, instr.src1, ESI);
  853. SetRegisterHint(code, instr.barrier, instr.src2, EDI);
  854. IF mode # immediate THEN
  855. SetRegisterHint(code, instr.barrier, instr.src3, ECX)
  856. END
  857. END;
  858. (*
  859. IF Experimental & (context # NIL) THEN
  860. alive := SYSTEM.VAL(AliveSetPtr, context);
  861. IF instr.info # NIL THEN
  862. info := SYSTEM.VAL(Address, instr.info);
  863. info.alive := alive^
  864. END;
  865. AliveSetProcess(alive, code, instr, copy)
  866. END;
  867. *)
  868. END Optimize;
  869. (* Address Handling Procedures *)
  870. (* UseRegister - use a register; last use frees it *)
  871. PROCEDURE UseRegisterI(VAR instr: PCLIR.Instruction; VAR reg: Register); (*shortcut*)
  872. VAR info: Address;
  873. BEGIN
  874. info := SYSTEM.VAL(Address, instr.info); ASSERT(info.mode IN {0, register}, 100);
  875. DEC(info.count); reg := info.i386;
  876. IF info.count <= 0 THEN FreeReg(reg) END;
  877. END UseRegisterI;
  878. PROCEDURE UseRegister(code: PCLIR.Code; vreg: PCLIR.Register; VAR reg: Register);
  879. VAR p: PCLIR.Piece;
  880. BEGIN
  881. IF vreg >= 0 THEN
  882. code.GetPiece(vreg, p); UseRegisterI(p.instr[vreg], reg)
  883. ELSIF vreg = PCLIR.SP THEN
  884. reg := ESP
  885. ELSIF vreg = PCLIR.FP THEN
  886. reg := EBP
  887. ELSIF (vreg <= PCLIR.HwReg-EAX) & (vreg >= PCLIR.HwReg - BH) THEN
  888. reg := SHORT(SHORT(PCLIR.HwReg-vreg))
  889. ELSE HALT(99) (*paranoid check*)
  890. END
  891. END UseRegister;
  892. PROCEDURE UseRegisterI2(VAR instr: PCLIR.Instruction; VAR reg, reg2: Register); (*shortcut*)
  893. VAR info: Address;
  894. BEGIN
  895. info := SYSTEM.VAL(Address, instr.info);
  896. ASSERT(info.mode IN {0, register}, 100);
  897. ASSERT(instr.dstSize = PCLIR.Int64, 101);
  898. DEC(info.count); reg := info.i386; reg2 := info.i3862;
  899. IF info.count <= 0 THEN FreeReg(reg); FreeReg(reg2) END;
  900. END UseRegisterI2;
  901. PROCEDURE UseRegister2(code: PCLIR.Code; vreg: PCLIR.Register; VAR reg, reg2: Register);
  902. VAR p: PCLIR.Piece;
  903. BEGIN
  904. IF vreg >= 0 THEN
  905. code.GetPiece(vreg, p); UseRegisterI2(p.instr[vreg], reg, reg2)
  906. ELSE HALT(99) (*paranoid check*)
  907. END
  908. END UseRegister2;
  909. (* UseComplex - use a complex addressing form, free registers after last use *)
  910. PROCEDURE UseComplexI(code: PCLIR.Code; VAR instr: PCLIR.Instruction; VAR addr: RealAddress);
  911. VAR info: Address; adr: PCBT.Procedure;
  912. PROCEDURE IntelScale(scale: LONGINT): SHORTINT;
  913. BEGIN
  914. CASE scale OF
  915. | 1: RETURN PCO.Scale1 | 2: RETURN PCO.Scale2 | 4: RETURN PCO.Scale4 | 8: RETURN PCO.Scale8
  916. END
  917. END IntelScale;
  918. BEGIN
  919. info := SYSTEM.VAL(Address, instr.info);
  920. addr.base := noBase; addr.base2 := noBase; addr.index := noInx; addr.disp := noDisp;
  921. addr.scale := noScale; addr.imm := noImm; addr.addr := info.addr; addr.size := instr.dstSize;
  922. CASE info.mode OF
  923. | 0:
  924. addr.mode := PCO.Regs;
  925. addr.addr := NIL;
  926. IF addr.size = PCLIR.Int64 THEN
  927. UseRegisterI2(instr, addr.base, addr.base2)
  928. ELSE
  929. UseRegisterI(instr, addr.base)
  930. END
  931. | register:
  932. addr.mode := PCO.Regs;
  933. addr.addr := NIL;
  934. IF addr.size = PCLIR.Int64 THEN
  935. UseRegister2(code, info.base, addr.base, addr.base2)
  936. ELSE
  937. UseRegister(code, info.base, addr.base)
  938. END
  939. | relative:
  940. addr.mode := PCO.Mem;
  941. UseRegister(code, info.base, addr.base);
  942. addr.base2 := addr.base; addr.disp := info.disp; addr.addr := info.addr;
  943. | indexed, scaled:
  944. addr.mode := PCO.Mem;
  945. IF (info.base # none) THEN UseRegister(code, info.base, addr.base) END;
  946. addr.base2 := addr.base; addr.disp := info.disp; addr.addr := info.addr;
  947. UseRegister(code, info.index, addr.index);
  948. IF info.mode = scaled THEN addr.scale := IntelScale(info.scale) END
  949. | absolute:
  950. addr.mode := PCO.Mem;
  951. addr.disp := info.disp; addr.addr := info.addr
  952. | immediate:
  953. addr.mode := PCO.Imme;
  954. IF instr.dstSize = PCLIR.Int64 THEN addr.base := EAX ELSE addr.base := RegisterA(instr.dstSize) END;
  955. addr.base2 := addr.base; addr.imm := info.imm;
  956. IF addr.imm >= 0 THEN addr.imm2 := 0 ELSE addr.imm2 := -1 END;
  957. IF addr.addr # NIL THEN ASSERT(addr.size = PCLIR.Address) END
  958. END;
  959. IF ((addr.mode = PCO.Mem) OR (addr.mode = PCO.Imme)) & (addr.addr # NIL) THEN
  960. INC(addr.mode, PCO.ForceDisp32)
  961. END;
  962. IF (addr.addr # NIL) & (addr.addr IS PCBT.Procedure) THEN
  963. adr := addr.addr(PCBT.Procedure);
  964. ASSERT(addr.disp = 0);
  965. IF (addr.mode = PCO.ImmeA) THEN
  966. ASSERT(addr.imm = 0)
  967. ELSIF (addr.mode = PCO.MemA) THEN
  968. ASSERT(addr.disp = 0)
  969. ELSE
  970. HALT(99)
  971. END;
  972. END
  973. END UseComplexI;
  974. PROCEDURE UseComplex(code: PCLIR.Code; vreg: PCLIR.Register; VAR addr: RealAddress);
  975. VAR p: PCLIR.Piece;
  976. BEGIN
  977. IF vreg >= 0 THEN
  978. code.GetPiece(vreg, p); UseComplexI(code, p.instr[vreg], addr)
  979. ELSE
  980. addr.mode := PCO.Regs;
  981. addr.addr := NIL;
  982. addr.size := PCLIR.Address; (*used for ESP/EBP*)
  983. UseRegister(code, vreg, addr.base)
  984. END
  985. END UseComplex;
  986. (* AllocateRegI - allocate a real register *)
  987. PROCEDURE AllocateRegI(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT): Register;
  988. VAR pos: LONGINT; p: PCLIR.Piece; info, info1: Address;
  989. BEGIN
  990. info := SYSTEM.VAL(Address, instr.info);
  991. IF (info.alias # none) THEN (*this register is aliased*)
  992. pos := info.alias; code.GetPiece(pos, p); info1 := SYSTEM.VAL(Address, p.instr[pos].info);
  993. info.i386 := info1.i386;
  994. ASSERT(instr.dstSize = p.instr[pos].dstSize);
  995. ASSERT(Owner(info.i386) = Free)
  996. END;
  997. IF instr.dstSize IN PCLIR.FloatSize THEN
  998. (*
  999. ASSERT(info.i386 = none);
  1000. *)
  1001. GetFPReg(info.i386, pc)
  1002. ELSIF (info.i386 = none) OR (Owner(info.i386) # Free) THEN (*no hints or hinted reg not free*)
  1003. GetReg(info.i386, PCLIR.NofBytes(instr.dstSize), pc, RegI)
  1004. ELSE
  1005. GetThisReg(info.i386, pc)
  1006. END;
  1007. IF info.count > 0 THEN
  1008. (*fof: If register has been in use before a procedure call and is now re-allocated after call of procedure it is wrong to take the initial count. Instead, the count
  1009. has to be kept as it was before the procedure call *)
  1010. ELSE
  1011. info.count := instr.dstCount;
  1012. END;
  1013. IF info.count <= 0 THEN FreeReg(info.i386) END;
  1014. IF TraceReg THEN PCM.LogWLn; PCM.LogWNum(pc); PCM.LogWStr(": "); PCM.LogWStr(IReg[info.i386]) END;
  1015. RETURN info.i386
  1016. END AllocateRegI;
  1017. PROCEDURE AllocateReg(code: PCLIR.Code; vreg: PCLIR.Register): Register;
  1018. VAR pc: LONGINT; p: PCLIR.Piece;
  1019. BEGIN
  1020. pc := vreg; code.GetPiece(pc, p);
  1021. RETURN AllocateRegI(code, p.instr[pc], vreg);
  1022. END AllocateReg;
  1023. PROCEDURE AllocateRegI2(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT; VAR reg, reg2: Register);
  1024. VAR pos: LONGINT; p: PCLIR.Piece; info, info1: Address;
  1025. BEGIN
  1026. ASSERT(instr.dstSize = PCLIR.Int64);
  1027. info := SYSTEM.VAL(Address, instr.info);
  1028. IF (info.alias # none) THEN (*this register is aliased*)
  1029. pos := info.alias; code.GetPiece(pos, p); info1 := SYSTEM.VAL(Address, p.instr[pos].info);
  1030. info.i386 := info1.i386;
  1031. info.i3862 := info1.i3862;
  1032. ASSERT(instr.dstSize = p.instr[pos].dstSize);
  1033. ASSERT(Owner(info.i386) = Free)
  1034. END;
  1035. IF (info.i386 = none) OR (Owner(info.i386) # Free) THEN (*no hints or hinted reg not free*)
  1036. GetReg(info.i386, 4, pc, RegI)
  1037. ELSE
  1038. GetThisReg(info.i386, pc)
  1039. END;
  1040. IF (info.i3862 = none) OR (Owner(info.i3862) # Free) THEN (*no hints or hinted reg not free*)
  1041. GetReg(info.i3862, 4, pc, RegI)
  1042. ELSE
  1043. GetThisReg(info.i3862, pc)
  1044. END;
  1045. reg := info.i386; reg2 := info.i3862;
  1046. info.count := instr.dstCount;
  1047. IF info.count <= 0 THEN FreeReg(info.i386); FreeReg(info.i3862) END;
  1048. IF TraceReg THEN PCM.LogWLn; PCM.LogWNum(pc); PCM.LogWStr(": "); PCM.LogWStr(IReg[info.i386]); PCM.LogWStr(IReg[info.i3862]) END;
  1049. END AllocateRegI2;
  1050. (* AllocateThisReg - allocate ireg *)
  1051. PROCEDURE AllocateThisRegI(VAR instr: PCLIR.Instruction; pc: LONGINT; ireg: Register);
  1052. VAR info: Address;
  1053. BEGIN
  1054. ASSERT(PCLIR.NofBytes(instr.dstSize) = RegisterSize(ireg));
  1055. IF ~(ireg IN {ESP, EBP}) THEN GetThisReg(ireg, pc) END;
  1056. info := SYSTEM.VAL(Address, instr.info); info.i386 := ireg; info.count := instr.dstCount
  1057. END AllocateThisRegI;
  1058. PROCEDURE AllocateThisReg(code: PCLIR.Code; vreg: PCLIR.Register; ireg: Register);
  1059. VAR pc: LONGINT; p: PCLIR.Piece;
  1060. BEGIN
  1061. IF vreg >= 0 THEN
  1062. pc := vreg; code.GetPiece(pc, p);
  1063. AllocateThisRegI(p.instr[pc], vreg, ireg)
  1064. ELSIF (vreg = PCLIR.SP) & (ireg = ESP) THEN (*ok*)
  1065. ELSIF (vreg = PCLIR.FP) & (ireg = EBP) THEN (*ok*)
  1066. ELSE
  1067. (* HW-Reg must not be a target *)
  1068. HALT(99) (*paranoid check*)
  1069. END
  1070. END AllocateThisReg;
  1071. PROCEDURE AllocateThisRegI2(VAR instr: PCLIR.Instruction; pc: LONGINT; ireg, ireg2: Register);
  1072. VAR info: Address;
  1073. BEGIN
  1074. ASSERT(instr.dstSize = PCLIR.Int64);
  1075. ASSERT(ireg IN Reg32);
  1076. ASSERT(ireg2 IN Reg32);
  1077. IF ~(ireg IN {ESP, EBP}) THEN GetThisReg(ireg, pc) END;
  1078. IF ~(ireg2 IN {ESP, EBP}) THEN GetThisReg(ireg2, pc) END;
  1079. info := SYSTEM.VAL(Address, instr.info); info.i386 := ireg; info.i3862 := ireg2; info.count := instr.dstCount
  1080. END AllocateThisRegI2;
  1081. (*
  1082. PROCEDURE AllocateThisReg2(code: PCLIR.Code; vreg: PCLIR.Register; ireg, ireg2: Register);
  1083. VAR pc: LONGINT; p: PCLIR.Piece;
  1084. BEGIN
  1085. IF vreg >= 0 THEN
  1086. pc := vreg; code.GetPiece(pc, p);
  1087. AllocateThisRegI2(p.instr[pc], vreg, ireg, ireg2)
  1088. ELSE
  1089. (* HW-Reg must not be a target *)
  1090. HALT(99) (*paranoid check*)
  1091. END
  1092. END AllocateThisReg2;
  1093. *)
  1094. (* ReleaseReg - Free reg. If allocated, move to another register *)
  1095. PROCEDURE ReleaseReg(code: PCLIR.Code; reg: Register; protect: SET);
  1096. VAR owner, pos: PCLIR.Register; mask: SET; p: PCLIR.Piece; src: Register; info: Address;
  1097. BEGIN
  1098. ASSERT(~(reg IN {ESP, EBP}));
  1099. mask := RegI - MakeMask(reg) - protect;
  1100. owner := Owner(reg);
  1101. WHILE owner # Free DO
  1102. IF owner = Splitted THEN
  1103. owner := Owner(reg MOD 8 + AL);
  1104. IF owner = Free THEN
  1105. owner := Owner(reg MOD 8 + AH);
  1106. ASSERT(owner # Free)
  1107. END
  1108. ELSIF owner = Blocked THEN
  1109. owner := Owner(reg MOD 4);
  1110. ASSERT(owner # Free)
  1111. END;
  1112. pos := owner; code.GetPiece(pos, p);
  1113. info := SYSTEM.VAL(Address, p.instr[pos].info); src := info.i386;
  1114. GetReg(info.i386, RegisterSize(src), owner, mask);
  1115. FreeReg(src);
  1116. PCO.GenMOV(PCO.RegReg, info.i386, src, noInx, noScale, noDisp, noImm);
  1117. IF TraceReg THEN
  1118. PCM.LogWLn; PCM.LogWStr("Spill reg ");
  1119. PCM.LogWNum(owner); PCM.LogWStr(": "); PCM.LogWNum(src); PCM.LogWStr(" -> "); PCM.LogWNum(info.i386)
  1120. END;
  1121. owner := Owner(reg)
  1122. END
  1123. END ReleaseReg;
  1124. PROCEDURE ForceRegister(code: PCLIR.Code; VAR reg: Register; dest: Register; protect: SET);
  1125. BEGIN
  1126. IF reg # dest THEN
  1127. ReleaseReg(code, dest, protect+MakeMask(reg));
  1128. PCO.GenMOV(PCO.RegReg, dest, reg, noInx, noScale, noDisp, noImm);
  1129. reg := dest
  1130. END
  1131. END ForceRegister;
  1132. PROCEDURE FixAbsolute(adr: PCM.Attribute; offset: LONGINT);
  1133. (* adr info prepared by UseComplexI *)
  1134. BEGIN
  1135. IF adr = NIL THEN
  1136. (*skip*)
  1137. ELSIF adr IS PCBT.GlobalVariable THEN
  1138. PCBT.context.UseVariable(adr(PCBT.GlobalVariable), PCO.pc+offset)
  1139. ELSIF adr IS PCBT.Procedure THEN
  1140. PCBT.context.UseProcedure(adr(PCBT.Procedure), PCO.pc+offset)
  1141. ELSE HALT(99)
  1142. END
  1143. END FixAbsolute;
  1144. (* Code Generation Procedures *)
  1145. (* GenEnter - Create Procedure activation frame of given size and clear the stack *)
  1146. PROCEDURE GenEnter(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1147. VAR size, L, i: LONGINT; padr: PCBT.Procedure (* ug *); adr: PCBT.Attribute (* ug *);
  1148. PROCEDURE SetAddress(proc: PCBT.Procedure);
  1149. VAR pos, dw: LONGINT;
  1150. BEGIN
  1151. WITH proc: PCBT.Procedure DO
  1152. IF proc.fixlist # PCBT.FixupSentinel THEN (*patch the fixlist*)
  1153. pos := proc.fixlist; proc.fixlist := PCBT.FixupSentinel;
  1154. REPEAT
  1155. PCO.GetDWord(pos, dw); PCO.PutDWordAt(pos, PCO.pc - 4 - pos);
  1156. pos := dw
  1157. UNTIL pos = PCBT.FixupSentinel
  1158. END
  1159. END
  1160. END SetAddress;
  1161. BEGIN
  1162. IF instr.adr IS PCBT.Procedure THEN (* ug *)
  1163. padr := instr.adr(PCBT.Procedure);
  1164. PCBT.context.AddOwnProc(padr, PCO.pc);
  1165. SetAddress(padr);
  1166. size := padr.locsize;
  1167. adr := padr;
  1168. ELSIF instr.adr IS PCBT.Module THEN
  1169. size := 0;
  1170. adr := instr.adr(PCBT.Module)
  1171. END; (* ug *)
  1172. IF (instr.val = PCBT.OberonCC) OR (instr.val = PCBT.WinAPICC) OR (instr.val= PCBT.CLangCC) (* fof for Linux *) THEN (* ejz *)
  1173. ASSERT(size MOD 4 = 0, 100);
  1174. size := size DIV 4; (* number of DOUBLE WORDS to be allocated *)
  1175. PCO.GenPUSH(PCO.Regs, EBP, noBase, noInx, noScale, noDisp, noImm);
  1176. PCO.GenMOV(PCO.RegReg, EBP, ESP, noInx, noScale, noDisp, noImm);
  1177. IF (PCM.FullStackInit IN PCM.codeOptions) & (size >= 8) THEN
  1178. PCO.GenMOV(PCO.ImmReg, ECX, noBase, noInx, noScale, noDisp, size DIV 4);
  1179. PCO.GenTyp1 (PCO.XOR, PCO.RegReg, EAX, EAX, noInx, noScale, noDisp, noImm);
  1180. i := size MOD 4;
  1181. WHILE i > 0 DO
  1182. PCO.GenPUSH(PCO.Regs, EAX, noBase, noInx, noScale, noDisp, noImm); DEC(i)
  1183. END;
  1184. L := PCO.pc;
  1185. PCO.GenDEC(PCO.ImmReg, ECX, noBase, noInx, noScale, noDisp);
  1186. PCO.GenPUSH(PCO.Regs, EAX, noBase, noInx, noScale, noDisp, noImm);
  1187. PCO.GenPUSH(PCO.Regs, EAX, noBase, noInx, noScale, noDisp, noImm);
  1188. PCO.GenPUSH(PCO.Regs, EAX, noBase, noInx, noScale, noDisp, noImm);
  1189. PCO.GenPUSH(PCO.Regs, EAX, noBase, noInx, noScale, noDisp, noImm);
  1190. PCO.GenJcc (PCO.JNZ, L - (PCO.pc + 2))
  1191. ELSIF (PCM.FullStackInit IN PCM.codeOptions) & (size > 0) THEN
  1192. PCO.GenTyp1 (PCO.XOR, PCO.RegReg, EAX, EAX, noInx, noScale, noDisp, noImm);
  1193. WHILE size > 0 DO
  1194. PCO.GenPUSH(PCO.Regs, EAX, noBase, noInx, noScale, noDisp, noImm); DEC(size)
  1195. END;
  1196. ELSIF size > 0 THEN
  1197. PCO.GenTyp1(PCO.SUB, PCO.ImmReg, ESP, noBase, noInx, noScale, noDisp, size*4)
  1198. END;
  1199. IF (instr.val = PCBT.WinAPICC) OR (instr.val = PCBT.CLangCC)(* fof for Linux *) THEN (* ejz *)
  1200. PCO.GenPUSH(PCO.Regs, EBX, noBase, noInx, noScale, noDisp, noImm);
  1201. PCO.GenPUSH(PCO.Regs, EDI, noBase, noInx, noScale, noDisp, noImm);
  1202. PCO.GenPUSH(PCO.Regs, ESI, noBase, noInx, noScale, noDisp, noImm)
  1203. END
  1204. ELSIF instr.val = PCBT.OberonPassivateCC THEN
  1205. PCO.GenPUSH(PCO.Regs, EBP, noBase, noInx, noScale, noDisp, noImm);
  1206. PCO.GenMOV(PCO.MemReg, EBP, ESP, noInx, noScale, 8, noImm)
  1207. ELSE
  1208. HALT(99)
  1209. END;
  1210. IF adr # NIL THEN adr.SetBeginOffset(PCO.pc) END;
  1211. FreeAll
  1212. END GenEnter;
  1213. (* GenExit - Remove procedure activation frame, remove the give size of parameters and return to the caller *)
  1214. PROCEDURE GenExit(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1215. VAR size: LONGINT;
  1216. BEGIN
  1217. IF instr.adr # NIL THEN (* ug *)
  1218. instr.adr(PCBT.Attribute).SetEndOffset(PCO.pc)
  1219. END;
  1220. IF (instr.val = PCBT.OberonCC) OR (instr.val = PCBT.WinAPICC) OR (instr.val = PCBT.CLangCC)(* fof for Linux *) THEN (* ejz *)
  1221. size := instr.src1;
  1222. ASSERT(size MOD 4 = 0, 100);
  1223. IF (instr.val = PCBT.WinAPICC) OR (instr.val = PCBT.CLangCC) (* fof for Linux *) THEN (* ejz *)
  1224. PCO.GenPOP(PCO.Regs, ESI, noBase, noInx, noScale, noDisp);
  1225. PCO.GenPOP(PCO.Regs, EDI, noBase, noInx, noScale, noDisp);
  1226. PCO.GenPOP(PCO.Regs, EBX, noBase, noInx, noScale, noDisp)
  1227. END;
  1228. PCO.GenMOV(PCO.RegReg, ESP, EBP, noInx, noScale, noDisp, noImm);
  1229. PCO.GenPOP(PCO.Regs, EBP, noBase, noInx, noScale, noDisp);
  1230. IF instr.val # PCBT.CLangCC THEN (* fof for Linux *)
  1231. PCO.GenRET(size)
  1232. ELSE (* fof for Linux *)
  1233. PCO.GenRET(0);
  1234. END;
  1235. ELSIF instr.val = PCBT.OberonPassivateCC THEN
  1236. PCO.GenPOP(PCO.Regs, EBP, noBase, noInx, noScale, noDisp);
  1237. PCO.GenRET(4)
  1238. ELSE
  1239. HALT(99)
  1240. END;
  1241. (* CheckAllFree; *)
  1242. END GenExit;
  1243. (* GenTrap - Implementation for trap, tcc *)
  1244. PROCEDURE GenTrap(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1245. VAR op: PCLIR.Opcode; src1, src2: RealAddress;
  1246. BEGIN
  1247. op := instr.op;
  1248. IF op # PCLIR.trap THEN
  1249. UseComplex(code, instr.src1, src1); UseComplex(code, instr.src2, src2);
  1250. ASSERT(src1.size IN PCLIR.IntSize - {PCLIR.Int64});
  1251. GenCmp1(code, src1, src2);
  1252. PCO.GenJcc(TccOpcode[op-PCLIR.tae], 3)
  1253. END;
  1254. PCO.GenPUSH(PCO.Imme, EAX (*gives size!*), noBase, noInx, noScale, noDisp, instr.val);
  1255. PCO.PutByte(0CCH); (* INT 3 *)
  1256. END GenTrap;
  1257. PROCEDURE GetRegSaveSize(): LONGINT; (* fld *)
  1258. VAR s: LONGINT; i: Register; t: PCLIR.Register;
  1259. BEGIN
  1260. s := 0;
  1261. IF FSP >= 0 THEN s := (FSP+1)*8 END;
  1262. FOR i := EAX TO EDI DO
  1263. IF ~(i IN {EBP, ESP}) THEN
  1264. t := Owner(i);
  1265. IF t # Free THEN INC( s, 4 ) END
  1266. END
  1267. END;
  1268. RETURN s
  1269. END GetRegSaveSize;
  1270. PROCEDURE GenSaveRegistersAligned(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT); (* fld *)
  1271. VAR rss, gap: LONGINT;
  1272. BEGIN
  1273. PCO.GenTyp1( PCO.AND, PCO.ImmReg, ESP, noBase, noInx, noScale, noDisp, -16 ); (* align stack to 16 byte boundary *)
  1274. rss := GetRegSaveSize();
  1275. gap := (16 - rss MOD 16) MOD 16;
  1276. IF gap # 0 THEN
  1277. PCO.GenTyp1( PCO.SUB, PCO.ImmReg, ESP, noBase, noInx, noScale, noDisp, gap );
  1278. END;
  1279. GenSaveRegisters( code, instr, pc )
  1280. END GenSaveRegistersAligned;
  1281. (*
  1282. Saved Registers are in the SavedRegisters structure.
  1283. * vreg0: 32/16/8(LSB) bits virtual register pushed
  1284. * vreg1: 8 (MSB) bits virtual register pushed
  1285. * freg: FPU register
  1286. not used = Free
  1287. Warning: vreg0 may be Free but vreg1 not!
  1288. *)
  1289. PROCEDURE GenSaveRegisters(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1290. VAR pos, i: Register; t: PCLIR.Register;
  1291. BEGIN
  1292. ASSERT((instr.op = PCLIR.saveregs)OR (instr.op = PCLIR.saveregsaligned) ); (* fld *)
  1293. (*PCM.LogWLn; PCM.LogWStr("SaveRegs:");*)
  1294. (*save float regs*)
  1295. pos := 0;
  1296. IF FSP >= 0 THEN (*allocate Stack*)
  1297. PCO.GenTyp1(PCO.SUB, PCO.ImmReg, ESP, noBase, noInx, noScale, noDisp, (FSP+1)*8);
  1298. WHILE FSP >= 0 DO
  1299. PCO.GenFSTP(PCO.RegMem, PCO.lReal, ESP, noInx, noScale, 8*FSP);
  1300. SavedRegisters[SaveLevel, FSP].freg := regFP[FSP];
  1301. regFP[FSP] := Free;
  1302. INC(pos); DEC(FSP)
  1303. END
  1304. END;
  1305. pos := 0;
  1306. FOR i := EAX TO EDI DO
  1307. IF ~(i IN {EBP, ESP}) THEN
  1308. t := Owner(i);
  1309. IF t # Free THEN
  1310. IF t = Splitted THEN
  1311. t := Owner(i+AL);
  1312. IF t # Free THEN
  1313. FreeReg(i+AL)
  1314. END;
  1315. SavedRegisters[SaveLevel, pos].vreg0 := t;
  1316. t := Owner(i+AH);
  1317. IF t # Free THEN
  1318. FreeReg(i+AH)
  1319. END;
  1320. SavedRegisters[SaveLevel, pos].vreg1 := t
  1321. ELSE
  1322. FreeReg(i);
  1323. SavedRegisters[SaveLevel, pos].vreg0 := t;
  1324. SavedRegisters[SaveLevel, pos].vreg1 := Free
  1325. END;
  1326. PCO.GenPUSH(PCO.Regs, i, noBase, noInx, noScale, noDisp, noImm);
  1327. INC(pos)
  1328. END;
  1329. END
  1330. END;
  1331. FOR i := pos TO 7 DO
  1332. SavedRegisters[SaveLevel, i].vreg0 := Free;
  1333. SavedRegisters[SaveLevel, i].vreg1 := Free
  1334. END;
  1335. (* CheckAllFree; *)
  1336. (* INC(SaveLevel); *)
  1337. IncSaveLevel;
  1338. END GenSaveRegisters;
  1339. PROCEDURE GenRestoreRegisters(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1340. VAR vreg0, vreg1, saved: PCLIR.Register; reg, dummy: Register; size, pos: LONGINT;
  1341. BEGIN
  1342. ASSERT(instr.op = PCLIR.loadregs);
  1343. DEC(SaveLevel);
  1344. pos := 5;
  1345. WHILE pos >= 0 DO
  1346. vreg0 := SavedRegisters[SaveLevel, pos].vreg0;
  1347. vreg1 := SavedRegisters[SaveLevel, pos].vreg1;
  1348. IF (vreg0 # Free) OR (vreg1 # Free) THEN
  1349. size := 1;
  1350. IF vreg0 # Free THEN
  1351. size := PCLIR.NofBytes(PCLIR.SizeOf(code, vreg0))
  1352. END;
  1353. IF size IN {2, 4} THEN
  1354. (* always pop 32-bit register, even when only 16-bit data required. POP with 16 is troublesome *)
  1355. reg := AllocateReg(code, vreg0) MOD 8
  1356. ELSIF size = 1 THEN (*A whole 32-bit register must be used for pop; get free reg, without allocating it!*)
  1357. GetTempReg32(reg);
  1358. IF vreg0 # Free THEN AllocateThisReg(code, vreg0, reg+AL) END;
  1359. IF vreg1 # Free THEN AllocateThisReg(code, vreg1, reg+AH) END
  1360. ELSE HALT(99)
  1361. END;
  1362. PCO.GenPOP(PCO.Regs, reg, noBase, noInx, noScale, noDisp)
  1363. END;
  1364. DEC(pos)
  1365. END;
  1366. IF SavedRegisters[SaveLevel, 0].freg # 0 THEN
  1367. saved := Free;
  1368. IF FSP = 0 THEN
  1369. PCO.GenTyp1(PCO.SUB, PCO.ImmReg, ESP, noBase, noInx, noScale, noDisp, 8);
  1370. PCO.GenFSTP(PCO.RegMem, PCO.lReal, ESP, noInx, noScale, 0);
  1371. saved := regFP[0];
  1372. FreeReg(24+0)
  1373. END;
  1374. ASSERT(FSP = -1);
  1375. pos := 0;
  1376. WHILE SavedRegisters[SaveLevel, pos].freg # 0 DO
  1377. IF saved # Free THEN
  1378. PCO.GenFLD(PCO.Mem, PCO.lReal, ESP, noInx, noScale, 8*(pos+1))
  1379. ELSE
  1380. PCO.GenFLD(PCO.Mem, PCO.lReal, ESP, noInx, noScale, 8*pos)
  1381. END;
  1382. dummy := AllocateReg(code, SavedRegisters[SaveLevel, pos].freg);
  1383. SavedRegisters[SaveLevel, pos].freg := Free;
  1384. INC(pos)
  1385. END;
  1386. IF saved # Free THEN
  1387. dummy := AllocateReg(code, saved);
  1388. PCO.GenFLD(PCO.Mem, PCO.lReal, ESP, noInx, noScale, 0);
  1389. INC(pos)
  1390. END;
  1391. PCO.GenTyp1(PCO.ADD, PCO.ImmReg, ESP, noBase, noInx, noScale, noDisp, pos*8)
  1392. END
  1393. END GenRestoreRegisters;
  1394. PROCEDURE GenPop(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1395. VAR reg: Register;
  1396. BEGIN
  1397. ASSERT(instr.dstSize IN PCLIR.IntSize);
  1398. reg := AllocateRegI(code, instr, pc);
  1399. PCO.GenPOP(PCO.Regs, reg, noBase, noInx, noScale, noDisp)
  1400. END GenPop;
  1401. (* GenResult - Allocate the registers for functions results (after a call) *)
  1402. PROCEDURE GenResult(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1403. VAR size: PCLIR.Size; reg: Register;
  1404. BEGIN
  1405. size := instr.dstSize;
  1406. IF size IN PCLIR.FloatSize THEN
  1407. reg := AllocateRegI(code, instr, pc)
  1408. ELSIF size = PCLIR.Int64 THEN
  1409. AllocateThisRegI2(instr, pc, EAX, EDX)
  1410. ELSIF instr.op = PCLIR.result THEN
  1411. AllocateThisRegI(instr, pc, RegisterA(size))
  1412. ELSIF instr.op = PCLIR.result2 THEN
  1413. AllocateThisRegI(instr, pc, RegisterD(size))
  1414. ELSE
  1415. HALT(99)
  1416. END
  1417. END GenResult;
  1418. (* GenReturn - Pass a value to the caller *)
  1419. PROCEDURE GenReturn(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1420. VAR reg: Register; info: Address; p: PCLIR.Piece; pos: LONGINT; size: PCLIR.Size; src: RealAddress;
  1421. BEGIN
  1422. pos := instr.src1; code.GetPiece(pos, p); info := SYSTEM.VAL(Address, p.instr[pos].info);
  1423. size := p.instr[pos].dstSize;
  1424. IF size IN PCLIR.FloatSize THEN
  1425. ASSERT(instr.op = PCLIR.ret);
  1426. ASSERT(info.i386 = 24 + FSP) (*must be ST(0)*)
  1427. ELSIF size = PCLIR.Int64 THEN
  1428. UseComplexI(code, p.instr[pos], src);
  1429. ASSERT(src.mode = PCO.Regs);
  1430. ForceRegister(code, src.base, EAX, {EDX}+MakeMask(src.base2));
  1431. ForceRegister(code, src.base2, EDX, {EAX});
  1432. RETURN
  1433. ELSE
  1434. IF instr.op = PCLIR.ret THEN
  1435. reg := RegisterA(size)
  1436. ELSE
  1437. ASSERT(instr.op = PCLIR.ret2);
  1438. reg := RegisterD(size)
  1439. END;
  1440. IF reg # info.i386 THEN
  1441. ReleaseReg(code, reg, {});
  1442. pc := Owner(info.i386);
  1443. FreeReg(info.i386);
  1444. GetThisReg(reg, pc);
  1445. PCO.GenMOV(PCO.RegReg, reg, info.i386, noInx, noScale, noDisp, noImm);
  1446. info.i386 := reg
  1447. END
  1448. END;
  1449. UseRegisterI(p.instr[pos], reg); (*ignore, use only to anchor the return register*)
  1450. END GenReturn;
  1451. (* LoadReg - Load a complex src into a register *)
  1452. PROCEDURE LoadReg(reg: Register; src: RealAddress);
  1453. BEGIN
  1454. IF reg IN RegFP THEN
  1455. ASSERT(reg-24 = FSP); (*Top of FPStack*)
  1456. ASSERT(src.mode IN {PCO.Mem, PCO.MemA});
  1457. PCO.GenFLD(src.mode, FPSize[src.size], src.base, src.index, src.scale, src.disp)
  1458. ELSIF (src.mode = PCO.Imme) & (src.addr # NIL) THEN
  1459. PCO.GenLEA(src.addr # NIL, reg, noBase, noInx, noScale, src.imm)
  1460. ELSIF (src.mode = PCO.Imme) & (src.imm = 0)THEN
  1461. PCO.GenTyp1(PCO.XOR, PCO.RegReg, reg, reg, noInx, noScale, noDisp, noImm)
  1462. ELSE
  1463. PCO.GenMOV(src.mode, reg, src.base, src.index, src.scale, src.disp, src.imm)
  1464. END;
  1465. FixAbsolute(src.addr, -4)
  1466. END LoadReg;
  1467. PROCEDURE LoadRegHi(reg: Register; src: RealAddress);
  1468. BEGIN
  1469. ASSERT(reg IN RegI);
  1470. ASSERT((src.mode # PCO.Imme) OR (src.addr = NIL));
  1471. IF (src.mode = PCO.Imme) & (src.imm = 0)THEN
  1472. PCO.GenTyp1(PCO.XOR, PCO.RegReg, reg, reg, noInx, noScale, noDisp, noImm)
  1473. ELSE
  1474. PCO.GenMOV(src.mode, reg, src.base2, src.index, src.scale, src.disp+4, src.imm2)
  1475. END;
  1476. FixAbsolute(src.addr, -4)
  1477. END LoadRegHi;
  1478. (* GenLoad - Load / Lea implementation *)
  1479. PROCEDURE GenLoad(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1480. VAR addr: RealAddress; op: PCLIR.Opcode; reg, reg2: Register; info: Address;
  1481. BEGIN
  1482. op := instr.op;
  1483. ASSERT((op=PCLIR.load) OR (op=PCLIR.loadc));
  1484. IF instr.dstSize = PCLIR.Int64 THEN
  1485. AllocateRegI2(code, instr, pc, reg, reg2); (*allocate before using to avoid overwriting a register*)
  1486. UseComplexI(code, instr, addr); (*exception 1, instr.addr contains the source*)
  1487. LoadReg(reg, addr); LoadRegHi(reg2, addr)
  1488. ELSE
  1489. UseComplexI(code, instr, addr); (*exception 1, instr.addr contains the source*)
  1490. reg := AllocateRegI(code, instr, pc);
  1491. LoadReg(reg, addr)
  1492. END;
  1493. ASSERT(instr.dstSize = addr.size);
  1494. info := SYSTEM.VAL(Address, instr.info);
  1495. info.mode := 0; (*Register=pc*)
  1496. END GenLoad;
  1497. PROCEDURE GenLoadSP(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1498. VAR src: RealAddress;
  1499. BEGIN
  1500. UseComplex(code, instr.src1, src);
  1501. IF (src.mode # PCO.Regs) OR (src.base # ESP) THEN (* source already in ESP *)
  1502. LoadReg(ESP, src);
  1503. END
  1504. END GenLoadSP;
  1505. PROCEDURE GenLoadFP(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1506. VAR src: RealAddress;
  1507. BEGIN
  1508. UseComplex(code, instr.src1, src);
  1509. IF (src.mode # PCO.Regs) OR (src.base # EBP) THEN (* source already in EBP *)
  1510. LoadReg(EBP, src);
  1511. END
  1512. END GenLoadFP;
  1513. PROCEDURE GenStore(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1514. VAR src, dst: RealAddress;
  1515. BEGIN
  1516. ASSERT(instr.op = PCLIR.store, 100);
  1517. UseComplex(code, instr.src2, src); ASSERT(src.mode IN {PCO.Regs, PCO.Imme, PCO.ImmeA, PCO.Mem, PCO.MemA}, 101);
  1518. UseComplexI(code, instr, dst); ASSERT(dst.mode IN {PCO.Regs, PCO.Mem, PCO.MemA}, 102);
  1519. ASSERT( ~(dst.mode IN {PCO.Mem, PCO.MemA} ) OR (src.mode IN {PCO.Regs, PCO.Imme, PCO.ImmeA}), 103);
  1520. IF src.size IN PCLIR.FloatSize THEN
  1521. ASSERT(src.mode = PCO.Regs);
  1522. ASSERT(dst.mode # PCO.ImmeA);
  1523. PCO.GenFSTP(dst.mode+(PCO.RegMem-PCO.Mem), FPSize[src.size], dst.base, dst.index, dst.scale, dst.disp);
  1524. FixAbsolute(dst.addr, -4);
  1525. PCO.PutByte(PCO.wWAIT)
  1526. ELSIF src.size = PCLIR.Int64 THEN
  1527. IF dst.mode = PCO.Regs THEN
  1528. HALT(99)
  1529. ELSIF src.mode IN {PCO.Imme, PCO.ImmeA} THEN
  1530. PCO.GenMOV(dst.mode+(PCO.ImmMem-PCO.Mem), src.base, dst.base, dst.index, dst.scale, dst.disp, src.imm);
  1531. FixAbsolute(dst.addr, -4-RegisterSize(src.base)); (*MOV r/m, imm: compensate imm size*)
  1532. FixAbsolute(src.addr, -4);
  1533. PCO.GenMOV(dst.mode+(PCO.ImmMem-PCO.Mem), src.base2, dst.base2, dst.index, dst.scale, dst.disp+4, src.imm2);
  1534. FixAbsolute(dst.addr, -4-RegisterSize(src.base2)); (*MOV r/m, imm: compensate imm size*)
  1535. FixAbsolute(src.addr, -4)
  1536. ELSE
  1537. dst.mode := dst.mode+(PCO.RegMem-PCO.Mem);
  1538. LoadReg(src.base, dst);
  1539. LoadRegHi(src.base2, dst);
  1540. END
  1541. ELSIF dst.mode = PCO.Regs THEN
  1542. LoadReg(dst.base, src);
  1543. ELSIF src.mode IN {PCO.Imme, PCO.ImmeA} THEN
  1544. PCO.GenMOV(dst.mode+(PCO.ImmMem-PCO.Mem), src.base, dst.base, dst.index, dst.scale, dst.disp, src.imm);
  1545. FixAbsolute(dst.addr, -4-RegisterSize(src.base)); (*MOV r/m, imm: compensate imm size*)
  1546. FixAbsolute(src.addr, -4)
  1547. ELSE
  1548. dst.mode := dst.mode+(PCO.RegMem-PCO.Mem);
  1549. LoadReg(src.base, dst);
  1550. END;
  1551. END GenStore;
  1552. PROCEDURE GenOut(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1553. (* src1 = portnr, src2 = value *)
  1554. VAR src: RealAddress; value, port: Register;
  1555. BEGIN
  1556. UseComplex(code, instr.src2, src); ASSERT(src.mode = PCO.Regs);
  1557. value := RegisterA(src.size);
  1558. ForceRegister(code, src.base, value, {DX});
  1559. UseRegister(code, instr.src1, port);
  1560. ForceRegister(code, port, DX, {value});
  1561. PCO.GenOUT(value)
  1562. END GenOut;
  1563. PROCEDURE GenIn(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1564. (* src1 = portnr *)
  1565. VAR value, port: Register;
  1566. BEGIN
  1567. value := RegisterA(instr.dstSize);
  1568. UseRegister(code, instr.src1, port);
  1569. ForceRegister(code, port, DX, {value});
  1570. ReleaseReg(code, value, {DX});
  1571. PCO.GenIN(value);
  1572. AllocateThisRegI(instr, pc, value);
  1573. END GenIn;
  1574. PROCEDURE GenNop(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1575. BEGIN PCO.PutByte(90H)
  1576. END GenNop;
  1577. PROCEDURE GenLabel(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1578. VAR info: Address; next: LONGINT;
  1579. BEGIN
  1580. info := SYSTEM.VAL(Address, instr.info);
  1581. info.imm := PCO.pc;
  1582. pc := info.disp;
  1583. WHILE pc > none (*fof # -> > *) DO
  1584. PCO.GetDWord(pc, next); PCO.PutDWordAt(pc, PCO.pc-pc-4);
  1585. pc := next - 10000H
  1586. END;
  1587. IF instr.val # 0 THEN PCO.errpos := instr.val END;
  1588. IF (instr.op = PCLIR.finallylabel) THEN
  1589. IF (instr.adr # NIL) THEN
  1590. IF (instr.adr IS PCBT.Procedure) THEN
  1591. instr.adr(PCBT.Procedure).finallyOff := info.imm;
  1592. ELSIF (instr.adr IS PCBT.Module) THEN
  1593. instr.adr(PCBT.Module).finallyOff := info.imm;
  1594. END;
  1595. END;
  1596. END;
  1597. END GenLabel;
  1598. PROCEDURE EmitJcc(op: SHORTINT; dest: LONGINT; VAR chain: LONGINT);
  1599. BEGIN
  1600. IF dest = 0 THEN (*fwd jmp*)
  1601. PCO.GenJcc(op, chain+10000H);
  1602. chain := PCO.pc-4
  1603. ELSIF PCO.pc - dest <= 126 THEN (*near jmp*)
  1604. PCO.GenJcc(op, dest - PCO.pc - 2) (* jcc Rel8: has 2 bytes*)
  1605. ELSE
  1606. PCO.GenJcc(op, dest - PCO.pc - 6) (* jcc Rel32: has 6 bytes*)
  1607. END
  1608. END EmitJcc;
  1609. PROCEDURE GenJcc(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1610. VAR info: Address; pos, fix: LONGINT; p: PCLIR.Piece; jcc: SHORTINT; src1, src2: RealAddress;
  1611. BEGIN
  1612. UseComplex(code, instr.src1, src1); UseComplex(code, instr.src2, src2);
  1613. pos := instr.val; code.GetPiece(pos, p);
  1614. info := SYSTEM.VAL(Address, p.instr[pos].info);
  1615. fix := none;
  1616. IF src1.size = PCLIR.Int64 THEN
  1617. ASSERT((instr.op >= PCLIR.je) & (instr.op <= PCLIR.jge));
  1618. (*compare upper dw*)
  1619. GenCmp2(code, src1, src2);
  1620. jcc := Jcc2Opcode[instr.op-PCLIR.je, 0]; (*hit*)
  1621. IF jcc # 0 THEN EmitJcc(jcc, info.imm, info.disp) END;
  1622. jcc := Jcc2Opcode[instr.op-PCLIR.je, 1]; (*fail*)
  1623. IF jcc # 0 THEN EmitJcc(jcc, 0, fix) END;
  1624. (*compare lower dw*)
  1625. GenCmp1(code, src1, src2);
  1626. jcc := Jcc2Opcode[instr.op-PCLIR.je, 2]; (*hit*)
  1627. EmitJcc(jcc, info.imm, info.disp);
  1628. IF fix # none THEN PCO.PutDWordAt(fix, PCO.pc - fix - 4) END
  1629. ELSIF (instr.op = PCLIR.jf) OR (instr.op = PCLIR.jnf) THEN
  1630. GenBitTest(code, src1, src2);
  1631. jcc := JccOpcode[instr.op-PCLIR.je, CCTableSwitch];
  1632. EmitJcc(jcc, info.imm, info.disp);
  1633. ELSE
  1634. GenCmp1(code, src1, src2);
  1635. jcc := JccOpcode[instr.op-PCLIR.je, CCTableSwitch];
  1636. EmitJcc(jcc, info.imm, info.disp);
  1637. END;
  1638. END GenJcc;
  1639. PROCEDURE GenJmp(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1640. VAR info: Address; pos: LONGINT; p: PCLIR.Piece;
  1641. BEGIN
  1642. pos := instr.val; code.GetPiece(pos, p);
  1643. info := SYSTEM.VAL(Address, p.instr[pos].info);
  1644. IF info.imm = 0 THEN (*fwd jmp*)
  1645. PCO.GenJMP(PCO.Imme, noBase, noBase, noInx, noScale, info.disp+10000H);
  1646. info.disp := PCO.pc-4
  1647. ELSIF PCO.pc - info.imm <= 126 THEN (*near jmp*)
  1648. PCO.GenJMP(PCO.Imme, noBase, noBase, noInx, noScale, info.imm - PCO.pc - 2)
  1649. ELSE
  1650. PCO.GenJMP(PCO.Imme, noBase, noBase, noInx, noScale, info.imm - PCO.pc - 5)
  1651. END
  1652. END GenJmp;
  1653. PROCEDURE GenCall(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1654. VAR adr: PCBT.Procedure;
  1655. BEGIN
  1656. adr := instr.adr(PCBT.Procedure);
  1657. IF (adr.owner # PCBT.context) THEN (* external procedure *)
  1658. PCO.GenCALL(PCO.ImmeA, 0, noBase, noInx, noScale, 0);
  1659. PCBT.context.UseProcedure(adr, PCO.pc-4)
  1660. ELSIF adr.codeoffset # 0 THEN
  1661. PCO.GenCALL(PCO.Imme, 0, noBase, noInx, noScale, adr.codeoffset - PCO.pc - 5)
  1662. ELSE (*local call*)
  1663. PCO.GenCALL(PCO.Imme, 0, noBase, noInx, noScale, adr.fixlist);
  1664. adr.fixlist := PCO.pc-4
  1665. (*
  1666. ELSE (* external procedure *)
  1667. PCO.GenCALL(PCO.ImmeA, 0, noBase, noInx, noScale, 0);
  1668. PCBT.context.UseProcedure(adr, PCO.pc-4)
  1669. *)
  1670. END
  1671. END GenCall;
  1672. PROCEDURE GenCallReg(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1673. VAR src: RealAddress; mode: SHORTINT;
  1674. BEGIN
  1675. UseComplex(code, instr.src1, src);
  1676. mode := src.mode;
  1677. ASSERT(mode IN {PCO.Regs, PCO.Mem, PCO.MemA});
  1678. PCO.GenCALL(mode, src.base, src.base, src.index, src.scale, src.disp);
  1679. FixAbsolute(src.addr, -4)
  1680. END GenCallReg;
  1681. PROCEDURE GenSysCall(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1682. BEGIN
  1683. PCO.GenCALL(PCO.ImmeA, 0, noBase, noInx, noScale, 0);
  1684. PCBT.context.UseSyscall(instr.val, PCO.pc-4)
  1685. END GenSysCall;
  1686. PROCEDURE GenSetcc(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1687. VAR reg: Register; jcc, op: SHORTINT; src1, src2: RealAddress; true1, true2, false: LONGINT;
  1688. BEGIN
  1689. UseComplex(code, instr.src1, src1); UseComplex(code, instr.src2, src2);
  1690. IF src1.size = PCLIR.Int64 THEN
  1691. false := 0; true1 := 0; true2 := 0; (* fof, variables were not initialized, even not implicitly by EmitJcc ! *)
  1692. reg := AllocateRegI(code, instr, pc);
  1693. GenCmp2(code, src1, src2);
  1694. jcc := Jcc2Opcode[instr.op-PCLIR.sete, 0]; (*hit*)
  1695. IF jcc # 0 THEN EmitJcc(jcc, 0, true1) END;
  1696. jcc := Jcc2Opcode[instr.op-PCLIR.sete, 1]; (*fail*)
  1697. IF jcc # 0 THEN EmitJcc(jcc, 0, false) END;
  1698. (*compare lower dw*)
  1699. GenCmp1(code, src1, src2);
  1700. jcc := Jcc2Opcode[instr.op-PCLIR.sete, 2]; (*hit*)
  1701. EmitJcc(jcc, 0, true2);
  1702. IF false # 0 THEN PCO.PutDWordAt(false, PCO.pc - false - 4) END; (* fof: false # none -> false # 0 *)
  1703. PCO.GenTyp1(PCO.XOR, PCO.RegReg, reg, reg, noInx, noScale, noDisp, noImm);
  1704. PCO.GenJMP(PCO.Imme, noBase, noBase, noInx, noScale, 0); false := PCO.pc-1;
  1705. IF true1 # 0 THEN PCO.PutDWordAt(true1, PCO.pc - true1 - 4) END;
  1706. IF true2 # 0 THEN PCO.PutDWordAt(true2, PCO.pc - true2 - 4) END;
  1707. PCO.GenMOV(PCO.ImmReg, reg, reg, noInx, noScale, noDisp, 1);
  1708. PCO.PutByteAt(false, SHORT(SHORT(PCO.pc-false-1)));
  1709. ELSIF (instr.op = PCLIR.setf) OR (instr.op = PCLIR.setnf) THEN
  1710. reg := AllocateRegI(code, instr, pc);
  1711. GenBitTest(code, src1, src2);
  1712. op := JccOpcode[instr.op-PCLIR.sete, CCTableSwitch];
  1713. PCO.GenSetcc(op, PCO.Regs, reg, noInx, noScale, noDisp)
  1714. ELSE
  1715. (*
  1716. WARNING: do not allocate the destination register before GenCmp1.
  1717. GenCmp1 for floats needs AX to store the flags; if the destination is EAX (like when returning
  1718. a comparison) GenCmp1 will spill the register. The result would be still stored in EAX, and
  1719. then could be overwritten with the spilled (but not set) register in GenRet
  1720. *)
  1721. GenCmp1(code, src1, src2);
  1722. reg := AllocateRegI(code, instr, pc);
  1723. op := JccOpcode[instr.op-PCLIR.sete, CCTableSwitch];
  1724. PCO.GenSetcc(op, PCO.Regs, reg, noInx, noScale, noDisp)
  1725. END;
  1726. END GenSetcc;
  1727. PROCEDURE GenKill(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1728. VAR pos: LONGINT; p: PCLIR.Piece; reg: Register; info: Address;
  1729. BEGIN
  1730. (*kill a register, used in conjunction with phi*)
  1731. pos := instr.src1; code.GetPiece(pos, p);
  1732. info := SYSTEM.VAL(Address, p.instr[pos].info);
  1733. UseRegisterI(p.instr[pos], reg); (*register used*)
  1734. pos := info.alias;
  1735. IF pos # none THEN
  1736. code.GetPiece(pos, p);
  1737. info := SYSTEM.VAL(Address, p.instr[pos].info);
  1738. IF reg # info.i386 THEN
  1739. ReleaseReg(code, info.i386, {});
  1740. PCO.GenMOV(PCO.RegReg, info.i386, reg, noInx, noScale, noDisp, noImm)
  1741. END
  1742. END;
  1743. (*
  1744. FreeReg(reg);
  1745. *)
  1746. END GenKill;
  1747. PROCEDURE GenPhi(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1748. VAR reg: Register;
  1749. BEGIN
  1750. reg := AllocateRegI(code, instr, pc)
  1751. END GenPhi;
  1752. PROCEDURE GenPush(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1753. VAR dst: RealAddress; reg: Register; size: LONGINT;
  1754. BEGIN
  1755. UseComplex(code, instr.src1, dst);
  1756. size := PCLIR.NofBytes(dst.size);
  1757. IF dst.mode IN {PCO.Mem, PCO.MemA} THEN
  1758. IF dst.size IN {PCLIR.Int16, PCLIR.Int64, PCLIR.Float32, PCLIR.Float64} THEN dst.size := PCLIR.Int32 END;
  1759. IF size = 8 THEN INC(dst.disp, 4) END;
  1760. WHILE size > 0 DO
  1761. PCO.GenPUSH(dst.mode, RegisterA(dst.size), dst.base, dst.index, dst.scale, dst.disp, dst.imm);
  1762. FixAbsolute(dst.addr, -4);
  1763. DEC(dst.disp, 4); DEC(size, 4)
  1764. END
  1765. ELSIF dst.size IN PCLIR.FloatSize THEN
  1766. PCO.GenTyp1(PCO.SUB, PCO.ImmReg, ESP, noBase, noInx, noScale, noDisp, size); (*allocate*)
  1767. PCO.GenFSTP(PCO.RegMem, FPSize[dst.size], ESP, noInx, noScale, 0); (*FSTP 0[ESP]*)
  1768. ELSE
  1769. IF dst.size = PCLIR.Int8 THEN
  1770. IF dst.base IN Reg8H THEN
  1771. GetReg(reg, 1, pc, Reg8L);
  1772. PCO.GenMOV(PCO.RegReg, reg, dst.base, noInx, noScale, noDisp, noImm);
  1773. dst.base := reg;
  1774. FreeReg(reg)
  1775. END;
  1776. ELSIF PCLIR.Int16 = dst.size THEN dst.base := dst.base MOD 8
  1777. END;
  1778. IF dst.size = PCLIR.Int64 THEN
  1779. PCO.GenPUSH(dst.mode, dst.base2, dst.base, dst.index, dst.scale, dst.disp+4, dst.imm2);
  1780. FixAbsolute(dst.addr, -4)
  1781. END;
  1782. PCO.GenPUSH(dst.mode, dst.base, dst.base, dst.index, dst.scale, dst.disp, dst.imm);
  1783. FixAbsolute(dst.addr, -4)
  1784. END
  1785. END GenPush;
  1786. PROCEDURE IntExpansion(op: PCLIR.Opcode; src: RealAddress; dst: Register);
  1787. VAR t: SHORTINT; size: LONGINT;
  1788. BEGIN
  1789. size := PCLIR.NofBytes(src.size);
  1790. IF size = 1 THEN t := 0 ELSE t := 1 END;
  1791. IF op = PCLIR.convs THEN (*signed extension*)
  1792. PCO.GenMOVSX(src.mode, t, dst, src.base, src.index, src.scale, src.disp);
  1793. FixAbsolute(src.addr, -4)
  1794. ELSIF RegisterOverlaps(dst, src.base) OR RegisterOverlaps(dst, src.index) THEN
  1795. PCO.GenMOVZX(src.mode, t, dst, src.base, src.index, src.scale, src.disp);
  1796. FixAbsolute(src.addr, -4)
  1797. ELSE
  1798. (* optimize pattern: Pentium Manual, 24.5 /3 (p.24-4)*)
  1799. dst := dst MOD 8;
  1800. PCO.GenTyp1(PCO.XOR, PCO.RegReg, dst, dst, noInx, noScale, noDisp, noImm);
  1801. IF size = 1 THEN INC(dst, AL) ELSE INC(dst, AX) END;
  1802. LoadReg(dst, src);
  1803. (*
  1804. PCO.GenMOV(src.mode, dst, src.base, src.index, src.scale, src.disp, src.imm);
  1805. *)
  1806. END;
  1807. (*
  1808. FixAbsolute(src.addr, -4)
  1809. *)
  1810. END IntExpansion;
  1811. PROCEDURE Entier(dst, dst2: Register; dest64: BOOLEAN);
  1812. VAR reg: Register; size: LONGINT;
  1813. BEGIN
  1814. GetTempReg32(reg);
  1815. IF dest64 THEN size := 12 ELSE size := 8 END;
  1816. PCO.GenTyp1(PCO.SUB, PCO.ImmReg, ESP, noBase, noInx, noScale, noDisp, size);
  1817. PCO.GenFSTCW(ESP, noInx, noScale, 0);
  1818. PCO.PutByte(PCO.wWAIT);
  1819. PCO.GenMOV(PCO.MemReg, reg, ESP, noInx, noScale, 0, noImm);
  1820. PCO.GenTyp1(PCO.AND, PCO.ImmReg, reg, noBase, noInx, noScale, noDisp, 0F3FFH);
  1821. PCO.GenTyp1(PCO.Or, PCO.ImmReg, reg, noBase, noInx, noScale, noDisp, 0400H);
  1822. PCO.GenMOV(PCO.RegMem, reg, ESP, noInx, noScale, 4, noImm);
  1823. PCO.GenFLDCW(ESP, noInx, noScale, 4);
  1824. IF dest64 THEN
  1825. PCO.GenFSTP(PCO.RegMem, PCO.qInt, ESP, noInx, noScale, 4)
  1826. ELSE
  1827. PCO.GenFSTP(PCO.RegMem, PCO.dInt, ESP, noInx, noScale, 4)
  1828. END;
  1829. PCO.PutByte(PCO.wWAIT);
  1830. PCO.GenFLDCW(ESP, noInx, noScale, 0);
  1831. PCO.GenPOP(PCO.Regs, dst, noBase, noInx, noScale, noDisp);
  1832. PCO.GenPOP(PCO.Regs, dst, noBase, noInx, noScale, noDisp);
  1833. IF dest64 THEN PCO.GenPOP(PCO.Regs, dst2, noBase, noInx, noScale, noDisp) END;
  1834. END Entier;
  1835. PROCEDURE GenConv(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1836. VAR op: PCLIR.Opcode; size, bs, bd: LONGINT; reg, reg2, tmp: Register; src: RealAddress;
  1837. BEGIN
  1838. op := instr.op;
  1839. ASSERT((op = PCLIR.convs) OR (op = PCLIR.convu) OR (op = PCLIR.copy));
  1840. UseComplex(code, instr.src1, src);
  1841. bs := PCLIR.NofBytes(src.size); bd := PCLIR.NofBytes(instr.dstSize);
  1842. IF instr.dstSize IN PCLIR.FloatSize THEN
  1843. reg := AllocateRegI(code, instr, pc);
  1844. IF (src.size IN PCLIR.FloatSize) & (src.mode = PCO.Regs) THEN RETURN END;
  1845. IF src.size = PCLIR.Int8 THEN (* no FILD for byte size available, first expand to double *)
  1846. GetReg(tmp, 4, pc, Reg32);
  1847. FreeReg(tmp);
  1848. IntExpansion(op, src, tmp);
  1849. src.mode := PCO.Regs; src.base := tmp; src.size := PCLIR.Int32;
  1850. END;
  1851. IF op = PCLIR.copy THEN size := instr.dstSize ELSE size := src.size END;
  1852. IF src.mode # PCO.Regs THEN
  1853. PCO.GenFLD(src.mode, FPSize[size], src.base, src.index, src.scale, src.disp);
  1854. FixAbsolute(src.addr, -4);
  1855. ELSIF size IN {PCLIR.Int64, PCLIR.Float64} THEN
  1856. PCO.GenPUSH(PCO.Regs, src.base2, noBase, noInx, noScale, noDisp, noImm);
  1857. PCO.GenPUSH(PCO.Regs, src.base, noBase, noInx, noScale, noDisp, noImm);
  1858. PCO.GenFLD(PCO.Mem, FPSize[size], ESP, noInx, noScale, 0);
  1859. PCO.GenTyp1(PCO.ADD, PCO.ImmReg, ESP, noBase, noInx, noScale, noDisp, 8)
  1860. ELSE
  1861. PCO.GenPUSH(PCO.Regs, src.base MOD 8, noBase, noInx, noScale, noDisp, noImm); (*push 32bit reg always*)
  1862. PCO.GenFLD(PCO.Mem, FPSize[size], ESP, noInx, noScale, 0);
  1863. PCO.GenTyp1(PCO.ADD, PCO.ImmReg, ESP, noBase, noInx, noScale, noDisp, 4)
  1864. END
  1865. ELSIF src.size IN PCLIR.FloatSize THEN
  1866. IF op = PCLIR.copy THEN
  1867. IF instr.dstSize = PCLIR.Int64 THEN
  1868. AllocateRegI2(code, instr, pc, reg, reg2);
  1869. PCO.GenTyp1(PCO.SUB, PCO.ImmReg, ESP, noBase, noInx, noScale, noDisp, 8);
  1870. PCO.GenFSTP(PCO.RegMem, PCO.lReal, ESP, noInx, noScale, 0); (*FSTP quad ptr 0[ESP]*)
  1871. PCO.GenPOP(PCO.Regs, reg, noBase, noInx, noScale, noDisp);
  1872. PCO.GenPOP(PCO.Regs, reg2, noBase, noInx, noScale, noDisp);
  1873. ELSE
  1874. reg := AllocateRegI(code, instr, pc);
  1875. PCO.GenTyp1(PCO.SUB, PCO.ImmReg, ESP, noBase, noInx, noScale, noDisp, 4);
  1876. PCO.GenFSTP(PCO.RegMem, PCO.sReal, ESP, noInx, noScale, 0); (*FSTP double ptr 0[ESP]*)
  1877. IF bd = 2 THEN reg := reg MOD 8 END; (*16-> 32 bit*)
  1878. PCO.GenPOP(PCO.Regs, reg, noBase, noInx, noScale, noDisp)
  1879. END
  1880. ELSIF instr.dstSize = PCLIR.Int64 THEN
  1881. AllocateRegI2(code, instr, pc, reg, reg2);
  1882. Entier(reg, reg2, TRUE)
  1883. ELSE
  1884. reg := AllocateRegI(code, instr, pc);
  1885. Entier(reg, none, FALSE)
  1886. END
  1887. ELSIF bd <= bs THEN (* truncate, dst <= src *)
  1888. ASSERT(src.mode = PCO.Regs, 100);
  1889. reg := src.base;
  1890. IF (bs = bd) OR (bs = 8) & (bd = 4) THEN (* x -> x *)
  1891. (*skip*)
  1892. ELSIF (bs IN {4, 8}) & (bd = 1) THEN (* 64/32->8 *)
  1893. INC(reg, AL)
  1894. ELSIF (bs IN {4, 8}) & (bd = 2) THEN (* 64/32->16 *)
  1895. INC(reg, AX)
  1896. ELSIF (bs = 2) & (bd = 1) THEN (* 16->8 *)
  1897. INC(reg, AL-AX)
  1898. ELSE
  1899. HALT(99)
  1900. END;
  1901. AllocateThisRegI(instr, pc, reg)
  1902. ELSIF bd = 8 THEN
  1903. IF (Owner(EAX) = Free) & (Owner(EDX) = Free) THEN
  1904. AllocateThisRegI2(instr, pc, EAX, EDX); reg := EAX; reg2 := EDX
  1905. ELSE
  1906. AllocateRegI2(code, instr, pc, reg, reg2)
  1907. END;
  1908. IF bs = 4 THEN
  1909. IF (src.mode # PCO.RegReg) & (src.base # EAX) THEN
  1910. LoadReg(reg, src);
  1911. ELSIF (src.mode = PCO.RegReg) & (src.base # reg) THEN
  1912. PCO.GenMOV(src.mode, reg, src.base, src.index, src.scale, src.disp, noImm)
  1913. END
  1914. ELSE
  1915. IntExpansion(op, src, reg)
  1916. END;
  1917. IF (reg = EAX) & (reg2 = EDX) THEN
  1918. PCO.PutByte(99H) (* CDQ *)
  1919. ELSE
  1920. PCO.GenMOV(PCO.RegReg, reg2, reg, noInx, noScale, noDisp, noImm);
  1921. PCO.GenShiftRot(PCO.SAR, PCO.ImmReg, reg2, noBase, noInx, noScale, noDisp, 31)
  1922. END
  1923. ELSE
  1924. reg := AllocateRegI(code, instr, pc);
  1925. IntExpansion(op, src, reg)
  1926. END
  1927. END GenConv;
  1928. PROCEDURE GenNegNot(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1929. VAR reg, reg2: Register;
  1930. BEGIN
  1931. IF instr.dstSize IN PCLIR.FloatSize THEN
  1932. UseRegister(code, instr.src1, reg);
  1933. ASSERT(reg = 25 + FSP, 200);
  1934. ASSERT(instr.op = PCLIR.neg, 201);
  1935. reg := AllocateRegI(code, instr, pc);
  1936. PCO.PutByte(0D9H); PCO.PutByte(0E0H); (*FCHS*)
  1937. ELSIF instr.dstSize = PCLIR.Int64 THEN
  1938. UseRegister2(code, instr.src1, reg, reg2);
  1939. AllocateThisRegI2(instr, pc, reg, reg2);
  1940. ASSERT(instr.op = PCLIR.neg);
  1941. PCO.GenGroup3(PCO.NEG, PCO.Regs, reg, noBase, noInx, noScale, noDisp);
  1942. PCO.GenTyp1(PCO.ADC, PCO.ImmReg, reg2, noBase, noInx, noScale, noDisp, 0);
  1943. PCO.GenGroup3(PCO.NEG, PCO.Regs, reg2, noBase, noInx, noScale, noDisp)
  1944. ELSE
  1945. UseRegister(code, instr.src1, reg);
  1946. AllocateThisRegI(instr, pc, reg);
  1947. PCO.GenGroup3(Group3Opcode[instr.op-PCLIR.not], PCO.Regs, reg, noBase, noInx, noScale, noDisp)
  1948. END
  1949. END GenNegNot;
  1950. PROCEDURE GenAbs(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1951. VAR reg, tmp: Register; size: LONGINT;
  1952. BEGIN
  1953. size := PCLIR.NofBytes(instr.dstSize);
  1954. UseRegister(code, instr.src1, reg);
  1955. IF instr.dstSize IN PCLIR.FloatSize THEN
  1956. ASSERT(reg = 25 + FSP);
  1957. reg := AllocateRegI(code, instr, pc);
  1958. PCO.PutByte(0D9H); PCO.PutByte(0E1H); (*FABS*)
  1959. ELSE
  1960. CASE size OF
  1961. | 1:
  1962. ForceRegister(code, reg, AL, MakeMask(AH)); tmp := AH;
  1963. PCO.PutByte(66H); PCO.PutByte(PCO.CBW)
  1964. | 2:
  1965. ForceRegister(code, reg, AX, MakeMask(DX)); tmp := DX;
  1966. PCO.PutByte(66H); PCO.PutByte(PCO.CWD)
  1967. | 4:
  1968. ForceRegister(code, reg, EAX, MakeMask(EDX)); tmp := EDX;
  1969. PCO.PutByte(PCO.CWD)
  1970. END;
  1971. AllocateThisRegI(instr, pc, reg);
  1972. ReleaseReg(code, tmp, MakeMask(reg));
  1973. PCO.GenTyp1(PCO.XOR, PCO.RegReg, reg, tmp, noInx, noScale, noDisp, noImm);
  1974. PCO.GenTyp1(PCO.SUB, PCO.RegReg, reg, tmp, noInx, noScale, noDisp, noImm)
  1975. END
  1976. END GenAbs;
  1977. PROCEDURE GenBitOp(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  1978. VAR reg: Register; src2: RealAddress; op: SHORTINT;
  1979. BEGIN
  1980. UseRegister(code, instr.src1, reg); AllocateThisRegI(instr, pc, reg);
  1981. UseComplex(code, instr.src2, src2);
  1982. ASSERT(src2.mode IN {PCO.Regs, PCO.Imme});
  1983. op := BitOpcode[instr.op-PCLIR.bts];
  1984. PCO.GenB(op, src2.mode, reg, src2.base, noInx, noScale, noDisp, src2.imm)
  1985. END GenBitOp;
  1986. PROCEDURE GenBitTest(code: PCLIR.Code; VAR src1, src2: RealAddress);
  1987. (* Intel: bit number is auto-masked only if source is register!! *)
  1988. BEGIN
  1989. ASSERT(src1.mode IN {PCO.Regs, PCO.Mem, PCO.MemA}, 500);
  1990. ASSERT(src2.mode IN {PCO.Regs, PCO.Imme}, 501);
  1991. IF src1.mode = PCO.Regs THEN
  1992. PCO.GenB(PCO.BT, src2.mode, src1.base, src2.base, noInx, noScale, noDisp, src2.imm)
  1993. ELSIF src2.mode = PCO.Regs THEN
  1994. PCO.GenTyp1(PCO.AND, PCO.ImmReg, src2.base, noBase, noInx, noScale, noDisp, 31);
  1995. PCO.GenB(PCO.BT, src1.mode+(PCO.RegMem-PCO.Mem), src2.base, src1.base, src1.index, src1.scale, src1.disp, src2.imm);
  1996. IF src1.addr # NIL THEN FixAbsolute(src1.addr, -4) END
  1997. ELSE
  1998. src2.imm := src2.imm MOD 32;
  1999. PCO.GenB(PCO.BT, src1.mode+(PCO.ImmMem-PCO.Mem), noBase, src1.base, src1.index, src1.scale, src1.disp, src2.imm);
  2000. IF src1.addr # NIL THEN FixAbsolute(src1.addr, -5) END
  2001. END
  2002. END GenBitTest;
  2003. (* GenCmp1 - Compare src1 with src2 *)
  2004. PROCEDURE GenCmp1(code: PCLIR.Code; VAR src1, src2: RealAddress);
  2005. BEGIN
  2006. CCTableSwitch := intMode; (*default: integer mode*)
  2007. IF src1.size IN PCLIR.FloatSize THEN
  2008. CCTableSwitch := floatMode; (*float mode*)
  2009. ASSERT(src1.mode = PCO.Regs);
  2010. IF src2.mode IN {PCO.Mem, PCO.MemA} THEN
  2011. ASSERT(src1.base = 25 + FSP);
  2012. PCO.GenFCOMP(src2.mode, FPSize[src2.size], src2.base, src2.index, src2.scale, src2.disp);
  2013. FixAbsolute(src2.addr, -4)
  2014. ELSIF src1.base > src2.base THEN (*nice case, cmp ST, ST1*)
  2015. ASSERT(src2.base = 25 + FSP);
  2016. PCO.PutByte(0DEH); PCO.PutByte(0D9H) (*FCOMPP*)
  2017. ELSE
  2018. (* cmp ST1, ST -> swap registers*)
  2019. ASSERT(src1.base = 25 + FSP);
  2020. ASSERT(src2.base = 26 + FSP);
  2021. PCO.PutByte(0D9H); PCO.PutByte(0C9H); (*FXCH*)
  2022. PCO.PutByte(0DEH); PCO.PutByte(0D9H) (*FCOMPP*)
  2023. END;
  2024. ReleaseReg(code, AX, {});
  2025. PCO.PutByte(0DFH); PCO.PutByte(0E0H); (*FNSTSW AX*)
  2026. PCO.PutByte(09EH); (*SAHF*)
  2027. ELSIF src1.mode = PCO.Regs THEN
  2028. PCO.GenTyp1(PCO.CMP, src2.mode, src1.base, src2.base, src2.index, src2.scale, src2.disp, src2.imm);
  2029. FixAbsolute(src2.addr, -4)
  2030. ELSIF src1.mode IN {PCO.Mem, PCO.MemA} THEN
  2031. IF src2.mode = PCO.Regs THEN
  2032. PCO.GenTyp1(PCO.CMP, src1.mode+(PCO.RegMem-PCO.Mem), src2.base, src1.base, src1.index, src1.scale, src1.disp, src1.imm);
  2033. FixAbsolute(src1.addr, -4)
  2034. ELSIF src2.mode IN {PCO.Imme, PCO.ImmeA} THEN
  2035. PCO.GenTyp1(PCO.CMP, src1.mode+(PCO.ImmMem-PCO.Mem), src2.base, src1.base, src1.index, src1.scale, src1.disp, src2.imm);
  2036. FixAbsolute(src1.addr, -4-ConstSize(src2.imm, src1.size = PCLIR.Int16));
  2037. FixAbsolute(src2.addr, -4)
  2038. ELSE HALT(99)
  2039. END
  2040. ELSE HALT(99) END;
  2041. END GenCmp1;
  2042. (* GenCmp2 - Compare higher dw of src1 with src2 *)
  2043. PROCEDURE GenCmp2(code: PCLIR.Code; VAR src1, src2: RealAddress);
  2044. BEGIN
  2045. ASSERT(src1.size = PCLIR.Int64);
  2046. IF src1.mode = PCO.Regs THEN
  2047. PCO.GenTyp1(PCO.CMP, src2.mode, src1.base2, src2.base2, src2.index, src2.scale, src2.disp+4, src2.imm2);
  2048. FixAbsolute(src2.addr, -4)
  2049. ELSIF src1.mode IN {PCO.Mem, PCO.MemA} THEN
  2050. IF src2.mode = PCO.Regs THEN
  2051. PCO.GenTyp1(PCO.CMP, src1.mode+(PCO.RegMem-PCO.Mem), src2.base2, src1.base2, src1.index, src1.scale, src1.disp+4, src1.imm2);
  2052. FixAbsolute(src1.addr, -4)
  2053. ELSIF src2.mode IN {PCO.Imme, PCO.ImmeA} THEN
  2054. PCO.GenTyp1(PCO.CMP, src1.mode+(PCO.ImmMem-PCO.Mem), src2.base2, src1.base2, src1.index, src1.scale, src1.disp+4, src2.imm2);
  2055. FixAbsolute(src1.addr, -4-ConstSize(src2.imm, src1.size = PCLIR.Int16));
  2056. FixAbsolute(src2.addr, -4)
  2057. ELSE HALT(99)
  2058. END
  2059. ELSE HALT(99) END;
  2060. END GenCmp2;
  2061. PROCEDURE GenFtyp1(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  2062. VAR src1, src2: RealAddress; reverse: BOOLEAN; op: SHORTINT; reg: Register;
  2063. BEGIN
  2064. ASSERT(instr.dstSize IN PCLIR.FloatSize);
  2065. UseComplex(code, instr.src2, src2); ASSERT(src2.mode IN {PCO.Regs, PCO.Mem, PCO.MemA}); (* higher on FP Stack, first used *)
  2066. UseComplex(code, instr.src1, src1); ASSERT(src1.mode = PCO.Regs);
  2067. reverse := (src2.mode = PCO.Regs) & (src2.base > src1.base);
  2068. reg := AllocateRegI(code, instr, pc);
  2069. CASE instr.op OF
  2070. | PCLIR.add:
  2071. op := 0 (*FADD*)
  2072. | PCLIR.sub:
  2073. IF (src2.mode # PCO.Regs) OR (src2.base < src1.base) THEN
  2074. op := 4
  2075. ELSE
  2076. (*PCM.LogWLn; PCM.LogWStr("GetFtyp1/sub, src2 < src1");*)
  2077. op := 5
  2078. END
  2079. | PCLIR.mul:
  2080. op := 1
  2081. | PCLIR.div:
  2082. IF (src2.mode # PCO.Regs) OR (src2.base < src1.base) THEN
  2083. op := 6
  2084. ELSE
  2085. (*PCM.LogWLn; PCM.LogWStr("GetFtyp1/div, src2 > src1");*)
  2086. op := 7
  2087. END
  2088. END;
  2089. IF src2.mode = PCO.Regs THEN
  2090. PCO.GenFtyp1(op, PCO.StRegP, FPSize[instr.dstSize], 1(*ST(1)*), noInx, noScale, noDisp)
  2091. ELSE
  2092. ASSERT(src1.base = 24+FSP);
  2093. PCO.GenFtyp1(op, src2.mode+(PCO.MemSt-PCO.Mem), FPSize[instr.dstSize], src2.base, src2.index, src2.scale, src2.disp);
  2094. IF src2.addr # NIL THEN
  2095. FixAbsolute(src2.addr, -4)
  2096. END
  2097. END
  2098. END GenFtyp1;
  2099. PROCEDURE GenMul64(src1, src2: RealAddress; dst1, dst2: Register);
  2100. VAR clean: LONGINT;
  2101. BEGIN
  2102. ASSERT(dst1 = EAX);
  2103. ASSERT(dst2 = EDX);
  2104. (*
  2105. ASSERT(src1.mode # PCO.Imme);
  2106. ASSERT(src1.mode # PCO.ImmeA);
  2107. ASSERT(src2.mode # PCO.Imme);
  2108. ASSERT(src2.mode # PCO.ImmeA);
  2109. *)
  2110. clean := 0;
  2111. IF src1.mode = PCO.Regs THEN
  2112. PCO.GenPUSH(PCO.Regs, src1.base2, noBase, noInx, noScale, noDisp, noImm);
  2113. PCO.GenPUSH(PCO.Regs, src1.base, noBase, noInx, noScale, noDisp, noImm);
  2114. src1.mode := PCO.Mem;
  2115. src1.base := ESP; src1.base2 := ESP; src1.index := noInx; src1.scale := noScale; src1.disp := 0;
  2116. INC(clean, 8)
  2117. END;
  2118. IF (src2.mode = PCO.Regs) OR (src2.mode = PCO.Imme) THEN
  2119. PCO.GenPUSH(PCO.Regs, src2.base2, noBase, noInx, noScale, noDisp, noImm);
  2120. PCO.GenPUSH(PCO.Regs, src2.base, noBase, noInx, noScale, noDisp, noImm);
  2121. src2.mode := PCO.Mem;
  2122. src2.base := ESP; src2.base2 := ESP; src2.index := noInx; src2.scale := noScale; src2.disp := 0;
  2123. IF src1.base = ESP THEN INC(src1.disp, 8) END;
  2124. INC(clean, 8)
  2125. END;
  2126. LoadReg(EAX, src1);
  2127. PCO.GenMUL(src2.mode >= PCO.ForceDisp32, EAX, src2.base, src2.index, src2.scale, src2.disp);
  2128. (*
  2129. PCO.GenIMUL(src2.mode, TRUE, EAX, src2.base, src2.index, src2.scale, src2.disp, src2.imm); (* MUL EAX, src2 (shortform -> MUL) *)
  2130. *)
  2131. FixAbsolute(src2.addr, -4);
  2132. LoadReg(EBX, src1);
  2133. PCO.GenIMUL(src2.mode, FALSE, EBX, src2.base2, src2.index, src2.scale, src2.disp+4, src2.imm2); (* IMUL Src1.L, Src2.H *)
  2134. FixAbsolute(src2.addr, -4);
  2135. PCO.GenTyp1(PCO.ADD, PCO.RegReg, EDX, EBX, noInx, noScale, noDisp, noImm);
  2136. LoadReg(EBX, src2);
  2137. PCO.GenIMUL(src1.mode, FALSE, EBX, src1.base2, src1.index, src1.scale, src1.disp+4, src1.imm2); (* IMUL Src2.L, Src1.H *)
  2138. FixAbsolute(src1.addr, -4);
  2139. PCO.GenTyp1(PCO.ADD, PCO.RegReg, EDX, EBX, noInx, noScale, noDisp, noImm);
  2140. IF clean # 0 THEN
  2141. PCO.GenTyp1(PCO.ADD, PCO.ImmReg, ESP, noBase, noInx, noScale, noDisp, clean)
  2142. END
  2143. END GenMul64;
  2144. PROCEDURE GenMul(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  2145. VAR size: LONGINT; reg: Register; src1, src2: RealAddress; short, spilled: BOOLEAN;
  2146. BEGIN
  2147. spilled := FALSE;
  2148. IF instr.dstSize IN PCLIR.FloatSize THEN
  2149. GenFtyp1(code, instr, pc)
  2150. ELSIF instr.dstSize = PCLIR.Int64 THEN
  2151. UseComplex(code, instr.src1, src1);
  2152. UseComplex(code, instr.src2, src2);
  2153. AllocateThisRegI2(instr, pc, EAX, EDX);
  2154. GenMul64(src1, src2, EAX, EDX)
  2155. ELSE
  2156. size := PCLIR.NofBytes(instr.dstSize);
  2157. UseComplex(code, instr.src1, src1); (* src1 = complex => src2 = immediate *)
  2158. IF (size = 1) & ((src1.mode # PCO.Regs) OR (src1.base # AL)) THEN (*8bit, special case, only IMUL AL possible*)
  2159. ReleaseReg(code, AX, MakeMask(src1.base)+MakeMask(src1.index));
  2160. LoadReg(AL, src1);
  2161. (*
  2162. PCO.GenMOV(src1.mode, AL, src1.base, src1.index, src1.scale, src1.disp, noImm);
  2163. *)
  2164. src1.base := AL; src1.mode := PCO.Regs;
  2165. END;
  2166. IF (src1.base IN{EBP, ESP}) OR (src1.base = none) OR (src1.mode # PCO.Regs) THEN
  2167. reg := AllocateRegI(code, instr, pc);
  2168. ELSE
  2169. AllocateThisRegI(instr, pc, src1.base); reg := src1.base
  2170. END;
  2171. UseComplex(code, instr.src2, src2);
  2172. IF (size = 1) & (src2.mode = PCO.Imme) THEN
  2173. GetTempReg8(src2.base, RegI-{AL, AH});
  2174. IF src2.base < 0 THEN (* no register is available, spill to stack. src1 is AL / dest is AX *)
  2175. KernelLog.String("PCG386: Spilling happens!"); KernelLog.Ln;
  2176. spilled := TRUE;
  2177. PCO.GenPUSH(PCO.Regs, EBX, noBase, noInx, noScale, noDisp, noImm);
  2178. src2.base := BL
  2179. END;
  2180. PCO.GenMOV(PCO.ImmReg, src2.base, noBase, noInx, noScale, noDisp, src2.imm);
  2181. src2.mode := PCO.Regs
  2182. END;
  2183. ASSERT((size # 1) OR (reg = AL)); (*size=1 => reg = AL*)
  2184. short := reg IN {AL, AX, EAX};
  2185. IF src2.mode IN {PCO.Imme, PCO.ImmeA} THEN
  2186. ASSERT(size # 1);
  2187. IF src1.mode = PCO.Regs THEN
  2188. PCO.GenIMUL(src2.mode, short, reg, src1.base, noInx, noScale, noDisp, src2.imm)
  2189. ELSE
  2190. ASSERT(src1.mode IN {PCO.Mem, PCO.MemA});
  2191. ASSERT(src2.mode # PCO.ImmeA);
  2192. PCO.GenIMUL(src1.mode+(PCO.ImmMem-PCO.Mem), short, reg, src1.base, src1.index, src1.scale, src1.disp, src2.imm);
  2193. IF src1.addr # NIL THEN
  2194. FixAbsolute(src1.addr, -4-ConstSize(src2.imm, size = PCLIR.Int16))
  2195. END;
  2196. END;
  2197. IF src2.addr # NIL THEN
  2198. FixAbsolute(src2.addr, -4)
  2199. END
  2200. ELSE
  2201. ASSERT(src1.mode = PCO.Regs, 500);
  2202. ASSERT(reg = src1.base, 501);
  2203. IF (short) & (size # 1) THEN
  2204. (*IF size = 1 THEN ReleaseReg(code, AH, MakeMask(AL)+MakeMask(src2base)+MakeMask(src2.index))*) (*already freed*)
  2205. short := Owner(EDX) = Free
  2206. END;
  2207. PCO.GenIMUL(src2.mode, short, src1.base, src2.base, src2.index, src2.scale, src2.disp, src2.imm);
  2208. IF src2.addr # NIL THEN
  2209. FixAbsolute(src2.addr, -4)
  2210. END;
  2211. IF spilled THEN
  2212. PCO.GenPOP(PCO.Regs, EBX, noBase, noInx, noScale, noDisp)
  2213. END
  2214. END
  2215. END
  2216. END GenMul;
  2217. PROCEDURE GenDivMod(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  2218. VAR size: PCLIR.Size; remainder, dividend, result, temp: Register; src2: RealAddress; offs, bytes: LONGINT; dest: SET;
  2219. BEGIN
  2220. ASSERT((instr.op = PCLIR.div) OR (instr.op = PCLIR.mod));
  2221. IF instr.dstSize = PCLIR.Int64 THEN
  2222. PCM.Error(200, PCO.errpos, "HUGEINT DIV/MOD");
  2223. ELSIF instr.dstSize IN PCLIR.FloatSize THEN
  2224. GenFtyp1(code, instr, pc)
  2225. ELSE
  2226. size := instr.dstSize; bytes := PCLIR.NofBytes(size);
  2227. remainder := RegisterD(size);
  2228. dividend := RegisterA(size);
  2229. UseRegister(code, instr.src1, temp);
  2230. dest := MakeMask(remainder)+MakeMask(dividend);
  2231. ForceRegister(code, temp, dividend, dest);
  2232. ReleaseReg(code, remainder, dest);
  2233. UseComplex(code, instr.src2, src2);
  2234. IF instr.op = PCLIR.div THEN
  2235. result := RegisterA(size); (*quotient*)
  2236. ELSE
  2237. result := RegisterD(size); (*remainder*)
  2238. END;
  2239. AllocateThisRegI(instr, pc, result);
  2240. IF bytes = 1 THEN
  2241. PCO.PutByte(66H); PCO.PutByte(PCO.CBW)
  2242. ELSE
  2243. IF bytes = 2 THEN PCO.PutByte(66H) END;
  2244. PCO.PutByte(PCO.CWD)
  2245. END;
  2246. IF src2.mode = PCO.Regs THEN
  2247. PCO.GenIDIV(PCO.RegReg, src2.base, src2.base, src2.index, src2.scale, src2.disp)
  2248. ELSE
  2249. PCO.GenIDIV(src2.mode, RegisterA(size), src2.base, src2.index, src2.scale, src2.disp);
  2250. IF src2.addr # NIL THEN
  2251. FixAbsolute(src2.addr, -4)
  2252. END
  2253. END;
  2254. (* correction for negative numbers *)
  2255. IF instr.op = PCLIR.div THEN
  2256. PCO.GenShiftRot(PCO.SHL, PCO.ImmReg, remainder, noBase, noInx, noScale, noDisp, 1);
  2257. PCO.GenTyp1(PCO.SBB, PCO.ImmReg, result, noBase, noInx, noScale, noDisp, 0);
  2258. ELSE
  2259. PCO.GenTyp1(PCO.CMP, PCO.ImmReg, remainder, remainder, noInx, noScale, noDisp, 0);
  2260. PCO.GenJcc(PCO.JGE, 0); (*dummy, fix later*)
  2261. offs := PCO.pc;
  2262. PCO.GenTyp1(PCO.ADD, src2.mode, result, src2.base, src2.index, src2.scale, src2.disp, src2.imm);
  2263. IF src2.addr # NIL THEN
  2264. FixAbsolute(src2.addr, -4)
  2265. END;
  2266. PCO.PutByteAt(offs-1, SHORT(SHORT(PCO.pc-offs)));
  2267. END
  2268. END
  2269. END GenDivMod;
  2270. PROCEDURE GenTyp1(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  2271. VAR src1, src2: RealAddress; t: Register; lea: BOOLEAN; info: Address;
  2272. BEGIN
  2273. ASSERT(instr.src1 # 0);
  2274. IF instr.dstSize IN PCLIR.FloatSize THEN
  2275. GenFtyp1(code, instr, pc);
  2276. ELSIF instr.dstSize = PCLIR.Int64 THEN
  2277. UseComplex(code, instr.src1, src1); ASSERT(src1.mode = PCO.Regs);
  2278. UseComplex(code, instr.src2, src2);
  2279. AllocateThisRegI2(instr, pc, src1.base, src1.base2);
  2280. PCO.GenTyp1(Typ1Opcode[instr.op-PCLIR.sub], src2.mode, src1.base, src2.base, src2.index, src2.scale, src2.disp, src2.imm);
  2281. FixAbsolute(src2.addr, -4);
  2282. PCO.GenTyp1(Typ1Opcode2[instr.op-PCLIR.sub], src2.mode, src1.base2, src2.base2, src2.index, src2.scale, src2.disp+4, src2.imm2);
  2283. FixAbsolute(src2.addr, -4);
  2284. ELSE
  2285. info := SYSTEM.VAL(Address, instr.info);
  2286. UseComplex(code, instr.src1, src1); ASSERT(src1.mode = PCO.Regs);
  2287. UseComplex(code, instr.src2, src2);
  2288. IF (instr.src1 = PCLIR.SP) & (info.i386 = ESP) THEN (*optimize ESP -> ESP *)
  2289. AllocateThisRegI(instr, pc, src1.base)
  2290. ELSIF (instr.src1 < 0) OR (Owner(src1.base) # Free) THEN (*don't overwrite hw-reg or registers still in use*)
  2291. t := src1.base;
  2292. src1.base := AllocateReg(code, pc);
  2293. IF (instr.op = PCLIR.add) & (src2.mode = PCO.Imme) THEN
  2294. lea := TRUE
  2295. ELSE
  2296. PCO.GenMOV(PCO.RegReg, src1.base, t, noInx, noScale, noDisp, noImm)
  2297. END
  2298. ELSE
  2299. AllocateThisRegI(instr, pc, src1.base)
  2300. END;
  2301. IF lea & (src2.addr = NIL) & (src2.imm = 0) THEN
  2302. PCO.GenMOV(PCO.RegReg, src1.base, t, noInx, noScale, noDisp, noImm);
  2303. ELSIF lea THEN
  2304. PCO.GenLEA(src2.addr # NIL, src1.base, t, noInx, noScale, src2.imm);
  2305. IF src2.addr # NIL THEN FixAbsolute(src2.addr, -4) END
  2306. ELSIF (src2.mode = PCO.Imme) & (src2.imm = 1) & (instr.op = PCLIR.add) THEN
  2307. PCO.GenINC(PCO.ImmReg, src1.base, noBase, noInx, noScale, noDisp)
  2308. ELSIF (src2.mode = PCO.Imme) & (src2.imm = 1) & (instr.op = PCLIR.sub) THEN
  2309. PCO.GenDEC(PCO.ImmReg, src1.base, noBase, noInx, noScale, noDisp)
  2310. ELSE
  2311. PCO.GenTyp1(Typ1Opcode[instr.op-PCLIR.sub], src2.mode, src1.base, src2.base, src2.index, src2.scale, src2.disp, src2.imm);
  2312. FixAbsolute(src2.addr, -4)
  2313. END
  2314. END
  2315. END GenTyp1;
  2316. PROCEDURE GenShift(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  2317. VAR op: PCLIR.Opcode; src, src2, tmp: Register; count: RealAddress; pos1, pos2: LONGINT; size64: BOOLEAN;
  2318. (*
  2319. Note: UseRegister must be done after ForceRegister, otherwise if the source is in ECX a conflict may occour.
  2320. *)
  2321. BEGIN
  2322. op := instr.op;
  2323. size64 := instr.dstSize = PCLIR.Int64;
  2324. UseComplex(code, instr.src2, count);
  2325. IF count.mode # PCO.Imme THEN ForceRegister(code, count.base, CL, {}) END;
  2326. ASSERT(count.mode # PCO.ImmeA);
  2327. IF size64 THEN
  2328. UseRegister2(code, instr.src1, src, src2);
  2329. AllocateThisRegI2(instr, pc, src, src2);
  2330. IF op = PCLIR.rot THEN
  2331. GetTempReg32(tmp);
  2332. PCO.GenMOV(PCO.RegReg, tmp, src2, noInx, noScale, noDisp, noImm);
  2333. END
  2334. ELSE
  2335. UseRegister(code, instr.src1, src);
  2336. AllocateThisRegI(instr, pc, src)
  2337. END;
  2338. IF count.mode # PCO.Imme THEN (*generic case: discriminate against count *)
  2339. ASSERT(count.mode = PCO.Regs);
  2340. PCO.GenTyp1(PCO.CMP, PCO.ImmReg, CL, noBase, noInx, noScale, noDisp, 0);
  2341. PCO.GenJcc(PCO.JL, 0);
  2342. pos1 := PCO.pc;
  2343. IF ~size64 THEN
  2344. PCO.GenShiftRot(ShiftOpcode[instr.op-PCLIR.ash, left], PCO.RegReg, src, count.base, noInx, noScale, noDisp, noImm);
  2345. ELSIF op = PCLIR.rot THEN
  2346. PCO.GenSHDouble(PCO.Left, PCO.RegReg, TRUE, src, src2, noInx, noScale, noDisp, noImm);
  2347. PCO.GenSHDouble(PCO.Left, PCO.RegReg, TRUE, tmp, src, noInx, noScale, noDisp, noImm);
  2348. ELSE
  2349. PCO.GenSHDouble(PCO.Left, PCO.RegReg, TRUE, src, src2, noInx, noScale, noDisp, noImm);
  2350. PCO.GenShiftRot(ShiftOpcode[instr.op-PCLIR.ash, left], PCO.RegReg, src, count.base, noInx, noScale, noDisp, noImm);
  2351. END;
  2352. PCO.GenJMP(PCO.Imme, noBase, noBase, noInx, noScale, 0);
  2353. pos2 := PCO.pc;
  2354. PCO.PutByteAt(pos1-1, SHORT(SHORT(PCO.pc-pos1)));
  2355. PCO.GenGroup3(PCO.NEG, PCO.Regs, count.base, count.base, noInx, noScale, noDisp);
  2356. IF ~size64 THEN
  2357. PCO.GenShiftRot(ShiftOpcode[instr.op-PCLIR.ash, right], PCO.RegReg, src, count.base, noInx, noScale, noDisp, noImm);
  2358. ELSIF op = PCLIR.rot THEN
  2359. PCO.GenSHDouble(PCO.Right, PCO.RegReg, TRUE, src, src2, noInx, noScale, noDisp, noImm);
  2360. PCO.GenSHDouble(PCO.Right, PCO.RegReg, TRUE, tmp, src, noInx, noScale, noDisp, noImm);
  2361. ELSE
  2362. PCO.GenSHDouble(PCO.Right, PCO.RegReg, TRUE, src2, src, noInx, noScale, noDisp, noImm);
  2363. PCO.GenShiftRot(ShiftOpcode[instr.op-PCLIR.ash, right], PCO.RegReg, src2, count.base, noInx, noScale, noDisp, noImm);
  2364. END;
  2365. PCO.PutByteAt(pos2-1, SHORT(SHORT(PCO.pc-pos2)));
  2366. ELSIF ~size64 THEN
  2367. IF count.imm >= 0 THEN
  2368. PCO.GenShiftRot(ShiftOpcode[instr.op-PCLIR.ash, left], PCO.ImmReg, src, src, noInx, noScale, noDisp, count.imm)
  2369. ELSE
  2370. PCO.GenShiftRot(ShiftOpcode[instr.op-PCLIR.ash, right], PCO.ImmReg, src, src, noInx, noScale, noDisp, -count.imm)
  2371. END;
  2372. ELSIF op = PCLIR.rot THEN (* 64-bit rot *)
  2373. count.imm := count.imm MOD 64;
  2374. IF (count.imm <= -32) OR (count.imm >= 32) THEN (* swap registers *)
  2375. FreeReg(src); FreeReg(src2); AllocateThisRegI2(instr, pc, src2, src);
  2376. count.imm := count.imm MOD 32
  2377. END;
  2378. IF count.imm > 0 THEN
  2379. PCO.GenSHDouble(PCO.Left, PCO.RegReg, FALSE, src, src2, noInx, noScale, noDisp, count.imm);
  2380. PCO.GenSHDouble(PCO.Left, PCO.RegReg, FALSE, tmp, src, noInx, noScale, noDisp, count.imm);
  2381. ELSIF count.imm < 0 THEN
  2382. PCO.GenSHDouble(PCO.Right, PCO.RegReg, FALSE, src, src2, noInx, noScale, noDisp, -count.imm);
  2383. PCO.GenSHDouble(PCO.Right, PCO.RegReg, FALSE, tmp, src, noInx, noScale, noDisp, -count.imm);
  2384. ELSE
  2385. END
  2386. ELSE (* 64-bit shifts *) (* src2:src, src lower part *)
  2387. IF count.imm >= 32 THEN
  2388. FreeReg(src); FreeReg(src2); AllocateThisRegI2(instr, pc, src2, src); (* swap registers *)
  2389. PCO.GenTyp1(PCO.XOR, PCO.RegReg, src2, src2, noInx, noScale, noDisp, noImm); (* xor src, src *)
  2390. PCO.GenShiftRot(ShiftOpcode[instr.op-PCLIR.ash, left], PCO.ImmReg, src, src, noInx, noScale, noDisp, count.imm-32);
  2391. ELSIF count.imm <= -32 THEN
  2392. IF instr.op = PCLIR.ash THEN
  2393. PCO.GenMOV(PCO.RegReg, src, src2, noInx, noScale, noDisp, noImm); (* mov l, h *)
  2394. PCO.GenShiftRot(ShiftOpcode[instr.op-PCLIR.ash, left], PCO.ImmReg, src2, src2, noInx, noScale, noDisp, 31); (*keep sign*)
  2395. PCO.GenShiftRot(ShiftOpcode[instr.op-PCLIR.ash, left], PCO.ImmReg, src, src, noInx, noScale, noDisp, count.imm+32);
  2396. ELSE
  2397. FreeReg(src); FreeReg(src2); AllocateThisRegI2(instr, pc, src2, src); (* swap registers *)
  2398. PCO.GenTyp1(PCO.XOR, PCO.RegReg, src, src, noInx, noScale, noDisp, noImm); (* xor src, src *)
  2399. PCO.GenShiftRot(ShiftOpcode[instr.op-PCLIR.ash, left], PCO.ImmReg, src2, src2, noInx, noScale, noDisp, count.imm+32);
  2400. END
  2401. ELSIF count.imm >= 0 THEN
  2402. PCO.GenSHDouble(PCO.Left, PCO.RegReg, FALSE, src, src2, noInx, noScale, noDisp, count.imm);
  2403. PCO.GenShiftRot(ShiftOpcode[instr.op-PCLIR.ash, left], PCO.ImmReg, src, src, noInx, noScale, noDisp, count.imm)
  2404. ELSE
  2405. PCO.GenSHDouble(PCO.Right, PCO.RegReg, FALSE, src2, src, noInx, noScale, noDisp, -count.imm);
  2406. PCO.GenShiftRot(ShiftOpcode[instr.op-PCLIR.ash, right], PCO.ImmReg, src2, src2, noInx, noScale, noDisp, -count.imm)
  2407. END
  2408. END;
  2409. END GenShift;
  2410. PROCEDURE GenMoveDown(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  2411. VAR src, dst: Register; size: RealAddress; step: INTEGER;
  2412. BEGIN
  2413. UseRegister(code, instr.src1, src); ForceRegister(code, src, ESI, MakeMask(EDI)+MakeMask(ECX));
  2414. UseRegister(code, instr.src2, dst); ForceRegister(code, dst, EDI, MakeMask(ESI)+MakeMask(ECX));
  2415. UseComplex(code, instr.src3, size);
  2416. ASSERT(size.mode # PCO.ImmeA);
  2417. step := PCO.Bit8;
  2418. PCO.PutByte(PCO.STD);
  2419. IF size.mode = PCO.ImmReg THEN
  2420. IF size.imm MOD 4 = 0 THEN
  2421. step := PCO.Bit32; size.imm := size.imm DIV 4
  2422. ELSIF size.imm MOD 2 = 0 THEN
  2423. step := PCO.Bit16; size.imm := size.imm DIV 2
  2424. END;
  2425. IF size.imm > 3 THEN
  2426. ReleaseReg(code, ECX, MakeMask(ESI)+MakeMask(EDI));
  2427. PCO.GenMOV(PCO.ImmReg, ECX, noBase, noInx, noScale, noDisp, size.imm);
  2428. PCO.GenRepString(PCO.MOVS, step)
  2429. ELSE
  2430. WHILE size.imm > 0 DO
  2431. PCO.GenString(PCO.MOVS, step);
  2432. DEC(size.imm)
  2433. END
  2434. END
  2435. ELSE
  2436. ForceRegister(code, size.base, ECX, MakeMask(ESI)+MakeMask(EDI));
  2437. PCO.GenRepString(PCO.MOVS, step);
  2438. PCO.PutByte(PCO.CLD);
  2439. END
  2440. END GenMoveDown;
  2441. PROCEDURE GenMove(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  2442. VAR src, dst, tmp: Register; size: RealAddress; step: INTEGER;
  2443. BEGIN
  2444. UseRegister(code, instr.src1, src); ForceRegister(code, src, ESI, MakeMask(EDI)+MakeMask(ECX));
  2445. UseRegister(code, instr.src2, dst); ForceRegister(code, dst, EDI, MakeMask(ESI)+MakeMask(ECX));
  2446. UseComplex(code, instr.src3, size);
  2447. ASSERT(size.mode # PCO.ImmeA);
  2448. step := PCO.Bit8;
  2449. IF size.mode = PCO.ImmReg THEN
  2450. IF size.imm MOD 4 = 0 THEN
  2451. step := PCO.Bit32; size.imm := size.imm DIV 4
  2452. ELSIF size.imm MOD 2 = 0 THEN
  2453. step := PCO.Bit16; size.imm := size.imm DIV 2
  2454. END;
  2455. IF size.imm > 3 THEN
  2456. ReleaseReg(code, ECX, MakeMask(ESI)+MakeMask(EDI));
  2457. PCO.GenMOV(PCO.ImmReg, ECX, noBase, noInx, noScale, noDisp, size.imm);
  2458. PCO.GenRepString(PCO.MOVS, step)
  2459. ELSE
  2460. WHILE size.imm > 0 DO
  2461. PCO.GenString(PCO.MOVS, step);
  2462. DEC(size.imm)
  2463. END
  2464. END
  2465. ELSE
  2466. ForceRegister(code, size.base, ECX, MakeMask(ESI)+MakeMask(EDI));
  2467. (* -> experimental*)
  2468. GetTempReg8(tmp, -(MakeMask(ECX)+MakeMask(ESI)+MakeMask(EDI)));
  2469. IF tmp # -1 THEN (*register found*)
  2470. PCO.GenMOV(PCO.RegReg, tmp, CL, noInx, noScale, noDisp, noImm);
  2471. PCO.GenShiftRot(PCO.SHR, PCO.ImmReg, ECX, noBase, noInx, noScale, noDisp, 2);
  2472. PCO.GenTyp1(PCO.AND, PCO.ImmReg, tmp, noBase, noInx, noScale, noDisp, 3);
  2473. PCO.GenRepString(PCO.MOVS, PCO.Bit32);
  2474. PCO.GenMOV(PCO.RegReg, CL, tmp, noInx, noScale, noDisp, noImm)
  2475. END;
  2476. (* <- experimental*)
  2477. PCO.GenRepString(PCO.MOVS, step)
  2478. END
  2479. END GenMove;
  2480. PROCEDURE GenInline(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  2481. VAR newpc, oldpc, i: LONGINT; inline: PCLIR.AsmInline; block: PCLIR.AsmBlock; fix: PCLIR.AsmFixup;
  2482. (*
  2483. c: LONGINT;
  2484. *)
  2485. BEGIN
  2486. (*
  2487. PCM.LogWLn; PCM.LogWStr("Emit Inline. code = ");
  2488. *)
  2489. inline := instr.adr(PCLIR.AsmInline);
  2490. oldpc := PCO.pc;
  2491. block := inline.code;
  2492. WHILE block # NIL DO
  2493. (*
  2494. INC(c, block.len);
  2495. *)
  2496. FOR i := 0 TO block.len-1 DO PCO.PutByte(ORD(block.code[i])) END;
  2497. block := block.next
  2498. END;
  2499. (*
  2500. PCM.LogWNum(c); PCM.LogWStr(" fixups = "); c := 0;
  2501. *)
  2502. newpc := PCO.pc; PCO.pc := oldpc;
  2503. fix := inline.fixup;
  2504. WHILE fix # NIL DO
  2505. (*
  2506. INC(c);
  2507. *)
  2508. PCO.PutDWordAt(PCO.pc+fix.offset, fix.adr(PCBT.GlobalVariable).offset);
  2509. FixAbsolute(fix.adr, fix.offset);
  2510. fix := fix.next
  2511. END;
  2512. (*
  2513. PCM.LogWNum(c);
  2514. *)
  2515. PCO.pc := newpc
  2516. END GenInline;
  2517. (* CaseTable Format
  2518. location: at offset "table" in the const section
  2519. CaseTable = ARRAY table size OF RECORD
  2520. pc-offset: INTEGER; (*address(rel to code base) to jump to*)
  2521. next: INTEGER (*next entry offset (used by the linker to patch addresses)*)
  2522. END;
  2523. *)
  2524. PROCEDURE GenCase(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  2525. VAR min, max, range, table: LONGINT; reg: Register; adr: PCBT.GlobalVariable; info: Address;
  2526. const: PCBT.ConstArray;
  2527. BEGIN
  2528. min := instr.src2;
  2529. max := instr.src3;
  2530. range := max-min+1;
  2531. (*fof this is not thread safe. Strictly speaking it does not have to be as the generator does not run concurrently
  2532. but it's bad style anyway.
  2533. table := PCBT.context.constsize;
  2534. INC(PCBT.context.constsize, SHORT(range*4));
  2535. IF PCBT.context.constsize > LEN(PCBT.context.const^) THEN
  2536. NEW(const, PCBT.context.constsize);
  2537. SYSTEM.MOVE(ADDRESSOF(PCBT.context.const[0]), ADDRESSOF(const[0]), LEN(PCBT.context.const));
  2538. PCBT.context.const := const
  2539. END;
  2540. PCBT.context.casetablesize := PCBT.context.casetablesize + SHORT(range);
  2541. *)
  2542. (* fof new: *)
  2543. table := PCBT.context.AddCasetable(range);
  2544. IF PCBT.context.syscalls[PCBT.casetable] = NIL THEN PCBT.context.UseSyscall(PCBT.casetable, table) END;
  2545. UseRegister(code, instr.src1, reg);
  2546. IF min # 0 THEN PCO.GenTyp1(PCO.SUB, PCO.ImmReg, reg, noBase, noInx, noScale, noDisp, min) END;
  2547. PCO.GenTyp1(PCO.CMP, PCO.ImmReg, reg, noBase, noInx, noScale, noDisp, range);
  2548. PCO.GenJcc(PCO.JAE, 10000H);
  2549. NEW(adr, PCBT.context); adr.offset := table;
  2550. info := SYSTEM.VAL(Address, instr.info);
  2551. info.addr := adr; (*case table*)
  2552. info.index := PCO.pc; (* addr for jmp to else fixup*)
  2553. PCO.GenJMP(PCO.MemA, noBase, noBase, reg, PCO.Scale4, table);
  2554. PCBT.context.UseVariable(adr, PCO.pc-4)
  2555. END GenCase;
  2556. PROCEDURE GenCaseLine(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  2557. VAR info: Address; table, pos, offset: LONGINT; p: PCLIR.Piece;
  2558. BEGIN
  2559. pos := instr.src1; code.GetPiece(pos, p);
  2560. info := SYSTEM.VAL(Address, p.instr[pos].info);
  2561. offset := instr.val - p.instr[pos].src2; (*val-min*)
  2562. table := info.addr(PCBT.GlobalVariable).offset + offset*4;
  2563. PCBT.context.const[table+0] := CHR(PCO.pc);
  2564. PCBT.context.const[table+1] := CHR(PCO.pc DIV 100H);
  2565. PCBT.context.const[table+2] := CHR(PCO.pc DIV 10000H); (* ug *)
  2566. PCBT.context.const[table+3] := CHR(PCO.pc DIV 1000000H) (* ug *)
  2567. END GenCaseLine;
  2568. PROCEDURE GenCaseElse(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT);
  2569. VAR pos, min, max, size, i: LONGINT; p: PCLIR.Piece; info: Address;
  2570. BEGIN
  2571. pos := instr.src1; code.GetPiece(pos, p);
  2572. info := SYSTEM.VAL(Address, p.instr[pos].info);
  2573. PCO.PutDWordAt(info.index-4, PCO.pc - info.index); (*patch jump to else*)
  2574. size := (*1 +*) p.instr[pos].src3 - p.instr[pos].src2;
  2575. min := info.addr(PCBT.GlobalVariable).offset;
  2576. max := min + size*4;
  2577. FOR i := min TO max BY 4 DO
  2578. IF (PCBT.context.const[i]=0X) & (PCBT.context.const[i+1]=0X) & (PCBT.context.const[i+2]=0X) & (PCBT.context.const[i+3]=0X)THEN
  2579. PCBT.context.const[i+0] := CHR(PCO.pc);
  2580. PCBT.context.const[i+1] := CHR(PCO.pc DIV 100H);
  2581. PCBT.context.const[i+2] := CHR(PCO.pc DIV 10000H); (* ug *)
  2582. PCBT.context.const[i+3] := CHR(PCO.pc DIV 1000000H) (* ug *)
  2583. END
  2584. END
  2585. END GenCaseElse;
  2586. (* Debug Procedures *)
  2587. PROCEDURE DumpCode(code: PCLIR.Code; VAR instr: PCLIR.Instruction; pc: LONGINT; context: ANY);
  2588. VAR op: PCLIR.Opcode; format: SHORTINT; info: Address;
  2589. PROCEDURE Reg(r: PCLIR.Register; expand: BOOLEAN);
  2590. VAR p: PCLIR.Piece; reg: LONGINT;
  2591. PROCEDURE WriteDisp(disp: LONGINT; abs: BOOLEAN);
  2592. BEGIN
  2593. IF abs THEN
  2594. PCM.LogWStr("@sb");
  2595. IF disp >= 0 THEN PCM.LogW("+") END
  2596. END;
  2597. PCM.LogWNum(disp)
  2598. END WriteDisp;
  2599. PROCEDURE ComplexAddress(VAR instr: PCLIR.Instruction; reg: LONGINT);
  2600. VAR info: Address; form: LONGINT;
  2601. BEGIN
  2602. info := SYSTEM.VAL(Address, instr.info);
  2603. form := PCLIR.InstructionSet[instr.op].format;
  2604. IF (info = NIL) OR (pc # reg) & ~instr.suppress & (form IN {PCLIR.form1M, PCLIR.form1C}) THEN Reg(reg, FALSE); RETURN END;
  2605. CASE info.mode OF
  2606. | 0:
  2607. Reg(reg, FALSE)
  2608. | register:
  2609. Reg(info.base, FALSE)
  2610. | immediate:
  2611. PCM.LogWNum(info.imm)
  2612. | absolute:
  2613. (*IF showSize THEN WriteSize(W, instr.dstSize) END;*)
  2614. WriteDisp(info.disp, info.addr # NIL)
  2615. | relative, indexed, scaled:
  2616. (*IF showSize THEN WriteSize(W, instr.dstSize) END;*)
  2617. WriteDisp(info.disp, info.addr # NIL);
  2618. IF info.base # none THEN
  2619. PCM.LogW("["); Reg(info.base, FALSE); PCM.LogW("]")
  2620. ELSE
  2621. ASSERT(info.mode # relative)
  2622. END;
  2623. IF info.mode # relative THEN
  2624. PCM.LogW("["); Reg(info.index, FALSE);
  2625. IF info.mode = scaled THEN PCM.LogW("*"); PCM.LogWNum(info.scale) END;
  2626. PCM.LogW("]")
  2627. END
  2628. ELSE
  2629. Dump(instr, info);
  2630. HALT(99)
  2631. END
  2632. END ComplexAddress;
  2633. BEGIN
  2634. IF (r > 0) & expand THEN
  2635. reg := r; code.GetPiece(reg, p); ComplexAddress(p.instr[reg], r)
  2636. ELSIF r = PCLIR.FP THEN PCM.LogWStr("FP")
  2637. ELSIF r = PCLIR.SP THEN PCM.LogWStr("SP")
  2638. ELSIF (r <= PCLIR.HwReg-EAX) & (r >= PCLIR.HwReg - BH) THEN
  2639. PCM.LogWStr(IReg[PCLIR.HwReg-r])
  2640. ELSE
  2641. PCM.LogW(RegName[PCLIR.SizeOf(code,r)]);
  2642. PCM.LogWNum(r)
  2643. END
  2644. END Reg;
  2645. BEGIN
  2646. IF instr.suppress THEN RETURN END;
  2647. op := instr.op; format := PCLIR.InstructionSet[op].format;
  2648. info := SYSTEM.VAL(Address, instr.info);
  2649. PCM.LogWNum(pc);
  2650. PCM.LogW(9X);
  2651. (*
  2652. IF (format IN PCLIR.form1X) THEN
  2653. PCM.LogWNum(info.count);
  2654. ELSE
  2655. PCM.LogWStr(" ")
  2656. END;
  2657. *)
  2658. (*
  2659. IF Experimental THEN
  2660. IF info # NIL THEN
  2661. i := 0;
  2662. WHILE (i < LEN(info.alive)) & (info.alive[i].reg # pc) DO INC(i) END;
  2663. IF i # LEN(info.alive) THEN
  2664. FOR j := 0 TO 23 DO
  2665. IF j IN info.alive[i].mask THEN PCM.LogW("1") ELSE PCM.LogW("0") END
  2666. END
  2667. ELSE
  2668. PCM.LogWStr("------------------------")
  2669. END
  2670. ELSE
  2671. PCM.LogWStr("------------------------")
  2672. END;
  2673. PCM.LogWStr("| ");
  2674. j := 0;
  2675. IF info # NIL THEN
  2676. FOR i := 0 TO LEN(info.alive)-1 DO
  2677. IF info.alive[i].reg # none THEN PCM.LogWNum(info.alive[i].reg); INC(j) END
  2678. END
  2679. ELSE
  2680. PCM.LogWStr("---"); INC(j)
  2681. END;
  2682. FOR i := j TO LEN(info.alive)-1 DO PCM.LogWStr(" ") END;
  2683. END;
  2684. *)
  2685. PCM.LogW(9X);
  2686. PCM.LogWStr(PCLIR.InstructionSet[op].name); PCM.LogW(9X);
  2687. CASE format OF
  2688. | PCLIR.form00:
  2689. | PCLIR.form0C:
  2690. PCM.LogWNum(instr.val)
  2691. | PCLIR.form01:
  2692. Reg(instr.src1, TRUE)
  2693. | PCLIR.form10:
  2694. Reg(pc, FALSE)
  2695. | PCLIR.form1C:
  2696. Reg(pc, FALSE); PCM.LogWStr(", "); PCM.LogWNum(instr.val)
  2697. | PCLIR.form1M:
  2698. Reg(pc, FALSE); PCM.LogWStr(", "); Reg(pc, TRUE); (*Indirect(instr.val, instr.src1)*)
  2699. | PCLIR.form11:
  2700. Reg(pc, FALSE); PCM.LogWStr(", "); Reg(instr.src1, TRUE)
  2701. | PCLIR.formM1:
  2702. Reg(pc, TRUE); PCM.LogWStr(", "); Reg(instr.src2, TRUE)
  2703. | PCLIR.form02:
  2704. Reg(instr.src1, TRUE); PCM.LogWStr(", "); Reg(instr.src2, TRUE)
  2705. | PCLIR.form12:
  2706. Reg(pc, FALSE); PCM.LogWStr(", "); Reg(instr.src1, TRUE);
  2707. PCM.LogWStr(", "); Reg(instr.src2, TRUE)
  2708. | PCLIR.form02C:
  2709. Reg(instr.src1, TRUE); PCM.LogWStr(", "); Reg(instr.src2, TRUE);
  2710. PCM.LogWStr(", "); PCM.LogWNum(instr.val)
  2711. | PCLIR.form03:
  2712. Reg(instr.src1, TRUE); PCM.LogWStr(", "); Reg(instr.src2, TRUE);
  2713. PCM.LogWStr(", "); Reg(instr.src3, TRUE)
  2714. | PCLIR.formXX:
  2715. CASE op OF
  2716. | PCLIR.enter, PCLIR.exit, PCLIR.inline:
  2717. | PCLIR.case:
  2718. Reg(instr.src1, TRUE); PCM.LogWStr(" {"); PCM.LogWNum(instr.val); PCM.LogW("}")
  2719. | PCLIR.casel:
  2720. PCM.LogWNum(instr.val); PCM.LogWStr(" {");
  2721. PCM.LogWNum(instr.src1); PCM.LogWStr("}")
  2722. | PCLIR.casee:
  2723. PCM.LogWStr(" {"); PCM.LogWNum(instr.src1); PCM.LogWStr("}")
  2724. END
  2725. END;
  2726. PCM.LogWLn;
  2727. END DumpCode;
  2728. PROCEDURE DoOptimize(code: PCLIR.Code);
  2729. VAR context: AliveSetPtr;
  2730. BEGIN
  2731. IF Experimental THEN
  2732. NEW(context);
  2733. AliveSetInit(context^)
  2734. END;
  2735. code.Traverse(Optimize, TRUE, context)
  2736. END DoOptimize;
  2737. PROCEDURE IncSaveLevel;
  2738. VAR s: SavedRegistersType; i: LONGINT;
  2739. BEGIN
  2740. INC(SaveLevel);
  2741. IF SaveLevel >= LEN(SavedRegisters) THEN
  2742. NEW(s, 2*LEN(SavedRegisters));
  2743. FOR i := 0 TO LEN(SavedRegisters)-1 DO
  2744. s[i] := SavedRegisters[i];
  2745. END;
  2746. SavedRegisters := s;
  2747. END;
  2748. END IncSaveLevel;
  2749. (* Init - Initialize code generator - Installed in PCBT.CG *)
  2750. PROCEDURE Init(): BOOLEAN;
  2751. BEGIN PCO.dsize := 0; PCO.pc := 0; CCTableSwitch := intMode;
  2752. SaveLevel := 0;
  2753. NEW(SavedRegisters, 16);
  2754. RETURN TRUE
  2755. END Init;
  2756. (* Done - Code generator results - Installed in PCBT.CG *)
  2757. PROCEDURE Done(VAR result: WORD);
  2758. BEGIN
  2759. IF PCO.CodeErr THEN result := -1
  2760. ELSE result := 0
  2761. END
  2762. END Done;
  2763. PROCEDURE GetCode(VAR codeArr: PCLIR.CodeArray; VAR length, hdrlength, addressFactor: LONGINT);
  2764. BEGIN
  2765. codeArr := PCO.code; length := PCO.pc; hdrlength := PCO.pc; addressFactor := 1
  2766. END GetCode;
  2767. (* Module Initialization and Configuration *)
  2768. (* Install - installs the i386 code generator in Paco *)
  2769. PROCEDURE Install*;
  2770. VAR i: PCLIR.Opcode;
  2771. BEGIN
  2772. PCLIR.CG.Init := Init;
  2773. PCLIR.CG.Done := Done;
  2774. PCLIR.CG.GetCode := GetCode;
  2775. PCLIR.CG.DumpCode := DumpCode;
  2776. PCLIR.CG.Optimize := DoOptimize;
  2777. PCLIR.CG.MaxCodeSize := PCO.MaxCodeLength;
  2778. PCLIR.CG.ParamAlign := 4;
  2779. PCBT.SetNumberOfSyscalls(PCBT.DefaultNofSysCalls);
  2780. NEW(PCLIR.CG.SysCallMap, PCBT.NofSysCalls);
  2781. PCLIR.InitDefaultSyscalls;
  2782. PCLIR.Address := PCLIR.Int32;
  2783. PCLIR.Set := PCLIR.Int32;
  2784. PCLIR.SizeType := PCLIR.Int32;
  2785. PCLIR.InstructionInit := InstructionInit;
  2786. PCLIR.SetMethods(PCLIR.enter, GenEnter);
  2787. PCLIR.SetMethods(PCLIR.exit, GenExit);
  2788. FOR i := PCLIR.trap TO PCLIR.tne DO
  2789. PCLIR.SetMethods(i, GenTrap)
  2790. END;
  2791. PCLIR.SetMethods(PCLIR.saveregs, GenSaveRegisters);
  2792. PCLIR.SetMethods(PCLIR.saveregsaligned, GenSaveRegistersAligned); (* fld *)
  2793. PCLIR.SetMethods(PCLIR.loadregs, GenRestoreRegisters);
  2794. PCLIR.SetMethods(PCLIR.ret, GenReturn);
  2795. PCLIR.SetMethods(PCLIR.ret2, GenReturn);
  2796. PCLIR.SetMethods(PCLIR.result, GenResult);
  2797. PCLIR.SetMethods(PCLIR.result2, GenResult);
  2798. PCLIR.SetMethods(PCLIR.pop, GenPop);
  2799. PCLIR.SetMethods(PCLIR.load, GenLoad);
  2800. PCLIR.SetMethods(PCLIR.loadc, GenLoad);
  2801. PCLIR.SetMethods(PCLIR.store, GenStore);
  2802. PCLIR.SetMethods(PCLIR.in, GenIn);
  2803. PCLIR.SetMethods(PCLIR.out, GenOut);
  2804. PCLIR.SetMethods(PCLIR.nop, GenNop);
  2805. PCLIR.SetMethods(PCLIR.label, GenLabel);
  2806. PCLIR.SetMethods(PCLIR.finallylabel, GenLabel);
  2807. FOR i := PCLIR.je TO PCLIR.jnf DO
  2808. PCLIR.SetMethods(i, GenJcc)
  2809. END;
  2810. PCLIR.SetMethods(PCLIR.jmp, GenJmp);
  2811. PCLIR.SetMethods(PCLIR.call, GenCall);
  2812. PCLIR.SetMethods(PCLIR.callreg, GenCallReg);
  2813. PCLIR.SetMethods(PCLIR.syscall, GenSysCall);
  2814. FOR i := PCLIR.sete TO PCLIR.setnf DO
  2815. PCLIR.SetMethods(i, GenSetcc)
  2816. END;
  2817. PCLIR.SetMethods(PCLIR.kill, GenKill);
  2818. PCLIR.SetMethods(PCLIR.phi, GenPhi);
  2819. PCLIR.SetMethods(PCLIR.push, GenPush);
  2820. PCLIR.SetMethods(PCLIR.loadsp, GenLoadSP);
  2821. PCLIR.SetMethods(PCLIR.loadfp, GenLoadFP);
  2822. PCLIR.SetMethods(PCLIR.convs, GenConv);
  2823. PCLIR.SetMethods(PCLIR.convu, GenConv);
  2824. PCLIR.SetMethods(PCLIR.copy, GenConv);
  2825. PCLIR.SetMethods(PCLIR.not, GenNegNot);
  2826. PCLIR.SetMethods(PCLIR.neg, GenNegNot);
  2827. PCLIR.SetMethods(PCLIR.abs, GenAbs);
  2828. PCLIR.SetMethods(PCLIR.bts, GenBitOp);
  2829. PCLIR.SetMethods(PCLIR.btc, GenBitOp);
  2830. PCLIR.SetMethods(PCLIR.mul, GenMul);
  2831. PCLIR.SetMethods(PCLIR.div, GenDivMod);
  2832. PCLIR.SetMethods(PCLIR.mod, GenDivMod);
  2833. PCLIR.SetMethods(PCLIR.sub, GenTyp1);
  2834. PCLIR.SetMethods(PCLIR.add, GenTyp1);
  2835. PCLIR.SetMethods(PCLIR.and, GenTyp1);
  2836. PCLIR.SetMethods(PCLIR.or, GenTyp1);
  2837. PCLIR.SetMethods(PCLIR.xor, GenTyp1);
  2838. PCLIR.SetMethods(PCLIR.ash, GenShift);
  2839. PCLIR.SetMethods(PCLIR.bsh, GenShift);
  2840. PCLIR.SetMethods(PCLIR.rot, GenShift);
  2841. PCLIR.SetMethods(PCLIR.move, GenMove);
  2842. PCLIR.SetMethods(PCLIR.moveDown, GenMoveDown);
  2843. PCLIR.SetMethods(PCLIR.inline, GenInline);
  2844. PCLIR.SetMethods(PCLIR.case, GenCase);
  2845. PCLIR.SetMethods(PCLIR.casel, GenCaseLine);
  2846. PCLIR.SetMethods(PCLIR.casee, GenCaseElse);
  2847. PCM.LogWStr("i386 code generator installed"); PCM.LogWLn;
  2848. END Install;
  2849. PROCEDURE Configure;
  2850. VAR i: SHORTINT;
  2851. BEGIN
  2852. TccOpcode[PCLIR.tae-PCLIR.tae] := PCO.JNAE;
  2853. TccOpcode[PCLIR.tne-PCLIR.tae] := PCO.JE;
  2854. JccOpcode[PCLIR.je-PCLIR.je, intMode] := PCO.JE;
  2855. JccOpcode[PCLIR.jne-PCLIR.je, intMode] := PCO.JNE;
  2856. JccOpcode[PCLIR.jlt-PCLIR.je, intMode] := PCO.JL;
  2857. JccOpcode[PCLIR.jle-PCLIR.je, intMode] := PCO.JLE;
  2858. JccOpcode[PCLIR.jgt-PCLIR.je, intMode] := PCO.JG;
  2859. JccOpcode[PCLIR.jge-PCLIR.je, intMode] := PCO.JGE;
  2860. JccOpcode[PCLIR.jb-PCLIR.je, intMode] := PCO.JB;
  2861. JccOpcode[PCLIR.jbe-PCLIR.je, intMode] := PCO.JBE;
  2862. JccOpcode[PCLIR.ja-PCLIR.je, intMode] := PCO.JA;
  2863. JccOpcode[PCLIR.jae-PCLIR.je, intMode] := PCO.JAE;
  2864. JccOpcode[PCLIR.jf-PCLIR.je, intMode] := PCO.JC;
  2865. JccOpcode[PCLIR.jnf-PCLIR.je, intMode] := PCO.JNC;
  2866. JccOpcode[PCLIR.je-PCLIR.je, floatMode] := PCO.JE;
  2867. JccOpcode[PCLIR.jne-PCLIR.je, floatMode] := PCO.JNE;
  2868. JccOpcode[PCLIR.jlt-PCLIR.je, floatMode] := PCO.JB;
  2869. JccOpcode[PCLIR.jle-PCLIR.je, floatMode] := PCO.JBE;
  2870. JccOpcode[PCLIR.jgt-PCLIR.je, floatMode] := PCO.JA;
  2871. JccOpcode[PCLIR.jge-PCLIR.je, floatMode] := PCO.JAE;
  2872. (* jb - jae not defined for FPU *)
  2873. JccOpcode[PCLIR.jf-PCLIR.je, floatMode] := PCO.JC;
  2874. JccOpcode[PCLIR.jnf-PCLIR.je, floatMode] := PCO.JNC;
  2875. Jcc2Opcode[PCLIR.je-PCLIR.je, 0] := 0;
  2876. Jcc2Opcode[PCLIR.je-PCLIR.je, 1] := PCO.JNE;
  2877. Jcc2Opcode[PCLIR.je-PCLIR.je, 2] := PCO.JE;
  2878. Jcc2Opcode[PCLIR.jne-PCLIR.je, 0] := PCO.JNE;
  2879. Jcc2Opcode[PCLIR.jne-PCLIR.je, 1] := 0;
  2880. Jcc2Opcode[PCLIR.jne-PCLIR.je, 2] := PCO.JNE;
  2881. Jcc2Opcode[PCLIR.jlt-PCLIR.je, 0] := PCO.JL;
  2882. Jcc2Opcode[PCLIR.jlt-PCLIR.je, 1] := PCO.JNE;
  2883. Jcc2Opcode[PCLIR.jlt-PCLIR.je, 2] := PCO.JB;
  2884. Jcc2Opcode[PCLIR.jle-PCLIR.je, 0] := PCO.JL;
  2885. Jcc2Opcode[PCLIR.jle-PCLIR.je, 1] := PCO.JNE;
  2886. Jcc2Opcode[PCLIR.jle-PCLIR.je, 2] := PCO.JBE;
  2887. Jcc2Opcode[PCLIR.jgt-PCLIR.je, 0] := PCO.JG;
  2888. Jcc2Opcode[PCLIR.jgt-PCLIR.je, 1] := PCO.JNE;
  2889. Jcc2Opcode[PCLIR.jgt-PCLIR.je, 2] := PCO.JA;
  2890. Jcc2Opcode[PCLIR.jge-PCLIR.je, 0] := PCO.JG;
  2891. Jcc2Opcode[PCLIR.jge-PCLIR.je, 1] := PCO.JNE;
  2892. Jcc2Opcode[PCLIR.jge-PCLIR.je, 2] := PCO.JAE;
  2893. (*
  2894. Jcc2Opcode[PCLIR.jb-PCLIR.je, intMode] := PCO.JB;
  2895. Jcc2Opcode[PCLIR.jbe-PCLIR.je, intMode] := PCO.JBE;
  2896. Jcc2Opcode[PCLIR.ja-PCLIR.je, intMode] := PCO.JA;
  2897. Jcc2Opcode[PCLIR.jae-PCLIR.je, intMode] := PCO.JAE;
  2898. Jcc2Opcode[PCLIR.jf-PCLIR.je, intMode] := PCO.JC;
  2899. Jcc2Opcode[PCLIR.jnf-PCLIR.je, intMode] := PCO.JNC;
  2900. *)
  2901. Typ1Opcode[PCLIR.sub-PCLIR.sub] := PCO.SUB;
  2902. Typ1Opcode[PCLIR.add-PCLIR.sub] := PCO.ADD;
  2903. Typ1Opcode[PCLIR.and-PCLIR.sub] := PCO.AND;
  2904. Typ1Opcode[PCLIR.or-PCLIR.sub] := PCO.Or;
  2905. Typ1Opcode[PCLIR.xor-PCLIR.sub] := PCO.XOR;
  2906. Typ1Opcode2[PCLIR.sub-PCLIR.sub] := PCO.SBB;
  2907. Typ1Opcode2[PCLIR.add-PCLIR.sub] := PCO.ADC;
  2908. Typ1Opcode2[PCLIR.and-PCLIR.sub] := PCO.AND;
  2909. Typ1Opcode2[PCLIR.or-PCLIR.sub] := PCO.Or;
  2910. Typ1Opcode2[PCLIR.xor-PCLIR.sub] := PCO.XOR;
  2911. Group3Opcode[PCLIR.neg-PCLIR.not] := PCO.NEG;
  2912. Group3Opcode[PCLIR.not-PCLIR.not] := PCO.NOT;
  2913. BitOpcode[PCLIR.bts-PCLIR.bts] := PCO.BTS;
  2914. BitOpcode[PCLIR.btc-PCLIR.bts] := PCO.BTR;
  2915. ShiftOpcode[PCLIR.ash-PCLIR.ash, left] := PCO.SAL;
  2916. ShiftOpcode[PCLIR.ash-PCLIR.ash, right] := PCO.SAR;
  2917. ShiftOpcode[PCLIR.bsh-PCLIR.ash, left] := PCO.SHL;
  2918. ShiftOpcode[PCLIR.bsh-PCLIR.ash, right] := PCO.SHR;
  2919. ShiftOpcode[PCLIR.rot-PCLIR.ash, left] := PCO.ROL;
  2920. ShiftOpcode[PCLIR.rot-PCLIR.ash, right] := PCO.Ror;
  2921. FOR i := 0 TO 6 DO FPSize[i] := -1 END;
  2922. FPSize[PCLIR.Int16] := PCO.wInt;
  2923. FPSize[PCLIR.Int32] := PCO.dInt;
  2924. FPSize[PCLIR.Int64] := PCO.qInt;
  2925. FPSize[PCLIR.Float32] := PCO.sReal;
  2926. FPSize[PCLIR.Float64] := PCO.lReal;
  2927. SaveLevel := 0;
  2928. RegName[PCLIR.Int8] := "B";
  2929. RegName[PCLIR.Int16] := "W";
  2930. RegName[PCLIR.Int32] := "D";
  2931. RegName[PCLIR.Int64] := "Q";
  2932. RegName[PCLIR.Float32] := "F";
  2933. RegName[PCLIR.Float64] := "G";
  2934. IReg[EAX] := "EAX"; IReg[EBX] := "EBX"; IReg[ECX] := "ECX"; IReg[EDX] := "EDX";
  2935. IReg[ESP] := "ESP"; IReg[EBP] := "EBP"; IReg[EDI] := "EDI"; IReg[ESI] := "ESI";
  2936. IReg[AX] := "AX"; IReg[BX] := "BX"; IReg[CX] := "CX"; IReg[DX] := "DX";
  2937. (*IReg[SP] := "ESP"; IReg[EBP] := "EBP"; IReg[EDI] := "EDI"; IReg[ESI] := "ESI";*)
  2938. IReg[AH] := "AH"; IReg[BH] := "BH"; IReg[CH] := "CH"; IReg[DH] := "DH";
  2939. IReg[AL] := "AL"; IReg[BL] := "BL"; IReg[CL] := "CL"; IReg[DL] := "DL";
  2940. END Configure;
  2941. BEGIN Configure;
  2942. IF TraceReg THEN PCM.LogWLn; PCM.LogWStr("PC386.TraceReg on") END
  2943. END PCG386.
  2944. (*
  2945. 15.11.06 ug GenCase, GenCaseLine, GenCaseElse adapted such that fixup chain contains 32 bit offsets
  2946. 20.09.03 prk "/Dcode" compiler option added
  2947. 03.07.03 prk setcc with float operands did spill destination register and store in wrong register when result used in return (return of float comparison is wrong)
  2948. 02.07.03 prk bug in setcc with 64bit operands fixed (did trash module body)
  2949. 29.06.03 prk bug in restoreregs fixed (pop 16bit instead of pop 32bit) (found by Vasile Rotaru)
  2950. 11.06.02 prk BIT implemented
  2951. 12.04.02 prk FullStackInit disabling compiler option
  2952. 04.04.02 prk DIV code pattern improved (proposed by pjm)
  2953. 02.04.02 prk Fix in LoadAdr (copy hw-register when load addr of 0[reg])
  2954. 18.03.02 prk PCBT code cleanup and redesign
  2955. 20.02.02 be refinement in the code generator plugin
  2956. 10.12.01 prk ENTIER: rounding mode set to chop, rounding modes caches as globals
  2957. 22.11.01 prk entier simplified
  2958. 11.08.01 prk Fixup and use lists for procedures in PCBT cleaned up
  2959. 10.08.01 prk PCBT.Procedure: imported: BOOLEAN replaced by owner: Module
  2960. 06.08.01 prk make code generator and object file generator indipendent
  2961. 06.08.01 prk Instruction: dst record removed, fields declared directly in instruction
  2962. 14.06.01 prk register spilling for when temporary 8bit registers not available
  2963. 13.06.01 prk GenMove optimized
  2964. 30.05.01 prk destination (\d) compiler-option to install the back-end
  2965. 30.05.01 prk optimize loadsp, try to keep value in ES
  2966. 29.05.01 be syscall structures moved to backend (PCLIR & code generators)
  2967. 28.05.01 prk Bug in local dynamic array allocation fixed
  2968. 14.05.01 prk PCLIR.lea removed
  2969. 11.05.01 prk correct handling of operation with hw-regs; PCLIR.loadsp instruction; PCC stack ops fixed
  2970. 11.05.01 prk When freeing stack, use pop instead of add (up to three words)
  2971. 07.05.01 prk Installable code generators moved to PCLIR; debug function added
  2972. 03.05.01 be Installable code generators
  2973. 26.04.01 prk PCLIR.lea partly removed
  2974. 15.03.01 prk ret2, result2 added
  2975. 15.03.01 prk calldel removed
  2976. 22.02.01 prk delegates
  2977. 12.09.00 prk FP Allocation
  2978. 12.09.00 prk GenLoad for FP
  2979. 30.08.00 prk conv -> convs/convu/copy
  2980. * barrier handling in Optimize/FSM
  2981. * SetRegisterHint
  2982. * Info initialization: Set to register at FSM or at init?
  2983. * different semantic for casel
  2984. o Debug code
  2985. o SetRegisterHint -> introduce "NiceToHave" and "MustBe" modes
  2986. o UseComplex: should return a PCO mode, not a PC386 one
  2987. o Use RealAddress in PCO to pass parameters
  2988. 4 optimize (FSM) cascaded convs (e.g. SHORT(SHORT()) )
  2989. Assert Values:
  2990. 1000 Allocated Register found
  2991. 1001 Allocated FP Register found
  2992. 1002 Unvalid register requested
  2993. 1003 Implementation restriction: pc # 0
  2994. 1004 Requested Register is not available (32-bit in use)
  2995. 1005 Requested Register is not available (8-bit in use)
  2996. 1006 Requested Register is not available
  2997. 1007 Sanity check 1
  2998. 1008 Sanity check 2
  2999. 1009 Could not find a free 8-bit register
  3000. 1010 Invalid Register Size
  3001. 1011 Implementation restriction: pc # 0
  3002. 1012 Could not find a register
  3003. 1013 No free regs left
  3004. 1014 No free regs left
  3005. 1015 FPU Stack Overflow
  3006. 1016 Unvalid register requested
  3007. 1017 Register is already free
  3008. 1018 Register splitted, cannot free
  3009. 1019 Register is already free
  3010. 1020 Register is already free
  3011. 1021 Freed register is not ST(0)/ST(1)
  3012. 1022 Register is already free
  3013. 1023 Unvalid register requested
  3014. *)