hlcgllvm.pas 38 KB

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