agllvm.pas 41 KB

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