cgx86.pas 85 KB

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