aasmllvmmetadata.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. {
  2. Copyright (c) 2019 by Jonas Maebe,
  3. member of the Free Pascal Compiler development team
  4. Support for LLVM metadata
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit aasmllvmmetadata;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,cclasses,
  23. cgbase,
  24. aasmtai,aasmcnst,
  25. symtype;
  26. {$push}{$ScopedEnums on}
  27. type
  28. tspecialisedmetadatanodekind = (
  29. DICompileUnit,
  30. DIFile,
  31. DIBasicType,
  32. DISubroutineType,
  33. DIDerivedType,
  34. DICompositeType,
  35. DISubrange,
  36. DIEnumerator,
  37. DITemplateTypeParameter,
  38. DITemplateValueParameter,
  39. DINamespace,
  40. DIGlobalVariable,
  41. DIGlobalVariableExpression,
  42. DISubprogram,
  43. DILexicalBlock,
  44. DILexicalBlockFile,
  45. DILocation,
  46. DILocalVariable,
  47. DIExpression,
  48. DIObjCProperty,
  49. DIImportedEntity,
  50. DIMacro,
  51. DIMacroFile
  52. );
  53. {$pop}
  54. // represented by a tai_simpletypedconst() with inside a metadata struct,
  55. // or as a metadata register (for parameters)
  56. // tai_llvmmetadatastring = class
  57. tai_llvmbasemetadatanode = class abstract(tai_aggregatetypedconst)
  58. strict protected
  59. function getname: ansistring; virtual; abstract;
  60. public
  61. procedure addvalue(val: tai_abstracttypedconst); override;
  62. property name: ansistring read getname;
  63. constructor create; reintroduce;
  64. class function isspecialised: boolean; virtual;
  65. end;
  66. (* !0 = !{ type1 value1, ... } *)
  67. tai_llvmunnamedmetadatanode = class(tai_llvmbasemetadatanode)
  68. strict private
  69. class function getnextid: cardinal;
  70. strict protected
  71. fnameval: cardinal;
  72. public
  73. constructor create; reintroduce;
  74. function getname: ansistring; override;
  75. end;
  76. (* !name = !{ type1 value1, ... } *)
  77. tai_llvmnamedmetadatanode = class(tai_llvmbasemetadatanode)
  78. strict protected
  79. fname: ansistring;
  80. function getname: ansistring; override;
  81. public
  82. constructor create(const aName: ansistring);
  83. end;
  84. { reference to a metadata node inside an expression, i.e., !X }
  85. tai_llvmmetadatareftypedconst = class(tai_simple)
  86. strict private
  87. fval: tai_llvmbasemetadatanode;
  88. public
  89. constructor create(_val: tai_llvmbasemetadatanode);
  90. property val: tai_llvmbasemetadatanode read fval;
  91. end;
  92. { @g1 = global i32 0, *!id !value.name* }
  93. tai_llvmmetadatareferenceoperand = class(tai_simple)
  94. strict private
  95. fid: ansistring;
  96. fvalue: tai_llvmmetadatareftypedconst;
  97. public
  98. constructor createreferenceto(const anID: ansistring; aValue: tai_llvmbasemetadatanode);
  99. destructor destroy; override;
  100. property id: ansistring read fid;
  101. property value: tai_llvmmetadatareftypedconst read fvalue;
  102. end;
  103. tllvmspecialmetaitemkind = (
  104. lsmik_boolean,
  105. lsmik_int64,
  106. lsmik_qword,
  107. lsmik_metadataref,
  108. lsmik_string,
  109. { difference with string: not quoted }
  110. lsmik_enum
  111. );
  112. tllvmspecialisedmetaitem = class(tai_simpletypedconst)
  113. private
  114. fitemkind: tllvmspecialmetaitemkind;
  115. fitemname: TSymStr;
  116. public
  117. constructor createboolean(const aitemname: TSymStr; boolval: boolean);
  118. constructor createint64(const aitemname: TSymStr; intval: int64);
  119. constructor createqword(const aitemname: TSymStr; qwval: qword);
  120. constructor createmetadataref(const aitemname: TSymStr; aival: tai_llvmmetadatareftypedconst);
  121. constructor createstring(const aitemname: TSymStr; const stringval: TSymStr);
  122. constructor createenum(const aitemname: TSymStr; const enumval: TSymStr);
  123. property itemname: TSymStr read fitemname;
  124. property itemkind: tllvmspecialmetaitemkind read fitemkind;
  125. end;
  126. { !name = !kindname(field1: value1, ...) }
  127. tai_llvmspecialisedmetadatanode = class(tai_llvmunnamedmetadatanode)
  128. strict private
  129. { identifies name and fieldnames }
  130. fkind: tspecialisedmetadatanodekind;
  131. { adds the item, appropriating its contents (so don't destroy the original
  132. afterwards) }
  133. procedure addemplaceitem(const item: tllvmspecialisedmetaitem);
  134. public
  135. constructor create(aKind: tspecialisedmetadatanodekind);
  136. procedure addvalue(val: tai_abstracttypedconst); override; deprecated 'use addboolean/addinteger/addmetadataref/addstring/addenum';
  137. procedure addboolean(const aitemname: TSymStr; boolval: boolean);
  138. procedure addint64(const aitemname: TSymStr; intval: int64);
  139. procedure addqword(const aitemname: TSymStr; qwval: qword);
  140. procedure addmetadatarefto(const aitemname: TSymStr; aival: tai_llvmbasemetadatanode);
  141. procedure addstring(const aitemname: TSymStr; const stringval: TSymStr);
  142. procedure addenum(const aitemname: TSymStr; const enumval: TSymStr);
  143. { only allowed before adding any items; needed because when generating
  144. debug info, we first generat everything as DIDerivedType (works for
  145. typedefs and most other types, and switch it later when necessary).
  146. Make it an explicit proc rather than a setter for kind to avoid
  147. accidental usage }
  148. procedure switchkind(newKind: tspecialisedmetadatanodekind);
  149. property kind: tspecialisedmetadatanodekind read fkind;
  150. function IsDistinct: boolean;
  151. class function isspecialised: boolean; override;
  152. end;
  153. {$push}
  154. {$scopedenums on}
  155. { not clear what the difference is between LineTablesOnly and DebugDirectivesOnly }
  156. tllvmdebugemissionkind = (NoDebug, FullDebug, LineTablesOnly, DebugDirectivesOnly);
  157. {$pop}
  158. tllvmmetadata = class
  159. strict private
  160. class function addstring(const s: TSymstr): TSuperRegister;
  161. class function regtostring(reg: TRegister): TSymStr;
  162. public
  163. class function getstringreg(const s: TSymstr): TRegister;
  164. class function getpcharreg(p: pchar; len: longint): TRegister;
  165. class function getregstring(reg: TRegister): TSymStr;
  166. end;
  167. function llvm_getmetadatareftypedconst(metadata: tai_llvmbasemetadatanode): tai_simpletypedconst;
  168. function llvm_constrainedexceptmodestring: ansistring;
  169. implementation
  170. uses
  171. verbose,globals,cutils,
  172. fmodule,
  173. symdef,
  174. dbgdwarfconst,
  175. aasmdata,aasmllvm;
  176. function llvm_getmetadatareftypedconst(metadata: tai_llvmbasemetadatanode): tai_simpletypedconst;
  177. begin
  178. if assigned(metadata) then
  179. result:=tai_simpletypedconst.create(llvm_metadatatype, tai_llvmmetadatareftypedconst.create(metadata))
  180. else
  181. result:=nil
  182. end;
  183. function llvm_constrainedexceptmodestring: ansistring;
  184. begin
  185. if not(cs_opt_fastmath in current_settings.optimizerswitches) then
  186. result:='fpexcept.maytrap'
  187. else
  188. result:='fpexcept.ignore'
  189. end;
  190. /////////////////////////////////////////////////
  191. procedure tai_llvmbasemetadatanode.addvalue(val: tai_abstracttypedconst);
  192. begin
  193. { bypass string merging attempts, as we add tai_strings directly here }
  194. fvalues.add(val);
  195. end;
  196. constructor tai_llvmbasemetadatanode.create;
  197. begin
  198. inherited create(tck_array, llvm_metadatatype);
  199. typ:=ait_llvmmetadatanode;
  200. end;
  201. class function tai_llvmbasemetadatanode.isspecialised: boolean;
  202. begin
  203. result:=false;
  204. end;
  205. class function tai_llvmunnamedmetadatanode.getnextid: cardinal;
  206. begin
  207. result:=tllvmasmdata(current_asmdata).fnextmetaid;
  208. inc(tllvmasmdata(current_asmdata).fnextmetaid);
  209. end;
  210. function tai_llvmunnamedmetadatanode.getname: ansistring;
  211. begin
  212. str(fnameval,result);
  213. end;
  214. constructor tai_llvmunnamedmetadatanode.create;
  215. begin
  216. inherited;
  217. fnameval:=getnextid;
  218. end;
  219. function tai_llvmnamedmetadatanode.getname: ansistring;
  220. begin
  221. result:=fname;
  222. end;
  223. constructor tai_llvmnamedmetadatanode.create(const aName: ansistring);
  224. begin
  225. inherited create;
  226. fname:=aName;
  227. end;
  228. constructor tai_llvmmetadatareftypedconst.create(_val: tai_llvmbasemetadatanode);
  229. begin
  230. inherited create(ait_llvmmetadatareftypedconst);
  231. fval:=_val;
  232. end;
  233. constructor tai_llvmmetadatareferenceoperand.createreferenceto(const anID: ansistring; aValue: tai_llvmbasemetadatanode);
  234. begin
  235. inherited create(ait_llvmmetadatarefoperand);
  236. fid:=anID;
  237. fvalue:=tai_llvmmetadatareftypedconst.create(aValue);
  238. end;
  239. destructor tai_llvmmetadatareferenceoperand.destroy;
  240. begin
  241. fvalue.free;
  242. inherited;
  243. end;
  244. /////////////////////////////////////////////////
  245. constructor tllvmspecialisedmetaitem.createboolean(const aitemname: TSymStr; boolval: boolean);
  246. begin
  247. fitemname:=aitemname;
  248. fitemkind:=lsmik_boolean;
  249. inherited create(llvmbool1type,tai_const.Create_8bit(ord(boolval)));
  250. end;
  251. constructor tllvmspecialisedmetaitem.createint64(const aitemname: TSymStr; intval: int64);
  252. begin
  253. fitemname:=aitemname;
  254. fitemkind:=lsmik_int64;
  255. inherited create(llvmbool1type,tai_const.Create_64bit(intval));
  256. end;
  257. constructor tllvmspecialisedmetaitem.createqword(const aitemname: TSymStr; qwval: qword);
  258. begin
  259. fitemname:=aitemname;
  260. fitemkind:=lsmik_qword;
  261. inherited create(llvmbool1type,tai_const.Create_64bit(int64(qwval)));
  262. end;
  263. constructor tllvmspecialisedmetaitem.createmetadataref(const aitemname: TSymStr; aival: tai_llvmmetadatareftypedconst);
  264. begin
  265. fitemname:=aitemname;
  266. fitemkind:=lsmik_metadataref;
  267. inherited create(llvm_metadatatype,aival);
  268. end;
  269. constructor tllvmspecialisedmetaitem.createstring(const aitemname: TSymStr; const stringval: TSymStr);
  270. begin
  271. fitemname:=aitemname;
  272. fitemkind:=lsmik_string;
  273. inherited create(charpointertype,tai_string.Create(stringval));
  274. end;
  275. constructor tllvmspecialisedmetaitem.createenum(const aitemname: TSymStr; const enumval: TSymStr);
  276. begin
  277. fitemname:=aitemname;
  278. fitemkind:=lsmik_enum;
  279. inherited create(charpointertype,tai_string.Create(enumval));
  280. end;
  281. constructor tai_llvmspecialisedmetadatanode.create(aKind: tspecialisedmetadatanodekind);
  282. begin
  283. inherited create;
  284. fkind:=aKind;
  285. end;
  286. procedure tai_llvmspecialisedmetadatanode.addemplaceitem(const item: tllvmspecialisedmetaitem);
  287. begin
  288. inherited addvalue(item);
  289. end;
  290. procedure tai_llvmspecialisedmetadatanode.switchkind(newKind: tspecialisedmetadatanodekind);
  291. begin
  292. if fvalues.Count<>0 then
  293. internalerror(2022110611);
  294. fkind:=newKind;
  295. end;
  296. procedure tai_llvmspecialisedmetadatanode.addvalue(val: tai_abstracttypedconst);
  297. begin
  298. internalerror(2021121601);
  299. end;
  300. procedure tai_llvmspecialisedmetadatanode.addboolean(const aitemname: TSymStr; boolval: boolean);
  301. var
  302. item: tllvmspecialisedmetaitem;
  303. begin
  304. item:=tllvmspecialisedmetaitem.createboolean(aitemname, boolval);
  305. addemplaceitem(item);
  306. end;
  307. procedure tai_llvmspecialisedmetadatanode.addint64(const aitemname: TSymStr; intval: int64);
  308. var
  309. item: tllvmspecialisedmetaitem;
  310. begin
  311. item:=tllvmspecialisedmetaitem.createint64(aitemname, intval);
  312. addemplaceitem(item);
  313. end;
  314. procedure tai_llvmspecialisedmetadatanode.addqword(const aitemname: TSymStr; qwval: qword);
  315. var
  316. item: tllvmspecialisedmetaitem;
  317. begin
  318. item:=tllvmspecialisedmetaitem.createqword(aitemname, qwval);
  319. addemplaceitem(item);
  320. end;
  321. procedure tai_llvmspecialisedmetadatanode.addmetadatarefto(const aitemname: TSymStr; aival: tai_llvmbasemetadatanode);
  322. var
  323. item: tllvmspecialisedmetaitem;
  324. begin
  325. if assigned(aival) then
  326. item:=tllvmspecialisedmetaitem.createmetadataref(aitemname, tai_llvmmetadatareftypedconst.create(aival))
  327. else
  328. item:=tllvmspecialisedmetaitem.createmetadataref(aitemname, nil);
  329. addemplaceitem(item);
  330. end;
  331. procedure tai_llvmspecialisedmetadatanode.addstring(const aitemname: TSymStr; const stringval: TSymStr);
  332. var
  333. item: tllvmspecialisedmetaitem;
  334. begin
  335. item:=tllvmspecialisedmetaitem.createstring(aitemname, stringval);
  336. addemplaceitem(item);
  337. end;
  338. procedure tai_llvmspecialisedmetadatanode.addenum(const aitemname: TSymStr; const enumval: TSymStr);
  339. var
  340. item: tllvmspecialisedmetaitem;
  341. begin
  342. item:=tllvmspecialisedmetaitem.createenum(aitemname, enumval);
  343. addemplaceitem(item);
  344. end;
  345. function tai_llvmspecialisedmetadatanode.IsDistinct: boolean;
  346. begin
  347. case fkind of
  348. tspecialisedmetadatanodekind.DICompileUnit,
  349. tspecialisedmetadatanodekind.DISubprogram,
  350. tspecialisedmetadatanodekind.DIGlobalVariable,
  351. tspecialisedmetadatanodekind.DICompositeType,
  352. tspecialisedmetadatanodekind.DILexicalBlock,
  353. tspecialisedmetadatanodekind.DIMacro:
  354. result:=true;
  355. tspecialisedmetadatanodekind.DIFile,
  356. tspecialisedmetadatanodekind.DIBasicType,
  357. tspecialisedmetadatanodekind.DIDerivedType,
  358. tspecialisedmetadatanodekind.DISubrange,
  359. tspecialisedmetadatanodekind.DIEnumerator,
  360. tspecialisedmetadatanodekind.DITemplateTypeParameter,
  361. tspecialisedmetadatanodekind.DITemplateValueParameter,
  362. tspecialisedmetadatanodekind.DINamespace,
  363. tspecialisedmetadatanodekind.DIGlobalVariableExpression,
  364. tspecialisedmetadatanodekind.DILexicalBlockFile,
  365. tspecialisedmetadatanodekind.DILocation,
  366. tspecialisedmetadatanodekind.DILocalVariable,
  367. tspecialisedmetadatanodekind.DIExpression,
  368. tspecialisedmetadatanodekind.DIObjCProperty,
  369. tspecialisedmetadatanodekind.DIImportedEntity,
  370. tspecialisedmetadatanodekind.DISubroutineType,
  371. tspecialisedmetadatanodekind.DIMacroFile:
  372. result:=false;
  373. end;
  374. end;
  375. class function tai_llvmspecialisedmetadatanode.isspecialised: boolean;
  376. begin
  377. result:=true;
  378. end;
  379. /////////////////////////////////////////////////
  380. class function tllvmmetadata.addstring(const s: TSymStr): TSuperRegister;
  381. var
  382. index: longint;
  383. begin
  384. index:=current_module.llvmmetadatastrings.Add(s,nil);
  385. if index>high(result) then
  386. internalerror(2019122806);
  387. result:=index;
  388. end;
  389. class function tllvmmetadata.regtostring(reg: TRegister): TSymStr;
  390. begin
  391. if getregtype(reg)<>R_METADATAREGISTER then
  392. internalerror(2019122807);
  393. if getsubreg(reg)<>R_SUBMETASTRING then
  394. internalerror(2019122808);
  395. result:=current_module.llvmmetadatastrings.NameOfIndex(getsupreg(reg));
  396. end;
  397. class function tllvmmetadata.getstringreg(const s: TSymstr): TRegister;
  398. var
  399. supreg: TSuperRegister;
  400. index: longint;
  401. begin
  402. index:=current_module.llvmmetadatastrings.FindIndexOf(s);
  403. if index<>-1 then
  404. supreg:=index
  405. else
  406. supreg:=addstring(s);
  407. result:=newreg(R_METADATAREGISTER,supreg,R_SUBMETASTRING);
  408. end;
  409. class function tllvmmetadata.getpcharreg(p: pchar; len: longint): TRegister;
  410. var
  411. str: TSymStr;
  412. begin
  413. if len>0 then
  414. begin
  415. setlength(str,len);
  416. move(p[0],str[1],len);
  417. result:=getstringreg(str);
  418. end
  419. else
  420. result:=getstringreg('');
  421. end;
  422. class function tllvmmetadata.getregstring(reg: TRegister): TSymStr;
  423. begin
  424. result:=regtostring(reg);
  425. end;
  426. end.