agllvm.pas 34 KB

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