From 68ce5dc91faba57d7440bd413449037847cb923c Mon Sep 17 00:00:00 2001 From: Jonas Maebe Date: Sat, 1 Dec 2018 20:30:27 +0000 Subject: [PATCH] * 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 - --- compiler/fmodule.pas | 12 ++--- compiler/llvm/nllvmtcon.pas | 7 +-- compiler/llvm/nllvmutil.pas | 88 +++++++++++++++++++++++++++++++++---- compiler/ngenutil.pas | 15 ++++++- compiler/rautils.pas | 18 +++++++- 5 files changed, 120 insertions(+), 20 deletions(-) diff --git a/compiler/fmodule.pas b/compiler/fmodule.pas index c2dce8b017..7f4b5ed252 100644 --- a/compiler/fmodule.pas +++ b/compiler/fmodule.pas @@ -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; diff --git a/compiler/llvm/nllvmtcon.pas b/compiler/llvm/nllvmtcon.pas index 8e5da19af4..f6fa7787e8 100644 --- a/compiler/llvm/nllvmtcon.pas +++ b/compiler/llvm/nllvmtcon.pas @@ -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; diff --git a/compiler/llvm/nllvmutil.pas b/compiler/llvm/nllvmutil.pas index 3b45f194c6..286d4a6be1 100644 --- a/compiler/llvm/nllvmutil.pas +++ b/compiler/llvm/nllvmutil.pas @@ -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. diff --git a/compiler/ngenutil.pas b/compiler/ngenutil.pas index 368f7f03d6..45986af309 100644 --- a/compiler/ngenutil.pas +++ b/compiler/ngenutil.pas @@ -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; diff --git a/compiler/rautils.pas b/compiler/rautils.pas index 33a63c2f3d..5a57406d13 100644 --- a/compiler/rautils.pas +++ b/compiler/rautils.pas @@ -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;