agllvm.pas 33 KB

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