cgcpu.pas 27 KB

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