agllvm.pas 36 KB

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