agllvm.pas 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094
  1. {
  2. Copyright (c) 1998-2013 by the Free Pascal team
  3. This unit implements the generic part of the LLVM IR writer
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit agllvm;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,globals,
  22. aasmbase,aasmtai,aasmdata,
  23. assemble;
  24. type
  25. TLLVMInstrWriter = class;
  26. { TLLVMAssember }
  27. TLLVMAssember=class(texternalassembler)
  28. protected
  29. fdecllevel: longint;
  30. procedure WriteExtraHeader;virtual;
  31. procedure WriteExtraFooter;virtual;
  32. procedure WriteInstruction(hp: tai);
  33. procedure WriteLlvmInstruction(hp: tai);
  34. procedure WriteDirectiveName(dir: TAsmDirective); virtual;
  35. procedure WriteRealConst(hp: tai_realconst; do_line: boolean);
  36. procedure WriteOrdConst(hp: tai_const);
  37. procedure WriteTai(const replaceforbidden: boolean; const do_line: boolean; var InlineLevel: cardinal; var hp: tai);
  38. public
  39. constructor create(smart: boolean); override;
  40. procedure AsmLn; override;
  41. function MakeCmdLine: TCmdStr; override;
  42. procedure WriteTree(p:TAsmList);override;
  43. procedure WriteAsmList;override;
  44. destructor destroy; override;
  45. protected
  46. InstrWriter: TLLVMInstrWriter;
  47. end;
  48. {# This is the base class for writing instructions.
  49. The WriteInstruction() method must be overridden
  50. to write a single instruction to the assembler
  51. file.
  52. }
  53. TLLVMInstrWriter = class
  54. constructor create(_owner: TLLVMAssember);
  55. procedure WriteInstruction(hp : tai);
  56. protected
  57. owner: TLLVMAssember;
  58. fstr: TSymStr;
  59. function getopstr(const o:toper; refwithalign: boolean) : TSymStr;
  60. end;
  61. implementation
  62. uses
  63. SysUtils,
  64. cutils,cfileutl,systems,
  65. fmodule,verbose,
  66. aasmcnst,symconst,symdef,
  67. llvmbase,aasmllvm,itllvm,llvmdef,
  68. cgbase,cgutils,cpubase;
  69. const
  70. line_length = 70;
  71. type
  72. {$ifdef cpuextended}
  73. t80bitarray = array[0..9] of byte;
  74. {$endif cpuextended}
  75. t64bitarray = array[0..7] of byte;
  76. t32bitarray = array[0..3] of byte;
  77. {****************************************************************************}
  78. { Support routines }
  79. {****************************************************************************}
  80. function single2str(d : single) : string;
  81. var
  82. hs : string;
  83. begin
  84. str(d,hs);
  85. { replace space with + }
  86. if hs[1]=' ' then
  87. hs[1]:='+';
  88. single2str:=hs
  89. end;
  90. function double2str(d : double) : string;
  91. var
  92. hs : string;
  93. begin
  94. str(d,hs);
  95. { replace space with + }
  96. if hs[1]=' ' then
  97. hs[1]:='+';
  98. double2str:=hs
  99. end;
  100. function extended2str(e : extended) : string;
  101. var
  102. hs : string;
  103. begin
  104. str(e,hs);
  105. { replace space with + }
  106. if hs[1]=' ' then
  107. hs[1]:='+';
  108. extended2str:=hs
  109. end;
  110. {****************************************************************************}
  111. { LLVM Instruction writer }
  112. {****************************************************************************}
  113. function getregisterstring(reg: tregister): ansistring;
  114. begin
  115. if getregtype(reg)=R_TEMPREGISTER then
  116. result:='%tmp.'
  117. else
  118. result:='%reg.'+tostr(byte(getregtype(reg)))+'_';
  119. result:=result+tostr(getsupreg(reg));
  120. end;
  121. function getreferencealignstring(var ref: treference) : ansistring;
  122. begin
  123. result:=', align '+tostr(ref.alignment);
  124. end;
  125. function getreferencestring(var ref : treference; withalign: boolean) : ansistring;
  126. begin
  127. result:='';
  128. if assigned(ref.relsymbol) or
  129. (assigned(ref.symbol) =
  130. (ref.base<>NR_NO)) or
  131. (ref.index<>NR_NO) or
  132. (ref.offset<>0) then
  133. begin
  134. result:=' **(error ref: ';
  135. if assigned(ref.symbol) then
  136. result:=result+'sym='+ref.symbol.name+', ';
  137. if assigned(ref.relsymbol) then
  138. result:=result+'sym='+ref.relsymbol.name+', ';
  139. if ref.base=NR_NO then
  140. result:=result+'base=NR_NO, ';
  141. if ref.index<>NR_NO then
  142. result:=result+'index<>NR_NO, ';
  143. if ref.offset<>0 then
  144. result:=result+'offset='+tostr(ref.offset);
  145. result:=result+')**'
  146. // internalerror(2013060225);
  147. end;
  148. if ref.base<>NR_NO then
  149. result:=result+getregisterstring(ref.base)
  150. else
  151. result:=result+LlvmAsmSymName(ref.symbol);
  152. if withalign then
  153. result:=result+getreferencealignstring(ref);
  154. end;
  155. function getparas(const o: toper): ansistring;
  156. var
  157. i: longint;
  158. para: pllvmcallpara;
  159. begin
  160. result:='(';
  161. for i:=0 to o.paras.count-1 do
  162. begin
  163. if i<>0 then
  164. result:=result+', ';
  165. para:=pllvmcallpara(o.paras[i]);
  166. result:=result+llvmencodetype(para^.def);
  167. if para^.valueext<>lve_none then
  168. result:=result+llvmvalueextension2str[para^.valueext];
  169. case para^.loc of
  170. LOC_REGISTER,
  171. LOC_FPUREGISTER,
  172. LOC_MMREGISTER:
  173. result:=result+' '+getregisterstring(para^.reg);
  174. else
  175. internalerror(2014010801);
  176. end;
  177. end;
  178. result:=result+')';
  179. end;
  180. function llvmdoubletostr(const d: double): TSymStr;
  181. type
  182. tdoubleval = record
  183. case byte of
  184. 1: (d: double);
  185. 2: (i: int64);
  186. end;
  187. begin
  188. { "When using the hexadecimal form, constants of types half,
  189. float, and double are represented using the 16-digit form shown
  190. above (which matches the IEEE754 representation for double)"
  191. And always in big endian form (sign bit leftmost)
  192. }
  193. result:='0x'+hexstr(tdoubleval(d).i,16);
  194. end;
  195. {$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
  196. function llvmextendedtostr(const e: extended): TSymStr;
  197. var
  198. extendedval: record
  199. case byte of
  200. 1: (e: extended);
  201. 2: (r: packed record
  202. {$ifdef FPC_LITTLE_ENDIAN}
  203. l: int64;
  204. h: word;
  205. {$else FPC_LITTLE_ENDIAN}
  206. h: int64;
  207. l: word;
  208. {$endif FPC_LITTLE_ENDIAN}
  209. end;
  210. );
  211. end;
  212. begin
  213. extendedval.e:=e;
  214. { hex format is always big endian in llvm }
  215. result:='0xK'+hexstr(extendedval.r.h,sizeof(extendedval.r.h)*2)+
  216. hexstr(extendedval.r.l,sizeof(extendedval.r.l)*2);
  217. end;
  218. {$endif cpuextended}
  219. function TLLVMInstrWriter.getopstr(const o:toper; refwithalign: boolean) : TSymStr;
  220. var
  221. hs : ansistring;
  222. hp: tai;
  223. tmpinline: cardinal;
  224. begin
  225. case o.typ of
  226. top_reg:
  227. getopstr:=getregisterstring(o.reg);
  228. top_const:
  229. getopstr:=tostr(int64(o.val));
  230. top_ref:
  231. if o.ref^.refaddr=addr_full then
  232. begin
  233. getopstr:='';
  234. getopstr:=LlvmAsmSymName(o.ref^.symbol);
  235. if o.ref^.offset<>0 then
  236. internalerror(2013060223);
  237. end
  238. else
  239. getopstr:=getreferencestring(o.ref^,refwithalign);
  240. top_def:
  241. begin
  242. getopstr:=llvmencodetype(o.def);
  243. end;
  244. top_cond:
  245. begin
  246. getopstr:=llvm_cond2str[o.cond];
  247. end;
  248. top_fpcond:
  249. begin
  250. getopstr:=llvm_fpcond2str[o.fpcond];
  251. end;
  252. top_single,
  253. top_double:
  254. begin
  255. { "When using the hexadecimal form, constants of types half,
  256. float, and double are represented using the 16-digit form shown
  257. above (which matches the IEEE754 representation for double)"
  258. And always in big endian form (sign bit leftmost)
  259. }
  260. if o.typ=top_double then
  261. result:=llvmdoubletostr(o.dval)
  262. else
  263. result:=llvmdoubletostr(o.sval)
  264. end;
  265. top_para:
  266. begin
  267. result:=getparas(o);
  268. end;
  269. top_tai:
  270. begin
  271. tmpinline:=1;
  272. hp:=o.ai;
  273. owner.AsmWrite(fstr);
  274. fstr:='';
  275. owner.WriteTai(false,false,tmpinline,hp);
  276. result:='';
  277. end;
  278. {$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
  279. top_extended80:
  280. begin
  281. result:=llvmextendedtostr(o.eval);
  282. end;
  283. {$endif cpuextended}
  284. else
  285. internalerror(2013060227);
  286. end;
  287. end;
  288. procedure TLLVMInstrWriter.WriteInstruction(hp: tai);
  289. var
  290. op: tllvmop;
  291. sep: TSymStr;
  292. i, opstart: byte;
  293. nested: boolean;
  294. done: boolean;
  295. begin
  296. op:=taillvm(hp).llvmopcode;
  297. { we write everything immediately rather than adding it into a string,
  298. because operands may contain other tai that will also write things out
  299. (and their output must come after everything that was processed in this
  300. instruction, such as its opcode or previous operands) }
  301. if owner.fdecllevel=0 then
  302. owner.AsmWrite(#9);
  303. sep:=' ';
  304. done:=false;
  305. opstart:=0;
  306. nested:=false;
  307. case op of
  308. la_ret, la_br, la_switch, la_indirectbr,
  309. la_invoke, la_resume,
  310. la_unreachable,
  311. la_store,
  312. la_fence,
  313. la_cmpxchg,
  314. la_atomicrmw:
  315. begin
  316. { instructions that never have a result }
  317. end;
  318. la_call:
  319. begin
  320. if taillvm(hp).oper[0]^.reg<>NR_NO then
  321. owner.AsmWrite(getregisterstring(taillvm(hp).oper[0]^.reg)+' = ');
  322. sep:=' ';
  323. opstart:=1;
  324. end;
  325. la_alloca:
  326. begin
  327. owner.AsmWrite(getreferencestring(taillvm(hp).oper[0]^.ref^,false)+' = ');
  328. sep:=' ';
  329. opstart:=1;
  330. end;
  331. la_trunc, la_zext, la_sext, la_fptrunc, la_fpext,
  332. la_fptoui, la_fptosi, la_uitofp, la_sitofp,
  333. la_ptrtoint, la_inttoptr,
  334. la_bitcast:
  335. begin
  336. { destination can be empty in case of nested constructs, or
  337. data initialisers }
  338. if (taillvm(hp).oper[0]^.typ<>top_reg) or
  339. (taillvm(hp).oper[0]^.reg<>NR_NO) then
  340. owner.AsmWrite(getopstr(taillvm(hp).oper[0]^,false)+' = ')
  341. else
  342. nested:=true;
  343. owner.AsmWrite(llvm_op2str[op]);
  344. if not nested then
  345. owner.AsmWrite(' ')
  346. else
  347. owner.AsmWrite(' (');
  348. owner.AsmWrite(getopstr(taillvm(hp).oper[1]^,false));
  349. { if there's a tai operand, its def is used instead of an
  350. explicit def operand }
  351. if taillvm(hp).ops=4 then
  352. begin
  353. owner.AsmWrite(' ');
  354. owner.AsmWrite(getopstr(taillvm(hp).oper[2]^,false));
  355. opstart:=3;
  356. end
  357. else
  358. opstart:=2;
  359. owner.AsmWrite(' to ');
  360. owner.AsmWrite(getopstr(taillvm(hp).oper[opstart]^,false));
  361. done:=true;
  362. end
  363. else
  364. begin
  365. if (taillvm(hp).oper[0]^.typ<>top_reg) or
  366. (taillvm(hp).oper[0]^.reg<>NR_NO) then
  367. begin
  368. owner.AsmWrite(getopstr(taillvm(hp).oper[0]^,true)+' = ');
  369. end
  370. else
  371. nested:=true;
  372. sep:=' ';
  373. opstart:=1
  374. end;
  375. end;
  376. { process operands }
  377. if not done then
  378. begin
  379. owner.AsmWrite(llvm_op2str[op]);
  380. if nested then
  381. owner.AsmWrite(' (');
  382. if taillvm(hp).ops<>0 then
  383. begin
  384. for i:=opstart to taillvm(hp).ops-1 do
  385. begin
  386. owner.AsmWrite(sep);
  387. owner.AsmWrite(getopstr(taillvm(hp).oper[i]^,op in [la_load,la_store]));
  388. if (taillvm(hp).oper[i]^.typ in [top_def,top_cond,top_fpcond]) or
  389. (op=la_call) then
  390. sep :=' '
  391. else
  392. sep:=', ';
  393. end;
  394. end;
  395. end;
  396. if op=la_alloca then
  397. owner.AsmWrite(getreferencealignstring(taillvm(hp).oper[0]^.ref^));
  398. if nested then
  399. owner.AsmWrite(')');
  400. owner.AsmLn;
  401. end;
  402. {****************************************************************************}
  403. { LLVM Assembler writer }
  404. {****************************************************************************}
  405. destructor TLLVMAssember.Destroy;
  406. begin
  407. InstrWriter.free;
  408. inherited destroy;
  409. end;
  410. function TLLVMAssember.MakeCmdLine: TCmdStr;
  411. var
  412. optstr: TCmdStr;
  413. begin
  414. result := inherited MakeCmdLine;
  415. { standard optimization flags for llc -- todo: this needs to be split
  416. into a call to opt and one to llc }
  417. if cs_opt_level3 in current_settings.optimizerswitches then
  418. optstr:='-O3'
  419. else if cs_opt_level2 in current_settings.optimizerswitches then
  420. optstr:='-O2'
  421. else if cs_opt_level1 in current_settings.optimizerswitches then
  422. optstr:='-O1'
  423. else
  424. optstr:='-O0';
  425. { stack frame elimination }
  426. if not(cs_opt_stackframe in current_settings.optimizerswitches) then
  427. optstr:=optstr+' -disable-fp-elim';
  428. { fast math }
  429. if cs_opt_fastmath in current_settings.optimizerswitches then
  430. optstr:=optstr+' -enable-unsafe-fp-math -enable-fp-mad -fp-contract=fast';
  431. { smart linking }
  432. if cs_create_smart in current_settings.moduleswitches then
  433. optstr:=optstr+' -fdata-sections -fcode-sections';
  434. { pic }
  435. if cs_create_pic in current_settings.moduleswitches then
  436. optstr:=optstr+' -relocation-model=pic'
  437. else if not(target_info.system in systems_darwin) then
  438. optstr:=optstr+' -relocation-model=static'
  439. else
  440. optstr:=optstr+' -relocation-model=dynamic-no-pic';
  441. { our stack alignment is non-standard on some targets. The following
  442. parameter is however ignored on some targets by llvm, so it may not
  443. be enough }
  444. optstr:=optstr+' -stack-alignment='+tostr(target_info.stackalign*8);
  445. { force object output instead of textual assembler code }
  446. optstr:=optstr+' -filetype=obj';
  447. replace(result,'$OPT',optstr);
  448. end;
  449. procedure TLLVMAssember.WriteTree(p:TAsmList);
  450. var
  451. hp : tai;
  452. InlineLevel : cardinal;
  453. do_line : boolean;
  454. replaceforbidden: boolean;
  455. begin
  456. if not assigned(p) then
  457. exit;
  458. replaceforbidden:=target_asm.dollarsign<>'$';
  459. InlineLevel:=0;
  460. { lineinfo is only needed for al_procedures (PFV) }
  461. do_line:=(cs_asm_source in current_settings.globalswitches) or
  462. ((cs_lineinfo in current_settings.moduleswitches)
  463. and (p=current_asmdata.asmlists[al_procedures]));
  464. hp:=tai(p.first);
  465. while assigned(hp) do
  466. begin
  467. prefetch(pointer(hp.next)^);
  468. if not(hp.typ in SkipLineInfo) then
  469. begin
  470. current_filepos:=tailineinfo(hp).fileinfo;
  471. { no line info for inlined code }
  472. if do_line and (inlinelevel=0) then
  473. WriteSourceLine(hp as tailineinfo);
  474. end;
  475. WriteTai(replaceforbidden, do_line, InlineLevel, hp);
  476. hp:=tai(hp.next);
  477. end;
  478. end;
  479. procedure TLLVMAssember.WriteExtraHeader;
  480. begin
  481. AsmWrite('target datalayout = "');
  482. AsmWrite(target_info.llvmdatalayout);
  483. AsmWriteln('"');
  484. AsmWrite('target triple = "');
  485. AsmWrite(llvm_target_name);
  486. AsmWriteln('"');
  487. end;
  488. procedure TLLVMAssember.WriteExtraFooter;
  489. begin
  490. end;
  491. procedure TLLVMAssember.WriteInstruction(hp: tai);
  492. begin
  493. end;
  494. procedure TLLVMAssember.WriteLlvmInstruction(hp: tai);
  495. begin
  496. InstrWriter.WriteInstruction(hp);
  497. end;
  498. procedure TLLVMAssember.WriteRealConst(hp: tai_realconst; do_line: boolean);
  499. begin
  500. if do_line and
  501. (fdecllevel=0) then
  502. begin
  503. case tai_realconst(hp).realtyp of
  504. aitrealconst_s32bit:
  505. AsmWriteLn(target_asm.comment+'value: '+single2str(tai_realconst(hp).value.s32val));
  506. aitrealconst_s64bit:
  507. AsmWriteLn(target_asm.comment+'value: '+double2str(tai_realconst(hp).value.s64val));
  508. {$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
  509. { can't write full 80 bit floating point constants yet on non-x86 }
  510. aitrealconst_s80bit:
  511. AsmWriteLn(target_asm.comment+'value: '+extended2str(tai_realconst(hp).value.s80val));
  512. {$endif cpuextended}
  513. aitrealconst_s64comp:
  514. AsmWriteLn(target_asm.comment+'value: '+extended2str(tai_realconst(hp).value.s64compval));
  515. else
  516. internalerror(2014050604);
  517. end;
  518. end;
  519. case hp.realtyp of
  520. aitrealconst_s32bit:
  521. AsmWriteln(llvmdoubletostr(hp.value.s32val));
  522. aitrealconst_s64bit:
  523. AsmWriteln(llvmdoubletostr(hp.value.s64val));
  524. {$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
  525. aitrealconst_s80bit:
  526. AsmWriteln(llvmextendedtostr(hp.value.s80val));
  527. {$endif defined(cpuextended)}
  528. aitrealconst_s64comp:
  529. { handled as int64 most of the time in llvm }
  530. AsmWriteln(tostr(round(hp.value.s64compval)));
  531. else
  532. internalerror(2014062401);
  533. end;
  534. end;
  535. procedure TLLVMAssember.WriteOrdConst(hp: tai_const);
  536. var
  537. consttyp: taiconst_type;
  538. begin
  539. if fdecllevel=0 then
  540. asmwrite(target_asm.comment+' const ');
  541. consttyp:=hp.consttype;
  542. case consttyp of
  543. aitconst_got,
  544. aitconst_gotoff_symbol,
  545. aitconst_uleb128bit,
  546. aitconst_sleb128bit,
  547. aitconst_rva_symbol,
  548. aitconst_secrel32_symbol,
  549. aitconst_darwin_dwarf_delta32,
  550. aitconst_darwin_dwarf_delta64,
  551. aitconst_half16bit,
  552. aitconst_gs:
  553. internalerror(2014052901);
  554. aitconst_128bit,
  555. aitconst_64bit,
  556. aitconst_32bit,
  557. aitconst_16bit,
  558. aitconst_8bit,
  559. aitconst_16bit_unaligned,
  560. aitconst_32bit_unaligned,
  561. aitconst_64bit_unaligned:
  562. begin
  563. if fdecllevel=0 then
  564. AsmWrite(target_asm.comment);
  565. { can't have compile-time differences between symbols; these are
  566. normally for PIC, but llvm takes care of that for us }
  567. if assigned(hp.endsym) then
  568. internalerror(2014052902);
  569. if assigned(hp.sym) then
  570. begin
  571. AsmWrite(LlvmAsmSymName(hp.sym));
  572. { can't have offsets }
  573. if hp.value<>0 then
  574. if fdecllevel<>0 then
  575. internalerror(2014052903)
  576. else
  577. asmwrite(' -- symbol offset: ' + tostr(hp.value));
  578. end
  579. else if hp.value=0 then
  580. AsmWrite('zeroinitializer')
  581. else
  582. AsmWrite(tostr(hp.value));
  583. AsmLn;
  584. end;
  585. else
  586. internalerror(200704251);
  587. end;
  588. end;
  589. procedure TLLVMAssember.WriteTai(const replaceforbidden: boolean; const do_line: boolean; var InlineLevel: cardinal; var hp: tai);
  590. procedure WriteTypedConstData(hp: tai_abstracttypedconst);
  591. var
  592. p: tai_abstracttypedconst;
  593. pval: tai;
  594. defstr: TSymStr;
  595. first, gotstring: boolean;
  596. begin
  597. defstr:=llvmencodetype(hp.def);
  598. { write the struct, array or simple type }
  599. case hp.adetyp of
  600. tck_record:
  601. begin
  602. AsmWrite(defstr);
  603. AsmWrite(' ');
  604. AsmWrite('<{');
  605. first:=true;
  606. for p in tai_aggregatetypedconst(hp) do
  607. begin
  608. if not first then
  609. AsmWrite(', ')
  610. else
  611. first:=false;
  612. WriteTypedConstData(p);
  613. end;
  614. AsmWrite('}>');
  615. end;
  616. tck_array:
  617. begin
  618. AsmWrite(defstr);
  619. first:=true;
  620. gotstring:=false;
  621. for p in tai_aggregatetypedconst(hp) do
  622. begin
  623. if not first then
  624. AsmWrite(',')
  625. else
  626. begin
  627. AsmWrite(' ');
  628. if (tai_abstracttypedconst(p).adetyp=tck_simple) and
  629. (tai_simpletypedconst(p).val.typ=ait_string) then
  630. begin
  631. gotstring:=true;
  632. end
  633. else
  634. begin
  635. AsmWrite('[');
  636. end;
  637. first:=false;
  638. end;
  639. { cannot concat strings and other things }
  640. if gotstring and
  641. ((tai_abstracttypedconst(p).adetyp<>tck_simple) or
  642. (tai_simpletypedconst(p).val.typ<>ait_string)) then
  643. internalerror(2014062701);
  644. WriteTypedConstData(p);
  645. end;
  646. if not gotstring then
  647. AsmWrite(']');
  648. end;
  649. tck_simple:
  650. begin
  651. pval:=tai_simpletypedconst(hp).val;
  652. if pval.typ<>ait_string then
  653. begin
  654. AsmWrite(defstr);
  655. AsmWrite(' ');
  656. end;
  657. WriteTai(replaceforbidden,do_line,InlineLevel,pval);
  658. end;
  659. end;
  660. end;
  661. var
  662. hp2: tai;
  663. s: string;
  664. i: longint;
  665. ch: ansichar;
  666. begin
  667. case hp.typ of
  668. ait_comment :
  669. begin
  670. AsmWrite(target_asm.comment);
  671. AsmWritePChar(tai_comment(hp).str);
  672. AsmLn;
  673. end;
  674. ait_regalloc :
  675. begin
  676. if (cs_asm_regalloc in current_settings.globalswitches) then
  677. begin
  678. AsmWrite(#9+target_asm.comment+'Register ');
  679. repeat
  680. AsmWrite(std_regname(Tai_regalloc(hp).reg));
  681. if (hp.next=nil) or
  682. (tai(hp.next).typ<>ait_regalloc) or
  683. (tai_regalloc(hp.next).ratype<>tai_regalloc(hp).ratype) then
  684. break;
  685. hp:=tai(hp.next);
  686. AsmWrite(',');
  687. until false;
  688. AsmWrite(' ');
  689. AsmWriteLn(regallocstr[tai_regalloc(hp).ratype]);
  690. end;
  691. end;
  692. ait_tempalloc :
  693. begin
  694. if (cs_asm_tempalloc in current_settings.globalswitches) then
  695. WriteTempalloc(tai_tempalloc(hp));
  696. end;
  697. ait_align,
  698. ait_section :
  699. begin
  700. { ignore, specified as part of declarations -- don't write
  701. comment, because could appear in the middle of an aggregate
  702. constant definition }
  703. end;
  704. ait_datablock :
  705. begin
  706. AsmWrite(target_asm.comment);
  707. AsmWriteln('datablock');
  708. end;
  709. ait_const:
  710. begin
  711. WriteOrdConst(tai_const(hp));
  712. end;
  713. ait_realconst :
  714. begin
  715. WriteRealConst(tai_realconst(hp), do_line);
  716. end;
  717. ait_string :
  718. begin
  719. if fdecllevel=0 then
  720. AsmWrite(target_asm.comment);
  721. AsmWrite('c"');
  722. for i:=1 to tai_string(hp).len do
  723. begin
  724. ch:=tai_string(hp).str[i-1];
  725. case ch of
  726. #0, {This can't be done by range, because a bug in FPC}
  727. #1..#31,
  728. #128..#255,
  729. '"',
  730. '\' : s:='\'+hexStr(ord(ch),2);
  731. else
  732. s:=ch;
  733. end;
  734. AsmWrite(s);
  735. end;
  736. AsmWriteLn('"');
  737. end;
  738. ait_label :
  739. begin
  740. if (tai_label(hp).labsym.is_used) then
  741. begin
  742. if (tai_label(hp).labsym.bind=AB_PRIVATE_EXTERN) then
  743. begin
  744. { should be emitted as part of the variable/function def }
  745. internalerror(2013010703);
  746. end;
  747. if tai_label(hp).labsym.bind in [AB_GLOBAL, AB_PRIVATE_EXTERN] then
  748. begin
  749. { should be emitted as part of the variable/function def }
  750. //internalerror(2013010704);
  751. AsmWriteln(target_asm.comment+'global/privateextern label: '+tai_label(hp).labsym.name);
  752. end;
  753. if replaceforbidden then
  754. AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_label(hp).labsym.name))
  755. else
  756. AsmWrite(tai_label(hp).labsym.name);
  757. AsmWriteLn(':');
  758. end;
  759. end;
  760. ait_symbol :
  761. begin
  762. if fdecllevel=0 then
  763. AsmWrite(target_asm.comment);
  764. AsmWriteln(LlvmAsmSymName(tai_symbol(hp).sym));
  765. { todo }
  766. if tai_symbol(hp).has_value then
  767. internalerror(2014062402);
  768. end;
  769. ait_llvmdecl:
  770. begin
  771. if taillvmdecl(hp).def.typ=procdef then
  772. begin
  773. if taillvmdecl(hp).namesym.bind in [AB_EXTERNAL, AB_WEAK_EXTERNAL] then
  774. begin
  775. asmwrite('declare');
  776. asmwriteln(llvmencodeproctype(tprocdef(taillvmdecl(hp).def), taillvmdecl(hp).namesym.name, lpd_decl));
  777. end
  778. else
  779. begin
  780. asmwrite('define');
  781. asmwrite(llvmencodeproctype(tprocdef(taillvmdecl(hp).def), '', lpd_decl));
  782. asmwriteln(' {');
  783. end;
  784. end
  785. else
  786. begin
  787. asmwrite(LlvmAsmSymName(taillvmdecl(hp).namesym));
  788. case taillvmdecl(hp).namesym.bind of
  789. AB_EXTERNAL:
  790. asmwrite(' = external ');
  791. AB_COMMON:
  792. asmwrite(' = common ');
  793. AB_LOCAL:
  794. asmwrite(' = internal ');
  795. AB_GLOBAL:
  796. asmwrite(' = ');
  797. AB_WEAK_EXTERNAL:
  798. asmwrite(' = extern_weak ');
  799. AB_PRIVATE_EXTERN:
  800. asmwrite('= linker_private ');
  801. else
  802. internalerror(2014020104);
  803. end;
  804. if taillvmdecl(hp).tls then
  805. asmwrite('thread_local ');
  806. { todo: handle more different section types (mainly
  807. Objective-C }
  808. if taillvmdecl(hp).sec in [sec_rodata,sec_rodata_norel] then
  809. asmwrite('unnamed_addr constant ')
  810. else
  811. asmwrite('global ');
  812. if not assigned(taillvmdecl(hp).initdata) then
  813. begin
  814. asmwrite(llvmencodetype(taillvmdecl(hp).def));
  815. if not(taillvmdecl(hp).namesym.bind in [AB_EXTERNAL, AB_WEAK_EXTERNAL]) then
  816. asmwrite(' zeroinitializer');
  817. end
  818. else
  819. begin
  820. inc(fdecllevel);
  821. { can't have an external symbol with initialisation data }
  822. if taillvmdecl(hp).namesym.bind in [AB_EXTERNAL, AB_WEAK_EXTERNAL] then
  823. internalerror(2014052905);
  824. { bitcast initialisation data to the type of the constant }
  825. { write initialisation data }
  826. hp2:=tai(taillvmdecl(hp).initdata.first);
  827. while assigned(hp2) do
  828. begin
  829. WriteTai(replaceforbidden,do_line,InlineLevel,hp2);
  830. hp2:=tai(hp2.next);
  831. end;
  832. dec(fdecllevel);
  833. end;
  834. { alignment }
  835. asmwrite(', align ');
  836. asmwriteln(tostr(taillvmdecl(hp).alignment));
  837. end;
  838. end;
  839. ait_llvmalias:
  840. begin
  841. asmwrite(LlvmAsmSymName(taillvmalias(hp).newsym));
  842. asmwrite(' = alias ');
  843. if taillvmalias(hp).linkage<>lll_default then
  844. begin
  845. str(taillvmalias(hp).linkage, s);
  846. asmwrite(copy(s, length('lll_'), 255));
  847. asmwrite(' ');
  848. end
  849. else
  850. asmwrite('external ');
  851. if taillvmalias(hp).vis<>llv_default then
  852. begin
  853. str(taillvmalias(hp).vis, s);
  854. asmwrite(copy(s, length('llv_'), 255));
  855. asmwrite(' ');
  856. end;
  857. asmwrite(llvmencodeproctype(tabstractprocdef(taillvmalias(hp).def), '', lpd_alias));
  858. asmwrite('* ');
  859. asmwriteln(LlvmAsmSymName(taillvmalias(hp).oldsym));
  860. end;
  861. ait_symbolpair:
  862. begin
  863. { should be emitted as part of the symbol def }
  864. internalerror(2013010708);
  865. end;
  866. ait_weak:
  867. begin
  868. { should be emitted as part of the symbol def }
  869. internalerror(2013010709);
  870. end;
  871. ait_symbol_end :
  872. begin
  873. if tai_symbol_end(hp).sym.typ=AT_FUNCTION then
  874. asmwriteln('}')
  875. else
  876. asmwriteln('; ait_symbol_end error, should not be generated');
  877. // internalerror(2013010711);
  878. end;
  879. ait_instruction :
  880. begin
  881. WriteInstruction(hp);
  882. end;
  883. ait_llvmins:
  884. begin
  885. WriteLlvmInstruction(hp);
  886. end;
  887. ait_stab :
  888. begin
  889. internalerror(2013010712);
  890. end;
  891. ait_force_line,
  892. ait_function_name :
  893. ;
  894. ait_cutobject :
  895. begin
  896. end;
  897. ait_marker :
  898. if tai_marker(hp).kind=mark_NoLineInfoStart then
  899. inc(InlineLevel)
  900. else if tai_marker(hp).kind=mark_NoLineInfoEnd then
  901. dec(InlineLevel);
  902. ait_directive :
  903. begin
  904. WriteDirectiveName(tai_directive(hp).directive);
  905. if tai_directive(hp).name <>'' then
  906. AsmWrite(tai_directive(hp).name);
  907. AsmLn;
  908. end;
  909. ait_seh_directive :
  910. begin
  911. internalerror(2013010713);
  912. end;
  913. ait_varloc:
  914. begin
  915. if tai_varloc(hp).newlocationhi<>NR_NO then
  916. AsmWrite(strpnew('Var '+tai_varloc(hp).varsym.realname+' located in register '+
  917. std_regname(tai_varloc(hp).newlocationhi)+':'+std_regname(tai_varloc(hp).newlocation)))
  918. else
  919. AsmWrite(strpnew('Var '+tai_varloc(hp).varsym.realname+' located in register '+
  920. std_regname(tai_varloc(hp).newlocation)));
  921. AsmLn;
  922. end;
  923. ait_typedconst:
  924. begin
  925. WriteTypedConstData(tai_abstracttypedconst(hp));
  926. end
  927. else
  928. internalerror(2006012201);
  929. end;
  930. end;
  931. constructor TLLVMAssember.create(smart: boolean);
  932. begin
  933. inherited create(smart);
  934. InstrWriter:=TLLVMInstrWriter.create(self);
  935. end;
  936. procedure TLLVMAssember.AsmLn;
  937. begin
  938. { don't write newlines in the middle of declarations }
  939. if fdecllevel=0 then
  940. inherited AsmLn;
  941. end;
  942. procedure TLLVMAssember.WriteDirectiveName(dir: TAsmDirective);
  943. begin
  944. AsmWrite('.'+directivestr[dir]+' ');
  945. end;
  946. procedure TLLVMAssember.WriteAsmList;
  947. var
  948. hal : tasmlisttype;
  949. i: longint;
  950. begin
  951. WriteExtraHeader;
  952. AsmStartSize:=AsmSize;
  953. for hal:=low(TasmlistType) to high(TasmlistType) do
  954. begin
  955. AsmWriteLn(target_asm.comment+'Begin asmlist '+AsmlistTypeStr[hal]);
  956. writetree(current_asmdata.asmlists[hal]);
  957. AsmWriteLn(target_asm.comment+'End asmlist '+AsmlistTypeStr[hal]);
  958. end;
  959. AsmLn;
  960. end;
  961. {****************************************************************************}
  962. { Abstract Instruction Writer }
  963. {****************************************************************************}
  964. constructor TLLVMInstrWriter.create(_owner: TLLVMAssember);
  965. begin
  966. inherited create;
  967. owner := _owner;
  968. end;
  969. const
  970. as_llvm_info : tasminfo =
  971. (
  972. id : as_llvm;
  973. idtxt : 'LLVM-AS';
  974. asmbin : 'llc';
  975. asmcmd: '$OPT -o $OBJ $ASM';
  976. supported_targets : [system_x86_64_linux,system_x86_64_darwin,system_powerpc64_darwin];
  977. flags : [af_smartlink_sections];
  978. labelprefix : 'L';
  979. comment : '; ';
  980. dollarsign: '$';
  981. );
  982. begin
  983. RegisterAssembler(as_llvm_info,TLLVMAssember);
  984. end.