llvmtype.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. {
  2. Copyright (c) 2008,2015 by Peter Vreman, Florian Klaempfl and Jonas Maebe
  3. This units contains support for generating LLVM type info
  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. {
  18. This units contains support for LLVM type info generation.
  19. It's based on the debug info system, since it's quite similar
  20. }
  21. unit llvmtype;
  22. {$i fpcdefs.inc}
  23. {$h+}
  24. interface
  25. uses
  26. cclasses,globtype,
  27. aasmbase,aasmtai,aasmdata,
  28. symbase,symtype,symdef,symsym,
  29. aasmllvm,aasmcnst,
  30. finput,
  31. dbgbase;
  32. { TLLVMTypeInfo }
  33. type
  34. TLLVMTypeInfo = class(TDebugInfo)
  35. protected
  36. { using alias/external declarations it's possible to refer to the same
  37. assembler symbol using multiple types:
  38. function f(p: pointer): pointer; [public, alias: 'FPC_FUNC'];
  39. procedure test(p: pointer); external name 'FPC_FUNC';
  40. We have to insert the appropriate typecasts (per module) for LLVM in
  41. this case. That can only be done after all code for a module has been
  42. generated, as these alias declarations can appear anywhere }
  43. asmsymtypes: THashSet;
  44. procedure record_asmsym_def(sym: TAsmSymbol; def: tdef);
  45. function get_asmsym_def(sym: TAsmSymbol): tdef;
  46. function record_def(def:tdef): tdef;
  47. procedure appenddef_array(list:TAsmList;def:tarraydef);override;
  48. procedure appenddef_abstractrecord(list:TAsmList;def:tabstractrecorddef);
  49. procedure appenddef_record(list:TAsmList;def:trecorddef);override;
  50. procedure appenddef_pointer(list:TAsmList;def:tpointerdef);override;
  51. procedure appenddef_procvar(list:TAsmList;def:tprocvardef);override;
  52. procedure appendprocdef(list:TAsmList;def:tprocdef);override;
  53. procedure appenddef_object(list:TAsmList;def: tobjectdef);override;
  54. procedure appenddef_variant(list:TAsmList;def: tvariantdef);override;
  55. procedure appendsym_var(list:TAsmList;sym:tabstractnormalvarsym);
  56. procedure appendsym_staticvar(list:TAsmList;sym:tstaticvarsym);override;
  57. procedure appendsym_paravar(list:TAsmList;sym:tparavarsym);override;
  58. procedure appendsym_localvar(list:TAsmList;sym:tlocalvarsym);override;
  59. procedure appendsym_fieldvar(list:TAsmList;sym:tfieldvarsym);override;
  60. procedure appendsym_const(list:TAsmList;sym:tconstsym);override;
  61. procedure appendsym_absolute(list:TAsmList;sym:tabsolutevarsym);override;
  62. procedure enum_membersyms_callback(p:TObject;arg:pointer);
  63. procedure collect_llvmins_info(deftypelist: tasmlist; p: taillvm);
  64. procedure collect_tai_info(deftypelist: tasmlist; p: tai);
  65. procedure collect_asmlist_info(deftypelist, asmlist: tasmlist);
  66. procedure insert_llvmins_typeconversions(p: taillvm);
  67. procedure insert_typedconst_typeconversion(p: tai_abstracttypedconst);
  68. procedure insert_tai_typeconversions(p: tai);
  69. procedure insert_asmlist_typeconversions(list: tasmlist);
  70. public
  71. constructor Create;override;
  72. destructor Destroy;override;
  73. procedure inserttypeinfo;override;
  74. end;
  75. implementation
  76. uses
  77. sysutils,cutils,cfileutl,constexp,
  78. version,globals,verbose,systems,
  79. cpubase,cgbase,paramgr,
  80. fmodule,nobj,
  81. defutil,defcmp,symconst,symtable,
  82. llvmbase,llvmdef
  83. ;
  84. {****************************************************************************
  85. TDebugInfoDwarf
  86. ****************************************************************************}
  87. procedure TLLVMTypeInfo.record_asmsym_def(sym: TAsmSymbol; def: tdef);
  88. var
  89. res: PHashSetItem;
  90. begin
  91. res:=asmsymtypes.FindOrAdd(@sym,sizeof(sym));
  92. { if there are multiple definitions of the same symbol, we're in
  93. trouble anyway, so don't bother checking whether data is already
  94. assigned }
  95. res^.Data:=def;
  96. end;
  97. function TLLVMTypeInfo.get_asmsym_def(sym: TAsmSymbol): tdef;
  98. var
  99. res: PHashSetItem;
  100. begin
  101. res:=asmsymtypes.Find(@sym,sizeof(sym));
  102. { we must have a def for every used asmsym }
  103. if not assigned(res) or
  104. not assigned(res^.data) then
  105. internalerror(2015042701);
  106. result:=tdef(res^.Data);
  107. end;
  108. function TLLVMTypeInfo.record_def(def:tdef): tdef;
  109. begin
  110. result:=def;
  111. if def.dbg_state<>dbg_state_unused then
  112. exit;
  113. def.dbg_state:=dbg_state_used;
  114. deftowritelist.Add(def);
  115. defnumberlist.Add(def);
  116. end;
  117. constructor TLLVMTypeInfo.Create;
  118. begin
  119. inherited Create;
  120. asmsymtypes:=THashSet.Create(current_asmdata.AsmSymbolDict.Count,true,false);
  121. end;
  122. destructor TLLVMTypeInfo.Destroy;
  123. begin
  124. asmsymtypes.free;
  125. inherited destroy;
  126. end;
  127. procedure TLLVMTypeInfo.enum_membersyms_callback(p:TObject; arg: pointer);
  128. begin
  129. case tsym(p).typ of
  130. fieldvarsym:
  131. appendsym_fieldvar(TAsmList(arg),tfieldvarsym(p));
  132. end;
  133. end;
  134. procedure TLLVMTypeInfo.collect_llvmins_info(deftypelist: tasmlist; p: taillvm);
  135. var
  136. opidx, paraidx: longint;
  137. callpara: pllvmcallpara;
  138. begin
  139. for opidx:=0 to p.ops-1 do
  140. case p.oper[opidx]^.typ of
  141. top_def:
  142. appenddef(deftypelist,p.oper[opidx]^.def);
  143. top_tai:
  144. collect_tai_info(deftypelist,p.oper[opidx]^.ai);
  145. top_para:
  146. for paraidx:=0 to p.oper[opidx]^.paras.count-1 do
  147. begin
  148. callpara:=pllvmcallpara(p.oper[opidx]^.paras[paraidx]);
  149. appenddef(deftypelist,callpara^.def);
  150. end;
  151. end;
  152. end;
  153. procedure TLLVMTypeInfo.collect_tai_info(deftypelist: tasmlist; p: tai);
  154. begin
  155. case p.typ of
  156. ait_llvmalias:
  157. begin
  158. appenddef(deftypelist,taillvmalias(p).def);
  159. record_asmsym_def(taillvmalias(p).newsym,taillvmalias(p).def);
  160. end;
  161. ait_llvmdecl:
  162. begin
  163. appenddef(deftypelist,taillvmdecl(p).def);
  164. record_asmsym_def(taillvmdecl(p).namesym,taillvmdecl(p).def);
  165. collect_asmlist_info(deftypelist,taillvmdecl(p).initdata);
  166. end;
  167. ait_llvmins:
  168. collect_llvmins_info(deftypelist,taillvm(p));
  169. ait_typedconst:
  170. appenddef(deftypelist,tai_abstracttypedconst(p).def);
  171. end;
  172. end;
  173. procedure TLLVMTypeInfo.collect_asmlist_info(deftypelist, asmlist: tasmlist);
  174. var
  175. hp: tai;
  176. begin
  177. if not assigned(asmlist) then
  178. exit;
  179. hp:=tai(asmlist.first);
  180. while assigned(hp) do
  181. begin
  182. collect_tai_info(deftypelist,hp);
  183. hp:=tai(hp.next);
  184. end;
  185. end;
  186. function equal_llvm_defs(def1, def2: tdef): boolean;
  187. var
  188. def1str, def2str: TSymStr;
  189. begin
  190. if def1=def2 then
  191. exit(true);
  192. def1str:=llvmencodetypename(def1);
  193. def2str:=llvmencodetypename(def2);
  194. { normalise both type representations in case one is a procdef
  195. and the other is a procvardef}
  196. if def1.typ=procdef then
  197. def1str:=def1str+'*';
  198. if def2.typ=procdef then
  199. def2str:=def2str+'*';
  200. result:=def1str=def2str;
  201. end;
  202. procedure TLLVMTypeInfo.insert_llvmins_typeconversions(p: taillvm);
  203. var
  204. symdef,
  205. opdef: tdef;
  206. cnv: taillvm;
  207. i: longint;
  208. begin
  209. case p.llvmopcode of
  210. la_call:
  211. if p.oper[3]^.typ=top_ref then
  212. begin
  213. symdef:=get_asmsym_def(p.oper[3]^.ref^.symbol);
  214. { the type used in the call is different from the type used to
  215. declare the symbol -> insert a typecast }
  216. if not equal_llvm_defs(symdef,p.oper[0]^.def) then
  217. begin
  218. if symdef.typ=procdef then
  219. { ugly, but can't use getcopyas(procvardef) due to the
  220. symtablestack not being available here (getpointerdef
  221. is hardcoded to put things in the current module's
  222. symtable) and "pointer to procedure" results in the
  223. correct llvm type }
  224. symdef:=getpointerdef(tprocdef(symdef));
  225. cnv:=taillvm.op_reg_size_sym_size(la_bitcast,NR_NO,symdef,p.oper[3]^.ref^.symbol,p.oper[0]^.def);
  226. p.loadtai(3,cnv);
  227. end;
  228. end;
  229. else if p.llvmopcode<>la_br then
  230. begin
  231. { check the types of all symbolic operands }
  232. for i:=0 to p.ops-1 do
  233. case p.oper[i]^.typ of
  234. top_ref:
  235. if (p.oper[i]^.ref^.refaddr=addr_full) and
  236. (p.oper[i]^.ref^.symbol.bind<>AB_TEMP) then
  237. begin
  238. symdef:=get_asmsym_def(p.oper[i]^.ref^.symbol);
  239. opdef:=p.spilling_get_reg_type(i);
  240. if not equal_llvm_defs(symdef,opdef) then
  241. begin
  242. cnv:=taillvm.op_reg_size_sym_size(la_bitcast,NR_NO,symdef,p.oper[i]^.ref^.symbol,opdef);
  243. p.loadtai(i,cnv);
  244. end;
  245. end;
  246. top_tai:
  247. insert_tai_typeconversions(p.oper[i]^.ai);
  248. end;
  249. end;
  250. end;
  251. end;
  252. procedure TLLVMTypeInfo.insert_typedconst_typeconversion(p: tai_abstracttypedconst);
  253. var
  254. symdef: tdef;
  255. cnv: taillvm;
  256. elementp: tai_abstracttypedconst;
  257. begin
  258. case p.adetyp of
  259. tck_simple:
  260. begin
  261. case tai_simpletypedconst(p).val.typ of
  262. ait_const:
  263. if assigned(tai_const(tai_simpletypedconst(p).val).sym) and
  264. not assigned(tai_const(tai_simpletypedconst(p).val).endsym) then
  265. begin
  266. symdef:=get_asmsym_def(tai_const(tai_simpletypedconst(p).val).sym);
  267. { all references to symbols in typed constants are
  268. references to the address of a global symbol (you can't
  269. refer to the data itself, just like you can't initialise
  270. a Pascal (typed) constant with the contents of another
  271. typed constant) }
  272. symdef:=getpointerdef(symdef);
  273. if not equal_llvm_defs(symdef,p.def) then
  274. begin
  275. cnv:=taillvm.op_reg_tai_size(la_bitcast,NR_NO,tai_simpletypedconst.create(tck_simple,symdef,tai_simpletypedconst(p).val),p.def);
  276. tai_simpletypedconst(p).val:=cnv;
  277. end;
  278. end;
  279. else
  280. insert_tai_typeconversions(tai_const(tai_simpletypedconst(p).val));
  281. end;
  282. end;
  283. tck_array,
  284. tck_record:
  285. begin
  286. for elementp in tai_aggregatetypedconst(p) do
  287. insert_typedconst_typeconversion(elementp);
  288. end;
  289. end;
  290. end;
  291. procedure TLLVMTypeInfo.insert_tai_typeconversions(p: tai);
  292. begin
  293. case p.typ of
  294. ait_llvmins:
  295. insert_llvmins_typeconversions(taillvm(p));
  296. { can also be necessary in case someone initialises a typed const with
  297. the address of an external symbol aliasing one declared with a
  298. different type in the same mmodule. }
  299. ait_typedconst:
  300. insert_typedconst_typeconversion(tai_abstracttypedconst(p));
  301. ait_llvmdecl:
  302. insert_asmlist_typeconversions(taillvmdecl(p).initdata);
  303. end;
  304. end;
  305. procedure TLLVMTypeInfo.insert_asmlist_typeconversions(list: tasmlist);
  306. var
  307. hp: tai;
  308. begin
  309. if not assigned(list) then
  310. exit;
  311. hp:=tai(list.first);
  312. while assigned(hp) do
  313. begin
  314. insert_tai_typeconversions(hp);
  315. hp:=tai(hp.next);
  316. end;
  317. end;
  318. procedure TLLVMTypeInfo.appenddef_array(list:TAsmList;def:tarraydef);
  319. begin
  320. appenddef(list,def.elementdef);
  321. end;
  322. procedure TLLVMTypeInfo.appenddef_abstractrecord(list:TAsmList;def:tabstractrecorddef);
  323. var
  324. symdeflist: tfpobjectlist;
  325. i: longint;
  326. begin
  327. symdeflist:=tabstractrecordsymtable(def.symtable).llvmst.symdeflist;
  328. for i:=0 to symdeflist.Count-1 do
  329. appenddef(list,tllvmshadowsymtableentry(symdeflist[i]).def);
  330. if assigned(def.typesym) then
  331. list.concat(taillvm.op_size(LA_TYPE,record_def(def)));
  332. end;
  333. procedure TLLVMTypeInfo.appenddef_record(list:TAsmList;def:trecorddef);
  334. begin
  335. appenddef_abstractrecord(list,def);
  336. end;
  337. procedure TLLVMTypeInfo.appenddef_pointer(list:TAsmList;def:tpointerdef);
  338. begin
  339. appenddef(list,def.pointeddef);
  340. end;
  341. procedure TLLVMTypeInfo.appenddef_procvar(list:TAsmList;def:tprocvardef);
  342. var
  343. i: longint;
  344. begin
  345. { todo: handle mantis #25551; there is no way to create a symbolic
  346. la_type for a procvardef (unless it's a procedure of object/record),
  347. which means that recursive references should become plain "procedure"
  348. types that are then casted to the real type when they are used }
  349. for i:=0 to def.paras.count-1 do
  350. appenddef(list,tparavarsym(def.paras[i]).vardef);
  351. appenddef(list,def.returndef);
  352. if assigned(def.typesym) and
  353. not def.is_addressonly then
  354. list.concat(taillvm.op_size(LA_TYPE,record_def(def)));
  355. end;
  356. procedure TLLVMTypeInfo.appendprocdef(list:TAsmList;def:tprocdef);
  357. begin
  358. { the procdef itself is already written by appendprocdef_implicit }
  359. { last write the types from this procdef }
  360. if assigned(def.parast) then
  361. write_symtable_defs(current_asmdata.asmlists[al_start],def.parast);
  362. if assigned(def.localst) and
  363. (def.localst.symtabletype=localsymtable) then
  364. write_symtable_defs(current_asmdata.asmlists[al_start],def.localst);
  365. end;
  366. procedure TLLVMTypeInfo.appendsym_var(list:TAsmList;sym:tabstractnormalvarsym);
  367. begin
  368. appenddef(list,sym.vardef);
  369. end;
  370. procedure TLLVMTypeInfo.appendsym_staticvar(list:TAsmList;sym:tstaticvarsym);
  371. begin
  372. appendsym_var(list,sym);
  373. end;
  374. procedure TLLVMTypeInfo.appendsym_localvar(list:TAsmList;sym:tlocalvarsym);
  375. begin
  376. appendsym_var(list,sym);
  377. end;
  378. procedure TLLVMTypeInfo.appendsym_paravar(list:TAsmList;sym:tparavarsym);
  379. begin
  380. appendsym_var(list,sym);
  381. end;
  382. procedure TLLVMTypeInfo.appendsym_fieldvar(list:TAsmList;sym: tfieldvarsym);
  383. begin
  384. appenddef(list,sym.vardef);
  385. end;
  386. procedure TLLVMTypeInfo.appendsym_const(list:TAsmList;sym:tconstsym);
  387. begin
  388. appenddef(list,sym.constdef);
  389. end;
  390. procedure TLLVMTypeInfo.appendsym_absolute(list:TAsmList;sym:tabsolutevarsym);
  391. begin
  392. appenddef(list,sym.vardef);
  393. end;
  394. procedure TLLVMTypeInfo.inserttypeinfo;
  395. procedure write_defs_to_write;
  396. var
  397. n : integer;
  398. looplist,
  399. templist: TFPObjectList;
  400. def : tdef;
  401. begin
  402. templist := TFPObjectList.Create(False);
  403. looplist := deftowritelist;
  404. while looplist.count > 0 do
  405. begin
  406. deftowritelist := templist;
  407. for n := 0 to looplist.count - 1 do
  408. begin
  409. def := tdef(looplist[n]);
  410. case def.dbg_state of
  411. dbg_state_written:
  412. continue;
  413. dbg_state_writing:
  414. internalerror(200610052);
  415. dbg_state_unused:
  416. internalerror(200610053);
  417. dbg_state_used:
  418. appenddef(current_asmdata.asmlists[al_start],def)
  419. else
  420. internalerror(200610054);
  421. end;
  422. end;
  423. looplist.clear;
  424. templist := looplist;
  425. looplist := deftowritelist;
  426. end;
  427. templist.free;
  428. end;
  429. var
  430. storefilepos: tfileposinfo;
  431. def: tdef;
  432. i: longint;
  433. hal: tasmlisttype;
  434. begin
  435. storefilepos:=current_filepos;
  436. current_filepos:=current_module.mainfilepos;
  437. defnumberlist:=TFPObjectList.create(false);
  438. deftowritelist:=TFPObjectList.create(false);
  439. { write all global/static variables, part of flaggin all required tdefs }
  440. if assigned(current_module.globalsymtable) then
  441. write_symtable_syms(current_asmdata.asmlists[al_start],current_module.globalsymtable);
  442. if assigned(current_module.localsymtable) then
  443. write_symtable_syms(current_asmdata.asmlists[al_start],current_module.localsymtable);
  444. { write all procedures and methods, part of flagging all required tdefs }
  445. if assigned(current_module.globalsymtable) then
  446. write_symtable_procdefs(current_asmdata.asmlists[al_start],current_module.globalsymtable);
  447. if assigned(current_module.localsymtable) then
  448. write_symtable_procdefs(current_asmdata.asmlists[al_start],current_module.localsymtable);
  449. { process all llvm instructions, part of flagging all required tdefs }
  450. for hal:=low(TasmlistType) to high(TasmlistType) do
  451. if hal<>al_start then
  452. collect_asmlist_info(current_asmdata.asmlists[al_start],current_asmdata.asmlists[hal]);
  453. for hal:=low(TasmlistType) to high(TasmlistType) do
  454. if hal<>al_start then
  455. insert_asmlist_typeconversions(current_asmdata.asmlists[hal]);
  456. { write all used defs }
  457. write_defs_to_write;
  458. { reset all def labels }
  459. for i:=0 to defnumberlist.count-1 do
  460. begin
  461. def := tdef(defnumberlist[i]);
  462. if assigned(def) then
  463. begin
  464. def.dbg_state:=dbg_state_unused;
  465. end;
  466. end;
  467. defnumberlist.free;
  468. defnumberlist:=nil;
  469. deftowritelist.free;
  470. deftowritelist:=nil;
  471. current_filepos:=storefilepos;
  472. end;
  473. procedure TLLVMTypeInfo.appenddef_object(list:TAsmList;def: tobjectdef);
  474. begin
  475. appenddef_abstractrecord(list,def);
  476. end;
  477. procedure TLLVMTypeInfo.appenddef_variant(list:TAsmList;def: tvariantdef);
  478. begin
  479. appenddef(list,tabstractrecorddef(search_system_type('TVARDATA').typedef));
  480. end;
  481. end.