cgcpu.pas 28 KB

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