agllvm.pas 36 KB

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