hlcgllvm.pas 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. {
  2. Copyright (c) 2010, 2013 by Jonas Maebe
  3. Member of the Free Pascal development team
  4. This unit implements the LLVM high level code generator
  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 hlcgllvm;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,
  23. aasmbase,aasmdata,
  24. symbase,symconst,symtype,symdef,symsym,
  25. cpubase, hlcgobj, cgbase, cgutils, parabase;
  26. type
  27. { thlcgllvm }
  28. thlcgllvm = class(thlcgobj)
  29. constructor create;
  30. function a_call_name(list : TAsmList;pd : tprocdef;const s : TSymStr; forceresdef: tdef; weak: boolean): tcgpara;override;
  31. procedure a_call_reg(list: TAsmList; pd: tabstractprocdef; reg: tregister); override;
  32. procedure a_load_const_reg(list : TAsmList;tosize : tdef;a : tcgint;register : tregister);override;
  33. procedure a_load_const_ref(list: TAsmList; tosize: tdef; a: tcgint; const ref: treference);override;
  34. procedure a_load_reg_ref(list : TAsmList;fromsize, tosize : tdef;register : tregister;const ref : treference);override;
  35. procedure a_load_reg_reg(list : TAsmList;fromsize, tosize : tdef;reg1,reg2 : tregister);override;
  36. procedure a_load_ref_reg(list : TAsmList;fromsize, tosize : tdef;const ref : treference;register : tregister);override;
  37. procedure a_loadaddr_ref_reg(list : TAsmList;fromsize, tosize : tdef;const ref : treference;r : tregister);override;
  38. procedure a_op_const_reg(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; reg: TRegister); override;
  39. procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister); override;
  40. procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister); override;
  41. procedure a_op_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; reg1, reg2: TRegister); override;
  42. procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation); override;
  43. procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation); override;
  44. procedure a_cmp_const_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel); override;
  45. procedure a_cmp_reg_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel); override;
  46. procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
  47. procedure g_concatcopy(list : TAsmList;size: tdef; const source,dest : treference);override;
  48. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister); override;
  49. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference); override;
  50. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister); override;
  51. procedure gen_proc_symbol(list: TAsmList); override;
  52. procedure gen_proc_symbol_end(list: TAsmList); override;
  53. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean); override;
  54. procedure g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean); override;
  55. procedure g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef); override;
  56. procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;var ovloc : tlocation); override;
  57. procedure a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister; shuffle: pmmshuffle); override;
  58. procedure a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference; shuffle: pmmshuffle); override;
  59. procedure a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister; shuffle: pmmshuffle); override;
  60. procedure a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; src, dst: tregister; shuffle: pmmshuffle); override;
  61. procedure a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize: tdef; intreg, mmreg: tregister; shuffle: pmmshuffle); override;
  62. procedure a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize: tdef; mmreg, intreg: tregister; shuffle: pmmshuffle); override;
  63. procedure gen_load_cgpara_loc(list: TAsmList; vardef: tdef; const para: TCGPara; var destloc: tlocation; reusepara: boolean); override;
  64. {$ifdef cpuflags}
  65. { llvm doesn't have flags, but cpuflags is defined in case the real cpu
  66. has flags and we have to override the abstract methods to prevent
  67. warnings }
  68. procedure a_jmp_flags(list: TAsmList; const f: TResFlags; l: tasmlabel); override;
  69. procedure g_flags2reg(list: TAsmList; size: tdef; const f: tresflags; reg: TRegister); override;
  70. procedure g_flags2ref(list: TAsmList; size: tdef; const f: tresflags; const ref: TReference); override;
  71. {$endif cpuflags}
  72. { unimplemented or unnecessary routines }
  73. procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: tdef; src, dst: tregister); override;
  74. procedure g_stackpointer_alloc(list: TAsmList; size: longint); override;
  75. procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint); override;
  76. procedure g_adjust_self_value(list: TAsmList; procdef: tprocdef; ioffset: aint); override;
  77. procedure g_local_unwind(list: TAsmList; l: TAsmLabel); override;
  78. procedure varsym_set_localloc(list: TAsmList; vs: tabstractnormalvarsym); override;
  79. procedure paravarsym_set_initialloc_to_paraloc(vs: tparavarsym); override;
  80. protected
  81. { def is the type of the data stored in memory pointed to by ref, not
  82. a pointer to this type }
  83. function make_simple_ref(list: TAsmList; const ref: treference; def: tdef): treference;
  84. end;
  85. procedure create_hlcodegen;
  86. implementation
  87. uses
  88. verbose,cutils,cclasses,globals,fmodule,constexp,
  89. defutil,llvmdef,llvmsym,
  90. aasmtai,aasmcpu,
  91. aasmllvm,llvmbase,tgllvm,
  92. symtable,
  93. paramgr,
  94. procinfo,cpuinfo,tgobj,cgobj,cgllvm,cghlcpu;
  95. const
  96. topcg2llvmop: array[topcg] of tllvmop =
  97. { OP_NONE OP_MOVE OP_ADD OP_AND OP_DIV OP_IDIV OP_IMUL OP_MUL }
  98. (la_none, la_none, la_add, la_and, la_udiv, la_sdiv, la_mul, la_mul,
  99. { OP_NEG OP_NOT OP_OR OP_SAR OP_SHL OP_SHR OP_SUB OP_XOR }
  100. la_none, la_none, la_or, la_ashr, la_shl, la_lshr, la_sub, la_xor,
  101. { OP_ROL OP_ROR }
  102. la_none, la_none);
  103. constructor thlcgllvm.create;
  104. begin
  105. inherited
  106. end;
  107. function thlcgllvm.a_call_name(list: TAsmList; pd: tprocdef; const s: TSymStr; forceresdef: tdef; weak: boolean): tcgpara;
  108. begin
  109. { todo: we also need the parameter locations here for llvm! }
  110. list.concat(tai_comment.create(strpnew('call '+s)));
  111. result:=get_call_result_cgpara(pd,forceresdef);
  112. end;
  113. procedure thlcgllvm.a_call_reg(list: TAsmList; pd: tabstractprocdef; reg: tregister);
  114. begin
  115. internalerror(2012042824);
  116. end;
  117. procedure thlcgllvm.a_load_const_reg(list: TAsmList; tosize: tdef; a: tcgint; register: tregister);
  118. begin
  119. list.concat(taillvm.op_reg_size_const_size(la_bitcast,register,tosize,a,tosize))
  120. end;
  121. procedure thlcgllvm.a_load_const_ref(list: TAsmList; tosize: tdef; a: tcgint; const ref: treference);
  122. var
  123. sref: treference;
  124. begin
  125. sref:=make_simple_ref(list,ref,tosize);
  126. list.concat(taillvm.op_size_const_size_ref(la_store,tosize,a,getpointerdef(tosize),sref))
  127. end;
  128. procedure thlcgllvm.a_load_reg_ref(list: TAsmList; fromsize, tosize: tdef; register: tregister; const ref: treference);
  129. var
  130. sref: treference;
  131. hreg: tregister;
  132. begin
  133. sref:=make_simple_ref(list,ref,tosize);
  134. hreg:=register;
  135. if fromsize.size<>tosize.size then
  136. begin
  137. hreg:=getregisterfordef(list,tosize);
  138. a_load_reg_reg(list,fromsize,tosize,register,hreg);
  139. end;
  140. list.concat(taillvm.op_size_reg_size_ref(la_store,tosize,hreg,getpointerdef(tosize),sref))
  141. end;
  142. procedure thlcgllvm.a_load_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister);
  143. var
  144. fromregtyp,
  145. toregtyp: tregistertype;
  146. op: tllvmop;
  147. begin
  148. fromregtyp:=def2regtyp(fromsize);
  149. toregtyp:=def2regtyp(tosize);
  150. { int to pointer or vice versa }
  151. if (fromregtyp=R_ADDRESSREGISTER) and
  152. (toregtyp=R_INTREGISTER) then
  153. op:=la_ptrtoint
  154. else if (fromregtyp=R_INTREGISTER) and
  155. (toregtyp=R_ADDRESSREGISTER) then
  156. op:=la_inttoptr
  157. { int to int or ptr to ptr: need zero/sign extension, or plain bitcast? }
  158. else if tosize.size<>fromsize.size then
  159. begin
  160. if tosize.size<fromsize.size then
  161. op:=la_trunc
  162. else if is_signed(fromsize) then
  163. { fromsize is signed -> sign extension }
  164. op:=la_sext
  165. else
  166. op:=la_zext;
  167. end
  168. else
  169. op:=la_bitcast;
  170. { reg2 = bitcast fromsize reg1 to tosize }
  171. list.concat(taillvm.op_reg_size_reg_size(op,reg2,fromsize,reg1,tosize));
  172. end;
  173. procedure thlcgllvm.a_load_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; register: tregister);
  174. var
  175. sref: treference;
  176. hreg: tregister;
  177. begin
  178. sref:=make_simple_ref(list,ref,fromsize);
  179. { "named register"? }
  180. if sref.refaddr=addr_full then
  181. list.concat(taillvm.op_reg_size_ref_size(la_bitcast,register,fromsize,sref,tosize))
  182. else
  183. begin
  184. hreg:=register;
  185. if fromsize<>tosize then
  186. hreg:=getregisterfordef(list,fromsize);
  187. list.concat(taillvm.op_reg_size_ref(la_load,hreg,getpointerdef(fromsize),sref));
  188. if hreg<>register then
  189. a_load_reg_reg(list,fromsize,tosize,hreg,register);
  190. end;
  191. end;
  192. procedure thlcgllvm.a_loadaddr_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; r: tregister);
  193. var
  194. sref: treference;
  195. begin
  196. { can't take the address of a 'named register' }
  197. if ref.refaddr=addr_full then
  198. internalerror(2013102306);
  199. sref:=make_simple_ref(list,ref,fromsize);
  200. list.concat(taillvm.op_reg_size_ref_size(la_bitcast,r,getpointerdef(fromsize),sref,tosize));
  201. end;
  202. procedure thlcgllvm.a_op_const_reg(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; reg: TRegister);
  203. begin
  204. a_op_const_reg_reg(list,op,size,a,reg,reg);
  205. end;
  206. procedure thlcgllvm.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister);
  207. var
  208. tmpreg: tregister;
  209. begin
  210. if (def2regtyp(size)=R_INTREGISTER) and
  211. (topcg2llvmop[op]<>la_none) then
  212. list.concat(taillvm.op_reg_size_reg_const(topcg2llvmop[op],dst,size,src,a))
  213. else
  214. begin
  215. { default implementation is not SSA-safe }
  216. tmpreg:=getregisterfordef(list,size);
  217. a_load_const_reg(list,size,a,tmpreg);
  218. a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
  219. end;
  220. end;
  221. procedure thlcgllvm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister);
  222. var
  223. orgdst,
  224. tmpreg1,
  225. tmpreg2,
  226. tmpreg3: tregister;
  227. opsize: tdef;
  228. begin
  229. orgdst:=dst;
  230. opsize:=size;
  231. { always perform using integer registers, because math operations on
  232. pointers are not supported (except via getelementptr, possible future
  233. optimization) }
  234. if def2regtyp(size)=R_ADDRESSREGISTER then
  235. begin
  236. opsize:=ptruinttype;
  237. tmpreg1:=getintregister(list,ptruinttype);
  238. a_load_reg_reg(list,size,ptruinttype,src1,tmpreg1);
  239. src1:=tmpreg1;
  240. tmpreg1:=getintregister(list,ptruinttype);
  241. a_load_reg_reg(list,size,ptruinttype,src2,tmpreg1);
  242. src2:=tmpreg1;
  243. dst:=getintregister(list,ptruinttype);
  244. end;
  245. if topcg2llvmop[op]<>la_none then
  246. list.concat(taillvm.op_reg_size_reg_reg(topcg2llvmop[op],dst,opsize,src2,src1))
  247. else
  248. begin
  249. case op of
  250. OP_NEG:
  251. { %dst = sub size 0, %src1 }
  252. list.concat(taillvm.op_reg_size_const_reg(la_sub,dst,opsize,0,src1));
  253. OP_NOT:
  254. { %dst = xor size -1, %src1 }
  255. list.concat(taillvm.op_reg_size_const_reg(la_xor,dst,opsize,-1,src1));
  256. OP_ROL:
  257. begin
  258. tmpreg1:=getintregister(list,opsize);
  259. tmpreg2:=getintregister(list,opsize);
  260. tmpreg3:=getintregister(list,opsize);
  261. { tmpreg1 := tcgsize2size[size] - src1 }
  262. list.concat(taillvm.op_reg_size_const_reg(la_sub,tmpreg1,opsize,opsize.size,src1));
  263. { tmpreg2 := src2 shr tmpreg1 }
  264. a_op_reg_reg_reg(list,OP_SHR,opsize,tmpreg1,src2,tmpreg2);
  265. { tmpreg3 := src2 shl src1 }
  266. a_op_reg_reg_reg(list,OP_SHL,opsize,src1,src2,tmpreg3);
  267. { dst := tmpreg2 or tmpreg3 }
  268. a_op_reg_reg_reg(list,OP_OR,opsize,tmpreg2,tmpreg3,dst);
  269. end;
  270. OP_ROR:
  271. begin
  272. tmpreg1:=getintregister(list,size);
  273. tmpreg2:=getintregister(list,size);
  274. tmpreg3:=getintregister(list,size);
  275. { tmpreg1 := tcgsize2size[size] - src1 }
  276. list.concat(taillvm.op_reg_size_const_reg(la_sub,tmpreg1,opsize,opsize.size,src1));
  277. { tmpreg2 := src2 shl tmpreg1 }
  278. a_op_reg_reg_reg(list,OP_SHL,opsize,tmpreg1,src2,tmpreg2);
  279. { tmpreg3 := src2 shr src1 }
  280. a_op_reg_reg_reg(list,OP_SHR,opsize,src1,src2,tmpreg3);
  281. { dst := tmpreg2 or tmpreg3 }
  282. a_op_reg_reg_reg(list,OP_OR,opsize,tmpreg2,tmpreg3,dst);
  283. end;
  284. else
  285. internalerror(2010081310);
  286. end;
  287. end;
  288. if dst<>orgdst then
  289. a_load_reg_reg(list,opsize,size,dst,orgdst);
  290. end;
  291. procedure thlcgllvm.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; reg1, reg2: TRegister);
  292. begin
  293. a_op_reg_reg_reg(list,op,size,reg1,reg2,reg2);
  294. end;
  295. procedure thlcgllvm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation);
  296. begin
  297. if not setflags then
  298. begin
  299. inherited;
  300. exit;
  301. end;
  302. { use xxx.with.overflow intrinsics }
  303. internalerror(2012111102);
  304. end;
  305. procedure thlcgllvm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation);
  306. begin
  307. if not setflags then
  308. begin
  309. inherited;
  310. exit;
  311. end;
  312. { use xxx.with.overflow intrinsics }
  313. internalerror(2012111103);
  314. end;
  315. procedure thlcgllvm.a_cmp_const_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
  316. var
  317. tmpreg : tregister;
  318. invert: boolean;
  319. falselab, tmplab: tasmlabel;
  320. begin
  321. { since all comparisons return their results in a register, we'll often
  322. get comparisons against true/false -> optimise }
  323. if (size=pasbool8type) and
  324. (cmp_op in [OC_EQ,OC_NE]) then
  325. begin
  326. case cmp_op of
  327. OC_EQ:
  328. invert:=a=0;
  329. OC_NE:
  330. invert:=a=1;
  331. end;
  332. current_asmdata.getjumplabel(falselab);
  333. if invert then
  334. begin
  335. tmplab:=l;
  336. l:=falselab;
  337. falselab:=tmplab;
  338. end;
  339. list.concat(taillvm.op_size_reg_lab_lab(la_br,pasbool8type,reg,l,falselab));
  340. a_label(list,falselab);
  341. exit;
  342. end;
  343. tmpreg:=getregisterfordef(list,size);
  344. a_load_const_reg(list,size,a,tmpreg);
  345. a_cmp_reg_reg_label(list,size,cmp_op,tmpreg,reg,l);
  346. end;
  347. procedure thlcgllvm.a_cmp_reg_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel);
  348. var
  349. resreg: tregister;
  350. falselab: tasmlabel;
  351. begin
  352. if getregtype(reg1)<>getregtype(reg2) then
  353. internalerror(2012111105);
  354. resreg:=getintregister(list,pasbool8type);
  355. current_asmdata.getjumplabel(falselab);
  356. { invert order of registers. In FPC, cmp_reg_reg(reg1,reg2) means that
  357. e.g. OC_GT is true if "subl %reg1,%reg2" in x86 AT&T is >0. In LLVM,
  358. OC_GT is true if op1>op2 }
  359. list.concat(taillvm.op_reg_cond_size_reg_reg(la_icmp,resreg,cmp_op,size,reg2,reg1));
  360. list.concat(taillvm.op_size_reg_lab_lab(la_br,pasbool8type,resreg,l,falselab));
  361. a_label(list,falselab);
  362. end;
  363. procedure thlcgllvm.a_jmp_always(list: TAsmList; l: tasmlabel);
  364. begin
  365. { implement in tcg because required by the overridden a_label; doesn't use
  366. any high level stuff anyway }
  367. cg.a_jmp_always(list,l);
  368. end;
  369. procedure thlcgllvm.g_concatcopy(list: TAsmList; size: tdef; const source, dest: treference);
  370. begin
  371. { todo }
  372. inherited;
  373. end;
  374. procedure thlcgllvm.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister);
  375. var
  376. tmpreg: tregister;
  377. href: treference;
  378. fromcompcurr,
  379. tocompcurr: boolean;
  380. begin
  381. { comp and currency are handled by the x87 in this case. They cannot
  382. be represented directly in llvm, and llvmdef translates them into i64
  383. (since that's their storage size and internally they also are int64).
  384. Solve this by changing the type to s80real once they are loaded into
  385. a register. }
  386. fromcompcurr:=tfloatdef(fromsize).floattype in [s64comp,s64currency];
  387. tocompcurr:=tfloatdef(tosize).floattype in [s64comp,s64currency];
  388. if tocompcurr then
  389. tosize:=s80floattype;
  390. href:=make_simple_ref(list,ref,fromsize);
  391. { don't generate different code for loading e.g. extended into cextended,
  392. but to take care of loading e.g. comp (=int64) into double }
  393. if (fromsize.size<>tosize.size) then
  394. tmpreg:=getfpuregister(list,fromsize)
  395. else
  396. tmpreg:=reg;
  397. { %tmpreg = load size* %ref }
  398. list.concat(taillvm.op_reg_size_ref(la_load,tmpreg,getpointerdef(fromsize),href));
  399. if tmpreg<>reg then
  400. if fromcompcurr then
  401. { treat as extended as long as it's in a register }
  402. list.concat(taillvm.op_reg_size_reg_size(la_sitofp,reg,fromsize,tmpreg,tosize))
  403. else
  404. a_loadfpu_reg_reg(list,fromsize,tosize,tmpreg,reg);
  405. end;
  406. procedure thlcgllvm.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference);
  407. var
  408. tmpreg: tregister;
  409. href: treference;
  410. fromcompcurr,
  411. tocompcurr: boolean;
  412. begin
  413. { see comment in a_loadfpu_ref_reg }
  414. fromcompcurr:=tfloatdef(fromsize).floattype in [s64comp,s64currency];
  415. tocompcurr:=tfloatdef(tosize).floattype in [s64comp,s64currency];
  416. if fromcompcurr then
  417. fromsize:=s80floattype;
  418. href:=make_simple_ref(list,ref,tosize);
  419. { don't generate different code for loading e.g. extended into cextended,
  420. but to take care of storing e.g. comp (=int64) into double }
  421. if (fromsize.size<>tosize.size) then
  422. begin
  423. tmpreg:=getfpuregister(list,tosize);
  424. if tocompcurr then
  425. { store back an int64 rather than an extended }
  426. list.concat(taillvm.op_reg_size_reg_size(la_fptosi,tmpreg,fromsize,reg,tosize))
  427. else
  428. a_loadfpu_reg_reg(list,fromsize,tosize,reg,tmpreg);
  429. end
  430. else
  431. tmpreg:=reg;
  432. { store tosize tmpreg, tosize* href }
  433. list.concat(taillvm.op_size_reg_size_ref(la_store,tosize,tmpreg,getpointerdef(tosize),href));
  434. end;
  435. procedure thlcgllvm.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister);
  436. var
  437. op: tllvmop;
  438. intfromsize,
  439. inttosize: longint;
  440. begin
  441. { treat comp and currency as extended in registers (see comment at start
  442. of a_loadfpu_ref_reg) }
  443. if tfloatdef(fromsize).floattype in [s64comp,s64currency] then
  444. fromsize:=sc80floattype;
  445. if tfloatdef(tosize).floattype in [s64comp,s64currency] then
  446. tosize:=sc80floattype;
  447. { at the value level, s80real and sc80real are the same }
  448. if fromsize<>s80floattype then
  449. intfromsize:=fromsize.size
  450. else
  451. intfromsize:=sc80floattype.size;
  452. if tosize<>s80floattype then
  453. inttosize:=tosize.size
  454. else
  455. inttosize:=sc80floattype.size;
  456. if intfromsize<inttosize then
  457. op:=la_fpext
  458. else if intfromsize>inttosize then
  459. op:=la_fptrunc
  460. else
  461. op:=la_bitcast;
  462. { reg2 = bitcast fromllsize reg1 to tollsize }
  463. list.concat(taillvm.op_reg_size_reg_size(op,reg2,fromsize,reg1,tosize));
  464. end;
  465. procedure thlcgllvm.gen_proc_symbol(list: TAsmList);
  466. var
  467. item: TCmdStrListItem;
  468. mangledname: TSymStr;
  469. begin
  470. item:=TCmdStrListItem(current_procinfo.procdef.aliasnames.first);
  471. mangledname:=current_procinfo.procdef.mangledname;
  472. { predefine the real function name as local/global, so the aliases can
  473. refer to the symbol and get the binding correct }
  474. if (cs_profile in current_settings.moduleswitches) or
  475. (po_global in current_procinfo.procdef.procoptions) then
  476. current_asmdata.DefineAsmSymbol(mangledname,AB_GLOBAL,AT_FUNCTION)
  477. else
  478. current_asmdata.DefineAsmSymbol(mangledname,AB_LOCAL,AT_FUNCTION);
  479. while assigned(item) do
  480. begin
  481. if mangledname<>item.Str then
  482. list.concat(taillvmalias.Create(mangledname,item.str,current_procinfo.procdef,llv_default,lll_default));
  483. item:=TCmdStrListItem(item.next);
  484. end;
  485. list.concat(taillvmprocdef.create(current_procinfo.procdef));
  486. end;
  487. procedure thlcgllvm.gen_proc_symbol_end(list: TAsmList);
  488. begin
  489. list.concat(Tai_symbol_end.Createname(current_procinfo.procdef.mangledname));
  490. { todo: darwin main proc, or handle in other way? }
  491. end;
  492. procedure thlcgllvm.g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean);
  493. begin
  494. list.concatlist(ttgllvm(tg).alloclist)
  495. { rest: todo }
  496. end;
  497. procedure thlcgllvm.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
  498. var
  499. retdef: tdef;
  500. begin
  501. if current_procinfo.procdef.proctypeoption in [potype_constructor,potype_class_constructor] then
  502. if is_implicit_pointer_object_type(current_procinfo.procdef.struct) then
  503. retdef:=current_procinfo.procdef.struct
  504. else
  505. retdef:=getpointerdef(current_procinfo.procdef.struct)
  506. else
  507. retdef:=current_procinfo.procdef.returndef;
  508. if is_void(retdef) then
  509. list.concat(taillvm.op_size(la_ret,retdef))
  510. else
  511. begin
  512. case current_procinfo.procdef.funcretloc[calleeside].location^.loc of
  513. LOC_REGISTER,
  514. LOC_FPUREGISTER:
  515. list.concat(taillvm.op_size_reg(la_ret,retdef,current_procinfo.procdef.funcretloc[calleeside].location^.register))
  516. else
  517. { todo: complex returns }
  518. internalerror(2012111106);
  519. end;
  520. end;
  521. end;
  522. procedure thlcgllvm.g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef);
  523. begin
  524. { not possible, need ovloc }
  525. internalerror(2012111107);
  526. end;
  527. procedure thlcgllvm.g_overflowCheck_loc(List: TAsmList; const Loc: TLocation; def: TDef; var ovloc: tlocation);
  528. begin
  529. { todo }
  530. internalerror(2012111108);
  531. end;
  532. procedure thlcgllvm.a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister; shuffle: pmmshuffle);
  533. var
  534. href: treference;
  535. begin
  536. if shuffle=mms_movescalar then
  537. a_loadfpu_ref_reg(list,fromsize,tosize,ref,reg)
  538. else
  539. begin
  540. { todo }
  541. if fromsize<>tosize then
  542. internalerror(2013060220);
  543. href:=make_simple_ref(list,ref,fromsize);
  544. { %reg = load size* %ref }
  545. list.concat(taillvm.op_reg_size_ref(la_load,reg,getpointerdef(fromsize),href));
  546. end;
  547. end;
  548. procedure thlcgllvm.a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference; shuffle: pmmshuffle);
  549. var
  550. href: treference;
  551. begin
  552. if shuffle=mms_movescalar then
  553. a_loadfpu_reg_ref(list,fromsize,tosize,reg,ref)
  554. else
  555. begin
  556. { todo }
  557. if fromsize<>tosize then
  558. internalerror(2013060220);
  559. href:=make_simple_ref(list,ref,tosize);
  560. { store tosize reg, tosize* href }
  561. list.concat(taillvm.op_size_reg_size_ref(la_store,tosize,reg,getpointerdef(tosize),href))
  562. end;
  563. end;
  564. procedure thlcgllvm.a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister; shuffle: pmmshuffle);
  565. begin
  566. if shuffle=mms_movescalar then
  567. a_loadfpu_reg_reg(list,fromsize,tosize,reg1,reg2)
  568. else
  569. { reg2 = bitcast fromllsize reg1 to tollsize }
  570. list.concat(taillvm.op_reg_size_reg_size(la_bitcast,reg2,fromsize,reg1,tosize));
  571. end;
  572. procedure thlcgllvm.a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; src, dst: tregister; shuffle: pmmshuffle);
  573. begin
  574. if (op=OP_XOR) and
  575. (src=dst) then
  576. a_load_const_reg(list,size,0,dst)
  577. else
  578. { todo }
  579. internalerror(2013060221);
  580. end;
  581. procedure thlcgllvm.a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize: tdef; intreg, mmreg: tregister; shuffle: pmmshuffle);
  582. begin
  583. internalerror(2013060222);
  584. end;
  585. procedure thlcgllvm.a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize: tdef; mmreg, intreg: tregister; shuffle: pmmshuffle);
  586. begin
  587. internalerror(2013060223);
  588. end;
  589. procedure thlcgllvm.gen_load_cgpara_loc(list: TAsmList; vardef: tdef; const para: TCGPara; var destloc: tlocation; reusepara: boolean);
  590. var
  591. href : treference;
  592. begin
  593. { skip e.g. empty records }
  594. if (para.location^.loc = LOC_VOID) then
  595. exit;
  596. para.check_simple_location;
  597. case destloc.loc of
  598. LOC_REFERENCE :
  599. begin
  600. { If the parameter location is reused we don't need to copy
  601. anything }
  602. if not reusepara then
  603. begin
  604. reference_reset_symbol(href,para.location^.llvmloc,0,para.location^.def.alignment);
  605. if para.location^.llvmvalueloc then
  606. href.refaddr:=addr_full;
  607. { TODO: if more than one location, use para.location^.def instead (otherwise para.def, because can be
  608. zext/sext -> paraloc.location^.def will be larger) }
  609. a_load_ref_ref(list,para.def,para.def,href,destloc.reference);
  610. end;
  611. end;
  612. { TODO other possible locations }
  613. else
  614. internalerror(2013102304);
  615. end;
  616. end;
  617. procedure thlcgllvm.a_jmp_flags(list: TAsmList; const f: TResFlags; l: tasmlabel);
  618. begin
  619. internalerror(2013060224);
  620. end;
  621. procedure thlcgllvm.g_flags2reg(list: TAsmList; size: tdef; const f: tresflags; reg: TRegister);
  622. begin
  623. internalerror(2013060225);
  624. end;
  625. procedure thlcgllvm.g_flags2ref(list: TAsmList; size: tdef; const f: tresflags; const ref: TReference);
  626. begin
  627. internalerror(2013060226);
  628. end;
  629. procedure thlcgllvm.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: tdef; src, dst: tregister);
  630. begin
  631. internalerror(2012090201);
  632. end;
  633. procedure thlcgllvm.g_stackpointer_alloc(list: TAsmList; size: longint);
  634. begin
  635. internalerror(2012090203);
  636. end;
  637. procedure thlcgllvm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  638. begin
  639. internalerror(2012090204);
  640. end;
  641. procedure thlcgllvm.g_adjust_self_value(list: TAsmList; procdef: tprocdef; ioffset: aint);
  642. begin
  643. internalerror(2012090205);
  644. end;
  645. procedure thlcgllvm.g_local_unwind(list: TAsmList; l: TAsmLabel);
  646. begin
  647. internalerror(2012090206);
  648. end;
  649. function thlcgllvm.make_simple_ref(list: TAsmList; const ref: treference; def: tdef): treference;
  650. var
  651. hreg1,
  652. hreg2: tregister;
  653. tmpref: treference;
  654. begin
  655. { already simple? }
  656. if (not assigned(ref.symbol) or
  657. (ref.base=NR_NO)) and
  658. (ref.index=NR_NO) and
  659. (ref.offset=0) then
  660. begin
  661. result:=ref;
  662. exit;
  663. end;
  664. { for now, perform all calculations using plain pointer arithmetic. Later
  665. we can look into optimizations based on getelementptr for structured
  666. accesses (if only to prevent running out of virtual registers).
  667. Assumptions:
  668. * symbol/base register: always type "def*"
  669. * index/offset: always type "ptruinttype" (llvm bitcode has no sign information, so sign doesn't matter) }
  670. hreg1:=getintregister(list,ptruinttype);
  671. if assigned(ref.symbol) then
  672. begin
  673. if ref.base<>NR_NO then
  674. internalerror(2012111301);
  675. reference_reset_symbol(tmpref,ref.symbol,0,ref.alignment);
  676. list.concat(taillvm.getelementptr_reg_size_ref_size_const(hreg1,getpointerdef(def),tmpref,ptruinttype,0));
  677. end
  678. else if ref.base<>NR_NO then
  679. begin
  680. a_load_reg_reg(list,getpointerdef(def),ptruinttype,ref.base,hreg1);
  681. end
  682. else
  683. { todo: support for absolute addresses on embedded platforms }
  684. internalerror(2012111302);
  685. if ref.index<>NR_NO then
  686. begin
  687. { SSA... }
  688. hreg2:=getintregister(list,ptruinttype);
  689. a_op_reg_reg_reg(list,OP_ADD,ptruinttype,ref.index,hreg1,hreg2);
  690. hreg1:=hreg2;
  691. end;
  692. if ref.offset<>0 then
  693. begin
  694. hreg2:=getintregister(list,ptruinttype);
  695. a_op_const_reg_reg(list,OP_ADD,ptruinttype,ref.offset,hreg1,hreg2);
  696. hreg1:=hreg2;
  697. end;
  698. hreg2:=getaddressregister(list,getpointerdef(def));
  699. a_load_reg_reg(list,ptruinttype,getpointerdef(def),hreg1,hreg2);
  700. reference_reset_base(result,hreg2,0,ref.alignment);
  701. end;
  702. procedure thlcgllvm.varsym_set_localloc(list: TAsmList; vs: tabstractnormalvarsym);
  703. begin
  704. if cs_asm_source in current_settings.globalswitches then
  705. begin
  706. case vs.initialloc.loc of
  707. LOC_REFERENCE :
  708. begin
  709. if assigned(vs.initialloc.reference.symbol) then
  710. list.concat(Tai_comment.Create(strpnew('Var '+vs.realname+' located at '+
  711. vs.initialloc.reference.symbol.name)))
  712. else
  713. list.concat(Tai_comment.Create(strpnew('Var '+vs.realname+' located at %tmp.'+
  714. tostr(getsupreg(vs.initialloc.reference.base)))));
  715. end;
  716. end;
  717. end;
  718. vs.localloc:=vs.initialloc;
  719. FillChar(vs.currentregloc,sizeof(vs.currentregloc),0);
  720. end;
  721. procedure thlcgllvm.paravarsym_set_initialloc_to_paraloc(vs: tparavarsym);
  722. var
  723. parasym : tasmsymbol;
  724. begin
  725. parasym:=vs.paraloc[calleeside].location^.llvmloc;
  726. reference_reset_symbol(vs.initialloc.reference,parasym,0,vs.paraloc[calleeside].alignment);
  727. if vs.paraloc[calleeside].location^.llvmvalueloc then
  728. vs.initialloc.reference.refaddr:=addr_full;
  729. end;
  730. procedure create_hlcodegen;
  731. begin
  732. hlcg:=thlcgllvm.create;
  733. cgllvm.create_codegen
  734. end;
  735. end.