fpc/compiler/llvm/llvmtype.pas
Jonas Maebe e2cf90ad8a * add type declarations for structure types in the llvm code so that we can
handle recursive record references (rec= record prec: ^rec)
   o llvm unfortunately does not support recursive references to array types
     or function pointers, so those will currently still result in endless
     recursion when the compiler tries to write them out. Solving those
     will require a lot of typecasting in the generated code

git-svn-id: trunk@30675 -
2015-04-19 21:37:46 +00:00

379 lines
12 KiB
ObjectPascal

{
Copyright (c) 2008,2015 by Peter Vreman, Florian Klaempfl and Jonas Maebe
This units contains support for generating LLVM type info
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
{
This units contains support for LLVM type info generation.
It's based on the debug info system, since it's quite similar
}
unit llvmtype;
{$i fpcdefs.inc}
{$h+}
interface
uses
cclasses,globtype,
aasmbase,aasmtai,aasmdata,
symbase,symtype,symdef,symsym,
finput,
dbgbase;
{ TLLVMTypeInfo }
type
TLLVMTypeInfo = class(TDebugInfo)
protected
function record_def(def:tdef): tdef;
procedure appenddef_array(list:TAsmList;def:tarraydef);override;
procedure appenddef_abstractrecord(list:TAsmList;def:tabstractrecorddef);
procedure appenddef_record(list:TAsmList;def:trecorddef);override;
procedure appenddef_pointer(list:TAsmList;def:tpointerdef);override;
procedure appenddef_procvar(list:TAsmList;def:tprocvardef);override;
procedure appendprocdef(list:TAsmList;def:tprocdef);override;
procedure appenddef_object(list:TAsmList;def: tobjectdef);override;
procedure appenddef_variant(list:TAsmList;def: tvariantdef);override;
procedure appendsym_var(list:TAsmList;sym:tabstractnormalvarsym);
procedure appendsym_staticvar(list:TAsmList;sym:tstaticvarsym);override;
procedure appendsym_paravar(list:TAsmList;sym:tparavarsym);override;
procedure appendsym_localvar(list:TAsmList;sym:tlocalvarsym);override;
procedure appendsym_fieldvar(list:TAsmList;sym:tfieldvarsym);override;
procedure appendsym_const(list:TAsmList;sym:tconstsym);override;
procedure appendsym_absolute(list:TAsmList;sym:tabsolutevarsym);override;
procedure enum_membersyms_callback(p:TObject;arg:pointer);
procedure process_llvmins(deftypelist: tasmlist; p: tai);
procedure process_tai(deftypelist: tasmlist; p: tai);
procedure process_asmlist(deftypelist, asmlist: tasmlist);
public
constructor Create;override;
destructor Destroy;override;
procedure inserttypeinfo;override;
end;
implementation
uses
sysutils,cutils,cfileutl,constexp,
version,globals,verbose,systems,
cpubase,cgbase,paramgr,
fmodule,nobj,
defutil,symconst,symtable,
llvmbase, aasmllvm, aasmcnst;
{****************************************************************************
TDebugInfoDwarf
****************************************************************************}
function TLLVMTypeInfo.record_def(def:tdef): tdef;
begin
result:=def;
if def.dbg_state<>dbg_state_unused then
exit;
def.dbg_state:=dbg_state_used;
deftowritelist.Add(def);
defnumberlist.Add(def);
end;
constructor TLLVMTypeInfo.Create;
begin
inherited Create;
end;
destructor TLLVMTypeInfo.Destroy;
begin
inherited destroy;
end;
procedure TLLVMTypeInfo.enum_membersyms_callback(p:TObject; arg: pointer);
begin
case tsym(p).typ of
fieldvarsym:
appendsym_fieldvar(TAsmList(arg),tfieldvarsym(p));
end;
end;
procedure TLLVMTypeInfo.process_llvmins(deftypelist: tasmlist; p: tai);
var
opidx, paraidx: longint;
callpara: pllvmcallpara;
begin
for opidx:=0 to taillvm(p).ops-1 do
case taillvm(p).oper[opidx]^.typ of
top_def:
appenddef(deftypelist,taillvm(p).oper[opidx]^.def);
top_tai:
process_tai(deftypelist,taillvm(p).oper[opidx]^.ai);
top_para:
for paraidx:=0 to taillvm(p).oper[opidx]^.paras.count-1 do
begin
callpara:=pllvmcallpara(taillvm(p).oper[opidx]^.paras[paraidx]);
appenddef(deftypelist,callpara^.def);
end;
end;
end;
procedure TLLVMTypeInfo.process_tai(deftypelist: tasmlist; p: tai);
begin
case p.typ of
ait_llvmalias:
appenddef(deftypelist,taillvmalias(p).def);
ait_llvmdecl:
appenddef(deftypelist,taillvmdecl(p).def);
ait_llvmins:
process_llvmins(deftypelist,p);
ait_typedconst:
appenddef(deftypelist,tai_abstracttypedconst(p).def);
end;
end;
procedure TLLVMTypeInfo.process_asmlist(deftypelist, asmlist: tasmlist);
var
hp: tai;
begin
if not assigned(asmlist) then
exit;
hp:=tai(asmlist.first);
while assigned(hp) do
begin
process_tai(deftypelist,hp);
hp:=tai(hp.next);
end;
end;
procedure TLLVMTypeInfo.appenddef_array(list:TAsmList;def:tarraydef);
begin
appenddef(list,def.elementdef);
end;
procedure TLLVMTypeInfo.appenddef_abstractrecord(list:TAsmList;def:tabstractrecorddef);
var
symdeflist: tfpobjectlist;
i: longint;
begin
symdeflist:=tabstractrecordsymtable(def.symtable).llvmst.symdeflist;
for i:=0 to symdeflist.Count-1 do
appenddef(list,tllvmshadowsymtableentry(symdeflist[i]).def);
if assigned(def.typesym) then
list.concat(taillvm.op_size(LA_TYPE,record_def(def)));
end;
procedure TLLVMTypeInfo.appenddef_record(list:TAsmList;def:trecorddef);
begin
appenddef_abstractrecord(list,def);
end;
procedure TLLVMTypeInfo.appenddef_pointer(list:TAsmList;def:tpointerdef);
begin
appenddef(list,def.pointeddef);
end;
procedure TLLVMTypeInfo.appenddef_procvar(list:TAsmList;def:tprocvardef);
var
i: longint;
begin
{ todo: handle mantis #25551; there is no way to create a symbolic
la_type for a procvardef (unless it's a procedure of object/record),
which means that recursive references should become plain "procedure"
types that are then casted to the real type when they are used }
for i:=0 to def.paras.count-1 do
appenddef(list,tparavarsym(def.paras[i]).vardef);
appenddef(list,def.returndef);
if assigned(def.typesym) and
not def.is_addressonly then
list.concat(taillvm.op_size(LA_TYPE,record_def(def)));
end;
procedure TLLVMTypeInfo.appendprocdef(list:TAsmList;def:tprocdef);
begin
{ the procdef itself is already written by appendprocdef_implicit }
{ last write the types from this procdef }
if assigned(def.parast) then
write_symtable_defs(current_asmdata.asmlists[al_start],def.parast);
if assigned(def.localst) and
(def.localst.symtabletype=localsymtable) then
write_symtable_defs(current_asmdata.asmlists[al_start],def.localst);
end;
procedure TLLVMTypeInfo.appendsym_var(list:TAsmList;sym:tabstractnormalvarsym);
begin
appenddef(list,sym.vardef);
end;
procedure TLLVMTypeInfo.appendsym_staticvar(list:TAsmList;sym:tstaticvarsym);
begin
appendsym_var(list,sym);
end;
procedure TLLVMTypeInfo.appendsym_localvar(list:TAsmList;sym:tlocalvarsym);
begin
appendsym_var(list,sym);
end;
procedure TLLVMTypeInfo.appendsym_paravar(list:TAsmList;sym:tparavarsym);
begin
appendsym_var(list,sym);
end;
procedure TLLVMTypeInfo.appendsym_fieldvar(list:TAsmList;sym: tfieldvarsym);
begin
appenddef(list,sym.vardef);
end;
procedure TLLVMTypeInfo.appendsym_const(list:TAsmList;sym:tconstsym);
begin
appenddef(list,sym.constdef);
end;
procedure TLLVMTypeInfo.appendsym_absolute(list:TAsmList;sym:tabsolutevarsym);
begin
appenddef(list,sym.vardef);
end;
procedure TLLVMTypeInfo.inserttypeinfo;
procedure write_defs_to_write;
var
n : integer;
looplist,
templist: TFPObjectList;
def : tdef;
begin
templist := TFPObjectList.Create(False);
looplist := deftowritelist;
while looplist.count > 0 do
begin
deftowritelist := templist;
for n := 0 to looplist.count - 1 do
begin
def := tdef(looplist[n]);
case def.dbg_state of
dbg_state_written:
continue;
dbg_state_writing:
internalerror(200610052);
dbg_state_unused:
internalerror(200610053);
dbg_state_used:
appenddef(current_asmdata.asmlists[al_start],def)
else
internalerror(200610054);
end;
end;
looplist.clear;
templist := looplist;
looplist := deftowritelist;
end;
templist.free;
end;
var
storefilepos: tfileposinfo;
def: tdef;
i: longint;
hal: tasmlisttype;
begin
storefilepos:=current_filepos;
current_filepos:=current_module.mainfilepos;
defnumberlist:=TFPObjectList.create(false);
deftowritelist:=TFPObjectList.create(false);
{ write all global/static variables, part of flaggin all required tdefs }
if assigned(current_module.globalsymtable) then
write_symtable_syms(current_asmdata.asmlists[al_start],current_module.globalsymtable);
if assigned(current_module.localsymtable) then
write_symtable_syms(current_asmdata.asmlists[al_start],current_module.localsymtable);
{ write all procedures and methods, part of flagging all required tdefs }
if assigned(current_module.globalsymtable) then
write_symtable_procdefs(current_asmdata.asmlists[al_start],current_module.globalsymtable);
if assigned(current_module.localsymtable) then
write_symtable_procdefs(current_asmdata.asmlists[al_start],current_module.localsymtable);
{ process all llvm instructions, part of flagging all required tdefs }
for hal:=low(TasmlistType) to high(TasmlistType) do
if hal<>al_start then
process_asmlist(current_asmdata.asmlists[al_start],current_asmdata.asmlists[hal]);
{ write all used defs }
write_defs_to_write;
{ reset all def labels }
for i:=0 to defnumberlist.count-1 do
begin
def := tdef(defnumberlist[i]);
if assigned(def) then
begin
def.dbg_state:=dbg_state_unused;
end;
end;
defnumberlist.free;
defnumberlist:=nil;
deftowritelist.free;
deftowritelist:=nil;
current_filepos:=storefilepos;
end;
procedure TLLVMTypeInfo.appenddef_object(list:TAsmList;def: tobjectdef);
begin
appenddef_abstractrecord(list,def);
end;
procedure TLLVMTypeInfo.appenddef_variant(list:TAsmList;def: tvariantdef);
begin
appenddef(list,tabstractrecorddef(search_system_type('TVARDATA').typedef));
end;
end.