cgcpu.pas 68 KB

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