cgx86.pas 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements the common parts of the code generator for the i386 and the x86-64.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. { This unit implements the common parts of the code generator for the i386 and the x86-64.
  19. }
  20. unit cgx86;
  21. {$i fpcdefs.inc}
  22. interface
  23. uses
  24. cgbase,cgobj,
  25. aasmbase,aasmtai,aasmcpu,
  26. cpubase,cpuinfo,rgobj,rgx86,rgcpu,
  27. symconst,symtype;
  28. type
  29. tcgx86 = class(tcg)
  30. rgfpu : Trgx86fpu;
  31. procedure done_register_allocators;override;
  32. function getfpuregister(list:Taasmoutput;size:Tcgsize):Tregister;override;
  33. function getmmxregister(list:Taasmoutput):Tregister;
  34. procedure getexplicitregister(list:Taasmoutput;r:Tregister);override;
  35. procedure ungetregister(list:Taasmoutput;r:Tregister);override;
  36. procedure allocexplicitregisters(list:Taasmoutput;rt:Tregistertype;r:Tcpuregisterset);override;
  37. procedure deallocexplicitregisters(list:Taasmoutput;rt:Tregistertype;r:Tcpuregisterset);override;
  38. function uses_registers(rt:Tregistertype):boolean;override;
  39. procedure add_reg_instruction(instr:Tai;r:tregister);override;
  40. procedure dec_fpu_stack;
  41. procedure inc_fpu_stack;
  42. { passing parameters, per default the parameter is pushed }
  43. { nr gives the number of the parameter (enumerated from }
  44. { left to right), this allows to move the parameter to }
  45. { register, if the cpu supports register calling }
  46. { conventions }
  47. procedure a_param_reg(list : taasmoutput;size : tcgsize;r : tregister;const locpara : tparalocation);override;
  48. procedure a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);override;
  49. procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);override;
  50. procedure a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);override;
  51. procedure a_call_name(list : taasmoutput;const s : string);override;
  52. procedure a_call_reg(list : taasmoutput;reg : tregister);override;
  53. procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; reg: TRegister); override;
  54. procedure a_op_const_ref(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; const ref: TReference); override;
  55. procedure a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  56. procedure a_op_ref_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister); override;
  57. procedure a_op_reg_ref(list : taasmoutput; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference); override;
  58. procedure a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  59. size: tcgsize; a: aword; src, dst: tregister); override;
  60. procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  61. size: tcgsize; src1, src2, dst: tregister); override;
  62. { move instructions }
  63. procedure a_load_const_reg(list : taasmoutput; tosize: tcgsize; a : aword;reg : tregister);override;
  64. procedure a_load_const_ref(list : taasmoutput; tosize: tcgsize; a : aword;const ref : treference);override;
  65. procedure a_load_reg_ref(list : taasmoutput;fromsize,tosize: tcgsize; reg : tregister;const ref : treference);override;
  66. procedure a_load_ref_reg(list : taasmoutput;fromsize,tosize: tcgsize;const ref : treference;reg : tregister);override;
  67. procedure a_load_reg_reg(list : taasmoutput;fromsize,tosize: tcgsize;reg1,reg2 : tregister);override;
  68. procedure a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
  69. { fpu move instructions }
  70. procedure a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister); override;
  71. procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister); override;
  72. procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference); override;
  73. { vector register move instructions }
  74. procedure a_loadmm_reg_reg(list: taasmoutput; fromsize, tosize : tcgsize;reg1, reg2: tregister;shuffle : pmmshuffle); override;
  75. procedure a_loadmm_ref_reg(list: taasmoutput; fromsize, tosize : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle); override;
  76. procedure a_loadmm_reg_ref(list: taasmoutput; fromsize, tosize : tcgsize;reg: tregister; const ref: treference;shuffle : pmmshuffle); override;
  77. procedure a_opmm_ref_reg(list: taasmoutput; Op: TOpCG; size : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle); override;
  78. procedure a_opmm_reg_reg(list: taasmoutput; Op: TOpCG; size : tcgsize;src,dst: tregister;shuffle : pmmshuffle);override;
  79. { comparison operations }
  80. procedure a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  81. l : tasmlabel);override;
  82. procedure a_cmp_const_ref_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;const ref : treference;
  83. l : tasmlabel);override;
  84. procedure a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  85. procedure a_cmp_ref_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;const ref: treference; reg : tregister; l : tasmlabel); override;
  86. procedure a_jmp_always(list : taasmoutput;l: tasmlabel); override;
  87. procedure a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel); override;
  88. procedure g_flags2reg(list: taasmoutput; size: TCgSize; const f: tresflags; reg: TRegister); override;
  89. procedure g_flags2ref(list: taasmoutput; size: TCgSize; const f: tresflags; const ref: TReference); override;
  90. procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);override;
  91. procedure g_exception_reason_save(list : taasmoutput; const href : treference);override;
  92. procedure g_exception_reason_save_const(list : taasmoutput; const href : treference; a: aword);override;
  93. procedure g_exception_reason_load(list : taasmoutput; const href : treference);override;
  94. { entry/exit code helpers }
  95. procedure g_releasevaluepara_openarray(list : taasmoutput;const ref:treference);override;
  96. procedure g_interrupt_stackframe_entry(list : taasmoutput);override;
  97. procedure g_interrupt_stackframe_exit(list : taasmoutput;accused,acchiused:boolean);override;
  98. procedure g_profilecode(list : taasmoutput);override;
  99. procedure g_stackpointer_alloc(list : taasmoutput;localsize : longint);override;
  100. procedure g_stackframe_entry(list : taasmoutput;localsize : longint);override;
  101. procedure g_restore_frame_pointer(list : taasmoutput);override;
  102. procedure g_return_from_proc(list : taasmoutput;parasize : aword);override;
  103. procedure g_save_standard_registers(list:Taasmoutput);override;
  104. procedure g_restore_standard_registers(list:Taasmoutput);override;
  105. procedure g_overflowcheck(list: taasmoutput; const l:tlocation;def:tdef);override;
  106. protected
  107. procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  108. procedure check_register_size(size:tcgsize;reg:tregister);
  109. procedure opmm_loc_reg(list: taasmoutput; Op: TOpCG; size : tcgsize;loc : tlocation;dst: tregister; shuffle : pmmshuffle);
  110. private
  111. procedure sizes2load(s1,s2 : tcgsize;var op: tasmop; var s3: topsize);
  112. procedure floatload(list: taasmoutput; t : tcgsize;const ref : treference);
  113. procedure floatstore(list: taasmoutput; t : tcgsize;const ref : treference);
  114. procedure floatloadops(t : tcgsize;var op : tasmop;var s : topsize);
  115. procedure floatstoreops(t : tcgsize;var op : tasmop;var s : topsize);
  116. end;
  117. function use_sse(def : tdef) : boolean;
  118. const
  119. {$ifdef x86_64}
  120. TCGSize2OpSize: Array[tcgsize] of topsize =
  121. (S_NO,S_B,S_W,S_L,S_Q,S_Q,S_B,S_W,S_L,S_Q,S_Q,
  122. S_FS,S_FL,S_FX,S_IQ,S_FXX,
  123. S_NO,S_NO,S_NO,S_MD,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO);
  124. {$else x86_64}
  125. TCGSize2OpSize: Array[tcgsize] of topsize =
  126. (S_NO,S_B,S_W,S_L,S_L,S_L,S_B,S_W,S_L,S_L,S_L,
  127. S_FS,S_FL,S_FX,S_IQ,S_FXX,
  128. S_NO,S_NO,S_NO,S_MD,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO);
  129. {$endif x86_64}
  130. {$ifndef NOTARGETWIN32}
  131. winstackpagesize = 4096;
  132. {$endif NOTARGETWIN32}
  133. implementation
  134. uses
  135. globtype,globals,verbose,systems,cutils,
  136. cgutils,
  137. symdef,defutil,paramgr,tgobj,procinfo;
  138. const
  139. TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,A_ADD,A_AND,A_DIV,
  140. A_IDIV,A_MUL, A_IMUL, A_NEG,A_NOT,A_OR,
  141. A_SAR,A_SHL,A_SHR,A_SUB,A_XOR);
  142. TOpCmp2AsmCond: Array[topcmp] of TAsmCond = (C_NONE,
  143. C_E,C_G,C_L,C_GE,C_LE,C_NE,C_BE,C_B,C_AE,C_A);
  144. function use_sse(def : tdef) : boolean;
  145. begin
  146. use_sse:=(is_single(def) and (aktfputype in sse_singlescalar)) or
  147. (is_double(def) and (aktfputype in sse_doublescalar));
  148. end;
  149. procedure Tcgx86.done_register_allocators;
  150. begin
  151. rg[R_INTREGISTER].free;
  152. rg[R_MMREGISTER].free;
  153. rg[R_MMXREGISTER].free;
  154. rgfpu.free;
  155. inherited done_register_allocators;
  156. end;
  157. function Tcgx86.getfpuregister(list:Taasmoutput;size:Tcgsize):Tregister;
  158. begin
  159. result:=rgfpu.getregisterfpu(list);
  160. end;
  161. function Tcgx86.getmmxregister(list:Taasmoutput):Tregister;
  162. begin
  163. if not assigned(rg[R_MMXREGISTER]) then
  164. internalerror(200312124);
  165. result:=rg[R_MMXREGISTER].getregister(list,R_SUBNONE);
  166. end;
  167. procedure Tcgx86.getexplicitregister(list:Taasmoutput;r:Tregister);
  168. begin
  169. if getregtype(r)=R_FPUREGISTER then
  170. internalerror(2003121210)
  171. else
  172. inherited getexplicitregister(list,r);
  173. end;
  174. procedure tcgx86.ungetregister(list:Taasmoutput;r:Tregister);
  175. begin
  176. if getregtype(r)=R_FPUREGISTER then
  177. rgfpu.ungetregisterfpu(list,r)
  178. else
  179. inherited ungetregister(list,r);
  180. end;
  181. procedure Tcgx86.allocexplicitregisters(list:Taasmoutput;rt:Tregistertype;r:Tcpuregisterset);
  182. begin
  183. if rt<>R_FPUREGISTER then
  184. inherited allocexplicitregisters(list,rt,r);
  185. end;
  186. procedure Tcgx86.deallocexplicitregisters(list:Taasmoutput;rt:Tregistertype;r:Tcpuregisterset);
  187. begin
  188. if rt<>R_FPUREGISTER then
  189. inherited deallocexplicitregisters(list,rt,r);
  190. end;
  191. function Tcgx86.uses_registers(rt:Tregistertype):boolean;
  192. begin
  193. if rt=R_FPUREGISTER then
  194. result:=false
  195. else
  196. result:=inherited uses_registers(rt);
  197. end;
  198. procedure tcgx86.add_reg_instruction(instr:Tai;r:tregister);
  199. begin
  200. if getregtype(r)<>R_FPUREGISTER then
  201. inherited add_reg_instruction(instr,r);
  202. end;
  203. procedure tcgx86.dec_fpu_stack;
  204. begin
  205. dec(rgfpu.fpuvaroffset);
  206. end;
  207. procedure tcgx86.inc_fpu_stack;
  208. begin
  209. inc(rgfpu.fpuvaroffset);
  210. end;
  211. {****************************************************************************
  212. This is private property, keep out! :)
  213. ****************************************************************************}
  214. procedure tcgx86.sizes2load(s1,s2 : tcgsize; var op: tasmop; var s3: topsize);
  215. begin
  216. case s2 of
  217. OS_8,OS_S8 :
  218. if S1 in [OS_8,OS_S8] then
  219. s3 := S_B
  220. else
  221. internalerror(200109221);
  222. OS_16,OS_S16:
  223. case s1 of
  224. OS_8,OS_S8:
  225. s3 := S_BW;
  226. OS_16,OS_S16:
  227. s3 := S_W;
  228. else
  229. internalerror(200109222);
  230. end;
  231. OS_32,OS_S32:
  232. case s1 of
  233. OS_8,OS_S8:
  234. s3 := S_BL;
  235. OS_16,OS_S16:
  236. s3 := S_WL;
  237. OS_32,OS_S32:
  238. s3 := S_L;
  239. else
  240. internalerror(200109223);
  241. end;
  242. {$ifdef x86_64}
  243. OS_64,OS_S64:
  244. case s1 of
  245. OS_8,OS_S8:
  246. s3 := S_BL;
  247. OS_16,OS_S16:
  248. s3 := S_WL;
  249. OS_32,OS_S32:
  250. s3 := S_L;
  251. OS_64,OS_S64:
  252. s3 := S_Q;
  253. else
  254. internalerror(200304302);
  255. end;
  256. {$endif x86_64}
  257. else
  258. internalerror(200109227);
  259. end;
  260. if s3 in [S_B,S_W,S_L,S_Q] then
  261. op := A_MOV
  262. else if s1 in [OS_8,OS_16,OS_32,OS_64] then
  263. op := A_MOVZX
  264. else
  265. op := A_MOVSX;
  266. end;
  267. procedure tcgx86.floatloadops(t : tcgsize;var op : tasmop;var s : topsize);
  268. begin
  269. case t of
  270. OS_F32 :
  271. begin
  272. op:=A_FLD;
  273. s:=S_FS;
  274. end;
  275. OS_F64 :
  276. begin
  277. op:=A_FLD;
  278. { ???? }
  279. s:=S_FL;
  280. end;
  281. OS_F80 :
  282. begin
  283. op:=A_FLD;
  284. s:=S_FX;
  285. end;
  286. OS_C64 :
  287. begin
  288. op:=A_FILD;
  289. s:=S_IQ;
  290. end;
  291. else
  292. internalerror(200204041);
  293. end;
  294. end;
  295. procedure tcgx86.floatload(list: taasmoutput; t : tcgsize;const ref : treference);
  296. var
  297. op : tasmop;
  298. s : topsize;
  299. begin
  300. floatloadops(t,op,s);
  301. list.concat(Taicpu.Op_ref(op,s,ref));
  302. inc_fpu_stack;
  303. end;
  304. procedure tcgx86.floatstoreops(t : tcgsize;var op : tasmop;var s : topsize);
  305. begin
  306. case t of
  307. OS_F32 :
  308. begin
  309. op:=A_FSTP;
  310. s:=S_FS;
  311. end;
  312. OS_F64 :
  313. begin
  314. op:=A_FSTP;
  315. s:=S_FL;
  316. end;
  317. OS_F80 :
  318. begin
  319. op:=A_FSTP;
  320. s:=S_FX;
  321. end;
  322. OS_C64 :
  323. begin
  324. op:=A_FISTP;
  325. s:=S_IQ;
  326. end;
  327. else
  328. internalerror(200204042);
  329. end;
  330. end;
  331. procedure tcgx86.floatstore(list: taasmoutput; t : tcgsize;const ref : treference);
  332. var
  333. op : tasmop;
  334. s : topsize;
  335. begin
  336. floatstoreops(t,op,s);
  337. list.concat(Taicpu.Op_ref(op,s,ref));
  338. dec_fpu_stack;
  339. end;
  340. procedure tcgx86.check_register_size(size:tcgsize;reg:tregister);
  341. begin
  342. if TCGSize2OpSize[size]<>TCGSize2OpSize[reg_cgsize(reg)] then
  343. internalerror(200306031);
  344. end;
  345. {****************************************************************************
  346. Assembler code
  347. ****************************************************************************}
  348. { currently does nothing }
  349. procedure tcgx86.a_jmp_always(list : taasmoutput;l: tasmlabel);
  350. begin
  351. a_jmp_cond(list, OC_NONE, l);
  352. end;
  353. { we implement the following routines because otherwise we can't }
  354. { instantiate the class since it's abstract }
  355. procedure tcgx86.a_param_reg(list : taasmoutput;size : tcgsize;r : tregister;const locpara : tparalocation);
  356. var
  357. pushsize : tcgsize;
  358. begin
  359. check_register_size(size,r);
  360. with locpara do
  361. if (loc=LOC_REFERENCE) and
  362. (reference.index=NR_STACK_POINTER_REG) then
  363. begin
  364. pushsize:=int_cgsize(alignment);
  365. list.concat(taicpu.op_reg(A_PUSH,tcgsize2opsize[pushsize],makeregsize(r,pushsize)));
  366. end
  367. else
  368. inherited a_param_reg(list,size,r,locpara);
  369. end;
  370. procedure tcgx86.a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);
  371. var
  372. pushsize : tcgsize;
  373. begin
  374. with locpara do
  375. if (loc=LOC_REFERENCE) and
  376. (reference.index=NR_STACK_POINTER_REG) then
  377. begin
  378. pushsize:=int_cgsize(alignment);
  379. list.concat(taicpu.op_const(A_PUSH,tcgsize2opsize[pushsize],a));
  380. end
  381. else
  382. inherited a_param_const(list,size,a,locpara);
  383. end;
  384. procedure tcgx86.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);
  385. var
  386. pushsize : tcgsize;
  387. tmpreg : tregister;
  388. begin
  389. with locpara do
  390. if (loc=LOC_REFERENCE) and
  391. (reference.index=NR_STACK_POINTER_REG) then
  392. begin
  393. pushsize:=int_cgsize(alignment);
  394. if tcgsize2size[size]<alignment then
  395. begin
  396. tmpreg:=getintregister(list,pushsize);
  397. a_load_ref_reg(list,size,pushsize,r,tmpreg);
  398. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize],tmpreg));
  399. ungetregister(list,tmpreg);
  400. end
  401. else
  402. list.concat(taicpu.op_ref(A_PUSH,TCgsize2opsize[pushsize],r));
  403. end
  404. else
  405. inherited a_param_ref(list,size,r,locpara);
  406. end;
  407. procedure tcgx86.a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);
  408. var
  409. tmpreg : tregister;
  410. opsize : topsize;
  411. begin
  412. with r do
  413. begin
  414. if (segment<>NR_NO) then
  415. cgmessage(cg_e_cant_use_far_pointer_there);
  416. with locpara do
  417. if (locpara.loc=LOC_REFERENCE) and
  418. (locpara.reference.index=NR_STACK_POINTER_REG) then
  419. begin
  420. opsize:=tcgsize2opsize[OS_ADDR];
  421. if (base=NR_NO) and (index=NR_NO) then
  422. begin
  423. if assigned(symbol) then
  424. list.concat(Taicpu.Op_sym_ofs(A_PUSH,opsize,symbol,offset))
  425. else
  426. list.concat(Taicpu.Op_const(A_PUSH,opsize,offset));
  427. end
  428. else if (base=NR_NO) and (index<>NR_NO) and
  429. (offset=0) and (scalefactor=0) and (symbol=nil) then
  430. list.concat(Taicpu.Op_reg(A_PUSH,opsize,index))
  431. else if (base<>NR_NO) and (index=NR_NO) and
  432. (offset=0) and (symbol=nil) then
  433. list.concat(Taicpu.Op_reg(A_PUSH,opsize,base))
  434. else
  435. begin
  436. tmpreg:=getaddressregister(list);
  437. a_loadaddr_ref_reg(list,r,tmpreg);
  438. ungetregister(list,tmpreg);
  439. list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
  440. end;
  441. end
  442. else
  443. inherited a_paramaddr_ref(list,r,locpara);
  444. end;
  445. end;
  446. procedure tcgx86.a_call_name(list : taasmoutput;const s : string);
  447. begin
  448. list.concat(taicpu.op_sym(A_CALL,S_NO,objectlibrary.newasmsymbol(s)));
  449. end;
  450. procedure tcgx86.a_call_reg(list : taasmoutput;reg : tregister);
  451. begin
  452. list.concat(taicpu.op_reg(A_CALL,S_NO,reg));
  453. end;
  454. {********************** load instructions ********************}
  455. procedure tcgx86.a_load_const_reg(list : taasmoutput; tosize: TCGSize; a : aword; reg : TRegister);
  456. begin
  457. check_register_size(tosize,reg);
  458. { the optimizer will change it to "xor reg,reg" when loading zero, }
  459. { no need to do it here too (JM) }
  460. list.concat(taicpu.op_const_reg(A_MOV,TCGSize2OpSize[tosize],a,reg))
  461. end;
  462. procedure tcgx86.a_load_const_ref(list : taasmoutput; tosize: tcgsize; a : aword;const ref : treference);
  463. begin
  464. list.concat(taicpu.op_const_ref(A_MOV,TCGSize2OpSize[tosize],a,ref));
  465. end;
  466. procedure tcgx86.a_load_reg_ref(list : taasmoutput; fromsize,tosize: TCGSize; reg : tregister;const ref : treference);
  467. var
  468. op: tasmop;
  469. s: topsize;
  470. tmpreg : tregister;
  471. begin
  472. check_register_size(fromsize,reg);
  473. sizes2load(fromsize,tosize,op,s);
  474. case s of
  475. {$ifdef x86_64}
  476. S_BQ,S_WQ,S_LQ,
  477. {$endif x86_64}
  478. S_BW,S_BL,S_WL :
  479. begin
  480. tmpreg:=getintregister(list,tosize);
  481. {$ifdef x86_64}
  482. { zero extensions to 64 bit on the x86_64 are simply done by writting to the lower 32 bit
  483. which clears the upper 64 bit too, so it could be that s is S_L while the reg is
  484. 64 bit (FK) }
  485. if s in [S_BL,S_WL,S_L] then
  486. tmpreg:=makeregsize(tmpreg,OS_32);
  487. {$endif x86_64}
  488. list.concat(taicpu.op_reg_reg(op,s,reg,tmpreg));
  489. a_load_reg_ref(list,tosize,tosize,tmpreg,ref);
  490. ungetregister(list,tmpreg);
  491. end;
  492. else
  493. list.concat(taicpu.op_reg_ref(op,s,reg,ref));
  494. end;
  495. end;
  496. procedure tcgx86.a_load_ref_reg(list : taasmoutput;fromsize,tosize : tcgsize;const ref: treference;reg : tregister);
  497. var
  498. op: tasmop;
  499. s: topsize;
  500. begin
  501. check_register_size(tosize,reg);
  502. sizes2load(fromsize,tosize,op,s);
  503. {$ifdef x86_64}
  504. { zero extensions to 64 bit on the x86_64 are simply done by writting to the lower 32 bit
  505. which clears the upper 64 bit too, so it could be that s is S_L while the reg is
  506. 64 bit (FK) }
  507. if s in [S_BL,S_WL,S_L] then
  508. reg:=makeregsize(reg,OS_32);
  509. {$endif x86_64}
  510. list.concat(taicpu.op_ref_reg(op,s,ref,reg));
  511. end;
  512. procedure tcgx86.a_load_reg_reg(list : taasmoutput;fromsize,tosize : tcgsize;reg1,reg2 : tregister);
  513. var
  514. op: tasmop;
  515. s: topsize;
  516. instr:Taicpu;
  517. begin
  518. check_register_size(fromsize,reg1);
  519. check_register_size(tosize,reg2);
  520. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  521. begin
  522. reg1:=makeregsize(reg1,tosize);
  523. s:=tcgsize2opsize[tosize];
  524. op:=A_MOV;
  525. end
  526. else
  527. sizes2load(fromsize,tosize,op,s);
  528. {$ifdef x86_64}
  529. { zero extensions to 64 bit on the x86_64 are simply done by writting to the lower 32 bit
  530. which clears the upper 64 bit too, so it could be that s is S_L while the reg is
  531. 64 bit (FK) }
  532. if s in [S_BL,S_WL,S_L] then
  533. reg2:=makeregsize(reg2,OS_32);
  534. {$endif x86_64}
  535. instr:=taicpu.op_reg_reg(op,s,reg1,reg2);
  536. { Notify the register allocator that we have written a move instruction so
  537. it can try to eliminate it. }
  538. add_move_instruction(instr);
  539. list.concat(instr);
  540. end;
  541. procedure tcgx86.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  542. begin
  543. with ref do
  544. if (base=NR_NO) and (index=NR_NO) then
  545. begin
  546. if assigned(ref.symbol) then
  547. list.concat(Taicpu.op_sym_ofs_reg(A_MOV,tcgsize2opsize[OS_ADDR],symbol,offset,r))
  548. else
  549. a_load_const_reg(list,OS_ADDR,offset,r);
  550. end
  551. else if (base=NR_NO) and (index<>NR_NO) and
  552. (offset=0) and (scalefactor=0) and (symbol=nil) then
  553. a_load_reg_reg(list,OS_ADDR,OS_ADDR,index,r)
  554. else if (base<>NR_NO) and (index=NR_NO) and
  555. (offset=0) and (symbol=nil) then
  556. a_load_reg_reg(list,OS_ADDR,OS_ADDR,base,r)
  557. else
  558. list.concat(taicpu.op_ref_reg(A_LEA,tcgsize2opsize[OS_ADDR],ref,r));
  559. end;
  560. { all fpu load routines expect that R_ST[0-7] means an fpu regvar and }
  561. { R_ST means "the current value at the top of the fpu stack" (JM) }
  562. procedure tcgx86.a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister);
  563. begin
  564. if (reg1<>NR_ST) then
  565. begin
  566. list.concat(taicpu.op_reg(A_FLD,S_NO,rgfpu.correct_fpuregister(reg1,rgfpu.fpuvaroffset)));
  567. inc_fpu_stack;
  568. end;
  569. if (reg2<>NR_ST) then
  570. begin
  571. list.concat(taicpu.op_reg(A_FSTP,S_NO,rgfpu.correct_fpuregister(reg2,rgfpu.fpuvaroffset)));
  572. dec_fpu_stack;
  573. end;
  574. end;
  575. procedure tcgx86.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  576. begin
  577. floatload(list,size,ref);
  578. if (reg<>NR_ST) then
  579. a_loadfpu_reg_reg(list,size,NR_ST,reg);
  580. end;
  581. procedure tcgx86.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  582. begin
  583. if reg<>NR_ST then
  584. a_loadfpu_reg_reg(list,size,reg,NR_ST);
  585. floatstore(list,size,ref);
  586. end;
  587. function get_scalar_mm_op(fromsize,tosize : tcgsize) : tasmop;
  588. begin
  589. case fromsize of
  590. OS_F32:
  591. case tosize of
  592. OS_F64:
  593. result:=A_CVTSS2SD;
  594. OS_F32:
  595. result:=A_MOVSS;
  596. else
  597. internalerror(200312205);
  598. end;
  599. OS_F64:
  600. case tosize of
  601. OS_F64:
  602. result:=A_MOVSD;
  603. OS_F32:
  604. result:=A_CVTSD2SS;
  605. else
  606. internalerror(200312204);
  607. end;
  608. else
  609. internalerror(200312203);
  610. end;
  611. end;
  612. procedure tcgx86.a_loadmm_reg_reg(list: taasmoutput; fromsize, tosize : tcgsize;reg1, reg2: tregister;shuffle : pmmshuffle);
  613. begin
  614. if shuffle=nil then
  615. begin
  616. if fromsize=tosize then
  617. list.concat(taicpu.op_reg_reg(A_MOVAPS,S_NO,reg1,reg2))
  618. else
  619. internalerror(200312202);
  620. end
  621. else if shufflescalar(shuffle) then
  622. list.concat(taicpu.op_reg_reg(get_scalar_mm_op(fromsize,tosize),S_NO,reg1,reg2))
  623. else
  624. internalerror(200312201);
  625. end;
  626. procedure tcgx86.a_loadmm_ref_reg(list: taasmoutput; fromsize, tosize : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle);
  627. begin
  628. if shuffle=nil then
  629. begin
  630. list.concat(taicpu.op_ref_reg(A_MOVQ,S_NO,ref,reg));
  631. end
  632. else if shufflescalar(shuffle) then
  633. list.concat(taicpu.op_ref_reg(get_scalar_mm_op(fromsize,tosize),S_NO,ref,reg))
  634. else
  635. internalerror(200312252);
  636. end;
  637. procedure tcgx86.a_loadmm_reg_ref(list: taasmoutput; fromsize, tosize : tcgsize;reg: tregister; const ref: treference;shuffle : pmmshuffle);
  638. begin
  639. if shuffle=nil then
  640. begin
  641. list.concat(taicpu.op_ref_reg(A_MOVQ,S_NO,ref,reg));
  642. end
  643. else if shufflescalar(shuffle) then
  644. list.concat(taicpu.op_reg_ref(get_scalar_mm_op(fromsize,tosize),S_NO,reg,ref))
  645. else
  646. internalerror(200312252);
  647. end;
  648. procedure tcgx86.a_opmm_ref_reg(list: taasmoutput; Op: TOpCG; size : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle);
  649. var
  650. l : tlocation;
  651. begin
  652. l.loc:=LOC_REFERENCE;
  653. l.reference:=ref;
  654. l.size:=size;
  655. opmm_loc_reg(list,op,size,l,reg,shuffle);
  656. end;
  657. procedure tcgx86.a_opmm_reg_reg(list: taasmoutput; Op: TOpCG; size : tcgsize;src,dst: tregister;shuffle : pmmshuffle);
  658. var
  659. l : tlocation;
  660. begin
  661. l.loc:=LOC_MMREGISTER;
  662. l.register:=src;
  663. l.size:=size;
  664. opmm_loc_reg(list,op,size,l,dst,shuffle);
  665. end;
  666. procedure tcgx86.opmm_loc_reg(list: taasmoutput; Op: TOpCG; size : tcgsize;loc : tlocation;dst: tregister; shuffle : pmmshuffle);
  667. const
  668. opmm2asmop : array[0..1,OS_F32..OS_F64,topcg] of tasmop = (
  669. ( { scalar }
  670. ( { OS_F32 }
  671. A_NOP,A_ADDSS,A_NOP,A_DIVSS,A_NOP,A_NOP,A_MULSS,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_SUBSS,A_NOP
  672. ),
  673. ( { OS_F64 }
  674. A_NOP,A_ADDSD,A_NOP,A_DIVSD,A_NOP,A_NOP,A_MULSD,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_SUBSD,A_NOP
  675. )
  676. ),
  677. ( { vectorized/packed }
  678. { because the logical packed single instructions have shorter op codes, we use always
  679. these
  680. }
  681. ( { OS_F32 }
  682. A_NOP,A_ADDPS,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_XORPS
  683. ),
  684. ( { OS_F64 }
  685. A_NOP,A_ADDPD,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_XORPS
  686. )
  687. )
  688. );
  689. var
  690. resultreg : tregister;
  691. asmop : tasmop;
  692. begin
  693. { this is an internally used procedure so the parameters have
  694. some constrains
  695. }
  696. if loc.size<>size then
  697. internalerror(200312213);
  698. resultreg:=dst;
  699. { deshuffle }
  700. //!!!
  701. if (shuffle<>nil) and not(shufflescalar(shuffle)) then
  702. begin
  703. end
  704. else if (shuffle=nil) then
  705. asmop:=opmm2asmop[1,size,op]
  706. else if shufflescalar(shuffle) then
  707. begin
  708. asmop:=opmm2asmop[0,size,op];
  709. { no scalar operation available? }
  710. if asmop=A_NOP then
  711. begin
  712. { do vectorized and shuffle finally }
  713. //!!!
  714. end;
  715. end
  716. else
  717. internalerror(200312211);
  718. if asmop=A_NOP then
  719. internalerror(200312215);
  720. case loc.loc of
  721. LOC_CREFERENCE,LOC_REFERENCE:
  722. list.concat(taicpu.op_ref_reg(asmop,S_NO,loc.reference,resultreg));
  723. LOC_CMMREGISTER,LOC_MMREGISTER:
  724. list.concat(taicpu.op_reg_reg(asmop,S_NO,loc.register,resultreg));
  725. else
  726. internalerror(200312214);
  727. end;
  728. { shuffle }
  729. if resultreg<>dst then
  730. begin
  731. internalerror(200312212);
  732. end;
  733. end;
  734. procedure tcgx86.a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; reg: TRegister);
  735. var
  736. opcode: tasmop;
  737. power: longint;
  738. begin
  739. check_register_size(size,reg);
  740. case op of
  741. OP_DIV, OP_IDIV:
  742. begin
  743. if ispowerof2(a,power) then
  744. begin
  745. case op of
  746. OP_DIV:
  747. opcode := A_SHR;
  748. OP_IDIV:
  749. opcode := A_SAR;
  750. end;
  751. list.concat(taicpu.op_const_reg(opcode,TCgSize2OpSize[size],power,reg));
  752. exit;
  753. end;
  754. { the rest should be handled specifically in the code }
  755. { generator because of the silly register usage restraints }
  756. internalerror(200109224);
  757. end;
  758. OP_MUL,OP_IMUL:
  759. begin
  760. if not(cs_check_overflow in aktlocalswitches) and
  761. ispowerof2(a,power) then
  762. begin
  763. list.concat(taicpu.op_const_reg(A_SHL,TCgSize2OpSize[size],power,reg));
  764. exit;
  765. end;
  766. if op = OP_IMUL then
  767. list.concat(taicpu.op_const_reg(A_IMUL,TCgSize2OpSize[size],a,reg))
  768. else
  769. { OP_MUL should be handled specifically in the code }
  770. { generator because of the silly register usage restraints }
  771. internalerror(200109225);
  772. end;
  773. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  774. if not(cs_check_overflow in aktlocalswitches) and
  775. (a = 1) and
  776. (op in [OP_ADD,OP_SUB]) then
  777. if op = OP_ADD then
  778. list.concat(taicpu.op_reg(A_INC,TCgSize2OpSize[size],reg))
  779. else
  780. list.concat(taicpu.op_reg(A_DEC,TCgSize2OpSize[size],reg))
  781. else if (a = 0) then
  782. if (op <> OP_AND) then
  783. exit
  784. else
  785. list.concat(taicpu.op_const_reg(A_MOV,TCgSize2OpSize[size],0,reg))
  786. else if (a = high(aword)) and
  787. (op in [OP_AND,OP_OR,OP_XOR]) then
  788. begin
  789. case op of
  790. OP_AND:
  791. exit;
  792. OP_OR:
  793. list.concat(taicpu.op_const_reg(A_MOV,TCgSize2OpSize[size],high(aword),reg));
  794. OP_XOR:
  795. list.concat(taicpu.op_reg(A_NOT,TCgSize2OpSize[size],reg));
  796. end
  797. end
  798. else
  799. list.concat(taicpu.op_const_reg(TOpCG2AsmOp[op],TCgSize2OpSize[size],a,reg));
  800. OP_SHL,OP_SHR,OP_SAR:
  801. begin
  802. if (a and 31) <> 0 Then
  803. list.concat(taicpu.op_const_reg(TOpCG2AsmOp[op],TCgSize2OpSize[size],a and 31,reg));
  804. if (a shr 5) <> 0 Then
  805. internalerror(68991);
  806. end
  807. else internalerror(68992);
  808. end;
  809. end;
  810. procedure tcgx86.a_op_const_ref(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; const ref: TReference);
  811. var
  812. opcode: tasmop;
  813. power: longint;
  814. begin
  815. Case Op of
  816. OP_DIV, OP_IDIV:
  817. Begin
  818. if ispowerof2(a,power) then
  819. begin
  820. case op of
  821. OP_DIV:
  822. opcode := A_SHR;
  823. OP_IDIV:
  824. opcode := A_SAR;
  825. end;
  826. list.concat(taicpu.op_const_ref(opcode,
  827. TCgSize2OpSize[size],power,ref));
  828. exit;
  829. end;
  830. { the rest should be handled specifically in the code }
  831. { generator because of the silly register usage restraints }
  832. internalerror(200109231);
  833. End;
  834. OP_MUL,OP_IMUL:
  835. begin
  836. if not(cs_check_overflow in aktlocalswitches) and
  837. ispowerof2(a,power) then
  838. begin
  839. list.concat(taicpu.op_const_ref(A_SHL,TCgSize2OpSize[size],
  840. power,ref));
  841. exit;
  842. end;
  843. { can't multiply a memory location directly with a constant }
  844. if op = OP_IMUL then
  845. inherited a_op_const_ref(list,op,size,a,ref)
  846. else
  847. { OP_MUL should be handled specifically in the code }
  848. { generator because of the silly register usage restraints }
  849. internalerror(200109232);
  850. end;
  851. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  852. if not(cs_check_overflow in aktlocalswitches) and
  853. (a = 1) and
  854. (op in [OP_ADD,OP_SUB]) then
  855. if op = OP_ADD then
  856. list.concat(taicpu.op_ref(A_INC,TCgSize2OpSize[size],ref))
  857. else
  858. list.concat(taicpu.op_ref(A_DEC,TCgSize2OpSize[size],ref))
  859. else if (a = 0) then
  860. if (op <> OP_AND) then
  861. exit
  862. else
  863. a_load_const_ref(list,size,0,ref)
  864. else if (a = high(aword)) and
  865. (op in [OP_AND,OP_OR,OP_XOR]) then
  866. begin
  867. case op of
  868. OP_AND:
  869. exit;
  870. OP_OR:
  871. list.concat(taicpu.op_const_ref(A_MOV,TCgSize2OpSize[size],high(aword),ref));
  872. OP_XOR:
  873. list.concat(taicpu.op_ref(A_NOT,TCgSize2OpSize[size],ref));
  874. end
  875. end
  876. else
  877. list.concat(taicpu.op_const_ref(TOpCG2AsmOp[op],
  878. TCgSize2OpSize[size],a,ref));
  879. OP_SHL,OP_SHR,OP_SAR:
  880. begin
  881. if (a and 31) <> 0 then
  882. list.concat(taicpu.op_const_ref(
  883. TOpCG2AsmOp[op],TCgSize2OpSize[size],a and 31,ref));
  884. if (a shr 5) <> 0 Then
  885. internalerror(68991);
  886. end
  887. else internalerror(68992);
  888. end;
  889. end;
  890. procedure tcgx86.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  891. var
  892. dstsize: topsize;
  893. instr:Taicpu;
  894. begin
  895. check_register_size(size,src);
  896. check_register_size(size,dst);
  897. dstsize := tcgsize2opsize[size];
  898. case op of
  899. OP_NEG,OP_NOT:
  900. begin
  901. if src<>dst then
  902. a_load_reg_reg(list,size,size,src,dst);
  903. list.concat(taicpu.op_reg(TOpCG2AsmOp[op],dstsize,dst));
  904. end;
  905. OP_MUL,OP_DIV,OP_IDIV:
  906. { special stuff, needs separate handling inside code }
  907. { generator }
  908. internalerror(200109233);
  909. OP_SHR,OP_SHL,OP_SAR:
  910. begin
  911. getexplicitregister(list,NR_CL);
  912. a_load_reg_reg(list,OS_8,OS_8,makeregsize(src,OS_8),NR_CL);
  913. list.concat(taicpu.op_reg_reg(Topcg2asmop[op],tcgsize2opsize[size],NR_CL,src));
  914. ungetregister(list,NR_CL);
  915. end;
  916. else
  917. begin
  918. if reg2opsize(src) <> dstsize then
  919. internalerror(200109226);
  920. instr:=taicpu.op_reg_reg(TOpCG2AsmOp[op],dstsize,src,dst);
  921. list.concat(instr);
  922. end;
  923. end;
  924. end;
  925. procedure tcgx86.a_op_ref_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister);
  926. begin
  927. check_register_size(size,reg);
  928. case op of
  929. OP_NEG,OP_NOT,OP_IMUL:
  930. begin
  931. inherited a_op_ref_reg(list,op,size,ref,reg);
  932. end;
  933. OP_MUL,OP_DIV,OP_IDIV:
  934. { special stuff, needs separate handling inside code }
  935. { generator }
  936. internalerror(200109239);
  937. else
  938. begin
  939. reg := makeregsize(reg,size);
  940. list.concat(taicpu.op_ref_reg(TOpCG2AsmOp[op],tcgsize2opsize[size],ref,reg));
  941. end;
  942. end;
  943. end;
  944. procedure tcgx86.a_op_reg_ref(list : taasmoutput; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference);
  945. begin
  946. check_register_size(size,reg);
  947. case op of
  948. OP_NEG,OP_NOT:
  949. begin
  950. if reg<>NR_NO then
  951. internalerror(200109237);
  952. list.concat(taicpu.op_ref(TOpCG2AsmOp[op],tcgsize2opsize[size],ref));
  953. end;
  954. OP_IMUL:
  955. begin
  956. { this one needs a load/imul/store, which is the default }
  957. inherited a_op_ref_reg(list,op,size,ref,reg);
  958. end;
  959. OP_MUL,OP_DIV,OP_IDIV:
  960. { special stuff, needs separate handling inside code }
  961. { generator }
  962. internalerror(200109238);
  963. else
  964. begin
  965. list.concat(taicpu.op_reg_ref(TOpCG2AsmOp[op],tcgsize2opsize[size],reg,ref));
  966. end;
  967. end;
  968. end;
  969. procedure tcgx86.a_op_const_reg_reg(list: taasmoutput; op: TOpCg; size: tcgsize; a: aword; src, dst: tregister);
  970. var
  971. tmpref: treference;
  972. power: longint;
  973. begin
  974. check_register_size(size,src);
  975. check_register_size(size,dst);
  976. if tcgsize2size[size]<>tcgsize2size[OS_INT] then
  977. begin
  978. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  979. exit;
  980. end;
  981. { if we get here, we have to do a 32 bit calculation, guaranteed }
  982. case op of
  983. OP_DIV, OP_IDIV, OP_MUL, OP_AND, OP_OR, OP_XOR, OP_SHL, OP_SHR,
  984. OP_SAR:
  985. { can't do anything special for these }
  986. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  987. OP_IMUL:
  988. begin
  989. if not(cs_check_overflow in aktlocalswitches) and
  990. ispowerof2(a,power) then
  991. { can be done with a shift }
  992. begin
  993. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  994. exit;
  995. end;
  996. list.concat(taicpu.op_const_reg_reg(A_IMUL,tcgsize2opsize[size],a,src,dst));
  997. end;
  998. OP_ADD, OP_SUB:
  999. if (a = 0) then
  1000. a_load_reg_reg(list,size,size,src,dst)
  1001. else
  1002. begin
  1003. reference_reset(tmpref);
  1004. tmpref.base := src;
  1005. tmpref.offset := longint(a);
  1006. if op = OP_SUB then
  1007. tmpref.offset := -tmpref.offset;
  1008. list.concat(taicpu.op_ref_reg(A_LEA,tcgsize2opsize[size],tmpref,dst));
  1009. end
  1010. else internalerror(200112302);
  1011. end;
  1012. end;
  1013. procedure tcgx86.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;size: tcgsize; src1, src2, dst: tregister);
  1014. var
  1015. tmpref: treference;
  1016. begin
  1017. check_register_size(size,src1);
  1018. check_register_size(size,src2);
  1019. check_register_size(size,dst);
  1020. if tcgsize2size[size]<>tcgsize2size[OS_INT] then
  1021. begin
  1022. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  1023. exit;
  1024. end;
  1025. { if we get here, we have to do a 32 bit calculation, guaranteed }
  1026. Case Op of
  1027. OP_DIV, OP_IDIV, OP_MUL, OP_AND, OP_OR, OP_XOR, OP_SHL, OP_SHR,
  1028. OP_SAR,OP_SUB,OP_NOT,OP_NEG:
  1029. { can't do anything special for these }
  1030. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  1031. OP_IMUL:
  1032. list.concat(taicpu.op_reg_reg_reg(A_IMUL,tcgsize2opsize[size],src1,src2,dst));
  1033. OP_ADD:
  1034. begin
  1035. reference_reset(tmpref);
  1036. tmpref.base := src1;
  1037. tmpref.index := src2;
  1038. tmpref.scalefactor := 1;
  1039. list.concat(taicpu.op_ref_reg(A_LEA,tcgsize2opsize[size],tmpref,dst));
  1040. end
  1041. else internalerror(200112303);
  1042. end;
  1043. end;
  1044. {*************** compare instructructions ****************}
  1045. procedure tcgx86.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  1046. l : tasmlabel);
  1047. begin
  1048. if (a = 0) then
  1049. list.concat(taicpu.op_reg_reg(A_TEST,tcgsize2opsize[size],reg,reg))
  1050. else
  1051. list.concat(taicpu.op_const_reg(A_CMP,tcgsize2opsize[size],a,reg));
  1052. a_jmp_cond(list,cmp_op,l);
  1053. end;
  1054. procedure tcgx86.a_cmp_const_ref_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;const ref : treference;
  1055. l : tasmlabel);
  1056. begin
  1057. list.concat(taicpu.op_const_ref(A_CMP,TCgSize2OpSize[size],a,ref));
  1058. a_jmp_cond(list,cmp_op,l);
  1059. end;
  1060. procedure tcgx86.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;
  1061. reg1,reg2 : tregister;l : tasmlabel);
  1062. begin
  1063. check_register_size(size,reg1);
  1064. check_register_size(size,reg2);
  1065. list.concat(taicpu.op_reg_reg(A_CMP,TCgSize2OpSize[size],reg1,reg2));
  1066. a_jmp_cond(list,cmp_op,l);
  1067. end;
  1068. procedure tcgx86.a_cmp_ref_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;const ref: treference; reg : tregister;l : tasmlabel);
  1069. begin
  1070. check_register_size(size,reg);
  1071. list.concat(taicpu.op_ref_reg(A_CMP,TCgSize2OpSize[size],ref,reg));
  1072. a_jmp_cond(list,cmp_op,l);
  1073. end;
  1074. procedure tcgx86.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  1075. var
  1076. ai : taicpu;
  1077. begin
  1078. if cond=OC_None then
  1079. ai := Taicpu.Op_sym(A_JMP,S_NO,l)
  1080. else
  1081. begin
  1082. ai:=Taicpu.Op_sym(A_Jcc,S_NO,l);
  1083. ai.SetCondition(TOpCmp2AsmCond[cond]);
  1084. end;
  1085. ai.is_jmp:=true;
  1086. list.concat(ai);
  1087. end;
  1088. procedure tcgx86.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  1089. var
  1090. ai : taicpu;
  1091. begin
  1092. ai := Taicpu.op_sym(A_Jcc,S_NO,l);
  1093. ai.SetCondition(flags_to_cond(f));
  1094. ai.is_jmp := true;
  1095. list.concat(ai);
  1096. end;
  1097. procedure tcgx86.g_flags2reg(list: taasmoutput; size: TCgSize; const f: tresflags; reg: TRegister);
  1098. var
  1099. ai : taicpu;
  1100. hreg : tregister;
  1101. begin
  1102. hreg:=makeregsize(reg,OS_8);
  1103. ai:=Taicpu.op_reg(A_SETcc,S_B,hreg);
  1104. ai.setcondition(flags_to_cond(f));
  1105. list.concat(ai);
  1106. if (reg<>hreg) then
  1107. a_load_reg_reg(list,OS_8,size,hreg,reg);
  1108. end;
  1109. procedure tcgx86.g_flags2ref(list: taasmoutput; size: TCgSize; const f: tresflags; const ref: TReference);
  1110. var
  1111. ai : taicpu;
  1112. begin
  1113. if not(size in [OS_8,OS_S8]) then
  1114. a_load_const_ref(list,size,0,ref);
  1115. ai:=Taicpu.op_ref(A_SETcc,S_B,ref);
  1116. ai.setcondition(flags_to_cond(f));
  1117. list.concat(ai);
  1118. end;
  1119. { ************* concatcopy ************ }
  1120. procedure Tcgx86.g_concatcopy(list:Taasmoutput;const source,dest:Treference;
  1121. len:aword;delsource,loadref:boolean);
  1122. const
  1123. {$ifdef cpu64bit}
  1124. REGCX=NR_RCX;
  1125. REGSI=NR_RSI;
  1126. REGDI=NR_RDI;
  1127. {$else cpu64bit}
  1128. REGCX=NR_ECX;
  1129. REGSI=NR_ESI;
  1130. REGDI=NR_EDI;
  1131. {$endif cpu64bit}
  1132. type copymode=(copy_move,copy_mmx,copy_string);
  1133. var srcref,dstref:Treference;
  1134. r,r0,r1,r2,r3:Tregister;
  1135. helpsize:aword;
  1136. copysize:byte;
  1137. cgsize:Tcgsize;
  1138. cm:copymode;
  1139. begin
  1140. cm:=copy_move;
  1141. helpsize:=12;
  1142. if cs_littlesize in aktglobalswitches then
  1143. helpsize:=8;
  1144. if (cs_mmx in aktlocalswitches) and
  1145. not(pi_uses_fpu in current_procinfo.flags) and
  1146. ((len=8) or (len=16) or (len=24) or (len=32)) then
  1147. cm:=copy_mmx;
  1148. if (len>helpsize) then
  1149. cm:=copy_string;
  1150. if (cs_littlesize in aktglobalswitches) and
  1151. not((len<=16) and (cm=copy_mmx)) then
  1152. cm:=copy_string;
  1153. if loadref then
  1154. cm:=copy_string;
  1155. case cm of
  1156. copy_move:
  1157. begin
  1158. dstref:=dest;
  1159. srcref:=source;
  1160. copysize:=sizeof(aword);
  1161. cgsize:=int_cgsize(copysize);
  1162. while len<>0 do
  1163. begin
  1164. if len<2 then
  1165. begin
  1166. copysize:=1;
  1167. cgsize:=OS_8;
  1168. end
  1169. else if len<4 then
  1170. begin
  1171. copysize:=2;
  1172. cgsize:=OS_16;
  1173. end
  1174. else if len<8 then
  1175. begin
  1176. copysize:=4;
  1177. cgsize:=OS_32;
  1178. end;
  1179. dec(len,copysize);
  1180. if (len=0) and delsource then
  1181. reference_release(list,source);
  1182. r:=getintregister(list,cgsize);
  1183. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1184. ungetregister(list,r);
  1185. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1186. inc(srcref.offset,copysize);
  1187. inc(dstref.offset,copysize);
  1188. end;
  1189. end;
  1190. copy_mmx:
  1191. begin
  1192. dstref:=dest;
  1193. srcref:=source;
  1194. r0:=getmmxregister(list);
  1195. a_loadmm_ref_reg(list,OS_M64,OS_M64,srcref,r0,nil);
  1196. if len>=16 then
  1197. begin
  1198. inc(srcref.offset,8);
  1199. r1:=getmmxregister(list);
  1200. a_loadmm_ref_reg(list,OS_M64,OS_M64,srcref,r1,nil);
  1201. end;
  1202. if len>=24 then
  1203. begin
  1204. inc(srcref.offset,8);
  1205. r2:=getmmxregister(list);
  1206. a_loadmm_ref_reg(list,OS_M64,OS_M64,srcref,r2,nil);
  1207. end;
  1208. if len>=32 then
  1209. begin
  1210. inc(srcref.offset,8);
  1211. r3:=getmmxregister(list);
  1212. a_loadmm_ref_reg(list,OS_M64,OS_M64,srcref,r3,nil);
  1213. end;
  1214. a_loadmm_reg_ref(list,OS_M64,OS_M64,r0,dstref,nil);
  1215. ungetregister(list,r0);
  1216. if len>=16 then
  1217. begin
  1218. inc(dstref.offset,8);
  1219. a_loadmm_reg_ref(list,OS_M64,OS_M64,r1,dstref,nil);
  1220. ungetregister(list,r1);
  1221. end;
  1222. if len>=24 then
  1223. begin
  1224. inc(dstref.offset,8);
  1225. a_loadmm_reg_ref(list,OS_M64,OS_M64,r2,dstref,nil);
  1226. ungetregister(list,r2);
  1227. end;
  1228. if len>=32 then
  1229. begin
  1230. inc(dstref.offset,8);
  1231. a_loadmm_reg_ref(list,OS_M64,OS_M64,r3,dstref,nil);
  1232. ungetregister(list,r3);
  1233. end;
  1234. end
  1235. else {copy_string, should be a good fallback in case of unhandled}
  1236. begin
  1237. getexplicitregister(list,REGDI);
  1238. a_loadaddr_ref_reg(list,dest,REGDI);
  1239. getexplicitregister(list,REGSI);
  1240. if loadref then
  1241. a_load_ref_reg(list,OS_ADDR,OS_ADDR,source,REGSI)
  1242. else
  1243. begin
  1244. a_loadaddr_ref_reg(list,source,REGSI);
  1245. if delsource then
  1246. begin
  1247. srcref:=source;
  1248. { Don't release ESI register yet, it's needed
  1249. by the movsl }
  1250. if (srcref.base=REGSI) then
  1251. srcref.base:=NR_NO
  1252. else if (srcref.index=REGSI) then
  1253. srcref.index:=NR_NO;
  1254. reference_release(list,srcref);
  1255. end;
  1256. end;
  1257. getexplicitregister(list,REGCX);
  1258. list.concat(Taicpu.op_none(A_CLD,S_NO));
  1259. if cs_littlesize in aktglobalswitches then
  1260. begin
  1261. a_load_const_reg(list,OS_INT,len,REGCX);
  1262. list.concat(Taicpu.op_none(A_REP,S_NO));
  1263. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  1264. end
  1265. else
  1266. begin
  1267. helpsize:=len div sizeof(aword);
  1268. len:=len mod sizeof(aword);
  1269. if helpsize>1 then
  1270. begin
  1271. a_load_const_reg(list,OS_INT,helpsize,REGCX);
  1272. list.concat(Taicpu.op_none(A_REP,S_NO));
  1273. end;
  1274. if helpsize>0 then
  1275. begin
  1276. {$ifdef cpu64bit}
  1277. if sizeof(aword)=8 then
  1278. list.concat(Taicpu.op_none(A_MOVSQ,S_NO))
  1279. else
  1280. {$endif cpu64bit}
  1281. list.concat(Taicpu.op_none(A_MOVSL,S_NO));
  1282. end;
  1283. if len>2 then
  1284. begin
  1285. dec(len,4);
  1286. list.concat(Taicpu.op_none(A_MOVSL,S_NO));
  1287. end;
  1288. if len>1 then
  1289. begin
  1290. dec(len,2);
  1291. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  1292. end;
  1293. if len=1 then
  1294. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  1295. end;
  1296. ungetregister(list,REGCX);
  1297. ungetregister(list,REGSI);
  1298. ungetregister(list,REGDI);
  1299. end;
  1300. end;
  1301. if delsource then
  1302. tg.ungetiftemp(list,source);
  1303. end;
  1304. procedure tcgx86.g_exception_reason_save(list : taasmoutput; const href : treference);
  1305. begin
  1306. list.concat(Taicpu.op_reg(A_PUSH,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG));
  1307. end;
  1308. procedure tcgx86.g_exception_reason_save_const(list : taasmoutput;const href : treference; a: aword);
  1309. begin
  1310. list.concat(Taicpu.op_const(A_PUSH,tcgsize2opsize[OS_INT],a));
  1311. end;
  1312. procedure tcgx86.g_exception_reason_load(list : taasmoutput; const href : treference);
  1313. begin
  1314. list.concat(Taicpu.op_reg(A_POP,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG));
  1315. end;
  1316. {****************************************************************************
  1317. Entry/Exit Code Helpers
  1318. ****************************************************************************}
  1319. procedure tcgx86.g_releasevaluepara_openarray(list : taasmoutput;const ref:treference);
  1320. begin
  1321. { Nothing to release }
  1322. end;
  1323. procedure tcgx86.g_interrupt_stackframe_entry(list : taasmoutput);
  1324. begin
  1325. {$ifdef i386}
  1326. { .... also the segment registers }
  1327. list.concat(Taicpu.Op_reg(A_PUSH,S_W,NR_GS));
  1328. list.concat(Taicpu.Op_reg(A_PUSH,S_W,NR_FS));
  1329. list.concat(Taicpu.Op_reg(A_PUSH,S_W,NR_ES));
  1330. list.concat(Taicpu.Op_reg(A_PUSH,S_W,NR_DS));
  1331. { save the registers of an interrupt procedure }
  1332. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_EDI));
  1333. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_ESI));
  1334. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_EDX));
  1335. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_ECX));
  1336. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_EBX));
  1337. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_EAX));
  1338. {$endif i386}
  1339. end;
  1340. procedure tcgx86.g_interrupt_stackframe_exit(list : taasmoutput;accused,acchiused:boolean);
  1341. begin
  1342. {$ifdef i386}
  1343. if accused then
  1344. list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,NR_ESP))
  1345. else
  1346. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EAX));
  1347. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EBX));
  1348. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_ECX));
  1349. if acchiused then
  1350. list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,NR_ESP))
  1351. else
  1352. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EDX));
  1353. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_ESI));
  1354. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EDI));
  1355. { .... also the segment registers }
  1356. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DS));
  1357. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_ES));
  1358. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_FS));
  1359. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_GS));
  1360. { this restores the flags }
  1361. list.concat(Taicpu.Op_none(A_IRET,S_NO));
  1362. {$endif i386}
  1363. end;
  1364. procedure tcgx86.g_profilecode(list : taasmoutput);
  1365. var
  1366. pl : tasmlabel;
  1367. mcountprefix : String[4];
  1368. begin
  1369. case target_info.system of
  1370. {$ifndef NOTARGETWIN32}
  1371. system_i386_win32,
  1372. {$endif}
  1373. system_i386_freebsd,
  1374. system_i386_netbsd,
  1375. // system_i386_openbsd,
  1376. system_i386_wdosx,
  1377. system_i386_linux:
  1378. begin
  1379. Case target_info.system Of
  1380. system_i386_freebsd : mcountprefix:='.';
  1381. system_i386_netbsd : mcountprefix:='__';
  1382. // system_i386_openbsd : mcountprefix:='.';
  1383. else
  1384. mcountPrefix:='';
  1385. end;
  1386. objectlibrary.getaddrlabel(pl);
  1387. list.concat(Tai_section.Create(sec_data));
  1388. list.concat(Tai_align.Create(4));
  1389. list.concat(Tai_label.Create(pl));
  1390. list.concat(Tai_const.Create_32bit(0));
  1391. list.concat(Tai_section.Create(sec_code));
  1392. list.concat(Taicpu.Op_sym_ofs_reg(A_MOV,S_L,pl,0,NR_EDX));
  1393. a_call_name(list,target_info.Cprefix+mcountprefix+'mcount');
  1394. include(rg[R_INTREGISTER].used_in_proc,RS_EDX);
  1395. end;
  1396. system_i386_go32v2,system_i386_watcom:
  1397. begin
  1398. a_call_name(list,'MCOUNT');
  1399. end;
  1400. end;
  1401. end;
  1402. procedure tcgx86.g_stackpointer_alloc(list : taasmoutput;localsize : longint);
  1403. {$ifdef i386}
  1404. {$ifndef NOTARGETWIN32}
  1405. var
  1406. href : treference;
  1407. i : integer;
  1408. again : tasmlabel;
  1409. {$endif NOTARGETWIN32}
  1410. {$endif i386}
  1411. begin
  1412. if localsize>0 then
  1413. begin
  1414. {$ifdef i386}
  1415. {$ifndef NOTARGETWIN32}
  1416. { windows guards only a few pages for stack growing, }
  1417. { so we have to access every page first }
  1418. if (target_info.system=system_i386_win32) and
  1419. (localsize>=winstackpagesize) then
  1420. begin
  1421. if localsize div winstackpagesize<=5 then
  1422. begin
  1423. list.concat(Taicpu.Op_const_reg(A_SUB,S_L,localsize-4,NR_ESP));
  1424. for i:=1 to localsize div winstackpagesize do
  1425. begin
  1426. reference_reset_base(href,NR_ESP,localsize-i*winstackpagesize);
  1427. list.concat(Taicpu.op_const_ref(A_MOV,S_L,0,href));
  1428. end;
  1429. list.concat(Taicpu.op_reg(A_PUSH,S_L,NR_EAX));
  1430. end
  1431. else
  1432. begin
  1433. objectlibrary.getlabel(again);
  1434. getexplicitregister(list,NR_EDI);
  1435. list.concat(Taicpu.op_const_reg(A_MOV,S_L,localsize div winstackpagesize,NR_EDI));
  1436. a_label(list,again);
  1437. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,NR_ESP));
  1438. list.concat(Taicpu.op_reg(A_PUSH,S_L,NR_EAX));
  1439. list.concat(Taicpu.op_reg(A_DEC,S_L,NR_EDI));
  1440. a_jmp_cond(list,OC_NE,again);
  1441. ungetregister(list,NR_EDI);
  1442. list.concat(Taicpu.op_const_reg(A_SUB,S_L,localsize mod winstackpagesize,NR_ESP));
  1443. end
  1444. end
  1445. else
  1446. {$endif NOTARGETWIN32}
  1447. {$endif i386}
  1448. list.concat(Taicpu.Op_const_reg(A_SUB,tcgsize2opsize[OS_ADDR],localsize,NR_STACK_POINTER_REG));
  1449. end;
  1450. end;
  1451. procedure tcgx86.g_stackframe_entry(list : taasmoutput;localsize : longint);
  1452. begin
  1453. list.concat(tai_regalloc.alloc(NR_FRAME_POINTER_REG));
  1454. include(rg[R_INTREGISTER].preserved_by_proc,RS_FRAME_POINTER_REG);
  1455. list.concat(Taicpu.op_reg(A_PUSH,tcgsize2opsize[OS_ADDR],NR_FRAME_POINTER_REG));
  1456. list.concat(Taicpu.op_reg_reg(A_MOV,tcgsize2opsize[OS_ADDR],NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG));
  1457. if localsize>0 then
  1458. g_stackpointer_alloc(list,localsize);
  1459. if cs_create_pic in aktmoduleswitches then
  1460. begin
  1461. a_call_name(list,'FPC_GETEIPINEBX');
  1462. list.concat(taicpu.op_sym_ofs_reg(A_ADD,tcgsize2opsize[OS_ADDR],objectlibrary.newasmsymboldata('_GLOBAL_OFFSET_TABLE_'),0,NR_PIC_OFFSET_REG));
  1463. list.concat(tai_regalloc.alloc(NR_PIC_OFFSET_REG));
  1464. end;
  1465. end;
  1466. procedure tcgx86.g_restore_frame_pointer(list : taasmoutput);
  1467. begin
  1468. if cs_create_pic in aktmoduleswitches then
  1469. list.concat(tai_regalloc.dealloc(NR_PIC_OFFSET_REG));
  1470. list.concat(tai_regalloc.dealloc(NR_FRAME_POINTER_REG));
  1471. list.concat(Taicpu.op_none(A_LEAVE,S_NO));
  1472. if assigned(rg[R_MMXREGISTER]) and
  1473. (rg[R_MMXREGISTER].uses_registers) then
  1474. list.concat(Taicpu.op_none(A_EMMS,S_NO));
  1475. end;
  1476. procedure tcgx86.g_return_from_proc(list : taasmoutput;parasize : aword);
  1477. begin
  1478. { Routines with the poclearstack flag set use only a ret }
  1479. { also routines with parasize=0 }
  1480. if current_procinfo.procdef.proccalloption in clearstack_pocalls then
  1481. begin
  1482. { complex return values are removed from stack in C code PM }
  1483. if paramanager.ret_in_param(current_procinfo.procdef.rettype.def,
  1484. current_procinfo.procdef.proccalloption) then
  1485. list.concat(Taicpu.Op_const(A_RET,S_NO,4))
  1486. else
  1487. list.concat(Taicpu.Op_none(A_RET,S_NO));
  1488. end
  1489. else if (parasize=0) then
  1490. list.concat(Taicpu.Op_none(A_RET,S_NO))
  1491. else
  1492. begin
  1493. { parameters are limited to 65535 bytes because }
  1494. { ret allows only imm16 }
  1495. if (parasize>65535) then
  1496. CGMessage(cg_e_parasize_too_big);
  1497. list.concat(Taicpu.Op_const(A_RET,S_NO,parasize));
  1498. end;
  1499. end;
  1500. procedure tcgx86.g_save_standard_registers(list:Taasmoutput);
  1501. var
  1502. href : treference;
  1503. size : longint;
  1504. r : integer;
  1505. begin
  1506. { Get temp }
  1507. size:=0;
  1508. for r:=low(saved_standard_registers) to high(saved_standard_registers) do
  1509. if saved_standard_registers[r] in rg[R_INTREGISTER].used_in_proc then
  1510. inc(size,POINTER_SIZE);
  1511. if size>0 then
  1512. begin
  1513. tg.GetTemp(list,size,tt_noreuse,current_procinfo.save_regs_ref);
  1514. { Copy registers to temp }
  1515. href:=current_procinfo.save_regs_ref;
  1516. for r:=low(saved_standard_registers) to high(saved_standard_registers) do
  1517. begin
  1518. if saved_standard_registers[r] in rg[R_INTREGISTER].used_in_proc then
  1519. begin
  1520. a_load_reg_ref(list,OS_ADDR,OS_ADDR,newreg(R_INTREGISTER,saved_standard_registers[r],R_SUBWHOLE),href);
  1521. inc(href.offset,POINTER_SIZE);
  1522. end;
  1523. include(rg[R_INTREGISTER].preserved_by_proc,saved_standard_registers[r]);
  1524. end;
  1525. end;
  1526. end;
  1527. procedure tcgx86.g_restore_standard_registers(list:Taasmoutput);
  1528. var
  1529. href : treference;
  1530. r : integer;
  1531. begin
  1532. { Copy registers from temp }
  1533. href:=current_procinfo.save_regs_ref;
  1534. for r:=low(saved_standard_registers) to high(saved_standard_registers) do
  1535. if saved_standard_registers[r] in rg[R_INTREGISTER].used_in_proc then
  1536. begin
  1537. a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,newreg(R_INTREGISTER,saved_standard_registers[r],R_SUBWHOLE));
  1538. inc(href.offset,POINTER_SIZE);
  1539. end;
  1540. tg.UnGetTemp(list,current_procinfo.save_regs_ref);
  1541. end;
  1542. { produces if necessary overflowcode }
  1543. procedure tcgx86.g_overflowcheck(list: taasmoutput; const l:tlocation;def:tdef);
  1544. var
  1545. hl : tasmlabel;
  1546. ai : taicpu;
  1547. cond : TAsmCond;
  1548. begin
  1549. if not(cs_check_overflow in aktlocalswitches) then
  1550. exit;
  1551. objectlibrary.getlabel(hl);
  1552. if not ((def.deftype=pointerdef) or
  1553. ((def.deftype=orddef) and
  1554. (torddef(def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,
  1555. bool8bit,bool16bit,bool32bit]))) then
  1556. cond:=C_NO
  1557. else
  1558. cond:=C_NB;
  1559. ai:=Taicpu.Op_Sym(A_Jcc,S_NO,hl);
  1560. ai.SetCondition(cond);
  1561. ai.is_jmp:=true;
  1562. list.concat(ai);
  1563. a_call_name(list,'FPC_OVERFLOW');
  1564. a_label(list,hl);
  1565. end;
  1566. end.
  1567. {
  1568. $Log$
  1569. Revision 1.115 2004-02-27 10:21:06 florian
  1570. * top_symbol killed
  1571. + refaddr to treference added
  1572. + refsymbol to treference added
  1573. * top_local stuff moved to an extra record to save memory
  1574. + aint introduced
  1575. * tppufile.get/putint64/aint implemented
  1576. Revision 1.114 2004/02/22 18:27:21 florian
  1577. * fixed exception reason size for 64 bit systems
  1578. Revision 1.113 2004/02/22 16:48:10 florian
  1579. * x86_64 uses generic concatcopy_valueopenarray for now
  1580. Revision 1.112 2004/02/21 19:46:37 florian
  1581. * OP_SH* code generation fixed
  1582. Revision 1.111 2004/02/20 16:01:49 peter
  1583. * allow mov to smaller sizes
  1584. Revision 1.110 2004/02/09 22:14:17 peter
  1585. * more x86_64 parameter fixes
  1586. * tparalocation.lochigh is now used to indicate if registerhigh
  1587. is used and what the type is
  1588. Revision 1.109 2004/02/07 23:28:34 daniel
  1589. * Take advantage of our new with statement optimization
  1590. Revision 1.108 2004/02/06 14:37:48 florian
  1591. * movz*q fixed
  1592. Revision 1.107 2004/02/05 18:28:37 peter
  1593. * x86_64 fixes for opsize
  1594. Revision 1.106 2004/02/04 22:01:13 peter
  1595. * first try to get cpupara working for x86_64
  1596. Revision 1.105 2004/02/04 19:22:27 peter
  1597. *** empty log message ***
  1598. Revision 1.104 2004/02/03 19:46:48 jonas
  1599. - removed "mov reg,reg" optimization (those instructions are removed by
  1600. the register allocator, and may be necessary to indicate a register
  1601. may not be released before some point)
  1602. Revision 1.103 2004/01/15 23:16:33 daniel
  1603. + Cleanup of stabstring generation code. Cleaner, faster, and compiler
  1604. executable reduced by 50 kb,
  1605. Revision 1.102 2004/01/14 23:39:05 florian
  1606. * another bunch of x86-64 fixes mainly calling convention and
  1607. assembler reader related
  1608. Revision 1.101 2004/01/14 21:43:54 peter
  1609. * add release_openarrayvalue
  1610. Revision 1.100 2003/12/26 14:02:30 peter
  1611. * sparc updates
  1612. * use registertype in spill_register
  1613. Revision 1.99 2003/12/26 13:19:16 florian
  1614. * rtl and compiler compile with -Cfsse2
  1615. Revision 1.98 2003/12/26 00:32:22 florian
  1616. + fpu<->mm register conversion
  1617. Revision 1.97 2003/12/25 12:01:35 florian
  1618. + possible sse2 unit usage for double calculations
  1619. * some sse2 assembler issues fixed
  1620. Revision 1.96 2003/12/25 01:07:09 florian
  1621. + $fputype directive support
  1622. + single data type operations with sse unit
  1623. * fixed more x86-64 stuff
  1624. Revision 1.95 2003/12/24 01:47:23 florian
  1625. * first fixes to compile the x86-64 system unit
  1626. Revision 1.94 2003/12/24 00:10:03 florian
  1627. - delete parameter in cg64 methods removed
  1628. Revision 1.93 2003/12/21 19:42:43 florian
  1629. * fixed ppc inlining stuff
  1630. * fixed wrong unit writing
  1631. + added some sse stuff
  1632. Revision 1.92 2003/12/19 22:08:44 daniel
  1633. * Some work to restore the MMX capabilities
  1634. Revision 1.91 2003/12/15 21:25:49 peter
  1635. * reg allocations for imaginary register are now inserted just
  1636. before reg allocation
  1637. * tregister changed to enum to allow compile time check
  1638. * fixed several tregister-tsuperregister errors
  1639. Revision 1.90 2003/12/12 17:16:18 peter
  1640. * rg[tregistertype] added in tcg
  1641. Revision 1.89 2003/12/06 01:15:23 florian
  1642. * reverted Peter's alloctemp patch; hopefully properly
  1643. Revision 1.88 2003/12/03 23:13:20 peter
  1644. * delayed paraloc allocation, a_param_*() gets extra parameter
  1645. if it needs to allocate temp or real paralocation
  1646. * optimized/simplified int-real loading
  1647. Revision 1.87 2003/11/05 23:06:03 florian
  1648. * elesize of g_copyvaluepara_openarray changed
  1649. Revision 1.86 2003/10/30 18:53:53 marco
  1650. * profiling fix
  1651. Revision 1.85 2003/10/30 16:22:40 peter
  1652. * call firstpass before allocation and codegeneration is started
  1653. * move leftover code from pass_2.generatecode() to psub
  1654. Revision 1.84 2003/10/29 21:24:14 jonas
  1655. + support for fpu temp parameters
  1656. + saving/restoring of fpu register before/after a procedure call
  1657. Revision 1.83 2003/10/20 19:30:08 peter
  1658. * remove memdebug code for rg
  1659. Revision 1.82 2003/10/18 15:41:26 peter
  1660. * made worklists dynamic in size
  1661. Revision 1.81 2003/10/17 15:25:18 florian
  1662. * fixed more ppc stuff
  1663. Revision 1.80 2003/10/17 14:38:32 peter
  1664. * 64k registers supported
  1665. * fixed some memory leaks
  1666. Revision 1.79 2003/10/14 00:30:48 florian
  1667. + some code for PIC support added
  1668. Revision 1.78 2003/10/13 01:23:13 florian
  1669. * some ideas for mm support implemented
  1670. Revision 1.77 2003/10/11 16:06:42 florian
  1671. * fixed some MMX<->SSE
  1672. * started to fix ppc, needs an overhaul
  1673. + stabs info improve for spilling, not sure if it works correctly/completly
  1674. - MMX_SUPPORT removed from Makefile.fpc
  1675. Revision 1.76 2003/10/10 17:48:14 peter
  1676. * old trgobj moved to x86/rgcpu and renamed to trgx86fpu
  1677. * tregisteralloctor renamed to trgobj
  1678. * removed rgobj from a lot of units
  1679. * moved location_* and reference_* to cgobj
  1680. * first things for mmx register allocation
  1681. Revision 1.75 2003/10/09 21:31:37 daniel
  1682. * Register allocator splitted, ans abstract now
  1683. Revision 1.74 2003/10/07 16:09:03 florian
  1684. * x86 supports only mem/reg to reg for movsx and movzx
  1685. Revision 1.73 2003/10/07 15:17:07 peter
  1686. * inline supported again, LOC_REFERENCEs are used to pass the
  1687. parameters
  1688. * inlineparasymtable,inlinelocalsymtable removed
  1689. * exitlabel inserting fixed
  1690. Revision 1.72 2003/10/03 22:00:33 peter
  1691. * parameter alignment fixes
  1692. Revision 1.71 2003/10/03 14:45:37 peter
  1693. * save ESP after pusha and restore before popa for save all registers
  1694. Revision 1.70 2003/10/01 20:34:51 peter
  1695. * procinfo unit contains tprocinfo
  1696. * cginfo renamed to cgbase
  1697. * moved cgmessage to verbose
  1698. * fixed ppc and sparc compiles
  1699. Revision 1.69 2003/09/30 19:53:47 peter
  1700. * fix pushw reg
  1701. Revision 1.68 2003/09/29 20:58:56 peter
  1702. * optimized releasing of registers
  1703. Revision 1.67 2003/09/28 13:37:19 peter
  1704. * a_call_ref removed
  1705. Revision 1.66 2003/09/25 21:29:16 peter
  1706. * change push/pop in getreg/ungetreg
  1707. Revision 1.65 2003/09/25 13:13:32 florian
  1708. * more x86-64 fixes
  1709. Revision 1.64 2003/09/11 11:55:00 florian
  1710. * improved arm code generation
  1711. * move some protected and private field around
  1712. * the temp. register for register parameters/arguments are now released
  1713. before the move to the parameter register is done. This improves
  1714. the code in a lot of cases.
  1715. Revision 1.63 2003/09/09 21:03:17 peter
  1716. * basics for x86 register calling
  1717. Revision 1.62 2003/09/09 20:59:27 daniel
  1718. * Adding register allocation order
  1719. Revision 1.61 2003/09/07 22:09:35 peter
  1720. * preparations for different default calling conventions
  1721. * various RA fixes
  1722. Revision 1.60 2003/09/05 17:41:13 florian
  1723. * merged Wiktor's Watcom patches in 1.1
  1724. Revision 1.59 2003/09/03 15:55:02 peter
  1725. * NEWRA branch merged
  1726. Revision 1.58.2.5 2003/08/31 20:40:50 daniel
  1727. * Fixed add_edges_used
  1728. Revision 1.58.2.4 2003/08/31 15:46:26 peter
  1729. * more updates for tregister
  1730. Revision 1.58.2.3 2003/08/29 17:29:00 peter
  1731. * next batch of updates
  1732. Revision 1.58.2.2 2003/08/28 18:35:08 peter
  1733. * tregister changed to cardinal
  1734. Revision 1.58.2.1 2003/08/27 21:06:34 peter
  1735. * more updates
  1736. Revision 1.58 2003/08/20 19:28:21 daniel
  1737. * Small NOTARGETWIN32 conditional tweak
  1738. Revision 1.57 2003/07/03 18:59:25 peter
  1739. * loadfpu_reg_reg size specifier
  1740. Revision 1.56 2003/06/14 14:53:50 jonas
  1741. * fixed newra cycle for x86
  1742. * added constants for indicating source and destination operands of the
  1743. "move reg,reg" instruction to aasmcpu (and use those in rgobj)
  1744. Revision 1.55 2003/06/13 21:19:32 peter
  1745. * current_procdef removed, use current_procinfo.procdef instead
  1746. Revision 1.54 2003/06/12 18:31:18 peter
  1747. * fix newra cycle for i386
  1748. Revision 1.53 2003/06/07 10:24:10 peter
  1749. * fixed copyvaluepara for left-to-right pushing
  1750. Revision 1.52 2003/06/07 10:06:55 jonas
  1751. * fixed cycling problem
  1752. Revision 1.51 2003/06/03 21:11:09 peter
  1753. * cg.a_load_* get a from and to size specifier
  1754. * makeregsize only accepts newregister
  1755. * i386 uses generic tcgnotnode,tcgunaryminus
  1756. Revision 1.50 2003/06/03 13:01:59 daniel
  1757. * Register allocator finished
  1758. Revision 1.49 2003/06/01 21:38:07 peter
  1759. * getregisterfpu size parameter added
  1760. * op_const_reg size parameter added
  1761. * sparc updates
  1762. Revision 1.48 2003/05/30 23:57:08 peter
  1763. * more sparc cleanup
  1764. * accumulator removed, splitted in function_return_reg (called) and
  1765. function_result_reg (caller)
  1766. Revision 1.47 2003/05/22 21:33:31 peter
  1767. * removed some unit dependencies
  1768. Revision 1.46 2003/05/16 14:33:31 peter
  1769. * regvar fixes
  1770. Revision 1.45 2003/05/15 18:58:54 peter
  1771. * removed selfpointer_offset, vmtpointer_offset
  1772. * tvarsym.adjusted_address
  1773. * address in localsymtable is now in the real direction
  1774. * removed some obsolete globals
  1775. Revision 1.44 2003/04/30 20:53:32 florian
  1776. * error when address of an abstract method is taken
  1777. * fixed some x86-64 problems
  1778. * merged some more x86-64 and i386 code
  1779. Revision 1.43 2003/04/27 11:21:36 peter
  1780. * aktprocdef renamed to current_procinfo.procdef
  1781. * procinfo renamed to current_procinfo
  1782. * procinfo will now be stored in current_module so it can be
  1783. cleaned up properly
  1784. * gen_main_procsym changed to create_main_proc and release_main_proc
  1785. to also generate a tprocinfo structure
  1786. * fixed unit implicit initfinal
  1787. Revision 1.42 2003/04/23 14:42:08 daniel
  1788. * Further register allocator work. Compiler now smaller with new
  1789. allocator than without.
  1790. * Somebody forgot to adjust ppu version number
  1791. Revision 1.41 2003/04/23 09:51:16 daniel
  1792. * Removed usage of edi in a lot of places when new register allocator used
  1793. + Added newra versions of g_concatcopy and secondadd_float
  1794. Revision 1.40 2003/04/22 13:47:08 peter
  1795. * fixed C style array of const
  1796. * fixed C array passing
  1797. * fixed left to right with high parameters
  1798. Revision 1.39 2003/04/22 10:09:35 daniel
  1799. + Implemented the actual register allocator
  1800. + Scratch registers unavailable when new register allocator used
  1801. + maybe_save/maybe_restore unavailable when new register allocator used
  1802. Revision 1.38 2003/04/17 16:48:21 daniel
  1803. * Added some code to keep track of move instructions in register
  1804. allocator
  1805. Revision 1.37 2003/03/28 19:16:57 peter
  1806. * generic constructor working for i386
  1807. * remove fixed self register
  1808. * esi added as address register for i386
  1809. Revision 1.36 2003/03/18 18:17:46 peter
  1810. * reg2opsize()
  1811. Revision 1.35 2003/03/13 19:52:23 jonas
  1812. * and more new register allocator fixes (in the i386 code generator this
  1813. time). At least now the ppc cross compiler can compile the linux
  1814. system unit again, but I haven't tested it.
  1815. Revision 1.34 2003/02/27 16:40:32 daniel
  1816. * Fixed ie 200301234 problem on Win32 target
  1817. Revision 1.33 2003/02/26 21:15:43 daniel
  1818. * Fixed the optimizer
  1819. Revision 1.32 2003/02/19 22:00:17 daniel
  1820. * Code generator converted to new register notation
  1821. - Horribily outdated todo.txt removed
  1822. Revision 1.31 2003/01/21 10:41:13 daniel
  1823. * Fixed another 200301081
  1824. Revision 1.30 2003/01/13 23:00:18 daniel
  1825. * Fixed internalerror
  1826. Revision 1.29 2003/01/13 14:54:34 daniel
  1827. * Further work to convert codegenerator register convention;
  1828. internalerror bug fixed.
  1829. Revision 1.28 2003/01/09 20:41:00 daniel
  1830. * Converted some code in cgx86.pas to new register numbering
  1831. Revision 1.27 2003/01/08 18:43:58 daniel
  1832. * Tregister changed into a record
  1833. Revision 1.26 2003/01/05 13:36:53 florian
  1834. * x86-64 compiles
  1835. + very basic support for float128 type (x86-64 only)
  1836. Revision 1.25 2003/01/02 16:17:50 peter
  1837. * align stack on 4 bytes in copyvalueopenarray
  1838. Revision 1.24 2002/12/24 15:56:50 peter
  1839. * stackpointer_alloc added for adjusting ESP. Win32 needs
  1840. this for the pageprotection
  1841. Revision 1.23 2002/11/25 18:43:34 carl
  1842. - removed the invalid if <> checking (Delphi is strange on this)
  1843. + implemented abstract warning on instance creation of class with
  1844. abstract methods.
  1845. * some error message cleanups
  1846. Revision 1.22 2002/11/25 17:43:29 peter
  1847. * splitted defbase in defutil,symutil,defcmp
  1848. * merged isconvertable and is_equal into compare_defs(_ext)
  1849. * made operator search faster by walking the list only once
  1850. Revision 1.21 2002/11/18 17:32:01 peter
  1851. * pass proccalloption to ret_in_xxx and push_xxx functions
  1852. Revision 1.20 2002/11/09 21:18:31 carl
  1853. * flags2reg() was not extending the byte register to the correct result size
  1854. Revision 1.19 2002/10/16 19:01:43 peter
  1855. + $IMPLICITEXCEPTIONS switch to turn on/off generation of the
  1856. implicit exception frames for procedures with initialized variables
  1857. and for constructors. The default is on for compatibility
  1858. Revision 1.18 2002/10/05 12:43:30 carl
  1859. * fixes for Delphi 6 compilation
  1860. (warning : Some features do not work under Delphi)
  1861. Revision 1.17 2002/09/17 18:54:06 jonas
  1862. * a_load_reg_reg() now has two size parameters: source and dest. This
  1863. allows some optimizations on architectures that don't encode the
  1864. register size in the register name.
  1865. Revision 1.16 2002/09/16 19:08:47 peter
  1866. * support references without registers and symbol in paramref_addr. It
  1867. pushes only the offset
  1868. Revision 1.15 2002/09/16 18:06:29 peter
  1869. * move CGSize2Opsize to interface
  1870. Revision 1.14 2002/09/01 14:42:41 peter
  1871. * removevaluepara added to fix the stackpointer so restoring of
  1872. saved registers works
  1873. Revision 1.13 2002/09/01 12:09:27 peter
  1874. + a_call_reg, a_call_loc added
  1875. * removed exprasmlist references
  1876. Revision 1.12 2002/08/17 09:23:50 florian
  1877. * first part of procinfo rewrite
  1878. Revision 1.11 2002/08/16 14:25:00 carl
  1879. * issameref() to test if two references are the same (then emit no opcodes)
  1880. + ret_in_reg to replace ret_in_acc
  1881. (fix some register allocation bugs at the same time)
  1882. + save_std_register now has an extra parameter which is the
  1883. usedinproc registers
  1884. Revision 1.10 2002/08/15 08:13:54 carl
  1885. - a_load_sym_ofs_reg removed
  1886. * loadvmt now calls loadaddr_ref_reg instead
  1887. Revision 1.9 2002/08/11 14:32:33 peter
  1888. * renamed current_library to objectlibrary
  1889. Revision 1.8 2002/08/11 13:24:20 peter
  1890. * saving of asmsymbols in ppu supported
  1891. * asmsymbollist global is removed and moved into a new class
  1892. tasmlibrarydata that will hold the info of a .a file which
  1893. corresponds with a single module. Added librarydata to tmodule
  1894. to keep the library info stored for the module. In the future the
  1895. objectfiles will also be stored to the tasmlibrarydata class
  1896. * all getlabel/newasmsymbol and friends are moved to the new class
  1897. Revision 1.7 2002/08/10 10:06:04 jonas
  1898. * fixed stupid bug of mine in g_flags2reg() when optimizations are on
  1899. Revision 1.6 2002/08/09 19:18:27 carl
  1900. * fix generic exception handling
  1901. Revision 1.5 2002/08/04 19:52:04 carl
  1902. + updated exception routines
  1903. Revision 1.4 2002/07/27 19:53:51 jonas
  1904. + generic implementation of tcg.g_flags2ref()
  1905. * tcg.flags2xxx() now also needs a size parameter
  1906. Revision 1.3 2002/07/26 21:15:46 florian
  1907. * rewrote the system handling
  1908. Revision 1.2 2002/07/21 16:55:34 jonas
  1909. * fixed bug in op_const_reg_reg() for imul
  1910. Revision 1.1 2002/07/20 19:28:47 florian
  1911. * splitting of i386\cgcpu.pas into x86\cgx86.pas and i386\cgcpu.pas
  1912. cgx86.pas will contain the common code for i386 and x86_64
  1913. }