agllvm.pas 41 KB

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