agllvm.pas 35 KB

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