cgx86.pas 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements the common parts of the code generator for the i386 and the x86-64.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. { This unit implements the common parts of the code generator for the i386 and the x86-64.
  19. }
  20. unit cgx86;
  21. {$i fpcdefs.inc}
  22. interface
  23. uses
  24. cginfo,cgbase,cgobj,
  25. aasmbase,aasmtai,aasmcpu,
  26. cpubase,cpuinfo,cpupara,
  27. node,symconst;
  28. type
  29. tcgx86 = class(tcg)
  30. { passing parameters, per default the parameter is pushed }
  31. { nr gives the number of the parameter (enumerated from }
  32. { left to right), this allows to move the parameter to }
  33. { register, if the cpu supports register calling }
  34. { conventions }
  35. procedure a_param_reg(list : taasmoutput;size : tcgsize;r : tregister;const locpara : tparalocation);override;
  36. procedure a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);override;
  37. procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);override;
  38. procedure a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);override;
  39. procedure a_call_name(list : taasmoutput;const s : string);override;
  40. procedure a_call_ref(list : taasmoutput;const ref : treference);override;
  41. procedure a_call_reg(list : taasmoutput;reg : tregister);override;
  42. procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; a: AWord; reg: TRegister); override;
  43. procedure a_op_const_ref(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; const ref: TReference); override;
  44. procedure a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  45. procedure a_op_ref_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister); override;
  46. procedure a_op_reg_ref(list : taasmoutput; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference); override;
  47. procedure a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  48. size: tcgsize; a: aword; src, dst: tregister); override;
  49. procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  50. size: tcgsize; src1, src2, dst: tregister); override;
  51. { move instructions }
  52. procedure a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);override;
  53. procedure a_load_const_ref(list : taasmoutput; size: tcgsize; a : aword;const ref : treference);override;
  54. procedure a_load_reg_ref(list : taasmoutput; size: tcgsize; reg : tregister;const ref : treference);override;
  55. procedure a_load_ref_reg(list : taasmoutput;size : tcgsize;const ref : treference;reg : tregister);override;
  56. procedure a_load_reg_reg(list : taasmoutput;fromsize,tosize : tcgsize;reg1,reg2 : tregister);override;
  57. procedure a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
  58. { fpu move instructions }
  59. procedure a_loadfpu_reg_reg(list: taasmoutput; reg1, reg2: tregister); override;
  60. procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister); override;
  61. procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference); override;
  62. { vector register move instructions }
  63. procedure a_loadmm_reg_reg(list: taasmoutput; reg1, reg2: tregister); override;
  64. procedure a_loadmm_ref_reg(list: taasmoutput; const ref: treference; reg: tregister); override;
  65. procedure a_loadmm_reg_ref(list: taasmoutput; reg: tregister; const ref: treference); override;
  66. procedure a_parammm_reg(list: taasmoutput; reg: tregister); override;
  67. { comparison operations }
  68. procedure a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  69. l : tasmlabel);override;
  70. procedure a_cmp_const_ref_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;const ref : treference;
  71. l : tasmlabel);override;
  72. procedure a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  73. procedure a_cmp_ref_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;const ref: treference; reg : tregister; l : tasmlabel); override;
  74. procedure a_jmp_always(list : taasmoutput;l: tasmlabel); override;
  75. procedure a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel); override;
  76. procedure g_flags2reg(list: taasmoutput; size: TCgSize; const f: tresflags; reg: TRegister); override;
  77. procedure g_flags2ref(list: taasmoutput; size: TCgSize; const f: tresflags; const ref: TReference); override;
  78. procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);override;
  79. procedure g_exception_reason_save(list : taasmoutput; const href : treference);override;
  80. procedure g_exception_reason_save_const(list : taasmoutput; const href : treference; a: aword);override;
  81. procedure g_exception_reason_load(list : taasmoutput; const href : treference);override;
  82. class function reg_cgsize(const reg: tregister): tcgsize; override;
  83. { entry/exit code helpers }
  84. procedure g_copyvaluepara_openarray(list : taasmoutput;const ref:treference;elesize:integer);override;
  85. procedure g_removevaluepara_openarray(list : taasmoutput;const ref:treference;elesize:integer);override;
  86. procedure g_interrupt_stackframe_entry(list : taasmoutput);override;
  87. procedure g_interrupt_stackframe_exit(list : taasmoutput;selfused,accused,acchiused:boolean);override;
  88. procedure g_profilecode(list : taasmoutput);override;
  89. procedure g_stackpointer_alloc(list : taasmoutput;localsize : longint);override;
  90. procedure g_stackframe_entry(list : taasmoutput;localsize : longint);override;
  91. procedure g_restore_frame_pointer(list : taasmoutput);override;
  92. procedure g_return_from_proc(list : taasmoutput;parasize : aword);override;
  93. {$ifndef TEST_GENERIC}
  94. procedure g_call_constructor_helper(list : taasmoutput);override;
  95. procedure g_call_destructor_helper(list : taasmoutput);override;
  96. procedure g_call_fail_helper(list : taasmoutput);override;
  97. {$endif}
  98. procedure g_save_standard_registers(list:Taasmoutput;usedinproc:Tsupregset);override;
  99. procedure g_restore_standard_registers(list:Taasmoutput;usedinproc:Tsupregset);override;
  100. procedure g_save_all_registers(list : taasmoutput);override;
  101. procedure g_restore_all_registers(list : taasmoutput;selfused,accused,acchiused:boolean);override;
  102. procedure g_overflowcheck(list: taasmoutput; const p: tnode);override;
  103. private
  104. procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  105. procedure sizes2load(s1 : tcgsize;s2 : topsize; var op: tasmop; var s3: topsize);
  106. procedure floatload(list: taasmoutput; t : tcgsize;const ref : treference);
  107. procedure floatstore(list: taasmoutput; t : tcgsize;const ref : treference);
  108. procedure floatloadops(t : tcgsize;var op : tasmop;var s : topsize);
  109. procedure floatstoreops(t : tcgsize;var op : tasmop;var s : topsize);
  110. end;
  111. const
  112. TCGSize2OpSize: Array[tcgsize] of topsize =
  113. (S_NO,S_B,S_W,S_L,S_L,S_B,S_W,S_L,S_L,
  114. S_FS,S_FL,S_FX,S_IQ,S_FXX,
  115. S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO);
  116. implementation
  117. uses
  118. globtype,globals,verbose,systems,cutils,
  119. symdef,symsym,defutil,paramgr,
  120. rgobj,tgobj,rgcpu;
  121. {$ifndef NOTARGETWIN32}
  122. const
  123. winstackpagesize = 4096;
  124. {$endif NOTARGETWIN32}
  125. TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,A_ADD,A_AND,A_DIV,
  126. A_IDIV,A_MUL, A_IMUL, A_NEG,A_NOT,A_OR,
  127. A_SAR,A_SHL,A_SHR,A_SUB,A_XOR);
  128. TOpCmp2AsmCond: Array[topcmp] of TAsmCond = (C_NONE,
  129. C_E,C_G,C_L,C_GE,C_LE,C_NE,C_BE,C_B,C_AE,C_A);
  130. {****************************************************************************
  131. This is private property, keep out! :)
  132. ****************************************************************************}
  133. procedure tcgx86.sizes2load(s1 : tcgsize;s2: topsize; var op: tasmop; var s3: topsize);
  134. begin
  135. case s2 of
  136. S_B:
  137. if S1 in [OS_8,OS_S8] then
  138. s3 := S_B
  139. else internalerror(200109221);
  140. S_W:
  141. case s1 of
  142. OS_8,OS_S8:
  143. s3 := S_BW;
  144. OS_16,OS_S16:
  145. s3 := S_W;
  146. else internalerror(200109222);
  147. end;
  148. S_L:
  149. case s1 of
  150. OS_8,OS_S8:
  151. s3 := S_BL;
  152. OS_16,OS_S16:
  153. s3 := S_WL;
  154. OS_32,OS_S32:
  155. s3 := S_L;
  156. else internalerror(200109223);
  157. end;
  158. else internalerror(200109227);
  159. end;
  160. if s3 in [S_B,S_W,S_L] then
  161. op := A_MOV
  162. else if s1 in [OS_8,OS_16,OS_32] then
  163. op := A_MOVZX
  164. else
  165. op := A_MOVSX;
  166. end;
  167. procedure tcgx86.floatloadops(t : tcgsize;var op : tasmop;var s : topsize);
  168. begin
  169. case t of
  170. OS_F32 :
  171. begin
  172. op:=A_FLD;
  173. s:=S_FS;
  174. end;
  175. OS_F64 :
  176. begin
  177. op:=A_FLD;
  178. { ???? }
  179. s:=S_FL;
  180. end;
  181. OS_F80 :
  182. begin
  183. op:=A_FLD;
  184. s:=S_FX;
  185. end;
  186. OS_C64 :
  187. begin
  188. op:=A_FILD;
  189. s:=S_IQ;
  190. end;
  191. else
  192. internalerror(200204041);
  193. end;
  194. end;
  195. procedure tcgx86.floatload(list: taasmoutput; t : tcgsize;const ref : treference);
  196. var
  197. op : tasmop;
  198. s : topsize;
  199. begin
  200. floatloadops(t,op,s);
  201. list.concat(Taicpu.Op_ref(op,s,ref));
  202. inc(trgcpu(rg).fpuvaroffset);
  203. end;
  204. procedure tcgx86.floatstoreops(t : tcgsize;var op : tasmop;var s : topsize);
  205. begin
  206. case t of
  207. OS_F32 :
  208. begin
  209. op:=A_FSTP;
  210. s:=S_FS;
  211. end;
  212. OS_F64 :
  213. begin
  214. op:=A_FSTP;
  215. s:=S_FL;
  216. end;
  217. OS_F80 :
  218. begin
  219. op:=A_FSTP;
  220. s:=S_FX;
  221. end;
  222. OS_C64 :
  223. begin
  224. op:=A_FISTP;
  225. s:=S_IQ;
  226. end;
  227. else
  228. internalerror(200204042);
  229. end;
  230. end;
  231. procedure tcgx86.floatstore(list: taasmoutput; t : tcgsize;const ref : treference);
  232. var
  233. op : tasmop;
  234. s : topsize;
  235. begin
  236. floatstoreops(t,op,s);
  237. list.concat(Taicpu.Op_ref(op,s,ref));
  238. dec(trgcpu(rg).fpuvaroffset);
  239. end;
  240. {****************************************************************************
  241. Assembler code
  242. ****************************************************************************}
  243. class function tcgx86.reg_cgsize(const reg: tregister): tcgsize;
  244. const
  245. regsize_2_cgsize: array[S_B..S_L] of tcgsize = (OS_8,OS_16,OS_32);
  246. begin
  247. if reg.enum>lastreg then
  248. internalerror(200301081);
  249. if (reg.enum = R_INTREGISTER) then
  250. result := regsize_2_cgsize[subreg2opsize[reg.number and $ff]];
  251. end;
  252. { currently does nothing }
  253. procedure tcgx86.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 tcgx86.a_param_reg(list : taasmoutput;size : tcgsize;r : tregister;const locpara : tparalocation);
  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. r.number:=(r.number and not $ff) or R_SUBW
  267. else
  268. r.number:=(r.number and not $ff) or R_SUBD;
  269. list.concat(taicpu.op_reg(A_PUSH,S_L,r));
  270. end;
  271. OS_32,OS_S32:
  272. begin
  273. if r.number and $ff<>R_SUBD then
  274. internalerror(7843);
  275. list.concat(taicpu.op_reg(A_PUSH,S_L,r));
  276. end
  277. else
  278. internalerror(2002032212);
  279. end;
  280. end;
  281. procedure tcgx86.a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);
  282. begin
  283. case size of
  284. OS_8,OS_S8,OS_16,OS_S16:
  285. begin
  286. if target_info.alignment.paraalign = 2 then
  287. list.concat(taicpu.op_const(A_PUSH,S_W,a))
  288. else
  289. list.concat(taicpu.op_const(A_PUSH,S_L,a));
  290. end;
  291. OS_32,OS_S32:
  292. list.concat(taicpu.op_const(A_PUSH,S_L,a));
  293. else
  294. internalerror(2002032213);
  295. end;
  296. end;
  297. procedure tcgx86.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);
  298. var
  299. tmpreg: tregister;
  300. begin
  301. case size of
  302. OS_8,OS_S8,
  303. OS_16,OS_S16:
  304. begin
  305. if target_info.alignment.paraalign = 2 then
  306. tmpreg:=get_scratch_reg_int(list,OS_16)
  307. else
  308. tmpreg:=get_scratch_reg_int(list,OS_32);
  309. a_load_ref_reg(list,size,r,tmpreg);
  310. list.concat(taicpu.op_reg(A_PUSH,S_L,tmpreg));
  311. free_scratch_reg(list,tmpreg);
  312. end;
  313. OS_32,OS_S32:
  314. list.concat(taicpu.op_ref(A_PUSH,S_L,r));
  315. else
  316. internalerror(2002032214);
  317. end;
  318. end;
  319. procedure tcgx86.a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);
  320. var
  321. tmpreg: tregister;
  322. baseno,indexno:boolean;
  323. begin
  324. if not((r.segment.enum=R_NO) or ((r.segment.enum=R_INTREGISTER) and (r.segment.number=NR_NO))) then
  325. CGMessage(cg_e_cant_use_far_pointer_there);
  326. baseno:=(r.base.enum=R_NO) or ((r.base.enum=R_INTREGISTER) and (r.base.number=NR_NO));
  327. indexno:=(r.index.enum=R_NO) or ((r.index.enum=R_INTREGISTER) and (r.index.number=NR_NO));
  328. if baseno and indexno then
  329. begin
  330. if assigned(r.symbol) then
  331. list.concat(Taicpu.Op_sym_ofs(A_PUSH,S_L,r.symbol,r.offset))
  332. else
  333. list.concat(Taicpu.Op_const(A_PUSH,S_L,r.offset));
  334. end
  335. else if baseno and not indexno and
  336. (r.offset=0) and (r.scalefactor=0) and (r.symbol=nil) then
  337. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r.index))
  338. else if not baseno and indexno and
  339. (r.offset=0) and (r.symbol=nil) then
  340. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r.base))
  341. else
  342. begin
  343. tmpreg := get_scratch_reg_address(list);
  344. a_loadaddr_ref_reg(list,r,tmpreg);
  345. list.concat(taicpu.op_reg(A_PUSH,S_L,tmpreg));
  346. free_scratch_reg(list,tmpreg);
  347. end;
  348. end;
  349. procedure tcgx86.a_call_name(list : taasmoutput;const s : string);
  350. begin
  351. list.concat(taicpu.op_sym(A_CALL,S_NO,objectlibrary.newasmsymbol(s)));
  352. end;
  353. procedure tcgx86.a_call_ref(list : taasmoutput;const ref : treference);
  354. begin
  355. list.concat(taicpu.op_ref(A_CALL,S_NO,ref));
  356. end;
  357. procedure tcgx86.a_call_reg(list : taasmoutput;reg : tregister);
  358. begin
  359. list.concat(taicpu.op_reg(A_CALL,S_NO,reg));
  360. end;
  361. {********************** load instructions ********************}
  362. procedure tcgx86.a_load_const_reg(list : taasmoutput; size: TCGSize; a : aword; reg : TRegister);
  363. begin
  364. { the optimizer will change it to "xor reg,reg" when loading zero, }
  365. { no need to do it here too (JM) }
  366. list.concat(taicpu.op_const_reg(A_MOV,TCGSize2OpSize[size],a,reg))
  367. end;
  368. procedure tcgx86.a_load_const_ref(list : taasmoutput; size: tcgsize; a : aword;const ref : treference);
  369. begin
  370. list.concat(taicpu.op_const_ref(A_MOV,TCGSize2OpSize[size],a,ref));
  371. end;
  372. procedure tcgx86.a_load_reg_ref(list : taasmoutput; size: TCGSize; reg : tregister;const ref : treference);
  373. begin
  374. list.concat(taicpu.op_reg_ref(A_MOV,TCGSize2OpSize[size],reg,
  375. ref));
  376. end;
  377. procedure tcgx86.a_load_ref_reg(list : taasmoutput;size : tcgsize;const ref: treference;reg : tregister);
  378. var
  379. op: tasmop;
  380. o,s: topsize;
  381. begin
  382. if reg.enum<>R_INTREGISTER then
  383. internalerror(200302058);
  384. o:=subreg2opsize[reg.number and $ff];
  385. sizes2load(size,o,op,s);
  386. list.concat(taicpu.op_ref_reg(op,s,ref,reg));
  387. end;
  388. procedure tcgx86.a_load_reg_reg(list : taasmoutput;fromsize,tosize : tcgsize;reg1,reg2 : tregister);
  389. var
  390. op: tasmop;
  391. s: topsize;
  392. eq:boolean;
  393. begin
  394. if (reg1.enum=R_INTREGISTER) and (reg2.enum=R_INTREGISTER) then
  395. begin
  396. sizes2load(fromsize,subreg2opsize[reg2.number and $ff],op,s);
  397. eq:=(reg1.number shr 8)=(reg2.number shr 8);
  398. end
  399. else
  400. internalerror(200301081);
  401. if eq then
  402. begin
  403. { "mov reg1, reg1" doesn't make sense }
  404. if op = A_MOV then
  405. exit;
  406. { optimize movzx with "and ffff,<reg>" operation }
  407. if (op = A_MOVZX) then
  408. begin
  409. case fromsize of
  410. OS_8:
  411. begin
  412. list.concat(taicpu.op_const_reg(A_AND,subreg2opsize[reg2.number and $ff],255,reg2));
  413. exit;
  414. end;
  415. OS_16:
  416. begin
  417. list.concat(taicpu.op_const_reg(A_AND,subreg2opsize[reg2.number and $ff],65535,reg2));
  418. exit;
  419. end;
  420. end;
  421. end;
  422. end;
  423. list.concat(taicpu.op_reg_reg(op,s,reg1,reg2));
  424. end;
  425. procedure tcgx86.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  426. begin
  427. if ref.base.enum<>R_INTREGISTER then
  428. internalerror(200302102);
  429. if ref.index.enum<>R_INTREGISTER then
  430. internalerror(200302102);
  431. if assigned(ref.symbol) and
  432. (ref.base.number=NR_NO) and
  433. (ref.index.number=NR_NO) then
  434. list.concat(taicpu.op_sym_ofs_reg(A_MOV,S_L,ref.symbol,ref.offset,r))
  435. else
  436. list.concat(taicpu.op_ref_reg(A_LEA,S_L,ref,r));
  437. end;
  438. { all fpu load routines expect that R_ST[0-7] means an fpu regvar and }
  439. { R_ST means "the current value at the top of the fpu stack" (JM) }
  440. procedure tcgx86.a_loadfpu_reg_reg(list: taasmoutput; reg1, reg2: tregister);
  441. begin
  442. if (reg1.enum <> R_ST) then
  443. begin
  444. list.concat(taicpu.op_reg(A_FLD,S_NO,
  445. trgcpu(rg).correct_fpuregister(reg1,trgcpu(rg).fpuvaroffset)));
  446. inc(trgcpu(rg).fpuvaroffset);
  447. end;
  448. if (reg2.enum <> R_ST) then
  449. begin
  450. list.concat(taicpu.op_reg(A_FSTP,S_NO,
  451. trgcpu(rg).correct_fpuregister(reg2,trgcpu(rg).fpuvaroffset)));
  452. dec(trgcpu(rg).fpuvaroffset);
  453. end;
  454. end;
  455. procedure tcgx86.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  456. var rst:Tregister;
  457. begin
  458. rst.enum:=R_ST;
  459. floatload(list,size,ref);
  460. if reg.enum>lastreg then
  461. internalerror(200301081);
  462. if (reg.enum <> R_ST) then
  463. a_loadfpu_reg_reg(list,rst,reg);
  464. end;
  465. procedure tcgx86.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  466. var rst:Tregister;
  467. begin
  468. rst.enum:=R_ST;
  469. if reg.enum>lastreg then
  470. internalerror(200301081);
  471. if reg.enum <> R_ST then
  472. a_loadfpu_reg_reg(list,reg,rst);
  473. floatstore(list,size,ref);
  474. end;
  475. procedure tcgx86.a_loadmm_reg_reg(list: taasmoutput; reg1, reg2: tregister);
  476. begin
  477. list.concat(taicpu.op_reg_reg(A_MOVQ,S_NO,reg1,reg2));
  478. end;
  479. procedure tcgx86.a_loadmm_ref_reg(list: taasmoutput; const ref: treference; reg: tregister);
  480. begin
  481. list.concat(taicpu.op_ref_reg(A_MOVQ,S_NO,ref,reg));
  482. end;
  483. procedure tcgx86.a_loadmm_reg_ref(list: taasmoutput; reg: tregister; const ref: treference);
  484. begin
  485. list.concat(taicpu.op_reg_ref(A_MOVQ,S_NO,reg,ref));
  486. end;
  487. procedure tcgx86.a_parammm_reg(list: taasmoutput; reg: tregister);
  488. var
  489. href : treference;
  490. r : Tregister;
  491. begin
  492. r.enum:=R_INTREGISTER;
  493. r.number:=NR_ESP;
  494. list.concat(taicpu.op_const_reg(A_SUB,S_L,8,r));
  495. reference_reset_base(href,r,0);
  496. list.concat(taicpu.op_reg_ref(A_MOVQ,S_NO,reg,href));
  497. end;
  498. procedure tcgx86.a_op_const_reg(list : taasmoutput; Op: TOpCG; a: AWord; reg: TRegister);
  499. var
  500. opcode: tasmop;
  501. power: longint;
  502. begin
  503. if reg.enum<>R_INTREGISTER then
  504. internalerror(200302034);
  505. case op of
  506. OP_DIV, OP_IDIV:
  507. begin
  508. if ispowerof2(a,power) then
  509. begin
  510. case op of
  511. OP_DIV:
  512. opcode := A_SHR;
  513. OP_IDIV:
  514. opcode := A_SAR;
  515. end;
  516. list.concat(taicpu.op_const_reg(opcode,subreg2opsize[reg.number and $ff],
  517. power,reg));
  518. exit;
  519. end;
  520. { the rest should be handled specifically in the code }
  521. { generator because of the silly register usage restraints }
  522. internalerror(200109224);
  523. end;
  524. OP_MUL,OP_IMUL:
  525. begin
  526. if not(cs_check_overflow in aktlocalswitches) and
  527. ispowerof2(a,power) then
  528. begin
  529. list.concat(taicpu.op_const_reg(A_SHL,subreg2opsize[reg.number and $ff],
  530. power,reg));
  531. exit;
  532. end;
  533. if op = OP_IMUL then
  534. list.concat(taicpu.op_const_reg(A_IMUL,subreg2opsize[reg.number and $ff],
  535. a,reg))
  536. else
  537. { OP_MUL should be handled specifically in the code }
  538. { generator because of the silly register usage restraints }
  539. internalerror(200109225);
  540. end;
  541. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  542. if not(cs_check_overflow in aktlocalswitches) and
  543. (a = 1) and
  544. (op in [OP_ADD,OP_SUB]) then
  545. if op = OP_ADD then
  546. list.concat(taicpu.op_reg(A_INC,subreg2opsize[reg.number and $ff],reg))
  547. else
  548. list.concat(taicpu.op_reg(A_DEC,subreg2opsize[reg.number and $ff],reg))
  549. else if (a = 0) then
  550. if (op <> OP_AND) then
  551. exit
  552. else
  553. list.concat(taicpu.op_const_reg(A_MOV,subreg2opsize[reg.number and $ff],0,reg))
  554. else if (a = high(aword)) and
  555. (op in [OP_AND,OP_OR,OP_XOR]) then
  556. begin
  557. case op of
  558. OP_AND:
  559. exit;
  560. OP_OR:
  561. list.concat(taicpu.op_const_reg(A_MOV,subreg2opsize[reg.number and $ff],high(aword),reg));
  562. OP_XOR:
  563. list.concat(taicpu.op_reg(A_NOT,subreg2opsize[reg.number and $ff],reg));
  564. end
  565. end
  566. else
  567. list.concat(taicpu.op_const_reg(TOpCG2AsmOp[op],subreg2opsize[reg.number and $ff],
  568. a,reg));
  569. OP_SHL,OP_SHR,OP_SAR:
  570. begin
  571. if (a and 31) <> 0 Then
  572. list.concat(taicpu.op_const_reg(
  573. TOpCG2AsmOp[op],subreg2opsize[reg.number and $ff],a and 31,reg));
  574. if (a shr 5) <> 0 Then
  575. internalerror(68991);
  576. end
  577. else internalerror(68992);
  578. end;
  579. end;
  580. procedure tcgx86.a_op_const_ref(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; const ref: TReference);
  581. var
  582. opcode: tasmop;
  583. power: longint;
  584. begin
  585. Case Op of
  586. OP_DIV, OP_IDIV:
  587. Begin
  588. if ispowerof2(a,power) then
  589. begin
  590. case op of
  591. OP_DIV:
  592. opcode := A_SHR;
  593. OP_IDIV:
  594. opcode := A_SAR;
  595. end;
  596. list.concat(taicpu.op_const_ref(opcode,
  597. TCgSize2OpSize[size],power,ref));
  598. exit;
  599. end;
  600. { the rest should be handled specifically in the code }
  601. { generator because of the silly register usage restraints }
  602. internalerror(200109231);
  603. End;
  604. OP_MUL,OP_IMUL:
  605. begin
  606. if not(cs_check_overflow in aktlocalswitches) and
  607. ispowerof2(a,power) then
  608. begin
  609. list.concat(taicpu.op_const_ref(A_SHL,TCgSize2OpSize[size],
  610. power,ref));
  611. exit;
  612. end;
  613. { can't multiply a memory location directly with a constant }
  614. if op = OP_IMUL then
  615. inherited a_op_const_ref(list,op,size,a,ref)
  616. else
  617. { OP_MUL should be handled specifically in the code }
  618. { generator because of the silly register usage restraints }
  619. internalerror(200109232);
  620. end;
  621. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  622. if not(cs_check_overflow in aktlocalswitches) and
  623. (a = 1) and
  624. (op in [OP_ADD,OP_SUB]) then
  625. if op = OP_ADD then
  626. list.concat(taicpu.op_ref(A_INC,TCgSize2OpSize[size],ref))
  627. else
  628. list.concat(taicpu.op_ref(A_DEC,TCgSize2OpSize[size],ref))
  629. else if (a = 0) then
  630. if (op <> OP_AND) then
  631. exit
  632. else
  633. a_load_const_ref(list,size,0,ref)
  634. else if (a = high(aword)) and
  635. (op in [OP_AND,OP_OR,OP_XOR]) then
  636. begin
  637. case op of
  638. OP_AND:
  639. exit;
  640. OP_OR:
  641. list.concat(taicpu.op_const_ref(A_MOV,TCgSize2OpSize[size],high(aword),ref));
  642. OP_XOR:
  643. list.concat(taicpu.op_ref(A_NOT,TCgSize2OpSize[size],ref));
  644. end
  645. end
  646. else
  647. list.concat(taicpu.op_const_ref(TOpCG2AsmOp[op],
  648. TCgSize2OpSize[size],a,ref));
  649. OP_SHL,OP_SHR,OP_SAR:
  650. begin
  651. if (a and 31) <> 0 then
  652. list.concat(taicpu.op_const_ref(
  653. TOpCG2AsmOp[op],TCgSize2OpSize[size],a and 31,ref));
  654. if (a shr 5) <> 0 Then
  655. internalerror(68991);
  656. end
  657. else internalerror(68992);
  658. end;
  659. end;
  660. procedure tcgx86.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  661. var
  662. regloadsize: tcgsize;
  663. dstsize: topsize;
  664. tmpreg : tregister;
  665. popecx : boolean;
  666. r:Tregister;
  667. begin
  668. if src.enum<>R_INTREGISTER then
  669. internalerror(200302025);
  670. if dst.enum<>R_INTREGISTER then
  671. internalerror(200302025);
  672. r.enum:=R_INTREGISTER;
  673. dstsize := tcgsize2opsize[size];
  674. dst.number:=(dst.number and not $ff) or cgsize2subreg(size);
  675. case op of
  676. OP_NEG,OP_NOT:
  677. begin
  678. if src.number <> NR_NO then
  679. internalerror(200112291);
  680. list.concat(taicpu.op_reg(TOpCG2AsmOp[op],dstsize,dst));
  681. end;
  682. OP_MUL,OP_DIV,OP_IDIV:
  683. { special stuff, needs separate handling inside code }
  684. { generator }
  685. internalerror(200109233);
  686. OP_SHR,OP_SHL,OP_SAR:
  687. begin
  688. tmpreg.enum:=R_INTREGISTER;
  689. tmpreg.number:=NR_NO;
  690. popecx := false;
  691. { we need cl to hold the shift count, so if the destination }
  692. { is ecx, save it to a temp for now }
  693. if dst.number shr 8=RS_ECX then
  694. begin
  695. case dst.number and $ff of
  696. R_SUBL,R_SUBH:
  697. regloadsize:=OS_8;
  698. R_SUBW:
  699. regloadsize:=OS_16;
  700. else
  701. regloadsize:=OS_32;
  702. end;
  703. tmpreg := get_scratch_reg_int(list,OS_INT);
  704. tmpreg.enum:=R_INTREGISTER;
  705. tmpreg.number:=NR_EDI;
  706. a_load_reg_reg(list,regloadsize,regloadsize,src,tmpreg);
  707. end;
  708. if src.number shr 8<>RS_ECX then
  709. begin
  710. { is ecx still free (it's also free if it was allocated }
  711. { to dst, since we've moved dst somewhere else already) }
  712. r.number:=NR_ECX;
  713. if not((dst.number shr 8=RS_ECX) or
  714. ((RS_ECX in rg.unusedregsint) and
  715. { this will always be true, it's just here to }
  716. { allocate ecx }
  717. (rg.getexplicitregisterint(list,NR_ECX).number = NR_ECX))) then
  718. begin
  719. list.concat(taicpu.op_reg(A_PUSH,S_L,r));
  720. popecx := true;
  721. end;
  722. a_load_reg_reg(list,OS_32,OS_32,rg.makeregsize(src,OS_32),r);
  723. end
  724. else
  725. src.number := NR_CL;
  726. { do the shift }
  727. r.number:=NR_CL;
  728. if tmpreg.number = NR_NO then
  729. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],dstsize,
  730. r,dst))
  731. else
  732. begin
  733. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],S_L,
  734. r,tmpreg));
  735. { move result back to the destination }
  736. r.number:=NR_ECX;
  737. a_load_reg_reg(list,OS_32,OS_32,tmpreg,r);
  738. free_scratch_reg(list,tmpreg);
  739. end;
  740. r.number:=NR_ECX;
  741. if popecx then
  742. list.concat(taicpu.op_reg(A_POP,S_L,r))
  743. else if not (dst.number shr 8=RS_ECX) then
  744. rg.ungetregisterint(list,r);
  745. end;
  746. else
  747. begin
  748. if subreg2opsize[src.number and $ff] <> dstsize then
  749. internalerror(200109226);
  750. list.concat(taicpu.op_reg_reg(TOpCG2AsmOp[op],dstsize,
  751. src,dst));
  752. end;
  753. end;
  754. end;
  755. procedure tcgx86.a_op_ref_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister);
  756. begin
  757. case op of
  758. OP_NEG,OP_NOT,OP_IMUL:
  759. begin
  760. inherited a_op_ref_reg(list,op,size,ref,reg);
  761. end;
  762. OP_MUL,OP_DIV,OP_IDIV:
  763. { special stuff, needs separate handling inside code }
  764. { generator }
  765. internalerror(200109239);
  766. else
  767. begin
  768. reg := rg.makeregsize(reg,size);
  769. list.concat(taicpu.op_ref_reg(TOpCG2AsmOp[op],tcgsize2opsize[size],ref,reg));
  770. end;
  771. end;
  772. end;
  773. procedure tcgx86.a_op_reg_ref(list : taasmoutput; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference);
  774. var
  775. opsize: topsize;
  776. begin
  777. if reg.enum<>R_INTREGISTER then
  778. internalerror(200302036);
  779. case op of
  780. OP_NEG,OP_NOT:
  781. begin
  782. if reg.number<>NR_NO then
  783. internalerror(200109237);
  784. list.concat(taicpu.op_ref(TOpCG2AsmOp[op],tcgsize2opsize[size],ref));
  785. end;
  786. OP_IMUL:
  787. begin
  788. { this one needs a load/imul/store, which is the default }
  789. inherited a_op_ref_reg(list,op,size,ref,reg);
  790. end;
  791. OP_MUL,OP_DIV,OP_IDIV:
  792. { special stuff, needs separate handling inside code }
  793. { generator }
  794. internalerror(200109238);
  795. else
  796. begin
  797. opsize := tcgsize2opsize[size];
  798. list.concat(taicpu.op_reg_ref(TOpCG2AsmOp[op],opsize,reg,ref));
  799. end;
  800. end;
  801. end;
  802. procedure tcgx86.a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  803. size: tcgsize; a: aword; src, dst: tregister);
  804. var
  805. tmpref: treference;
  806. power: longint;
  807. opsize: topsize;
  808. begin
  809. if src.enum<>R_INTREGISTER then
  810. internalerror(200302057);
  811. if dst.enum<>R_INTREGISTER then
  812. internalerror(200302057);
  813. opsize := subreg2opsize[src.number and $ff];
  814. if (opsize <> S_L) or
  815. not (size in [OS_32,OS_S32]) then
  816. begin
  817. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  818. exit;
  819. end;
  820. { if we get here, we have to do a 32 bit calculation, guaranteed }
  821. case op of
  822. OP_DIV, OP_IDIV, OP_MUL, OP_AND, OP_OR, OP_XOR, OP_SHL, OP_SHR,
  823. OP_SAR:
  824. { can't do anything special for these }
  825. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  826. OP_IMUL:
  827. begin
  828. if not(cs_check_overflow in aktlocalswitches) and
  829. ispowerof2(a,power) then
  830. { can be done with a shift }
  831. begin
  832. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  833. exit;
  834. end;
  835. list.concat(taicpu.op_const_reg_reg(A_IMUL,S_L,a,src,dst));
  836. end;
  837. OP_ADD, OP_SUB:
  838. if (a = 0) then
  839. a_load_reg_reg(list,size,size,src,dst)
  840. else
  841. begin
  842. reference_reset(tmpref);
  843. tmpref.base := src;
  844. tmpref.offset := longint(a);
  845. if op = OP_SUB then
  846. tmpref.offset := -tmpref.offset;
  847. list.concat(taicpu.op_ref_reg(A_LEA,S_L,tmpref,dst));
  848. end
  849. else internalerror(200112302);
  850. end;
  851. end;
  852. procedure tcgx86.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  853. size: tcgsize; src1, src2, dst: tregister);
  854. var
  855. tmpref: treference;
  856. opsize: topsize;
  857. begin
  858. if src1.enum>lastreg then
  859. internalerror(200201081);
  860. if src2.enum>lastreg then
  861. internalerror(200201081);
  862. if dst.enum>lastreg then
  863. internalerror(200201081);
  864. opsize := subreg2opsize[src1.number and $ff];
  865. if (opsize <> S_L) or
  866. (subreg2opsize[src2.number and $ff] <> S_L) or
  867. not (size in [OS_32,OS_S32]) then
  868. begin
  869. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  870. exit;
  871. end;
  872. { if we get here, we have to do a 32 bit calculation, guaranteed }
  873. Case Op of
  874. OP_DIV, OP_IDIV, OP_MUL, OP_AND, OP_OR, OP_XOR, OP_SHL, OP_SHR,
  875. OP_SAR,OP_SUB,OP_NOT,OP_NEG:
  876. { can't do anything special for these }
  877. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  878. OP_IMUL:
  879. list.concat(taicpu.op_reg_reg_reg(A_IMUL,S_L,src1,src2,dst));
  880. OP_ADD:
  881. begin
  882. reference_reset(tmpref);
  883. tmpref.base := src1;
  884. tmpref.index := src2;
  885. tmpref.scalefactor := 1;
  886. list.concat(taicpu.op_ref_reg(A_LEA,S_L,tmpref,dst));
  887. end
  888. else internalerror(200112303);
  889. end;
  890. end;
  891. {*************** compare instructructions ****************}
  892. procedure tcgx86.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  893. l : tasmlabel);
  894. begin
  895. if reg.enum=R_INTREGISTER then
  896. begin
  897. if (a = 0) then
  898. list.concat(taicpu.op_reg_reg(A_TEST,subreg2opsize[reg.number and $ff],reg,reg))
  899. else
  900. list.concat(taicpu.op_const_reg(A_CMP,subreg2opsize[reg.number and $ff],a,reg));
  901. end
  902. else
  903. internalerror(200303131);
  904. a_jmp_cond(list,cmp_op,l);
  905. end;
  906. procedure tcgx86.a_cmp_const_ref_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;const ref : treference;
  907. l : tasmlabel);
  908. begin
  909. list.concat(taicpu.op_const_ref(A_CMP,TCgSize2OpSize[size],a,ref));
  910. a_jmp_cond(list,cmp_op,l);
  911. end;
  912. procedure tcgx86.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;
  913. reg1,reg2 : tregister;l : tasmlabel);
  914. begin
  915. if reg1.enum<>R_INTREGISTER then
  916. internalerror(200101081);
  917. if reg2.enum<>R_INTREGISTER then
  918. internalerror(200101081);
  919. if subreg2opsize[reg1.number and $ff] <> subreg2opsize[reg2.number and $ff] then
  920. internalerror(200109226);
  921. list.concat(taicpu.op_reg_reg(A_CMP,subreg2opsize[reg1.number and $ff],reg1,reg2));
  922. a_jmp_cond(list,cmp_op,l);
  923. end;
  924. procedure tcgx86.a_cmp_ref_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;const ref: treference; reg : tregister;l : tasmlabel);
  925. begin
  926. if reg.enum<>R_INTREGISTER then
  927. internalerror(200302059);
  928. reg.number:=(reg.number and not $ff) or cgsize2subreg(size);
  929. list.concat(taicpu.op_ref_reg(A_CMP,tcgsize2opsize[size],ref,reg));
  930. a_jmp_cond(list,cmp_op,l);
  931. end;
  932. procedure tcgx86.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  933. var
  934. ai : taicpu;
  935. begin
  936. if cond=OC_None then
  937. ai := Taicpu.Op_sym(A_JMP,S_NO,l)
  938. else
  939. begin
  940. ai:=Taicpu.Op_sym(A_Jcc,S_NO,l);
  941. ai.SetCondition(TOpCmp2AsmCond[cond]);
  942. end;
  943. ai.is_jmp:=true;
  944. list.concat(ai);
  945. end;
  946. procedure tcgx86.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  947. var
  948. ai : taicpu;
  949. begin
  950. ai := Taicpu.op_sym(A_Jcc,S_NO,l);
  951. ai.SetCondition(flags_to_cond(f));
  952. ai.is_jmp := true;
  953. list.concat(ai);
  954. end;
  955. procedure tcgx86.g_flags2reg(list: taasmoutput; size: TCgSize; const f: tresflags; reg: TRegister);
  956. var
  957. ai : taicpu;
  958. hreg : tregister;
  959. begin
  960. if reg.enum<>R_INTREGISTER then
  961. internalerror(200202031);
  962. hreg.enum:=R_INTREGISTER;
  963. hreg.number:=(reg.number and not $ff) or R_SUBL;
  964. ai:=Taicpu.op_reg(A_SETcc,S_B,hreg);
  965. ai.setcondition(flags_to_cond(f));
  966. list.concat(ai);
  967. if (reg.number <> hreg.number) then
  968. a_load_reg_reg(list,OS_8,size,hreg,reg);
  969. end;
  970. procedure tcgx86.g_flags2ref(list: taasmoutput; size: TCgSize; const f: tresflags; const ref: TReference);
  971. var
  972. ai : taicpu;
  973. begin
  974. if not(size in [OS_8,OS_S8]) then
  975. a_load_const_ref(list,size,0,ref);
  976. ai:=Taicpu.op_ref(A_SETcc,S_B,ref);
  977. ai.setcondition(flags_to_cond(f));
  978. list.concat(ai);
  979. end;
  980. { ************* concatcopy ************ }
  981. procedure tcgx86.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);
  982. var
  983. ecxpushed : boolean;
  984. helpsize : longint;
  985. i : byte;
  986. reg8,reg32 : tregister;
  987. srcref,dstref : treference;
  988. swap : boolean;
  989. r : Tregister;
  990. procedure maybepushecx;
  991. var r:Tregister;
  992. begin
  993. r.enum:=R_INTREGISTER;
  994. r.number:=NR_ECX;
  995. if not(RS_ECX in rg.unusedregsint) then
  996. begin
  997. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r));
  998. ecxpushed:=true;
  999. end
  1000. else rg.getexplicitregisterint(list,NR_ECX);
  1001. end;
  1002. begin
  1003. if (not loadref) and
  1004. ((len<=8) or
  1005. (not(cs_littlesize in aktglobalswitches ) and (len<=12))) then
  1006. begin
  1007. r.enum:=R_INTREGISTER;
  1008. helpsize:=len shr 2;
  1009. dstref:=dest;
  1010. srcref:=source;
  1011. for i:=1 to helpsize do
  1012. begin
  1013. rg.getexplicitregisterint(list,NR_EDI);
  1014. r.number:=NR_EDI;
  1015. a_load_ref_reg(list,OS_32,srcref,r);
  1016. If (len = 4) and delsource then
  1017. reference_release(list,source);
  1018. a_load_reg_ref(list,OS_32,r,dstref);
  1019. inc(srcref.offset,4);
  1020. inc(dstref.offset,4);
  1021. dec(len,4);
  1022. rg.ungetregisterint(list,r);
  1023. end;
  1024. if len>1 then
  1025. begin
  1026. rg.getexplicitregisterint(list,NR_DI);
  1027. r.number:=NR_DI;
  1028. a_load_ref_reg(list,OS_16,srcref,r);
  1029. If (len = 2) and delsource then
  1030. reference_release(list,source);
  1031. a_load_reg_ref(list,OS_16,r,dstref);
  1032. inc(srcref.offset,2);
  1033. inc(dstref.offset,2);
  1034. dec(len,2);
  1035. rg.ungetregisterint(list,r);
  1036. end;
  1037. r.enum:=R_INTREGISTER;
  1038. reg8.enum:=R_INTREGISTER;
  1039. reg32.enum:=R_INTREGISTER;
  1040. if len>0 then
  1041. begin
  1042. { and now look for an 8 bit register }
  1043. swap:=false;
  1044. if RS_EAX in rg.unusedregsint then reg8:=rg.getexplicitregisterint(list,NR_AL)
  1045. else if RS_EDX in rg.unusedregsint then reg8:=rg.getexplicitregisterint(list,NR_DL)
  1046. else if RS_EBX in rg.unusedregsint then reg8:=rg.getexplicitregisterint(list,NR_BL)
  1047. else if RS_ECX in rg.unusedregsint then reg8:=rg.getexplicitregisterint(list,NR_CL)
  1048. else
  1049. begin
  1050. swap:=true;
  1051. { we need only to check 3 registers, because }
  1052. { one is always not index or base }
  1053. if (dest.base.number<>NR_EAX) and (dest.index.number<>NR_EAX) then
  1054. begin
  1055. reg8.number:=NR_AL;
  1056. reg32.number:=NR_EAX;
  1057. end
  1058. else if (dest.base.number<>NR_EBX) and (dest.index.number<>NR_EBX) then
  1059. begin
  1060. reg8.number:=NR_BL;
  1061. reg32.number:=NR_EBX;
  1062. end
  1063. else if (dest.base.number<>NR_ECX) and (dest.index.number<>NR_ECX) then
  1064. begin
  1065. reg8.number:=NR_CL;
  1066. reg32.number:=NR_ECX;
  1067. end;
  1068. end;
  1069. if swap then
  1070. { was earlier XCHG, of course nonsense }
  1071. begin
  1072. rg.getexplicitregisterint(list,NR_EDI);
  1073. r.number:=NR_EDI;
  1074. a_load_reg_reg(list,OS_32,OS_32,reg32,r);
  1075. end;
  1076. a_load_ref_reg(list,OS_8,srcref,reg8);
  1077. If delsource and (len=1) then
  1078. reference_release(list,source);
  1079. a_load_reg_ref(list,OS_8,reg8,dstref);
  1080. if swap then
  1081. begin
  1082. r.number:=NR_EDI;
  1083. a_load_reg_reg(list,OS_32,OS_32,r,reg32);
  1084. rg.ungetregisterint(list,r);
  1085. end
  1086. else
  1087. rg.ungetregisterint(list,reg8);
  1088. end;
  1089. end
  1090. else
  1091. begin
  1092. r.enum:=R_INTREGISTER;
  1093. r.number:=NR_EDI;
  1094. rg.getexplicitregisterint(list,NR_EDI);
  1095. a_loadaddr_ref_reg(list,dest,r);
  1096. r.number:=NR_ESI;
  1097. list.concat(tai_regalloc.alloc(r));
  1098. if loadref then
  1099. a_load_ref_reg(list,OS_ADDR,source,r)
  1100. else
  1101. begin
  1102. a_loadaddr_ref_reg(list,source,r);
  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. r.number:=NR_ECX;
  1109. if cs_littlesize in aktglobalswitches then
  1110. begin
  1111. maybepushecx;
  1112. a_load_const_reg(list,OS_INT,len,r);
  1113. list.concat(Taicpu.Op_none(A_REP,S_NO));
  1114. list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1115. end
  1116. else
  1117. begin
  1118. helpsize:=len shr 2;
  1119. len:=len and 3;
  1120. if helpsize>1 then
  1121. begin
  1122. maybepushecx;
  1123. a_load_const_reg(list,OS_INT,helpsize,r);
  1124. list.concat(Taicpu.Op_none(A_REP,S_NO));
  1125. end;
  1126. if helpsize>0 then
  1127. list.concat(Taicpu.Op_none(A_MOVSD,S_NO));
  1128. if len>1 then
  1129. begin
  1130. dec(len,2);
  1131. list.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  1132. end;
  1133. if len=1 then
  1134. list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1135. end;
  1136. r.enum:=R_INTREGISTER;
  1137. r.number:=NR_EDI;
  1138. rg.ungetregisterint(list,r);
  1139. r.number:=NR_ESI;
  1140. list.concat(tai_regalloc.dealloc(r));
  1141. if ecxpushed then
  1142. begin
  1143. r.number:=NR_ECX;
  1144. list.concat(Taicpu.Op_reg(A_POP,S_L,r))
  1145. end
  1146. else
  1147. begin
  1148. r.number:=NR_ECX;
  1149. rg.ungetregisterint(list,r);
  1150. end;
  1151. { loading SELF-reference again }
  1152. g_maybe_loadself(list);
  1153. end;
  1154. if delsource then
  1155. tg.ungetiftemp(list,source);
  1156. end;
  1157. procedure tcgx86.g_exception_reason_save(list : taasmoutput; const href : treference);
  1158. var r:Tregister;
  1159. begin
  1160. r.enum:=R_INTREGISTER;
  1161. r.number:=NR_EAX;
  1162. list.concat(Taicpu.op_reg(A_PUSH,S_L,r));
  1163. end;
  1164. procedure tcgx86.g_exception_reason_save_const(list : taasmoutput;const href : treference; a: aword);
  1165. begin
  1166. list.concat(Taicpu.op_const(A_PUSH,S_L,a));
  1167. end;
  1168. procedure tcgx86.g_exception_reason_load(list : taasmoutput; const href : treference);
  1169. var r:Tregister;
  1170. begin
  1171. r.enum:=R_INTREGISTER;
  1172. r.number:=NR_EAX;
  1173. list.concat(Taicpu.op_reg(A_POP,S_L,r));
  1174. end;
  1175. {****************************************************************************
  1176. Entry/Exit Code Helpers
  1177. ****************************************************************************}
  1178. procedure tcgx86.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. r,r2,rsp:Tregister;
  1187. begin
  1188. lenref:=ref;
  1189. inc(lenref.offset,4);
  1190. { get stack space }
  1191. r.enum:=R_INTREGISTER;
  1192. r.number:=NR_EDI;
  1193. rsp.enum:=R_INTREGISTER;
  1194. rsp.number:=NR_ESP;
  1195. r2.enum:=R_INTREGISTER;
  1196. rg.getexplicitregisterint(list,NR_EDI);
  1197. list.concat(Taicpu.op_ref_reg(A_MOV,S_L,lenref,r));
  1198. list.concat(Taicpu.op_reg(A_INC,S_L,r));
  1199. if (elesize<>1) then
  1200. begin
  1201. if ispowerof2(elesize, power) then
  1202. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,r))
  1203. else
  1204. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,elesize,r));
  1205. end;
  1206. {$ifndef __NOWINPECOFF__}
  1207. { windows guards only a few pages for stack growing, }
  1208. { so we have to access every page first }
  1209. if target_info.system=system_i386_win32 then
  1210. begin
  1211. objectlibrary.getlabel(again);
  1212. objectlibrary.getlabel(ok);
  1213. a_label(list,again);
  1214. list.concat(Taicpu.op_const_reg(A_CMP,S_L,winstackpagesize,r));
  1215. a_jmp_cond(list,OC_B,ok);
  1216. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,rsp));
  1217. r2.number:=NR_EAX;
  1218. list.concat(Taicpu.op_reg(A_PUSH,S_L,r));
  1219. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize,r));
  1220. a_jmp_always(list,again);
  1221. a_label(list,ok);
  1222. list.concat(Taicpu.op_reg_reg(A_SUB,S_L,r,rsp));
  1223. rg.ungetregisterint(list,r);
  1224. { now reload EDI }
  1225. rg.getexplicitregisterint(list,NR_EDI);
  1226. list.concat(Taicpu.op_ref_reg(A_MOV,S_L,lenref,r));
  1227. list.concat(Taicpu.op_reg(A_INC,S_L,r));
  1228. if (elesize<>1) then
  1229. begin
  1230. if ispowerof2(elesize, power) then
  1231. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,r))
  1232. else
  1233. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,elesize,r));
  1234. end;
  1235. end
  1236. else
  1237. {$endif __NOWINPECOFF__}
  1238. list.concat(Taicpu.op_reg_reg(A_SUB,S_L,r,rsp));
  1239. { align stack on 4 bytes }
  1240. list.concat(Taicpu.op_const_reg(A_AND,S_L,$fffffff4,rsp));
  1241. { load destination }
  1242. list.concat(Taicpu.op_reg_reg(A_MOV,S_L,rsp,r));
  1243. { don't destroy the registers! }
  1244. r2.number:=NR_ECX;
  1245. list.concat(Taicpu.op_reg(A_PUSH,S_L,r2));
  1246. r2.number:=NR_ESI;
  1247. list.concat(Taicpu.op_reg(A_PUSH,S_L,r2));
  1248. { load count }
  1249. r2.number:=NR_ECX;
  1250. list.concat(Taicpu.op_ref_reg(A_MOV,S_L,lenref,r2));
  1251. { load source }
  1252. r2.number:=NR_ESI;
  1253. list.concat(Taicpu.op_ref_reg(A_MOV,S_L,ref,r2));
  1254. { scheduled .... }
  1255. r2.number:=NR_ECX;
  1256. list.concat(Taicpu.op_reg(A_INC,S_L,r2));
  1257. { calculate size }
  1258. len:=elesize;
  1259. opsize:=S_B;
  1260. if (len and 3)=0 then
  1261. begin
  1262. opsize:=S_L;
  1263. len:=len shr 2;
  1264. end
  1265. else
  1266. if (len and 1)=0 then
  1267. begin
  1268. opsize:=S_W;
  1269. len:=len shr 1;
  1270. end;
  1271. if ispowerof2(len, power) then
  1272. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,r2))
  1273. else
  1274. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,len,r2));
  1275. list.concat(Taicpu.op_none(A_REP,S_NO));
  1276. case opsize of
  1277. S_B : list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1278. S_W : list.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  1279. S_L : list.concat(Taicpu.Op_none(A_MOVSD,S_NO));
  1280. end;
  1281. rg.ungetregisterint(list,r);
  1282. r2.number:=NR_ESI;
  1283. list.concat(Taicpu.op_reg(A_POP,S_L,r2));
  1284. r2.number:=NR_ECX;
  1285. list.concat(Taicpu.op_reg(A_POP,S_L,r2));
  1286. { patch the new address }
  1287. list.concat(Taicpu.op_reg_ref(A_MOV,S_L,rsp,ref));
  1288. end;
  1289. procedure tcgx86.g_removevaluepara_openarray(list : taasmoutput;const ref:treference;elesize:integer);
  1290. var
  1291. lenref : treference;
  1292. power,len : longint;
  1293. r,rsp:Tregister;
  1294. begin
  1295. lenref:=ref;
  1296. inc(lenref.offset,4);
  1297. { caluclate size and adjust stack space }
  1298. rg.getexplicitregisterint(list,NR_EDI);
  1299. r.enum:=R_INTREGISTER;
  1300. r.number:=NR_EDI;
  1301. rsp.enum:=R_INTREGISTER;
  1302. rsp.number:=NR_ESP;
  1303. list.concat(Taicpu.op_ref_reg(A_MOV,S_L,lenref,r));
  1304. list.concat(Taicpu.op_reg(A_INC,S_L,r));
  1305. if (elesize<>1) then
  1306. begin
  1307. if ispowerof2(elesize, power) then
  1308. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,r))
  1309. else
  1310. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,elesize,r));
  1311. end;
  1312. list.concat(Taicpu.op_reg_reg(A_ADD,S_L,r,rsp));
  1313. end;
  1314. procedure tcgx86.g_interrupt_stackframe_entry(list : taasmoutput);
  1315. var r:Tregister;
  1316. begin
  1317. r.enum:=R_INTREGISTER;
  1318. r.number:=NR_GS;
  1319. { .... also the segment registers }
  1320. list.concat(Taicpu.Op_reg(A_PUSH,S_W,r));
  1321. r.number:=NR_FS;
  1322. list.concat(Taicpu.Op_reg(A_PUSH,S_W,r));
  1323. r.number:=NR_ES;
  1324. list.concat(Taicpu.Op_reg(A_PUSH,S_W,r));
  1325. r.number:=NR_DS;
  1326. list.concat(Taicpu.Op_reg(A_PUSH,S_W,r));
  1327. { save the registers of an interrupt procedure }
  1328. r.number:=NR_EDI;
  1329. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r));
  1330. r.number:=NR_ESI;
  1331. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r));
  1332. r.number:=NR_EDX;
  1333. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r));
  1334. r.number:=NR_ECX;
  1335. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r));
  1336. r.number:=NR_EBX;
  1337. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r));
  1338. r.number:=NR_EAX;
  1339. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r));
  1340. end;
  1341. procedure tcgx86.g_interrupt_stackframe_exit(list : taasmoutput;selfused,accused,acchiused:boolean);
  1342. var r:Tregister;
  1343. begin
  1344. r.enum:=R_INTREGISTER;
  1345. if accused then
  1346. begin
  1347. r.number:=NR_ESP;
  1348. list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,r))
  1349. end
  1350. else
  1351. begin
  1352. r.number:=NR_EAX;
  1353. list.concat(Taicpu.Op_reg(A_POP,S_L,r));
  1354. end;
  1355. r.number:=NR_EBX;
  1356. list.concat(Taicpu.Op_reg(A_POP,S_L,r));
  1357. r.number:=NR_ECX;
  1358. list.concat(Taicpu.Op_reg(A_POP,S_L,r));
  1359. if acchiused then
  1360. begin
  1361. r.number:=NR_ESP;
  1362. list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,r))
  1363. end
  1364. else
  1365. begin
  1366. r.number:=NR_EDX;
  1367. list.concat(Taicpu.Op_reg(A_POP,S_L,r));
  1368. end;
  1369. if selfused then
  1370. begin
  1371. r.number:=NR_ESP;
  1372. list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,r))
  1373. end
  1374. else
  1375. begin
  1376. r.number:=NR_ESI;
  1377. list.concat(Taicpu.Op_reg(A_POP,S_L,r));
  1378. end;
  1379. r.number:=NR_EDI;
  1380. list.concat(Taicpu.Op_reg(A_POP,S_L,r));
  1381. { .... also the segment registers }
  1382. r.number:=NR_DS;
  1383. list.concat(Taicpu.Op_reg(A_POP,S_W,r));
  1384. r.number:=NR_ES;
  1385. list.concat(Taicpu.Op_reg(A_POP,S_W,r));
  1386. r.number:=NR_FS;
  1387. list.concat(Taicpu.Op_reg(A_POP,S_W,r));
  1388. r.number:=NR_GS;
  1389. list.concat(Taicpu.Op_reg(A_POP,S_W,r));
  1390. { this restores the flags }
  1391. list.concat(Taicpu.Op_none(A_IRET,S_NO));
  1392. end;
  1393. procedure tcgx86.g_profilecode(list : taasmoutput);
  1394. var
  1395. pl : tasmlabel;
  1396. r : Tregister;
  1397. begin
  1398. case target_info.system of
  1399. system_i386_win32,
  1400. system_i386_freebsd,
  1401. system_i386_wdosx,
  1402. system_i386_linux:
  1403. begin
  1404. objectlibrary.getaddrlabel(pl);
  1405. list.concat(Tai_section.Create(sec_data));
  1406. list.concat(Tai_align.Create(4));
  1407. list.concat(Tai_label.Create(pl));
  1408. list.concat(Tai_const.Create_32bit(0));
  1409. list.concat(Tai_section.Create(sec_code));
  1410. r.enum:=R_INTREGISTER;
  1411. r.number:=NR_EDX;
  1412. list.concat(Taicpu.Op_sym_ofs_reg(A_MOV,S_L,pl,0,r));
  1413. a_call_name(list,target_info.Cprefix+'mcount');
  1414. include(rg.usedinproc,R_EDX);
  1415. end;
  1416. system_i386_go32v2:
  1417. begin
  1418. a_call_name(list,'MCOUNT');
  1419. end;
  1420. end;
  1421. end;
  1422. procedure tcgx86.g_stackpointer_alloc(list : taasmoutput;localsize : longint);
  1423. var
  1424. href : treference;
  1425. i : integer;
  1426. again : tasmlabel;
  1427. r,rsp : Tregister;
  1428. begin
  1429. r.enum:=R_INTREGISTER;
  1430. rsp.enum:=R_INTREGISTER;
  1431. rsp.number:=NR_ESP;
  1432. if localsize>0 then
  1433. begin
  1434. {$ifndef NOTARGETWIN32}
  1435. { windows guards only a few pages for stack growing, }
  1436. { so we have to access every page first }
  1437. if (target_info.system=system_i386_win32) and
  1438. (localsize>=winstackpagesize) then
  1439. begin
  1440. if localsize div winstackpagesize<=5 then
  1441. begin
  1442. list.concat(Taicpu.Op_const_reg(A_SUB,S_L,localsize-4,rsp));
  1443. for i:=1 to localsize div winstackpagesize do
  1444. begin
  1445. reference_reset_base(href,rsp,localsize-i*winstackpagesize);
  1446. list.concat(Taicpu.op_const_ref(A_MOV,S_L,0,href));
  1447. end;
  1448. r.number:=NR_EAX;
  1449. list.concat(Taicpu.op_reg(A_PUSH,S_L,r));
  1450. end
  1451. else
  1452. begin
  1453. objectlibrary.getlabel(again);
  1454. r.number:=NR_EDI;
  1455. rg.getexplicitregisterint(list,NR_EDI);
  1456. list.concat(Taicpu.op_const_reg(A_MOV,S_L,localsize div winstackpagesize,r));
  1457. a_label(list,again);
  1458. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,rsp));
  1459. r.number:=NR_EAX;
  1460. list.concat(Taicpu.op_reg(A_PUSH,S_L,r));
  1461. r.number:=NR_EDI;
  1462. list.concat(Taicpu.op_reg(A_DEC,S_L,r));
  1463. a_jmp_cond(list,OC_NE,again);
  1464. rg.ungetregisterint(list,r);
  1465. list.concat(Taicpu.op_const_reg(A_SUB,S_L,localsize mod winstackpagesize,rsp));
  1466. end
  1467. end
  1468. else
  1469. {$endif NOTARGETWIN32}
  1470. list.concat(Taicpu.Op_const_reg(A_SUB,S_L,localsize,rsp));
  1471. end;
  1472. end;
  1473. procedure tcgx86.g_stackframe_entry(list : taasmoutput;localsize : longint);
  1474. var r,rsp:Tregister;
  1475. begin
  1476. r.enum:=R_INTREGISTER;
  1477. r.number:=NR_EBP;
  1478. rsp.enum:=R_INTREGISTER;
  1479. rsp.number:=NR_ESP;
  1480. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r));
  1481. list.concat(Taicpu.Op_reg_reg(A_MOV,S_L,rsp,r));
  1482. if localsize>0 then
  1483. g_stackpointer_alloc(list,localsize);
  1484. end;
  1485. procedure tcgx86.g_restore_frame_pointer(list : taasmoutput);
  1486. begin
  1487. list.concat(Taicpu.Op_none(A_LEAVE,S_NO));
  1488. end;
  1489. procedure tcgx86.g_return_from_proc(list : taasmoutput;parasize : aword);
  1490. begin
  1491. { Routines with the poclearstack flag set use only a ret }
  1492. { also routines with parasize=0 }
  1493. if (po_clearstack in aktprocdef.procoptions) then
  1494. begin
  1495. { complex return values are removed from stack in C code PM }
  1496. if paramanager.ret_in_param(aktprocdef.rettype.def,aktprocdef.proccalloption) then
  1497. list.concat(Taicpu.Op_const(A_RET,S_NO,4))
  1498. else
  1499. list.concat(Taicpu.Op_none(A_RET,S_NO));
  1500. end
  1501. else if (parasize=0) then
  1502. list.concat(Taicpu.Op_none(A_RET,S_NO))
  1503. else
  1504. begin
  1505. { parameters are limited to 65535 bytes because }
  1506. { ret allows only imm16 }
  1507. if (parasize>65535) then
  1508. CGMessage(cg_e_parasize_too_big);
  1509. list.concat(Taicpu.Op_const(A_RET,S_NO,parasize));
  1510. end;
  1511. end;
  1512. {$ifndef TEST_GENERIC}
  1513. procedure tcgx86.g_call_constructor_helper(list : taasmoutput);
  1514. var r:Tregister;
  1515. begin
  1516. r.enum:=R_INTREGISTER;
  1517. r.number:=NR_EDI;
  1518. if is_class(procinfo._class) then
  1519. begin
  1520. if (cs_implicit_exceptions in aktmoduleswitches) then
  1521. procinfo.flags:=procinfo.flags or pi_needs_implicit_finally;
  1522. a_call_name(list,'FPC_NEW_CLASS');
  1523. list.concat(Taicpu.Op_cond_sym(A_Jcc,C_Z,S_NO,faillabel));
  1524. end
  1525. else if is_object(procinfo._class) then
  1526. begin
  1527. rg.getexplicitregisterint(list,NR_EDI);
  1528. a_load_const_reg(list,OS_ADDR,procinfo._class.vmt_offset,r);
  1529. a_call_name(list,'FPC_HELP_CONSTRUCTOR');
  1530. list.concat(Taicpu.Op_cond_sym(A_Jcc,C_Z,S_NO,faillabel));
  1531. end
  1532. else
  1533. internalerror(200006161);
  1534. end;
  1535. procedure tcgx86.g_call_destructor_helper(list : taasmoutput);
  1536. var
  1537. nofinal : tasmlabel;
  1538. href : treference;
  1539. r : Tregister;
  1540. begin
  1541. r.enum:=R_INTREGISTER;
  1542. if is_class(procinfo._class) then
  1543. begin
  1544. a_call_name(list,'FPC_DISPOSE_CLASS')
  1545. end
  1546. else if is_object(procinfo._class) then
  1547. begin
  1548. { must the object be finalized ? }
  1549. if procinfo._class.needs_inittable then
  1550. begin
  1551. objectlibrary.getlabel(nofinal);
  1552. r.number:=NR_EBP;
  1553. reference_reset_base(href,r,8);
  1554. a_cmp_const_ref_label(list,OS_ADDR,OC_EQ,0,href,nofinal);
  1555. r.number:=NR_ESI;
  1556. reference_reset_base(href,r,0);
  1557. g_finalize(list,procinfo._class,href,false);
  1558. a_label(list,nofinal);
  1559. end;
  1560. rg.getexplicitregisterint(list,NR_EDI);
  1561. r.number:=NR_EDI;
  1562. a_load_const_reg(list,OS_ADDR,procinfo._class.vmt_offset,r);
  1563. rg.ungetregisterint(list,r);
  1564. a_call_name(list,'FPC_HELP_DESTRUCTOR')
  1565. end
  1566. else
  1567. internalerror(200006162);
  1568. end;
  1569. procedure tcgx86.g_call_fail_helper(list : taasmoutput);
  1570. var
  1571. href : treference;
  1572. r : Tregister;
  1573. begin
  1574. r.enum:=R_INTREGISTER;
  1575. if is_class(procinfo._class) then
  1576. begin
  1577. reference_reset_base(href,procinfo.framepointer,8);
  1578. r.number:=NR_ESI;
  1579. a_load_ref_reg(list,OS_ADDR,href,r);
  1580. a_call_name(list,'FPC_HELP_FAIL_CLASS');
  1581. end
  1582. else if is_object(procinfo._class) then
  1583. begin
  1584. reference_reset_base(href,procinfo.framepointer,12);
  1585. r.number:=NR_ESI;
  1586. a_load_ref_reg(list,OS_ADDR,href,r);
  1587. rg.getexplicitregisterint(list,NR_EDI);
  1588. r.number:=NR_EDI;
  1589. a_load_const_reg(list,OS_ADDR,procinfo._class.vmt_offset,r);
  1590. a_call_name(list,'FPC_HELP_FAIL');
  1591. rg.ungetregisterint(list,r);
  1592. end
  1593. else
  1594. internalerror(200006163);
  1595. end;
  1596. {$endif}
  1597. procedure tcgx86.g_save_standard_registers(list:Taasmoutput;usedinproc:Tsupregset);
  1598. var r:Tregister;
  1599. begin
  1600. r.enum:=R_INTREGISTER;
  1601. r.number:=NR_EBX;
  1602. if (RS_EBX in usedinproc) then
  1603. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r));
  1604. r.number:=NR_ESI;
  1605. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r));
  1606. r.number:=NR_EDI;
  1607. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r));
  1608. end;
  1609. procedure tcgx86.g_restore_standard_registers(list:Taasmoutput;usedinproc:Tsupregset);
  1610. var r:Tregister;
  1611. begin
  1612. r.enum:=R_INTREGISTER;
  1613. r.number:=NR_EDI;
  1614. list.concat(Taicpu.Op_reg(A_POP,S_L,r));
  1615. r.number:=NR_ESI;
  1616. list.concat(Taicpu.Op_reg(A_POP,S_L,r));
  1617. r.number:=NR_EBX;
  1618. if (RS_EBX in usedinproc) then
  1619. list.concat(Taicpu.Op_reg(A_POP,S_L,r));
  1620. end;
  1621. procedure tcgx86.g_save_all_registers(list : taasmoutput);
  1622. begin
  1623. list.concat(Taicpu.Op_none(A_PUSHA,S_L));
  1624. end;
  1625. procedure tcgx86.g_restore_all_registers(list : taasmoutput;selfused,accused,acchiused:boolean);
  1626. var
  1627. href : treference;
  1628. r,rsp: Tregister;
  1629. begin
  1630. rsp.enum:=R_INTREGISTER;
  1631. rsp.number:=NR_ESP;
  1632. r.enum:=R_INTREGISTER;
  1633. if selfused then
  1634. begin
  1635. reference_reset_base(href,rsp,4);
  1636. r.number:=NR_ESI;
  1637. list.concat(Taicpu.Op_reg_ref(A_MOV,S_L,r,href));
  1638. end;
  1639. if acchiused then
  1640. begin
  1641. reference_reset_base(href,rsp,20);
  1642. r.number:=NR_EDX;
  1643. list.concat(Taicpu.Op_reg_ref(A_MOV,S_L,r,href));
  1644. end;
  1645. if accused then
  1646. begin
  1647. reference_reset_base(href,rsp,28);
  1648. r.number:=NR_EAX;
  1649. list.concat(Taicpu.Op_reg_ref(A_MOV,S_L,r,href));
  1650. end;
  1651. list.concat(Taicpu.Op_none(A_POPA,S_L));
  1652. { We add a NOP because of the 386DX CPU bugs with POPAD }
  1653. list.concat(taicpu.op_none(A_NOP,S_L));
  1654. end;
  1655. { produces if necessary overflowcode }
  1656. procedure tcgx86.g_overflowcheck(list: taasmoutput; const p: tnode);
  1657. var
  1658. hl : tasmlabel;
  1659. ai : taicpu;
  1660. cond : TAsmCond;
  1661. begin
  1662. if not(cs_check_overflow in aktlocalswitches) then
  1663. exit;
  1664. objectlibrary.getlabel(hl);
  1665. if not ((p.resulttype.def.deftype=pointerdef) or
  1666. ((p.resulttype.def.deftype=orddef) and
  1667. (torddef(p.resulttype.def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,
  1668. bool8bit,bool16bit,bool32bit]))) then
  1669. cond:=C_NO
  1670. else
  1671. cond:=C_NB;
  1672. ai:=Taicpu.Op_Sym(A_Jcc,S_NO,hl);
  1673. ai.SetCondition(cond);
  1674. ai.is_jmp:=true;
  1675. list.concat(ai);
  1676. a_call_name(list,'FPC_OVERFLOW');
  1677. a_label(list,hl);
  1678. end;
  1679. end.
  1680. {
  1681. $Log$
  1682. Revision 1.35 2003-03-13 19:52:23 jonas
  1683. * and more new register allocator fixes (in the i386 code generator this
  1684. time). At least now the ppc cross compiler can compile the linux
  1685. system unit again, but I haven't tested it.
  1686. Revision 1.34 2003/02/27 16:40:32 daniel
  1687. * Fixed ie 200301234 problem on Win32 target
  1688. Revision 1.33 2003/02/26 21:15:43 daniel
  1689. * Fixed the optimizer
  1690. Revision 1.32 2003/02/19 22:00:17 daniel
  1691. * Code generator converted to new register notation
  1692. - Horribily outdated todo.txt removed
  1693. Revision 1.31 2003/01/21 10:41:13 daniel
  1694. * Fixed another 200301081
  1695. Revision 1.30 2003/01/13 23:00:18 daniel
  1696. * Fixed internalerror
  1697. Revision 1.29 2003/01/13 14:54:34 daniel
  1698. * Further work to convert codegenerator register convention;
  1699. internalerror bug fixed.
  1700. Revision 1.28 2003/01/09 20:41:00 daniel
  1701. * Converted some code in cgx86.pas to new register numbering
  1702. Revision 1.27 2003/01/08 18:43:58 daniel
  1703. * Tregister changed into a record
  1704. Revision 1.26 2003/01/05 13:36:53 florian
  1705. * x86-64 compiles
  1706. + very basic support for float128 type (x86-64 only)
  1707. Revision 1.25 2003/01/02 16:17:50 peter
  1708. * align stack on 4 bytes in copyvalueopenarray
  1709. Revision 1.24 2002/12/24 15:56:50 peter
  1710. * stackpointer_alloc added for adjusting ESP. Win32 needs
  1711. this for the pageprotection
  1712. Revision 1.23 2002/11/25 18:43:34 carl
  1713. - removed the invalid if <> checking (Delphi is strange on this)
  1714. + implemented abstract warning on instance creation of class with
  1715. abstract methods.
  1716. * some error message cleanups
  1717. Revision 1.22 2002/11/25 17:43:29 peter
  1718. * splitted defbase in defutil,symutil,defcmp
  1719. * merged isconvertable and is_equal into compare_defs(_ext)
  1720. * made operator search faster by walking the list only once
  1721. Revision 1.21 2002/11/18 17:32:01 peter
  1722. * pass proccalloption to ret_in_xxx and push_xxx functions
  1723. Revision 1.20 2002/11/09 21:18:31 carl
  1724. * flags2reg() was not extending the byte register to the correct result size
  1725. Revision 1.19 2002/10/16 19:01:43 peter
  1726. + $IMPLICITEXCEPTIONS switch to turn on/off generation of the
  1727. implicit exception frames for procedures with initialized variables
  1728. and for constructors. The default is on for compatibility
  1729. Revision 1.18 2002/10/05 12:43:30 carl
  1730. * fixes for Delphi 6 compilation
  1731. (warning : Some features do not work under Delphi)
  1732. Revision 1.17 2002/09/17 18:54:06 jonas
  1733. * a_load_reg_reg() now has two size parameters: source and dest. This
  1734. allows some optimizations on architectures that don't encode the
  1735. register size in the register name.
  1736. Revision 1.16 2002/09/16 19:08:47 peter
  1737. * support references without registers and symbol in paramref_addr. It
  1738. pushes only the offset
  1739. Revision 1.15 2002/09/16 18:06:29 peter
  1740. * move CGSize2Opsize to interface
  1741. Revision 1.14 2002/09/01 14:42:41 peter
  1742. * removevaluepara added to fix the stackpointer so restoring of
  1743. saved registers works
  1744. Revision 1.13 2002/09/01 12:09:27 peter
  1745. + a_call_reg, a_call_loc added
  1746. * removed exprasmlist references
  1747. Revision 1.12 2002/08/17 09:23:50 florian
  1748. * first part of procinfo rewrite
  1749. Revision 1.11 2002/08/16 14:25:00 carl
  1750. * issameref() to test if two references are the same (then emit no opcodes)
  1751. + ret_in_reg to replace ret_in_acc
  1752. (fix some register allocation bugs at the same time)
  1753. + save_std_register now has an extra parameter which is the
  1754. usedinproc registers
  1755. Revision 1.10 2002/08/15 08:13:54 carl
  1756. - a_load_sym_ofs_reg removed
  1757. * loadvmt now calls loadaddr_ref_reg instead
  1758. Revision 1.9 2002/08/11 14:32:33 peter
  1759. * renamed current_library to objectlibrary
  1760. Revision 1.8 2002/08/11 13:24:20 peter
  1761. * saving of asmsymbols in ppu supported
  1762. * asmsymbollist global is removed and moved into a new class
  1763. tasmlibrarydata that will hold the info of a .a file which
  1764. corresponds with a single module. Added librarydata to tmodule
  1765. to keep the library info stored for the module. In the future the
  1766. objectfiles will also be stored to the tasmlibrarydata class
  1767. * all getlabel/newasmsymbol and friends are moved to the new class
  1768. Revision 1.7 2002/08/10 10:06:04 jonas
  1769. * fixed stupid bug of mine in g_flags2reg() when optimizations are on
  1770. Revision 1.6 2002/08/09 19:18:27 carl
  1771. * fix generic exception handling
  1772. Revision 1.5 2002/08/04 19:52:04 carl
  1773. + updated exception routines
  1774. Revision 1.4 2002/07/27 19:53:51 jonas
  1775. + generic implementation of tcg.g_flags2ref()
  1776. * tcg.flags2xxx() now also needs a size parameter
  1777. Revision 1.3 2002/07/26 21:15:46 florian
  1778. * rewrote the system handling
  1779. Revision 1.2 2002/07/21 16:55:34 jonas
  1780. * fixed bug in op_const_reg_reg() for imul
  1781. Revision 1.1 2002/07/20 19:28:47 florian
  1782. * splitting of i386\cgcpu.pas into x86\cgx86.pas and i386\cgcpu.pas
  1783. cgx86.pas will contain the common code for i386 and x86_64
  1784. }