cgx86.pas 84 KB

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