agllvm.pas 41 KB

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