agllvm.pas 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222
  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_blockaddress:
  371. begin
  372. owner.writer.AsmWrite(getopstr(taillvm(hp).oper[0]^,false));
  373. owner.writer.AsmWrite(' = blockaddress(');
  374. owner.writer.AsmWrite(getopstr(taillvm(hp).oper[1]^,false));
  375. owner.writer.AsmWrite(',');
  376. owner.writer.AsmWrite(getopstr(taillvm(hp).oper[2]^,false));
  377. owner.writer.AsmWrite(')');
  378. done:=true;
  379. end;
  380. la_alloca:
  381. begin
  382. owner.writer.AsmWrite(getreferencestring(taillvm(hp).oper[0]^.ref^,false)+' = ');
  383. sep:=' ';
  384. opstart:=1;
  385. end;
  386. la_trunc, la_zext, la_sext, la_fptrunc, la_fpext,
  387. la_fptoui, la_fptosi, la_uitofp, la_sitofp,
  388. la_ptrtoint, la_inttoptr,
  389. la_bitcast:
  390. begin
  391. { destination can be empty in case of nested constructs, or
  392. data initialisers }
  393. if (taillvm(hp).oper[0]^.typ<>top_reg) or
  394. (taillvm(hp).oper[0]^.reg<>NR_NO) then
  395. owner.writer.AsmWrite(getopstr(taillvm(hp).oper[0]^,false)+' = ')
  396. else
  397. nested:=true;
  398. owner.writer.AsmWrite(llvm_op2str[op]);
  399. if not nested then
  400. owner.writer.AsmWrite(' ')
  401. else
  402. owner.writer.AsmWrite(' (');
  403. owner.writer.AsmWrite(getopstr(taillvm(hp).oper[1]^,false));
  404. { if there's a tai operand, its def is used instead of an
  405. explicit def operand }
  406. if taillvm(hp).ops=4 then
  407. begin
  408. owner.writer.AsmWrite(' ');
  409. owner.writer.AsmWrite(getopstr(taillvm(hp).oper[2]^,false));
  410. opstart:=3;
  411. end
  412. else
  413. opstart:=2;
  414. owner.writer.AsmWrite(' to ');
  415. owner.writer.AsmWrite(getopstr(taillvm(hp).oper[opstart]^,false));
  416. done:=true;
  417. end
  418. else
  419. begin
  420. if (taillvm(hp).oper[0]^.typ<>top_reg) or
  421. (taillvm(hp).oper[0]^.reg<>NR_NO) then
  422. begin
  423. owner.writer.AsmWrite(getopstr(taillvm(hp).oper[0]^,true)+' = ');
  424. end
  425. else
  426. nested:=true;
  427. sep:=' ';
  428. opstart:=1
  429. end;
  430. end;
  431. { process operands }
  432. if not done then
  433. begin
  434. owner.writer.AsmWrite(llvm_op2str[op]);
  435. if nested then
  436. owner.writer.AsmWrite(' (');
  437. if taillvm(hp).ops<>0 then
  438. begin
  439. for i:=opstart to taillvm(hp).ops-1 do
  440. begin
  441. owner.writer.AsmWrite(sep);
  442. owner.writer.AsmWrite(getopstr(taillvm(hp).oper[i]^,op in [la_load,la_store]));
  443. if (taillvm(hp).oper[i]^.typ in [top_def,top_cond,top_fpcond]) or
  444. (op=la_call) then
  445. sep :=' '
  446. else
  447. sep:=', ';
  448. end;
  449. end;
  450. end;
  451. if op=la_alloca then
  452. owner.writer.AsmWrite(getreferencealignstring(taillvm(hp).oper[0]^.ref^));
  453. if nested then
  454. owner.writer.AsmWrite(')')
  455. else if owner.fdecllevel=0 then
  456. owner.writer.AsmLn;
  457. end;
  458. {****************************************************************************}
  459. { LLVM Assembler writer }
  460. {****************************************************************************}
  461. destructor TLLVMAssember.Destroy;
  462. begin
  463. InstrWriter.free;
  464. inherited destroy;
  465. end;
  466. function TLLVMAssember.MakeCmdLine: TCmdStr;
  467. var
  468. optstr: TCmdStr;
  469. begin
  470. result := inherited MakeCmdLine;
  471. { standard optimization flags for llc -- todo: this needs to be split
  472. into a call to opt and one to llc }
  473. if cs_opt_level3 in current_settings.optimizerswitches then
  474. optstr:='-O3'
  475. else if cs_opt_level2 in current_settings.optimizerswitches then
  476. optstr:='-O2'
  477. else if cs_opt_level1 in current_settings.optimizerswitches then
  478. optstr:='-O1'
  479. else
  480. optstr:='-O0';
  481. { stack frame elimination }
  482. if not(cs_opt_stackframe in current_settings.optimizerswitches) then
  483. optstr:=optstr+' -disable-fp-elim';
  484. { fast math }
  485. if cs_opt_fastmath in current_settings.optimizerswitches then
  486. optstr:=optstr+' -enable-unsafe-fp-math -enable-fp-mad -fp-contract=fast';
  487. { smart linking }
  488. if cs_create_smart in current_settings.moduleswitches then
  489. optstr:=optstr+' -fdata-sections -fcode-sections';
  490. { pic }
  491. if cs_create_pic in current_settings.moduleswitches then
  492. optstr:=optstr+' -relocation-model=pic'
  493. else if not(target_info.system in systems_darwin) then
  494. optstr:=optstr+' -relocation-model=static'
  495. else
  496. optstr:=optstr+' -relocation-model=dynamic-no-pic';
  497. { our stack alignment is non-standard on some targets. The following
  498. parameter is however ignored on some targets by llvm, so it may not
  499. be enough }
  500. optstr:=optstr+' -stack-alignment='+tostr(target_info.stackalign*8);
  501. { force object output instead of textual assembler code }
  502. optstr:=optstr+' -filetype=obj';
  503. replace(result,'$OPT',optstr);
  504. end;
  505. procedure TLLVMAssember.WriteTree(p:TAsmList);
  506. var
  507. hp : tai;
  508. InlineLevel : cardinal;
  509. asmblock: boolean;
  510. do_line : boolean;
  511. replaceforbidden: boolean;
  512. begin
  513. if not assigned(p) then
  514. exit;
  515. replaceforbidden:=asminfo^.dollarsign<>'$';
  516. InlineLevel:=0;
  517. asmblock:=false;
  518. { lineinfo is only needed for al_procedures (PFV) }
  519. do_line:=(cs_asm_source in current_settings.globalswitches) or
  520. ((cs_lineinfo in current_settings.moduleswitches)
  521. and (p=current_asmdata.asmlists[al_procedures]));
  522. hp:=tai(p.first);
  523. while assigned(hp) do
  524. begin
  525. prefetch(pointer(hp.next)^);
  526. if not(hp.typ in SkipLineInfo) then
  527. begin
  528. current_filepos:=tailineinfo(hp).fileinfo;
  529. { no line info for inlined code }
  530. if do_line and (inlinelevel=0) then
  531. WriteSourceLine(hp as tailineinfo);
  532. end;
  533. WriteTai(replaceforbidden, do_line, InlineLevel, asmblock, hp);
  534. hp:=tai(hp.next);
  535. end;
  536. end;
  537. procedure TLLVMAssember.WriteExtraHeader;
  538. begin
  539. writer.AsmWrite('target datalayout = "');
  540. writer.AsmWrite(target_info.llvmdatalayout);
  541. writer.AsmWriteln('"');
  542. writer.AsmWrite('target triple = "');
  543. writer.AsmWrite(llvm_target_name);
  544. writer.AsmWriteln('"');
  545. end;
  546. procedure TLLVMAssember.WriteExtraFooter;
  547. begin
  548. end;
  549. procedure TLLVMAssember.WriteInstruction(hp: tai);
  550. begin
  551. end;
  552. procedure TLLVMAssember.WriteLlvmInstruction(hp: tai);
  553. begin
  554. InstrWriter.WriteInstruction(hp);
  555. end;
  556. procedure TLLVMAssember.WriteRealConst(hp: tai_realconst; do_line: boolean);
  557. begin
  558. if do_line and
  559. (fdecllevel=0) then
  560. begin
  561. case tai_realconst(hp).realtyp of
  562. aitrealconst_s32bit:
  563. writer.AsmWriteLn(asminfo^.comment+'value: '+single2str(tai_realconst(hp).value.s32val));
  564. aitrealconst_s64bit:
  565. writer.AsmWriteLn(asminfo^.comment+'value: '+double2str(tai_realconst(hp).value.s64val));
  566. {$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
  567. { can't write full 80 bit floating point constants yet on non-x86 }
  568. aitrealconst_s80bit:
  569. writer.AsmWriteLn(asminfo^.comment+'value: '+extended2str(tai_realconst(hp).value.s80val));
  570. {$endif cpuextended}
  571. aitrealconst_s64comp:
  572. writer.AsmWriteLn(asminfo^.comment+'value: '+extended2str(tai_realconst(hp).value.s64compval));
  573. else
  574. internalerror(2014050604);
  575. end;
  576. end;
  577. case hp.realtyp of
  578. aitrealconst_s32bit:
  579. writer.AsmWriteln(llvmdoubletostr(hp.value.s32val));
  580. aitrealconst_s64bit:
  581. writer.AsmWriteln(llvmdoubletostr(hp.value.s64val));
  582. {$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
  583. aitrealconst_s80bit:
  584. writer.AsmWriteln(llvmextendedtostr(hp.value.s80val));
  585. {$endif defined(cpuextended)}
  586. aitrealconst_s64comp:
  587. { handled as int64 most of the time in llvm }
  588. writer.AsmWriteln(tostr(round(hp.value.s64compval)));
  589. else
  590. internalerror(2014062401);
  591. end;
  592. end;
  593. procedure TLLVMAssember.WriteOrdConst(hp: tai_const);
  594. var
  595. consttyp: taiconst_type;
  596. begin
  597. if fdecllevel=0 then
  598. writer.AsmWrite(asminfo^.comment+' const ');
  599. consttyp:=hp.consttype;
  600. case consttyp of
  601. aitconst_got,
  602. aitconst_gotoff_symbol,
  603. aitconst_uleb128bit,
  604. aitconst_sleb128bit,
  605. aitconst_rva_symbol,
  606. aitconst_secrel32_symbol,
  607. aitconst_darwin_dwarf_delta32,
  608. aitconst_darwin_dwarf_delta64,
  609. aitconst_half16bit,
  610. aitconst_gs:
  611. internalerror(2014052901);
  612. aitconst_128bit,
  613. aitconst_64bit,
  614. aitconst_32bit,
  615. aitconst_16bit,
  616. aitconst_8bit,
  617. aitconst_16bit_unaligned,
  618. aitconst_32bit_unaligned,
  619. aitconst_64bit_unaligned:
  620. begin
  621. if fdecllevel=0 then
  622. writer.AsmWrite(asminfo^.comment);
  623. { can't have compile-time differences between symbols; these are
  624. normally for PIC, but llvm takes care of that for us }
  625. if assigned(hp.endsym) then
  626. internalerror(2014052902);
  627. if assigned(hp.sym) then
  628. begin
  629. writer.AsmWrite(LlvmAsmSymName(hp.sym));
  630. { can't have offsets }
  631. if hp.value<>0 then
  632. if fdecllevel<>0 then
  633. internalerror(2014052903)
  634. else
  635. writer.AsmWrite(' -- symbol offset: ' + tostr(hp.value));
  636. end
  637. else if hp.value=0 then
  638. writer.AsmWrite('zeroinitializer')
  639. else
  640. writer.AsmWrite(tostr(hp.value));
  641. if fdecllevel=0 then
  642. writer.AsmLn;
  643. end;
  644. else
  645. internalerror(200704251);
  646. end;
  647. end;
  648. procedure TLLVMAssember.WriteTai(const replaceforbidden: boolean; const do_line: boolean; var InlineLevel: cardinal; var asmblock: boolean; var hp: tai);
  649. procedure WriteFunctionFlags(pd: tprocdef);
  650. begin
  651. if (pos('FPC_SETJMP',upper(pd.mangledname))<>0) or
  652. (pd.mangledname=(target_info.cprefix+'setjmp')) then
  653. writer.AsmWrite(' returns_twice');
  654. if po_inline in pd.procoptions then
  655. writer.AsmWrite(' inlinehint');
  656. { ensure that functions that happen to have the same name as a
  657. standard C library function, but which are implemented in Pascal,
  658. are not considered to have the same semantics as the C function with
  659. the same name }
  660. if not(po_external in pd.procoptions) then
  661. writer.AsmWrite(' nobuiltin');
  662. if po_noreturn in pd.procoptions then
  663. writer.AsmWrite(' noreturn');
  664. end;
  665. procedure WriteTypedConstData(hp: tai_abstracttypedconst);
  666. var
  667. p: tai_abstracttypedconst;
  668. pval: tai;
  669. defstr: TSymStr;
  670. first, gotstring: boolean;
  671. begin
  672. defstr:=llvmencodetypename(hp.def);
  673. { write the struct, array or simple type }
  674. case hp.adetyp of
  675. tck_record:
  676. begin
  677. writer.AsmWrite(defstr);
  678. writer.AsmWrite(' ');
  679. if (hp.def.typ in [objectdef,recorddef]) and
  680. (tabstractrecordsymtable(tabstractrecorddef(hp.def).symtable).usefieldalignment<>C_alignment) then
  681. writer.AsmWrite('<{')
  682. else
  683. writer.AsmWrite('{');
  684. first:=true;
  685. for p in tai_aggregatetypedconst(hp) do
  686. begin
  687. if not first then
  688. writer.AsmWrite(', ')
  689. else
  690. first:=false;
  691. WriteTypedConstData(p);
  692. end;
  693. if (hp.def.typ in [recorddef,objectdef]) and
  694. (tabstractrecordsymtable(tabstractrecorddef(hp.def).symtable).usefieldalignment<>C_alignment) then
  695. writer.AsmWrite('}>')
  696. else
  697. writer.AsmWrite('}');
  698. end;
  699. tck_array:
  700. begin
  701. writer.AsmWrite(defstr);
  702. first:=true;
  703. gotstring:=false;
  704. for p in tai_aggregatetypedconst(hp) do
  705. begin
  706. if not first then
  707. writer.AsmWrite(',')
  708. else
  709. begin
  710. writer.AsmWrite(' ');
  711. if (tai_abstracttypedconst(p).adetyp=tck_simple) and
  712. (tai_simpletypedconst(p).val.typ=ait_string) then
  713. begin
  714. gotstring:=true;
  715. end
  716. else
  717. begin
  718. writer.AsmWrite('[');
  719. end;
  720. first:=false;
  721. end;
  722. { cannot concat strings and other things }
  723. if gotstring and
  724. ((tai_abstracttypedconst(p).adetyp<>tck_simple) or
  725. (tai_simpletypedconst(p).val.typ<>ait_string)) then
  726. internalerror(2014062701);
  727. WriteTypedConstData(p);
  728. end;
  729. if not gotstring then
  730. writer.AsmWrite(']');
  731. end;
  732. tck_simple:
  733. begin
  734. pval:=tai_simpletypedconst(hp).val;
  735. if pval.typ<>ait_string then
  736. begin
  737. writer.AsmWrite(defstr);
  738. writer.AsmWrite(' ');
  739. end;
  740. WriteTai(replaceforbidden,do_line,InlineLevel,asmblock,pval);
  741. end;
  742. end;
  743. end;
  744. var
  745. hp2: tai;
  746. s: string;
  747. i: longint;
  748. ch: ansichar;
  749. begin
  750. case hp.typ of
  751. ait_comment :
  752. begin
  753. writer.AsmWrite(asminfo^.comment);
  754. writer.AsmWritePChar(tai_comment(hp).str);
  755. if fdecllevel<>0 then
  756. internalerror(2015090601);
  757. writer.AsmLn;
  758. end;
  759. ait_regalloc :
  760. begin
  761. if (cs_asm_regalloc in current_settings.globalswitches) then
  762. begin
  763. writer.AsmWrite(#9+asminfo^.comment+'Register ');
  764. repeat
  765. writer.AsmWrite(std_regname(Tai_regalloc(hp).reg));
  766. if (hp.next=nil) or
  767. (tai(hp.next).typ<>ait_regalloc) or
  768. (tai_regalloc(hp.next).ratype<>tai_regalloc(hp).ratype) then
  769. break;
  770. hp:=tai(hp.next);
  771. writer.AsmWrite(',');
  772. until false;
  773. writer.AsmWrite(' ');
  774. writer.AsmWriteLn(regallocstr[tai_regalloc(hp).ratype]);
  775. end;
  776. end;
  777. ait_tempalloc :
  778. begin
  779. if (cs_asm_tempalloc in current_settings.globalswitches) then
  780. WriteTempalloc(tai_tempalloc(hp));
  781. end;
  782. ait_align,
  783. ait_section :
  784. begin
  785. { ignore, specified as part of declarations -- don't write
  786. comment, because could appear in the middle of an aggregate
  787. constant definition }
  788. end;
  789. ait_datablock :
  790. begin
  791. writer.AsmWrite(asminfo^.comment);
  792. writer.AsmWriteln('datablock');
  793. end;
  794. ait_const:
  795. begin
  796. WriteOrdConst(tai_const(hp));
  797. end;
  798. ait_realconst :
  799. begin
  800. WriteRealConst(tai_realconst(hp), do_line);
  801. end;
  802. ait_string :
  803. begin
  804. if fdecllevel=0 then
  805. writer.AsmWrite(asminfo^.comment);
  806. writer.AsmWrite('c"');
  807. for i:=1 to tai_string(hp).len do
  808. begin
  809. ch:=tai_string(hp).str[i-1];
  810. case ch of
  811. #0, {This can't be done by range, because a bug in FPC}
  812. #1..#31,
  813. #128..#255,
  814. '"',
  815. '\' : s:='\'+hexStr(ord(ch),2);
  816. else
  817. s:=ch;
  818. end;
  819. writer.AsmWrite(s);
  820. end;
  821. writer.AsmWriteLn('"');
  822. end;
  823. ait_label :
  824. begin
  825. if not asmblock and
  826. (tai_label(hp).labsym.is_used) then
  827. begin
  828. if (tai_label(hp).labsym.bind=AB_PRIVATE_EXTERN) then
  829. begin
  830. { should be emitted as part of the variable/function def }
  831. internalerror(2013010703);
  832. end;
  833. if tai_label(hp).labsym.bind in [AB_GLOBAL, AB_PRIVATE_EXTERN] then
  834. begin
  835. { should be emitted as part of the variable/function def }
  836. //internalerror(2013010704);
  837. writer.AsmWriteln(asminfo^.comment+'global/privateextern label: '+tai_label(hp).labsym.name);
  838. end;
  839. if replaceforbidden then
  840. writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_label(hp).labsym.name))
  841. else
  842. writer.AsmWrite(tai_label(hp).labsym.name);
  843. writer.AsmWriteLn(':');
  844. end;
  845. end;
  846. ait_symbol :
  847. begin
  848. if fdecllevel=0 then
  849. writer.AsmWrite(asminfo^.comment);
  850. writer.AsmWriteln(LlvmAsmSymName(tai_symbol(hp).sym));
  851. { todo }
  852. if tai_symbol(hp).has_value then
  853. internalerror(2014062402);
  854. end;
  855. ait_llvmdecl:
  856. begin
  857. if taillvmdecl(hp).def.typ=procdef then
  858. begin
  859. if not(ldf_definition in taillvmdecl(hp).flags) then
  860. begin
  861. writer.AsmWrite('declare');
  862. writer.AsmWrite(llvmencodeproctype(tprocdef(taillvmdecl(hp).def), taillvmdecl(hp).namesym.name, lpd_decl));
  863. WriteFunctionFlags(tprocdef(taillvmdecl(hp).def));
  864. writer.AsmLn;
  865. end
  866. else
  867. begin
  868. writer.AsmWrite('define');
  869. writer.AsmWrite(llvmencodeproctype(tprocdef(taillvmdecl(hp).def), '', lpd_decl));
  870. WriteFunctionFlags(tprocdef(taillvmdecl(hp).def));
  871. writer.AsmWriteln(' {');
  872. end;
  873. end
  874. else
  875. begin
  876. writer.AsmWrite(LlvmAsmSymName(taillvmdecl(hp).namesym));
  877. case taillvmdecl(hp).namesym.bind of
  878. AB_EXTERNAL:
  879. writer.AsmWrite(' = external ');
  880. AB_COMMON:
  881. writer.AsmWrite(' = common ');
  882. AB_LOCAL:
  883. writer.AsmWrite(' = internal ');
  884. AB_GLOBAL:
  885. writer.AsmWrite(' = ');
  886. AB_WEAK_EXTERNAL:
  887. writer.AsmWrite(' = extern_weak ');
  888. AB_PRIVATE_EXTERN:
  889. writer.AsmWrite('= linker_private ');
  890. else
  891. internalerror(2014020104);
  892. end;
  893. if (ldf_tls in taillvmdecl(hp).flags) then
  894. writer.AsmWrite('thread_local ');
  895. if ldf_unnamed_addr in taillvmdecl(hp).flags then
  896. writer.AsmWrite('unnamed_addr ');
  897. { todo: handle more different section types (mainly
  898. Objective-C }
  899. if taillvmdecl(hp).sec in [sec_rodata,sec_rodata_norel] then
  900. writer.AsmWrite('constant ')
  901. else
  902. writer.AsmWrite('global ');
  903. if not assigned(taillvmdecl(hp).initdata) then
  904. begin
  905. writer.AsmWrite(llvmencodetypename(taillvmdecl(hp).def));
  906. if not(taillvmdecl(hp).namesym.bind in [AB_EXTERNAL, AB_WEAK_EXTERNAL]) then
  907. writer.AsmWrite(' zeroinitializer');
  908. end
  909. else
  910. begin
  911. inc(fdecllevel);
  912. { can't have an external symbol with initialisation data }
  913. if taillvmdecl(hp).namesym.bind in [AB_EXTERNAL, AB_WEAK_EXTERNAL] then
  914. internalerror(2014052905);
  915. { bitcast initialisation data to the type of the constant }
  916. { write initialisation data }
  917. hp2:=tai(taillvmdecl(hp).initdata.first);
  918. while assigned(hp2) do
  919. begin
  920. WriteTai(replaceforbidden,do_line,InlineLevel,asmblock,hp2);
  921. hp2:=tai(hp2.next);
  922. end;
  923. dec(fdecllevel);
  924. end;
  925. { custom section name? }
  926. if taillvmdecl(hp).sec=sec_user then
  927. begin
  928. writer.AsmWrite(', section "');
  929. writer.AsmWrite(taillvmdecl(hp).secname);
  930. writer.AsmWrite('"');
  931. end;
  932. { alignment }
  933. writer.AsmWrite(', align ');
  934. writer.AsmWriteln(tostr(taillvmdecl(hp).alignment));
  935. end;
  936. end;
  937. ait_llvmalias:
  938. begin
  939. writer.AsmWrite(LlvmAsmSymName(taillvmalias(hp).newsym));
  940. writer.AsmWrite(' = alias ');
  941. if taillvmalias(hp).linkage<>lll_default then
  942. begin
  943. str(taillvmalias(hp).linkage, s);
  944. writer.AsmWrite(copy(s, length('lll_')+1, 255));
  945. writer.AsmWrite(' ');
  946. end;
  947. if taillvmalias(hp).vis<>llv_default then
  948. begin
  949. str(taillvmalias(hp).vis, s);
  950. writer.AsmWrite(copy(s, length('llv_')+1, 255));
  951. writer.AsmWrite(' ');
  952. end;
  953. if taillvmalias(hp).def.typ=procdef then
  954. writer.AsmWrite(llvmencodeproctype(tabstractprocdef(taillvmalias(hp).def), '', lpd_alias))
  955. else
  956. writer.AsmWrite(llvmencodetypename(taillvmalias(hp).def));
  957. writer.AsmWrite('* ');
  958. writer.AsmWriteln(LlvmAsmSymName(taillvmalias(hp).oldsym));
  959. end;
  960. ait_symbolpair:
  961. begin
  962. { should be emitted as part of the symbol def }
  963. internalerror(2013010708);
  964. end;
  965. ait_weak:
  966. begin
  967. { should be emitted as part of the symbol def }
  968. internalerror(2013010709);
  969. end;
  970. ait_symbol_end :
  971. begin
  972. if tai_symbol_end(hp).sym.typ=AT_FUNCTION then
  973. writer.AsmWriteln('}')
  974. else
  975. writer.AsmWriteln('; ait_symbol_end error, should not be generated');
  976. // internalerror(2013010711);
  977. end;
  978. ait_instruction :
  979. begin
  980. WriteInstruction(hp);
  981. end;
  982. ait_llvmins:
  983. begin
  984. WriteLlvmInstruction(hp);
  985. end;
  986. ait_stab :
  987. begin
  988. internalerror(2013010712);
  989. end;
  990. ait_force_line,
  991. ait_function_name :
  992. ;
  993. ait_cutobject :
  994. begin
  995. end;
  996. ait_marker :
  997. case
  998. tai_marker(hp).kind of
  999. mark_NoLineInfoStart:
  1000. inc(InlineLevel);
  1001. mark_NoLineInfoEnd:
  1002. dec(InlineLevel);
  1003. { these cannot be nested }
  1004. mark_AsmBlockStart:
  1005. asmblock:=true;
  1006. mark_AsmBlockEnd:
  1007. asmblock:=false;
  1008. end;
  1009. ait_directive :
  1010. begin
  1011. WriteDirectiveName(tai_directive(hp).directive);
  1012. if tai_directive(hp).name <>'' then
  1013. writer.AsmWrite(tai_directive(hp).name);
  1014. if fdecllevel<>0 then
  1015. internalerror(2015090602);
  1016. writer.AsmLn;
  1017. end;
  1018. ait_seh_directive :
  1019. begin
  1020. internalerror(2013010713);
  1021. end;
  1022. ait_varloc:
  1023. begin
  1024. if tai_varloc(hp).newlocationhi<>NR_NO then
  1025. writer.AsmWrite(strpnew('Var '+tai_varloc(hp).varsym.realname+' located in register '+
  1026. std_regname(tai_varloc(hp).newlocationhi)+':'+std_regname(tai_varloc(hp).newlocation)))
  1027. else
  1028. writer.AsmWrite(strpnew('Var '+tai_varloc(hp).varsym.realname+' located in register '+
  1029. std_regname(tai_varloc(hp).newlocation)));
  1030. if fdecllevel<>0 then
  1031. internalerror(2015090603);
  1032. writer.AsmLn;
  1033. end;
  1034. ait_typedconst:
  1035. begin
  1036. WriteTypedConstData(tai_abstracttypedconst(hp));
  1037. end
  1038. else
  1039. internalerror(2006012201);
  1040. end;
  1041. end;
  1042. constructor TLLVMAssember.create(info: pasminfo; smart: boolean);
  1043. begin
  1044. inherited;
  1045. InstrWriter:=TLLVMInstrWriter.create(self);
  1046. end;
  1047. procedure TLLVMAssember.WriteDirectiveName(dir: TAsmDirective);
  1048. begin
  1049. writer.AsmWrite('.'+directivestr[dir]+' ');
  1050. end;
  1051. procedure TLLVMAssember.WriteAsmList;
  1052. var
  1053. hal : tasmlisttype;
  1054. i: longint;
  1055. a: TExternalAssembler;
  1056. decorator: TLLVMModuleInlineAssemblyDecorator;
  1057. begin
  1058. WriteExtraHeader;
  1059. for hal:=low(TasmlistType) to high(TasmlistType) do
  1060. begin
  1061. if not assigned(current_asmdata.asmlists[hal]) or
  1062. current_asmdata.asmlists[hal].Empty then
  1063. continue;
  1064. writer.AsmWriteLn(asminfo^.comment+'Begin asmlist '+AsmlistTypeStr[hal]);
  1065. if hal<>al_pure_assembler then
  1066. writetree(current_asmdata.asmlists[hal])
  1067. else
  1068. begin
  1069. { write routines using the target-specific external assembler
  1070. writer, filtered using the LLVM module-level assembly
  1071. decorator }
  1072. decorator:=TLLVMModuleInlineAssemblyDecorator.Create;
  1073. writer.decorator:=decorator;
  1074. a:=GetExternalGnuAssemblerWithAsmInfoWriter(asminfo,writer);
  1075. a.WriteTree(current_asmdata.asmlists[hal]);
  1076. writer.decorator:=nil;
  1077. decorator.free;
  1078. end;
  1079. writer.AsmWriteLn(asminfo^.comment+'End asmlist '+AsmlistTypeStr[hal]);
  1080. end;
  1081. writer.AsmLn;
  1082. end;
  1083. {****************************************************************************}
  1084. { Abstract Instruction Writer }
  1085. {****************************************************************************}
  1086. constructor TLLVMInstrWriter.create(_owner: TLLVMAssember);
  1087. begin
  1088. inherited create;
  1089. owner := _owner;
  1090. end;
  1091. const
  1092. as_llvm_info : tasminfo =
  1093. (
  1094. id : as_llvm;
  1095. idtxt : 'LLVM-AS';
  1096. asmbin : 'llc';
  1097. asmcmd: '$OPT -o $OBJ $ASM';
  1098. supported_targets : [system_x86_64_linux,system_x86_64_darwin,system_powerpc64_darwin];
  1099. flags : [af_smartlink_sections];
  1100. labelprefix : 'L';
  1101. comment : '; ';
  1102. dollarsign: '$';
  1103. );
  1104. begin
  1105. RegisterAssembler(as_llvm_info,TLLVMAssember);
  1106. end.