cgx86.pas 60 KB

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