agllvm.pas 35 KB

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