agllvm.pas 43 KB

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