cgx86.pas 84 KB

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