cgcpu.pas 67 KB

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