agllvm.pas 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108
  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. if fdecllevel=0 then
  562. AsmWrite(target_asm.comment);
  563. { can't have compile-time differences between symbols; these are
  564. normally for PIC, but llvm takes care of that for us }
  565. if assigned(hp.endsym) then
  566. internalerror(2014052902);
  567. if assigned(hp.sym) then
  568. begin
  569. AsmWrite(hp.sym.name);
  570. { can't have offsets }
  571. if hp.value<>0 then
  572. if fdecllevel<>0 then
  573. internalerror(2014052903)
  574. else
  575. asmwrite(' -- symbol offset: ' + tostr(hp.value));
  576. end
  577. else
  578. AsmWrite(tostr(hp.value));
  579. AsmLn;
  580. end;
  581. else
  582. internalerror(200704251);
  583. end;
  584. end;
  585. procedure TLLVMAssember.WriteTai(const replaceforbidden: boolean; const do_line: boolean; var InlineLevel: cardinal; var hp: tai);
  586. procedure WriteTypedConstData(hp: tai_abstracttypedconst);
  587. var
  588. p: tai_abstracttypedconst;
  589. pval: tai;
  590. defstr: TSymStr;
  591. first, gotstring: boolean;
  592. begin
  593. { special case: tck_simple_procvar2proc; this means that we want the
  594. procdef of the procvardef, rather than both the procdef and the
  595. method/nestedfp/... pointers }
  596. if hp.adetyp<>tck_simple_procvar2proc then
  597. defstr:=llvmencodetype(hp.def)
  598. else
  599. defstr:=llvmencodeproctype(tabstractprocdef(hp.def),'',lpd_procvar);
  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. tck_simple_procvar2proc:
  653. begin
  654. pval:=tai_simpletypedconst(hp).val;
  655. if pval.typ<>ait_string then
  656. begin
  657. AsmWrite(defstr);
  658. AsmWrite(' ');
  659. end;
  660. WriteTai(replaceforbidden,do_line,InlineLevel,pval);
  661. end;
  662. end;
  663. end;
  664. var
  665. hp2: tai;
  666. s: string;
  667. begin
  668. case hp.typ of
  669. ait_comment :
  670. begin
  671. AsmWrite(target_asm.comment);
  672. AsmWritePChar(tai_comment(hp).str);
  673. AsmLn;
  674. end;
  675. ait_regalloc :
  676. begin
  677. if (cs_asm_regalloc in current_settings.globalswitches) then
  678. begin
  679. AsmWrite(#9+target_asm.comment+'Register ');
  680. repeat
  681. AsmWrite(std_regname(Tai_regalloc(hp).reg));
  682. if (hp.next=nil) or
  683. (tai(hp.next).typ<>ait_regalloc) or
  684. (tai_regalloc(hp.next).ratype<>tai_regalloc(hp).ratype) then
  685. break;
  686. hp:=tai(hp.next);
  687. AsmWrite(',');
  688. until false;
  689. AsmWrite(' ');
  690. AsmWriteLn(regallocstr[tai_regalloc(hp).ratype]);
  691. end;
  692. end;
  693. ait_tempalloc :
  694. begin
  695. if (cs_asm_tempalloc in current_settings.globalswitches) then
  696. WriteTempalloc(tai_tempalloc(hp));
  697. end;
  698. ait_align :
  699. begin
  700. { has to be specified as part of the symbol declaration }
  701. AsmWriteln('; error: explicit aligns are forbidden');
  702. // internalerror(2013010714);
  703. end;
  704. ait_section :
  705. begin
  706. AsmWrite(target_asm.comment);
  707. AsmWriteln('section');
  708. end;
  709. ait_datablock :
  710. begin
  711. AsmWrite(target_asm.comment);
  712. AsmWriteln('datablock');
  713. end;
  714. ait_const:
  715. begin
  716. WriteOrdConst(tai_const(hp));
  717. end;
  718. ait_realconst :
  719. begin
  720. WriteRealConst(tai_realconst(hp), do_line);
  721. end;
  722. ait_string :
  723. begin
  724. AsmWrite(target_asm.comment);
  725. AsmWriteln('string');
  726. end;
  727. ait_label :
  728. begin
  729. if (tai_label(hp).labsym.is_used) then
  730. begin
  731. if (tai_label(hp).labsym.bind=AB_PRIVATE_EXTERN) then
  732. begin
  733. { should be emitted as part of the variable/function def }
  734. internalerror(2013010703);
  735. end;
  736. if tai_label(hp).labsym.bind in [AB_GLOBAL, AB_PRIVATE_EXTERN] then
  737. begin
  738. { should be emitted as part of the variable/function def }
  739. //internalerror(2013010704);
  740. AsmWriteln(target_asm.comment+'global/privateextern label: '+tai_label(hp).labsym.name);
  741. end;
  742. if replaceforbidden then
  743. AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_label(hp).labsym.name))
  744. else
  745. AsmWrite(tai_label(hp).labsym.name);
  746. AsmWriteLn(':');
  747. end;
  748. end;
  749. ait_symbol :
  750. begin
  751. { should be emitted as part of the variable/function def }
  752. asmwrite('; (ait_symbol error, should be part of variable/function def) :');
  753. asmwriteln(tai_symbol(hp).sym.name);
  754. // internalerror(2013010705);
  755. end;
  756. ait_llvmdecl:
  757. begin
  758. if taillvmdecl(hp).def.typ=procdef then
  759. begin
  760. if taillvmdecl(hp).namesym.bind in [AB_EXTERNAL, AB_WEAK_EXTERNAL] then
  761. begin
  762. asmwrite('declare');
  763. asmwriteln(llvmencodeproctype(tprocdef(taillvmdecl(hp).def), taillvmdecl(hp).namesym.name, lpd_decl));
  764. end
  765. else
  766. begin
  767. asmwrite('define');
  768. asmwrite(llvmencodeproctype(tprocdef(taillvmdecl(hp).def), '', lpd_decl));
  769. asmwriteln(' {');
  770. end;
  771. end
  772. else
  773. begin
  774. asmwrite(taillvmdecl(hp).namesym.name);
  775. case taillvmdecl(hp).namesym.bind of
  776. AB_EXTERNAL:
  777. asmwrite(' = external global ');
  778. AB_COMMON:
  779. asmwrite(' = common global ');
  780. AB_LOCAL:
  781. asmwrite(' = internal global ');
  782. AB_GLOBAL:
  783. asmwrite(' = global ');
  784. AB_WEAK_EXTERNAL:
  785. asmwrite(' = extern_weak global ');
  786. AB_PRIVATE_EXTERN:
  787. asmwrite('= linker_private global ');
  788. else
  789. internalerror(2014020104);
  790. end;
  791. if not assigned(taillvmdecl(hp).initdata) then
  792. begin
  793. asmwrite(llvmencodetype(taillvmdecl(hp).def));
  794. if not(taillvmdecl(hp).namesym.bind in [AB_EXTERNAL, AB_WEAK_EXTERNAL]) then
  795. asmwrite(' zeroinitializer');
  796. end
  797. else
  798. begin
  799. inc(fdecllevel);
  800. { can't have an external symbol with initialisation data }
  801. if taillvmdecl(hp).namesym.bind in [AB_EXTERNAL, AB_WEAK_EXTERNAL] then
  802. internalerror(2014052905);
  803. { bitcast initialisation data to the type of the constant }
  804. { write initialisation data }
  805. hp2:=tai(taillvmdecl(hp).initdata.first);
  806. while assigned(hp2) do
  807. begin
  808. WriteTai(replaceforbidden,do_line,InlineLevel,hp2);
  809. hp2:=tai(hp2.next);
  810. end;
  811. dec(fdecllevel);
  812. end;
  813. { alignment }
  814. asmwrite(', align ');
  815. asmwriteln(tostr(taillvmdecl(hp).def.alignment));
  816. end;
  817. end;
  818. ait_llvmalias:
  819. begin
  820. asmwrite('@'+taillvmalias(hp).newsym.name);
  821. asmwrite(' = alias ');
  822. if taillvmalias(hp).linkage<>lll_default then
  823. begin
  824. str(taillvmalias(hp).linkage, s);
  825. asmwrite(copy(s, length('lll_'), 255));
  826. asmwrite(' ');
  827. end
  828. else
  829. asmwrite('external ');
  830. if taillvmalias(hp).vis<>llv_default then
  831. begin
  832. str(taillvmalias(hp).vis, s);
  833. asmwrite(copy(s, length('llv_'), 255));
  834. asmwrite(' ');
  835. end;
  836. asmwrite(llvmencodeproctype(tabstractprocdef(taillvmalias(hp).def), '', lpd_alias));
  837. asmwrite('* ');
  838. asmwriteln(taillvmalias(hp).oldsym.name);
  839. end;
  840. {$ifdef arm}
  841. ait_thumb_func:
  842. begin
  843. { should be emitted as part of the function def }
  844. internalerror(2013010706);
  845. end;
  846. ait_thumb_set:
  847. begin
  848. { should be emitted as part of the symbol def }
  849. internalerror(2013010707);
  850. end;
  851. {$endif arm}
  852. ait_set:
  853. begin
  854. { should be emitted as part of the symbol def }
  855. internalerror(2013010708);
  856. end;
  857. ait_weak:
  858. begin
  859. { should be emitted as part of the symbol def }
  860. internalerror(2013010709);
  861. end;
  862. ait_symbol_end :
  863. begin
  864. if tai_symbol_end(hp).sym.typ=AT_FUNCTION then
  865. asmwriteln('}')
  866. else
  867. asmwriteln('; ait_symbol_end error, should not be generated');
  868. // internalerror(2013010711);
  869. end;
  870. ait_instruction :
  871. begin
  872. WriteInstruction(hp);
  873. end;
  874. ait_llvmins:
  875. begin
  876. WriteLlvmInstruction(hp);
  877. end;
  878. ait_stab :
  879. begin
  880. internalerror(2013010712);
  881. end;
  882. ait_force_line,
  883. ait_function_name :
  884. ;
  885. ait_cutobject :
  886. begin
  887. end;
  888. ait_marker :
  889. if tai_marker(hp).kind=mark_NoLineInfoStart then
  890. inc(InlineLevel)
  891. else if tai_marker(hp).kind=mark_NoLineInfoEnd then
  892. dec(InlineLevel);
  893. ait_directive :
  894. begin
  895. WriteDirectiveName(tai_directive(hp).directive);
  896. if tai_directive(hp).name <>'' then
  897. AsmWrite(tai_directive(hp).name);
  898. AsmLn;
  899. end;
  900. ait_seh_directive :
  901. begin
  902. internalerror(2013010713);
  903. end;
  904. ait_varloc:
  905. begin
  906. if tai_varloc(hp).newlocationhi<>NR_NO then
  907. AsmWrite(strpnew('Var '+tai_varloc(hp).varsym.realname+' located in register '+
  908. std_regname(tai_varloc(hp).newlocationhi)+':'+std_regname(tai_varloc(hp).newlocation)))
  909. else
  910. AsmWrite(strpnew('Var '+tai_varloc(hp).varsym.realname+' located in register '+
  911. std_regname(tai_varloc(hp).newlocation)));
  912. AsmLn;
  913. end;
  914. ait_typedconst:
  915. begin
  916. WriteTypedConstData(tai_abstracttypedconst(hp));
  917. end
  918. else
  919. internalerror(2006012201);
  920. end;
  921. end;
  922. constructor TLLVMAssember.create(smart: boolean);
  923. begin
  924. inherited create(smart);
  925. InstrWriter:=TLLVMInstrWriter.create(self);
  926. end;
  927. procedure TLLVMAssember.AsmLn;
  928. begin
  929. { don't write newlines in the middle of declarations }
  930. if fdecllevel=0 then
  931. inherited AsmLn;
  932. end;
  933. procedure TLLVMAssember.WriteDirectiveName(dir: TAsmDirective);
  934. begin
  935. AsmWrite('.'+directivestr[dir]+' ');
  936. end;
  937. procedure TLLVMAssember.WriteAsmList;
  938. var
  939. n : string;
  940. hal : tasmlisttype;
  941. i: longint;
  942. begin
  943. if current_module.mainsource<>'' then
  944. n:=ExtractFileName(current_module.mainsource)
  945. else
  946. n:=InputFileName;
  947. { gcc does not add it either for Darwin. Grep for
  948. TARGET_ASM_FILE_START_FILE_DIRECTIVE in gcc/config/*.h
  949. }
  950. if not(target_info.system in systems_darwin) then
  951. AsmWriteLn(#9'.file "'+FixFileName(n)+'"');
  952. WriteExtraHeader;
  953. AsmStartSize:=AsmSize;
  954. symendcount:=0;
  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. { add weak symbol markers }
  962. for i:=0 to current_asmdata.asmsymboldict.count-1 do
  963. if (tasmsymbol(current_asmdata.asmsymboldict[i]).bind=AB_WEAK_EXTERNAL) then
  964. writeweaksymboldef(tasmsymbol(current_asmdata.asmsymboldict[i]));
  965. AsmLn;
  966. end;
  967. {****************************************************************************}
  968. { Abstract Instruction Writer }
  969. {****************************************************************************}
  970. constructor TLLVMInstrWriter.create(_owner: TLLVMAssember);
  971. begin
  972. inherited create;
  973. owner := _owner;
  974. end;
  975. const
  976. as_llvm_info : tasminfo =
  977. (
  978. id : as_llvm;
  979. idtxt : 'LLVM-AS';
  980. asmbin : 'llc';
  981. asmcmd: '$OPT -o $OBJ $ASM';
  982. supported_targets : [system_x86_64_linux,system_x86_64_darwin,system_powerpc64_darwin];
  983. flags : [af_smartlink_sections];
  984. labelprefix : 'L';
  985. comment : '; ';
  986. dollarsign: '$';
  987. );
  988. begin
  989. RegisterAssembler(as_llvm_info,TLLVMAssember);
  990. end.