cgx86.pas 79 KB

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