cgcpu.pas 29 KB

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