cgcpu.pas 67 KB

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