agllvm.pas 36 KB

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