cgcpu.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  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,parabase,
  24. symdef,
  25. 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_local_unwind(list: TAsmList; l: TAsmLabel);override;
  34. procedure g_save_registers(list: TAsmList);override;
  35. procedure g_restore_registers(list: TAsmList);override;
  36. procedure a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize;intreg, mmreg: tregister; shuffle: pmmshuffle); override;
  37. procedure a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize : tcgsize;mmreg, intreg: tregister;shuffle : pmmshuffle); override;
  38. function use_ms_abi: boolean;
  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. cpuinfo,
  48. symtable,paramgr,cpupi,
  49. rgcpu,ncgutil;
  50. procedure Tcgx86_64.init_register_allocators;
  51. var
  52. ms_abi: boolean;
  53. begin
  54. inherited init_register_allocators;
  55. ms_abi:=use_ms_abi;
  56. if ms_abi then
  57. begin
  58. if (cs_userbp in current_settings.optimizerswitches) and assigned(current_procinfo) and (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  59. begin
  60. rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_RAX,RS_RDX,RS_RCX,RS_R8,RS_R9,RS_R10,
  61. RS_R11,RS_RBX,RS_RSI,RS_RDI,RS_R12,RS_R13,RS_R14,RS_R15,RS_RBP],first_int_imreg,[]);
  62. end
  63. else
  64. rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_RAX,RS_RDX,RS_RCX,RS_R8,RS_R9,RS_R10,
  65. RS_R11,RS_RBX,RS_RSI,RS_RDI,RS_R12,RS_R13,RS_R14,RS_R15],first_int_imreg,[])
  66. end
  67. else
  68. rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_RAX,RS_RDX,RS_RCX,RS_RSI,RS_RDI,RS_R8,
  69. RS_R9,RS_R10,RS_R11,RS_RBX,RS_R12,RS_R13,RS_R14,RS_R15],first_int_imreg,[]);
  70. if FPUX86_HAS_32MMREGS in fpu_capabilities[current_settings.fputype] then
  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,
  72. RS_XMM8,RS_XMM9,RS_XMM10,RS_XMM11,RS_XMM12,RS_XMM13,RS_XMM14,RS_XMM15,RS_XMM16,RS_XMM17,RS_XMM18,RS_XMM19,RS_XMM20,
  73. RS_XMM21,RS_XMM22,RS_XMM23,RS_XMM24,RS_XMM25,RS_XMM26,RS_XMM27,RS_XMM28,RS_XMM29,RS_XMM30,RS_XMM31],first_mm_imreg,[])
  74. else
  75. 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,
  76. RS_XMM8,RS_XMM9,RS_XMM10,RS_XMM11,RS_XMM12,RS_XMM13,RS_XMM14,RS_XMM15],first_mm_imreg,[]);
  77. rgfpu:=Trgx86fpu.create;
  78. end;
  79. procedure tcgx86_64.a_loadfpu_ref_cgpara(list: TAsmList; size: tcgsize; const ref: treference; const cgpara: TCGPara);
  80. begin
  81. { a record containing an extended value is returned on the x87 stack
  82. -> size will be OS_F128 (if not packed), while cgpara.paraloc^.size
  83. contains the proper size
  84. In the future we should probably always use cgpara.location^.size, but
  85. that should only be tested/done after 2.8 is branched }
  86. if size in [OS_128,OS_F128] then
  87. size:=cgpara.location^.size;
  88. inherited;
  89. end;
  90. procedure tcgx86_64.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  91. begin
  92. { same as with a_loadfpu_ref_cgpara() above, but on the callee side
  93. when the value is moved from the fpu register into a memory location }
  94. if tosize in [OS_128,OS_F128] then
  95. tosize:=OS_F80;
  96. inherited;
  97. end;
  98. function tcgx86_64.use_push: boolean;
  99. begin
  100. result:=(current_procinfo.framepointer=NR_STACK_POINTER_REG) or
  101. (current_procinfo.procdef.proctypeoption=potype_exceptfilter);
  102. end;
  103. function tcgx86_64.saved_xmm_reg_size: longint;
  104. var
  105. i: longint;
  106. regs_to_save_mm: tcpuregisterarray;
  107. begin
  108. result:=0;
  109. if (target_info.system<>system_x86_64_win64) or
  110. (not uses_registers(R_MMREGISTER)) then
  111. exit;
  112. regs_to_save_mm:=paramanager.get_saved_registers_mm(current_procinfo.procdef.proccalloption);
  113. for i:=low(regs_to_save_mm) to high(regs_to_save_mm) do
  114. begin
  115. if (regs_to_save_mm[i] in rg[R_MMREGISTER].used_in_proc) then
  116. inc(result,tcgsize2size[OS_VECTOR]);
  117. end;
  118. end;
  119. procedure tcgx86_64.g_proc_entry(list : TAsmList;localsize:longint;nostackframe:boolean);
  120. var
  121. hitem: tlinkedlistitem;
  122. seh_proc: tai_seh_directive;
  123. regsize: longint;
  124. r: integer;
  125. href: treference;
  126. templist: TAsmList;
  127. frame_offset: longint;
  128. suppress_endprologue: boolean;
  129. stackmisalignment: longint;
  130. xmmsize: longint;
  131. regs_to_save_int,
  132. regs_to_save_mm: tcpuregisterarray;
  133. procedure push_one_reg(reg: tregister);
  134. begin
  135. list.concat(taicpu.op_reg(A_PUSH,tcgsize2opsize[OS_ADDR],reg));
  136. if (target_info.system=system_x86_64_win64) then
  137. begin
  138. list.concat(cai_seh_directive.create_reg(ash_pushreg,reg));
  139. include(current_procinfo.flags,pi_has_unwind_info);
  140. end;
  141. end;
  142. procedure push_regs;
  143. var
  144. r: longint;
  145. usedregs: tcpuregisterset;
  146. hreg: TRegister;
  147. begin
  148. usedregs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(current_procinfo.procdef.proccalloption);
  149. for r := low(regs_to_save_int) to high(regs_to_save_int) do
  150. if regs_to_save_int[r] in usedregs then
  151. begin
  152. inc(regsize,sizeof(aint));
  153. inc(stackmisalignment,sizeof(aint));
  154. hreg:=newreg(R_INTREGISTER,regs_to_save_int[r],R_SUBWHOLE);
  155. push_one_reg(hreg);
  156. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  157. current_asmdata.asmcfi.cfa_offset(list,hreg,-(regsize+sizeof(pint)*2+localsize))
  158. else
  159. begin
  160. current_asmdata.asmcfi.cfa_offset(list,hreg,-(regsize+sizeof(pint)+localsize));
  161. current_asmdata.asmcfi.cfa_def_cfa_offset(list,regsize+sizeof(pint)+localsize);
  162. end;
  163. end;
  164. end;
  165. begin
  166. regsize:=0;
  167. regs_to_save_int:=paramanager.get_saved_registers_int(current_procinfo.procdef.proccalloption);
  168. regs_to_save_mm:=paramanager.get_saved_registers_mm(current_procinfo.procdef.proccalloption);
  169. hitem:=list.last;
  170. { pi_has_unwind_info may already be set at this point if there are
  171. SEH directives in assembler body. In this case, .seh_endprologue
  172. is expected to be one of those directives, and not generated here. }
  173. suppress_endprologue:=(pi_has_unwind_info in current_procinfo.flags);
  174. list.concat(tai_regalloc.alloc(NR_STACK_POINTER_REG,nil));
  175. { save old framepointer }
  176. if not nostackframe then
  177. begin
  178. { return address }
  179. stackmisalignment := sizeof(pint);
  180. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  181. begin
  182. push_regs;
  183. CGmessage(cg_d_stackframe_omited);
  184. end
  185. else
  186. begin
  187. list.concat(tai_regalloc.alloc(current_procinfo.framepointer,nil));
  188. { push <frame_pointer> }
  189. inc(stackmisalignment,sizeof(pint));
  190. push_one_reg(NR_FRAME_POINTER_REG);
  191. { Return address and FP are both on stack }
  192. current_asmdata.asmcfi.cfa_def_cfa_offset(list,2*sizeof(pint));
  193. current_asmdata.asmcfi.cfa_offset(list,NR_FRAME_POINTER_REG,-(2*sizeof(pint)));
  194. if current_procinfo.procdef.proctypeoption<>potype_exceptfilter then
  195. list.concat(Taicpu.op_reg_reg(A_MOV,tcgsize2opsize[OS_ADDR],NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG))
  196. else
  197. begin
  198. push_regs;
  199. gen_load_frame_for_exceptfilter(list);
  200. { Need only as much stack space as necessary to do the calls.
  201. Exception filters don't have own local vars, and temps are 'mapped'
  202. to the parent procedure.
  203. maxpushedparasize is already aligned at least on x86_64. }
  204. localsize:=current_procinfo.maxpushedparasize;
  205. end;
  206. current_asmdata.asmcfi.cfa_def_cfa_register(list,NR_FRAME_POINTER_REG);
  207. {
  208. TODO: current framepointer handling is not compatible with Win64 at all:
  209. Win64 expects FP to point to the top or into the middle of local area.
  210. In FPC it points to the bottom, making it impossible to generate
  211. UWOP_SET_FPREG unwind code if local area is > 240 bytes.
  212. So for now pretend we never have a framepointer.
  213. }
  214. end;
  215. xmmsize:=saved_xmm_reg_size;
  216. if use_push and (xmmsize<>0) then
  217. begin
  218. localsize:=align(localsize,target_info.stackalign)+xmmsize;
  219. reference_reset_base(current_procinfo.save_regs_ref,NR_STACK_POINTER_REG,
  220. localsize-xmmsize,ctempposinvalid,tcgsize2size[OS_VECTOR],[]);
  221. end;
  222. { allocate stackframe space }
  223. if (localsize<>0) or
  224. ((target_info.stackalign>sizeof(pint)) and
  225. (stackmisalignment <> 0) and
  226. ((pi_do_call in current_procinfo.flags) or
  227. (po_assembler in current_procinfo.procdef.procoptions))) then
  228. begin
  229. if target_info.stackalign>sizeof(pint) then
  230. localsize := align(localsize+stackmisalignment,target_info.stackalign)-stackmisalignment;
  231. g_stackpointer_alloc(list,localsize);
  232. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  233. current_asmdata.asmcfi.cfa_def_cfa_offset(list,regsize+localsize+sizeof(pint));
  234. current_procinfo.final_localsize:=localsize;
  235. if (target_info.system=system_x86_64_win64) then
  236. begin
  237. if localsize<>0 then
  238. list.concat(cai_seh_directive.create_offset(ash_stackalloc,localsize));
  239. include(current_procinfo.flags,pi_has_unwind_info);
  240. if use_push and (xmmsize<>0) then
  241. begin
  242. href:=current_procinfo.save_regs_ref;
  243. for r:=low(regs_to_save_mm) to high(regs_to_save_mm) do
  244. if regs_to_save_mm[r] in rg[R_MMREGISTER].used_in_proc then
  245. begin
  246. a_loadmm_reg_ref(list,OS_VECTOR,OS_VECTOR,newreg(R_MMREGISTER,regs_to_save_mm[r],R_SUBMMWHOLE),href,nil);
  247. inc(href.offset,tcgsize2size[OS_VECTOR]);
  248. end;
  249. end;
  250. end;
  251. end;
  252. end;
  253. if not (pi_has_unwind_info in current_procinfo.flags) then
  254. exit;
  255. { Generate unwind data for x86_64-win64 }
  256. seh_proc:=cai_seh_directive.create_name(ash_proc,current_procinfo.procdef.mangledname);
  257. if assigned(hitem) then
  258. list.insertafter(seh_proc,hitem)
  259. else
  260. list.insert(seh_proc);
  261. { the directive creates another section }
  262. inc(list.section_count);
  263. templist:=TAsmList.Create;
  264. { We need to record postive offsets from RSP; if registers are saved
  265. at negative offsets from RBP we need to account for it. }
  266. if (not use_push) then
  267. frame_offset:=current_procinfo.final_localsize
  268. else
  269. frame_offset:=0;
  270. { There's no need to describe position of register saves precisely;
  271. since registers are not modified before they are saved, and saves do not
  272. change RSP, 'logically' all saves can happen at the end of prologue. }
  273. href:=current_procinfo.save_regs_ref;
  274. if (not use_push) then
  275. begin
  276. for r:=low(regs_to_save_int) to high(regs_to_save_int) do
  277. if regs_to_save_int[r] in rg[R_INTREGISTER].used_in_proc then
  278. begin
  279. templist.concat(cai_seh_directive.create_reg_offset(ash_savereg,
  280. newreg(R_INTREGISTER,regs_to_save_int[r],R_SUBWHOLE),
  281. href.offset+frame_offset));
  282. inc(href.offset,sizeof(aint));
  283. end;
  284. end;
  285. if uses_registers(R_MMREGISTER) then
  286. begin
  287. if (href.offset mod tcgsize2size[OS_VECTOR])<>0 then
  288. inc(href.offset,tcgsize2size[OS_VECTOR]-(href.offset mod tcgsize2size[OS_VECTOR]));
  289. for r:=low(regs_to_save_mm) to high(regs_to_save_mm) do
  290. begin
  291. if regs_to_save_mm[r] in rg[R_MMREGISTER].used_in_proc then
  292. begin
  293. templist.concat(cai_seh_directive.create_reg_offset(ash_savexmm,
  294. newreg(R_MMREGISTER,regs_to_save_mm[r],R_SUBMMWHOLE),
  295. href.offset+frame_offset));
  296. inc(href.offset,tcgsize2size[OS_VECTOR]);
  297. end;
  298. end;
  299. end;
  300. if not suppress_endprologue then
  301. templist.concat(cai_seh_directive.create(ash_endprologue));
  302. if assigned(current_procinfo.endprologue_ai) then
  303. current_procinfo.aktproccode.insertlistafter(current_procinfo.endprologue_ai,templist)
  304. else
  305. list.concatlist(templist);
  306. templist.free;
  307. end;
  308. procedure tcgx86_64.g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);
  309. procedure increase_sp(a : tcgint);
  310. var
  311. href : treference;
  312. begin
  313. if a=8 then
  314. list.concat(Taicpu.op_reg(A_POP,TCGSize2OpSize[OS_ADDR],NR_RCX))
  315. else
  316. begin
  317. reference_reset_base(href,NR_STACK_POINTER_REG,a,ctempposinvalid,0,[]);
  318. { normally, lea is a better choice than an add }
  319. list.concat(Taicpu.op_ref_reg(A_LEA,TCGSize2OpSize[OS_ADDR],href,NR_STACK_POINTER_REG));
  320. end;
  321. end;
  322. var
  323. href : treference;
  324. hreg : tregister;
  325. r : longint;
  326. regs_to_save_mm: tcpuregisterarray;
  327. begin
  328. { we do not need an exit stack frame when we never return
  329. * the final ret is left so the peephole optimizer can easily do call/ret -> jmp or call conversions
  330. * the entry stack frame must be normally generated because the subroutine could be still left by
  331. an exception and then the unwinding code might need to restore the registers stored by the entry code
  332. }
  333. if not(po_noreturn in current_procinfo.procdef.procoptions) then
  334. begin
  335. regs_to_save_mm:=paramanager.get_saved_registers_mm(current_procinfo.procdef.proccalloption);
  336. { Prevent return address from a possible call from ending up in the epilogue }
  337. { (restoring registers happens before epilogue, providing necessary padding) }
  338. if (current_procinfo.flags*[pi_has_unwind_info,pi_do_call,pi_has_saved_regs])=[pi_has_unwind_info,pi_do_call] then
  339. list.concat(Taicpu.op_none(A_NOP));
  340. { remove stackframe }
  341. if not(nostackframe) then
  342. begin
  343. if use_push then
  344. begin
  345. if (saved_xmm_reg_size<>0) then
  346. begin
  347. href:=current_procinfo.save_regs_ref;
  348. for r:=low(regs_to_save_mm) to high(regs_to_save_mm) do
  349. if regs_to_save_mm[r] in rg[R_MMREGISTER].used_in_proc then
  350. begin
  351. { Allocate register so the optimizer does not remove the load }
  352. hreg:=newreg(R_MMREGISTER,regs_to_save_mm[r],R_SUBMMWHOLE);
  353. a_reg_alloc(list,hreg);
  354. a_loadmm_ref_reg(list,OS_VECTOR,OS_VECTOR,href,hreg,nil);
  355. inc(href.offset,tcgsize2size[OS_VECTOR]);
  356. end;
  357. end;
  358. if (current_procinfo.final_localsize<>0) then
  359. increase_sp(current_procinfo.final_localsize);
  360. internal_restore_regs(list,true);
  361. if (current_procinfo.procdef.proctypeoption=potype_exceptfilter) then
  362. list.concat(Taicpu.op_reg(A_POP,tcgsize2opsize[OS_ADDR],NR_FRAME_POINTER_REG));
  363. current_asmdata.asmcfi.cfa_def_cfa_offset(list,sizeof(pint));
  364. end
  365. else if (target_info.system=system_x86_64_win64) then
  366. begin
  367. { Comply with Win64 unwinding mechanism, which only recognizes
  368. 'add $constant,%rsp' and 'lea offset(FPREG),%rsp' as belonging to
  369. the function epilog.
  370. Neither 'leave' nor even 'mov %FPREG,%rsp' are allowed. }
  371. reference_reset_base(href,current_procinfo.framepointer,0,ctempposinvalid,sizeof(pint),[]);
  372. list.concat(Taicpu.op_ref_reg(A_LEA,tcgsize2opsize[OS_ADDR],href,NR_STACK_POINTER_REG));
  373. list.concat(Taicpu.op_reg(A_POP,tcgsize2opsize[OS_ADDR],current_procinfo.framepointer));
  374. end
  375. else
  376. generate_leave(list);
  377. list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
  378. end;
  379. if pi_uses_ymm in current_procinfo.flags then
  380. list.Concat(taicpu.op_none(A_VZEROUPPER));
  381. end;
  382. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  383. list.concat(tai_regalloc.dealloc(NR_STACK_POINTER_REG,nil));
  384. list.concat(Taicpu.Op_none(A_RET,S_NO));
  385. if (pi_has_unwind_info in current_procinfo.flags) then
  386. begin
  387. tcpuprocinfo(current_procinfo).dump_scopes(list);
  388. list.concat(cai_seh_directive.create(ash_endproc));
  389. end;
  390. end;
  391. procedure tcgx86_64.g_save_registers(list: TAsmList);
  392. begin
  393. if (not use_push) then
  394. inherited g_save_registers(list);
  395. end;
  396. procedure tcgx86_64.g_restore_registers(list: TAsmList);
  397. begin
  398. if (not use_push) then
  399. inherited g_restore_registers(list);
  400. end;
  401. procedure tcgx86_64.g_local_unwind(list: TAsmList; l: TAsmLabel);
  402. var
  403. para1,para2: tcgpara;
  404. href: treference;
  405. pd: tprocdef;
  406. begin
  407. if (target_info.system<>system_x86_64_win64) then
  408. begin
  409. inherited g_local_unwind(list,l);
  410. exit;
  411. end;
  412. pd:=search_system_proc('_fpc_local_unwind');
  413. para1.init;
  414. para2.init;
  415. paramanager.getcgtempparaloc(list,pd,1,para1);
  416. paramanager.getcgtempparaloc(list,pd,2,para2);
  417. reference_reset_symbol(href,l,0,1,[]);
  418. { TODO: using RSP is correct only while the stack is fixed!!
  419. (true now, but will change if/when allocating from stack is implemented) }
  420. a_load_reg_cgpara(list,OS_ADDR,NR_STACK_POINTER_REG,para1);
  421. a_loadaddr_ref_cgpara(list,href,para2);
  422. paramanager.freecgpara(list,para2);
  423. paramanager.freecgpara(list,para1);
  424. g_call(list,'_FPC_local_unwind');
  425. para2.done;
  426. para1.done;
  427. end;
  428. procedure tcgx86_64.a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize; intreg, mmreg: tregister; shuffle: pmmshuffle);
  429. var
  430. opc: tasmop;
  431. begin
  432. { this code can only be used to transfer raw data, not to perform
  433. conversions }
  434. if (tcgsize2size[fromsize]<>tcgsize2size[tosize]) or
  435. not(tosize in [OS_F32,OS_F64,OS_M64]) then
  436. internalerror(2009112505);
  437. case fromsize of
  438. OS_32,OS_S32:
  439. opc:=A_MOVD;
  440. OS_64,OS_S64:
  441. opc:=A_MOVQ;
  442. else
  443. internalerror(2009112506);
  444. end;
  445. if assigned(shuffle) and
  446. not shufflescalar(shuffle) then
  447. internalerror(2009112517);
  448. list.concat(taicpu.op_reg_reg(opc,S_NO,intreg,mmreg));
  449. end;
  450. procedure tcgx86_64.a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize : tcgsize; mmreg, intreg: tregister;shuffle : pmmshuffle);
  451. var
  452. opc: tasmop;
  453. begin
  454. { this code can only be used to transfer raw data, not to perform
  455. conversions }
  456. if (tcgsize2size[fromsize]<>tcgsize2size[tosize]) or
  457. not (fromsize in [OS_F32,OS_F64,OS_M64]) then
  458. internalerror(2009112507);
  459. case tosize of
  460. OS_32,OS_S32:
  461. opc:=A_MOVD;
  462. OS_64,OS_S64:
  463. opc:=A_MOVQ;
  464. else
  465. internalerror(2009112408);
  466. end;
  467. if assigned(shuffle) and
  468. not shufflescalar(shuffle) then
  469. internalerror(2009112515);
  470. list.concat(taicpu.op_reg_reg(opc,S_NO,mmreg,intreg));
  471. end;
  472. function tcgx86_64.use_ms_abi: boolean;
  473. begin
  474. if assigned(current_procinfo) then
  475. use_ms_abi:=x86_64_use_ms_abi(current_procinfo.procdef.proccalloption)
  476. else
  477. use_ms_abi:=target_info.system=system_x86_64_win64;
  478. end;
  479. procedure create_codegen;
  480. begin
  481. cg:=tcgx86_64.create;
  482. cg128:=tcg128.create;
  483. end;
  484. end.