llvmtype.pas 21 KB

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