cgx86.pas 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements the common parts of the code generator for the i386 and the x86-64.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. { This unit implements the common parts of the code generator for the i386 and the x86-64.
  19. }
  20. unit cgx86;
  21. {$i fpcdefs.inc}
  22. interface
  23. uses
  24. cginfo,cgbase,cgobj,
  25. aasmbase,aasmtai,aasmcpu,
  26. cpubase,cpuinfo,cpupara,
  27. node,symconst;
  28. type
  29. tcgx86 = class(tcg)
  30. { passing parameters, per default the parameter is pushed }
  31. { nr gives the number of the parameter (enumerated from }
  32. { left to right), this allows to move the parameter to }
  33. { register, if the cpu supports register calling }
  34. { conventions }
  35. procedure a_param_reg(list : taasmoutput;size : tcgsize;r : tregister;const locpara : tparalocation);override;
  36. procedure a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);override;
  37. procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);override;
  38. procedure a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);override;
  39. procedure a_call_name(list : taasmoutput;const s : string);override;
  40. procedure a_call_ref(list : taasmoutput;const ref : treference);override;
  41. procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; a: AWord; reg: TRegister); override;
  42. procedure a_op_const_ref(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; const ref: TReference); override;
  43. procedure a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  44. procedure a_op_ref_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister); override;
  45. procedure a_op_reg_ref(list : taasmoutput; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference); override;
  46. procedure a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  47. size: tcgsize; a: aword; src, dst: tregister); override;
  48. procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  49. size: tcgsize; src1, src2, dst: tregister); override;
  50. { move instructions }
  51. procedure a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);override;
  52. procedure a_load_const_ref(list : taasmoutput; size: tcgsize; a : aword;const ref : treference);override;
  53. procedure a_load_reg_ref(list : taasmoutput; size: tcgsize; reg : tregister;const ref : treference);override;
  54. procedure a_load_ref_reg(list : taasmoutput;size : tcgsize;const ref : treference;reg : tregister);override;
  55. procedure a_load_reg_reg(list : taasmoutput;size : tcgsize;reg1,reg2 : tregister);override;
  56. procedure a_load_sym_ofs_reg(list: taasmoutput; const sym: tasmsymbol; ofs: longint; reg: tregister); override;
  57. procedure a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
  58. { fpu move instructions }
  59. procedure a_loadfpu_reg_reg(list: taasmoutput; reg1, reg2: tregister); override;
  60. procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister); override;
  61. procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference); override;
  62. { vector register move instructions }
  63. procedure a_loadmm_reg_reg(list: taasmoutput; reg1, reg2: tregister); override;
  64. procedure a_loadmm_ref_reg(list: taasmoutput; const ref: treference; reg: tregister); override;
  65. procedure a_loadmm_reg_ref(list: taasmoutput; reg: tregister; const ref: treference); override;
  66. procedure a_parammm_reg(list: taasmoutput; reg: tregister); override;
  67. { comparison operations }
  68. procedure a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  69. l : tasmlabel);override;
  70. procedure a_cmp_const_ref_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;const ref : treference;
  71. l : tasmlabel);override;
  72. procedure a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  73. procedure a_cmp_ref_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;const ref: treference; reg : tregister; l : tasmlabel); override;
  74. procedure a_jmp_always(list : taasmoutput;l: tasmlabel); override;
  75. procedure a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel); override;
  76. procedure g_flags2reg(list: taasmoutput; const f: tresflags; reg: TRegister); override;
  77. procedure g_flags2ref(list: taasmoutput; const f: tresflags; const ref: TReference); override;
  78. procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);override;
  79. procedure g_push_exception(list : taasmoutput;const exceptbuf:treference;l:AWord; exceptlabel:TAsmLabel);override;
  80. procedure g_pop_exception(list : taasmoutput;endexceptlabel:tasmlabel);override;
  81. class function reg_cgsize(const reg: tregister): tcgsize; override;
  82. { entry/exit code helpers }
  83. procedure g_copyvaluepara_openarray(list : taasmoutput;const ref:treference;elesize:integer);override;
  84. procedure g_interrupt_stackframe_entry(list : taasmoutput);override;
  85. procedure g_interrupt_stackframe_exit(list : taasmoutput;selfused,accused,acchiused:boolean);override;
  86. procedure g_profilecode(list : taasmoutput);override;
  87. procedure g_stackframe_entry(list : taasmoutput;localsize : longint);override;
  88. procedure g_restore_frame_pointer(list : taasmoutput);override;
  89. procedure g_return_from_proc(list : taasmoutput;parasize : aword);override;
  90. {$ifndef TEST_GENERIC}
  91. procedure g_call_constructor_helper(list : taasmoutput);override;
  92. procedure g_call_destructor_helper(list : taasmoutput);override;
  93. procedure g_call_fail_helper(list : taasmoutput);override;
  94. {$endif}
  95. procedure g_save_standard_registers(list : taasmoutput);override;
  96. procedure g_restore_standard_registers(list : taasmoutput);override;
  97. procedure g_save_all_registers(list : taasmoutput);override;
  98. procedure g_restore_all_registers(list : taasmoutput;selfused,accused,acchiused:boolean);override;
  99. procedure g_overflowcheck(list: taasmoutput; const p: tnode);override;
  100. private
  101. procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  102. procedure sizes2load(s1 : tcgsize;s2 : topsize; var op: tasmop; var s3: topsize);
  103. procedure floatload(list: taasmoutput; t : tcgsize;const ref : treference);
  104. procedure floatstore(list: taasmoutput; t : tcgsize;const ref : treference);
  105. procedure floatloadops(t : tcgsize;var op : tasmop;var s : topsize);
  106. procedure floatstoreops(t : tcgsize;var op : tasmop;var s : topsize);
  107. end;
  108. implementation
  109. uses
  110. globtype,globals,verbose,systems,cutils,
  111. symdef,symsym,defbase,paramgr,
  112. rgobj,tgobj,rgcpu;
  113. {$ifndef NOTARGETWIN32}
  114. const
  115. winstackpagesize = 4096;
  116. TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,A_ADD,A_AND,A_DIV,
  117. A_IDIV,A_MUL, A_IMUL, A_NEG,A_NOT,A_OR,
  118. A_SAR,A_SHL,A_SHR,A_SUB,A_XOR);
  119. TOpCmp2AsmCond: Array[topcmp] of TAsmCond = (C_NONE,
  120. C_E,C_G,C_L,C_GE,C_LE,C_NE,C_BE,C_B,C_AE,C_A);
  121. TCGSize2OpSize: Array[tcgsize] of topsize =
  122. (S_NO,S_B,S_W,S_L,S_L,S_B,S_W,S_L,S_L,
  123. S_FS,S_FL,S_FX,S_IQ,
  124. S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO);
  125. {$endif NOTARGETWIN32}
  126. {****************************************************************************
  127. This is private property, keep out! :)
  128. ****************************************************************************}
  129. procedure tcgx86.sizes2load(s1 : tcgsize;s2: topsize; var op: tasmop; var s3: topsize);
  130. begin
  131. case s2 of
  132. S_B:
  133. if S1 in [OS_8,OS_S8] then
  134. s3 := S_B
  135. else internalerror(200109221);
  136. S_W:
  137. case s1 of
  138. OS_8,OS_S8:
  139. s3 := S_BW;
  140. OS_16,OS_S16:
  141. s3 := S_W;
  142. else internalerror(200109222);
  143. end;
  144. S_L:
  145. case s1 of
  146. OS_8,OS_S8:
  147. s3 := S_BL;
  148. OS_16,OS_S16:
  149. s3 := S_WL;
  150. OS_32,OS_S32:
  151. s3 := S_L;
  152. else internalerror(200109223);
  153. end;
  154. else internalerror(200109227);
  155. end;
  156. if s3 in [S_B,S_W,S_L] then
  157. op := A_MOV
  158. else if s1 in [OS_8,OS_16,OS_32] then
  159. op := A_MOVZX
  160. else
  161. op := A_MOVSX;
  162. end;
  163. procedure tcgx86.floatloadops(t : tcgsize;var op : tasmop;var s : topsize);
  164. begin
  165. case t of
  166. OS_F32 :
  167. begin
  168. op:=A_FLD;
  169. s:=S_FS;
  170. end;
  171. OS_F64 :
  172. begin
  173. op:=A_FLD;
  174. { ???? }
  175. s:=S_FL;
  176. end;
  177. OS_F80 :
  178. begin
  179. op:=A_FLD;
  180. s:=S_FX;
  181. end;
  182. OS_C64 :
  183. begin
  184. op:=A_FILD;
  185. s:=S_IQ;
  186. end;
  187. else
  188. internalerror(200204041);
  189. end;
  190. end;
  191. procedure tcgx86.floatload(list: taasmoutput; t : tcgsize;const ref : treference);
  192. var
  193. op : tasmop;
  194. s : topsize;
  195. begin
  196. floatloadops(t,op,s);
  197. list.concat(Taicpu.Op_ref(op,s,ref));
  198. inc(trgcpu(rg).fpuvaroffset);
  199. end;
  200. procedure tcgx86.floatstoreops(t : tcgsize;var op : tasmop;var s : topsize);
  201. begin
  202. case t of
  203. OS_F32 :
  204. begin
  205. op:=A_FSTP;
  206. s:=S_FS;
  207. end;
  208. OS_F64 :
  209. begin
  210. op:=A_FSTP;
  211. s:=S_FL;
  212. end;
  213. OS_F80 :
  214. begin
  215. op:=A_FSTP;
  216. s:=S_FX;
  217. end;
  218. OS_C64 :
  219. begin
  220. op:=A_FISTP;
  221. s:=S_IQ;
  222. end;
  223. else
  224. internalerror(200204042);
  225. end;
  226. end;
  227. procedure tcgx86.floatstore(list: taasmoutput; t : tcgsize;const ref : treference);
  228. var
  229. op : tasmop;
  230. s : topsize;
  231. begin
  232. floatstoreops(t,op,s);
  233. list.concat(Taicpu.Op_ref(op,s,ref));
  234. dec(trgcpu(rg).fpuvaroffset);
  235. end;
  236. {****************************************************************************
  237. Assembler code
  238. ****************************************************************************}
  239. function tcgx86.reg_cgsize(const reg: tregister): tcgsize;
  240. const
  241. regsize_2_cgsize: array[S_B..S_L] of tcgsize = (OS_8,OS_16,OS_32);
  242. begin
  243. result := regsize_2_cgsize[reg2opsize[reg]];
  244. end;
  245. { currently does nothing }
  246. procedure tcgx86.a_jmp_always(list : taasmoutput;l: tasmlabel);
  247. begin
  248. a_jmp_cond(list, OC_NONE, l);
  249. end;
  250. { we implement the following routines because otherwise we can't }
  251. { instantiate the class since it's abstract }
  252. procedure tcgx86.a_param_reg(list : taasmoutput;size : tcgsize;r : tregister;const locpara : tparalocation);
  253. begin
  254. case size of
  255. OS_8,OS_S8,
  256. OS_16,OS_S16:
  257. begin
  258. if target_info.alignment.paraalign = 2 then
  259. list.concat(taicpu.op_reg(A_PUSH,S_W,rg.makeregsize(r,OS_16)))
  260. else
  261. list.concat(taicpu.op_reg(A_PUSH,S_L,rg.makeregsize(r,OS_32)));
  262. end;
  263. OS_32,OS_S32:
  264. list.concat(taicpu.op_reg(A_PUSH,S_L,r));
  265. else
  266. internalerror(2002032212);
  267. end;
  268. end;
  269. procedure tcgx86.a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);
  270. begin
  271. case size of
  272. OS_8,OS_S8,OS_16,OS_S16:
  273. begin
  274. if target_info.alignment.paraalign = 2 then
  275. list.concat(taicpu.op_const(A_PUSH,S_W,a))
  276. else
  277. list.concat(taicpu.op_const(A_PUSH,S_L,a));
  278. end;
  279. OS_32,OS_S32:
  280. list.concat(taicpu.op_const(A_PUSH,S_L,a));
  281. else
  282. internalerror(2002032213);
  283. end;
  284. end;
  285. procedure tcgx86.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);
  286. var
  287. tmpreg: tregister;
  288. begin
  289. case size of
  290. OS_8,OS_S8,
  291. OS_16,OS_S16:
  292. begin
  293. tmpreg := get_scratch_reg_address(list);
  294. a_load_ref_reg(list,size,r,tmpreg);
  295. if target_info.alignment.paraalign = 2 then
  296. list.concat(taicpu.op_reg(A_PUSH,S_W,rg.makeregsize(tmpreg,OS_16)))
  297. else
  298. list.concat(taicpu.op_reg(A_PUSH,S_L,tmpreg));
  299. free_scratch_reg(list,tmpreg);
  300. end;
  301. OS_32,OS_S32:
  302. list.concat(taicpu.op_ref(A_PUSH,S_L,r));
  303. else
  304. internalerror(2002032214);
  305. end;
  306. end;
  307. procedure tcgx86.a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);
  308. var
  309. tmpreg: tregister;
  310. begin
  311. if r.segment<>R_NO then
  312. CGMessage(cg_e_cant_use_far_pointer_there);
  313. if (r.base=R_NO) and (r.index=R_NO) then
  314. list.concat(Taicpu.Op_sym_ofs(A_PUSH,S_L,r.symbol,r.offset))
  315. else if (r.base=R_NO) and (r.index<>R_NO) and
  316. (r.offset=0) and (r.scalefactor=0) and (r.symbol=nil) then
  317. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r.index))
  318. else if (r.base<>R_NO) and (r.index=R_NO) and
  319. (r.offset=0) and (r.symbol=nil) then
  320. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r.base))
  321. else
  322. begin
  323. tmpreg := get_scratch_reg_address(list);
  324. a_loadaddr_ref_reg(list,r,tmpreg);
  325. list.concat(taicpu.op_reg(A_PUSH,S_L,tmpreg));
  326. free_scratch_reg(list,tmpreg);
  327. end;
  328. end;
  329. procedure tcgx86.a_call_name(list : taasmoutput;const s : string);
  330. begin
  331. list.concat(taicpu.op_sym(A_CALL,S_NO,newasmsymbol(s)));
  332. end;
  333. procedure tcgx86.a_call_ref(list : taasmoutput;const ref : treference);
  334. begin
  335. list.concat(taicpu.op_ref(A_CALL,S_NO,ref));
  336. end;
  337. {********************** load instructions ********************}
  338. procedure tcgx86.a_load_const_reg(list : taasmoutput; size: TCGSize; a : aword; reg : TRegister);
  339. begin
  340. { the optimizer will change it to "xor reg,reg" when loading zero, }
  341. { no need to do it here too (JM) }
  342. list.concat(taicpu.op_const_reg(A_MOV,TCGSize2OpSize[size],a,reg))
  343. end;
  344. procedure tcgx86.a_load_const_ref(list : taasmoutput; size: tcgsize; a : aword;const ref : treference);
  345. begin
  346. {$ifdef OPTLOAD0}
  347. { zero is often used several times in succession -> load it in a }
  348. { register and then store it to memory, so the optimizer can then }
  349. { remove the unnecessary loads of registers and you get smaller }
  350. { (and faster) code }
  351. if (a = 0) and
  352. (size in [OS_32,OS_S32]) then
  353. inherited a_load_const_ref(list,size,a,ref)
  354. else
  355. {$endif OPTLOAD0}
  356. list.concat(taicpu.op_const_ref(A_MOV,TCGSize2OpSize[size],a,ref));
  357. end;
  358. procedure tcgx86.a_load_reg_ref(list : taasmoutput; size: TCGSize; reg : tregister;const ref : treference);
  359. begin
  360. list.concat(taicpu.op_reg_ref(A_MOV,TCGSize2OpSize[size],reg,
  361. ref));
  362. End;
  363. procedure tcgx86.a_load_ref_reg(list : taasmoutput;size : tcgsize;const ref: treference;reg : tregister);
  364. var
  365. op: tasmop;
  366. s: topsize;
  367. begin
  368. sizes2load(size,reg2opsize[reg],op,s);
  369. list.concat(taicpu.op_ref_reg(op,s,ref,reg));
  370. end;
  371. procedure tcgx86.a_load_reg_reg(list : taasmoutput;size : tcgsize;reg1,reg2 : tregister);
  372. var
  373. op: tasmop;
  374. s: topsize;
  375. begin
  376. sizes2load(size,reg2opsize[reg2],op,s);
  377. if (rg.makeregsize(reg1,OS_INT) = rg.makeregsize(reg2,OS_INT)) then
  378. begin
  379. { "mov reg1, reg1" doesn't make sense }
  380. if op = A_MOV then
  381. exit;
  382. { optimize movzx with "and ffff,<reg>" operation }
  383. if (op = A_MOVZX) then
  384. begin
  385. case size of
  386. OS_8:
  387. begin
  388. list.concat(taicpu.op_const_reg(A_AND,reg2opsize[reg2],255,reg2));
  389. exit;
  390. end;
  391. OS_16:
  392. begin
  393. list.concat(taicpu.op_const_reg(A_AND,reg2opsize[reg2],65535,reg2));
  394. exit;
  395. end;
  396. end;
  397. end;
  398. end;
  399. list.concat(taicpu.op_reg_reg(op,s,reg1,reg2));
  400. end;
  401. procedure tcgx86.a_load_sym_ofs_reg(list: taasmoutput; const sym: tasmsymbol; ofs: longint; reg: tregister);
  402. begin
  403. list.concat(taicpu.op_sym_ofs_reg(A_MOV,S_L,sym,ofs,reg));
  404. end;
  405. procedure tcgx86.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  406. begin
  407. if assigned(ref.symbol) and
  408. (ref.base=R_NO) and
  409. (ref.index=R_NO) then
  410. list.concat(taicpu.op_sym_ofs_reg(A_MOV,S_L,ref.symbol,ref.offset,r))
  411. else
  412. list.concat(taicpu.op_ref_reg(A_LEA,S_L,ref,r));
  413. end;
  414. { all fpu load routines expect that R_ST[0-7] means an fpu regvar and }
  415. { R_ST means "the current value at the top of the fpu stack" (JM) }
  416. procedure tcgx86.a_loadfpu_reg_reg(list: taasmoutput; reg1, reg2: tregister);
  417. begin
  418. if (reg1 <> R_ST) then
  419. begin
  420. list.concat(taicpu.op_reg(A_FLD,S_NO,
  421. trgcpu(rg).correct_fpuregister(reg1,trgcpu(rg).fpuvaroffset)));
  422. inc(trgcpu(rg).fpuvaroffset);
  423. end;
  424. if (reg2 <> R_ST) then
  425. begin
  426. list.concat(taicpu.op_reg(A_FSTP,S_NO,
  427. trgcpu(rg).correct_fpuregister(reg2,trgcpu(rg).fpuvaroffset)));
  428. dec(trgcpu(rg).fpuvaroffset);
  429. end;
  430. end;
  431. procedure tcgx86.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  432. begin
  433. floatload(list,size,ref);
  434. if (reg <> R_ST) then
  435. a_loadfpu_reg_reg(list,R_ST,reg);
  436. end;
  437. procedure tcgx86.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  438. begin
  439. if reg <> R_ST then
  440. a_loadfpu_reg_reg(list,reg,R_ST);
  441. floatstore(list,size,ref);
  442. end;
  443. procedure tcgx86.a_loadmm_reg_reg(list: taasmoutput; reg1, reg2: tregister);
  444. begin
  445. list.concat(taicpu.op_reg_reg(A_MOVQ,S_NO,reg1,reg2));
  446. end;
  447. procedure tcgx86.a_loadmm_ref_reg(list: taasmoutput; const ref: treference; reg: tregister);
  448. begin
  449. list.concat(taicpu.op_ref_reg(A_MOVQ,S_NO,ref,reg));
  450. end;
  451. procedure tcgx86.a_loadmm_reg_ref(list: taasmoutput; reg: tregister; const ref: treference);
  452. begin
  453. list.concat(taicpu.op_reg_ref(A_MOVQ,S_NO,reg,ref));
  454. end;
  455. procedure tcgx86.a_parammm_reg(list: taasmoutput; reg: tregister);
  456. var
  457. href : treference;
  458. begin
  459. list.concat(taicpu.op_const_reg(A_SUB,S_L,8,R_ESP));
  460. reference_reset_base(href,R_ESP,0);
  461. list.concat(taicpu.op_reg_ref(A_MOVQ,S_NO,reg,href));
  462. end;
  463. procedure tcgx86.a_op_const_reg(list : taasmoutput; Op: TOpCG; a: AWord; reg: TRegister);
  464. var
  465. opcode: tasmop;
  466. power: longint;
  467. begin
  468. Case Op of
  469. OP_DIV, OP_IDIV:
  470. Begin
  471. if ispowerof2(a,power) then
  472. begin
  473. case op of
  474. OP_DIV:
  475. opcode := A_SHR;
  476. OP_IDIV:
  477. opcode := A_SAR;
  478. end;
  479. list.concat(taicpu.op_const_reg(opcode,reg2opsize[reg],power,
  480. reg));
  481. exit;
  482. end;
  483. { the rest should be handled specifically in the code }
  484. { generator because of the silly register usage restraints }
  485. internalerror(200109224);
  486. End;
  487. OP_MUL,OP_IMUL:
  488. begin
  489. if not(cs_check_overflow in aktlocalswitches) and
  490. ispowerof2(a,power) then
  491. begin
  492. list.concat(taicpu.op_const_reg(A_SHL,reg2opsize[reg],power,
  493. reg));
  494. exit;
  495. end;
  496. if op = OP_IMUL then
  497. list.concat(taicpu.op_const_reg(A_IMUL,reg2opsize[reg],
  498. a,reg))
  499. else
  500. { OP_MUL should be handled specifically in the code }
  501. { generator because of the silly register usage restraints }
  502. internalerror(200109225);
  503. end;
  504. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  505. if not(cs_check_overflow in aktlocalswitches) and
  506. (a = 1) and
  507. (op in [OP_ADD,OP_SUB]) then
  508. if op = OP_ADD then
  509. list.concat(taicpu.op_reg(A_INC,reg2opsize[reg],reg))
  510. else
  511. list.concat(taicpu.op_reg(A_DEC,reg2opsize[reg],reg))
  512. else if (a = 0) then
  513. if (op <> OP_AND) then
  514. exit
  515. else
  516. list.concat(taicpu.op_const_reg(A_MOV,reg2opsize[reg],0,reg))
  517. else if (a = high(aword)) and
  518. (op in [OP_AND,OP_OR,OP_XOR]) then
  519. begin
  520. case op of
  521. OP_AND:
  522. exit;
  523. OP_OR:
  524. list.concat(taicpu.op_const_reg(A_MOV,reg2opsize[reg],high(aword),reg));
  525. OP_XOR:
  526. list.concat(taicpu.op_reg(A_NOT,reg2opsize[reg],reg));
  527. end
  528. end
  529. else
  530. list.concat(taicpu.op_const_reg(TOpCG2AsmOp[op],reg2opsize[reg],
  531. a,reg));
  532. OP_SHL,OP_SHR,OP_SAR:
  533. begin
  534. if (a and 31) <> 0 Then
  535. list.concat(taicpu.op_const_reg(
  536. TOpCG2AsmOp[op],reg2opsize[reg],a and 31,reg));
  537. if (a shr 5) <> 0 Then
  538. internalerror(68991);
  539. end
  540. else internalerror(68992);
  541. end;
  542. end;
  543. procedure tcgx86.a_op_const_ref(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; const ref: TReference);
  544. var
  545. opcode: tasmop;
  546. power: longint;
  547. begin
  548. Case Op of
  549. OP_DIV, OP_IDIV:
  550. Begin
  551. if ispowerof2(a,power) then
  552. begin
  553. case op of
  554. OP_DIV:
  555. opcode := A_SHR;
  556. OP_IDIV:
  557. opcode := A_SAR;
  558. end;
  559. list.concat(taicpu.op_const_ref(opcode,
  560. TCgSize2OpSize[size],power,ref));
  561. exit;
  562. end;
  563. { the rest should be handled specifically in the code }
  564. { generator because of the silly register usage restraints }
  565. internalerror(200109231);
  566. End;
  567. OP_MUL,OP_IMUL:
  568. begin
  569. if not(cs_check_overflow in aktlocalswitches) and
  570. ispowerof2(a,power) then
  571. begin
  572. list.concat(taicpu.op_const_ref(A_SHL,TCgSize2OpSize[size],
  573. power,ref));
  574. exit;
  575. end;
  576. { can't multiply a memory location directly with a constant }
  577. if op = OP_IMUL then
  578. inherited a_op_const_ref(list,op,size,a,ref)
  579. else
  580. { OP_MUL should be handled specifically in the code }
  581. { generator because of the silly register usage restraints }
  582. internalerror(200109232);
  583. end;
  584. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  585. if not(cs_check_overflow in aktlocalswitches) and
  586. (a = 1) and
  587. (op in [OP_ADD,OP_SUB]) then
  588. if op = OP_ADD then
  589. list.concat(taicpu.op_ref(A_INC,TCgSize2OpSize[size],ref))
  590. else
  591. list.concat(taicpu.op_ref(A_DEC,TCgSize2OpSize[size],ref))
  592. else if (a = 0) then
  593. if (op <> OP_AND) then
  594. exit
  595. else
  596. a_load_const_ref(list,size,0,ref)
  597. else if (a = high(aword)) and
  598. (op in [OP_AND,OP_OR,OP_XOR]) then
  599. begin
  600. case op of
  601. OP_AND:
  602. exit;
  603. OP_OR:
  604. list.concat(taicpu.op_const_ref(A_MOV,TCgSize2OpSize[size],high(aword),ref));
  605. OP_XOR:
  606. list.concat(taicpu.op_ref(A_NOT,TCgSize2OpSize[size],ref));
  607. end
  608. end
  609. else
  610. list.concat(taicpu.op_const_ref(TOpCG2AsmOp[op],
  611. TCgSize2OpSize[size],a,ref));
  612. OP_SHL,OP_SHR,OP_SAR:
  613. begin
  614. if (a and 31) <> 0 Then
  615. list.concat(taicpu.op_const_ref(
  616. TOpCG2AsmOp[op],TCgSize2OpSize[size],a and 31,ref));
  617. if (a shr 5) <> 0 Then
  618. internalerror(68991);
  619. end
  620. else internalerror(68992);
  621. end;
  622. end;
  623. procedure tcgx86.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  624. var
  625. regloadsize: tcgsize;
  626. dstsize: topsize;
  627. tmpreg : tregister;
  628. popecx : boolean;
  629. begin
  630. dstsize := tcgsize2opsize[size];
  631. dst := rg.makeregsize(dst,size);
  632. case op of
  633. OP_NEG,OP_NOT:
  634. begin
  635. if src <> R_NO then
  636. internalerror(200112291);
  637. list.concat(taicpu.op_reg(TOpCG2AsmOp[op],dstsize,dst));
  638. end;
  639. OP_MUL,OP_DIV,OP_IDIV:
  640. { special stuff, needs separate handling inside code }
  641. { generator }
  642. internalerror(200109233);
  643. OP_SHR,OP_SHL,OP_SAR:
  644. begin
  645. tmpreg := R_NO;
  646. popecx := false;
  647. { we need cl to hold the shift count, so if the destination }
  648. { is ecx, save it to a temp for now }
  649. if dst in [R_ECX,R_CX,R_CL] then
  650. begin
  651. case reg2opsize[dst] of
  652. S_B: regloadsize := OS_8;
  653. S_W: regloadsize := OS_16;
  654. else regloadsize := OS_32;
  655. end;
  656. tmpreg := get_scratch_reg_int(list);
  657. a_load_reg_reg(list,regloadsize,src,tmpreg);
  658. end;
  659. if not(src in [R_ECX,R_CX,R_CL]) then
  660. begin
  661. { is ecx still free (it's also free if it was allocated }
  662. { to dst, since we've moved dst somewhere else already) }
  663. if not((dst = R_ECX) or
  664. ((R_ECX in rg.unusedregsint) and
  665. { this will always be true, it's just here to }
  666. { allocate ecx }
  667. (rg.getexplicitregisterint(list,R_ECX) = R_ECX))) then
  668. begin
  669. list.concat(taicpu.op_reg(A_PUSH,S_L,R_ECX));
  670. popecx := true;
  671. end;
  672. a_load_reg_reg(list,OS_32,rg.makeregsize(src,OS_32),R_ECX);
  673. end
  674. else
  675. src := R_CL;
  676. { do the shift }
  677. if tmpreg = R_NO then
  678. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],dstsize,
  679. R_CL,dst))
  680. else
  681. begin
  682. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],S_L,
  683. R_CL,tmpreg));
  684. { move result back to the destination }
  685. a_load_reg_reg(list,OS_32,tmpreg,R_ECX);
  686. free_scratch_reg(list,tmpreg);
  687. end;
  688. if popecx then
  689. list.concat(taicpu.op_reg(A_POP,S_L,R_ECX))
  690. else if not (dst in [R_ECX,R_CX,R_CL]) then
  691. rg.ungetregisterint(list,R_ECX);
  692. end;
  693. else
  694. begin
  695. if reg2opsize[src] <> dstsize then
  696. internalerror(200109226);
  697. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],dstsize,
  698. src,dst));
  699. end;
  700. end;
  701. end;
  702. procedure tcgx86.a_op_ref_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister);
  703. begin
  704. case op of
  705. OP_NEG,OP_NOT,OP_IMUL:
  706. begin
  707. inherited a_op_ref_reg(list,op,size,ref,reg);
  708. end;
  709. OP_MUL,OP_DIV,OP_IDIV:
  710. { special stuff, needs separate handling inside code }
  711. { generator }
  712. internalerror(200109239);
  713. else
  714. begin
  715. reg := rg.makeregsize(reg,size);
  716. list.concat(taicpu.op_ref_reg(TOpCG2AsmOp[op],tcgsize2opsize[size],ref,reg));
  717. end;
  718. end;
  719. end;
  720. procedure tcgx86.a_op_reg_ref(list : taasmoutput; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference);
  721. var
  722. opsize: topsize;
  723. begin
  724. case op of
  725. OP_NEG,OP_NOT:
  726. begin
  727. if reg <> R_NO then
  728. internalerror(200109237);
  729. list.concat(taicpu.op_ref(TOpCG2AsmOp[op],tcgsize2opsize[size],ref));
  730. end;
  731. OP_IMUL:
  732. begin
  733. { this one needs a load/imul/store, which is the default }
  734. inherited a_op_ref_reg(list,op,size,ref,reg);
  735. end;
  736. OP_MUL,OP_DIV,OP_IDIV:
  737. { special stuff, needs separate handling inside code }
  738. { generator }
  739. internalerror(200109238);
  740. else
  741. begin
  742. opsize := tcgsize2opsize[size];
  743. list.concat(taicpu.op_reg_ref(TOpCG2AsmOp[op],opsize,reg,ref));
  744. end;
  745. end;
  746. end;
  747. procedure tcgx86.a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  748. size: tcgsize; a: aword; src, dst: tregister);
  749. var
  750. tmpref: treference;
  751. power: longint;
  752. opsize: topsize;
  753. begin
  754. opsize := reg2opsize[src];
  755. if (opsize <> S_L) or
  756. not (size in [OS_32,OS_S32]) then
  757. begin
  758. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  759. exit;
  760. end;
  761. { if we get here, we have to do a 32 bit calculation, guaranteed }
  762. Case Op of
  763. OP_DIV, OP_IDIV, OP_MUL, OP_AND, OP_OR, OP_XOR, OP_SHL, OP_SHR,
  764. OP_SAR:
  765. { can't do anything special for these }
  766. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  767. OP_IMUL:
  768. begin
  769. if not(cs_check_overflow in aktlocalswitches) and
  770. ispowerof2(a,power) then
  771. { can be done with a shift }
  772. begin
  773. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  774. exit;
  775. end;
  776. list.concat(taicpu.op_const_reg_reg(A_IMUL,S_L,a,src,dst));
  777. end;
  778. OP_ADD, OP_SUB:
  779. if (a = 0) then
  780. a_load_reg_reg(list,size,src,dst)
  781. else
  782. begin
  783. reference_reset(tmpref);
  784. tmpref.base := src;
  785. tmpref.offset := longint(a);
  786. if op = OP_SUB then
  787. tmpref.offset := -tmpref.offset;
  788. list.concat(taicpu.op_ref_reg(A_LEA,S_L,tmpref,dst));
  789. end
  790. else internalerror(200112302);
  791. end;
  792. end;
  793. procedure tcgx86.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  794. size: tcgsize; src1, src2, dst: tregister);
  795. var
  796. tmpref: treference;
  797. opsize: topsize;
  798. begin
  799. opsize := reg2opsize[src1];
  800. if (opsize <> S_L) or
  801. (reg2opsize[src2] <> S_L) or
  802. not (size in [OS_32,OS_S32]) then
  803. begin
  804. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  805. exit;
  806. end;
  807. { if we get here, we have to do a 32 bit calculation, guaranteed }
  808. Case Op of
  809. OP_DIV, OP_IDIV, OP_MUL, OP_AND, OP_OR, OP_XOR, OP_SHL, OP_SHR,
  810. OP_SAR,OP_SUB,OP_NOT,OP_NEG:
  811. { can't do anything special for these }
  812. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  813. OP_IMUL:
  814. list.concat(taicpu.op_reg_reg_reg(A_IMUL,S_L,src1,src2,dst));
  815. OP_ADD:
  816. begin
  817. reference_reset(tmpref);
  818. tmpref.base := src1;
  819. tmpref.index := src2;
  820. tmpref.scalefactor := 1;
  821. list.concat(taicpu.op_ref_reg(A_LEA,S_L,tmpref,dst));
  822. end
  823. else internalerror(200112303);
  824. end;
  825. end;
  826. {*************** compare instructructions ****************}
  827. procedure tcgx86.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  828. l : tasmlabel);
  829. begin
  830. if (a = 0) then
  831. list.concat(taicpu.op_reg_reg(A_TEST,reg2opsize[reg],reg,reg))
  832. else
  833. list.concat(taicpu.op_const_reg(A_CMP,reg2opsize[reg],a,reg));
  834. a_jmp_cond(list,cmp_op,l);
  835. end;
  836. procedure tcgx86.a_cmp_const_ref_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;const ref : treference;
  837. l : tasmlabel);
  838. begin
  839. list.concat(taicpu.op_const_ref(A_CMP,TCgSize2OpSize[size],a,ref));
  840. a_jmp_cond(list,cmp_op,l);
  841. end;
  842. procedure tcgx86.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;
  843. reg1,reg2 : tregister;l : tasmlabel);
  844. begin
  845. if reg2opsize[reg1] <> reg2opsize[reg2] then
  846. internalerror(200109226);
  847. list.concat(taicpu.op_reg_reg(A_CMP,reg2opsize[reg1],reg1,reg2));
  848. a_jmp_cond(list,cmp_op,l);
  849. end;
  850. procedure tcgx86.a_cmp_ref_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;const ref: treference; reg : tregister;l : tasmlabel);
  851. begin
  852. reg := rg.makeregsize(reg,size);
  853. list.concat(taicpu.op_ref_reg(A_CMP,tcgsize2opsize[size],ref,reg));
  854. a_jmp_cond(list,cmp_op,l);
  855. end;
  856. procedure tcgx86.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  857. var
  858. ai : taicpu;
  859. begin
  860. if cond=OC_None then
  861. ai := Taicpu.Op_sym(A_JMP,S_NO,l)
  862. else
  863. begin
  864. ai:=Taicpu.Op_sym(A_Jcc,S_NO,l);
  865. ai.SetCondition(TOpCmp2AsmCond[cond]);
  866. end;
  867. ai.is_jmp:=true;
  868. list.concat(ai);
  869. end;
  870. procedure tcgx86.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  871. var
  872. ai : taicpu;
  873. begin
  874. ai := Taicpu.op_sym(A_Jcc,S_NO,l);
  875. ai.SetCondition(flags_to_cond(f));
  876. ai.is_jmp := true;
  877. list.concat(ai);
  878. end;
  879. procedure tcgx86.g_flags2reg(list: taasmoutput; const f: tresflags; reg: TRegister);
  880. var
  881. ai : taicpu;
  882. hreg : tregister;
  883. begin
  884. hreg := rg.makeregsize(reg,OS_8);
  885. ai:=Taicpu.Op_reg(A_Setcc,S_B,hreg);
  886. ai.SetCondition(flags_to_cond(f));
  887. list.concat(ai);
  888. if hreg<>reg then
  889. a_load_reg_reg(list,OS_8,hreg,reg);
  890. end;
  891. procedure tcgx86.g_flags2ref(list: taasmoutput; const f: tresflags; const ref: TReference);
  892. var
  893. ai : taicpu;
  894. begin
  895. ai:=Taicpu.Op_ref(A_Setcc,S_B,ref);
  896. ai.SetCondition(flags_to_cond(f));
  897. list.concat(ai);
  898. end;
  899. { ************* concatcopy ************ }
  900. procedure tcgx86.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);
  901. var
  902. ecxpushed : boolean;
  903. helpsize : longint;
  904. i : byte;
  905. reg8,reg32 : tregister;
  906. srcref,dstref : treference;
  907. swap : boolean;
  908. procedure maybepushecx;
  909. begin
  910. if not(R_ECX in rg.unusedregsint) then
  911. begin
  912. list.concat(Taicpu.Op_reg(A_PUSH,S_L,R_ECX));
  913. ecxpushed:=true;
  914. end
  915. else rg.getexplicitregisterint(list,R_ECX);
  916. end;
  917. begin
  918. if (not loadref) and
  919. ((len<=8) or
  920. (not(cs_littlesize in aktglobalswitches ) and (len<=12))) then
  921. begin
  922. helpsize:=len shr 2;
  923. rg.getexplicitregisterint(list,R_EDI);
  924. dstref:=dest;
  925. srcref:=source;
  926. for i:=1 to helpsize do
  927. begin
  928. a_load_ref_reg(list,OS_32,srcref,R_EDI);
  929. If (len = 4) and delsource then
  930. reference_release(list,source);
  931. a_load_reg_ref(list,OS_32,R_EDI,dstref);
  932. inc(srcref.offset,4);
  933. inc(dstref.offset,4);
  934. dec(len,4);
  935. end;
  936. if len>1 then
  937. begin
  938. a_load_ref_reg(list,OS_16,srcref,R_DI);
  939. If (len = 2) and delsource then
  940. reference_release(list,source);
  941. a_load_reg_ref(list,OS_16,R_DI,dstref);
  942. inc(srcref.offset,2);
  943. inc(dstref.offset,2);
  944. dec(len,2);
  945. end;
  946. rg.ungetregisterint(list,R_EDI);
  947. if len>0 then
  948. begin
  949. { and now look for an 8 bit register }
  950. swap:=false;
  951. if R_EAX in rg.unusedregsint then reg8:=rg.makeregsize(rg.getexplicitregisterint(list,R_EAX),OS_8)
  952. else if R_EDX in rg.unusedregsint then reg8:=rg.makeregsize(rg.getexplicitregisterint(list,R_EDX),OS_8)
  953. else if R_EBX in rg.unusedregsint then reg8:=rg.makeregsize(rg.getexplicitregisterint(list,R_EBX),OS_8)
  954. else if R_ECX in rg.unusedregsint then reg8:=rg.makeregsize(rg.getexplicitregisterint(list,R_ECX),OS_8)
  955. else
  956. begin
  957. swap:=true;
  958. { we need only to check 3 registers, because }
  959. { one is always not index or base }
  960. if (dest.base<>R_EAX) and (dest.index<>R_EAX) then
  961. begin
  962. reg8:=R_AL;
  963. reg32:=R_EAX;
  964. end
  965. else if (dest.base<>R_EBX) and (dest.index<>R_EBX) then
  966. begin
  967. reg8:=R_BL;
  968. reg32:=R_EBX;
  969. end
  970. else if (dest.base<>R_ECX) and (dest.index<>R_ECX) then
  971. begin
  972. reg8:=R_CL;
  973. reg32:=R_ECX;
  974. end;
  975. end;
  976. if swap then
  977. { was earlier XCHG, of course nonsense }
  978. begin
  979. rg.getexplicitregisterint(list,R_EDI);
  980. a_load_reg_reg(list,OS_32,reg32,R_EDI);
  981. end;
  982. a_load_ref_reg(list,OS_8,srcref,reg8);
  983. If delsource and (len=1) then
  984. reference_release(list,source);
  985. a_load_reg_ref(list,OS_8,reg8,dstref);
  986. if swap then
  987. begin
  988. a_load_reg_reg(list,OS_32,R_EDI,reg32);
  989. rg.ungetregisterint(list,R_EDI);
  990. end
  991. else
  992. rg.ungetregister(list,reg8);
  993. end;
  994. end
  995. else
  996. begin
  997. rg.getexplicitregisterint(list,R_EDI);
  998. a_loadaddr_ref_reg(list,dest,R_EDI);
  999. list.concat(tai_regalloc.Alloc(R_ESI));
  1000. if loadref then
  1001. a_load_ref_reg(list,OS_ADDR,source,R_ESI)
  1002. else
  1003. begin
  1004. a_loadaddr_ref_reg(list,source,R_ESI);
  1005. if delsource then
  1006. reference_release(list,source);
  1007. end;
  1008. list.concat(Taicpu.Op_none(A_CLD,S_NO));
  1009. ecxpushed:=false;
  1010. if cs_littlesize in aktglobalswitches then
  1011. begin
  1012. maybepushecx;
  1013. a_load_const_reg(list,OS_INT,len,R_ECX);
  1014. list.concat(Taicpu.Op_none(A_REP,S_NO));
  1015. list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1016. end
  1017. else
  1018. begin
  1019. helpsize:=len shr 2;
  1020. len:=len and 3;
  1021. if helpsize>1 then
  1022. begin
  1023. maybepushecx;
  1024. a_load_const_reg(list,OS_INT,helpsize,R_ECX);
  1025. list.concat(Taicpu.Op_none(A_REP,S_NO));
  1026. end;
  1027. if helpsize>0 then
  1028. list.concat(Taicpu.Op_none(A_MOVSD,S_NO));
  1029. if len>1 then
  1030. begin
  1031. dec(len,2);
  1032. list.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  1033. end;
  1034. if len=1 then
  1035. list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1036. end;
  1037. rg.ungetregisterint(list,R_EDI);
  1038. list.concat(tai_regalloc.DeAlloc(R_ESI));
  1039. if ecxpushed then
  1040. list.concat(Taicpu.Op_reg(A_POP,S_L,R_ECX))
  1041. else
  1042. rg.ungetregisterint(list,R_ECX);
  1043. { loading SELF-reference again }
  1044. g_maybe_loadself(list);
  1045. end;
  1046. if delsource then
  1047. tg.ungetiftemp(list,source);
  1048. end;
  1049. procedure tcgx86.g_push_exception(list : taasmoutput;const exceptbuf:treference;l:AWord; exceptlabel:TAsmLabel);
  1050. var
  1051. tempaddr,tempbuf : treference;
  1052. begin
  1053. tempaddr:=exceptbuf;
  1054. tempbuf:=exceptbuf;
  1055. inc(tempbuf.offset,12);
  1056. a_paramaddr_ref(list,tempaddr,paramanager.getintparaloc(3));
  1057. a_paramaddr_ref(list,tempbuf,paramanager.getintparaloc(2));
  1058. a_param_const(list,OS_INT,l,paramanager.getintparaloc(1));
  1059. a_call_name(list,'FPC_PUSHEXCEPTADDR');
  1060. a_reg_alloc(list,accumulator);
  1061. a_param_reg(list,OS_ADDR,accumulator,paramanager.getintparaloc(1));
  1062. a_reg_dealloc(list,accumulator);
  1063. a_call_name(list,'FPC_SETJMP');
  1064. list.concat(tai_regalloc.Alloc(accumulator));
  1065. list.concat(Taicpu.op_reg(A_PUSH,S_L,accumulator));
  1066. list.concat(tai_regalloc.DeAlloc(accumulator));
  1067. a_cmp_const_reg_label(list,OS_ADDR,OC_NE,0,accumulator,exceptlabel);
  1068. end;
  1069. procedure tcgx86.g_pop_exception(list : taasmoutput;endexceptlabel:tasmlabel);
  1070. begin
  1071. a_call_name(list,'FPC_POPADDRSTACK');
  1072. a_reg_alloc(list,accumulator);
  1073. list.concat(Taicpu.op_reg(A_POP,S_L,accumulator));
  1074. a_reg_dealloc(list,accumulator);
  1075. a_cmp_const_reg_label(list,OS_ADDR,OC_EQ,0,accumulator,endexceptlabel);
  1076. end;
  1077. {****************************************************************************
  1078. Entry/Exit Code Helpers
  1079. ****************************************************************************}
  1080. procedure tcgx86.g_copyvaluepara_openarray(list : taasmoutput;const ref:treference;elesize:integer);
  1081. var
  1082. lenref : treference;
  1083. power,len : longint;
  1084. opsize : topsize;
  1085. {$ifndef __NOWINPECOFF__}
  1086. again,ok : tasmlabel;
  1087. {$endif}
  1088. begin
  1089. lenref:=ref;
  1090. inc(lenref.offset,4);
  1091. { get stack space }
  1092. rg.getexplicitregisterint(list,R_EDI);
  1093. list.concat(Taicpu.op_ref_reg(A_MOV,S_L,lenref,R_EDI));
  1094. list.concat(Taicpu.op_reg(A_INC,S_L,R_EDI));
  1095. if (elesize<>1) then
  1096. begin
  1097. if ispowerof2(elesize, power) then
  1098. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,R_EDI))
  1099. else
  1100. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,elesize,R_EDI));
  1101. end;
  1102. {$ifndef __NOWINPECOFF__}
  1103. { windows guards only a few pages for stack growing, }
  1104. { so we have to access every page first }
  1105. if target_info.target=target_i386_win32 then
  1106. begin
  1107. getlabel(again);
  1108. getlabel(ok);
  1109. a_label(list,again);
  1110. list.concat(Taicpu.op_const_reg(A_CMP,S_L,winstackpagesize,R_EDI));
  1111. a_jmp_cond(list,OC_B,ok);
  1112. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,R_ESP));
  1113. list.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  1114. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize,R_EDI));
  1115. a_jmp_always(list,again);
  1116. a_label(list,ok);
  1117. list.concat(Taicpu.op_reg_reg(A_SUB,S_L,R_EDI,R_ESP));
  1118. rg.ungetregisterint(list,R_EDI);
  1119. { now reload EDI }
  1120. rg.getexplicitregisterint(list,R_EDI);
  1121. list.concat(Taicpu.op_ref_reg(A_MOV,S_L,lenref,R_EDI));
  1122. list.concat(Taicpu.op_reg(A_INC,S_L,R_EDI));
  1123. if (elesize<>1) then
  1124. begin
  1125. if ispowerof2(elesize, power) then
  1126. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,R_EDI))
  1127. else
  1128. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,elesize,R_EDI));
  1129. end;
  1130. end
  1131. else
  1132. {$endif __NOWINPECOFF__}
  1133. list.concat(Taicpu.op_reg_reg(A_SUB,S_L,R_EDI,R_ESP));
  1134. { load destination }
  1135. list.concat(Taicpu.op_reg_reg(A_MOV,S_L,R_ESP,R_EDI));
  1136. { don't destroy the registers! }
  1137. list.concat(Taicpu.op_reg(A_PUSH,S_L,R_ECX));
  1138. list.concat(Taicpu.op_reg(A_PUSH,S_L,R_ESI));
  1139. { load count }
  1140. list.concat(Taicpu.op_ref_reg(A_MOV,S_L,lenref,R_ECX));
  1141. { load source }
  1142. list.concat(Taicpu.op_ref_reg(A_MOV,S_L,ref,R_ESI));
  1143. { scheduled .... }
  1144. list.concat(Taicpu.op_reg(A_INC,S_L,R_ECX));
  1145. { calculate size }
  1146. len:=elesize;
  1147. opsize:=S_B;
  1148. if (len and 3)=0 then
  1149. begin
  1150. opsize:=S_L;
  1151. len:=len shr 2;
  1152. end
  1153. else
  1154. if (len and 1)=0 then
  1155. begin
  1156. opsize:=S_W;
  1157. len:=len shr 1;
  1158. end;
  1159. if ispowerof2(len, power) then
  1160. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,R_ECX))
  1161. else
  1162. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,len,R_ECX));
  1163. list.concat(Taicpu.op_none(A_REP,S_NO));
  1164. case opsize of
  1165. S_B : list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1166. S_W : list.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  1167. S_L : list.concat(Taicpu.Op_none(A_MOVSD,S_NO));
  1168. end;
  1169. rg.ungetregisterint(list,R_EDI);
  1170. list.concat(Taicpu.op_reg(A_POP,S_L,R_ESI));
  1171. list.concat(Taicpu.op_reg(A_POP,S_L,R_ECX));
  1172. { patch the new address }
  1173. list.concat(Taicpu.op_reg_ref(A_MOV,S_L,R_ESP,ref));
  1174. end;
  1175. procedure tcgx86.g_interrupt_stackframe_entry(list : taasmoutput);
  1176. begin
  1177. { .... also the segment registers }
  1178. list.concat(Taicpu.Op_reg(A_PUSH,S_W,R_GS));
  1179. list.concat(Taicpu.Op_reg(A_PUSH,S_W,R_FS));
  1180. list.concat(Taicpu.Op_reg(A_PUSH,S_W,R_ES));
  1181. list.concat(Taicpu.Op_reg(A_PUSH,S_W,R_DS));
  1182. { save the registers of an interrupt procedure }
  1183. list.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  1184. list.concat(Taicpu.Op_reg(A_PUSH,S_L,R_ESI));
  1185. list.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDX));
  1186. list.concat(Taicpu.Op_reg(A_PUSH,S_L,R_ECX));
  1187. list.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EBX));
  1188. list.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EAX));
  1189. end;
  1190. procedure tcgx86.g_interrupt_stackframe_exit(list : taasmoutput;selfused,accused,acchiused:boolean);
  1191. begin
  1192. if accused then
  1193. list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,R_ESP))
  1194. else
  1195. list.concat(Taicpu.Op_reg(A_POP,S_L,R_EAX));
  1196. list.concat(Taicpu.Op_reg(A_POP,S_L,R_EBX));
  1197. list.concat(Taicpu.Op_reg(A_POP,S_L,R_ECX));
  1198. if acchiused then
  1199. list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,R_ESP))
  1200. else
  1201. list.concat(Taicpu.Op_reg(A_POP,S_L,R_EDX));
  1202. if selfused then
  1203. list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,R_ESP))
  1204. else
  1205. list.concat(Taicpu.Op_reg(A_POP,S_L,R_ESI));
  1206. list.concat(Taicpu.Op_reg(A_POP,S_L,R_EDI));
  1207. { .... also the segment registers }
  1208. list.concat(Taicpu.Op_reg(A_POP,S_W,R_DS));
  1209. list.concat(Taicpu.Op_reg(A_POP,S_W,R_ES));
  1210. list.concat(Taicpu.Op_reg(A_POP,S_W,R_FS));
  1211. list.concat(Taicpu.Op_reg(A_POP,S_W,R_GS));
  1212. { this restores the flags }
  1213. list.concat(Taicpu.Op_none(A_IRET,S_NO));
  1214. end;
  1215. procedure tcgx86.g_profilecode(list : taasmoutput);
  1216. var
  1217. pl : tasmlabel;
  1218. begin
  1219. case target_info.target of
  1220. target_i386_win32,
  1221. target_i386_freebsd,
  1222. target_i386_wdosx,
  1223. target_i386_linux:
  1224. begin
  1225. getaddrlabel(pl);
  1226. list.concat(Tai_section.Create(sec_data));
  1227. list.concat(Tai_align.Create(4));
  1228. list.concat(Tai_label.Create(pl));
  1229. list.concat(Tai_const.Create_32bit(0));
  1230. list.concat(Tai_section.Create(sec_code));
  1231. list.concat(Taicpu.Op_sym_ofs_reg(A_MOV,S_L,pl,0,R_EDX));
  1232. a_call_name(list,target_info.Cprefix+'mcount');
  1233. include(rg.usedinproc,R_EDX);
  1234. end;
  1235. target_i386_go32v2:
  1236. begin
  1237. a_call_name(list,'MCOUNT');
  1238. end;
  1239. end;
  1240. end;
  1241. procedure tcgx86.g_stackframe_entry(list : taasmoutput;localsize : longint);
  1242. var
  1243. href : treference;
  1244. i : integer;
  1245. again : tasmlabel;
  1246. begin
  1247. list.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EBP));
  1248. list.concat(Taicpu.Op_reg_reg(A_MOV,S_L,R_ESP,R_EBP));
  1249. if localsize>0 then
  1250. begin
  1251. {$ifndef NOTARGETWIN32}
  1252. { windows guards only a few pages for stack growing, }
  1253. { so we have to access every page first }
  1254. if (target_info.target=target_i386_win32) and
  1255. (localsize>=winstackpagesize) then
  1256. begin
  1257. if localsize div winstackpagesize<=5 then
  1258. begin
  1259. list.concat(Taicpu.Op_const_reg(A_SUB,S_L,localsize-4,R_ESP));
  1260. for i:=1 to localsize div winstackpagesize do
  1261. begin
  1262. reference_reset_base(href,R_ESP,localsize-i*winstackpagesize);
  1263. list.concat(Taicpu.op_const_ref(A_MOV,S_L,0,href));
  1264. end;
  1265. list.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  1266. end
  1267. else
  1268. begin
  1269. getlabel(again);
  1270. rg.getexplicitregisterint(list,R_EDI);
  1271. list.concat(Taicpu.op_const_reg(A_MOV,S_L,localsize div winstackpagesize,R_EDI));
  1272. a_label(list,again);
  1273. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,R_ESP));
  1274. list.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  1275. list.concat(Taicpu.op_reg(A_DEC,S_L,R_EDI));
  1276. a_jmp_cond(list,OC_NE,again);
  1277. rg.ungetregisterint(list,R_EDI);
  1278. list.concat(Taicpu.op_const_reg(A_SUB,S_L,localsize mod winstackpagesize,R_ESP));
  1279. end
  1280. end
  1281. else
  1282. {$endif NOTARGETWIN32}
  1283. list.concat(Taicpu.Op_const_reg(A_SUB,S_L,localsize,R_ESP));
  1284. end;
  1285. end;
  1286. procedure tcgx86.g_restore_frame_pointer(list : taasmoutput);
  1287. begin
  1288. list.concat(Taicpu.Op_none(A_LEAVE,S_NO));
  1289. end;
  1290. procedure tcgx86.g_return_from_proc(list : taasmoutput;parasize : aword);
  1291. begin
  1292. { Routines with the poclearstack flag set use only a ret }
  1293. { also routines with parasize=0 }
  1294. if (po_clearstack in aktprocdef.procoptions) then
  1295. begin
  1296. { complex return values are removed from stack in C code PM }
  1297. if paramanager.ret_in_param(aktprocdef.rettype.def) then
  1298. list.concat(Taicpu.Op_const(A_RET,S_NO,4))
  1299. else
  1300. list.concat(Taicpu.Op_none(A_RET,S_NO));
  1301. end
  1302. else if (parasize=0) then
  1303. list.concat(Taicpu.Op_none(A_RET,S_NO))
  1304. else
  1305. begin
  1306. { parameters are limited to 65535 bytes because }
  1307. { ret allows only imm16 }
  1308. if (parasize>65535) then
  1309. CGMessage(cg_e_parasize_too_big);
  1310. list.concat(Taicpu.Op_const(A_RET,S_NO,parasize));
  1311. end;
  1312. end;
  1313. {$ifndef TEST_GENERIC}
  1314. procedure tcgx86.g_call_constructor_helper(list : taasmoutput);
  1315. begin
  1316. if is_class(procinfo^._class) then
  1317. begin
  1318. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1319. a_call_name(list,'FPC_NEW_CLASS');
  1320. list.concat(Taicpu.Op_cond_sym(A_Jcc,C_Z,S_NO,faillabel));
  1321. end
  1322. else if is_object(procinfo^._class) then
  1323. begin
  1324. rg.getexplicitregisterint(list,R_EDI);
  1325. a_load_const_reg(list,OS_ADDR,procinfo^._class.vmt_offset,R_EDI);
  1326. a_call_name(list,'FPC_HELP_CONSTRUCTOR');
  1327. list.concat(Taicpu.Op_cond_sym(A_Jcc,C_Z,S_NO,faillabel));
  1328. end
  1329. else
  1330. internalerror(200006161);
  1331. end;
  1332. procedure tcgx86.g_call_destructor_helper(list : taasmoutput);
  1333. var
  1334. nofinal : tasmlabel;
  1335. href : treference;
  1336. begin
  1337. if is_class(procinfo^._class) then
  1338. begin
  1339. a_call_name(list,'FPC_DISPOSE_CLASS')
  1340. end
  1341. else if is_object(procinfo^._class) then
  1342. begin
  1343. { must the object be finalized ? }
  1344. if procinfo^._class.needs_inittable then
  1345. begin
  1346. getlabel(nofinal);
  1347. reference_reset_base(href,R_EBP,8);
  1348. a_cmp_const_ref_label(list,OS_ADDR,OC_EQ,0,href,nofinal);
  1349. reference_reset_base(href,R_ESI,0);
  1350. g_finalize(list,procinfo^._class,href,false);
  1351. a_label(list,nofinal);
  1352. end;
  1353. rg.getexplicitregisterint(list,R_EDI);
  1354. a_load_const_reg(list,OS_ADDR,procinfo^._class.vmt_offset,R_EDI);
  1355. rg.ungetregisterint(list,R_EDI);
  1356. a_call_name(list,'FPC_HELP_DESTRUCTOR')
  1357. end
  1358. else
  1359. internalerror(200006162);
  1360. end;
  1361. procedure tcgx86.g_call_fail_helper(list : taasmoutput);
  1362. var
  1363. href : treference;
  1364. begin
  1365. if is_class(procinfo^._class) then
  1366. begin
  1367. reference_reset_base(href,procinfo^.framepointer,8);
  1368. a_load_ref_reg(list,OS_ADDR,href,R_ESI);
  1369. a_call_name(list,'FPC_HELP_FAIL_CLASS');
  1370. end
  1371. else if is_object(procinfo^._class) then
  1372. begin
  1373. reference_reset_base(href,procinfo^.framepointer,12);
  1374. a_load_ref_reg(list,OS_ADDR,href,R_ESI);
  1375. rg.getexplicitregisterint(list,R_EDI);
  1376. a_load_const_reg(list,OS_ADDR,procinfo^._class.vmt_offset,R_EDI);
  1377. a_call_name(list,'FPC_HELP_FAIL');
  1378. rg.ungetregisterint(list,R_EDI);
  1379. end
  1380. else
  1381. internalerror(200006163);
  1382. end;
  1383. {$endif}
  1384. procedure tcgx86.g_save_standard_registers(list : taasmoutput);
  1385. begin
  1386. if (R_EBX in aktprocdef.usedregisters) then
  1387. list.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EBX));
  1388. list.concat(Taicpu.Op_reg(A_PUSH,S_L,R_ESI));
  1389. list.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  1390. end;
  1391. procedure tcgx86.g_restore_standard_registers(list : taasmoutput);
  1392. begin
  1393. list.concat(Taicpu.Op_reg(A_POP,S_L,R_EDI));
  1394. list.concat(Taicpu.Op_reg(A_POP,S_L,R_ESI));
  1395. if (R_EBX in aktprocdef.usedregisters) then
  1396. list.concat(Taicpu.Op_reg(A_POP,S_L,R_EBX));
  1397. end;
  1398. procedure tcgx86.g_save_all_registers(list : taasmoutput);
  1399. begin
  1400. list.concat(Taicpu.Op_none(A_PUSHA,S_L));
  1401. end;
  1402. procedure tcgx86.g_restore_all_registers(list : taasmoutput;selfused,accused,acchiused:boolean);
  1403. var
  1404. href : treference;
  1405. begin
  1406. if selfused then
  1407. begin
  1408. reference_reset_base(href,R_ESP,4);
  1409. list.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_ESI,href));
  1410. end;
  1411. if acchiused then
  1412. begin
  1413. reference_reset_base(href,R_ESP,20);
  1414. list.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDX,href));
  1415. end;
  1416. if accused then
  1417. begin
  1418. reference_reset_base(href,R_ESP,28);
  1419. list.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EAX,href));
  1420. end;
  1421. list.concat(Taicpu.Op_none(A_POPA,S_L));
  1422. { We add a NOP because of the 386DX CPU bugs with POPAD }
  1423. list.concat(taicpu.op_none(A_NOP,S_L));
  1424. end;
  1425. { produces if necessary overflowcode }
  1426. procedure tcgx86.g_overflowcheck(list: taasmoutput; const p: tnode);
  1427. var
  1428. hl : tasmlabel;
  1429. ai : taicpu;
  1430. cond : TAsmCond;
  1431. begin
  1432. if not(cs_check_overflow in aktlocalswitches) then
  1433. exit;
  1434. getlabel(hl);
  1435. if not ((p.resulttype.def.deftype=pointerdef) or
  1436. ((p.resulttype.def.deftype=orddef) and
  1437. (torddef(p.resulttype.def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,
  1438. bool8bit,bool16bit,bool32bit]))) then
  1439. cond:=C_NO
  1440. else
  1441. cond:=C_NB;
  1442. ai:=Taicpu.Op_Sym(A_Jcc,S_NO,hl);
  1443. ai.SetCondition(cond);
  1444. ai.is_jmp:=true;
  1445. list.concat(ai);
  1446. a_call_name(list,'FPC_OVERFLOW');
  1447. a_label(list,hl);
  1448. end;
  1449. end.
  1450. {
  1451. $Log$
  1452. Revision 1.2 2002-07-21 16:55:34 jonas
  1453. * fixed bug in op_const_reg_reg() for imul
  1454. Revision 1.1 2002/07/20 19:28:47 florian
  1455. * splitting of i386\cgcpu.pas into x86\cgx86.pas and i386\cgcpu.pas
  1456. cgx86.pas will contain the common code for i386 and x86_64
  1457. }