agllvm.pas 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236
  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. writer.AsmWrite(' external');
  659. AB_COMMON:
  660. writer.AsmWrite(' common');
  661. AB_LOCAL:
  662. writer.AsmWrite(' internal');
  663. AB_GLOBAL:
  664. writer.AsmWrite('');
  665. AB_WEAK_EXTERNAL:
  666. writer.AsmWrite(' extern_weak');
  667. AB_PRIVATE_EXTERN:
  668. begin
  669. if not(llvmflag_linker_private in llvmversion_properties[current_settings.llvmversion]) then
  670. writer.AsmWrite(' hidden')
  671. else
  672. writer.AsmWrite(' linker_private');
  673. end
  674. else
  675. internalerror(2014020104);
  676. end;
  677. end;
  678. procedure WriteFunctionFlags(pd: tprocdef);
  679. begin
  680. if (pos('FPC_SETJMP',upper(pd.mangledname))<>0) or
  681. (pd.mangledname=(target_info.cprefix+'setjmp')) then
  682. writer.AsmWrite(' returns_twice');
  683. if po_inline in pd.procoptions then
  684. writer.AsmWrite(' inlinehint');
  685. { ensure that functions that happen to have the same name as a
  686. standard C library function, but which are implemented in Pascal,
  687. are not considered to have the same semantics as the C function with
  688. the same name }
  689. if not(po_external in pd.procoptions) then
  690. writer.AsmWrite(' nobuiltin');
  691. if po_noreturn in pd.procoptions then
  692. writer.AsmWrite(' noreturn');
  693. end;
  694. procedure WriteTypedConstData(hp: tai_abstracttypedconst);
  695. var
  696. p: tai_abstracttypedconst;
  697. pval: tai;
  698. defstr: TSymStr;
  699. first, gotstring: boolean;
  700. begin
  701. defstr:=llvmencodetypename(hp.def);
  702. { write the struct, array or simple type }
  703. case hp.adetyp of
  704. tck_record:
  705. begin
  706. writer.AsmWrite(defstr);
  707. writer.AsmWrite(' <{');
  708. first:=true;
  709. for p in tai_aggregatetypedconst(hp) do
  710. begin
  711. if not first then
  712. writer.AsmWrite(', ')
  713. else
  714. first:=false;
  715. WriteTypedConstData(p);
  716. end;
  717. writer.AsmWrite('}>');
  718. end;
  719. tck_array:
  720. begin
  721. writer.AsmWrite(defstr);
  722. first:=true;
  723. gotstring:=false;
  724. for p in tai_aggregatetypedconst(hp) do
  725. begin
  726. if not first then
  727. writer.AsmWrite(',')
  728. else
  729. begin
  730. writer.AsmWrite(' ');
  731. if (tai_abstracttypedconst(p).adetyp=tck_simple) and
  732. (tai_simpletypedconst(p).val.typ=ait_string) then
  733. begin
  734. gotstring:=true;
  735. end
  736. else
  737. begin
  738. writer.AsmWrite('[');
  739. end;
  740. first:=false;
  741. end;
  742. { cannot concat strings and other things }
  743. if gotstring and
  744. ((tai_abstracttypedconst(p).adetyp<>tck_simple) or
  745. (tai_simpletypedconst(p).val.typ<>ait_string)) then
  746. internalerror(2014062701);
  747. WriteTypedConstData(p);
  748. end;
  749. if not gotstring then
  750. writer.AsmWrite(']');
  751. end;
  752. tck_simple:
  753. begin
  754. pval:=tai_simpletypedconst(hp).val;
  755. if pval.typ<>ait_string then
  756. begin
  757. writer.AsmWrite(defstr);
  758. writer.AsmWrite(' ');
  759. end;
  760. WriteTai(replaceforbidden,do_line,InlineLevel,asmblock,pval);
  761. end;
  762. end;
  763. end;
  764. var
  765. hp2: tai;
  766. s: string;
  767. i: longint;
  768. ch: ansichar;
  769. begin
  770. case hp.typ of
  771. ait_comment :
  772. begin
  773. writer.AsmWrite(asminfo^.comment);
  774. writer.AsmWritePChar(tai_comment(hp).str);
  775. if fdecllevel<>0 then
  776. internalerror(2015090601);
  777. writer.AsmLn;
  778. end;
  779. ait_regalloc :
  780. begin
  781. if (cs_asm_regalloc in current_settings.globalswitches) then
  782. begin
  783. writer.AsmWrite(#9+asminfo^.comment+'Register ');
  784. repeat
  785. writer.AsmWrite(std_regname(Tai_regalloc(hp).reg));
  786. if (hp.next=nil) or
  787. (tai(hp.next).typ<>ait_regalloc) or
  788. (tai_regalloc(hp.next).ratype<>tai_regalloc(hp).ratype) then
  789. break;
  790. hp:=tai(hp.next);
  791. writer.AsmWrite(',');
  792. until false;
  793. writer.AsmWrite(' ');
  794. writer.AsmWriteLn(regallocstr[tai_regalloc(hp).ratype]);
  795. end;
  796. end;
  797. ait_tempalloc :
  798. begin
  799. if (cs_asm_tempalloc in current_settings.globalswitches) then
  800. WriteTempalloc(tai_tempalloc(hp));
  801. end;
  802. ait_align,
  803. ait_section :
  804. begin
  805. { ignore, specified as part of declarations -- don't write
  806. comment, because could appear in the middle of an aggregate
  807. constant definition }
  808. end;
  809. ait_datablock :
  810. begin
  811. writer.AsmWrite(asminfo^.comment);
  812. writer.AsmWriteln('datablock');
  813. end;
  814. ait_const:
  815. begin
  816. WriteOrdConst(tai_const(hp));
  817. end;
  818. ait_realconst :
  819. begin
  820. WriteRealConst(tai_realconst(hp), do_line);
  821. end;
  822. ait_string :
  823. begin
  824. if fdecllevel=0 then
  825. writer.AsmWrite(asminfo^.comment);
  826. writer.AsmWrite('c"');
  827. for i:=1 to tai_string(hp).len do
  828. begin
  829. ch:=tai_string(hp).str[i-1];
  830. case ch of
  831. #0, {This can't be done by range, because a bug in FPC}
  832. #1..#31,
  833. #128..#255,
  834. '"',
  835. '\' : s:='\'+hexStr(ord(ch),2);
  836. else
  837. s:=ch;
  838. end;
  839. writer.AsmWrite(s);
  840. end;
  841. writer.AsmWriteLn('"');
  842. end;
  843. ait_label :
  844. begin
  845. if not asmblock and
  846. (tai_label(hp).labsym.is_used) then
  847. begin
  848. if (tai_label(hp).labsym.bind=AB_PRIVATE_EXTERN) then
  849. begin
  850. { should be emitted as part of the variable/function def }
  851. internalerror(2013010703);
  852. end;
  853. if tai_label(hp).labsym.bind in [AB_GLOBAL, AB_PRIVATE_EXTERN] then
  854. begin
  855. { should be emitted as part of the variable/function def }
  856. //internalerror(2013010704);
  857. writer.AsmWriteln(asminfo^.comment+'global/privateextern label: '+tai_label(hp).labsym.name);
  858. end;
  859. if replaceforbidden then
  860. writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_label(hp).labsym.name))
  861. else
  862. writer.AsmWrite(tai_label(hp).labsym.name);
  863. writer.AsmWriteLn(':');
  864. end;
  865. end;
  866. ait_symbol :
  867. begin
  868. if fdecllevel=0 then
  869. writer.AsmWrite(asminfo^.comment);
  870. writer.AsmWriteln(LlvmAsmSymName(tai_symbol(hp).sym));
  871. { todo }
  872. if tai_symbol(hp).has_value then
  873. internalerror(2014062402);
  874. end;
  875. ait_llvmdecl:
  876. begin
  877. if taillvmdecl(hp).def.typ=procdef then
  878. begin
  879. if not(ldf_definition in taillvmdecl(hp).flags) then
  880. begin
  881. writer.AsmWrite('declare');
  882. writer.AsmWrite(llvmencodeproctype(tprocdef(taillvmdecl(hp).def), taillvmdecl(hp).namesym.name, lpd_decl));
  883. WriteFunctionFlags(tprocdef(taillvmdecl(hp).def));
  884. writer.AsmLn;
  885. end
  886. else
  887. begin
  888. writer.AsmWrite('define');
  889. if ldf_weak in taillvmdecl(hp).flags then
  890. writer.AsmWrite(' weak');
  891. WriteLinkageVibilityFlags(taillvmdecl(hp).namesym.bind);
  892. writer.AsmWrite(llvmencodeproctype(tprocdef(taillvmdecl(hp).def), '', lpd_def));
  893. WriteFunctionFlags(tprocdef(taillvmdecl(hp).def));
  894. writer.AsmWriteln(' {');
  895. end;
  896. end
  897. else
  898. begin
  899. writer.AsmWrite(LlvmAsmSymName(taillvmdecl(hp).namesym));
  900. writer.AsmWrite(' =');
  901. if ldf_weak in taillvmdecl(hp).flags then
  902. writer.AsmWrite(' weak');
  903. WriteLinkageVibilityFlags(taillvmdecl(hp).namesym.bind);
  904. writer.AsmWrite(' ');
  905. if (ldf_tls in taillvmdecl(hp).flags) then
  906. writer.AsmWrite('thread_local ');
  907. if ldf_unnamed_addr in taillvmdecl(hp).flags then
  908. writer.AsmWrite('unnamed_addr ');
  909. if taillvmdecl(hp).sec in [sec_rodata,sec_rodata_norel] then
  910. writer.AsmWrite('constant ')
  911. else
  912. writer.AsmWrite('global ');
  913. if not assigned(taillvmdecl(hp).initdata) then
  914. begin
  915. writer.AsmWrite(llvmencodetypename(taillvmdecl(hp).def));
  916. if not(taillvmdecl(hp).namesym.bind in [AB_EXTERNAL, AB_WEAK_EXTERNAL]) then
  917. writer.AsmWrite(' zeroinitializer');
  918. end
  919. else
  920. begin
  921. inc(fdecllevel);
  922. { can't have an external symbol with initialisation data }
  923. if taillvmdecl(hp).namesym.bind in [AB_EXTERNAL, AB_WEAK_EXTERNAL] then
  924. internalerror(2014052905);
  925. { bitcast initialisation data to the type of the constant }
  926. { write initialisation data }
  927. hp2:=tai(taillvmdecl(hp).initdata.first);
  928. while assigned(hp2) do
  929. begin
  930. WriteTai(replaceforbidden,do_line,InlineLevel,asmblock,hp2);
  931. hp2:=tai(hp2.next);
  932. end;
  933. dec(fdecllevel);
  934. end;
  935. { custom section name? }
  936. case taillvmdecl(hp).sec of
  937. sec_user:
  938. begin
  939. writer.AsmWrite(', section "');
  940. writer.AsmWrite(taillvmdecl(hp).secname);
  941. writer.AsmWrite('"');
  942. end;
  943. low(TObjCAsmSectionType)..high(TObjCAsmSectionType):
  944. begin
  945. writer.AsmWrite(', section "');
  946. writer.AsmWrite(objc_section_name(taillvmdecl(hp).sec));
  947. writer.AsmWrite('"');
  948. end;
  949. end;
  950. { alignment }
  951. writer.AsmWrite(', align ');
  952. writer.AsmWriteln(tostr(taillvmdecl(hp).alignment));
  953. end;
  954. end;
  955. ait_llvmalias:
  956. begin
  957. writer.AsmWrite(LlvmAsmSymName(taillvmalias(hp).newsym));
  958. writer.AsmWrite(' = alias ');
  959. if taillvmalias(hp).linkage<>lll_default then
  960. begin
  961. str(taillvmalias(hp).linkage, s);
  962. writer.AsmWrite(copy(s, length('lll_')+1, 255));
  963. writer.AsmWrite(' ');
  964. end;
  965. if taillvmalias(hp).vis<>llv_default then
  966. begin
  967. str(taillvmalias(hp).vis, s);
  968. writer.AsmWrite(copy(s, length('llv_')+1, 255));
  969. writer.AsmWrite(' ');
  970. end;
  971. if taillvmalias(hp).def.typ=procdef then
  972. writer.AsmWrite(llvmencodeproctype(tabstractprocdef(taillvmalias(hp).def), '', lpd_alias))
  973. else
  974. writer.AsmWrite(llvmencodetypename(taillvmalias(hp).def));
  975. writer.AsmWrite('* ');
  976. writer.AsmWriteln(LlvmAsmSymName(taillvmalias(hp).oldsym));
  977. end;
  978. ait_symbolpair:
  979. begin
  980. { should be emitted as part of the symbol def }
  981. internalerror(2013010708);
  982. end;
  983. ait_symbol_end :
  984. begin
  985. if tai_symbol_end(hp).sym.typ=AT_FUNCTION then
  986. writer.AsmWriteln('}')
  987. else
  988. writer.AsmWriteln('; ait_symbol_end error, should not be generated');
  989. // internalerror(2013010711);
  990. end;
  991. ait_instruction :
  992. begin
  993. WriteInstruction(hp);
  994. end;
  995. ait_llvmins:
  996. begin
  997. WriteLlvmInstruction(hp);
  998. end;
  999. ait_stab :
  1000. begin
  1001. internalerror(2013010712);
  1002. end;
  1003. ait_force_line,
  1004. ait_function_name :
  1005. ;
  1006. ait_cutobject :
  1007. begin
  1008. end;
  1009. ait_marker :
  1010. case
  1011. tai_marker(hp).kind of
  1012. mark_NoLineInfoStart:
  1013. inc(InlineLevel);
  1014. mark_NoLineInfoEnd:
  1015. dec(InlineLevel);
  1016. { these cannot be nested }
  1017. mark_AsmBlockStart:
  1018. asmblock:=true;
  1019. mark_AsmBlockEnd:
  1020. asmblock:=false;
  1021. end;
  1022. ait_directive :
  1023. begin
  1024. WriteDirectiveName(tai_directive(hp).directive);
  1025. if tai_directive(hp).name <>'' then
  1026. writer.AsmWrite(tai_directive(hp).name);
  1027. if fdecllevel<>0 then
  1028. internalerror(2015090602);
  1029. writer.AsmLn;
  1030. end;
  1031. ait_seh_directive :
  1032. begin
  1033. internalerror(2013010713);
  1034. end;
  1035. ait_varloc:
  1036. begin
  1037. if tai_varloc(hp).newlocationhi<>NR_NO then
  1038. writer.AsmWrite(strpnew('Var '+tai_varloc(hp).varsym.realname+' located in register '+
  1039. std_regname(tai_varloc(hp).newlocationhi)+':'+std_regname(tai_varloc(hp).newlocation)))
  1040. else
  1041. writer.AsmWrite(strpnew('Var '+tai_varloc(hp).varsym.realname+' located in register '+
  1042. std_regname(tai_varloc(hp).newlocation)));
  1043. if fdecllevel<>0 then
  1044. internalerror(2015090603);
  1045. writer.AsmLn;
  1046. end;
  1047. ait_typedconst:
  1048. begin
  1049. WriteTypedConstData(tai_abstracttypedconst(hp));
  1050. end
  1051. else
  1052. internalerror(2006012201);
  1053. end;
  1054. end;
  1055. constructor TLLVMAssember.create(info: pasminfo; smart: boolean);
  1056. begin
  1057. inherited;
  1058. InstrWriter:=TLLVMInstrWriter.create(self);
  1059. end;
  1060. procedure TLLVMAssember.WriteDirectiveName(dir: TAsmDirective);
  1061. begin
  1062. writer.AsmWrite('.'+directivestr[dir]+' ');
  1063. end;
  1064. procedure TLLVMAssember.WriteAsmList;
  1065. var
  1066. hal : tasmlisttype;
  1067. i: longint;
  1068. a: TExternalAssembler;
  1069. decorator: TLLVMModuleInlineAssemblyDecorator;
  1070. begin
  1071. WriteExtraHeader;
  1072. for hal:=low(TasmlistType) to high(TasmlistType) do
  1073. begin
  1074. if not assigned(current_asmdata.asmlists[hal]) or
  1075. current_asmdata.asmlists[hal].Empty then
  1076. continue;
  1077. writer.AsmWriteLn(asminfo^.comment+'Begin asmlist '+AsmlistTypeStr[hal]);
  1078. if hal<>al_pure_assembler then
  1079. writetree(current_asmdata.asmlists[hal])
  1080. else
  1081. begin
  1082. { write routines using the target-specific external assembler
  1083. writer, filtered using the LLVM module-level assembly
  1084. decorator }
  1085. decorator:=TLLVMModuleInlineAssemblyDecorator.Create;
  1086. writer.decorator:=decorator;
  1087. a:=GetExternalGnuAssemblerWithAsmInfoWriter(asminfo,writer);
  1088. a.WriteTree(current_asmdata.asmlists[hal]);
  1089. writer.decorator:=nil;
  1090. decorator.free;
  1091. end;
  1092. writer.AsmWriteLn(asminfo^.comment+'End asmlist '+AsmlistTypeStr[hal]);
  1093. end;
  1094. writer.AsmLn;
  1095. end;
  1096. {****************************************************************************}
  1097. { Abstract Instruction Writer }
  1098. {****************************************************************************}
  1099. constructor TLLVMInstrWriter.create(_owner: TLLVMAssember);
  1100. begin
  1101. inherited create;
  1102. owner := _owner;
  1103. end;
  1104. const
  1105. as_llvm_info : tasminfo =
  1106. (
  1107. id : as_llvm;
  1108. idtxt : 'LLVM-AS';
  1109. asmbin : 'llc';
  1110. asmcmd: '$OPT -o $OBJ $ASM';
  1111. supported_targets : [system_x86_64_linux,system_x86_64_darwin,system_powerpc64_darwin];
  1112. flags : [af_smartlink_sections];
  1113. labelprefix : 'L';
  1114. comment : '; ';
  1115. dollarsign: '$';
  1116. );
  1117. begin
  1118. RegisterAssembler(as_llvm_info,TLLVMAssember);
  1119. end.