agllvm.pas 48 KB

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