agllvm.pas 44 KB

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