agllvm.pas 49 KB

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