agllvm.pas 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918
  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,
  22. aasmbase,aasmtai,aasmdata,
  23. assemble;
  24. type
  25. TLLVMInstrWriter = class;
  26. { TLLVMAssember }
  27. TLLVMAssember=class(texternalassembler)
  28. protected
  29. procedure WriteExtraHeader;virtual;
  30. procedure WriteExtraFooter;virtual;
  31. procedure WriteInstruction(hp: tai);
  32. procedure WriteLlvmInstruction(hp: tai);
  33. // procedure WriteWeakSymbolDef(s: tasmsymbol); virtual;
  34. procedure WriteDirectiveName(dir: TAsmDirective); virtual;
  35. procedure WriteWeakSymbolDef(s: tasmsymbol);
  36. procedure WriteRealConst(hp: tai_realconst; do_line: boolean);
  37. procedure WriteOrdConst(hp: tai_const);
  38. procedure WriteTai(const replaceforbidden: boolean; const do_line: boolean; var InlineLevel: cardinal; var hp: tai);
  39. public
  40. constructor create(smart: boolean); override;
  41. function MakeCmdLine: TCmdStr; override;
  42. procedure WriteTree(p:TAsmList);override;
  43. procedure WriteAsmList;override;
  44. destructor destroy; override;
  45. protected
  46. InstrWriter: TLLVMInstrWriter;
  47. end;
  48. {# This is the base class for writing instructions.
  49. The WriteInstruction() method must be overridden
  50. to write a single instruction to the assembler
  51. file.
  52. }
  53. TLLVMInstrWriter = class
  54. constructor create(_owner: TLLVMAssember);
  55. procedure WriteInstruction(hp : tai);
  56. protected
  57. owner: TLLVMAssember;
  58. end;
  59. implementation
  60. uses
  61. SysUtils,
  62. cutils,cfileutl,systems,
  63. fmodule,verbose,
  64. symconst,symdef,
  65. llvmbase,aasmllvm,itllvm,llvmdef,
  66. cgbase,cgutils,cpubase;
  67. const
  68. line_length = 70;
  69. var
  70. symendcount : longint;
  71. type
  72. {$ifdef cpuextended}
  73. t80bitarray = array[0..9] of byte;
  74. {$endif cpuextended}
  75. t64bitarray = array[0..7] of byte;
  76. t32bitarray = array[0..3] of byte;
  77. {****************************************************************************}
  78. { Support routines }
  79. {****************************************************************************}
  80. function single2str(d : single) : string;
  81. var
  82. hs : string;
  83. begin
  84. str(d,hs);
  85. { replace space with + }
  86. if hs[1]=' ' then
  87. hs[1]:='+';
  88. single2str:=hs
  89. end;
  90. function double2str(d : double) : string;
  91. var
  92. hs : string;
  93. begin
  94. str(d,hs);
  95. { replace space with + }
  96. if hs[1]=' ' then
  97. hs[1]:='+';
  98. double2str:=hs
  99. end;
  100. function extended2str(e : extended) : string;
  101. var
  102. hs : string;
  103. begin
  104. str(e,hs);
  105. { replace space with + }
  106. if hs[1]=' ' then
  107. hs[1]:='+';
  108. extended2str:=hs
  109. end;
  110. {****************************************************************************}
  111. { LLVM Instruction writer }
  112. {****************************************************************************}
  113. function getregisterstring(reg: tregister): ansistring;
  114. begin
  115. if getregtype(reg)=R_TEMPREGISTER then
  116. result:='%tmp.'
  117. else
  118. result:='%reg.'+tostr(byte(getregtype(reg)))+'_';
  119. result:=result+tostr(getsupreg(reg));
  120. end;
  121. function getreferencealignstring(var ref: treference) : ansistring;
  122. begin
  123. result:=', align '+tostr(ref.alignment);
  124. end;
  125. function getreferencestring(var ref : treference; withalign: boolean) : ansistring;
  126. begin
  127. result:='';
  128. if assigned(ref.relsymbol) or
  129. (assigned(ref.symbol) =
  130. (ref.base<>NR_NO)) or
  131. (ref.index<>NR_NO) or
  132. (ref.offset<>0) then
  133. begin
  134. result:=' **(error ref: ';
  135. if assigned(ref.symbol) then
  136. result:=result+'sym='+ref.symbol.name+', ';
  137. if assigned(ref.relsymbol) then
  138. result:=result+'sym='+ref.relsymbol.name+', ';
  139. if ref.base=NR_NO then
  140. result:=result+'base=NR_NO, ';
  141. if ref.index<>NR_NO then
  142. result:=result+'index<>NR_NO, ';
  143. if ref.offset<>0 then
  144. result:=result+'offset='+tostr(ref.offset);
  145. result:=result+')**'
  146. // internalerror(2013060225);
  147. end;
  148. if ref.base<>NR_NO then
  149. result:=result+getregisterstring(ref.base)
  150. else
  151. result:=result+ref.symbol.name;
  152. if withalign then
  153. result:=result+getreferencealignstring(ref);
  154. end;
  155. function getparas(const o: toper): ansistring;
  156. var
  157. i: longint;
  158. para: pllvmcallpara;
  159. begin
  160. result:='(';
  161. for i:=0 to o.paras.count-1 do
  162. begin
  163. if i<>0 then
  164. result:=result+', ';
  165. para:=pllvmcallpara(o.paras[i]);
  166. result:=result+llvmencodetype(para^.def);
  167. if para^.valueext<>lve_none then
  168. result:=result+llvmvalueextension2str[para^.valueext];
  169. case para^.loc of
  170. LOC_REGISTER,
  171. LOC_FPUREGISTER,
  172. LOC_MMREGISTER:
  173. result:=result+' '+getregisterstring(para^.reg);
  174. else
  175. internalerror(2014010801);
  176. end;
  177. end;
  178. result:=result+')';
  179. end;
  180. function getopstr(const o:toper; refwithalign: boolean) : ansistring;
  181. var
  182. hs : ansistring;
  183. doubleval: record
  184. case byte of
  185. 1: (d: double);
  186. 2: (i: int64);
  187. end;
  188. {$ifdef cpuextended}
  189. extendedval: record
  190. case byte of
  191. 1: (e: extended);
  192. 2: (r: record
  193. {$ifdef FPC_LITTLE_ENDIAN}
  194. l: int64;
  195. h: word;
  196. {$else FPC_LITTLE_ENDIAN}
  197. h: int64;
  198. l: word;
  199. {$endif FPC_LITTLE_ENDIAN}
  200. end;
  201. );
  202. end;
  203. {$endif cpuextended}
  204. begin
  205. case o.typ of
  206. top_reg:
  207. getopstr:=getregisterstring(o.reg);
  208. top_const:
  209. getopstr:=tostr(int64(o.val));
  210. top_ref:
  211. if o.ref^.refaddr=addr_full then
  212. begin
  213. getopstr:='';
  214. if o.ref^.symbol.typ=AT_LABEL then
  215. getopstr:='label %';
  216. hs:=o.ref^.symbol.name;
  217. if o.ref^.offset<>0 then
  218. internalerror(2013060223);
  219. getopstr:=getopstr+hs;
  220. end
  221. else
  222. getopstr:=getreferencestring(o.ref^,refwithalign);
  223. top_def:
  224. begin
  225. getopstr:=llvmencodetype(o.def);
  226. end;
  227. top_cond:
  228. begin
  229. getopstr:=llvm_cond2str[o.cond];
  230. end;
  231. top_fpcond:
  232. begin
  233. getopstr:=llvm_fpcond2str[o.fpcond];
  234. end;
  235. top_single,
  236. top_double:
  237. begin
  238. { "When using the hexadecimal form, constants of types half,
  239. float, and double are represented using the 16-digit form shown
  240. above (which matches the IEEE754 representation for double)"
  241. And always in big endian form (sign bit leftmost)
  242. }
  243. if o.typ=top_double then
  244. doubleval.d:=o.dval
  245. else
  246. doubleval.d:=o.sval;
  247. result:='0x'+hexstr(doubleval.i,16);
  248. end;
  249. top_para:
  250. begin
  251. result:=getparas(o);
  252. end;
  253. {$ifdef cpuextended}
  254. top_extended80:
  255. begin
  256. { hex format is always big endian in llvm }
  257. extendedval.e:=o.eval;
  258. result:='0xK'+hexstr(extendedval.r.h,sizeof(extendedval.r.h)*2)+hexstr(extendedval.r.l,sizeof(extendedval.r.l)*2);
  259. end;
  260. {$endif cpuextended}
  261. else
  262. internalerror(2013060227);
  263. end;
  264. end;
  265. procedure TLlvmInstrWriter.WriteInstruction(hp: tai);
  266. var
  267. op: tllvmop;
  268. s: string;
  269. i, opstart: byte;
  270. sep: string[3];
  271. done: boolean;
  272. begin
  273. op:=taillvm(hp).llvmopcode;
  274. s:=#9;
  275. sep:=' ';
  276. done:=false;
  277. opstart:=0;
  278. case op of
  279. la_ret, la_br, la_switch, la_indirectbr,
  280. la_invoke, la_resume,
  281. la_unreachable,
  282. la_store,
  283. la_fence,
  284. la_cmpxchg,
  285. la_atomicrmw:
  286. begin
  287. { instructions that never have a result }
  288. end;
  289. la_call:
  290. begin
  291. if taillvm(hp).oper[0]^.reg<>NR_NO then
  292. s:=s+getregisterstring(taillvm(hp).oper[0]^.reg)+' = ';
  293. sep:=' ';
  294. opstart:=1;
  295. end;
  296. la_alloca:
  297. begin
  298. s:=s+getreferencestring(taillvm(hp).oper[0]^.ref^,false)+' = ';
  299. sep:=' ';
  300. opstart:=1;
  301. end;
  302. la_trunc, la_zext, la_sext, la_fptrunc, la_fpext,
  303. la_fptoui, la_fptosi, la_uitofp, la_sitofp,
  304. la_ptrtoint, la_inttoptr,
  305. la_bitcast:
  306. begin
  307. s:=s+getopstr(taillvm(hp).oper[0]^,false)+' = '+
  308. llvm_op2str[op]+' '+
  309. getopstr(taillvm(hp).oper[1]^,false)+' '+
  310. getopstr(taillvm(hp).oper[2]^,false)+' to '+
  311. getopstr(taillvm(hp).oper[3]^,false);
  312. done:=true;
  313. end
  314. else
  315. begin
  316. s:=s+getopstr(taillvm(hp).oper[0]^,true)+' = ';
  317. sep:=' ';
  318. opstart:=1
  319. end;
  320. end;
  321. { process operands }
  322. if not done then
  323. begin
  324. s:=s+llvm_op2str[op];
  325. if taillvm(hp).ops<>0 then
  326. begin
  327. for i:=opstart to taillvm(hp).ops-1 do
  328. begin
  329. s:=s+sep+getopstr(taillvm(hp).oper[i]^,op in [la_load,la_store]);
  330. if (taillvm(hp).oper[i]^.typ in [top_def,top_cond,top_fpcond]) or
  331. (op=la_call) then
  332. sep :=' '
  333. else
  334. sep:=', ';
  335. end;
  336. end;
  337. end;
  338. if op=la_alloca then
  339. begin
  340. s:=s+getreferencealignstring(taillvm(hp).oper[0]^.ref^)
  341. end;
  342. owner.AsmWriteLn(s);
  343. end;
  344. {****************************************************************************}
  345. { LLVM Assembler writer }
  346. {****************************************************************************}
  347. destructor TLLVMAssember.Destroy;
  348. begin
  349. InstrWriter.free;
  350. inherited destroy;
  351. end;
  352. function TLLVMAssember.MakeCmdLine: TCmdStr;
  353. var
  354. optstr: TCmdStr;
  355. begin
  356. result := inherited MakeCmdLine;
  357. { standard optimization flags for llc -- todo: this needs to be split
  358. into a call to opt and one to llc }
  359. if cs_opt_level3 in current_settings.optimizerswitches then
  360. optstr:='-O3'
  361. else if cs_opt_level2 in current_settings.optimizerswitches then
  362. optstr:='-O2'
  363. else if cs_opt_level1 in current_settings.optimizerswitches then
  364. optstr:='-O1'
  365. else
  366. optstr:='-O0';
  367. { stack frame elimination }
  368. if not(cs_opt_stackframe in current_settings.optimizerswitches) then
  369. optstr:=optstr+' -disable-fp-elim';
  370. { fast math }
  371. if cs_opt_fastmath in current_settings.optimizerswitches then
  372. optstr:=optstr+' -enable-unsafe-fp-math -enable-fp-mad -fp-contract=fast';
  373. { smart linking }
  374. if cs_create_smart in current_settings.moduleswitches then
  375. optstr:=optstr+' -fdata-sections -fcode-sections';
  376. { pic }
  377. if cs_create_pic in current_settings.moduleswitches then
  378. optstr:=optstr+' -relocation-model=pic'
  379. else if not(target_info.system in systems_darwin) then
  380. optstr:=optstr+' -relocation-model=static'
  381. else
  382. optstr:=optstr+' -relocation-model=dynamic-no-pic';
  383. { our stack alignment is non-standard on some targets. The following
  384. parameter is however ignored on some targets by llvm, so it may not
  385. be enough }
  386. optstr:=optstr+' -stack-alignment='+tostr(target_info.stackalign*8);
  387. { force object output instead of textual assembler code }
  388. optstr:=optstr+' -filetype=obj';
  389. replace(result,'$OPT',optstr);
  390. end;
  391. procedure TLLVMAssember.WriteTree(p:TAsmList);
  392. var
  393. hp : tai;
  394. InlineLevel : cardinal;
  395. do_line : boolean;
  396. replaceforbidden: boolean;
  397. begin
  398. if not assigned(p) then
  399. exit;
  400. replaceforbidden:=target_asm.dollarsign<>'$';
  401. InlineLevel:=0;
  402. { lineinfo is only needed for al_procedures (PFV) }
  403. do_line:=(cs_asm_source in current_settings.globalswitches) or
  404. ((cs_lineinfo in current_settings.moduleswitches)
  405. and (p=current_asmdata.asmlists[al_procedures]));
  406. hp:=tai(p.first);
  407. while assigned(hp) do
  408. begin
  409. prefetch(pointer(hp.next)^);
  410. if not(hp.typ in SkipLineInfo) then
  411. begin
  412. current_filepos:=tailineinfo(hp).fileinfo;
  413. { no line info for inlined code }
  414. if do_line and (inlinelevel=0) then
  415. WriteSourceLine(hp as tailineinfo);
  416. end;
  417. WriteTai(replaceforbidden, do_line, InlineLevel, hp);
  418. hp:=tai(hp.next);
  419. end;
  420. end;
  421. procedure TLLVMAssember.WriteExtraHeader;
  422. begin
  423. AsmWrite('target datalayout = "');
  424. AsmWrite(target_info.llvmdatalayout);
  425. AsmWriteln('"');
  426. AsmWrite('target triple = "');
  427. AsmWrite(llvm_target_name);
  428. AsmWriteln('"');
  429. end;
  430. procedure TLLVMAssember.WriteExtraFooter;
  431. begin
  432. end;
  433. procedure TLLVMAssember.WriteInstruction(hp: tai);
  434. begin
  435. end;
  436. procedure TLLVMAssember.WriteLlvmInstruction(hp: tai);
  437. begin
  438. InstrWriter.WriteInstruction(hp);
  439. end;
  440. procedure TLLVMAssember.WriteWeakSymbolDef(s: tasmsymbol);
  441. begin
  442. AsmWriteLn(#9'.weak '+s.name);
  443. end;
  444. procedure TLLVMAssember.WriteRealConst(hp: tai_realconst; do_line: boolean);
  445. var
  446. pdata: pbyte;
  447. index, step, swapmask, count: longint;
  448. begin
  449. // if do_line then
  450. begin
  451. case tai_realconst(hp).realtyp of
  452. aitrealconst_s32bit:
  453. AsmWriteLn(target_asm.comment+'value: '+single2str(tai_realconst(hp).value.s32val));
  454. aitrealconst_s64bit:
  455. AsmWriteLn(target_asm.comment+'value: '+double2str(tai_realconst(hp).value.s64val));
  456. {$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
  457. { can't write full 80 bit floating point constants yet on non-x86 }
  458. aitrealconst_s80bit:
  459. AsmWriteLn(target_asm.comment+'value: '+extended2str(tai_realconst(hp).value.s80val));
  460. {$endif cpuextended}
  461. aitrealconst_s64comp:
  462. AsmWriteLn(target_asm.comment+'value: '+extended2str(tai_realconst(hp).value.s64compval));
  463. else
  464. internalerror(2014050604);
  465. end;
  466. end;
  467. end;
  468. procedure TLLVMAssember.WriteOrdConst(hp: tai_const);
  469. var
  470. consttyp: taiconst_type;
  471. begin
  472. asmwrite(target_asm.comment+' const ');
  473. consttyp:=hp.consttype;
  474. case consttyp of
  475. aitconst_got,
  476. aitconst_gotoff_symbol,
  477. aitconst_uleb128bit,
  478. aitconst_sleb128bit,
  479. aitconst_rva_symbol,
  480. aitconst_secrel32_symbol,
  481. aitconst_darwin_dwarf_delta32,
  482. aitconst_darwin_dwarf_delta64,
  483. aitconst_half16bit:
  484. internalerror(2014052901);
  485. aitconst_128bit,
  486. aitconst_64bit,
  487. aitconst_32bit,
  488. aitconst_16bit,
  489. aitconst_8bit,
  490. aitconst_16bit_unaligned,
  491. aitconst_32bit_unaligned,
  492. aitconst_64bit_unaligned:
  493. begin
  494. { can't have compile-time differences between symbols; these are
  495. normally for PIC, but llvm takes care of that for us }
  496. if assigned(hp.endsym) then
  497. internalerror(2014052902);
  498. if assigned(hp.sym) then
  499. begin
  500. { type of struct vs type of field; type of asmsym? }
  501. { if hp.value<>0 then
  502. xxx }
  503. AsmWrite(hp.sym.name);
  504. if hp.value<>0 then
  505. AsmWrite(tostr_with_plus(hp.value));
  506. end
  507. else
  508. AsmWrite(tostr(hp.value));
  509. AsmLn;
  510. end;
  511. else
  512. internalerror(200704251);
  513. end;
  514. end;
  515. procedure TLLVMAssember.WriteTai(const replaceforbidden: boolean; const do_line: boolean; var InlineLevel: cardinal; var hp: tai);
  516. var
  517. hp2: tai;
  518. s: string;
  519. begin
  520. case hp.typ of
  521. ait_comment :
  522. begin
  523. AsmWrite(target_asm.comment);
  524. AsmWritePChar(tai_comment(hp).str);
  525. AsmLn;
  526. end;
  527. ait_regalloc :
  528. begin
  529. if (cs_asm_regalloc in current_settings.globalswitches) then
  530. begin
  531. AsmWrite(#9+target_asm.comment+'Register ');
  532. repeat
  533. AsmWrite(std_regname(Tai_regalloc(hp).reg));
  534. if (hp.next=nil) or
  535. (tai(hp.next).typ<>ait_regalloc) or
  536. (tai_regalloc(hp.next).ratype<>tai_regalloc(hp).ratype) then
  537. break;
  538. hp:=tai(hp.next);
  539. AsmWrite(',');
  540. until false;
  541. AsmWrite(' ');
  542. AsmWriteLn(regallocstr[tai_regalloc(hp).ratype]);
  543. end;
  544. end;
  545. ait_tempalloc :
  546. begin
  547. if (cs_asm_tempalloc in current_settings.globalswitches) then
  548. WriteTempalloc(tai_tempalloc(hp));
  549. end;
  550. ait_align :
  551. begin
  552. { has to be specified as part of the symbol declaration }
  553. AsmWriteln('; error: explicit aligns are forbidden');
  554. // internalerror(2013010714);
  555. end;
  556. ait_section :
  557. begin
  558. AsmWrite(target_asm.comment);
  559. AsmWriteln('section');
  560. end;
  561. ait_datablock :
  562. begin
  563. AsmWrite(target_asm.comment);
  564. AsmWriteln('datablock');
  565. end;
  566. ait_const:
  567. begin
  568. WriteOrdConst(tai_const(hp));
  569. end;
  570. ait_realconst :
  571. begin
  572. WriteRealConst(tai_realconst(hp), do_line);
  573. end;
  574. ait_string :
  575. begin
  576. AsmWrite(target_asm.comment);
  577. AsmWriteln('string');
  578. end;
  579. ait_label :
  580. begin
  581. if (tai_label(hp).labsym.is_used) then
  582. begin
  583. if (tai_label(hp).labsym.bind=AB_PRIVATE_EXTERN) then
  584. begin
  585. { should be emitted as part of the variable/function def }
  586. internalerror(2013010703);
  587. end;
  588. if tai_label(hp).labsym.bind in [AB_GLOBAL, AB_PRIVATE_EXTERN] then
  589. begin
  590. { should be emitted as part of the variable/function def }
  591. //internalerror(2013010704);
  592. AsmWriteln(target_asm.comment+'global/privateextern label: '+tai_label(hp).labsym.name);
  593. end;
  594. if replaceforbidden then
  595. AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_label(hp).labsym.name))
  596. else
  597. AsmWrite(tai_label(hp).labsym.name);
  598. AsmWriteLn(':');
  599. end;
  600. end;
  601. ait_symbol :
  602. begin
  603. { should be emitted as part of the variable/function def }
  604. asmwrite('; (ait_symbol error, should be part of variable/function def) :');
  605. asmwriteln(tai_symbol(hp).sym.name);
  606. // internalerror(2013010705);
  607. end;
  608. ait_llvmdecl:
  609. begin
  610. if taillvmdecl(hp).def.typ=procdef then
  611. begin
  612. if taillvmdecl(hp).namesym.bind in [AB_EXTERNAL, AB_WEAK_EXTERNAL] then
  613. begin
  614. asmwrite('declare');
  615. asmwriteln(llvmencodeproctype(tprocdef(taillvmdecl(hp).def), taillvmdecl(hp).namesym.name, lpd_decl));
  616. end
  617. else
  618. begin
  619. asmwrite('define');
  620. asmwrite(llvmencodeproctype(tprocdef(taillvmdecl(hp).def), '', lpd_decl));
  621. asmwriteln(' {');
  622. end;
  623. end
  624. else
  625. begin
  626. asmwrite(taillvmdecl(hp).namesym.name);
  627. case taillvmdecl(hp).namesym.bind of
  628. AB_EXTERNAL:
  629. asmwrite(' = external global ');
  630. AB_COMMON:
  631. asmwrite(' = common global ');
  632. AB_LOCAL:
  633. asmwrite(' = internal global ');
  634. AB_GLOBAL:
  635. asmwrite(' = global ');
  636. AB_WEAK_EXTERNAL:
  637. asmwrite(' = extern_weak global ');
  638. AB_PRIVATE_EXTERN:
  639. asmwrite('= linker_private global ');
  640. else
  641. internalerror(2014020104);
  642. end;
  643. asmwrite(llvmencodetype(taillvmdecl(hp).def));
  644. if not(taillvmdecl(hp).namesym.bind in [AB_EXTERNAL, AB_WEAK_EXTERNAL]) then
  645. asmwrite(' zeroinitializer');
  646. { alignment }
  647. asmwrite(', align ');
  648. asmwriteln(tostr(taillvmdecl(hp).def.alignment));
  649. end;
  650. end;
  651. ait_llvmalias:
  652. begin
  653. asmwrite('@'+taillvmalias(hp).newsym.name);
  654. asmwrite(' = alias ');
  655. if taillvmalias(hp).linkage<>lll_default then
  656. begin
  657. str(taillvmalias(hp).linkage, s);
  658. asmwrite(copy(s, length('lll_'), 255));
  659. asmwrite(' ');
  660. end
  661. else
  662. asmwrite('external ');
  663. if taillvmalias(hp).vis<>llv_default then
  664. begin
  665. str(taillvmalias(hp).vis, s);
  666. asmwrite(copy(s, length('llv_'), 255));
  667. asmwrite(' ');
  668. end;
  669. asmwrite(llvmencodeproctype(tabstractprocdef(taillvmalias(hp).def), '', lpd_alias));
  670. asmwrite('* ');
  671. asmwriteln(taillvmalias(hp).oldsym.name);
  672. end;
  673. {$ifdef arm}
  674. ait_thumb_func:
  675. begin
  676. { should be emitted as part of the function def }
  677. internalerror(2013010706);
  678. end;
  679. ait_thumb_set:
  680. begin
  681. { should be emitted as part of the symbol def }
  682. internalerror(2013010707);
  683. end;
  684. {$endif arm}
  685. ait_set:
  686. begin
  687. { should be emitted as part of the symbol def }
  688. internalerror(2013010708);
  689. end;
  690. ait_weak:
  691. begin
  692. { should be emitted as part of the symbol def }
  693. internalerror(2013010709);
  694. end;
  695. ait_symbol_end :
  696. begin
  697. if tai_symbol_end(hp).sym.typ=AT_FUNCTION then
  698. asmwriteln('}')
  699. else
  700. asmwriteln('; ait_symbol_end error, should not be generated');
  701. // internalerror(2013010711);
  702. end;
  703. ait_instruction :
  704. begin
  705. WriteInstruction(hp);
  706. end;
  707. ait_llvmins:
  708. begin
  709. WriteLlvmInstruction(hp);
  710. end;
  711. ait_stab :
  712. begin
  713. internalerror(2013010712);
  714. end;
  715. ait_force_line,
  716. ait_function_name :
  717. ;
  718. ait_cutobject :
  719. begin
  720. end;
  721. ait_marker :
  722. if tai_marker(hp).kind=mark_NoLineInfoStart then
  723. inc(InlineLevel)
  724. else if tai_marker(hp).kind=mark_NoLineInfoEnd then
  725. dec(InlineLevel);
  726. ait_directive :
  727. begin
  728. WriteDirectiveName(tai_directive(hp).directive);
  729. if tai_directive(hp).name <>'' then
  730. AsmWrite(tai_directive(hp).name);
  731. AsmLn;
  732. end;
  733. ait_seh_directive :
  734. begin
  735. internalerror(2013010713);
  736. end;
  737. ait_varloc:
  738. begin
  739. if tai_varloc(hp).newlocationhi<>NR_NO then
  740. AsmWrite(strpnew('Var '+tai_varloc(hp).varsym.realname+' located in register '+
  741. std_regname(tai_varloc(hp).newlocationhi)+':'+std_regname(tai_varloc(hp).newlocation)))
  742. else
  743. AsmWrite(strpnew('Var '+tai_varloc(hp).varsym.realname+' located in register '+
  744. std_regname(tai_varloc(hp).newlocation)));
  745. AsmLn;
  746. end;
  747. else
  748. internalerror(2006012201);
  749. end;
  750. end;
  751. constructor TLLVMAssember.create(smart: boolean);
  752. begin
  753. inherited create(smart);
  754. InstrWriter:=TLLVMInstrWriter.create(self);
  755. end;
  756. procedure TLLVMAssember.WriteDirectiveName(dir: TAsmDirective);
  757. begin
  758. AsmWrite('.'+directivestr[dir]+' ');
  759. end;
  760. procedure TLLVMAssember.WriteAsmList;
  761. var
  762. n : string;
  763. hal : tasmlisttype;
  764. i: longint;
  765. begin
  766. if current_module.mainsource<>'' then
  767. n:=ExtractFileName(current_module.mainsource)
  768. else
  769. n:=InputFileName;
  770. { gcc does not add it either for Darwin. Grep for
  771. TARGET_ASM_FILE_START_FILE_DIRECTIVE in gcc/config/*.h
  772. }
  773. if not(target_info.system in systems_darwin) then
  774. AsmWriteLn(#9'.file "'+FixFileName(n)+'"');
  775. WriteExtraHeader;
  776. AsmStartSize:=AsmSize;
  777. symendcount:=0;
  778. for hal:=low(TasmlistType) to high(TasmlistType) do
  779. begin
  780. AsmWriteLn(target_asm.comment+'Begin asmlist '+AsmlistTypeStr[hal]);
  781. writetree(current_asmdata.asmlists[hal]);
  782. AsmWriteLn(target_asm.comment+'End asmlist '+AsmlistTypeStr[hal]);
  783. end;
  784. { add weak symbol markers }
  785. for i:=0 to current_asmdata.asmsymboldict.count-1 do
  786. if (tasmsymbol(current_asmdata.asmsymboldict[i]).bind=AB_WEAK_EXTERNAL) then
  787. writeweaksymboldef(tasmsymbol(current_asmdata.asmsymboldict[i]));
  788. AsmLn;
  789. end;
  790. {****************************************************************************}
  791. { Abstract Instruction Writer }
  792. {****************************************************************************}
  793. constructor TLLVMInstrWriter.create(_owner: TLLVMAssember);
  794. begin
  795. inherited create;
  796. owner := _owner;
  797. end;
  798. const
  799. as_llvm_info : tasminfo =
  800. (
  801. id : as_llvm;
  802. idtxt : 'LLVM-AS';
  803. asmbin : 'llc';
  804. asmcmd: '$OPT -o $OBJ $ASM';
  805. supported_targets : [system_x86_64_linux,system_x86_64_darwin,system_powerpc64_darwin];
  806. flags : [af_smartlink_sections];
  807. labelprefix : 'L';
  808. comment : '; ';
  809. dollarsign: '$';
  810. );
  811. begin
  812. RegisterAssembler(as_llvm_info,TLLVMAssember);
  813. end.