agllvm.pas 39 KB

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