* register static symbols references from assembly code as "used" so that LLVM won't

remove them if there are no references from regular code

git-svn-id: branches/debug_eh@40432 -
This commit is contained in:
Jonas Maebe 2018-12-01 20:30:27 +00:00
parent 85702dd263
commit 68ce5dc91f
5 changed files with 120 additions and 20 deletions

View File

@ -147,8 +147,8 @@ interface
procaddrdefs : THashSet; { list of procvardefs created when getting the address of a procdef (not saved/restored) }
{$ifdef llvm}
llvmdefs : THashSet; { defs added for llvm-specific reasons (not saved/restored) }
llvmusedsyms : TFPObjectList; { a list of tllvmdecls of all symbols that need to be added to llvm.used (so they're not removed by llvm optimisation passes nor by the linker) }
llvmcompilerusedsyms : TFPObjectList; { a list of tllvmdecls of all symbols that need to be added to llvm.compiler.used (so they're not removed by llvm optimisation passes) }
llvmusedsyms : TFPObjectList; { a list of asmsymbols and their defs that need to be added to llvm.used (so they're not removed by llvm optimisation passes nor by the linker) }
llvmcompilerusedsyms : TFPObjectList; { a list of asmsymbols and their defs that need to be added to llvm.compiler.used (so they're not removed by llvm optimisation passes) }
{$endif llvm}
ansistrdef : tobject; { an ansistring def redefined for the current module }
wpoinfo : tunitwpoinfobase; { whole program optimization-related information that is generated during the current run for this unit }
@ -590,8 +590,8 @@ implementation
procaddrdefs:=THashSet.Create(64,true,false);
{$ifdef llvm}
llvmdefs:=THashSet.Create(64,true,false);
llvmusedsyms:=TFPObjectList.Create(false);
llvmcompilerusedsyms:=TFPObjectList.Create(false);
llvmusedsyms:=TFPObjectList.Create(true);
llvmcompilerusedsyms:=TFPObjectList.Create(true);
{$endif llvm}
ansistrdef:=nil;
wpoinfo:=nil;
@ -791,9 +791,9 @@ implementation
llvmdefs.free;
llvmdefs:=THashSet.Create(64,true,false);
llvmusedsyms.free;
llvmusedsyms:=TFPObjectList.Create(false);
llvmusedsyms:=TFPObjectList.Create(true);
llvmcompilerusedsyms.free;
llvmcompilerusedsyms:=TFPObjectList.Create(false);
llvmcompilerusedsyms:=TFPObjectList.Create(true);
{$endif llvm}
wpoinfo.free;
wpoinfo:=nil;

View File

@ -128,7 +128,8 @@ implementation
verbose,systems,fmodule,
aasmdata,
cpubase,cpuinfo,llvmbase,
symtable,llvmdef,defutil,defcmp;
symtable,llvmdef,defutil,defcmp,
ngenutil;
{ tllvmaggregateinformation }
@ -212,9 +213,9 @@ implementation
why it's done like this, but this is how Clang does it) }
if (target_info.system in systems_darwin) and
(section in [low(TObjCAsmSectionType)..high(TObjCAsmSectionType)]) then
current_module.llvmcompilerusedsyms.add(decl)
cnodeutils.RegisterUsedAsmSym(sym,def,false)
else
current_module.llvmusedsyms.add(decl);
cnodeutils.RegisterUsedAsmSym(sym,def,true);
newasmlist.concat(decl);
fasmlist:=newasmlist;
end;

View File

@ -27,7 +27,7 @@ interface
uses
globtype,cclasses,
aasmdata,ngenutil,
aasmbase,aasmdata,ngenutil,
symtype,symconst,symsym,symdef;
@ -38,6 +38,7 @@ interface
class procedure InsertUsedList(var usedsyms: tfpobjectlist; const usedsymsname: TSymstr);
public
class procedure InsertObjectInfo; override;
class procedure RegisterUsedAsmSym(sym: TAsmSymbol; def: tdef; compileronly: boolean); override;
end;
@ -45,7 +46,7 @@ implementation
uses
verbose,cutils,globals,fmodule,systems,
aasmbase,aasmtai,cpubase,llvmbase,aasmllvm,
aasmtai,cpubase,llvmbase,aasmllvm,
aasmcnst,nllvmtcon,
symbase,symtable,defutil,
llvmtype;
@ -71,24 +72,73 @@ implementation
end;
type
TTypedAsmSym = class
sym: TAsmSymbol;
def: tdef;
constructor Create(s: TAsmSymbol; d: tdef);
end;
constructor TTypedAsmSym.Create(s: TAsmSymbol; d: tdef);
begin
sym:=s;
def:=d;
end;
function TypedAsmSymComparer(p1, p2: Pointer): Integer;
var
sym1: TTypedAsmSym absolute p1;
sym2: TTypedAsmSym absolute p2;
begin
result:=CompareStr(sym1.sym.Name,sym2.sym.Name);
end;
class procedure tllvmnodeutils.InsertUsedList(var usedsyms: tfpobjectlist; const usedsymsname: TSymstr);
var
useddef: tdef;
tcb: ttai_typedconstbuilder;
decl: taillvmdecl;
i: longint;
prevasmsym: TAsmSymbol;
typedsym: TTypedAsmSym;
uniquesyms, i: longint;
begin
if usedsyms.count<>0 then
begin
{ a symbol can appear multiple times -> sort the list so we can filter out doubles }
usedsyms.Sort(@TypedAsmSymComparer);
{ count uniques }
prevasmsym:=nil;
uniquesyms:=0;
for i:=0 to usedsyms.count-1 do
begin
typedsym:=TTypedAsmSym(usedsyms[i]);
if (prevasmsym<>typedsym.sym) and
{ even though we already filter on pure assembler routines when adding the symbols,
some may slip through because of forward definitions that are not yet resolved }
not((typedsym.def.typ=procdef) and
(po_assembler in tprocdef(typedsym.def).procoptions)) then
inc(uniquesyms);
prevasmsym:=typedsym.sym;
end;
{ emit uniques }
prevasmsym:=nil;
tcb:=ctai_typedconstbuilder.create([tcalo_new_section]);
tllvmtai_typedconstbuilder(tcb).appendingdef:=true;
useddef:=carraydef.getreusable(voidpointertype,usedsyms.count);
useddef:=carraydef.getreusable(voidpointertype,uniquesyms);
tcb.maybe_begin_aggregate(useddef);
for i:=0 to usedsyms.count-1 do
begin
decl:=taillvmdecl(usedsyms[i]);
tcb.queue_init(voidpointertype);
tcb.queue_emit_asmsym(decl.namesym,decl.def);
typedsym:=TTypedAsmSym(usedsyms[i]);
if (prevasmsym<>typedsym.sym) and
not((typedsym.def.typ=procdef) and
(po_assembler in tprocdef(typedsym.def).procoptions)) then
begin
tcb.queue_init(voidpointertype);
tcb.queue_emit_asmsym(typedsym.sym,typedsym.def);
prevasmsym:=typedsym.sym;
end;
end;
tcb.maybe_end_aggregate(useddef);
current_asmdata.AsmLists[al_globals].concatlist(
@ -123,6 +173,28 @@ implementation
end;
class procedure tllvmnodeutils.RegisterUsedAsmSym(sym: TAsmSymbol; def: tdef; compileronly: boolean);
var
last: TTypedAsmSym;
begin
if compileronly then
begin
{ filter multiple adds in succession here already }
last:=TTypedAsmSym(current_module.llvmcompilerusedsyms.Last);
if not assigned(last) or
(last.sym<>sym) then
current_module.llvmcompilerusedsyms.Add(TTypedAsmSym.Create(sym,def))
end
else
begin
last:=TTypedAsmSym(current_module.llvmusedsyms.Last);
if not assigned(last) or
(last.sym<>sym) then
current_module.llvmusedsyms.Add(TTypedAsmSym.Create(sym,def))
end;
end;
begin
cnodeutils:=tllvmnodeutils;
end.

View File

@ -29,7 +29,7 @@ interface
uses
cclasses,globtype,
fmodule,
aasmdata,
aasmbase,aasmdata,
node,nbas,symtype,symsym,symconst,symdef;
@ -138,6 +138,11 @@ interface
info) }
class procedure InsertObjectInfo; virtual;
{ register that asm symbol sym with type def has to be considered as "used" even if not
references to it can be found. If compileronly, this is only for the compiler, otherwise
also for the linker }
class procedure RegisterUsedAsmSym(sym: TAsmSymbol; def: tdef; compileronly: boolean); virtual;
strict protected
class procedure add_main_procdef_paras(pd: tdef); virtual;
end;
@ -152,7 +157,7 @@ implementation
uses
verbose,version,globals,cutils,constexp,compinnr,
systems,procinfo,pparautl,
aasmbase,aasmtai,aasmcnst,
aasmtai,aasmcnst,
symbase,symtable,defutil,
nadd,ncal,ncnv,ncon,nflw,ninl,nld,nmem,nutils,
ppu,
@ -1547,6 +1552,12 @@ implementation
end;
class procedure tnodeutils.RegisterUsedAsmSym(sym: TAsmSymbol; def: tdef; compileronly: boolean);
begin
{ don't do anything by default }
end;
class procedure tnodeutils.add_main_procdef_paras(pd: tdef);
var
pvs: tparavarsym;

View File

@ -217,7 +217,7 @@ uses
defutil,systems,verbose,globals,
symtable,paramgr,
aasmcpu,
procinfo;
procinfo,ngenutil;
{*************************************************************************
TExprParse
@ -1383,6 +1383,22 @@ begin
srsym:=tprocdef(srsymtable.defowner).procsym;
srsymtable:=srsym.Owner;
end;
{ llvm can't catch symbol references from inline assembler blocks }
if assigned(srsym) then
begin
case srsym.typ of
staticvarsym:
cnodeutils.RegisterUsedAsmSym(current_asmdata.RefAsmSymbol(srsym.mangledname,AT_DATA),tstaticvarsym(srsym).vardef,true);
procsym:
begin
{ if it's a pure assembler routine, the definition of the symbol will also
be in assembler and it can't be removed by the compiler (and if we mark
it as used anyway, clang will get into trouble) }
if not(po_assembler in tprocdef(tprocsym(srsym).ProcdefList[0]).procoptions) then
cnodeutils.RegisterUsedAsmSym(current_asmdata.RefAsmSymbol(tprocdef(tprocsym(srsym).ProcdefList[0]).mangledname,AT_FUNCTION),tprocdef(tprocsym(srsym).ProcdefList[0]),true);
end;
end;
end;
end;