agllvm.pas 61 KB

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