[InstrProfiling] Place __llvm_prf_vnodes and __llvm_prf_names in llvm.used on ELF

`__llvm_prf_vnodes` and `__llvm_prf_names` are used by runtime but not
referenced via relocation in the translation unit.

With `-z start-stop-gc` (LLD 13 (D96914); GNU ld 2.37 https://sourceware.org/bugzilla/show_bug.cgi?id=27451),
the linker does not let `__start_/__stop_` references retain their sections.

Place `__llvm_prf_vnodes` and `__llvm_prf_names` in `llvm.used` to make
them retained by the linker.

This patch changes most existing `UsedVars` cases to `CompilerUsedVars`
to reflect the ideal state - if the binary format properly supports
section based GC (dead stripping), `llvm.compiler.used` should be sufficient.

`__llvm_prf_vnodes` and `__llvm_prf_names` are switched to `UsedVars`
since we want them to be unconditionally retained by both compiler and linker.

Behaviors on COFF/Mach-O are not affected.

Reviewed By: davidxl

Differential Revision: https://reviews.llvm.org/D97649
This commit is contained in:
Fangrui Song 2021-03-03 11:32:24 -08:00
parent 75df61e93d
commit a84f4fc0df
4 changed files with 25 additions and 5 deletions

View File

@ -1,7 +1,7 @@
// REQUIRES: lld-available
/// Test ld with GC.
// RUN: %clang_pgogen -o %t -O3 %S/Inputs/instrprof-value-merge.c -fuse-ld=lld -ffunction-sections -fdata-sections -Wl,--gc-sections
// RUN: %clang_pgogen -o %t -O3 %S/Inputs/instrprof-value-merge.c -fuse-ld=lld -ffunction-sections -fdata-sections -Wl,--gc-sections -z start-stop-gc
// RUN: rm -rf %t.profdir
// RUN: env LLVM_PROFILE_FILE=%t.profdir/default_%m.profraw %run %t
// RUN: env LLVM_PROFILE_FILE=%t.profdir/default_%m.profraw %run %t

View File

@ -57,6 +57,7 @@ private:
}
};
DenseMap<GlobalVariable *, PerFunctionProfileData> ProfileDataMap;
std::vector<GlobalValue *> CompilerUsedVars;
std::vector<GlobalValue *> UsedVars;
std::vector<GlobalVariable *> ReferencedNames;
GlobalVariable *NamesVar;

View File

@ -539,6 +539,7 @@ bool InstrProfiling::run(
NamesVar = nullptr;
NamesSize = 0;
ProfileDataMap.clear();
CompilerUsedVars.clear();
UsedVars.clear();
TT = Triple(M.getTargetTriple());
@ -921,7 +922,7 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfIncrementInst *Inc) {
ProfileDataMap[NamePtr] = PD;
// Mark the data variable as used so that it isn't stripped out.
UsedVars.push_back(Data);
CompilerUsedVars.push_back(Data);
// Now that the linkage set by the FE has been passed to the data and counter
// variables, reset Name variable's linkage and visibility to private so that
// it can be removed later by the compiler.
@ -976,6 +977,8 @@ void InstrProfiling::emitVNodes() {
Constant::getNullValue(VNodesTy), getInstrProfVNodesVarName());
VNodesVar->setSection(
getInstrProfSectionName(IPSK_vnodes, TT.getObjectFormat()));
// VNodesVar is used by runtime but not referenced via relocation by other
// sections. Conservatively make it linker retained.
UsedVars.push_back(VNodesVar);
}
@ -1004,6 +1007,8 @@ void InstrProfiling::emitNameData() {
// linker from inserting padding before the start of the names section or
// between names entries.
NamesVar->setAlignment(Align(1));
// NamesVar is used by runtime but not referenced via relocation by other
// sections. Conservatively make it linker retained.
UsedVars.push_back(NamesVar);
for (auto *NamePtr : ReferencedNames)
@ -1031,6 +1036,9 @@ void InstrProfiling::emitRegistration() {
getInstrProfRegFuncName(), M);
IRBuilder<> IRB(BasicBlock::Create(M->getContext(), "", RegisterF));
for (Value *Data : CompilerUsedVars)
if (!isa<Function>(Data))
IRB.CreateCall(RuntimeRegisterF, IRB.CreateBitCast(Data, VoidPtrTy));
for (Value *Data : UsedVars)
if (Data != NamesVar && !isa<Function>(Data))
IRB.CreateCall(RuntimeRegisterF, IRB.CreateBitCast(Data, VoidPtrTy));
@ -1081,7 +1089,7 @@ bool InstrProfiling::emitRuntimeHook() {
IRB.CreateRet(Load);
// Mark the user variable as used so that it isn't stripped out.
UsedVars.push_back(User);
CompilerUsedVars.push_back(User);
return true;
}
@ -1094,8 +1102,13 @@ void InstrProfiling::emitUses() {
// or discarded as a unit, so llvm.compiler.used is sufficient. Otherwise,
// conservatively make all of them retained by the linker.
if (TT.isOSBinFormatELF())
appendToCompilerUsed(*M, UsedVars);
appendToCompilerUsed(*M, CompilerUsedVars);
else
appendToUsed(*M, CompilerUsedVars);
// We do not add proper references from used metadata sections to NamesVar and
// VNodesVar, so we have to be conservative and place them in llvm.used
// regardless of the target,
appendToUsed(*M, UsedVars);
}

View File

@ -50,6 +50,12 @@ attributes #0 = { nounwind }
; DYN-NOT: @__profvp_foo
; DYN-NOT: @__llvm_prf_vnodes
;; __llvm_prf_vnodes and __llvm_prf_nm are not referenced by other metadata sections.
;; We have to conservatively place them in llvm.used.
; STATIC: @llvm.used = appending global
; STATIC-SAME: @__llvm_prf_vnodes
; STATIC-SAME: @__llvm_prf_nm
; STATIC: call void @__llvm_profile_instrument_target(i64 %3, i8* bitcast ({ i64, i64, i64*, i8*, i8*, i32, [2 x i16] }* @__profd_foo to i8*), i32 0)
; STATIC-EXT: call void @__llvm_profile_instrument_target(i64 %3, i8* bitcast ({ i64, i64, i64*, i8*, i8*, i32, [2 x i16] }* @__profd_foo to i8*), i32 zeroext 0)
; STATIC-SEXT: call void @__llvm_profile_instrument_target(i64 %3, i8* bitcast ({ i64, i64, i64*, i8*, i8*, i32, [2 x i16] }* @__profd_foo to i8*), i32 signext 0)