agllvm.pas 51 KB

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