cgcpu.pas 27 KB

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