cgx86.pas 84 KB

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