cgcpu.pas 27 KB

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