agllvm.pas 35 KB

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