cgcpu.pas 27 KB

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