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