agllvm.pas 36 KB

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