cgx86.pas 80 KB

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