cgcpu.pas 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. This unit implements the code generator for the i386
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit cgcpu;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. cgbase,cgobj,cg64f32,cgx86,
  23. aasmbase,aasmtai,aasmcpu,
  24. cpubase,parabase,cgutils,
  25. symconst,symdef
  26. ;
  27. type
  28. tcg386 = class(tcgx86)
  29. procedure init_register_allocators;override;
  30. procedure do_register_allocation(list:Taasmoutput;headertai:tai);override;
  31. { passing parameter using push instead of mov }
  32. procedure a_param_reg(list : taasmoutput;size : tcgsize;r : tregister;const cgpara : tcgpara);override;
  33. procedure a_param_const(list : taasmoutput;size : tcgsize;a : aint;const cgpara : tcgpara);override;
  34. procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const cgpara : tcgpara);override;
  35. procedure a_paramaddr_ref(list : taasmoutput;const r : treference;const cgpara : tcgpara);override;
  36. procedure g_proc_exit(list : taasmoutput;parasize:longint;nostackframe:boolean);override;
  37. procedure g_copyvaluepara_openarray(list : taasmoutput;const ref:treference;const lenloc:tlocation;elesize:aint;destreg:tregister);override;
  38. procedure g_exception_reason_save(list : taasmoutput; const href : treference);override;
  39. procedure g_exception_reason_save_const(list : taasmoutput; const href : treference; a: aint);override;
  40. procedure g_exception_reason_load(list : taasmoutput; const href : treference);override;
  41. procedure g_intf_wrapper(list: TAAsmoutput; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  42. end;
  43. tcg64f386 = class(tcg64f32)
  44. procedure a_op64_ref_reg(list : taasmoutput;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);override;
  45. procedure a_op64_reg_reg(list : taasmoutput;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  46. procedure a_op64_const_reg(list : taasmoutput;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  47. procedure a_op64_const_ref(list : taasmoutput;op:TOpCG;size : tcgsize;value : int64;const ref : treference);override;
  48. private
  49. procedure get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  50. end;
  51. implementation
  52. uses
  53. globals,verbose,systems,cutils,
  54. paramgr,procinfo,fmodule,
  55. rgcpu,rgx86;
  56. function use_push(const cgpara:tcgpara):boolean;
  57. begin
  58. result:=(not use_fixed_stack) and
  59. assigned(cgpara.location) and
  60. (cgpara.location^.loc=LOC_REFERENCE) and
  61. (cgpara.location^.reference.index=NR_STACK_POINTER_REG);
  62. end;
  63. procedure tcg386.init_register_allocators;
  64. begin
  65. inherited init_register_allocators;
  66. if cs_create_pic in aktmoduleswitches then
  67. rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_EAX,RS_EDX,RS_ECX,RS_ESI,RS_EDI],first_int_imreg,[RS_EBP])
  68. else
  69. rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_EAX,RS_EDX,RS_ECX,RS_EBX,RS_ESI,RS_EDI],first_int_imreg,[RS_EBP]);
  70. rg[R_MMXREGISTER]:=trgcpu.create(R_MMXREGISTER,R_SUBNONE,[RS_XMM0,RS_XMM1,RS_XMM2,RS_XMM3,RS_XMM4,RS_XMM5,RS_XMM6,RS_XMM7],first_mm_imreg,[]);
  71. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBWHOLE,[RS_XMM0,RS_XMM1,RS_XMM2,RS_XMM3,RS_XMM4,RS_XMM5,RS_XMM6,RS_XMM7],first_mm_imreg,[]);
  72. rgfpu:=Trgx86fpu.create;
  73. end;
  74. procedure tcg386.do_register_allocation(list:Taasmoutput;headertai:tai);
  75. begin
  76. if pi_needs_got in current_procinfo.flags then
  77. include(rg[R_INTREGISTER].used_in_proc,getsupreg(current_procinfo.got));
  78. inherited do_register_allocation(list,headertai);
  79. end;
  80. procedure tcg386.a_param_reg(list : taasmoutput;size : tcgsize;r : tregister;const cgpara : tcgpara);
  81. var
  82. pushsize : tcgsize;
  83. begin
  84. check_register_size(size,r);
  85. if use_push(cgpara) then
  86. begin
  87. cgpara.check_simple_location;
  88. if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
  89. pushsize:=cgpara.location^.size
  90. else
  91. pushsize:=int_cgsize(cgpara.alignment);
  92. list.concat(taicpu.op_reg(A_PUSH,tcgsize2opsize[pushsize],makeregsize(list,r,pushsize)));
  93. end
  94. else
  95. inherited a_param_reg(list,size,r,cgpara);
  96. end;
  97. procedure tcg386.a_param_const(list : taasmoutput;size : tcgsize;a : aint;const cgpara : tcgpara);
  98. var
  99. pushsize : tcgsize;
  100. begin
  101. if use_push(cgpara) then
  102. begin
  103. cgpara.check_simple_location;
  104. if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
  105. pushsize:=cgpara.location^.size
  106. else
  107. pushsize:=int_cgsize(cgpara.alignment);
  108. list.concat(taicpu.op_const(A_PUSH,tcgsize2opsize[pushsize],a));
  109. end
  110. else
  111. inherited a_param_const(list,size,a,cgpara);
  112. end;
  113. procedure tcg386.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const cgpara : tcgpara);
  114. procedure pushdata(paraloc:pcgparalocation;ofs:aint);
  115. var
  116. pushsize : tcgsize;
  117. tmpreg : tregister;
  118. href : treference;
  119. begin
  120. if not assigned(paraloc) then
  121. exit;
  122. if (paraloc^.loc<>LOC_REFERENCE) or
  123. (paraloc^.reference.index<>NR_STACK_POINTER_REG) or
  124. (tcgsize2size[paraloc^.size]>sizeof(aint)) then
  125. internalerror(200501162);
  126. { Pushes are needed in reverse order, add the size of the
  127. current location to the offset where to load from. This
  128. prevents wrong calculations for the last location when
  129. the size is not a power of 2 }
  130. if assigned(paraloc^.next) then
  131. pushdata(paraloc^.next,ofs+tcgsize2size[paraloc^.size]);
  132. { Push the data starting at ofs }
  133. href:=r;
  134. inc(href.offset,ofs);
  135. if tcgsize2size[paraloc^.size]>cgpara.alignment then
  136. pushsize:=paraloc^.size
  137. else
  138. pushsize:=int_cgsize(cgpara.alignment);
  139. if tcgsize2size[paraloc^.size]<cgpara.alignment then
  140. begin
  141. tmpreg:=getintregister(list,pushsize);
  142. a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg);
  143. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize],tmpreg));
  144. end
  145. else
  146. list.concat(taicpu.op_ref(A_PUSH,TCgsize2opsize[pushsize],href));
  147. end;
  148. var
  149. len : aint;
  150. href : treference;
  151. begin
  152. { cgpara.size=OS_NO requires a copy on the stack }
  153. if use_push(cgpara) then
  154. begin
  155. { Record copy? }
  156. if (cgpara.size in [OS_NO,OS_F64]) or (size=OS_NO) then
  157. begin
  158. cgpara.check_simple_location;
  159. len:=align(cgpara.intsize,cgpara.alignment);
  160. g_stackpointer_alloc(list,len);
  161. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  162. g_concatcopy(list,r,href,len);
  163. end
  164. else
  165. begin
  166. if tcgsize2size[cgpara.size]<>tcgsize2size[size] then
  167. internalerror(200501161);
  168. { We need to push the data in reverse order,
  169. therefor we use a recursive algorithm }
  170. pushdata(cgpara.location,0);
  171. end
  172. end
  173. else
  174. inherited a_param_ref(list,size,r,cgpara);
  175. end;
  176. procedure tcg386.a_paramaddr_ref(list : taasmoutput;const r : treference;const cgpara : tcgpara);
  177. var
  178. tmpreg : tregister;
  179. opsize : topsize;
  180. begin
  181. with r do
  182. begin
  183. if (segment<>NR_NO) then
  184. cgmessage(cg_e_cant_use_far_pointer_there);
  185. if use_push(cgpara) then
  186. begin
  187. cgpara.check_simple_location;
  188. opsize:=tcgsize2opsize[OS_ADDR];
  189. if (segment=NR_NO) and (base=NR_NO) and (index=NR_NO) then
  190. begin
  191. if assigned(symbol) then
  192. list.concat(Taicpu.Op_sym_ofs(A_PUSH,opsize,symbol,offset))
  193. else
  194. list.concat(Taicpu.Op_const(A_PUSH,opsize,offset));
  195. end
  196. else if (segment=NR_NO) and (base=NR_NO) and (index<>NR_NO) and
  197. (offset=0) and (scalefactor=0) and (symbol=nil) then
  198. list.concat(Taicpu.Op_reg(A_PUSH,opsize,index))
  199. else if (segment=NR_NO) and (base<>NR_NO) and (index=NR_NO) and
  200. (offset=0) and (symbol=nil) then
  201. list.concat(Taicpu.Op_reg(A_PUSH,opsize,base))
  202. else
  203. begin
  204. tmpreg:=getaddressregister(list);
  205. a_loadaddr_ref_reg(list,r,tmpreg);
  206. list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
  207. end;
  208. end
  209. else
  210. inherited a_paramaddr_ref(list,r,cgpara);
  211. end;
  212. end;
  213. procedure tcg386.g_proc_exit(list : taasmoutput;parasize:longint;nostackframe:boolean);
  214. var
  215. stacksize : longint;
  216. begin
  217. { Release PIC register }
  218. if cs_create_pic in aktmoduleswitches then
  219. list.concat(tai_regalloc.dealloc(NR_PIC_OFFSET_REG,nil));
  220. { MMX needs to call EMMS }
  221. if assigned(rg[R_MMXREGISTER]) and
  222. (rg[R_MMXREGISTER].uses_registers) then
  223. list.concat(Taicpu.op_none(A_EMMS,S_NO));
  224. { remove stackframe }
  225. if not nostackframe then
  226. begin
  227. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  228. begin
  229. stacksize:=current_procinfo.calc_stackframe_size;
  230. if (target_info.system = system_i386_darwin) and
  231. ((stacksize <> 0) or
  232. (pi_do_call in current_procinfo.flags)) then
  233. stacksize := align(stacksize+sizeof(aint),16) - sizeof(aint);
  234. if (stacksize<>0) then
  235. cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);
  236. end
  237. else
  238. list.concat(Taicpu.op_none(A_LEAVE,S_NO));
  239. list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
  240. end;
  241. { return from proc }
  242. if (po_interrupt in current_procinfo.procdef.procoptions) and
  243. { this messes up stack alignment }
  244. (target_info.system <> system_i386_darwin) then
  245. begin
  246. if (current_procinfo.procdef.funcretloc[calleeside].loc<>LOC_VOID) and
  247. (current_procinfo.procdef.funcretloc[calleeside].loc=LOC_REGISTER) then
  248. list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,NR_ESP))
  249. else
  250. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EAX));
  251. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EBX));
  252. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_ECX));
  253. if (current_procinfo.procdef.funcretloc[calleeside].loc=LOC_REGISTER) and
  254. (current_procinfo.procdef.funcretloc[calleeside].size in [OS_64,OS_S64]) then
  255. list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,NR_ESP))
  256. else
  257. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EDX));
  258. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_ESI));
  259. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EDI));
  260. { .... also the segment registers }
  261. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DS));
  262. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_ES));
  263. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_FS));
  264. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_GS));
  265. { this restores the flags }
  266. list.concat(Taicpu.Op_none(A_IRET,S_NO));
  267. end
  268. { Routines with the poclearstack flag set use only a ret }
  269. else if (current_procinfo.procdef.proccalloption in clearstack_pocalls) and
  270. (not use_fixed_stack) then
  271. begin
  272. { complex return values are removed from stack in C code PM }
  273. if paramanager.ret_in_param(current_procinfo.procdef.rettype.def,
  274. current_procinfo.procdef.proccalloption) then
  275. list.concat(Taicpu.Op_const(A_RET,S_W,sizeof(aint)))
  276. else
  277. list.concat(Taicpu.Op_none(A_RET,S_NO));
  278. end
  279. { ... also routines with parasize=0 }
  280. else if (parasize=0) then
  281. list.concat(Taicpu.Op_none(A_RET,S_NO))
  282. else
  283. begin
  284. { parameters are limited to 65535 bytes because ret allows only imm16 }
  285. if (parasize>65535) then
  286. CGMessage(cg_e_parasize_too_big);
  287. list.concat(Taicpu.Op_const(A_RET,S_W,parasize));
  288. end;
  289. end;
  290. procedure tcg386.g_copyvaluepara_openarray(list : taasmoutput;const ref:treference;const lenloc:tlocation;elesize:aint;destreg:tregister);
  291. var
  292. power,len : longint;
  293. opsize : topsize;
  294. {$ifndef __NOWINPECOFF__}
  295. again,ok : tasmlabel;
  296. {$endif}
  297. begin
  298. { get stack space }
  299. getcpuregister(list,NR_EDI);
  300. a_load_loc_reg(list,OS_INT,lenloc,NR_EDI);
  301. list.concat(Taicpu.op_reg(A_INC,S_L,NR_EDI));
  302. if (elesize<>1) then
  303. begin
  304. if ispowerof2(elesize, power) then
  305. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,NR_EDI))
  306. else
  307. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,elesize,NR_EDI));
  308. end;
  309. {$ifndef __NOWINPECOFF__}
  310. { windows guards only a few pages for stack growing, }
  311. { so we have to access every page first }
  312. if target_info.system=system_i386_win32 then
  313. begin
  314. objectlibrary.getjumplabel(again);
  315. objectlibrary.getjumplabel(ok);
  316. a_label(list,again);
  317. list.concat(Taicpu.op_const_reg(A_CMP,S_L,winstackpagesize,NR_EDI));
  318. a_jmp_cond(list,OC_B,ok);
  319. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,NR_ESP));
  320. list.concat(Taicpu.op_reg(A_PUSH,S_L,NR_EDI));
  321. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize,NR_EDI));
  322. a_jmp_always(list,again);
  323. a_label(list,ok);
  324. list.concat(Taicpu.op_reg_reg(A_SUB,S_L,NR_EDI,NR_ESP));
  325. ungetcpuregister(list,NR_EDI);
  326. { now reload EDI }
  327. getcpuregister(list,NR_EDI);
  328. a_load_loc_reg(list,OS_INT,lenloc,NR_EDI);
  329. list.concat(Taicpu.op_reg(A_INC,S_L,NR_EDI));
  330. if (elesize<>1) then
  331. begin
  332. if ispowerof2(elesize, power) then
  333. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,NR_EDI))
  334. else
  335. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,elesize,NR_EDI));
  336. end;
  337. end
  338. else
  339. {$endif __NOWINPECOFF__}
  340. list.concat(Taicpu.op_reg_reg(A_SUB,S_L,NR_EDI,NR_ESP));
  341. { align stack on 4 bytes }
  342. list.concat(Taicpu.op_const_reg(A_AND,S_L,aint($fffffff4),NR_ESP));
  343. { load destination, don't use a_load_reg_reg, that will add a move instruction
  344. that can confuse the reg allocator }
  345. list.concat(Taicpu.Op_reg_reg(A_MOV,S_L,NR_ESP,NR_EDI));
  346. { Allocate other registers }
  347. getcpuregister(list,NR_ECX);
  348. getcpuregister(list,NR_ESI);
  349. { load count }
  350. a_load_loc_reg(list,OS_INT,lenloc,NR_ECX);
  351. { load source }
  352. a_loadaddr_ref_reg(list,ref,NR_ESI);
  353. { scheduled .... }
  354. list.concat(Taicpu.op_reg(A_INC,S_L,NR_ECX));
  355. { calculate size }
  356. len:=elesize;
  357. opsize:=S_B;
  358. if (len and 3)=0 then
  359. begin
  360. opsize:=S_L;
  361. len:=len shr 2;
  362. end
  363. else
  364. if (len and 1)=0 then
  365. begin
  366. opsize:=S_W;
  367. len:=len shr 1;
  368. end;
  369. if len<>0 then
  370. begin
  371. if ispowerof2(len, power) then
  372. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,NR_ECX))
  373. else
  374. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,len,NR_ECX));
  375. end;
  376. list.concat(Taicpu.op_none(A_REP,S_NO));
  377. case opsize of
  378. S_B : list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  379. S_W : list.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  380. S_L : list.concat(Taicpu.Op_none(A_MOVSD,S_NO));
  381. end;
  382. ungetcpuregister(list,NR_EDI);
  383. ungetcpuregister(list,NR_ECX);
  384. ungetcpuregister(list,NR_ESI);
  385. { patch the new address, but don't use a_load_reg_reg, that will add a move instruction
  386. that can confuse the reg allocator }
  387. list.concat(Taicpu.Op_reg_reg(A_MOV,S_L,NR_ESP,destreg));
  388. end;
  389. procedure tcg386.g_exception_reason_save(list : taasmoutput; const href : treference);
  390. begin
  391. if not use_fixed_stack then
  392. list.concat(Taicpu.op_reg(A_PUSH,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG))
  393. else
  394. inherited g_exception_reason_save(list,href);
  395. end;
  396. procedure tcg386.g_exception_reason_save_const(list : taasmoutput;const href : treference; a: aint);
  397. begin
  398. if not use_fixed_stack then
  399. list.concat(Taicpu.op_const(A_PUSH,tcgsize2opsize[OS_INT],a))
  400. else
  401. inherited g_exception_reason_save_const(list,href,a);
  402. end;
  403. procedure tcg386.g_exception_reason_load(list : taasmoutput; const href : treference);
  404. begin
  405. if not use_fixed_stack then
  406. list.concat(Taicpu.op_reg(A_POP,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG))
  407. else
  408. inherited g_exception_reason_load(list,href);
  409. end;
  410. procedure tcg386.g_intf_wrapper(list: TAAsmoutput; procdef: tprocdef; const labelname: string; ioffset: longint);
  411. {
  412. possible calling conventions:
  413. default stdcall cdecl pascal register
  414. default(0): OK OK OK(1) OK OK
  415. virtual(2): OK OK OK(3) OK OK
  416. (0):
  417. set self parameter to correct value
  418. jmp mangledname
  419. (1): The code is the following
  420. set self parameter to correct value
  421. call mangledname
  422. set self parameter to interface value
  423. (2): The wrapper code use %eax to reach the virtual method address
  424. set self to correct value
  425. move self,%eax
  426. mov 0(%eax),%eax ; load vmt
  427. jmp vmtoffs(%eax) ; method offs
  428. (3): The wrapper code use %eax to reach the virtual method address
  429. set self to correct value
  430. move self,%eax
  431. mov 0(%eax),%eax ; load vmt
  432. jmp vmtoffs(%eax) ; method offs
  433. set self parameter to interface value
  434. (4): Virtual use values pushed on stack to reach the method address
  435. so the following code be generated:
  436. set self to correct value
  437. push %ebx ; allocate space for function address
  438. push %eax
  439. mov self,%eax
  440. mov 0(%eax),%eax ; load vmt
  441. mov vmtoffs(%eax),eax ; method offs
  442. mov %eax,4(%esp)
  443. pop %eax
  444. ret 0; jmp the address
  445. }
  446. procedure getselftoeax(offs: longint);
  447. var
  448. href : treference;
  449. selfoffsetfromsp : longint;
  450. begin
  451. { mov offset(%esp),%eax }
  452. if (procdef.proccalloption<>pocall_register) then
  453. begin
  454. { framepointer is pushed for nested procs }
  455. if procdef.parast.symtablelevel>normal_function_level then
  456. selfoffsetfromsp:=2*sizeof(aint)
  457. else
  458. selfoffsetfromsp:=sizeof(aint);
  459. reference_reset_base(href,NR_ESP,selfoffsetfromsp+offs);
  460. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_EAX);
  461. end;
  462. end;
  463. procedure loadvmttoeax;
  464. var
  465. href : treference;
  466. begin
  467. { mov 0(%eax),%eax ; load vmt}
  468. reference_reset_base(href,NR_EAX,0);
  469. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_EAX);
  470. end;
  471. procedure op_oneaxmethodaddr(op: TAsmOp);
  472. var
  473. href : treference;
  474. begin
  475. if (procdef.extnumber=$ffff) then
  476. Internalerror(200006139);
  477. { call/jmp vmtoffs(%eax) ; method offs }
  478. reference_reset_base(href,NR_EAX,procdef._class.vmtmethodoffset(procdef.extnumber));
  479. list.concat(taicpu.op_ref(op,S_L,href));
  480. end;
  481. procedure loadmethodoffstoeax;
  482. var
  483. href : treference;
  484. begin
  485. if (procdef.extnumber=$ffff) then
  486. Internalerror(200006139);
  487. { mov vmtoffs(%eax),%eax ; method offs }
  488. reference_reset_base(href,NR_EAX,procdef._class.vmtmethodoffset(procdef.extnumber));
  489. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_EAX);
  490. end;
  491. var
  492. lab : tasmsymbol;
  493. make_global : boolean;
  494. href : treference;
  495. begin
  496. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  497. Internalerror(200006137);
  498. if not assigned(procdef._class) or
  499. (procdef.procoptions*[po_classmethod, po_staticmethod,
  500. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  501. Internalerror(200006138);
  502. if procdef.owner.symtabletype<>objectsymtable then
  503. Internalerror(200109191);
  504. make_global:=false;
  505. if (not current_module.is_unit) or
  506. (cs_create_smart in aktmoduleswitches) or
  507. (af_smartlink_sections in target_asm.flags) or
  508. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  509. make_global:=true;
  510. if make_global then
  511. List.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  512. else
  513. List.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  514. { set param1 interface to self }
  515. g_adjust_self_value(list,procdef,ioffset);
  516. { case 1 or 2 }
  517. if (procdef.proccalloption in clearstack_pocalls) then
  518. begin
  519. if po_virtualmethod in procdef.procoptions then
  520. begin
  521. { case 2 }
  522. getselftoeax(0);
  523. loadvmttoeax;
  524. op_oneaxmethodaddr(A_CALL);
  525. end
  526. else
  527. begin
  528. { case 1 }
  529. cg.a_call_name(list,procdef.mangledname);
  530. end;
  531. { restore param1 value self to interface }
  532. g_adjust_self_value(list,procdef,-ioffset);
  533. end
  534. else if po_virtualmethod in procdef.procoptions then
  535. begin
  536. if (procdef.proccalloption=pocall_register) then
  537. begin
  538. { case 4 }
  539. list.concat(taicpu.op_reg(A_PUSH,S_L,NR_EBX)); { allocate space for address}
  540. list.concat(taicpu.op_reg(A_PUSH,S_L,NR_EAX));
  541. getselftoeax(8);
  542. loadvmttoeax;
  543. loadmethodoffstoeax;
  544. { mov %eax,4(%esp) }
  545. reference_reset_base(href,NR_ESP,4);
  546. list.concat(taicpu.op_reg_ref(A_MOV,S_L,NR_EAX,href));
  547. { pop %eax }
  548. list.concat(taicpu.op_reg(A_POP,S_L,NR_EAX));
  549. { ret ; jump to the address }
  550. list.concat(taicpu.op_none(A_RET,S_L));
  551. end
  552. else
  553. begin
  554. { case 3 }
  555. getselftoeax(0);
  556. loadvmttoeax;
  557. op_oneaxmethodaddr(A_JMP);
  558. end;
  559. end
  560. { case 0 }
  561. else
  562. begin
  563. lab:=objectlibrary.newasmsymbol(procdef.mangledname,AB_EXTERNAL,AT_FUNCTION);
  564. list.concat(taicpu.op_sym(A_JMP,S_NO,lab));
  565. end;
  566. List.concat(Tai_symbol_end.Createname(labelname));
  567. end;
  568. { ************* 64bit operations ************ }
  569. procedure tcg64f386.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  570. begin
  571. case op of
  572. OP_ADD :
  573. begin
  574. op1:=A_ADD;
  575. op2:=A_ADC;
  576. end;
  577. OP_SUB :
  578. begin
  579. op1:=A_SUB;
  580. op2:=A_SBB;
  581. end;
  582. OP_XOR :
  583. begin
  584. op1:=A_XOR;
  585. op2:=A_XOR;
  586. end;
  587. OP_OR :
  588. begin
  589. op1:=A_OR;
  590. op2:=A_OR;
  591. end;
  592. OP_AND :
  593. begin
  594. op1:=A_AND;
  595. op2:=A_AND;
  596. end;
  597. else
  598. internalerror(200203241);
  599. end;
  600. end;
  601. procedure tcg64f386.a_op64_ref_reg(list : taasmoutput;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);
  602. var
  603. op1,op2 : TAsmOp;
  604. tempref : treference;
  605. begin
  606. get_64bit_ops(op,op1,op2);
  607. list.concat(taicpu.op_ref_reg(op1,S_L,ref,reg.reglo));
  608. tempref:=ref;
  609. inc(tempref.offset,4);
  610. list.concat(taicpu.op_ref_reg(op2,S_L,tempref,reg.reghi));
  611. end;
  612. procedure tcg64f386.a_op64_reg_reg(list : taasmoutput;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  613. var
  614. op1,op2 : TAsmOp;
  615. begin
  616. case op of
  617. OP_NEG :
  618. begin
  619. if (regsrc.reglo<>regdst.reglo) then
  620. a_load64_reg_reg(list,regsrc,regdst);
  621. list.concat(taicpu.op_reg(A_NOT,S_L,regdst.reghi));
  622. list.concat(taicpu.op_reg(A_NEG,S_L,regdst.reglo));
  623. list.concat(taicpu.op_const_reg(A_SBB,S_L,-1,regdst.reghi));
  624. exit;
  625. end;
  626. OP_NOT :
  627. begin
  628. if (regsrc.reglo<>regdst.reglo) then
  629. a_load64_reg_reg(list,regsrc,regdst);
  630. list.concat(taicpu.op_reg(A_NOT,S_L,regdst.reghi));
  631. list.concat(taicpu.op_reg(A_NOT,S_L,regdst.reglo));
  632. exit;
  633. end;
  634. end;
  635. get_64bit_ops(op,op1,op2);
  636. list.concat(taicpu.op_reg_reg(op1,S_L,regsrc.reglo,regdst.reglo));
  637. list.concat(taicpu.op_reg_reg(op2,S_L,regsrc.reghi,regdst.reghi));
  638. end;
  639. procedure tcg64f386.a_op64_const_reg(list : taasmoutput;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  640. var
  641. op1,op2 : TAsmOp;
  642. begin
  643. case op of
  644. OP_AND,OP_OR,OP_XOR:
  645. begin
  646. cg.a_op_const_reg(list,op,OS_32,aint(lo(value)),reg.reglo);
  647. cg.a_op_const_reg(list,op,OS_32,aint(hi(value)),reg.reghi);
  648. end;
  649. OP_ADD, OP_SUB:
  650. begin
  651. // can't use a_op_const_ref because this may use dec/inc
  652. get_64bit_ops(op,op1,op2);
  653. list.concat(taicpu.op_const_reg(op1,S_L,aint(lo(value)),reg.reglo));
  654. list.concat(taicpu.op_const_reg(op2,S_L,aint(hi(value)),reg.reghi));
  655. end;
  656. else
  657. internalerror(200204021);
  658. end;
  659. end;
  660. procedure tcg64f386.a_op64_const_ref(list : taasmoutput;op:TOpCG;size : tcgsize;value : int64;const ref : treference);
  661. var
  662. op1,op2 : TAsmOp;
  663. tempref : treference;
  664. begin
  665. case op of
  666. OP_AND,OP_OR,OP_XOR:
  667. begin
  668. cg.a_op_const_ref(list,op,OS_32,lo(value),ref);
  669. tempref:=ref;
  670. inc(tempref.offset,4);
  671. cg.a_op_const_ref(list,op,OS_32,hi(value),tempref);
  672. end;
  673. OP_ADD, OP_SUB:
  674. begin
  675. get_64bit_ops(op,op1,op2);
  676. // can't use a_op_const_ref because this may use dec/inc
  677. list.concat(taicpu.op_const_ref(op1,S_L,lo(value),ref));
  678. tempref:=ref;
  679. inc(tempref.offset,4);
  680. list.concat(taicpu.op_const_ref(op2,S_L,hi(value),tempref));
  681. end;
  682. else
  683. internalerror(200204022);
  684. end;
  685. end;
  686. begin
  687. cg := tcg386.create;
  688. cg64 := tcg64f386.create;
  689. end.