cgcpu.pas 28 KB

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