cgcpu.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. {
  2. Copyright (c) 2002 by Florian Klaempfl
  3. This unit implements the code generator for the x86-64.
  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. cgbase,cgutils,cgobj,cgx86,
  22. aasmbase,aasmtai,aasmdata,aasmcpu,
  23. cpubase,cpuinfo,cpupara,parabase,
  24. symdef,
  25. node,symconst,rgx86,procinfo;
  26. type
  27. tcgx86_64 = class(tcgx86)
  28. procedure init_register_allocators;override;
  29. procedure a_loadfpu_ref_cgpara(list: TAsmList; size: tcgsize; const ref: treference; const cgpara: TCGPara); override;
  30. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
  31. procedure g_proc_entry(list : TAsmList;localsize:longint; nostackframe:boolean);override;
  32. procedure g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);override;
  33. procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  34. procedure g_local_unwind(list: TAsmList; l: TAsmLabel);override;
  35. procedure g_save_registers(list: TAsmList);override;
  36. procedure g_restore_registers(list: TAsmList);override;
  37. procedure a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize;intreg, mmreg: tregister; shuffle: pmmshuffle); override;
  38. procedure a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize : tcgsize;mmreg, intreg: tregister;shuffle : pmmshuffle); override;
  39. private
  40. function use_push: boolean;
  41. function saved_xmm_reg_size: longint;
  42. end;
  43. procedure create_codegen;
  44. implementation
  45. uses
  46. globtype,globals,verbose,systems,cutils,cclasses,
  47. symsym,symtable,defutil,paramgr,fmodule,cpupi,
  48. rgobj,tgobj,rgcpu,ncgutil;
  49. procedure Tcgx86_64.init_register_allocators;
  50. const
  51. win64_saved_std_regs : array[0..7] of tsuperregister = (RS_RBX,RS_RDI,RS_RSI,RS_R12,RS_R13,RS_R14,RS_R15,RS_RBP);
  52. others_saved_std_regs : array[0..4] of tsuperregister = (RS_RBX,RS_R12,RS_R13,RS_R14,RS_R15);
  53. saved_regs_length : array[boolean] of longint = (5,7);
  54. win64_saved_xmm_regs : array[0..9] of tsuperregister = (RS_XMM6,RS_XMM7,
  55. RS_XMM8,RS_XMM9,RS_XMM10,RS_XMM11,RS_XMM12,RS_XMM13,RS_XMM14,RS_XMM15);
  56. var
  57. i : longint;
  58. begin
  59. inherited init_register_allocators;
  60. if (length(saved_standard_registers)<>saved_regs_length[target_info.system=system_x86_64_win64]) then
  61. begin
  62. if target_info.system=system_x86_64_win64 then
  63. begin
  64. SetLength(saved_standard_registers,Length(win64_saved_std_regs));
  65. SetLength(saved_mm_registers,Length(win64_saved_xmm_regs));
  66. for i:=low(win64_saved_std_regs) to high(win64_saved_std_regs) do
  67. saved_standard_registers[i]:=win64_saved_std_regs[i];
  68. for i:=low(win64_saved_xmm_regs) to high(win64_saved_xmm_regs) do
  69. saved_mm_registers[i]:=win64_saved_xmm_regs[i];
  70. end
  71. else
  72. begin
  73. SetLength(saved_standard_registers,Length(others_saved_std_regs));
  74. SetLength(saved_mm_registers,0);
  75. for i:=low(others_saved_std_regs) to high(others_saved_std_regs) do
  76. saved_standard_registers[i]:=others_saved_std_regs[i];
  77. end;
  78. end;
  79. if target_info.system=system_x86_64_win64 then
  80. begin
  81. if (cs_userbp in current_settings.optimizerswitches) and assigned(current_procinfo) and (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  82. begin
  83. rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_RAX,RS_RDX,RS_RCX,RS_R8,RS_R9,RS_R10,
  84. RS_R11,RS_RBX,RS_RSI,RS_RDI,RS_R12,RS_R13,RS_R14,RS_R15,RS_RBP],first_int_imreg,[]);
  85. end
  86. else
  87. rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_RAX,RS_RDX,RS_RCX,RS_R8,RS_R9,RS_R10,
  88. RS_R11,RS_RBX,RS_RSI,RS_RDI,RS_R12,RS_R13,RS_R14,RS_R15],first_int_imreg,[])
  89. end
  90. else
  91. rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_RAX,RS_RDX,RS_RCX,RS_RSI,RS_RDI,RS_R8,
  92. RS_R9,RS_R10,RS_R11,RS_RBX,RS_R12,RS_R13,RS_R14,RS_R15],first_int_imreg,[]);
  93. 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,
  94. RS_XMM8,RS_XMM9,RS_XMM10,RS_XMM11,RS_XMM12,RS_XMM13,RS_XMM14,RS_XMM15],first_mm_imreg,[]);
  95. rgfpu:=Trgx86fpu.create;
  96. end;
  97. procedure tcgx86_64.a_loadfpu_ref_cgpara(list: TAsmList; size: tcgsize; const ref: treference; const cgpara: TCGPara);
  98. begin
  99. { a record containing an extended value is returned on the x87 stack
  100. -> size will be OS_F128 (if not packed), while cgpara.paraloc^.size
  101. contains the proper size
  102. In the future we should probably always use cgpara.location^.size, but
  103. that should only be tested/done after 2.8 is branched }
  104. if size in [OS_128,OS_F128] then
  105. size:=cgpara.location^.size;
  106. inherited;
  107. end;
  108. procedure tcgx86_64.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  109. begin
  110. { same as with a_loadfpu_ref_cgpara() above, but on the callee side
  111. when the value is moved from the fpu register into a memory location }
  112. if tosize in [OS_128,OS_F128] then
  113. tosize:=OS_F80;
  114. inherited;
  115. end;
  116. function tcgx86_64.use_push: boolean;
  117. begin
  118. result:=(current_procinfo.framepointer=NR_STACK_POINTER_REG) or
  119. (current_procinfo.procdef.proctypeoption=potype_exceptfilter);
  120. end;
  121. function tcgx86_64.saved_xmm_reg_size: longint;
  122. var
  123. i: longint;
  124. begin
  125. result:=0;
  126. if (target_info.system<>system_x86_64_win64) or
  127. (not uses_registers(R_MMREGISTER)) then
  128. exit;
  129. for i:=low(saved_mm_registers) to high(saved_mm_registers) do
  130. begin
  131. if (saved_mm_registers[i] in rg[R_MMREGISTER].used_in_proc) then
  132. inc(result,tcgsize2size[OS_VECTOR]);
  133. end;
  134. end;
  135. procedure tcgx86_64.g_proc_entry(list : TAsmList;localsize:longint;nostackframe:boolean);
  136. var
  137. hitem: tlinkedlistitem;
  138. r: integer;
  139. href: treference;
  140. templist: TAsmList;
  141. frame_offset: longint;
  142. suppress_endprologue: boolean;
  143. stackmisalignment: longint;
  144. xmmsize: longint;
  145. procedure push_one_reg(reg: tregister);
  146. begin
  147. list.concat(taicpu.op_reg(A_PUSH,tcgsize2opsize[OS_ADDR],reg));
  148. if (target_info.system=system_x86_64_win64) then
  149. begin
  150. list.concat(cai_seh_directive.create_reg(ash_pushreg,reg));
  151. include(current_procinfo.flags,pi_has_unwind_info);
  152. end;
  153. end;
  154. procedure push_regs;
  155. var
  156. r: longint;
  157. begin
  158. for r := low(saved_standard_registers) to high(saved_standard_registers) do
  159. if saved_standard_registers[r] in rg[R_INTREGISTER].used_in_proc then
  160. begin
  161. inc(stackmisalignment,sizeof(pint));
  162. push_one_reg(newreg(R_INTREGISTER,saved_standard_registers[r],R_SUBWHOLE));
  163. end;
  164. end;
  165. begin
  166. hitem:=list.last;
  167. { pi_has_unwind_info may already be set at this point if there are
  168. SEH directives in assembler body. In this case, .seh_endprologue
  169. is expected to be one of those directives, and not generated here. }
  170. suppress_endprologue:=(pi_has_unwind_info in current_procinfo.flags);
  171. { save old framepointer }
  172. if not nostackframe then
  173. begin
  174. { return address }
  175. stackmisalignment := sizeof(pint);
  176. list.concat(tai_regalloc.alloc(current_procinfo.framepointer,nil));
  177. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  178. begin
  179. push_regs;
  180. CGmessage(cg_d_stackframe_omited);
  181. end
  182. else
  183. begin
  184. { push <frame_pointer> }
  185. inc(stackmisalignment,sizeof(pint));
  186. push_one_reg(NR_FRAME_POINTER_REG);
  187. { Return address and FP are both on stack }
  188. current_asmdata.asmcfi.cfa_def_cfa_offset(list,2*sizeof(pint));
  189. current_asmdata.asmcfi.cfa_offset(list,NR_FRAME_POINTER_REG,-(2*sizeof(pint)));
  190. if current_procinfo.procdef.proctypeoption<>potype_exceptfilter then
  191. list.concat(Taicpu.op_reg_reg(A_MOV,tcgsize2opsize[OS_ADDR],NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG))
  192. else
  193. begin
  194. push_regs;
  195. gen_load_frame_for_exceptfilter(list);
  196. { Need only as much stack space as necessary to do the calls.
  197. Exception filters don't have own local vars, and temps are 'mapped'
  198. to the parent procedure.
  199. maxpushedparasize is already aligned at least on x86_64. }
  200. localsize:=current_procinfo.maxpushedparasize;
  201. end;
  202. current_asmdata.asmcfi.cfa_def_cfa_register(list,NR_FRAME_POINTER_REG);
  203. {
  204. TODO: current framepointer handling is not compatible with Win64 at all:
  205. Win64 expects FP to point to the top or into the middle of local area.
  206. In FPC it points to the bottom, making it impossible to generate
  207. UWOP_SET_FPREG unwind code if local area is > 240 bytes.
  208. So for now pretend we never have a framepointer.
  209. }
  210. end;
  211. xmmsize:=saved_xmm_reg_size;
  212. if use_push and (xmmsize<>0) then
  213. begin
  214. localsize:=align(localsize,target_info.stackalign)+xmmsize;
  215. reference_reset_base(current_procinfo.save_regs_ref,NR_STACK_POINTER_REG,
  216. localsize-xmmsize,tcgsize2size[OS_VECTOR]);
  217. end;
  218. { allocate stackframe space }
  219. if (localsize<>0) or
  220. ((target_info.stackalign>sizeof(pint)) and
  221. (stackmisalignment <> 0) and
  222. ((pi_do_call in current_procinfo.flags) or
  223. (po_assembler in current_procinfo.procdef.procoptions))) then
  224. begin
  225. if target_info.stackalign>sizeof(pint) then
  226. localsize := align(localsize+stackmisalignment,target_info.stackalign)-stackmisalignment;
  227. cg.g_stackpointer_alloc(list,localsize);
  228. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  229. current_asmdata.asmcfi.cfa_def_cfa_offset(list,localsize+sizeof(pint));
  230. current_procinfo.final_localsize:=localsize;
  231. if (target_info.system=system_x86_64_win64) then
  232. begin
  233. if localsize<>0 then
  234. list.concat(cai_seh_directive.create_offset(ash_stackalloc,localsize));
  235. include(current_procinfo.flags,pi_has_unwind_info);
  236. if use_push and (xmmsize<>0) then
  237. begin
  238. href:=current_procinfo.save_regs_ref;
  239. for r:=low(saved_mm_registers) to high(saved_mm_registers) do
  240. if saved_mm_registers[r] in rg[R_MMREGISTER].used_in_proc then
  241. begin
  242. a_loadmm_reg_ref(list,OS_VECTOR,OS_VECTOR,newreg(R_MMREGISTER,saved_mm_registers[r],R_SUBMMWHOLE),href,nil);
  243. inc(href.offset,tcgsize2size[OS_VECTOR]);
  244. end;
  245. end;
  246. end;
  247. end;
  248. end;
  249. if not (pi_has_unwind_info in current_procinfo.flags) then
  250. exit;
  251. { Generate unwind data for x86_64-win64 }
  252. list.insertafter(cai_seh_directive.create_name(ash_proc,current_procinfo.procdef.mangledname),hitem);
  253. templist:=TAsmList.Create;
  254. { We need to record postive offsets from RSP; if registers are saved
  255. at negative offsets from RBP we need to account for it. }
  256. if (not use_push) then
  257. frame_offset:=current_procinfo.final_localsize
  258. else
  259. frame_offset:=0;
  260. { There's no need to describe position of register saves precisely;
  261. since registers are not modified before they are saved, and saves do not
  262. change RSP, 'logically' all saves can happen at the end of prologue. }
  263. href:=current_procinfo.save_regs_ref;
  264. if (not use_push) then
  265. begin
  266. for r:=low(saved_standard_registers) to high(saved_standard_registers) do
  267. if saved_standard_registers[r] in rg[R_INTREGISTER].used_in_proc then
  268. begin
  269. templist.concat(cai_seh_directive.create_reg_offset(ash_savereg,
  270. newreg(R_INTREGISTER,saved_standard_registers[r],R_SUBWHOLE),
  271. href.offset+frame_offset));
  272. inc(href.offset,sizeof(aint));
  273. end;
  274. end;
  275. if uses_registers(R_MMREGISTER) then
  276. begin
  277. if (href.offset mod tcgsize2size[OS_VECTOR])<>0 then
  278. inc(href.offset,tcgsize2size[OS_VECTOR]-(href.offset mod tcgsize2size[OS_VECTOR]));
  279. for r:=low(saved_mm_registers) to high(saved_mm_registers) do
  280. begin
  281. if saved_mm_registers[r] in rg[R_MMREGISTER].used_in_proc then
  282. begin
  283. templist.concat(cai_seh_directive.create_reg_offset(ash_savexmm,
  284. newreg(R_MMREGISTER,saved_mm_registers[r],R_SUBMMWHOLE),
  285. href.offset+frame_offset));
  286. inc(href.offset,tcgsize2size[OS_VECTOR]);
  287. end;
  288. end;
  289. end;
  290. if not suppress_endprologue then
  291. templist.concat(cai_seh_directive.create(ash_endprologue));
  292. if assigned(current_procinfo.endprologue_ai) then
  293. current_procinfo.aktproccode.insertlistafter(current_procinfo.endprologue_ai,templist)
  294. else
  295. list.concatlist(templist);
  296. templist.free;
  297. end;
  298. procedure tcgx86_64.g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);
  299. procedure increase_sp(a : tcgint);
  300. var
  301. href : treference;
  302. begin
  303. reference_reset_base(href,NR_STACK_POINTER_REG,a,0);
  304. { normally, lea is a better choice than an add }
  305. list.concat(Taicpu.op_ref_reg(A_LEA,TCGSize2OpSize[OS_ADDR],href,NR_STACK_POINTER_REG));
  306. end;
  307. var
  308. href : treference;
  309. hreg : tregister;
  310. r : longint;
  311. begin
  312. { Prevent return address from a possible call from ending up in the epilogue }
  313. { (restoring registers happens before epilogue, providing necessary padding) }
  314. if (current_procinfo.flags*[pi_has_unwind_info,pi_do_call,pi_has_saved_regs])=[pi_has_unwind_info,pi_do_call] then
  315. list.concat(Taicpu.op_none(A_NOP));
  316. { remove stackframe }
  317. if not nostackframe then
  318. begin
  319. if use_push then
  320. begin
  321. if (saved_xmm_reg_size<>0) then
  322. begin
  323. href:=current_procinfo.save_regs_ref;
  324. for r:=low(saved_mm_registers) to high(saved_mm_registers) do
  325. if saved_mm_registers[r] in rg[R_MMREGISTER].used_in_proc then
  326. begin
  327. { Allocate register so the optimizer does not remove the load }
  328. hreg:=newreg(R_MMREGISTER,saved_mm_registers[r],R_SUBMMWHOLE);
  329. a_reg_alloc(list,hreg);
  330. a_loadmm_ref_reg(list,OS_VECTOR,OS_VECTOR,href,hreg,nil);
  331. inc(href.offset,tcgsize2size[OS_VECTOR]);
  332. end;
  333. end;
  334. if (current_procinfo.final_localsize<>0) then
  335. increase_sp(current_procinfo.final_localsize);
  336. internal_restore_regs(list,true);
  337. if (current_procinfo.procdef.proctypeoption=potype_exceptfilter) then
  338. list.concat(Taicpu.op_reg(A_POP,tcgsize2opsize[OS_ADDR],NR_FRAME_POINTER_REG));
  339. end
  340. else if (target_info.system=system_x86_64_win64) then
  341. begin
  342. { Comply with Win64 unwinding mechanism, which only recognizes
  343. 'add $constant,%rsp' and 'lea offset(FPREG),%rsp' as belonging to
  344. the function epilog.
  345. Neither 'leave' nor even 'mov %FPREG,%rsp' are allowed. }
  346. reference_reset_base(href,current_procinfo.framepointer,0,sizeof(pint));
  347. list.concat(Taicpu.op_ref_reg(A_LEA,tcgsize2opsize[OS_ADDR],href,NR_STACK_POINTER_REG));
  348. list.concat(Taicpu.op_reg(A_POP,tcgsize2opsize[OS_ADDR],current_procinfo.framepointer));
  349. end
  350. else
  351. generate_leave(list);
  352. list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
  353. end;
  354. list.concat(Taicpu.Op_none(A_RET,S_NO));
  355. if (pi_has_unwind_info in current_procinfo.flags) then
  356. begin
  357. tx86_64procinfo(current_procinfo).dump_scopes(list);
  358. list.concat(cai_seh_directive.create(ash_endproc));
  359. end;
  360. end;
  361. procedure tcgx86_64.g_save_registers(list: TAsmList);
  362. begin
  363. if (not use_push) then
  364. inherited g_save_registers(list);
  365. end;
  366. procedure tcgx86_64.g_restore_registers(list: TAsmList);
  367. begin
  368. if (not use_push) then
  369. inherited g_restore_registers(list);
  370. end;
  371. procedure tcgx86_64.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  372. var
  373. make_global : boolean;
  374. href : treference;
  375. sym : tasmsymbol;
  376. r : treference;
  377. begin
  378. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  379. Internalerror(200006137);
  380. if not assigned(procdef.struct) or
  381. (procdef.procoptions*[po_classmethod, po_staticmethod,
  382. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  383. Internalerror(200006138);
  384. if procdef.owner.symtabletype<>ObjectSymtable then
  385. Internalerror(200109191);
  386. make_global:=false;
  387. if (not current_module.is_unit) or create_smartlink or
  388. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  389. make_global:=true;
  390. if make_global then
  391. List.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  392. else
  393. List.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  394. { set param1 interface to self }
  395. g_adjust_self_value(list,procdef,ioffset);
  396. if (po_virtualmethod in procdef.procoptions) and
  397. not is_objectpascal_helper(procdef.struct) then
  398. begin
  399. if (procdef.extnumber=$ffff) then
  400. Internalerror(200006139);
  401. { load vmt from first paramter }
  402. { win64 uses a different abi }
  403. if target_info.system=system_x86_64_win64 then
  404. reference_reset_base(href,NR_RCX,0,sizeof(pint))
  405. else
  406. reference_reset_base(href,NR_RDI,0,sizeof(pint));
  407. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_RAX);
  408. { jmp *vmtoffs(%eax) ; method offs }
  409. reference_reset_base(href,NR_RAX,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),sizeof(pint));
  410. list.concat(taicpu.op_ref(A_JMP,S_Q,href));
  411. end
  412. else
  413. begin
  414. sym:=current_asmdata.RefAsmSymbol(procdef.mangledname);
  415. reference_reset_symbol(r,sym,0,sizeof(pint));
  416. if (cs_create_pic in current_settings.moduleswitches) and
  417. { darwin/x86_64's assembler doesn't want @PLT after call symbols }
  418. not(target_info.system in systems_darwin) then
  419. r.refaddr:=addr_pic
  420. else
  421. r.refaddr:=addr_full;
  422. list.concat(taicpu.op_ref(A_JMP,S_NO,r));
  423. end;
  424. List.concat(Tai_symbol_end.Createname(labelname));
  425. end;
  426. procedure tcgx86_64.g_local_unwind(list: TAsmList; l: TAsmLabel);
  427. var
  428. para1,para2: tcgpara;
  429. href: treference;
  430. pd: tprocdef;
  431. begin
  432. if (target_info.system<>system_x86_64_win64) then
  433. begin
  434. inherited g_local_unwind(list,l);
  435. exit;
  436. end;
  437. pd:=search_system_proc('_fpc_local_unwind');
  438. para1.init;
  439. para2.init;
  440. paramanager.getintparaloc(pd,1,para1);
  441. paramanager.getintparaloc(pd,2,para2);
  442. reference_reset_symbol(href,l,0,1);
  443. { TODO: using RSP is correct only while the stack is fixed!!
  444. (true now, but will change if/when allocating from stack is implemented) }
  445. a_load_reg_cgpara(list,OS_ADDR,NR_STACK_POINTER_REG,para1);
  446. a_loadaddr_ref_cgpara(list,href,para2);
  447. paramanager.freecgpara(list,para2);
  448. paramanager.freecgpara(list,para1);
  449. g_call(list,'_FPC_local_unwind');
  450. para2.done;
  451. para1.done;
  452. end;
  453. procedure tcgx86_64.a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize; intreg, mmreg: tregister; shuffle: pmmshuffle);
  454. var
  455. opc: tasmop;
  456. begin
  457. { this code can only be used to transfer raw data, not to perform
  458. conversions }
  459. if (tcgsize2size[fromsize]<>tcgsize2size[tosize]) or
  460. not(tosize in [OS_F32,OS_F64,OS_M64]) then
  461. internalerror(2009112505);
  462. case fromsize of
  463. OS_32,OS_S32:
  464. opc:=A_MOVD;
  465. OS_64,OS_S64:
  466. opc:=A_MOVQ;
  467. else
  468. internalerror(2009112506);
  469. end;
  470. if assigned(shuffle) and
  471. not shufflescalar(shuffle) then
  472. internalerror(2009112517);
  473. list.concat(taicpu.op_reg_reg(opc,S_NO,intreg,mmreg));
  474. end;
  475. procedure tcgx86_64.a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize : tcgsize; mmreg, intreg: tregister;shuffle : pmmshuffle);
  476. var
  477. opc: tasmop;
  478. begin
  479. { this code can only be used to transfer raw data, not to perform
  480. conversions }
  481. if (tcgsize2size[fromsize]<>tcgsize2size[tosize]) or
  482. not (fromsize in [OS_F32,OS_F64,OS_M64]) then
  483. internalerror(2009112507);
  484. case tosize of
  485. OS_32,OS_S32:
  486. opc:=A_MOVD;
  487. OS_64,OS_S64:
  488. opc:=A_MOVQ;
  489. else
  490. internalerror(2009112408);
  491. end;
  492. if assigned(shuffle) and
  493. not shufflescalar(shuffle) then
  494. internalerror(2009112515);
  495. list.concat(taicpu.op_reg_reg(opc,S_NO,mmreg,intreg));
  496. end;
  497. procedure create_codegen;
  498. begin
  499. cg:=tcgx86_64.create;
  500. cg128:=tcg128.create;
  501. end;
  502. end.