agllvm.pas 41 KB

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