agllvm.pas 41 KB

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