cgx86.pas 84 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302
  1. {
  2. Copyright (c) 1998-2005 by Florian Klaempfl
  3. This unit implements the common parts of the code generator for the i386 and the x86-64.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. { This unit implements the common parts of the code generator for the i386 and the x86-64.
  18. }
  19. unit cgx86;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. globtype,
  24. cgbase,cgutils,cgobj,
  25. aasmbase,aasmtai,aasmdata,aasmcpu,
  26. cpubase,cpuinfo,rgobj,rgx86,rgcpu,
  27. symconst,symtype,symdef;
  28. type
  29. tcgx86 = class(tcg)
  30. rgfpu : Trgx86fpu;
  31. procedure done_register_allocators;override;
  32. function getfpuregister(list:TAsmList;size:Tcgsize):Tregister;override;
  33. function getmmxregister(list:TAsmList):Tregister;
  34. function getmmregister(list:TAsmList;size:Tcgsize):Tregister;override;
  35. procedure getcpuregister(list:TAsmList;r:Tregister);override;
  36. procedure ungetcpuregister(list:TAsmList;r:Tregister);override;
  37. procedure alloccpuregisters(list:TAsmList;rt:Tregistertype;const r:Tcpuregisterset);override;
  38. procedure dealloccpuregisters(list:TAsmList;rt:Tregistertype;const r:Tcpuregisterset);override;
  39. function uses_registers(rt:Tregistertype):boolean;override;
  40. procedure add_reg_instruction(instr:Tai;r:tregister);override;
  41. procedure dec_fpu_stack;
  42. procedure inc_fpu_stack;
  43. procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override;
  44. procedure a_call_reg(list : TAsmList;reg : tregister);override;
  45. procedure a_call_ref(list : TAsmList;ref : treference);override;
  46. procedure a_call_name_static(list : TAsmList;const s : string);override;
  47. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
  48. procedure a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference); override;
  49. procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  50. procedure a_op_ref_reg(list : TAsmList; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister); override;
  51. procedure a_op_reg_ref(list : TAsmList; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference); override;
  52. { move instructions }
  53. procedure a_load_const_reg(list : TAsmList; tosize: tcgsize; a : tcgint;reg : tregister);override;
  54. procedure a_load_const_ref(list : TAsmList; tosize: tcgsize; a : tcgint;const ref : treference);override;
  55. procedure a_load_reg_ref(list : TAsmList;fromsize,tosize: tcgsize; reg : tregister;const ref : treference);override;
  56. procedure a_load_ref_reg(list : TAsmList;fromsize,tosize: tcgsize;const ref : treference;reg : tregister);override;
  57. procedure a_load_reg_reg(list : TAsmList;fromsize,tosize: tcgsize;reg1,reg2 : tregister);override;
  58. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
  59. { bit scan instructions }
  60. procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister); override;
  61. { fpu move instructions }
  62. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  63. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  64. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
  65. { vector register move instructions }
  66. procedure a_loadmm_reg_reg(list: TAsmList; fromsize, tosize : tcgsize;reg1, reg2: tregister;shuffle : pmmshuffle); override;
  67. procedure a_loadmm_ref_reg(list: TAsmList; fromsize, tosize : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle); override;
  68. procedure a_loadmm_reg_ref(list: TAsmList; fromsize, tosize : tcgsize;reg: tregister; const ref: treference;shuffle : pmmshuffle); override;
  69. procedure a_opmm_ref_reg(list: TAsmList; Op: TOpCG; size : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle); override;
  70. procedure a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size : tcgsize;src,dst: tregister;shuffle : pmmshuffle);override;
  71. { comparison operations }
  72. procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister;
  73. l : tasmlabel);override;
  74. procedure a_cmp_const_ref_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;const ref : treference;
  75. l : tasmlabel);override;
  76. procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  77. procedure a_cmp_ref_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;const ref: treference; reg : tregister; l : tasmlabel); override;
  78. procedure a_cmp_reg_ref_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg : tregister; const ref: treference; l : tasmlabel); override;
  79. procedure a_jmp_name(list : TAsmList;const s : string);override;
  80. procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
  81. procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
  82. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister); override;
  83. procedure g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref: TReference); override;
  84. procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);override;
  85. { entry/exit code helpers }
  86. procedure g_profilecode(list : TAsmList);override;
  87. procedure g_stackpointer_alloc(list : TAsmList;localsize : longint);override;
  88. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  89. procedure g_overflowcheck(list: TAsmList; const l:tlocation;def:tdef);override;
  90. procedure g_external_wrapper(list: TAsmList; procdef: tprocdef; const externalname: string); override;
  91. procedure make_simple_ref(list:TAsmList;var ref: treference);
  92. protected
  93. procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  94. procedure check_register_size(size:tcgsize;reg:tregister);
  95. procedure opmm_loc_reg(list: TAsmList; Op: TOpCG; size : tcgsize;loc : tlocation;dst: tregister; shuffle : pmmshuffle);
  96. function get_darwin_call_stub(const s: string; weak: boolean): tasmsymbol;
  97. private
  98. procedure sizes2load(s1,s2 : tcgsize;var op: tasmop; var s3: topsize);
  99. procedure floatload(list: TAsmList; t : tcgsize;const ref : treference);
  100. procedure floatstore(list: TAsmList; t : tcgsize;const ref : treference);
  101. procedure floatloadops(t : tcgsize;var op : tasmop;var s : topsize);
  102. procedure floatstoreops(t : tcgsize;var op : tasmop;var s : topsize);
  103. end;
  104. const
  105. {$ifdef x86_64}
  106. TCGSize2OpSize: Array[tcgsize] of topsize =
  107. (S_NO,S_B,S_W,S_L,S_Q,S_XMM,S_B,S_W,S_L,S_Q,S_XMM,
  108. S_FS,S_FL,S_FX,S_IQ,S_FXX,
  109. S_NO,S_NO,S_NO,S_MD,S_XMM,S_YMM,
  110. S_NO,S_NO,S_NO,S_NO,S_XMM,S_YMM);
  111. {$else x86_64}
  112. TCGSize2OpSize: Array[tcgsize] of topsize =
  113. (S_NO,S_B,S_W,S_L,S_L,S_T,S_B,S_W,S_L,S_L,S_L,
  114. S_FS,S_FL,S_FX,S_IQ,S_FXX,
  115. S_NO,S_NO,S_NO,S_MD,S_XMM,S_YMM,
  116. S_NO,S_NO,S_NO,S_NO,S_XMM,S_YMM);
  117. {$endif x86_64}
  118. {$ifndef NOTARGETWIN}
  119. winstackpagesize = 4096;
  120. {$endif NOTARGETWIN}
  121. function UseAVX: boolean;
  122. implementation
  123. uses
  124. globals,verbose,systems,cutils,
  125. defutil,paramgr,procinfo,
  126. tgobj,ncgutil,
  127. fmodule,symsym;
  128. function UseAVX: boolean;
  129. begin
  130. Result:=current_settings.fputype in [fpu_avx];
  131. end;
  132. const
  133. TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,A_MOV,A_ADD,A_AND,A_DIV,
  134. A_IDIV,A_IMUL,A_MUL,A_NEG,A_NOT,A_OR,
  135. A_SAR,A_SHL,A_SHR,A_SUB,A_XOR,A_ROL,A_ROR);
  136. TOpCmp2AsmCond: Array[topcmp] of TAsmCond = (C_NONE,
  137. C_E,C_G,C_L,C_GE,C_LE,C_NE,C_BE,C_B,C_AE,C_A);
  138. procedure Tcgx86.done_register_allocators;
  139. begin
  140. rg[R_INTREGISTER].free;
  141. rg[R_MMREGISTER].free;
  142. rg[R_MMXREGISTER].free;
  143. rgfpu.free;
  144. inherited done_register_allocators;
  145. end;
  146. function Tcgx86.getfpuregister(list:TAsmList;size:Tcgsize):Tregister;
  147. begin
  148. result:=rgfpu.getregisterfpu(list);
  149. end;
  150. function Tcgx86.getmmxregister(list:TAsmList):Tregister;
  151. begin
  152. if not assigned(rg[R_MMXREGISTER]) then
  153. internalerror(2003121214);
  154. result:=rg[R_MMXREGISTER].getregister(list,R_SUBNONE);
  155. end;
  156. function Tcgx86.getmmregister(list:TAsmList;size:Tcgsize):Tregister;
  157. begin
  158. if not assigned(rg[R_MMREGISTER]) then
  159. internalerror(2003121234);
  160. case size of
  161. OS_F64:
  162. result:=rg[R_MMREGISTER].getregister(list,R_SUBMMD);
  163. OS_F32:
  164. result:=rg[R_MMREGISTER].getregister(list,R_SUBMMS);
  165. OS_M64:
  166. result:=rg[R_MMREGISTER].getregister(list,R_SUBQ);
  167. OS_M128:
  168. result:=rg[R_MMREGISTER].getregister(list,R_SUBMMWHOLE);
  169. else
  170. internalerror(200506041);
  171. end;
  172. end;
  173. procedure Tcgx86.getcpuregister(list:TAsmList;r:Tregister);
  174. begin
  175. if getregtype(r)=R_FPUREGISTER then
  176. internalerror(2003121210)
  177. else
  178. inherited getcpuregister(list,r);
  179. end;
  180. procedure tcgx86.ungetcpuregister(list:TAsmList;r:Tregister);
  181. begin
  182. if getregtype(r)=R_FPUREGISTER then
  183. rgfpu.ungetregisterfpu(list,r)
  184. else
  185. inherited ungetcpuregister(list,r);
  186. end;
  187. procedure Tcgx86.alloccpuregisters(list:TAsmList;rt:Tregistertype;const r:Tcpuregisterset);
  188. begin
  189. if rt<>R_FPUREGISTER then
  190. inherited alloccpuregisters(list,rt,r);
  191. end;
  192. procedure Tcgx86.dealloccpuregisters(list:TAsmList;rt:Tregistertype;const r:Tcpuregisterset);
  193. begin
  194. if rt<>R_FPUREGISTER then
  195. inherited dealloccpuregisters(list,rt,r);
  196. end;
  197. function Tcgx86.uses_registers(rt:Tregistertype):boolean;
  198. begin
  199. if rt=R_FPUREGISTER then
  200. result:=false
  201. else
  202. result:=inherited uses_registers(rt);
  203. end;
  204. procedure tcgx86.add_reg_instruction(instr:Tai;r:tregister);
  205. begin
  206. if getregtype(r)<>R_FPUREGISTER then
  207. inherited add_reg_instruction(instr,r);
  208. end;
  209. procedure tcgx86.dec_fpu_stack;
  210. begin
  211. if rgfpu.fpuvaroffset<=0 then
  212. internalerror(200604201);
  213. dec(rgfpu.fpuvaroffset);
  214. end;
  215. procedure tcgx86.inc_fpu_stack;
  216. begin
  217. if rgfpu.fpuvaroffset>=7 then
  218. internalerror(2012062901);
  219. inc(rgfpu.fpuvaroffset);
  220. end;
  221. {****************************************************************************
  222. This is private property, keep out! :)
  223. ****************************************************************************}
  224. procedure tcgx86.sizes2load(s1,s2 : tcgsize; var op: tasmop; var s3: topsize);
  225. begin
  226. { ensure to have always valid sizes }
  227. if s1=OS_NO then
  228. s1:=s2;
  229. if s2=OS_NO then
  230. s2:=s1;
  231. case s2 of
  232. OS_8,OS_S8 :
  233. if S1 in [OS_8,OS_S8] then
  234. s3 := S_B
  235. else
  236. internalerror(200109221);
  237. OS_16,OS_S16:
  238. case s1 of
  239. OS_8,OS_S8:
  240. s3 := S_BW;
  241. OS_16,OS_S16:
  242. s3 := S_W;
  243. else
  244. internalerror(200109222);
  245. end;
  246. OS_32,OS_S32:
  247. case s1 of
  248. OS_8,OS_S8:
  249. s3 := S_BL;
  250. OS_16,OS_S16:
  251. s3 := S_WL;
  252. OS_32,OS_S32:
  253. s3 := S_L;
  254. else
  255. internalerror(200109223);
  256. end;
  257. {$ifdef x86_64}
  258. OS_64,OS_S64:
  259. case s1 of
  260. OS_8:
  261. s3 := S_BL;
  262. OS_S8:
  263. s3 := S_BQ;
  264. OS_16:
  265. s3 := S_WL;
  266. OS_S16:
  267. s3 := S_WQ;
  268. OS_32:
  269. s3 := S_L;
  270. OS_S32:
  271. s3 := S_LQ;
  272. OS_64,OS_S64:
  273. s3 := S_Q;
  274. else
  275. internalerror(200304302);
  276. end;
  277. {$endif x86_64}
  278. else
  279. internalerror(200109227);
  280. end;
  281. if s3 in [S_B,S_W,S_L,S_Q] then
  282. op := A_MOV
  283. else if s1 in [OS_8,OS_16,OS_32,OS_64] then
  284. op := A_MOVZX
  285. else
  286. {$ifdef x86_64}
  287. if s3 in [S_LQ] then
  288. op := A_MOVSXD
  289. else
  290. {$endif x86_64}
  291. op := A_MOVSX;
  292. end;
  293. procedure tcgx86.make_simple_ref(list:TAsmList;var ref: treference);
  294. var
  295. hreg : tregister;
  296. href : treference;
  297. {$ifndef x86_64}
  298. add_hreg: boolean;
  299. {$endif not x86_64}
  300. begin
  301. { make_simple_ref() may have already been called earlier, and in that
  302. case make sure we don't perform the PIC-simplifications twice }
  303. if (ref.refaddr in [addr_pic,addr_pic_no_got]) then
  304. exit;
  305. {$ifdef x86_64}
  306. { Only 32bit is allowed }
  307. { Note that this isn't entirely correct: for RIP-relative targets/memory models,
  308. it is actually (offset+@symbol-RIP) that should fit into 32 bits. Since two last
  309. members aren't known until link time, ABIs place very pessimistic limits
  310. on offset values, e.g. SysV AMD64 allows +/-$1000000 (16 megabytes) }
  311. if ((ref.offset<low(longint)) or (ref.offset>high(longint))) or
  312. { absolute address is not a common thing in x64, but nevertheless a possible one }
  313. ((ref.base=NR_NO) and (ref.index=NR_NO) and (ref.symbol=nil)) then
  314. begin
  315. { Load constant value to register }
  316. hreg:=GetAddressRegister(list);
  317. list.concat(taicpu.op_const_reg(A_MOV,S_Q,ref.offset,hreg));
  318. ref.offset:=0;
  319. {if assigned(ref.symbol) then
  320. begin
  321. list.concat(taicpu.op_sym_ofs_reg(A_ADD,S_Q,ref.symbol,0,hreg));
  322. ref.symbol:=nil;
  323. end;}
  324. { Add register to reference }
  325. if ref.base=NR_NO then
  326. ref.base:=hreg
  327. else if ref.index=NR_NO then
  328. ref.index:=hreg
  329. else
  330. begin
  331. { don't use add, as the flags may contain a value }
  332. reference_reset_base(href,ref.base,0,8);
  333. href.index:=hreg;
  334. if ref.scalefactor<>0 then
  335. begin
  336. reference_reset_base(href,ref.base,0,8);
  337. href.index:=hreg;
  338. list.concat(taicpu.op_ref_reg(A_LEA,S_Q,href,hreg));
  339. ref.base:=hreg;
  340. end
  341. else
  342. begin
  343. reference_reset_base(href,ref.index,0,8);
  344. href.index:=hreg;
  345. list.concat(taicpu.op_reg_reg(A_ADD,S_Q,ref.index,hreg));
  346. ref.index:=hreg;
  347. end;
  348. end;
  349. end;
  350. if assigned(ref.symbol) then
  351. begin
  352. if cs_create_pic in current_settings.moduleswitches then
  353. begin
  354. { Local symbols must not be accessed via the GOT }
  355. if (ref.symbol.bind=AB_LOCAL) then
  356. begin
  357. { unfortunately, RIP-based addresses don't support an index }
  358. if (ref.base<>NR_NO) or
  359. (ref.index<>NR_NO) then
  360. begin
  361. reference_reset_symbol(href,ref.symbol,0,ref.alignment);
  362. hreg:=getaddressregister(list);
  363. href.refaddr:=addr_pic_no_got;
  364. href.base:=NR_RIP;
  365. list.concat(taicpu.op_ref_reg(A_LEA,S_Q,href,hreg));
  366. ref.symbol:=nil;
  367. end
  368. else
  369. begin
  370. ref.refaddr:=addr_pic_no_got;
  371. hreg:=NR_NO;
  372. ref.base:=NR_RIP;
  373. end;
  374. end
  375. else
  376. begin
  377. reference_reset_symbol(href,ref.symbol,0,ref.alignment);
  378. hreg:=getaddressregister(list);
  379. href.refaddr:=addr_pic;
  380. href.base:=NR_RIP;
  381. list.concat(taicpu.op_ref_reg(A_MOV,S_Q,href,hreg));
  382. ref.symbol:=nil;
  383. end;
  384. if ref.base=NR_NO then
  385. ref.base:=hreg
  386. else if ref.index=NR_NO then
  387. begin
  388. ref.index:=hreg;
  389. ref.scalefactor:=1;
  390. end
  391. else
  392. begin
  393. { don't use add, as the flags may contain a value }
  394. reference_reset_base(href,ref.base,0,8);
  395. href.index:=hreg;
  396. list.concat(taicpu.op_ref_reg(A_LEA,S_Q,href,hreg));
  397. ref.base:=hreg;
  398. end;
  399. end
  400. else
  401. { Always use RIP relative symbol addressing for Windows and Darwin targets. }
  402. if (target_info.system in (systems_all_windows+[system_x86_64_darwin])) and (ref.base<>NR_RIP) then
  403. begin
  404. if (ref.refaddr=addr_no) and (ref.base=NR_NO) and (ref.index=NR_NO) then
  405. begin
  406. { Set RIP relative addressing for simple symbol references }
  407. ref.base:=NR_RIP;
  408. ref.refaddr:=addr_pic_no_got
  409. end
  410. else
  411. begin
  412. { Use temp register to load calculated 64-bit symbol address for complex references }
  413. reference_reset_symbol(href,ref.symbol,0,sizeof(pint));
  414. href.base:=NR_RIP;
  415. href.refaddr:=addr_pic_no_got;
  416. hreg:=GetAddressRegister(list);
  417. list.concat(taicpu.op_ref_reg(A_LEA,S_Q,href,hreg));
  418. ref.symbol:=nil;
  419. if ref.base=NR_NO then
  420. ref.base:=hreg
  421. else if ref.index=NR_NO then
  422. begin
  423. ref.index:=hreg;
  424. ref.scalefactor:=0;
  425. end
  426. else
  427. begin
  428. { don't use add, as the flags may contain a value }
  429. reference_reset_base(href,ref.base,0,8);
  430. href.index:=hreg;
  431. list.concat(taicpu.op_ref_reg(A_LEA,S_Q,href,hreg));
  432. ref.base:=hreg;
  433. end;
  434. end;
  435. end;
  436. end;
  437. {$else x86_64}
  438. add_hreg:=false;
  439. if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) then
  440. begin
  441. if assigned(ref.symbol) and
  442. not(assigned(ref.relsymbol)) and
  443. ((ref.symbol.bind in [AB_EXTERNAL,AB_WEAK_EXTERNAL,AB_PRIVATE_EXTERN]) or
  444. (cs_create_pic in current_settings.moduleswitches)) then
  445. begin
  446. if ref.symbol.bind in [AB_EXTERNAL,AB_WEAK_EXTERNAL,AB_PRIVATE_EXTERN] then
  447. begin
  448. hreg:=g_indirect_sym_load(list,ref.symbol.name,asmsym2indsymflags(ref.symbol));
  449. ref.symbol:=nil;
  450. end
  451. else
  452. begin
  453. include(current_procinfo.flags,pi_needs_got);
  454. { make a copy of the got register, hreg can get modified }
  455. hreg:=cg.getaddressregister(list);
  456. a_load_reg_reg(list,OS_ADDR,OS_ADDR,current_procinfo.got,hreg);
  457. ref.relsymbol:=current_procinfo.CurrGOTLabel;
  458. end;
  459. add_hreg:=true
  460. end
  461. end
  462. else if (cs_create_pic in current_settings.moduleswitches) and
  463. assigned(ref.symbol) then
  464. begin
  465. reference_reset_symbol(href,ref.symbol,0,sizeof(pint));
  466. href.base:=current_procinfo.got;
  467. href.refaddr:=addr_pic;
  468. include(current_procinfo.flags,pi_needs_got);
  469. hreg:=cg.getaddressregister(list);
  470. list.concat(taicpu.op_ref_reg(A_MOV,S_L,href,hreg));
  471. ref.symbol:=nil;
  472. add_hreg:=true;
  473. end;
  474. if add_hreg then
  475. begin
  476. if ref.base=NR_NO then
  477. ref.base:=hreg
  478. else if ref.index=NR_NO then
  479. begin
  480. ref.index:=hreg;
  481. ref.scalefactor:=1;
  482. end
  483. else
  484. begin
  485. { don't use add, as the flags may contain a value }
  486. reference_reset_base(href,ref.base,0,8);
  487. href.index:=hreg;
  488. list.concat(taicpu.op_ref_reg(A_LEA,S_L,href,hreg));
  489. ref.base:=hreg;
  490. end;
  491. end;
  492. {$endif x86_64}
  493. end;
  494. procedure tcgx86.floatloadops(t : tcgsize;var op : tasmop;var s : topsize);
  495. begin
  496. case t of
  497. OS_F32 :
  498. begin
  499. op:=A_FLD;
  500. s:=S_FS;
  501. end;
  502. OS_F64 :
  503. begin
  504. op:=A_FLD;
  505. s:=S_FL;
  506. end;
  507. OS_F80 :
  508. begin
  509. op:=A_FLD;
  510. s:=S_FX;
  511. end;
  512. OS_C64 :
  513. begin
  514. op:=A_FILD;
  515. s:=S_IQ;
  516. end;
  517. else
  518. internalerror(200204043);
  519. end;
  520. end;
  521. procedure tcgx86.floatload(list: TAsmList; t : tcgsize;const ref : treference);
  522. var
  523. op : tasmop;
  524. s : topsize;
  525. tmpref : treference;
  526. begin
  527. tmpref:=ref;
  528. make_simple_ref(list,tmpref);
  529. floatloadops(t,op,s);
  530. list.concat(Taicpu.Op_ref(op,s,tmpref));
  531. inc_fpu_stack;
  532. end;
  533. procedure tcgx86.floatstoreops(t : tcgsize;var op : tasmop;var s : topsize);
  534. begin
  535. case t of
  536. OS_F32 :
  537. begin
  538. op:=A_FSTP;
  539. s:=S_FS;
  540. end;
  541. OS_F64 :
  542. begin
  543. op:=A_FSTP;
  544. s:=S_FL;
  545. end;
  546. OS_F80 :
  547. begin
  548. op:=A_FSTP;
  549. s:=S_FX;
  550. end;
  551. OS_C64 :
  552. begin
  553. op:=A_FISTP;
  554. s:=S_IQ;
  555. end;
  556. else
  557. internalerror(200204042);
  558. end;
  559. end;
  560. procedure tcgx86.floatstore(list: TAsmList; t : tcgsize;const ref : treference);
  561. var
  562. op : tasmop;
  563. s : topsize;
  564. tmpref : treference;
  565. begin
  566. tmpref:=ref;
  567. make_simple_ref(list,tmpref);
  568. floatstoreops(t,op,s);
  569. list.concat(Taicpu.Op_ref(op,s,tmpref));
  570. { storing non extended floats can cause a floating point overflow }
  571. if (t<>OS_F80) and
  572. (cs_fpu_fwait in current_settings.localswitches) then
  573. list.concat(Taicpu.Op_none(A_FWAIT,S_NO));
  574. dec_fpu_stack;
  575. end;
  576. procedure tcgx86.check_register_size(size:tcgsize;reg:tregister);
  577. begin
  578. if TCGSize2OpSize[size]<>TCGSize2OpSize[reg_cgsize(reg)] then
  579. internalerror(200306031);
  580. end;
  581. {****************************************************************************
  582. Assembler code
  583. ****************************************************************************}
  584. procedure tcgx86.a_jmp_name(list : TAsmList;const s : string);
  585. var
  586. r: treference;
  587. begin
  588. if (target_info.system <> system_i386_darwin) then
  589. list.concat(taicpu.op_sym(A_JMP,S_NO,current_asmdata.RefAsmSymbol(s)))
  590. else
  591. begin
  592. reference_reset_symbol(r,get_darwin_call_stub(s,false),0,sizeof(pint));
  593. r.refaddr:=addr_full;
  594. list.concat(taicpu.op_ref(A_JMP,S_NO,r));
  595. end;
  596. end;
  597. procedure tcgx86.a_jmp_always(list : TAsmList;l: tasmlabel);
  598. begin
  599. a_jmp_cond(list, OC_NONE, l);
  600. end;
  601. function tcgx86.get_darwin_call_stub(const s: string; weak: boolean): tasmsymbol;
  602. var
  603. stubname: string;
  604. begin
  605. stubname := 'L'+s+'$stub';
  606. result := current_asmdata.getasmsymbol(stubname);
  607. if assigned(result) then
  608. exit;
  609. if current_asmdata.asmlists[al_imports]=nil then
  610. current_asmdata.asmlists[al_imports]:=TAsmList.create;
  611. new_section(current_asmdata.asmlists[al_imports],sec_stub,'',0);
  612. result := current_asmdata.RefAsmSymbol(stubname);
  613. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(result,0));
  614. { register as a weak symbol if necessary }
  615. if weak then
  616. current_asmdata.weakrefasmsymbol(s);
  617. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  618. current_asmdata.asmlists[al_imports].concat(taicpu.op_none(A_HLT));
  619. current_asmdata.asmlists[al_imports].concat(taicpu.op_none(A_HLT));
  620. current_asmdata.asmlists[al_imports].concat(taicpu.op_none(A_HLT));
  621. current_asmdata.asmlists[al_imports].concat(taicpu.op_none(A_HLT));
  622. current_asmdata.asmlists[al_imports].concat(taicpu.op_none(A_HLT));
  623. end;
  624. procedure tcgx86.a_call_name(list : TAsmList;const s : string; weak: boolean);
  625. var
  626. sym : tasmsymbol;
  627. r : treference;
  628. begin
  629. if (target_info.system <> system_i386_darwin) then
  630. begin
  631. if not(weak) then
  632. sym:=current_asmdata.RefAsmSymbol(s)
  633. else
  634. sym:=current_asmdata.WeakRefAsmSymbol(s);
  635. reference_reset_symbol(r,sym,0,sizeof(pint));
  636. if (cs_create_pic in current_settings.moduleswitches) and
  637. { darwin's assembler doesn't want @PLT after call symbols }
  638. not(target_info.system in [system_x86_64_darwin,system_i386_iphonesim]) then
  639. begin
  640. {$ifdef i386}
  641. include(current_procinfo.flags,pi_needs_got);
  642. {$endif i386}
  643. r.refaddr:=addr_pic
  644. end
  645. else
  646. r.refaddr:=addr_full;
  647. end
  648. else
  649. begin
  650. reference_reset_symbol(r,get_darwin_call_stub(s,weak),0,sizeof(pint));
  651. r.refaddr:=addr_full;
  652. end;
  653. list.concat(taicpu.op_ref(A_CALL,S_NO,r));
  654. end;
  655. procedure tcgx86.a_call_name_static(list : TAsmList;const s : string);
  656. var
  657. sym : tasmsymbol;
  658. r : treference;
  659. begin
  660. sym:=current_asmdata.RefAsmSymbol(s);
  661. reference_reset_symbol(r,sym,0,sizeof(pint));
  662. r.refaddr:=addr_full;
  663. list.concat(taicpu.op_ref(A_CALL,S_NO,r));
  664. end;
  665. procedure tcgx86.a_call_reg(list : TAsmList;reg : tregister);
  666. begin
  667. list.concat(taicpu.op_reg(A_CALL,S_NO,reg));
  668. end;
  669. procedure tcgx86.a_call_ref(list : TAsmList;ref : treference);
  670. begin
  671. list.concat(taicpu.op_ref(A_CALL,S_NO,ref));
  672. end;
  673. {********************** load instructions ********************}
  674. procedure tcgx86.a_load_const_reg(list : TAsmList; tosize: TCGSize; a : tcgint; reg : TRegister);
  675. begin
  676. check_register_size(tosize,reg);
  677. { the optimizer will change it to "xor reg,reg" when loading zero, }
  678. { no need to do it here too (JM) }
  679. list.concat(taicpu.op_const_reg(A_MOV,TCGSize2OpSize[tosize],a,reg))
  680. end;
  681. procedure tcgx86.a_load_const_ref(list : TAsmList; tosize: tcgsize; a : tcgint;const ref : treference);
  682. var
  683. tmpref : treference;
  684. begin
  685. tmpref:=ref;
  686. make_simple_ref(list,tmpref);
  687. {$ifdef x86_64}
  688. { x86_64 only supports signed 32 bits constants directly }
  689. if (tosize in [OS_S64,OS_64]) and
  690. ((a<low(longint)) or (a>high(longint))) then
  691. begin
  692. a_load_const_ref(list,OS_32,longint(a and $ffffffff),tmpref);
  693. inc(tmpref.offset,4);
  694. a_load_const_ref(list,OS_32,longint(a shr 32),tmpref);
  695. end
  696. else
  697. {$endif x86_64}
  698. list.concat(taicpu.op_const_ref(A_MOV,TCGSize2OpSize[tosize],a,tmpref));
  699. end;
  700. procedure tcgx86.a_load_reg_ref(list : TAsmList; fromsize,tosize: TCGSize; reg : tregister;const ref : treference);
  701. var
  702. op: tasmop;
  703. s: topsize;
  704. tmpsize : tcgsize;
  705. tmpreg : tregister;
  706. tmpref : treference;
  707. begin
  708. tmpref:=ref;
  709. make_simple_ref(list,tmpref);
  710. check_register_size(fromsize,reg);
  711. sizes2load(fromsize,tosize,op,s);
  712. case s of
  713. {$ifdef x86_64}
  714. S_BQ,S_WQ,S_LQ,
  715. {$endif x86_64}
  716. S_BW,S_BL,S_WL :
  717. begin
  718. tmpreg:=getintregister(list,tosize);
  719. {$ifdef x86_64}
  720. { zero extensions to 64 bit on the x86_64 are simply done by writting to the lower 32 bit
  721. which clears the upper 64 bit too, so it could be that s is S_L while the reg is
  722. 64 bit (FK) }
  723. if s in [S_BL,S_WL,S_L] then
  724. begin
  725. tmpreg:=makeregsize(list,tmpreg,OS_32);
  726. tmpsize:=OS_32;
  727. end
  728. else
  729. {$endif x86_64}
  730. tmpsize:=tosize;
  731. list.concat(taicpu.op_reg_reg(op,s,reg,tmpreg));
  732. a_load_reg_ref(list,tmpsize,tosize,tmpreg,tmpref);
  733. end;
  734. else
  735. list.concat(taicpu.op_reg_ref(op,s,reg,tmpref));
  736. end;
  737. end;
  738. procedure tcgx86.a_load_ref_reg(list : TAsmList;fromsize,tosize : tcgsize;const ref: treference;reg : tregister);
  739. var
  740. op: tasmop;
  741. s: topsize;
  742. tmpref : treference;
  743. begin
  744. tmpref:=ref;
  745. make_simple_ref(list,tmpref);
  746. check_register_size(tosize,reg);
  747. sizes2load(fromsize,tosize,op,s);
  748. {$ifdef x86_64}
  749. { zero extensions to 64 bit on the x86_64 are simply done by writting to the lower 32 bit
  750. which clears the upper 64 bit too, so it could be that s is S_L while the reg is
  751. 64 bit (FK) }
  752. if s in [S_BL,S_WL,S_L] then
  753. reg:=makeregsize(list,reg,OS_32);
  754. {$endif x86_64}
  755. list.concat(taicpu.op_ref_reg(op,s,tmpref,reg));
  756. end;
  757. procedure tcgx86.a_load_reg_reg(list : TAsmList;fromsize,tosize : tcgsize;reg1,reg2 : tregister);
  758. var
  759. op: tasmop;
  760. s: topsize;
  761. instr:Taicpu;
  762. begin
  763. check_register_size(fromsize,reg1);
  764. check_register_size(tosize,reg2);
  765. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  766. begin
  767. reg1:=makeregsize(list,reg1,tosize);
  768. s:=tcgsize2opsize[tosize];
  769. op:=A_MOV;
  770. end
  771. else
  772. sizes2load(fromsize,tosize,op,s);
  773. {$ifdef x86_64}
  774. { zero extensions to 64 bit on the x86_64 are simply done by writting to the lower 32 bit
  775. which clears the upper 64 bit too, so it could be that s is S_L while the reg is
  776. 64 bit (FK)
  777. }
  778. if s in [S_BL,S_WL,S_L] then
  779. reg2:=makeregsize(list,reg2,OS_32);
  780. {$endif x86_64}
  781. if (reg1<>reg2) then
  782. begin
  783. instr:=taicpu.op_reg_reg(op,s,reg1,reg2);
  784. { Notify the register allocator that we have written a move instruction so
  785. it can try to eliminate it. }
  786. if (reg1<>current_procinfo.framepointer) and (reg1<>NR_STACK_POINTER_REG) then
  787. add_move_instruction(instr);
  788. list.concat(instr);
  789. end;
  790. {$ifdef x86_64}
  791. { avoid merging of registers and killing the zero extensions (FK) }
  792. if (tosize in [OS_64,OS_S64]) and (s=S_L) then
  793. list.concat(taicpu.op_const_reg(A_AND,S_L,$ffffffff,reg2));
  794. {$endif x86_64}
  795. end;
  796. procedure tcgx86.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  797. var
  798. tmpref : treference;
  799. begin
  800. with ref do
  801. begin
  802. if (base=NR_NO) and (index=NR_NO) then
  803. begin
  804. if assigned(ref.symbol) then
  805. begin
  806. if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
  807. ((ref.symbol.bind in [AB_EXTERNAL,AB_WEAK_EXTERNAL]) or
  808. (cs_create_pic in current_settings.moduleswitches)) then
  809. begin
  810. if (ref.symbol.bind in [AB_EXTERNAL,AB_WEAK_EXTERNAL]) or
  811. ((cs_create_pic in current_settings.moduleswitches) and
  812. (ref.symbol.bind in [AB_COMMON,AB_GLOBAL,AB_PRIVATE_EXTERN])) then
  813. begin
  814. reference_reset_base(tmpref,
  815. g_indirect_sym_load(list,ref.symbol.name,asmsym2indsymflags(ref.symbol)),
  816. offset,sizeof(pint));
  817. a_loadaddr_ref_reg(list,tmpref,r);
  818. end
  819. else
  820. begin
  821. include(current_procinfo.flags,pi_needs_got);
  822. reference_reset_base(tmpref,current_procinfo.got,offset,ref.alignment);
  823. tmpref.symbol:=symbol;
  824. tmpref.relsymbol:=current_procinfo.CurrGOTLabel;
  825. list.concat(Taicpu.op_ref_reg(A_LEA,tcgsize2opsize[OS_ADDR],tmpref,r));
  826. end;
  827. end
  828. else if (cs_create_pic in current_settings.moduleswitches)
  829. {$ifdef x86_64}
  830. and not(ref.symbol.bind=AB_LOCAL)
  831. {$endif x86_64}
  832. then
  833. begin
  834. {$ifdef x86_64}
  835. reference_reset_symbol(tmpref,ref.symbol,0,ref.alignment);
  836. tmpref.refaddr:=addr_pic;
  837. tmpref.base:=NR_RIP;
  838. list.concat(taicpu.op_ref_reg(A_MOV,S_Q,tmpref,r));
  839. {$else x86_64}
  840. reference_reset_symbol(tmpref,ref.symbol,0,ref.alignment);
  841. tmpref.refaddr:=addr_pic;
  842. tmpref.base:=current_procinfo.got;
  843. include(current_procinfo.flags,pi_needs_got);
  844. list.concat(taicpu.op_ref_reg(A_MOV,S_L,tmpref,r));
  845. {$endif x86_64}
  846. if offset<>0 then
  847. a_op_const_reg(list,OP_ADD,OS_ADDR,offset,r);
  848. end
  849. {$ifdef x86_64}
  850. else if (target_info.system in (systems_all_windows+[system_x86_64_darwin]))
  851. or (cs_create_pic in current_settings.moduleswitches)
  852. then
  853. begin
  854. { Win64 and Darwin/x86_64 always require RIP-relative addressing }
  855. tmpref:=ref;
  856. tmpref.base:=NR_RIP;
  857. tmpref.refaddr:=addr_pic_no_got;
  858. list.concat(Taicpu.op_ref_reg(A_LEA,S_Q,tmpref,r));
  859. end
  860. {$endif x86_64}
  861. else
  862. begin
  863. tmpref:=ref;
  864. tmpref.refaddr:=ADDR_FULL;
  865. list.concat(Taicpu.op_ref_reg(A_MOV,tcgsize2opsize[OS_ADDR],tmpref,r));
  866. end
  867. end
  868. else
  869. a_load_const_reg(list,OS_ADDR,offset,r)
  870. end
  871. else if (base=NR_NO) and (index<>NR_NO) and
  872. (offset=0) and (scalefactor=0) and (symbol=nil) then
  873. a_load_reg_reg(list,OS_ADDR,OS_ADDR,index,r)
  874. else if (base<>NR_NO) and (index=NR_NO) and
  875. (offset=0) and (symbol=nil) then
  876. a_load_reg_reg(list,OS_ADDR,OS_ADDR,base,r)
  877. else
  878. begin
  879. tmpref:=ref;
  880. make_simple_ref(list,tmpref);
  881. list.concat(Taicpu.op_ref_reg(A_LEA,tcgsize2opsize[OS_ADDR],tmpref,r));
  882. end;
  883. if segment<>NR_NO then
  884. begin
  885. if (tf_section_threadvars in target_info.flags) then
  886. begin
  887. { Convert thread local address to a process global addres
  888. as we cannot handle far pointers.}
  889. case target_info.system of
  890. system_i386_linux,system_i386_android:
  891. if segment=NR_GS then
  892. begin
  893. reference_reset_symbol(tmpref,current_asmdata.RefAsmSymbol('___fpc_threadvar_offset'),0,ref.alignment);
  894. tmpref.segment:=NR_GS;
  895. list.concat(Taicpu.op_ref_reg(A_ADD,tcgsize2opsize[OS_ADDR],tmpref,r));
  896. end
  897. else
  898. cgmessage(cg_e_cant_use_far_pointer_there);
  899. else
  900. cgmessage(cg_e_cant_use_far_pointer_there);
  901. end;
  902. end
  903. else
  904. cgmessage(cg_e_cant_use_far_pointer_there);
  905. end;
  906. end;
  907. end;
  908. { all fpu load routines expect that R_ST[0-7] means an fpu regvar and }
  909. { R_ST means "the current value at the top of the fpu stack" (JM) }
  910. procedure tcgx86.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister);
  911. var
  912. href: treference;
  913. op: tasmop;
  914. s: topsize;
  915. begin
  916. if (reg1<>NR_ST) then
  917. begin
  918. floatloadops(tosize,op,s);
  919. list.concat(taicpu.op_reg(op,s,rgfpu.correct_fpuregister(reg1,rgfpu.fpuvaroffset)));
  920. inc_fpu_stack;
  921. end;
  922. if (reg2<>NR_ST) then
  923. begin
  924. floatstoreops(tosize,op,s);
  925. list.concat(taicpu.op_reg(op,s,rgfpu.correct_fpuregister(reg2,rgfpu.fpuvaroffset)));
  926. dec_fpu_stack;
  927. end;
  928. { OS_F80 < OS_C64, but OS_C64 fits perfectly in OS_F80 }
  929. if (reg1=NR_ST) and
  930. (reg2=NR_ST) and
  931. (tosize<>OS_F80) and
  932. (tosize<fromsize) then
  933. begin
  934. { can't round down to lower precision in x87 :/ }
  935. tg.gettemp(list,tcgsize2size[tosize],tcgsize2size[tosize],tt_normal,href);
  936. a_loadfpu_reg_ref(list,fromsize,tosize,NR_ST,href);
  937. a_loadfpu_ref_reg(list,tosize,tosize,href,NR_ST);
  938. tg.ungettemp(list,href);
  939. end;
  940. end;
  941. procedure tcgx86.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
  942. begin
  943. floatload(list,fromsize,ref);
  944. a_loadfpu_reg_reg(list,fromsize,tosize,NR_ST,reg);
  945. end;
  946. procedure tcgx86.a_loadfpu_reg_ref(list: TAsmList; fromsize,tosize: tcgsize; reg: tregister; const ref: treference);
  947. begin
  948. { in case a record returned in a floating point register
  949. (LOC_FPUREGISTER with OS_F32/OS_F64) is stored in memory
  950. (LOC_REFERENCE with OS_32/OS_64), we have to adjust the
  951. tosize }
  952. if (fromsize in [OS_F32,OS_F64]) and
  953. (tcgsize2size[fromsize]=tcgsize2size[tosize]) then
  954. case tosize of
  955. OS_32:
  956. tosize:=OS_F32;
  957. OS_64:
  958. tosize:=OS_F64;
  959. end;
  960. if reg<>NR_ST then
  961. a_loadfpu_reg_reg(list,fromsize,tosize,reg,NR_ST);
  962. floatstore(list,tosize,ref);
  963. end;
  964. function get_scalar_mm_op(fromsize,tosize : tcgsize) : tasmop;
  965. const
  966. convertop : array[OS_F32..OS_F128,OS_F32..OS_F128] of tasmop = (
  967. (A_MOVSS,A_CVTSS2SD,A_NONE,A_NONE,A_NONE),
  968. (A_CVTSD2SS,A_MOVSD,A_NONE,A_NONE,A_NONE),
  969. (A_NONE,A_NONE,A_NONE,A_NONE,A_NONE),
  970. (A_NONE,A_NONE,A_NONE,A_MOVQ,A_NONE),
  971. (A_NONE,A_NONE,A_NONE,A_NONE,A_NONE));
  972. begin
  973. { we can have OS_F32/OS_F64 (record in function result/LOC_MMREGISTER) to
  974. OS_32/OS_64 (record in memory/LOC_REFERENCE) }
  975. if (fromsize in [OS_F32,OS_F64]) and
  976. (tcgsize2size[fromsize]=tcgsize2size[tosize]) then
  977. case tosize of
  978. OS_32:
  979. tosize:=OS_F32;
  980. OS_64:
  981. tosize:=OS_F64;
  982. end;
  983. if (fromsize in [low(convertop)..high(convertop)]) and
  984. (tosize in [low(convertop)..high(convertop)]) then
  985. result:=convertop[fromsize,tosize]
  986. { we can have OS_M64 (record in function result/LOC_MMREGISTER) to
  987. OS_64 (record in memory/LOC_REFERENCE) }
  988. else if (tcgsize2size[fromsize]=tcgsize2size[tosize]) and
  989. (fromsize=OS_M64) then
  990. result:=A_MOVQ
  991. else
  992. internalerror(2010060104);
  993. if result=A_NONE then
  994. internalerror(200312205);
  995. end;
  996. procedure tcgx86.a_loadmm_reg_reg(list: TAsmList; fromsize, tosize : tcgsize;reg1, reg2: tregister;shuffle : pmmshuffle);
  997. var
  998. instr : taicpu;
  999. begin
  1000. if shuffle=nil then
  1001. begin
  1002. if fromsize=tosize then
  1003. { needs correct size in case of spilling }
  1004. case fromsize of
  1005. OS_F32:
  1006. instr:=taicpu.op_reg_reg(A_MOVAPS,S_NO,reg1,reg2);
  1007. OS_F64:
  1008. instr:=taicpu.op_reg_reg(A_MOVAPD,S_NO,reg1,reg2);
  1009. OS_M64:
  1010. instr:=taicpu.op_reg_reg(A_MOVQ,S_NO,reg1,reg2);
  1011. else
  1012. internalerror(2006091201);
  1013. end
  1014. else
  1015. internalerror(200312202);
  1016. add_move_instruction(instr);
  1017. end
  1018. else if shufflescalar(shuffle) then
  1019. begin
  1020. instr:=taicpu.op_reg_reg(get_scalar_mm_op(fromsize,tosize),S_NO,reg1,reg2);
  1021. case get_scalar_mm_op(fromsize,tosize) of
  1022. A_MOVSS,
  1023. A_MOVSD,
  1024. A_MOVQ:
  1025. add_move_instruction(instr);
  1026. end;
  1027. end
  1028. else
  1029. internalerror(200312201);
  1030. list.concat(instr);
  1031. end;
  1032. procedure tcgx86.a_loadmm_ref_reg(list: TAsmList; fromsize, tosize : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle);
  1033. var
  1034. tmpref : treference;
  1035. begin
  1036. tmpref:=ref;
  1037. make_simple_ref(list,tmpref);
  1038. if shuffle=nil then
  1039. begin
  1040. if fromsize=OS_M64 then
  1041. list.concat(taicpu.op_ref_reg(A_MOVQ,S_NO,tmpref,reg))
  1042. else
  1043. {$ifdef x86_64}
  1044. { x86-64 has always properly aligned data }
  1045. list.concat(taicpu.op_ref_reg(A_MOVDQA,S_NO,tmpref,reg));
  1046. {$else x86_64}
  1047. list.concat(taicpu.op_ref_reg(A_MOVDQU,S_NO,tmpref,reg));
  1048. {$endif x86_64}
  1049. end
  1050. else if shufflescalar(shuffle) then
  1051. list.concat(taicpu.op_ref_reg(get_scalar_mm_op(fromsize,tosize),S_NO,tmpref,reg))
  1052. else
  1053. internalerror(200312252);
  1054. end;
  1055. procedure tcgx86.a_loadmm_reg_ref(list: TAsmList; fromsize, tosize : tcgsize;reg: tregister; const ref: treference;shuffle : pmmshuffle);
  1056. var
  1057. hreg : tregister;
  1058. tmpref : treference;
  1059. begin
  1060. tmpref:=ref;
  1061. make_simple_ref(list,tmpref);
  1062. if shuffle=nil then
  1063. begin
  1064. if fromsize=OS_M64 then
  1065. list.concat(taicpu.op_reg_ref(A_MOVQ,S_NO,reg,tmpref))
  1066. else
  1067. {$ifdef x86_64}
  1068. { x86-64 has always properly aligned data }
  1069. list.concat(taicpu.op_reg_ref(A_MOVDQA,S_NO,reg,tmpref))
  1070. {$else x86_64}
  1071. list.concat(taicpu.op_reg_ref(A_MOVDQU,S_NO,reg,tmpref))
  1072. {$endif x86_64}
  1073. end
  1074. else if shufflescalar(shuffle) then
  1075. begin
  1076. if tcgsize2size[tosize]<>tcgsize2size[fromsize] then
  1077. begin
  1078. hreg:=getmmregister(list,tosize);
  1079. list.concat(taicpu.op_reg_reg(get_scalar_mm_op(fromsize,tosize),S_NO,reg,hreg));
  1080. list.concat(taicpu.op_reg_ref(get_scalar_mm_op(tosize,tosize),S_NO,hreg,tmpref));
  1081. end
  1082. else
  1083. list.concat(taicpu.op_reg_ref(get_scalar_mm_op(fromsize,tosize),S_NO,reg,tmpref));
  1084. end
  1085. else
  1086. internalerror(200312252);
  1087. end;
  1088. procedure tcgx86.a_opmm_ref_reg(list: TAsmList; Op: TOpCG; size : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle);
  1089. var
  1090. l : tlocation;
  1091. begin
  1092. l.loc:=LOC_REFERENCE;
  1093. l.reference:=ref;
  1094. l.size:=size;
  1095. opmm_loc_reg(list,op,size,l,reg,shuffle);
  1096. end;
  1097. procedure tcgx86.a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size : tcgsize;src,dst: tregister;shuffle : pmmshuffle);
  1098. var
  1099. l : tlocation;
  1100. begin
  1101. l.loc:=LOC_MMREGISTER;
  1102. l.register:=src;
  1103. l.size:=size;
  1104. opmm_loc_reg(list,op,size,l,dst,shuffle);
  1105. end;
  1106. procedure tcgx86.opmm_loc_reg(list: TAsmList; Op: TOpCG; size : tcgsize;loc : tlocation;dst: tregister; shuffle : pmmshuffle);
  1107. const
  1108. opmm2asmop : array[0..1,OS_F32..OS_F64,topcg] of tasmop = (
  1109. ( { scalar }
  1110. ( { OS_F32 }
  1111. A_NOP,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,A_NOP,A_NOP
  1112. ),
  1113. ( { OS_F64 }
  1114. A_NOP,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,A_NOP,A_NOP
  1115. )
  1116. ),
  1117. ( { vectorized/packed }
  1118. { because the logical packed single instructions have shorter op codes, we use always
  1119. these
  1120. }
  1121. ( { OS_F32 }
  1122. A_NOP,A_NOP,A_ADDPS,A_NOP,A_DIVPS,A_NOP,A_NOP,A_MULPS,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_SUBPS,A_XORPS,A_NOP,A_NOP
  1123. ),
  1124. ( { OS_F64 }
  1125. A_NOP,A_NOP,A_ADDPD,A_NOP,A_DIVPD,A_NOP,A_NOP,A_MULPD,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_NOP,A_SUBPD,A_XORPD,A_NOP,A_NOP
  1126. )
  1127. )
  1128. );
  1129. var
  1130. resultreg : tregister;
  1131. asmop : tasmop;
  1132. begin
  1133. { this is an internally used procedure so the parameters have
  1134. some constrains
  1135. }
  1136. if loc.size<>size then
  1137. internalerror(200312213);
  1138. resultreg:=dst;
  1139. { deshuffle }
  1140. //!!!
  1141. if (shuffle<>nil) and not(shufflescalar(shuffle)) then
  1142. begin
  1143. internalerror(2010060101);
  1144. end
  1145. else if (shuffle=nil) then
  1146. asmop:=opmm2asmop[1,size,op]
  1147. else if shufflescalar(shuffle) then
  1148. begin
  1149. asmop:=opmm2asmop[0,size,op];
  1150. { no scalar operation available? }
  1151. if asmop=A_NOP then
  1152. begin
  1153. { do vectorized and shuffle finally }
  1154. internalerror(2010060102);
  1155. end;
  1156. end
  1157. else
  1158. internalerror(200312211);
  1159. if asmop=A_NOP then
  1160. internalerror(200312216);
  1161. case loc.loc of
  1162. LOC_CREFERENCE,LOC_REFERENCE:
  1163. begin
  1164. make_simple_ref(current_asmdata.CurrAsmList,loc.reference);
  1165. list.concat(taicpu.op_ref_reg(asmop,S_NO,loc.reference,resultreg));
  1166. end;
  1167. LOC_CMMREGISTER,LOC_MMREGISTER:
  1168. list.concat(taicpu.op_reg_reg(asmop,S_NO,loc.register,resultreg));
  1169. else
  1170. internalerror(200312214);
  1171. end;
  1172. { shuffle }
  1173. if resultreg<>dst then
  1174. begin
  1175. internalerror(200312212);
  1176. end;
  1177. end;
  1178. procedure tcgx86.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
  1179. var
  1180. opcode : tasmop;
  1181. power : longint;
  1182. {$ifdef x86_64}
  1183. tmpreg : tregister;
  1184. {$endif x86_64}
  1185. begin
  1186. optimize_op_const(op, a);
  1187. {$ifdef x86_64}
  1188. { x86_64 only supports signed 32 bits constants directly }
  1189. if not(op in [OP_NONE,OP_MOVE]) and
  1190. (size in [OS_S64,OS_64]) and
  1191. ((a<low(longint)) or (a>high(longint))) then
  1192. begin
  1193. tmpreg:=getintregister(list,size);
  1194. a_load_const_reg(list,size,a,tmpreg);
  1195. a_op_reg_reg(list,op,size,tmpreg,reg);
  1196. exit;
  1197. end;
  1198. {$endif x86_64}
  1199. check_register_size(size,reg);
  1200. case op of
  1201. OP_NONE :
  1202. begin
  1203. { Opcode is optimized away }
  1204. end;
  1205. OP_MOVE :
  1206. begin
  1207. { Optimized, replaced with a simple load }
  1208. a_load_const_reg(list,size,a,reg);
  1209. end;
  1210. OP_DIV, OP_IDIV:
  1211. begin
  1212. if ispowerof2(int64(a),power) then
  1213. begin
  1214. case op of
  1215. OP_DIV:
  1216. opcode := A_SHR;
  1217. OP_IDIV:
  1218. opcode := A_SAR;
  1219. end;
  1220. list.concat(taicpu.op_const_reg(opcode,TCgSize2OpSize[size],power,reg));
  1221. exit;
  1222. end;
  1223. { the rest should be handled specifically in the code }
  1224. { generator because of the silly register usage restraints }
  1225. internalerror(200109224);
  1226. end;
  1227. OP_MUL,OP_IMUL:
  1228. begin
  1229. if not(cs_check_overflow in current_settings.localswitches) and
  1230. ispowerof2(int64(a),power) then
  1231. begin
  1232. list.concat(taicpu.op_const_reg(A_SHL,TCgSize2OpSize[size],power,reg));
  1233. exit;
  1234. end;
  1235. if op = OP_IMUL then
  1236. list.concat(taicpu.op_const_reg(A_IMUL,TCgSize2OpSize[size],a,reg))
  1237. else
  1238. { OP_MUL should be handled specifically in the code }
  1239. { generator because of the silly register usage restraints }
  1240. internalerror(200109225);
  1241. end;
  1242. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  1243. if not(cs_check_overflow in current_settings.localswitches) and
  1244. (a = 1) and
  1245. (op in [OP_ADD,OP_SUB]) then
  1246. if op = OP_ADD then
  1247. list.concat(taicpu.op_reg(A_INC,TCgSize2OpSize[size],reg))
  1248. else
  1249. list.concat(taicpu.op_reg(A_DEC,TCgSize2OpSize[size],reg))
  1250. else if (a = 0) then
  1251. if (op <> OP_AND) then
  1252. exit
  1253. else
  1254. list.concat(taicpu.op_const_reg(A_MOV,TCgSize2OpSize[size],0,reg))
  1255. else if (aword(a) = high(aword)) and
  1256. (op in [OP_AND,OP_OR,OP_XOR]) then
  1257. begin
  1258. case op of
  1259. OP_AND:
  1260. exit;
  1261. OP_OR:
  1262. list.concat(taicpu.op_const_reg(A_MOV,TCgSize2OpSize[size],aint(high(aword)),reg));
  1263. OP_XOR:
  1264. list.concat(taicpu.op_reg(A_NOT,TCgSize2OpSize[size],reg));
  1265. end
  1266. end
  1267. else
  1268. list.concat(taicpu.op_const_reg(TOpCG2AsmOp[op],TCgSize2OpSize[size],aint(a),reg));
  1269. OP_SHL,OP_SHR,OP_SAR,OP_ROL,OP_ROR:
  1270. begin
  1271. {$ifdef x86_64}
  1272. if (a and 63) <> 0 Then
  1273. list.concat(taicpu.op_const_reg(TOpCG2AsmOp[op],TCgSize2OpSize[size],a and 63,reg));
  1274. if (a shr 6) <> 0 Then
  1275. internalerror(200609073);
  1276. {$else x86_64}
  1277. if (a and 31) <> 0 Then
  1278. list.concat(taicpu.op_const_reg(TOpCG2AsmOp[op],TCgSize2OpSize[size],a and 31,reg));
  1279. if (a shr 5) <> 0 Then
  1280. internalerror(200609071);
  1281. {$endif x86_64}
  1282. end
  1283. else internalerror(200609072);
  1284. end;
  1285. end;
  1286. procedure tcgx86.a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference);
  1287. var
  1288. opcode: tasmop;
  1289. power: longint;
  1290. {$ifdef x86_64}
  1291. tmpreg : tregister;
  1292. {$endif x86_64}
  1293. tmpref : treference;
  1294. begin
  1295. optimize_op_const(op, a);
  1296. tmpref:=ref;
  1297. make_simple_ref(list,tmpref);
  1298. {$ifdef x86_64}
  1299. { x86_64 only supports signed 32 bits constants directly }
  1300. if not(op in [OP_NONE,OP_MOVE]) and
  1301. (size in [OS_S64,OS_64]) and
  1302. ((a<low(longint)) or (a>high(longint))) then
  1303. begin
  1304. tmpreg:=getintregister(list,size);
  1305. a_load_const_reg(list,size,a,tmpreg);
  1306. a_op_reg_ref(list,op,size,tmpreg,tmpref);
  1307. exit;
  1308. end;
  1309. {$endif x86_64}
  1310. Case Op of
  1311. OP_NONE :
  1312. begin
  1313. { Opcode is optimized away }
  1314. end;
  1315. OP_MOVE :
  1316. begin
  1317. { Optimized, replaced with a simple load }
  1318. a_load_const_ref(list,size,a,ref);
  1319. end;
  1320. OP_DIV, OP_IDIV:
  1321. Begin
  1322. if ispowerof2(int64(a),power) then
  1323. begin
  1324. case op of
  1325. OP_DIV:
  1326. opcode := A_SHR;
  1327. OP_IDIV:
  1328. opcode := A_SAR;
  1329. end;
  1330. list.concat(taicpu.op_const_ref(opcode,
  1331. TCgSize2OpSize[size],power,tmpref));
  1332. exit;
  1333. end;
  1334. { the rest should be handled specifically in the code }
  1335. { generator because of the silly register usage restraints }
  1336. internalerror(200109231);
  1337. End;
  1338. OP_MUL,OP_IMUL:
  1339. begin
  1340. if not(cs_check_overflow in current_settings.localswitches) and
  1341. ispowerof2(int64(a),power) then
  1342. begin
  1343. list.concat(taicpu.op_const_ref(A_SHL,TCgSize2OpSize[size],
  1344. power,tmpref));
  1345. exit;
  1346. end;
  1347. { can't multiply a memory location directly with a constant }
  1348. if op = OP_IMUL then
  1349. inherited a_op_const_ref(list,op,size,a,tmpref)
  1350. else
  1351. { OP_MUL should be handled specifically in the code }
  1352. { generator because of the silly register usage restraints }
  1353. internalerror(200109232);
  1354. end;
  1355. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  1356. if not(cs_check_overflow in current_settings.localswitches) and
  1357. (a = 1) and
  1358. (op in [OP_ADD,OP_SUB]) then
  1359. if op = OP_ADD then
  1360. list.concat(taicpu.op_ref(A_INC,TCgSize2OpSize[size],tmpref))
  1361. else
  1362. list.concat(taicpu.op_ref(A_DEC,TCgSize2OpSize[size],tmpref))
  1363. else if (a = 0) then
  1364. if (op <> OP_AND) then
  1365. exit
  1366. else
  1367. a_load_const_ref(list,size,0,tmpref)
  1368. else if (aword(a) = high(aword)) and
  1369. (op in [OP_AND,OP_OR,OP_XOR]) then
  1370. begin
  1371. case op of
  1372. OP_AND:
  1373. exit;
  1374. OP_OR:
  1375. list.concat(taicpu.op_const_ref(A_MOV,TCgSize2OpSize[size],aint(high(aword)),tmpref));
  1376. OP_XOR:
  1377. list.concat(taicpu.op_ref(A_NOT,TCgSize2OpSize[size],tmpref));
  1378. end
  1379. end
  1380. else
  1381. list.concat(taicpu.op_const_ref(TOpCG2AsmOp[op],
  1382. TCgSize2OpSize[size],a,tmpref));
  1383. OP_SHL,OP_SHR,OP_SAR,OP_ROL,OP_ROR:
  1384. begin
  1385. if (a and 31) <> 0 then
  1386. list.concat(taicpu.op_const_ref(
  1387. TOpCG2AsmOp[op],TCgSize2OpSize[size],a and 31,tmpref));
  1388. if (a shr 5) <> 0 Then
  1389. internalerror(68991);
  1390. end
  1391. else internalerror(68992);
  1392. end;
  1393. end;
  1394. procedure tcgx86.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  1395. var
  1396. dstsize: topsize;
  1397. instr:Taicpu;
  1398. begin
  1399. check_register_size(size,src);
  1400. check_register_size(size,dst);
  1401. dstsize := tcgsize2opsize[size];
  1402. case op of
  1403. OP_NEG,OP_NOT:
  1404. begin
  1405. if src<>dst then
  1406. a_load_reg_reg(list,size,size,src,dst);
  1407. list.concat(taicpu.op_reg(TOpCG2AsmOp[op],dstsize,dst));
  1408. end;
  1409. OP_MUL,OP_DIV,OP_IDIV:
  1410. { special stuff, needs separate handling inside code }
  1411. { generator }
  1412. internalerror(200109233);
  1413. OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
  1414. begin
  1415. { Use ecx to load the value, that allows better coalescing }
  1416. getcpuregister(list,NR_ECX);
  1417. a_load_reg_reg(list,size,OS_32,src,NR_ECX);
  1418. list.concat(taicpu.op_reg_reg(Topcg2asmop[op],tcgsize2opsize[size],NR_CL,dst));
  1419. ungetcpuregister(list,NR_ECX);
  1420. end;
  1421. else
  1422. begin
  1423. if reg2opsize(src) <> dstsize then
  1424. internalerror(200109226);
  1425. instr:=taicpu.op_reg_reg(TOpCG2AsmOp[op],dstsize,src,dst);
  1426. list.concat(instr);
  1427. end;
  1428. end;
  1429. end;
  1430. procedure tcgx86.a_op_ref_reg(list : TAsmList; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister);
  1431. var
  1432. tmpref : treference;
  1433. begin
  1434. tmpref:=ref;
  1435. make_simple_ref(list,tmpref);
  1436. check_register_size(size,reg);
  1437. case op of
  1438. OP_NEG,OP_NOT,OP_IMUL:
  1439. begin
  1440. inherited a_op_ref_reg(list,op,size,tmpref,reg);
  1441. end;
  1442. OP_MUL,OP_DIV,OP_IDIV:
  1443. { special stuff, needs separate handling inside code }
  1444. { generator }
  1445. internalerror(200109239);
  1446. else
  1447. begin
  1448. reg := makeregsize(list,reg,size);
  1449. list.concat(taicpu.op_ref_reg(TOpCG2AsmOp[op],tcgsize2opsize[size],tmpref,reg));
  1450. end;
  1451. end;
  1452. end;
  1453. procedure tcgx86.a_op_reg_ref(list : TAsmList; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference);
  1454. var
  1455. tmpref : treference;
  1456. begin
  1457. tmpref:=ref;
  1458. make_simple_ref(list,tmpref);
  1459. check_register_size(size,reg);
  1460. case op of
  1461. OP_NEG,OP_NOT:
  1462. begin
  1463. if reg<>NR_NO then
  1464. internalerror(200109237);
  1465. list.concat(taicpu.op_ref(TOpCG2AsmOp[op],tcgsize2opsize[size],tmpref));
  1466. end;
  1467. OP_IMUL:
  1468. begin
  1469. { this one needs a load/imul/store, which is the default }
  1470. inherited a_op_ref_reg(list,op,size,tmpref,reg);
  1471. end;
  1472. OP_MUL,OP_DIV,OP_IDIV:
  1473. { special stuff, needs separate handling inside code }
  1474. { generator }
  1475. internalerror(200109238);
  1476. else
  1477. begin
  1478. list.concat(taicpu.op_reg_ref(TOpCG2AsmOp[op],tcgsize2opsize[size],reg,tmpref));
  1479. end;
  1480. end;
  1481. end;
  1482. procedure tcgx86.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister);
  1483. var
  1484. opsize: topsize;
  1485. l : TAsmLabel;
  1486. begin
  1487. opsize:=tcgsize2opsize[size];
  1488. if not reverse then
  1489. list.concat(taicpu.op_reg_reg(A_BSF,opsize,src,dst))
  1490. else
  1491. list.concat(taicpu.op_reg_reg(A_BSR,opsize,src,dst));
  1492. current_asmdata.getjumplabel(l);
  1493. a_jmp_cond(list,OC_NE,l);
  1494. list.concat(taicpu.op_const_reg(A_MOV,opsize,$ff,dst));
  1495. a_label(list,l);
  1496. end;
  1497. {*************** compare instructructions ****************}
  1498. procedure tcgx86.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister;
  1499. l : tasmlabel);
  1500. {$ifdef x86_64}
  1501. var
  1502. tmpreg : tregister;
  1503. {$endif x86_64}
  1504. begin
  1505. {$ifdef x86_64}
  1506. { x86_64 only supports signed 32 bits constants directly }
  1507. if (size in [OS_S64,OS_64]) and
  1508. ((a<low(longint)) or (a>high(longint))) then
  1509. begin
  1510. tmpreg:=getintregister(list,size);
  1511. a_load_const_reg(list,size,a,tmpreg);
  1512. a_cmp_reg_reg_label(list,size,cmp_op,tmpreg,reg,l);
  1513. exit;
  1514. end;
  1515. {$endif x86_64}
  1516. if (a = 0) then
  1517. list.concat(taicpu.op_reg_reg(A_TEST,tcgsize2opsize[size],reg,reg))
  1518. else
  1519. list.concat(taicpu.op_const_reg(A_CMP,tcgsize2opsize[size],a,reg));
  1520. a_jmp_cond(list,cmp_op,l);
  1521. end;
  1522. procedure tcgx86.a_cmp_const_ref_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;const ref : treference;
  1523. l : tasmlabel);
  1524. var
  1525. {$ifdef x86_64}
  1526. tmpreg : tregister;
  1527. {$endif x86_64}
  1528. tmpref : treference;
  1529. begin
  1530. tmpref:=ref;
  1531. make_simple_ref(list,tmpref);
  1532. {$ifdef x86_64}
  1533. { x86_64 only supports signed 32 bits constants directly }
  1534. if (size in [OS_S64,OS_64]) and
  1535. ((a<low(longint)) or (a>high(longint))) then
  1536. begin
  1537. tmpreg:=getintregister(list,size);
  1538. a_load_const_reg(list,size,a,tmpreg);
  1539. a_cmp_reg_ref_label(list,size,cmp_op,tmpreg,tmpref,l);
  1540. exit;
  1541. end;
  1542. {$endif x86_64}
  1543. list.concat(taicpu.op_const_ref(A_CMP,TCgSize2OpSize[size],a,tmpref));
  1544. a_jmp_cond(list,cmp_op,l);
  1545. end;
  1546. procedure tcgx86.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;
  1547. reg1,reg2 : tregister;l : tasmlabel);
  1548. begin
  1549. check_register_size(size,reg1);
  1550. check_register_size(size,reg2);
  1551. list.concat(taicpu.op_reg_reg(A_CMP,TCgSize2OpSize[size],reg1,reg2));
  1552. a_jmp_cond(list,cmp_op,l);
  1553. end;
  1554. procedure tcgx86.a_cmp_ref_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;const ref: treference; reg : tregister;l : tasmlabel);
  1555. var
  1556. tmpref : treference;
  1557. begin
  1558. tmpref:=ref;
  1559. make_simple_ref(list,tmpref);
  1560. check_register_size(size,reg);
  1561. list.concat(taicpu.op_ref_reg(A_CMP,TCgSize2OpSize[size],tmpref,reg));
  1562. a_jmp_cond(list,cmp_op,l);
  1563. end;
  1564. procedure tcgx86.a_cmp_reg_ref_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg : tregister;const ref: treference; l : tasmlabel);
  1565. var
  1566. tmpref : treference;
  1567. begin
  1568. tmpref:=ref;
  1569. make_simple_ref(list,tmpref);
  1570. check_register_size(size,reg);
  1571. list.concat(taicpu.op_reg_ref(A_CMP,TCgSize2OpSize[size],reg,tmpref));
  1572. a_jmp_cond(list,cmp_op,l);
  1573. end;
  1574. procedure tcgx86.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  1575. var
  1576. ai : taicpu;
  1577. begin
  1578. if cond=OC_None then
  1579. ai := Taicpu.Op_sym(A_JMP,S_NO,l)
  1580. else
  1581. begin
  1582. ai:=Taicpu.Op_sym(A_Jcc,S_NO,l);
  1583. ai.SetCondition(TOpCmp2AsmCond[cond]);
  1584. end;
  1585. ai.is_jmp:=true;
  1586. list.concat(ai);
  1587. end;
  1588. procedure tcgx86.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1589. var
  1590. ai : taicpu;
  1591. begin
  1592. ai := Taicpu.op_sym(A_Jcc,S_NO,l);
  1593. ai.SetCondition(flags_to_cond(f));
  1594. ai.is_jmp := true;
  1595. list.concat(ai);
  1596. end;
  1597. procedure tcgx86.g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister);
  1598. var
  1599. ai : taicpu;
  1600. hreg : tregister;
  1601. begin
  1602. hreg:=makeregsize(list,reg,OS_8);
  1603. ai:=Taicpu.op_reg(A_SETcc,S_B,hreg);
  1604. ai.setcondition(flags_to_cond(f));
  1605. list.concat(ai);
  1606. if reg<>hreg then
  1607. a_load_reg_reg(list,OS_8,size,hreg,reg);
  1608. end;
  1609. procedure tcgx86.g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref: TReference);
  1610. var
  1611. ai : taicpu;
  1612. tmpref : treference;
  1613. begin
  1614. tmpref:=ref;
  1615. make_simple_ref(list,tmpref);
  1616. if not(size in [OS_8,OS_S8]) then
  1617. a_load_const_ref(list,size,0,tmpref);
  1618. ai:=Taicpu.op_ref(A_SETcc,S_B,tmpref);
  1619. ai.setcondition(flags_to_cond(f));
  1620. list.concat(ai);
  1621. {$ifndef cpu64bitalu}
  1622. if size in [OS_S64,OS_64] then
  1623. begin
  1624. inc(tmpref.offset,4);
  1625. a_load_const_ref(list,OS_32,0,tmpref);
  1626. end;
  1627. {$endif cpu64bitalu}
  1628. end;
  1629. { ************* concatcopy ************ }
  1630. procedure Tcgx86.g_concatcopy(list:TAsmList;const source,dest:Treference;len:tcgint);
  1631. const
  1632. {$ifdef cpu64bitalu}
  1633. REGCX=NR_RCX;
  1634. REGSI=NR_RSI;
  1635. REGDI=NR_RDI;
  1636. {$else cpu64bitalu}
  1637. REGCX=NR_ECX;
  1638. REGSI=NR_ESI;
  1639. REGDI=NR_EDI;
  1640. {$endif cpu64bitalu}
  1641. type copymode=(copy_move,copy_mmx,copy_string);
  1642. var srcref,dstref:Treference;
  1643. r,r0,r1,r2,r3:Tregister;
  1644. helpsize:tcgint;
  1645. copysize:byte;
  1646. cgsize:Tcgsize;
  1647. cm:copymode;
  1648. begin
  1649. cm:=copy_move;
  1650. helpsize:=3*sizeof(aword);
  1651. if cs_opt_size in current_settings.optimizerswitches then
  1652. helpsize:=2*sizeof(aword);
  1653. if (cs_mmx in current_settings.localswitches) and
  1654. not(pi_uses_fpu in current_procinfo.flags) and
  1655. ((len=8) or (len=16) or (len=24) or (len=32)) then
  1656. cm:=copy_mmx;
  1657. if (len>helpsize) then
  1658. cm:=copy_string;
  1659. if (cs_opt_size in current_settings.optimizerswitches) and
  1660. not((len<=16) and (cm=copy_mmx)) and
  1661. not(len in [1,2,4{$ifdef x86_64},8{$endif x86_64}]) then
  1662. cm:=copy_string;
  1663. if (source.segment<>NR_NO) or
  1664. (dest.segment<>NR_NO) then
  1665. cm:=copy_string;
  1666. case cm of
  1667. copy_move:
  1668. begin
  1669. dstref:=dest;
  1670. srcref:=source;
  1671. copysize:=sizeof(aint);
  1672. cgsize:=int_cgsize(copysize);
  1673. while len<>0 do
  1674. begin
  1675. if len<2 then
  1676. begin
  1677. copysize:=1;
  1678. cgsize:=OS_8;
  1679. end
  1680. else if len<4 then
  1681. begin
  1682. copysize:=2;
  1683. cgsize:=OS_16;
  1684. end
  1685. else if len<8 then
  1686. begin
  1687. copysize:=4;
  1688. cgsize:=OS_32;
  1689. end
  1690. {$ifdef cpu64bitalu}
  1691. else if len<16 then
  1692. begin
  1693. copysize:=8;
  1694. cgsize:=OS_64;
  1695. end
  1696. {$endif}
  1697. ;
  1698. dec(len,copysize);
  1699. r:=getintregister(list,cgsize);
  1700. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1701. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1702. inc(srcref.offset,copysize);
  1703. inc(dstref.offset,copysize);
  1704. end;
  1705. end;
  1706. copy_mmx:
  1707. begin
  1708. dstref:=dest;
  1709. srcref:=source;
  1710. r0:=getmmxregister(list);
  1711. a_loadmm_ref_reg(list,OS_M64,OS_M64,srcref,r0,nil);
  1712. if len>=16 then
  1713. begin
  1714. inc(srcref.offset,8);
  1715. r1:=getmmxregister(list);
  1716. a_loadmm_ref_reg(list,OS_M64,OS_M64,srcref,r1,nil);
  1717. end;
  1718. if len>=24 then
  1719. begin
  1720. inc(srcref.offset,8);
  1721. r2:=getmmxregister(list);
  1722. a_loadmm_ref_reg(list,OS_M64,OS_M64,srcref,r2,nil);
  1723. end;
  1724. if len>=32 then
  1725. begin
  1726. inc(srcref.offset,8);
  1727. r3:=getmmxregister(list);
  1728. a_loadmm_ref_reg(list,OS_M64,OS_M64,srcref,r3,nil);
  1729. end;
  1730. a_loadmm_reg_ref(list,OS_M64,OS_M64,r0,dstref,nil);
  1731. if len>=16 then
  1732. begin
  1733. inc(dstref.offset,8);
  1734. a_loadmm_reg_ref(list,OS_M64,OS_M64,r1,dstref,nil);
  1735. end;
  1736. if len>=24 then
  1737. begin
  1738. inc(dstref.offset,8);
  1739. a_loadmm_reg_ref(list,OS_M64,OS_M64,r2,dstref,nil);
  1740. end;
  1741. if len>=32 then
  1742. begin
  1743. inc(dstref.offset,8);
  1744. a_loadmm_reg_ref(list,OS_M64,OS_M64,r3,dstref,nil);
  1745. end;
  1746. end
  1747. else {copy_string, should be a good fallback in case of unhandled}
  1748. begin
  1749. getcpuregister(list,REGDI);
  1750. if (dest.segment=NR_NO) then
  1751. a_loadaddr_ref_reg(list,dest,REGDI)
  1752. else
  1753. begin
  1754. dstref:=dest;
  1755. dstref.segment:=NR_NO;
  1756. a_loadaddr_ref_reg(list,dstref,REGDI);
  1757. list.concat(taicpu.op_reg(A_PUSH,S_L,NR_ES));
  1758. list.concat(taicpu.op_reg(A_PUSH,S_L,dest.segment));
  1759. list.concat(taicpu.op_reg(A_POP,S_L,NR_ES));
  1760. end;
  1761. getcpuregister(list,REGSI);
  1762. if (source.segment=NR_NO) then
  1763. a_loadaddr_ref_reg(list,source,REGSI)
  1764. else
  1765. begin
  1766. srcref:=source;
  1767. srcref.segment:=NR_NO;
  1768. a_loadaddr_ref_reg(list,srcref,REGSI);
  1769. list.concat(taicpu.op_reg(A_PUSH,S_L,NR_DS));
  1770. list.concat(taicpu.op_reg(A_PUSH,S_L,source.segment));
  1771. list.concat(taicpu.op_reg(A_POP,S_L,NR_DS));
  1772. end;
  1773. getcpuregister(list,REGCX);
  1774. {$ifdef i386}
  1775. list.concat(Taicpu.op_none(A_CLD,S_NO));
  1776. {$endif i386}
  1777. if (cs_opt_size in current_settings.optimizerswitches) and
  1778. (len>sizeof(aint)+(sizeof(aint) div 2)) then
  1779. begin
  1780. a_load_const_reg(list,OS_INT,len,REGCX);
  1781. list.concat(Taicpu.op_none(A_REP,S_NO));
  1782. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  1783. end
  1784. else
  1785. begin
  1786. helpsize:=len div sizeof(aint);
  1787. len:=len mod sizeof(aint);
  1788. if helpsize>1 then
  1789. begin
  1790. a_load_const_reg(list,OS_INT,helpsize,REGCX);
  1791. list.concat(Taicpu.op_none(A_REP,S_NO));
  1792. end;
  1793. if helpsize>0 then
  1794. begin
  1795. {$ifdef cpu64bitalu}
  1796. list.concat(Taicpu.op_none(A_MOVSQ,S_NO))
  1797. {$else}
  1798. list.concat(Taicpu.op_none(A_MOVSD,S_NO));
  1799. {$endif cpu64bitalu}
  1800. end;
  1801. if len>=4 then
  1802. begin
  1803. dec(len,4);
  1804. list.concat(Taicpu.op_none(A_MOVSD,S_NO));
  1805. end;
  1806. if len>=2 then
  1807. begin
  1808. dec(len,2);
  1809. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  1810. end;
  1811. if len=1 then
  1812. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  1813. end;
  1814. ungetcpuregister(list,REGCX);
  1815. ungetcpuregister(list,REGSI);
  1816. ungetcpuregister(list,REGDI);
  1817. if (source.segment<>NR_NO) then
  1818. list.concat(taicpu.op_reg(A_POP,S_L,NR_DS));
  1819. if (dest.segment<>NR_NO) then
  1820. list.concat(taicpu.op_reg(A_POP,S_L,NR_ES));
  1821. end;
  1822. end;
  1823. end;
  1824. {****************************************************************************
  1825. Entry/Exit Code Helpers
  1826. ****************************************************************************}
  1827. procedure tcgx86.g_profilecode(list : TAsmList);
  1828. var
  1829. pl : tasmlabel;
  1830. mcountprefix : String[4];
  1831. begin
  1832. case target_info.system of
  1833. {$ifndef NOTARGETWIN}
  1834. system_i386_win32,
  1835. {$endif}
  1836. system_i386_freebsd,
  1837. system_i386_netbsd,
  1838. // system_i386_openbsd,
  1839. system_i386_wdosx :
  1840. begin
  1841. Case target_info.system Of
  1842. system_i386_freebsd : mcountprefix:='.';
  1843. system_i386_netbsd : mcountprefix:='__';
  1844. // system_i386_openbsd : mcountprefix:='.';
  1845. else
  1846. mcountPrefix:='';
  1847. end;
  1848. current_asmdata.getaddrlabel(pl);
  1849. new_section(list,sec_data,lower(current_procinfo.procdef.mangledname),sizeof(pint));
  1850. list.concat(Tai_label.Create(pl));
  1851. list.concat(Tai_const.Create_32bit(0));
  1852. new_section(list,sec_code,lower(current_procinfo.procdef.mangledname),0);
  1853. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_EDX));
  1854. list.concat(Taicpu.Op_sym_ofs_reg(A_MOV,S_L,pl,0,NR_EDX));
  1855. a_call_name(list,target_info.Cprefix+mcountprefix+'mcount',false);
  1856. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EDX));
  1857. end;
  1858. system_i386_linux:
  1859. a_call_name(list,target_info.Cprefix+'mcount',false);
  1860. system_i386_go32v2,system_i386_watcom:
  1861. begin
  1862. a_call_name(list,'MCOUNT',false);
  1863. end;
  1864. system_x86_64_linux,
  1865. system_x86_64_darwin:
  1866. begin
  1867. a_call_name(list,'mcount',false);
  1868. end;
  1869. end;
  1870. end;
  1871. procedure tcgx86.g_stackpointer_alloc(list : TAsmList;localsize : longint);
  1872. {$ifdef x86}
  1873. {$ifndef NOTARGETWIN}
  1874. var
  1875. href : treference;
  1876. i : integer;
  1877. again : tasmlabel;
  1878. {$endif NOTARGETWIN}
  1879. {$endif x86}
  1880. begin
  1881. if localsize>0 then
  1882. begin
  1883. {$ifdef i386}
  1884. {$ifndef NOTARGETWIN}
  1885. { windows guards only a few pages for stack growing,
  1886. so we have to access every page first }
  1887. if (target_info.system in [system_i386_win32,system_i386_wince]) and
  1888. (localsize>=winstackpagesize) then
  1889. begin
  1890. if localsize div winstackpagesize<=5 then
  1891. begin
  1892. list.concat(Taicpu.Op_const_reg(A_SUB,S_L,localsize-4,NR_ESP));
  1893. for i:=1 to localsize div winstackpagesize do
  1894. begin
  1895. reference_reset_base(href,NR_ESP,localsize-i*winstackpagesize,4);
  1896. list.concat(Taicpu.op_reg_ref(A_MOV,S_L,NR_EAX,href));
  1897. end;
  1898. list.concat(Taicpu.op_reg(A_PUSH,S_L,NR_EAX));
  1899. end
  1900. else
  1901. begin
  1902. current_asmdata.getjumplabel(again);
  1903. getcpuregister(list,NR_EDI);
  1904. list.concat(Taicpu.op_reg(A_PUSH,S_L,NR_EDI));
  1905. list.concat(Taicpu.op_const_reg(A_MOV,S_L,localsize div winstackpagesize,NR_EDI));
  1906. a_label(list,again);
  1907. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,NR_ESP));
  1908. list.concat(Taicpu.op_reg(A_PUSH,S_L,NR_EAX));
  1909. list.concat(Taicpu.op_reg(A_DEC,S_L,NR_EDI));
  1910. a_jmp_cond(list,OC_NE,again);
  1911. list.concat(Taicpu.op_const_reg(A_SUB,S_L,localsize mod winstackpagesize - 4,NR_ESP));
  1912. reference_reset_base(href,NR_ESP,localsize-4,4);
  1913. list.concat(Taicpu.op_ref_reg(A_MOV,S_L,href,NR_EDI));
  1914. ungetcpuregister(list,NR_EDI);
  1915. end
  1916. end
  1917. else
  1918. {$endif NOTARGETWIN}
  1919. {$endif i386}
  1920. {$ifdef x86_64}
  1921. {$ifndef NOTARGETWIN}
  1922. { windows guards only a few pages for stack growing,
  1923. so we have to access every page first }
  1924. if (target_info.system=system_x86_64_win64) and
  1925. (localsize>=winstackpagesize) then
  1926. begin
  1927. if localsize div winstackpagesize<=5 then
  1928. begin
  1929. list.concat(Taicpu.Op_const_reg(A_SUB,S_Q,localsize,NR_RSP));
  1930. for i:=1 to localsize div winstackpagesize do
  1931. begin
  1932. reference_reset_base(href,NR_RSP,localsize-i*winstackpagesize+4,4);
  1933. list.concat(Taicpu.op_reg_ref(A_MOV,S_L,NR_EAX,href));
  1934. end;
  1935. reference_reset_base(href,NR_RSP,0,4);
  1936. list.concat(Taicpu.op_reg_ref(A_MOV,S_L,NR_EAX,href));
  1937. end
  1938. else
  1939. begin
  1940. current_asmdata.getjumplabel(again);
  1941. getcpuregister(list,NR_R10);
  1942. list.concat(Taicpu.op_const_reg(A_MOV,S_Q,localsize div winstackpagesize,NR_R10));
  1943. a_label(list,again);
  1944. list.concat(Taicpu.op_const_reg(A_SUB,S_Q,winstackpagesize,NR_RSP));
  1945. reference_reset_base(href,NR_RSP,0,4);
  1946. list.concat(Taicpu.op_reg_ref(A_MOV,S_L,NR_EAX,href));
  1947. list.concat(Taicpu.op_reg(A_DEC,S_Q,NR_R10));
  1948. a_jmp_cond(list,OC_NE,again);
  1949. list.concat(Taicpu.op_const_reg(A_SUB,S_Q,localsize mod winstackpagesize,NR_RSP));
  1950. ungetcpuregister(list,NR_R10);
  1951. end
  1952. end
  1953. else
  1954. {$endif NOTARGETWIN}
  1955. {$endif x86_64}
  1956. list.concat(Taicpu.Op_const_reg(A_SUB,tcgsize2opsize[OS_ADDR],localsize,NR_STACK_POINTER_REG));
  1957. end;
  1958. end;
  1959. procedure tcgx86.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1960. var
  1961. stackmisalignment: longint;
  1962. para: tparavarsym;
  1963. begin
  1964. {$ifdef i386}
  1965. { interrupt support for i386 }
  1966. if (po_interrupt in current_procinfo.procdef.procoptions) and
  1967. { this messes up stack alignment }
  1968. not(target_info.system in [system_i386_darwin,system_i386_iphonesim,system_i386_android]) then
  1969. begin
  1970. { .... also the segment registers }
  1971. list.concat(Taicpu.Op_reg(A_PUSH,S_W,NR_GS));
  1972. list.concat(Taicpu.Op_reg(A_PUSH,S_W,NR_FS));
  1973. list.concat(Taicpu.Op_reg(A_PUSH,S_W,NR_ES));
  1974. list.concat(Taicpu.Op_reg(A_PUSH,S_W,NR_DS));
  1975. { save the registers of an interrupt procedure }
  1976. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_EDI));
  1977. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_ESI));
  1978. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_EDX));
  1979. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_ECX));
  1980. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_EBX));
  1981. list.concat(Taicpu.Op_reg(A_PUSH,S_L,NR_EAX));
  1982. end;
  1983. {$endif i386}
  1984. { save old framepointer }
  1985. if not nostackframe then
  1986. begin
  1987. { return address }
  1988. stackmisalignment := sizeof(pint);
  1989. list.concat(tai_regalloc.alloc(current_procinfo.framepointer,nil));
  1990. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  1991. CGmessage(cg_d_stackframe_omited)
  1992. else
  1993. begin
  1994. { push <frame_pointer> }
  1995. inc(stackmisalignment,sizeof(pint));
  1996. include(rg[R_INTREGISTER].preserved_by_proc,RS_FRAME_POINTER_REG);
  1997. list.concat(Taicpu.op_reg(A_PUSH,tcgsize2opsize[OS_ADDR],NR_FRAME_POINTER_REG));
  1998. if (target_info.system=system_x86_64_win64) then
  1999. begin
  2000. list.concat(cai_seh_directive.create_reg(ash_pushreg,NR_FRAME_POINTER_REG));
  2001. include(current_procinfo.flags,pi_has_unwind_info);
  2002. end;
  2003. { Return address and FP are both on stack }
  2004. current_asmdata.asmcfi.cfa_def_cfa_offset(list,2*sizeof(pint));
  2005. current_asmdata.asmcfi.cfa_offset(list,NR_FRAME_POINTER_REG,-(2*sizeof(pint)));
  2006. if current_procinfo.procdef.proctypeoption<>potype_exceptfilter then
  2007. list.concat(Taicpu.op_reg_reg(A_MOV,tcgsize2opsize[OS_ADDR],NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG))
  2008. else
  2009. begin
  2010. { load framepointer from hidden $parentfp parameter }
  2011. para:=tparavarsym(current_procinfo.procdef.paras[0]);
  2012. if not (vo_is_parentfp in para.varoptions) then
  2013. InternalError(201201142);
  2014. if (para.paraloc[calleeside].location^.loc<>LOC_REGISTER) or
  2015. (para.paraloc[calleeside].location^.next<>nil) then
  2016. InternalError(201201143);
  2017. list.concat(Taicpu.op_reg_reg(A_MOV,tcgsize2opsize[OS_ADDR],
  2018. para.paraloc[calleeside].location^.register,NR_FRAME_POINTER_REG));
  2019. { Need only as much stack space as necessary to do the calls.
  2020. Exception filters don't have own local vars, and temps are 'mapped'
  2021. to the parent procedure.
  2022. maxpushedparasize is already aligned at least on x86_64. }
  2023. localsize:=current_procinfo.maxpushedparasize;
  2024. end;
  2025. current_asmdata.asmcfi.cfa_def_cfa_register(list,NR_FRAME_POINTER_REG);
  2026. {
  2027. TODO: current framepointer handling is not compatible with Win64 at all:
  2028. Win64 expects FP to point to the top or into the middle of local area.
  2029. In FPC it points to the bottom, making it impossible to generate
  2030. UWOP_SET_FPREG unwind code if local area is > 240 bytes.
  2031. So for now pretend we never have a framepointer.
  2032. }
  2033. end;
  2034. { allocate stackframe space }
  2035. if (localsize<>0) or
  2036. ((target_info.stackalign>sizeof(pint)) and
  2037. (stackmisalignment <> 0) and
  2038. ((pi_do_call in current_procinfo.flags) or
  2039. (po_assembler in current_procinfo.procdef.procoptions))) then
  2040. begin
  2041. if target_info.stackalign>sizeof(pint) then
  2042. localsize := align(localsize+stackmisalignment,target_info.stackalign)-stackmisalignment;
  2043. cg.g_stackpointer_alloc(list,localsize);
  2044. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  2045. current_asmdata.asmcfi.cfa_def_cfa_offset(list,localsize+sizeof(pint));
  2046. current_procinfo.final_localsize:=localsize;
  2047. if (target_info.system=system_x86_64_win64) then
  2048. begin
  2049. if localsize<>0 then
  2050. list.concat(cai_seh_directive.create_offset(ash_stackalloc,localsize));
  2051. include(current_procinfo.flags,pi_has_unwind_info);
  2052. end;
  2053. end;
  2054. end;
  2055. end;
  2056. { produces if necessary overflowcode }
  2057. procedure tcgx86.g_overflowcheck(list: TAsmList; const l:tlocation;def:tdef);
  2058. var
  2059. hl : tasmlabel;
  2060. ai : taicpu;
  2061. cond : TAsmCond;
  2062. begin
  2063. if not(cs_check_overflow in current_settings.localswitches) then
  2064. exit;
  2065. current_asmdata.getjumplabel(hl);
  2066. if not ((def.typ=pointerdef) or
  2067. ((def.typ=orddef) and
  2068. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  2069. pasbool8,pasbool16,pasbool32,pasbool64]))) then
  2070. cond:=C_NO
  2071. else
  2072. cond:=C_NB;
  2073. ai:=Taicpu.Op_Sym(A_Jcc,S_NO,hl);
  2074. ai.SetCondition(cond);
  2075. ai.is_jmp:=true;
  2076. list.concat(ai);
  2077. a_call_name(list,'FPC_OVERFLOW',false);
  2078. a_label(list,hl);
  2079. end;
  2080. procedure tcgx86.g_external_wrapper(list: TAsmList; procdef: tprocdef; const externalname: string);
  2081. var
  2082. ref : treference;
  2083. sym : tasmsymbol;
  2084. begin
  2085. if (target_info.system = system_i386_darwin) then
  2086. begin
  2087. { a_jmp_name jumps to a stub which is always pic-safe on darwin }
  2088. inherited g_external_wrapper(list,procdef,externalname);
  2089. exit;
  2090. end;
  2091. sym:=current_asmdata.RefAsmSymbol(externalname);
  2092. reference_reset_symbol(ref,sym,0,sizeof(pint));
  2093. { create pic'ed? }
  2094. if (cs_create_pic in current_settings.moduleswitches) and
  2095. { darwin/x86_64's assembler doesn't want @PLT after call symbols }
  2096. not(target_info.system in [system_x86_64_darwin,system_i386_iphonesim]) then
  2097. ref.refaddr:=addr_pic
  2098. else
  2099. ref.refaddr:=addr_full;
  2100. list.concat(taicpu.op_ref(A_JMP,S_NO,ref));
  2101. end;
  2102. end.