cgcpu.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements the code generator for the i386
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cgcpu;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,
  23. cgbase,cgobj,cg64f32,cgx86,
  24. aasmbase,aasmtai,aasmcpu,
  25. cpubase,parabase,cgutils,
  26. symconst,symdef
  27. ;
  28. type
  29. tcg386 = class(tcgx86)
  30. procedure init_register_allocators;override;
  31. { passing parameter using push instead of mov }
  32. procedure a_param_reg(list : taasmoutput;size : tcgsize;r : tregister;const cgpara : tcgpara);override;
  33. procedure a_param_const(list : taasmoutput;size : tcgsize;a : aint;const cgpara : tcgpara);override;
  34. procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const cgpara : tcgpara);override;
  35. procedure a_paramaddr_ref(list : taasmoutput;const r : treference;const cgpara : tcgpara);override;
  36. procedure g_proc_exit(list : taasmoutput;parasize:longint;nostackframe:boolean);override;
  37. procedure g_copyvaluepara_openarray(list : taasmoutput;const ref:treference;const lenloc:tlocation;elesize:aint;destreg:tregister);override;
  38. procedure g_exception_reason_save(list : taasmoutput; const href : treference);override;
  39. procedure g_exception_reason_save_const(list : taasmoutput; const href : treference; a: aint);override;
  40. procedure g_exception_reason_load(list : taasmoutput; const href : treference);override;
  41. procedure g_intf_wrapper(list: TAAsmoutput; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  42. end;
  43. tcg64f386 = class(tcg64f32)
  44. procedure a_op64_ref_reg(list : taasmoutput;op:TOpCG;const ref : treference;reg : tregister64);override;
  45. procedure a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);override;
  46. procedure a_op64_const_reg(list : taasmoutput;op:TOpCG;value : int64;reg : tregister64);override;
  47. procedure a_op64_const_ref(list : taasmoutput;op:TOpCG;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:=assigned(cgpara.location) and
  59. (cgpara.location^.loc=LOC_REFERENCE) and
  60. (cgpara.location^.reference.index=NR_STACK_POINTER_REG);
  61. end;
  62. procedure Tcg386.init_register_allocators;
  63. begin
  64. inherited init_register_allocators;
  65. if cs_create_pic in aktmoduleswitches then
  66. 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])
  67. else
  68. 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]);
  69. 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,[]);
  70. 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,[]);
  71. rgfpu:=Trgx86fpu.create;
  72. end;
  73. procedure tcg386.a_param_reg(list : taasmoutput;size : tcgsize;r : tregister;const cgpara : tcgpara);
  74. var
  75. pushsize : tcgsize;
  76. begin
  77. check_register_size(size,r);
  78. if use_push(cgpara) then
  79. begin
  80. cgpara.check_simple_location;
  81. pushsize:=int_cgsize(cgpara.alignment);
  82. list.concat(taicpu.op_reg(A_PUSH,tcgsize2opsize[pushsize],makeregsize(list,r,pushsize)));
  83. end
  84. else
  85. inherited a_param_reg(list,size,r,cgpara);
  86. end;
  87. procedure tcg386.a_param_const(list : taasmoutput;size : tcgsize;a : aint;const cgpara : tcgpara);
  88. var
  89. pushsize : tcgsize;
  90. begin
  91. if use_push(cgpara) then
  92. begin
  93. cgpara.check_simple_location;
  94. pushsize:=int_cgsize(cgpara.alignment);
  95. list.concat(taicpu.op_const(A_PUSH,tcgsize2opsize[pushsize],a));
  96. end
  97. else
  98. inherited a_param_const(list,size,a,cgpara);
  99. end;
  100. procedure tcg386.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const cgpara : tcgpara);
  101. procedure pushdata(paraloc:pcgparalocation;ofs:aint);
  102. var
  103. pushsize : tcgsize;
  104. tmpreg : tregister;
  105. href : treference;
  106. begin
  107. if not assigned(paraloc) then
  108. exit;
  109. if (paraloc^.loc<>LOC_REFERENCE) or
  110. (paraloc^.reference.index<>NR_STACK_POINTER_REG) or
  111. (tcgsize2size[paraloc^.size]>sizeof(aint)) then
  112. internalerror(200501162);
  113. { Pushes are needed in reverse order, add the size of the
  114. current location to the offset where to load from. This
  115. prevents wrong calculations for the last location when
  116. the size is not a power of 2 }
  117. if assigned(paraloc^.next) then
  118. pushdata(paraloc^.next,ofs+tcgsize2size[paraloc^.size]);
  119. { Push the data starting at ofs }
  120. href:=r;
  121. inc(href.offset,ofs);
  122. if tcgsize2size[paraloc^.size]>cgpara.alignment then
  123. pushsize:=paraloc^.size
  124. else
  125. pushsize:=int_cgsize(cgpara.alignment);
  126. if tcgsize2size[paraloc^.size]<cgpara.alignment then
  127. begin
  128. tmpreg:=getintregister(list,pushsize);
  129. a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg);
  130. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize],tmpreg));
  131. end
  132. else
  133. list.concat(taicpu.op_ref(A_PUSH,TCgsize2opsize[pushsize],href));
  134. end;
  135. var
  136. len : aint;
  137. href : treference;
  138. begin
  139. { cgpara.size=OS_NO requires a copy on the stack }
  140. if use_push(cgpara) then
  141. begin
  142. { Record copy? }
  143. if (cgpara.size=OS_NO) or (size=OS_NO) then
  144. begin
  145. cgpara.check_simple_location;
  146. len:=align(cgpara.intsize,cgpara.alignment);
  147. g_stackpointer_alloc(list,len);
  148. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  149. g_concatcopy(list,r,href,len);
  150. end
  151. else
  152. begin
  153. if tcgsize2size[cgpara.size]<>tcgsize2size[size] then
  154. internalerror(200501161);
  155. { We need to push the data in reverse order,
  156. therefor we use a recursive algorithm }
  157. pushdata(cgpara.location,0);
  158. end
  159. end
  160. else
  161. inherited a_param_ref(list,size,r,cgpara);
  162. end;
  163. procedure tcg386.a_paramaddr_ref(list : taasmoutput;const r : treference;const cgpara : tcgpara);
  164. var
  165. tmpreg : tregister;
  166. opsize : topsize;
  167. begin
  168. with r do
  169. begin
  170. if (segment<>NR_NO) then
  171. cgmessage(cg_e_cant_use_far_pointer_there);
  172. if use_push(cgpara) then
  173. begin
  174. cgpara.check_simple_location;
  175. opsize:=tcgsize2opsize[OS_ADDR];
  176. if (base=NR_NO) and (index=NR_NO) then
  177. begin
  178. if assigned(symbol) then
  179. list.concat(Taicpu.Op_sym_ofs(A_PUSH,opsize,symbol,offset))
  180. else
  181. list.concat(Taicpu.Op_const(A_PUSH,opsize,offset));
  182. end
  183. else if (base=NR_NO) and (index<>NR_NO) and
  184. (offset=0) and (scalefactor=0) and (symbol=nil) then
  185. list.concat(Taicpu.Op_reg(A_PUSH,opsize,index))
  186. else if (base<>NR_NO) and (index=NR_NO) and
  187. (offset=0) and (symbol=nil) then
  188. list.concat(Taicpu.Op_reg(A_PUSH,opsize,base))
  189. else
  190. begin
  191. tmpreg:=getaddressregister(list);
  192. a_loadaddr_ref_reg(list,r,tmpreg);
  193. list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
  194. end;
  195. end
  196. else
  197. inherited a_paramaddr_ref(list,r,cgpara);
  198. end;
  199. end;
  200. procedure tcg386.g_proc_exit(list : taasmoutput;parasize:longint;nostackframe:boolean);
  201. var
  202. stacksize : longint;
  203. begin
  204. { Release PIC register }
  205. if cs_create_pic in aktmoduleswitches then
  206. list.concat(tai_regalloc.dealloc(NR_PIC_OFFSET_REG,nil));
  207. { MMX needs to call EMMS }
  208. if assigned(rg[R_MMXREGISTER]) and
  209. (rg[R_MMXREGISTER].uses_registers) then
  210. list.concat(Taicpu.op_none(A_EMMS,S_NO));
  211. { remove stackframe }
  212. if not nostackframe then
  213. begin
  214. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  215. begin
  216. stacksize:=current_procinfo.calc_stackframe_size;
  217. if (stacksize<>0) then
  218. cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);
  219. end
  220. else
  221. list.concat(Taicpu.op_none(A_LEAVE,S_NO));
  222. list.concat(tai_regalloc.dealloc(NR_FRAME_POINTER_REG,nil));
  223. end;
  224. { return from proc }
  225. if (po_interrupt in current_procinfo.procdef.procoptions) then
  226. begin
  227. if (current_procinfo.procdef.funcretloc[calleeside].loc<>LOC_VOID) and
  228. (current_procinfo.procdef.funcretloc[calleeside].loc=LOC_REGISTER) then
  229. list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,NR_ESP))
  230. else
  231. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EAX));
  232. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EBX));
  233. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_ECX));
  234. if (current_procinfo.procdef.funcretloc[calleeside].loc=LOC_REGISTER) and
  235. (current_procinfo.procdef.funcretloc[calleeside].size in [OS_64,OS_S64]) 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_EDX));
  239. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_ESI));
  240. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EDI));
  241. { .... also the segment registers }
  242. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DS));
  243. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_ES));
  244. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_FS));
  245. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_GS));
  246. { this restores the flags }
  247. list.concat(Taicpu.Op_none(A_IRET,S_NO));
  248. end
  249. { Routines with the poclearstack flag set use only a ret }
  250. else if current_procinfo.procdef.proccalloption in clearstack_pocalls then
  251. begin
  252. { complex return values are removed from stack in C code PM }
  253. if paramanager.ret_in_param(current_procinfo.procdef.rettype.def,
  254. current_procinfo.procdef.proccalloption) then
  255. list.concat(Taicpu.Op_const(A_RET,S_NO,sizeof(aint)))
  256. else
  257. list.concat(Taicpu.Op_none(A_RET,S_NO));
  258. end
  259. { ... also routines with parasize=0 }
  260. else if (parasize=0) then
  261. list.concat(Taicpu.Op_none(A_RET,S_NO))
  262. else
  263. begin
  264. { parameters are limited to 65535 bytes because ret allows only imm16 }
  265. if (parasize>65535) then
  266. CGMessage(cg_e_parasize_too_big);
  267. list.concat(Taicpu.Op_const(A_RET,S_NO,parasize));
  268. end;
  269. end;
  270. procedure tcg386.g_copyvaluepara_openarray(list : taasmoutput;const ref:treference;const lenloc:tlocation;elesize:aint;destreg:tregister);
  271. var
  272. power,len : longint;
  273. opsize : topsize;
  274. {$ifndef __NOWINPECOFF__}
  275. again,ok : tasmlabel;
  276. {$endif}
  277. begin
  278. { get stack space }
  279. getcpuregister(list,NR_EDI);
  280. a_load_loc_reg(list,OS_INT,lenloc,NR_EDI);
  281. list.concat(Taicpu.op_reg(A_INC,S_L,NR_EDI));
  282. if (elesize<>1) then
  283. begin
  284. if ispowerof2(elesize, power) then
  285. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,NR_EDI))
  286. else
  287. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,elesize,NR_EDI));
  288. end;
  289. {$ifndef __NOWINPECOFF__}
  290. { windows guards only a few pages for stack growing, }
  291. { so we have to access every page first }
  292. if target_info.system=system_i386_win32 then
  293. begin
  294. objectlibrary.getlabel(again);
  295. objectlibrary.getlabel(ok);
  296. a_label(list,again);
  297. list.concat(Taicpu.op_const_reg(A_CMP,S_L,winstackpagesize,NR_EDI));
  298. a_jmp_cond(list,OC_B,ok);
  299. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,NR_ESP));
  300. list.concat(Taicpu.op_reg(A_PUSH,S_L,NR_EDI));
  301. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize,NR_EDI));
  302. a_jmp_always(list,again);
  303. a_label(list,ok);
  304. list.concat(Taicpu.op_reg_reg(A_SUB,S_L,NR_EDI,NR_ESP));
  305. ungetcpuregister(list,NR_EDI);
  306. { now reload EDI }
  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. end
  318. else
  319. {$endif __NOWINPECOFF__}
  320. list.concat(Taicpu.op_reg_reg(A_SUB,S_L,NR_EDI,NR_ESP));
  321. { align stack on 4 bytes }
  322. list.concat(Taicpu.op_const_reg(A_AND,S_L,aint($fffffff4),NR_ESP));
  323. { load destination, don't use a_load_reg_reg, that will add a move instruction
  324. that can confuse the reg allocator }
  325. list.concat(Taicpu.Op_reg_reg(A_MOV,S_L,NR_ESP,NR_EDI));
  326. { Allocate other registers }
  327. getcpuregister(list,NR_ECX);
  328. getcpuregister(list,NR_ESI);
  329. { load count }
  330. a_load_loc_reg(list,OS_INT,lenloc,NR_ECX);
  331. { load source }
  332. a_loadaddr_ref_reg(list,ref,NR_ESI);
  333. { scheduled .... }
  334. list.concat(Taicpu.op_reg(A_INC,S_L,NR_ECX));
  335. { calculate size }
  336. len:=elesize;
  337. opsize:=S_B;
  338. if (len and 3)=0 then
  339. begin
  340. opsize:=S_L;
  341. len:=len shr 2;
  342. end
  343. else
  344. if (len and 1)=0 then
  345. begin
  346. opsize:=S_W;
  347. len:=len shr 1;
  348. end;
  349. if len<>0 then
  350. begin
  351. if ispowerof2(len, power) then
  352. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,NR_ECX))
  353. else
  354. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,len,NR_ECX));
  355. end;
  356. list.concat(Taicpu.op_none(A_REP,S_NO));
  357. case opsize of
  358. S_B : list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  359. S_W : list.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  360. S_L : list.concat(Taicpu.Op_none(A_MOVSD,S_NO));
  361. end;
  362. ungetcpuregister(list,NR_EDI);
  363. ungetcpuregister(list,NR_ECX);
  364. ungetcpuregister(list,NR_ESI);
  365. { patch the new address, but don't use a_load_reg_reg, that will add a move instruction
  366. that can confuse the reg allocator }
  367. list.concat(Taicpu.Op_reg_reg(A_MOV,S_L,NR_ESP,destreg));
  368. end;
  369. procedure tcg386.g_exception_reason_save(list : taasmoutput; const href : treference);
  370. begin
  371. list.concat(Taicpu.op_reg(A_PUSH,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG));
  372. end;
  373. procedure tcg386.g_exception_reason_save_const(list : taasmoutput;const href : treference; a: aint);
  374. begin
  375. list.concat(Taicpu.op_const(A_PUSH,tcgsize2opsize[OS_INT],a));
  376. end;
  377. procedure tcg386.g_exception_reason_load(list : taasmoutput; const href : treference);
  378. begin
  379. list.concat(Taicpu.op_reg(A_POP,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG));
  380. end;
  381. procedure tcg386.g_intf_wrapper(list: TAAsmoutput; procdef: tprocdef; const labelname: string; ioffset: longint);
  382. {
  383. possible calling conventions:
  384. default stdcall cdecl pascal register
  385. default(0): OK OK OK(1) OK OK
  386. virtual(2): OK OK OK(3) OK OK
  387. (0):
  388. set self parameter to correct value
  389. jmp mangledname
  390. (1): The code is the following
  391. set self parameter to correct value
  392. call mangledname
  393. set self parameter to interface value
  394. (2): The wrapper code use %eax to reach the virtual method address
  395. set self to correct value
  396. move self,%eax
  397. mov 0(%eax),%eax ; load vmt
  398. jmp vmtoffs(%eax) ; method offs
  399. (3): 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. set self parameter to interface value
  405. (4): Virtual use values pushed on stack to reach the method address
  406. so the following code be generated:
  407. set self to correct value
  408. push %ebx ; allocate space for function address
  409. push %eax
  410. mov self,%eax
  411. mov 0(%eax),%eax ; load vmt
  412. mov vmtoffs(%eax),eax ; method offs
  413. mov %eax,4(%esp)
  414. pop %eax
  415. ret 0; jmp the address
  416. }
  417. procedure getselftoeax(offs: longint);
  418. var
  419. href : treference;
  420. selfoffsetfromsp : longint;
  421. begin
  422. { mov offset(%esp),%eax }
  423. if (procdef.proccalloption<>pocall_register) then
  424. begin
  425. { framepointer is pushed for nested procs }
  426. if procdef.parast.symtablelevel>normal_function_level then
  427. selfoffsetfromsp:=2*sizeof(aint)
  428. else
  429. selfoffsetfromsp:=sizeof(aint);
  430. reference_reset_base(href,NR_ESP,selfoffsetfromsp+offs);
  431. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_EAX);
  432. end;
  433. end;
  434. procedure loadvmttoeax;
  435. var
  436. href : treference;
  437. begin
  438. { mov 0(%eax),%eax ; load vmt}
  439. reference_reset_base(href,NR_EAX,0);
  440. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_EAX);
  441. end;
  442. procedure op_oneaxmethodaddr(op: TAsmOp);
  443. var
  444. href : treference;
  445. begin
  446. if (procdef.extnumber=$ffff) then
  447. Internalerror(200006139);
  448. { call/jmp vmtoffs(%eax) ; method offs }
  449. reference_reset_base(href,NR_EAX,procdef._class.vmtmethodoffset(procdef.extnumber));
  450. list.concat(taicpu.op_ref(op,S_L,href));
  451. end;
  452. procedure loadmethodoffstoeax;
  453. var
  454. href : treference;
  455. begin
  456. if (procdef.extnumber=$ffff) then
  457. Internalerror(200006139);
  458. { mov vmtoffs(%eax),%eax ; method offs }
  459. reference_reset_base(href,NR_EAX,procdef._class.vmtmethodoffset(procdef.extnumber));
  460. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_EAX);
  461. end;
  462. var
  463. lab : tasmsymbol;
  464. make_global : boolean;
  465. href : treference;
  466. begin
  467. if procdef.proctypeoption<>potype_none then
  468. Internalerror(200006137);
  469. if not assigned(procdef._class) or
  470. (procdef.procoptions*[po_classmethod, po_staticmethod,
  471. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  472. Internalerror(200006138);
  473. if procdef.owner.symtabletype<>objectsymtable then
  474. Internalerror(200109191);
  475. make_global:=false;
  476. if (not current_module.is_unit) or
  477. (cs_create_smart in aktmoduleswitches) or
  478. (af_smartlink_sections in target_asm.flags) or
  479. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  480. make_global:=true;
  481. if make_global then
  482. List.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  483. else
  484. List.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  485. { set param1 interface to self }
  486. g_adjust_self_value(list,procdef,ioffset);
  487. { case 1 or 2 }
  488. if (procdef.proccalloption in clearstack_pocalls) then
  489. begin
  490. if po_virtualmethod in procdef.procoptions then
  491. begin
  492. { case 2 }
  493. getselftoeax(0);
  494. loadvmttoeax;
  495. op_oneaxmethodaddr(A_CALL);
  496. end
  497. else
  498. begin
  499. { case 1 }
  500. cg.a_call_name(list,procdef.mangledname);
  501. end;
  502. { restore param1 value self to interface }
  503. g_adjust_self_value(list,procdef,-ioffset);
  504. end
  505. else if po_virtualmethod in procdef.procoptions then
  506. begin
  507. if (procdef.proccalloption=pocall_register) then
  508. begin
  509. { case 4 }
  510. list.concat(taicpu.op_reg(A_PUSH,S_L,NR_EBX)); { allocate space for address}
  511. list.concat(taicpu.op_reg(A_PUSH,S_L,NR_EAX));
  512. getselftoeax(8);
  513. loadvmttoeax;
  514. loadmethodoffstoeax;
  515. { mov %eax,4(%esp) }
  516. reference_reset_base(href,NR_ESP,4);
  517. list.concat(taicpu.op_reg_ref(A_MOV,S_L,NR_EAX,href));
  518. { pop %eax }
  519. list.concat(taicpu.op_reg(A_POP,S_L,NR_EAX));
  520. { ret ; jump to the address }
  521. list.concat(taicpu.op_none(A_RET,S_L));
  522. end
  523. else
  524. begin
  525. { case 3 }
  526. getselftoeax(0);
  527. loadvmttoeax;
  528. op_oneaxmethodaddr(A_JMP);
  529. end;
  530. end
  531. { case 0 }
  532. else
  533. begin
  534. lab:=objectlibrary.newasmsymbol(procdef.mangledname,AB_EXTERNAL,AT_FUNCTION);
  535. list.concat(taicpu.op_sym(A_JMP,S_NO,lab));
  536. end;
  537. List.concat(Tai_symbol_end.Createname(labelname));
  538. end;
  539. { ************* 64bit operations ************ }
  540. procedure tcg64f386.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  541. begin
  542. case op of
  543. OP_ADD :
  544. begin
  545. op1:=A_ADD;
  546. op2:=A_ADC;
  547. end;
  548. OP_SUB :
  549. begin
  550. op1:=A_SUB;
  551. op2:=A_SBB;
  552. end;
  553. OP_XOR :
  554. begin
  555. op1:=A_XOR;
  556. op2:=A_XOR;
  557. end;
  558. OP_OR :
  559. begin
  560. op1:=A_OR;
  561. op2:=A_OR;
  562. end;
  563. OP_AND :
  564. begin
  565. op1:=A_AND;
  566. op2:=A_AND;
  567. end;
  568. else
  569. internalerror(200203241);
  570. end;
  571. end;
  572. procedure tcg64f386.a_op64_ref_reg(list : taasmoutput;op:TOpCG;const ref : treference;reg : tregister64);
  573. var
  574. op1,op2 : TAsmOp;
  575. tempref : treference;
  576. begin
  577. get_64bit_ops(op,op1,op2);
  578. list.concat(taicpu.op_ref_reg(op1,S_L,ref,reg.reglo));
  579. tempref:=ref;
  580. inc(tempref.offset,4);
  581. list.concat(taicpu.op_ref_reg(op2,S_L,tempref,reg.reghi));
  582. end;
  583. procedure tcg64f386.a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);
  584. var
  585. op1,op2 : TAsmOp;
  586. begin
  587. case op of
  588. OP_NEG :
  589. begin
  590. if (regsrc.reglo<>regdst.reglo) then
  591. a_load64_reg_reg(list,regsrc,regdst);
  592. list.concat(taicpu.op_reg(A_NOT,S_L,regdst.reghi));
  593. list.concat(taicpu.op_reg(A_NEG,S_L,regdst.reglo));
  594. list.concat(taicpu.op_const_reg(A_SBB,S_L,-1,regdst.reghi));
  595. exit;
  596. end;
  597. OP_NOT :
  598. begin
  599. if (regsrc.reglo<>regdst.reglo) then
  600. a_load64_reg_reg(list,regsrc,regdst);
  601. list.concat(taicpu.op_reg(A_NOT,S_L,regdst.reghi));
  602. list.concat(taicpu.op_reg(A_NOT,S_L,regdst.reglo));
  603. exit;
  604. end;
  605. end;
  606. get_64bit_ops(op,op1,op2);
  607. list.concat(taicpu.op_reg_reg(op1,S_L,regsrc.reglo,regdst.reglo));
  608. list.concat(taicpu.op_reg_reg(op2,S_L,regsrc.reghi,regdst.reghi));
  609. end;
  610. procedure tcg64f386.a_op64_const_reg(list : taasmoutput;op:TOpCG;value : int64;reg : tregister64);
  611. var
  612. op1,op2 : TAsmOp;
  613. begin
  614. case op of
  615. OP_AND,OP_OR,OP_XOR:
  616. begin
  617. cg.a_op_const_reg(list,op,OS_32,aint(lo(value)),reg.reglo);
  618. cg.a_op_const_reg(list,op,OS_32,aint(hi(value)),reg.reghi);
  619. end;
  620. OP_ADD, OP_SUB:
  621. begin
  622. // can't use a_op_const_ref because this may use dec/inc
  623. get_64bit_ops(op,op1,op2);
  624. list.concat(taicpu.op_const_reg(op1,S_L,aint(lo(value)),reg.reglo));
  625. list.concat(taicpu.op_const_reg(op2,S_L,aint(hi(value)),reg.reghi));
  626. end;
  627. else
  628. internalerror(200204021);
  629. end;
  630. end;
  631. procedure tcg64f386.a_op64_const_ref(list : taasmoutput;op:TOpCG;value : int64;const ref : treference);
  632. var
  633. op1,op2 : TAsmOp;
  634. tempref : treference;
  635. begin
  636. case op of
  637. OP_AND,OP_OR,OP_XOR:
  638. begin
  639. cg.a_op_const_ref(list,op,OS_32,lo(value),ref);
  640. tempref:=ref;
  641. inc(tempref.offset,4);
  642. cg.a_op_const_ref(list,op,OS_32,hi(value),tempref);
  643. end;
  644. OP_ADD, OP_SUB:
  645. begin
  646. get_64bit_ops(op,op1,op2);
  647. // can't use a_op_const_ref because this may use dec/inc
  648. list.concat(taicpu.op_const_ref(op1,S_L,lo(value),ref));
  649. tempref:=ref;
  650. inc(tempref.offset,4);
  651. list.concat(taicpu.op_const_ref(op2,S_L,hi(value),tempref));
  652. end;
  653. else
  654. internalerror(200204022);
  655. end;
  656. end;
  657. begin
  658. cg := tcg386.create;
  659. cg64 := tcg64f386.create;
  660. end.
  661. {
  662. $Log$
  663. Revision 1.65 2005-02-03 17:10:21 peter
  664. * fix win32 small array parameters
  665. Revision 1.64 2005/01/24 22:08:32 peter
  666. * interface wrapper generation moved to cgobj
  667. * generate interface wrappers after the module is parsed
  668. Revision 1.63 2005/01/18 22:19:20 peter
  669. * multiple location support for i386 a_param_ref
  670. * remove a_param_copy_ref for i386
  671. Revision 1.62 2004/11/21 17:54:59 peter
  672. * ttempcreatenode.create_reg merged into .create with parameter
  673. whether a register is allowed
  674. * funcret_paraloc renamed to funcretloc
  675. Revision 1.61 2004/11/21 17:17:04 florian
  676. * changed funcret location back to tlocation
  677. Revision 1.60 2004/10/31 21:45:03 peter
  678. * generic tlocation
  679. * move tlocation to cgutils
  680. Revision 1.59 2004/10/24 20:01:08 peter
  681. * remove saveregister calling convention
  682. Revision 1.58 2004/10/24 11:44:28 peter
  683. * small regvar fixes
  684. * loadref parameter removed from concatcopy,incrrefcount,etc
  685. Revision 1.57 2004/10/15 09:16:21 mazen
  686. - remove $IFDEF DELPHI and related code
  687. - remove $IFDEF FPCPROCVAR and related code
  688. Revision 1.56 2004/10/13 21:12:51 peter
  689. * -Or fixes for open array
  690. Revision 1.55 2004/10/11 15:46:45 peter
  691. * length parameter for copyvaluearray changed to tlocation
  692. Revision 1.54 2004/10/05 20:41:01 peter
  693. * more spilling rewrites
  694. Revision 1.53 2004/09/25 14:23:54 peter
  695. * ungetregister is now only used for cpuregisters, renamed to
  696. ungetcpuregister
  697. * renamed (get|unget)explicitregister(s) to ..cpuregister
  698. * removed location-release/reference_release
  699. Revision 1.52 2004/09/21 17:25:12 peter
  700. * paraloc branch merged
  701. Revision 1.51.4.1 2004/08/31 20:43:06 peter
  702. * paraloc patch
  703. Revision 1.51 2004/07/09 23:30:13 jonas
  704. * changed first_sse_imreg to first_mm_imreg
  705. Revision 1.50 2004/06/20 08:55:31 florian
  706. * logs truncated
  707. Revision 1.49 2004/06/16 20:07:10 florian
  708. * dwarf branch merged
  709. Revision 1.48 2004/04/09 14:36:05 peter
  710. * A_MOVSL renamed to A_MOVSD
  711. Revision 1.47.2.9 2004/05/30 10:45:50 peter
  712. * merged fixes from main branch
  713. Revision 1.47.2.8 2004/05/02 21:34:01 florian
  714. * i386 compilation fixed
  715. Revision 1.47.2.7 2004/05/02 12:45:32 peter
  716. * enabled cpuhasfixedstack for x86-64 again
  717. * fixed size of temp allocation for parameters
  718. }