cgcpu.pas 22 KB

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