cgx86.pas 88 KB

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