hlcgllvm.pas 39 KB

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