cgcpu.pas 67 KB

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