cgx86.pas 78 KB

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