agllvm.pas 36 KB

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