agllvm.pas 61 KB

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