cgllvm.pas 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064
  1. {
  2. Copyright (c) 2010 by Florian Klaempfl and Jonas Maebe
  3. Member of the Free Pascal development team
  4. This unit implements the code generator for LLVM
  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 cgllvm;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,symtype,symdef,
  23. cgbase,cgutils,cgobj,
  24. aasmbase,aasmcpu,aasmtai,aasmdata,
  25. parabase,
  26. cpubase,cpuinfo,node,cg64f32,rgcpu;
  27. type
  28. { tcgllvm }
  29. tcgllvm = class(tcg)
  30. procedure init_register_allocators; override;
  31. procedure done_register_allocators; override;
  32. procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);override;
  33. procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
  34. procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);override;
  35. procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override;
  36. procedure a_call_reg(list : TAsmList;reg: tregister);override;
  37. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister); override;
  38. procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  39. procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister); override;
  40. procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister); override;
  41. procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  42. procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  43. { move instructions }
  44. procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  45. procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  46. procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  47. procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);override;
  48. { fpu move instructions }
  49. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  50. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  51. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
  52. procedure a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);override;
  53. { comparison operations }
  54. procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  55. l : tasmlabel);override;
  56. procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  57. procedure a_jmp_name(list : TAsmList;const s : string); override;
  58. procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
  59. {$ifdef using_llvm_tresflags}
  60. procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
  61. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  62. {$endif}
  63. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  64. procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
  65. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
  66. procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);override;
  67. procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override;
  68. procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);override;
  69. procedure g_save_registers(list : TAsmList);override;
  70. procedure g_restore_registers(list : TAsmList);override;
  71. procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  72. procedure g_stackpointer_alloc(list : TAsmList;size : longint);override;
  73. private
  74. function make_simple_ref(list: TAsmList; const ref: treference): treference;
  75. function make_simple_ref_of_ptrsize(list: TAsmList; const ref: treference; tosize: tcgsize): treference;
  76. end;
  77. procedure create_codegen;
  78. implementation
  79. uses
  80. globals,verbose,systems,cutils,
  81. fmodule,
  82. symconst,symsym,
  83. tgobj,rgobj,
  84. procinfo,cpupi,
  85. paramgr,
  86. llvmbase,
  87. aasmllvm,defutil;
  88. procedure tcgllvm.init_register_allocators;
  89. begin
  90. inherited init_register_allocators;
  91. rg[R_INTREGISTER]:=trgobj.create(R_INTREGISTER,R_SUBWHOLE,[RS_INVALID],RS_INVALID,[]);
  92. rg[R_FPUREGISTER]:=trgobj.create(R_FPUREGISTER,R_SUBNONE,[RS_INVALID],RS_INVALID,[]);
  93. rg[R_MMREGISTER]:=trgobj.create(R_FPUREGISTER,R_SUBNONE,[RS_INVALID],RS_INVALID,[]);
  94. rg[R_ADDRESSREGISTER]:=trgobj.create(R_ADDRESSREGISTER,R_SUBNONE,[RS_INVALID],RS_INVALID,[]);
  95. rg[R_FLAGSREGISTER]:=trgobj.create(R_FLAGSREGISTER,R_SUBNONE,[RS_INVALID],RS_INVALID,[]);
  96. rg[R_AGGREGATEREGISTER]:=trgobj.create(R_AGGREGATEREGISTER,R_SUBNONE,[RS_INVALID],RS_INVALID,[]);
  97. end;
  98. procedure tcgllvm.done_register_allocators;
  99. begin
  100. rg[R_INTREGISTER].free;
  101. rg[R_FPUREGISTER].free;
  102. rg[R_MMREGISTER].free;
  103. rg[R_ADDRESSREGISTER].free;
  104. rg[R_FLAGSREGISTER].free;
  105. rg[R_AGGREGATEREGISTER].free;
  106. inherited done_register_allocators;
  107. end;
  108. procedure tcgllvm.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);
  109. //var
  110. // ref: treference;
  111. begin
  112. { TODO }
  113. internalerror(2010081318);
  114. //paraloc.check_simple_location;
  115. //paramanager.allocparaloc(list,paraloc.location);
  116. //case paraloc.location^.loc of
  117. // LOC_REGISTER,LOC_CREGISTER:
  118. // a_load_const_reg(list,size,a,paraloc.location^.register);
  119. // LOC_REFERENCE:
  120. // begin
  121. // reference_reset(ref,paraloc.alignment);
  122. // ref.base:=paraloc.location^.reference.index;
  123. // ref.offset:=paraloc.location^.reference.offset;
  124. // a_load_const_ref(list,size,a,ref);
  125. // end;
  126. // else
  127. // internalerror(2002081101);
  128. //end;
  129. end;
  130. procedure tcgllvm.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);
  131. var
  132. tmpref, ref: treference;
  133. location: pcgparalocation;
  134. sizeleft: aint;
  135. begin
  136. { TODO }
  137. internalerror(2010081317);
  138. //location := paraloc.location;
  139. //tmpref := r;
  140. //sizeleft := paraloc.intsize;
  141. //while assigned(location) do
  142. // begin
  143. // paramanager.allocparaloc(list,location);
  144. // case location^.loc of
  145. // LOC_REGISTER,LOC_CREGISTER:
  146. // a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  147. // LOC_REFERENCE:
  148. // begin
  149. // reference_reset_base(ref,location^.reference.index,location^.reference.offset,paraloc.alignment);
  150. // { doubles in softemu mode have a strange order of registers and references }
  151. // if location^.size=OS_32 then
  152. // g_concatcopy(list,tmpref,ref,4)
  153. // else
  154. // begin
  155. // g_concatcopy(list,tmpref,ref,sizeleft);
  156. // if assigned(location^.next) then
  157. // internalerror(2005010710);
  158. // end;
  159. // end;
  160. // LOC_FPUREGISTER,LOC_CFPUREGISTER:
  161. // case location^.size of
  162. // OS_F32, OS_F64:
  163. // a_loadfpu_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  164. // else
  165. // internalerror(2002072801);
  166. // end;
  167. // LOC_VOID:
  168. // begin
  169. // // nothing to do
  170. // end;
  171. // else
  172. // internalerror(2002081103);
  173. // end;
  174. // inc(tmpref.offset,tcgsize2size[location^.size]);
  175. // dec(sizeleft,tcgsize2size[location^.size]);
  176. // location := location^.next;
  177. // end;
  178. end;
  179. procedure tcgllvm.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);
  180. var
  181. ref: treference;
  182. tmpreg: tregister;
  183. begin
  184. { TODO }
  185. internalerror(2010081316);
  186. //paraloc.check_simple_location;
  187. //paramanager.allocparaloc(list,paraloc.location);
  188. //case paraloc.location^.loc of
  189. // LOC_REGISTER,LOC_CREGISTER:
  190. // a_loadaddr_ref_reg(list,r,paraloc.location^.register);
  191. // LOC_REFERENCE:
  192. // begin
  193. // reference_reset(ref,paraloc.alignment);
  194. // ref.base := paraloc.location^.reference.index;
  195. // ref.offset := paraloc.location^.reference.offset;
  196. // tmpreg := getintregister(list,OS_ADDR);
  197. // a_loadaddr_ref_reg(list,r,tmpreg);
  198. // a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  199. // end;
  200. // else
  201. // internalerror(2002080701);
  202. //end;
  203. end;
  204. procedure tcgllvm.a_call_name(list : TAsmList;const s : string; weak: boolean);
  205. begin
  206. { Not possible like this in LLVM, needs type info }
  207. internalerror(2010081315);
  208. end;
  209. procedure tcgllvm.a_call_reg(list : TAsmList;reg: tregister);
  210. begin
  211. { Not possible like this in LLVM, needs type info }
  212. internalerror(2010081313);
  213. end;
  214. procedure tcgllvm.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister);
  215. begin
  216. { not SSA-safe! }
  217. internalerror(2010081312);
  218. end;
  219. procedure tcgllvm.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  220. begin
  221. case op of
  222. OP_NEG,
  223. OP_NOT:
  224. a_op_reg_reg_reg(list,op,size,src,src,dst)
  225. else
  226. { not SSA-safe! }
  227. internalerror(2010081311);
  228. end;
  229. end;
  230. const
  231. topcg2llvmop: array[topcg] of tllvmop =
  232. { OP_NONE OP_MOVE OP_ADD OP_AND OP_DIV OP_IDIV OP_IMUL OP_MUL }
  233. (la_none, la_bitcast, la_add, la_and, la_udiv, la_sdiv, la_mul, la_mul,
  234. { OP_NEG OP_NOT OP_OR OP_SAR OP_SHL OP_SHR OP_SUB OP_XOR }
  235. la_none, la_none, la_or, la_ashr, la_shl, la_lshr, la_sub, la_xor,
  236. { OP_ROL OP_ROR }
  237. la_none, la_none);
  238. procedure tcgllvm.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister);
  239. var
  240. tmpreg: tregister;
  241. begin
  242. { default tcg implementation is not SSA-safe }
  243. tmpreg:=getintregister(list,size);
  244. a_load_const_reg(list,size,a,tmpreg);
  245. a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
  246. end;
  247. procedure tcgllvm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister);
  248. var
  249. orgdst,
  250. tmpreg1,
  251. tmpreg2,
  252. tmpreg3: tregister;
  253. llsize: tllvmopsize;
  254. tmpref: treference;
  255. begin
  256. llsize:=cgsize2llvmopsize[size];
  257. orgdst:=dst;
  258. if isaddressregister(src1) or
  259. isaddressregister(src2) or
  260. isaddressregister(dst) then
  261. begin
  262. { use getelementptr for address registers if possible, it helps with
  263. LLVM optimisations }
  264. if (op=OP_SUB) and
  265. (isaddressregister(src1)<>isaddressregister(src2)) then
  266. begin
  267. { since getelementptr can only add, convert the sub into an add }
  268. tmpreg1:=getintregister(list,OS_ADDR);
  269. if isaddressregister(src1) then
  270. begin
  271. a_op_reg_reg_reg(list,OP_NEG,size,src2,NR_NO,tmpreg1);
  272. src2:=tmpreg2;
  273. end
  274. else
  275. begin
  276. a_op_reg_reg_reg(list,OP_NEG,size,src1,NR_NO,tmpreg1);
  277. src1:=tmpreg2;
  278. end;
  279. op:=OP_ADD;
  280. end;
  281. if (op=OP_ADD) and
  282. (isaddressregister(src1)<>isaddressregister(src2)) then
  283. begin
  284. reference_reset_base(tmpref,NR_NO,0,1);
  285. if isaddressregister(src1) then
  286. begin
  287. tmpref.base:=src1;
  288. tmpref.index:=src2;
  289. end
  290. else
  291. begin
  292. tmpref.base:=src2;
  293. tmpref.index:=src1;
  294. end;
  295. if isaddressregister(dst) then
  296. tmpreg1:=dst
  297. else
  298. tmpreg1:=getaddressregister(list);
  299. a_loadaddr_ref_reg(list,tmpref,tmpreg1);
  300. if tmpreg1<>dst then
  301. a_load_reg_reg(list,OS_ADDR,OS_ADDR,tmpreg1,dst);
  302. exit;
  303. end
  304. else
  305. begin
  306. { move everything to integer registers }
  307. if isaddressregister(src1) then
  308. begin
  309. tmpreg1:=getintregister(list,OS_ADDR);
  310. a_load_reg_reg(list,OS_ADDR,OS_ADDR,src1,tmpreg1);
  311. src1:=tmpreg1;
  312. end;
  313. if isaddressregister(src2) then
  314. begin
  315. tmpreg1:=getintregister(list,OS_ADDR);
  316. a_load_reg_reg(list,OS_ADDR,OS_ADDR,src2,tmpreg1);
  317. src2:=tmpreg1;
  318. end;
  319. if isaddressregister(dst) then
  320. begin
  321. tmpreg1:=getintregister(list,OS_ADDR);
  322. dst:=tmpreg1;
  323. end
  324. end;
  325. end;
  326. if topcg2llvmop[op]<>la_none then
  327. list.concat(taillvm.op_reg_size_reg_reg(topcg2llvmop[op],dst,llsize,src1,src2))
  328. else
  329. begin
  330. case op of
  331. OP_NEG:
  332. { %dst = sub size 0, %src1 }
  333. list.concat(taillvm.op_reg_size_const_reg(la_sub,dst,llsize,0,src1));
  334. OP_NOT:
  335. { %dst = xor size -1, %src1 }
  336. list.concat(taillvm.op_reg_size_const_reg(la_xor,dst,llsize,-1,src1));
  337. OP_ROL:
  338. begin
  339. tmpreg1:=getintregister(list,size);
  340. tmpreg2:=getintregister(list,size);
  341. tmpreg3:=getintregister(list,size);
  342. { tmpreg1 := tcgsize2size[size] - src1 }
  343. list.concat(taillvm.op_reg_size_const_reg(la_sub,tmpreg1,llsize,tcgsize2size[size],src1));
  344. { tmpreg2 := src2 shr tmpreg1 }
  345. a_op_reg_reg_reg(list,OP_SHR,size,tmpreg1,src2,tmpreg2);
  346. { tmpreg3 := src2 shl src1 }
  347. a_op_reg_reg_reg(list,OP_SHL,size,src1,src2,tmpreg3);
  348. { dst := tmpreg2 or tmpreg3 }
  349. a_op_reg_reg_reg(list,OP_OR,size,tmpreg2,tmpreg3,dst);
  350. end;
  351. OP_ROR:
  352. begin
  353. tmpreg1:=getintregister(list,size);
  354. tmpreg2:=getintregister(list,size);
  355. tmpreg3:=getintregister(list,size);
  356. { tmpreg1 := tcgsize2size[size] - src1 }
  357. list.concat(taillvm.op_reg_size_const_reg(la_sub,tmpreg1,llsize,tcgsize2size[size],src1));
  358. { tmpreg2 := src2 shl tmpreg1 }
  359. a_op_reg_reg_reg(list,OP_SHL,size,tmpreg1,src2,tmpreg2);
  360. { tmpreg3 := src2 shr src1 }
  361. a_op_reg_reg_reg(list,OP_SHR,size,src1,src2,tmpreg3);
  362. { dst := tmpreg2 or tmpreg3 }
  363. a_op_reg_reg_reg(list,OP_OR,size,tmpreg2,tmpreg3,dst);
  364. end;
  365. else
  366. internalerror(2010081310);
  367. end;
  368. end;
  369. if dst<>orgdst then
  370. a_load_reg_reg(list,OS_ADDR,OS_ADDR,dst,orgdst);
  371. end;
  372. procedure tcgllvm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  373. begin
  374. { TODO: call intrinsics }
  375. internalerror(2010081314)
  376. end;
  377. procedure tcgllvm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  378. begin
  379. { TODO: call intrinsics }
  380. internalerror(2010081315)
  381. end;
  382. { returns a reference that either only has the base set, or a symbol }
  383. function tcgllvm.make_simple_ref(list: TAsmList; const ref: treference): treference;
  384. var
  385. tmpref: treference;
  386. hreg: tregister;
  387. begin
  388. { base (if it's present) has to be an address register, index (if it's
  389. present) an integer }
  390. if (ref.index<>NR_NO) and
  391. isaddressregister(ref.index) then
  392. internalerror(2010081301);
  393. { base address: either a symbol, a base register, or a direct
  394. offset }
  395. if assigned(ref.symbol) and
  396. (ref.base<>NR_NO) then
  397. internalerror(2010081302);
  398. hreg:=NR_NO;
  399. { the index consists of the index reg (if any) and the offset }
  400. if (ref.index<>NR_NO) then
  401. begin
  402. { if we have both an index register and an offset, add them
  403. together first }
  404. if (ref.offset<>0) then
  405. begin
  406. hreg:=getintregister(list,OS_ADDR);
  407. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.index,hreg);
  408. end
  409. else
  410. { assume the index register has always OS_ADDR as size}
  411. hreg:=ref.index;
  412. end
  413. else if (ref.offset<>0) or
  414. (not assigned(ref.symbol) and
  415. (ref.base=NR_NO)) then
  416. begin
  417. { if we have as symbol or base register, they are the base address;
  418. if not, use the offset as "base" address (e.g. a null pointer) }
  419. if assigned(ref.symbol) or
  420. (ref.base<>NR_NO) then
  421. hreg:=getintregister(list,OS_ADDR)
  422. else
  423. hreg:=getaddressregister(list);
  424. a_load_const_reg(list,OS_ADDR,ref.offset,hreg);
  425. end;
  426. if hreg<>NR_NO then
  427. begin
  428. reference_reset_base(result,getaddressregister(list),0,ref.alignment);
  429. if assigned(ref.symbol) or
  430. (ref.base<>NR_NO) then
  431. begin
  432. { only one of the above conditions is true, checked at the
  433. start }
  434. tmpref:=ref;
  435. tmpref.index:=NR_NO;
  436. tmpref.offset:=0;
  437. list.concat(taillvm.getelementptr_reg_size_ref_size_reg(result.base,SL_I8P,tmpref,cgsize2llvmopsize[OS_ADDR],hreg))
  438. end
  439. else
  440. a_load_reg_reg(list,OS_ADDR,OS_ADDR,hreg,result.base);
  441. end
  442. else
  443. result:=ref;
  444. end;
  445. function tcgllvm.make_simple_ref_of_ptrsize(list: TAsmList; const ref: treference; tosize: tcgsize): treference;
  446. var
  447. newbase: tregister;
  448. begin
  449. result:=make_simple_ref(list,ref);
  450. { convert to the desired size if <> SL_I8P }
  451. if not(tosize in [OS_8,OS_S8]) then
  452. begin
  453. newbase:=cg.getaddressregister(list);
  454. list.concat(taillvm.op_reg_size_ref_size(la_bitcast,newbase,SL_I8P,result,cgsize2llvmptropsize[tosize]));
  455. result.symbol:=nil;
  456. result.base:=newbase;
  457. end;
  458. end;
  459. procedure tcgllvm.a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);
  460. var
  461. op: tllvmop;
  462. fromsize,
  463. tosize: tllvmopsize;
  464. begin
  465. fromsize:=cgsize2llvmopsize[size];
  466. { bitcast only works amongst integers and vectors }
  467. if not isaddressregister(reg) then
  468. begin
  469. op:=la_bitcast;
  470. tosize:=fromsize;
  471. end
  472. else
  473. begin
  474. op:=la_inttoptr;
  475. tosize:=cgsize2llvmptropsize[size];
  476. end;
  477. { reg = la_bitcast fromsize a to tosize }
  478. list.concat(taillvm.op_reg_size_const_size(op,reg,fromsize,a,tosize));
  479. end;
  480. procedure tcgllvm.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  481. var
  482. tmpreg: tregister;
  483. href: treference;
  484. begin
  485. href:=make_simple_ref_of_ptrsize(list,ref,tosize);
  486. if tcgsize2size[fromsize]<>tcgsize2size[tosize] then
  487. begin
  488. tmpreg:=getintregister(list,tosize);
  489. a_load_reg_reg(list,fromsize,tosize,reg,tmpreg);
  490. end
  491. else
  492. tmpreg:=reg;
  493. { store tosize tmpreg, tosize* href }
  494. list.concat(taillvm.op_size_reg_size_ref(la_store,cgsize2llvmopsize[tosize],tmpreg,cgsize2llvmptropsize[tosize],href));
  495. end;
  496. procedure tcgllvm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const ref : treference;reg : tregister);
  497. var
  498. tmpreg: tregister;
  499. href: treference;
  500. begin
  501. href:=make_simple_ref_of_ptrsize(list,ref,fromsize);
  502. if tcgsize2size[fromsize]<>tcgsize2size[tosize] then
  503. tmpreg:=getintregister(list,fromsize)
  504. else
  505. tmpreg:=reg;
  506. { %tmpreg = load size* %ref }
  507. list.concat(taillvm.op_reg_size_ref(la_load,tmpreg,cgsize2llvmptropsize[fromsize],href));
  508. if tmpreg<>reg then
  509. a_load_reg_reg(list,fromsize,tosize,tmpreg,reg);
  510. end;
  511. procedure tcgllvm.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1, reg2 : tregister);
  512. var
  513. op: tllvmop;
  514. fromllsize,
  515. tollsize: tllvmopsize;
  516. begin
  517. if (fromsize=OS_NO) or (tosize=OS_NO) then
  518. internalerror(2010081001);
  519. { get llvm fromsize/tosize }
  520. if not isaddressregister(reg1) then
  521. fromllsize:=cgsize2llvmopsize[fromsize]
  522. else
  523. fromllsize:=cgsize2llvmptropsize[fromsize];
  524. if not isaddressregister(reg2) then
  525. tollsize:=cgsize2llvmopsize[tosize]
  526. else
  527. tollsize:=cgsize2llvmptropsize[tosize];
  528. { int to pointer or vice versa }
  529. if isaddressregister(reg1) and
  530. not isaddressregister(reg2) then
  531. op:=la_ptrtoint
  532. else if not isaddressregister(reg1) and
  533. isaddressregister(reg2) then
  534. op:=la_inttoptr
  535. { int to int or ptr to ptr: need zero/sign extension, or plain bitcast? }
  536. else if tcgsize2size[tosize]<>tcgsize2size[fromsize] then
  537. begin
  538. if tcgsize2size[tosize]<tcgsize2size[fromsize] then
  539. op:=la_trunc
  540. else if tcgsize2unsigned[fromsize]<>fromsize then
  541. { fromsize is signed -> sign extension }
  542. op:=la_sext
  543. else
  544. op:=la_zext;
  545. end
  546. else
  547. op:=la_bitcast;
  548. { reg2 = bitcast fromllsize reg1 to tollsize }
  549. list.concat(taillvm.op_reg_size_reg_size(op,reg2,fromllsize,reg1,tollsize));
  550. end;
  551. procedure tcgllvm.a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);
  552. //var
  553. // href,href2 : treference;
  554. // hloc : pcgparalocation;
  555. begin
  556. { TODO }
  557. internalerror(2010081323);
  558. //href:=ref;
  559. //hloc:=paraloc.location;
  560. //while assigned(hloc) do
  561. // begin
  562. // case hloc^.loc of
  563. // LOC_FPUREGISTER,LOC_CFPUREGISTER:
  564. // begin
  565. // paramanager.allocparaloc(list,paraloc.location);
  566. // a_loadfpu_ref_reg(list,size,size,ref,hloc^.register);
  567. // end;
  568. // LOC_REGISTER :
  569. // case hloc^.size of
  570. // OS_32,
  571. // OS_F32:
  572. // begin
  573. // paramanager.allocparaloc(list,paraloc.location);
  574. // a_load_ref_reg(list,OS_32,OS_32,href,hloc^.register);
  575. // end;
  576. // OS_64,
  577. // OS_F64:
  578. // cg64.a_load64_ref_cgpara(list,href,paraloc);
  579. // else
  580. // a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  581. // end;
  582. // LOC_REFERENCE :
  583. // begin
  584. // reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset,paraloc.alignment);
  585. // { concatcopy should choose the best way to copy the data }
  586. // g_concatcopy(list,href,href2,tcgsize2size[hloc^.size]);
  587. // end;
  588. // else
  589. // internalerror(200408241);
  590. // end;
  591. // inc(href.offset,tcgsize2size[hloc^.size]);
  592. // hloc:=hloc^.next;
  593. // end;
  594. end;
  595. procedure tcgllvm.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
  596. var
  597. op: tllvmop;
  598. fromllsize,
  599. tollsize: tllvmopsize;
  600. begin
  601. if (fromsize=OS_NO) or (tosize=OS_NO) then
  602. internalerror(2010081309);
  603. { get llvm fromsize/tosize }
  604. fromllsize:=cgsize2llvmopsize[fromsize];
  605. tollsize:=cgsize2llvmopsize[tosize];
  606. if fromllsize<tollsize then
  607. op:=la_fptrunc
  608. else if fromllsize>tollsize then
  609. op:=la_fpext
  610. else
  611. op:=la_bitcast;
  612. { reg2 = bitcast fromllsize reg1 to tollsize }
  613. list.concat(taillvm.op_reg_size_reg_size(op,reg2,fromllsize,reg1,tollsize));
  614. end;
  615. procedure tcgllvm.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
  616. var
  617. tmpreg: tregister;
  618. href: treference;
  619. begin
  620. href:=make_simple_ref_of_ptrsize(list,ref,fromsize);
  621. if fromsize<>tosize then
  622. tmpreg:=getfpuregister(list,fromsize)
  623. else
  624. tmpreg:=reg;
  625. { %tmpreg = load size* %ref }
  626. list.concat(taillvm.op_reg_size_ref(la_load,tmpreg,cgsize2llvmptropsize[fromsize],href));
  627. if tmpreg<>reg then
  628. a_loadfpu_reg_reg(list,fromsize,tosize,tmpreg,reg);
  629. end;
  630. procedure tcgllvm.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  631. var
  632. tmpreg: tregister;
  633. href: treference;
  634. begin
  635. href:=make_simple_ref_of_ptrsize(list,ref,tosize);
  636. if tcgsize2size[fromsize]<>tcgsize2size[tosize] then
  637. begin
  638. tmpreg:=getfpuregister(list,tosize);
  639. a_loadfpu_reg_reg(list,fromsize,tosize,reg,tmpreg);
  640. end
  641. else
  642. tmpreg:=reg;
  643. { store tosize tmpreg, tosize* href }
  644. list.concat(taillvm.op_size_reg_size_ref(la_store,cgsize2llvmopsize[tosize],tmpreg,cgsize2llvmptropsize[tosize],href));
  645. end;
  646. { comparison operations }
  647. procedure tcgllvm.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;l : tasmlabel);
  648. var
  649. tmpreg : tregister;
  650. begin
  651. if not isaddressregister(reg) then
  652. tmpreg:=getintregister(list,size)
  653. else
  654. tmpreg:=getaddressregister(list);
  655. a_load_const_reg(list,size,a,tmpreg);
  656. a_cmp_reg_reg_label(list,size,cmp_op,tmpreg,reg,l);
  657. end;
  658. procedure tcgllvm.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  659. var
  660. resreg,
  661. tmpreg: tregister;
  662. cmpsize: tllvmopsize;
  663. begin
  664. if isaddressregister(reg1)<>isaddressregister(reg2) then
  665. begin
  666. tmpreg:=getaddressregister(list);
  667. if not isaddressregister(reg1) then
  668. begin
  669. a_load_reg_reg(list,size,size,reg1,tmpreg);
  670. reg1:=tmpreg;
  671. end
  672. else
  673. begin
  674. a_load_reg_reg(list,size,size,reg2,tmpreg);
  675. reg2:=tmpreg;
  676. end;
  677. end;
  678. if isaddressregister(reg1) then
  679. begin
  680. if size<>OS_ADDR then
  681. internalerror(2010081308);
  682. cmpsize:=SL_I8P;
  683. end
  684. else
  685. cmpsize:=cgsize2llvmopsize[size];
  686. resreg:=getflagsregister(list);
  687. list.concat(taillvm.op_reg_cond_size_reg_reg(la_icmp,resreg,cmp_op,cmpsize,reg1,reg2));
  688. {$ifdef using_llvm_tresflags}
  689. a_jmp_flags(list,resreg,l);
  690. {$endif}
  691. end;
  692. procedure tcgllvm.a_jmp_name(list : TAsmList;const s : string);
  693. begin
  694. { it's not possible to jump between different functions in llvm }
  695. internalerror(2010081307);
  696. end;
  697. procedure tcgllvm.a_jmp_always(list : TAsmList;l: tasmlabel);
  698. var
  699. ai : taillvm;
  700. begin
  701. ai:=taillvm.op_lab(la_br,l);
  702. ai.is_jmp:=true;
  703. list.concat(ai);
  704. end;
  705. {$ifdef using_llvm_tresflags}
  706. procedure tcgllvm.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  707. var
  708. ai : taicpu;
  709. lab: tasmlabel;
  710. begin
  711. current_asmdata.getjumplabel(lab);
  712. ai:=taillvm.op_size_reg_lab_lab(la_br,SL_I1,f,l,lab);
  713. ai.is_jmp:=true;
  714. list.concat(ai);
  715. a_label(list,lab);
  716. end;
  717. procedure tcgllvm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  718. var
  719. op: tllvmop;
  720. begin
  721. if not isaddressregister(reg) then
  722. op:=la_zext
  723. else
  724. op:=la_inttoptr;
  725. list.concat(taillvm.op_reg_size_reg_size(op,reg,SL_I1,f,cgsize2llvmopsize[size]));
  726. end;
  727. {$endif using_llvm_tresflags}
  728. procedure tcgllvm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  729. begin
  730. { nothing to do }
  731. end;
  732. procedure tcgllvm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  733. begin
  734. if is_void(current_procinfo.procdef.returndef) or
  735. (
  736. (po_assembler in current_procinfo.procdef.procoptions) and
  737. (not(assigned(current_procinfo.procdef.funcretsym)) or
  738. (tabstractvarsym(current_procinfo.procdef.funcretsym).refs=0))
  739. ) or
  740. paramanager.ret_in_param(current_procinfo.procdef.returndef,current_procinfo.procdef.proccalloption) then
  741. list.concat(taillvm.op_none(la_ret))
  742. else
  743. begin
  744. { TODO: in case of a simple result, return location^.register,
  745. otherwise define an undef and use insertvalue to insert the
  746. fields
  747. list.concat(taillvm.op_def_reg(la_ret,current_procinfo.procdef.returndef,current_procinfo.procdef.funcretloc[calleeside].location^.register)); }
  748. internalerror(2010081401);
  749. end;
  750. end;
  751. procedure tcgllvm.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  752. var
  753. tmpref: treference;
  754. hreg: tregister;
  755. begin
  756. if not isaddressregister(r) then
  757. internalerror(2010081503);
  758. tmpref:=make_simple_ref(list,ref);
  759. list.concat(taillvm.op_reg_size_ref_size(la_bitcast,r,SL_I8P,tmpref,SL_I8P));
  760. end;
  761. procedure tcgllvm.g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);
  762. var
  763. srcref,dstref: treference;
  764. tmpreg : tregister;
  765. copyalignment: longint;
  766. copysize: tcgsize;
  767. procedure create_loop(iterations: aint; copyalignment: longint);
  768. var
  769. tmpbasereg,
  770. newbasereg: tregister;
  771. lab: tasmlabel;
  772. loopcntref,tmpref: treference;
  773. begin
  774. if iterations=0 then
  775. exit;
  776. if iterations<>1 then
  777. begin
  778. { init loop counter }
  779. tg.gettemp(list,sizeof(pint),sizeof(pint),tt_normal,loopcntref);
  780. a_load_const_ref(list,OS_ADDR,iterations,loopcntref);
  781. { loop label }
  782. current_asmdata.getjumplabel(lab);
  783. a_label(list,lab);
  784. end;
  785. { load source value: first load source address pointer }
  786. tmpbasereg:=getaddressregister(list);
  787. a_load_ref_reg(list,OS_ADDR,OS_ADDR,srcref,tmpbasereg);
  788. reference_reset_base(tmpref,tmpbasereg,0,copyalignment);
  789. { and then the value }
  790. tmpreg:=getintregister(list,copysize);
  791. a_load_ref_reg(list,copysize,copysize,tmpref,tmpreg);
  792. if iterations<>1 then
  793. begin
  794. { update the source reference }
  795. newbasereg:=getaddressregister(list);
  796. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,copyalignment,tmpbasereg,newbasereg);
  797. a_load_reg_ref(list,OS_ADDR,OS_ADDR,newbasereg,srcref);
  798. end;
  799. { store the loaded value: first load the dest address pointer }
  800. tmpbasereg:=getaddressregister(list);
  801. a_load_ref_reg(list,OS_ADDR,OS_ADDR,dstref,tmpbasereg);
  802. reference_reset_base(tmpref,tmpbasereg,0,copyalignment);
  803. { and store the value }
  804. a_load_reg_ref(list,copysize,copysize,tmpreg,tmpref);
  805. if iterations<>1 then
  806. begin
  807. { update the dest reference }
  808. newbasereg:=getaddressregister(list);
  809. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,copyalignment,tmpbasereg,newbasereg);
  810. a_load_reg_ref(list,OS_ADDR,OS_ADDR,newbasereg,dstref);
  811. { decrease the loop counter }
  812. a_op_const_ref(list,OP_SUB,OS_ADDR,1,loopcntref);
  813. { loop }
  814. a_cmp_const_ref_label(list,OS_ADDR,OC_NE,0,loopcntref,lab);
  815. end;
  816. end;
  817. begin { g_concatcopy }
  818. if len=0 then
  819. exit;
  820. { determine maximum common copyalignment }
  821. copyalignment:=min(source.alignment,dest.alignment);
  822. { limit to 128 bits, since we don't support > 128 bit loads/stores }
  823. if copyalignment>16 then
  824. copyalignment:=16;
  825. { don't load more per iteration than the total length }
  826. while copyalignment>len do
  827. copyalignment:=copyalignment div 2;
  828. case copyalignment of
  829. 1 : copysize:=OS_8;
  830. 2 : copysize:=OS_16;
  831. 4 : copysize:=OS_32;
  832. 8 : copysize:=OS_64;
  833. 16 : copysize:=OS_128;
  834. else
  835. internalerror(2010081304);
  836. end;
  837. { keep reference addresses in memory so we don't have to insert phi
  838. nodes; llvm will lower everything to registers, or replace it with
  839. memcpy }
  840. tmpreg:=getaddressregister(list);
  841. a_loadaddr_ref_reg(list,source,tmpreg);
  842. tg.gettemp(list,sizeof(pint),sizeof(pint),tt_normal,srcref);
  843. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,srcref);
  844. tmpreg:=getaddressregister(list);
  845. a_loadaddr_ref_reg(list,dest,tmpreg);
  846. tg.gettemp(list,sizeof(pint),sizeof(pint),tt_normal,dstref);
  847. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,dstref);
  848. { main loop (separately because alignment is propagated to LLVM) }
  849. create_loop(len div copyalignment,copyalignment);
  850. { leftovers }
  851. create_loop(len mod copyalignment,1);
  852. end;
  853. procedure tcgllvm.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
  854. begin
  855. { overflow checking cannot be performed like that with LLVM }
  856. internalerror(2010081322);
  857. end;
  858. procedure tcgllvm.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
  859. var
  860. hl : tasmlabel;
  861. ai:TAiCpu;
  862. hflags : tresflags;
  863. begin
  864. if not(cs_check_overflow in current_settings.localswitches) then
  865. exit;
  866. current_asmdata.getjumplabel(hl);
  867. case ovloc.loc of
  868. LOC_FLAGS:
  869. cg.a_jmp_flags(list,ovloc.resflags,hl);
  870. else
  871. internalerror(2010081321);
  872. end;
  873. a_call_name(list,'FPC_OVERFLOW',false);
  874. a_label(list,hl);
  875. end;
  876. procedure tcgllvm.g_save_registers(list : TAsmList);
  877. begin
  878. { LLVM does that for us }
  879. end;
  880. procedure tcgllvm.g_restore_registers(list : TAsmList);
  881. begin
  882. { LLVM does that for us }
  883. end;
  884. procedure tcgllvm.g_stackpointer_alloc(list: TAsmList; size: longint);
  885. begin
  886. internalerror(2010081319);
  887. end;
  888. procedure tcgllvm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  889. begin
  890. { TODO }
  891. internalerror(2010081320);
  892. //if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  893. // Internalerror(200006137);
  894. //if not assigned(procdef._class) or
  895. // (procdef.procoptions*[po_classmethod, po_staticmethod,
  896. // po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  897. // Internalerror(200006138);
  898. //if procdef.owner.symtabletype<>ObjectSymtable then
  899. // Internalerror(200109191);
  900. //
  901. //make_global:=false;
  902. //if (not current_module.is_unit) or
  903. // create_smartlink or
  904. // (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  905. // make_global:=true;
  906. //
  907. //if make_global then
  908. // list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  909. //else
  910. // list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  911. //
  912. //{ the wrapper might need aktlocaldata for the additional data to
  913. // load the constant }
  914. //current_procinfo:=cprocinfo.create(nil);
  915. //
  916. //{ set param1 interface to self }
  917. //g_adjust_self_value(list,procdef,ioffset);
  918. //
  919. //{ case 4 }
  920. //if po_virtualmethod in procdef.procoptions then
  921. // begin
  922. // loadvmttor12;
  923. // op_onr12methodaddr;
  924. // end
  925. //{ case 0 }
  926. //else
  927. // list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)));
  928. //list.concatlist(current_procinfo.aktlocaldata);
  929. //
  930. //current_procinfo.Free;
  931. //current_procinfo:=nil;
  932. //
  933. //list.concat(Tai_symbol_end.Createname(labelname));
  934. end;
  935. procedure create_codegen;
  936. begin
  937. cg:=tcgllvm.create;
  938. end;
  939. end.