From a84f4fc0dfcd0c0d249c3071f9bc5de0c56b6cca Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Wed, 3 Mar 2021 11:32:24 -0800 Subject: [PATCH] [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 --- .../profile/Linux/instrprof-value-merge-lld.c | 2 +- .../Instrumentation/InstrProfiling.h | 1 + .../Instrumentation/InstrProfiling.cpp | 21 +++++++++++++++---- .../Instrumentation/InstrProfiling/icall.ll | 6 ++++++ 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/compiler-rt/test/profile/Linux/instrprof-value-merge-lld.c b/compiler-rt/test/profile/Linux/instrprof-value-merge-lld.c index fda6b9722237..af3e92db1e5a 100644 --- a/compiler-rt/test/profile/Linux/instrprof-value-merge-lld.c +++ b/compiler-rt/test/profile/Linux/instrprof-value-merge-lld.c @@ -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 diff --git a/llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h b/llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h index 5242211138f5..94b156f3b137 100644 --- a/llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h +++ b/llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h @@ -57,6 +57,7 @@ private: } }; DenseMap ProfileDataMap; + std::vector CompilerUsedVars; std::vector UsedVars; std::vector ReferencedNames; GlobalVariable *NamesVar; diff --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp index d73bb66ed003..bdb182403041 100644 --- a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp +++ b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -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(Data)) + IRB.CreateCall(RuntimeRegisterF, IRB.CreateBitCast(Data, VoidPtrTy)); for (Value *Data : UsedVars) if (Data != NamesVar && !isa(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,9 +1102,14 @@ 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, UsedVars); + 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); } void InstrProfiling::emitInitialization() { diff --git a/llvm/test/Instrumentation/InstrProfiling/icall.ll b/llvm/test/Instrumentation/InstrProfiling/icall.ll index 311770ae5707..bc7d6c90d0be 100644 --- a/llvm/test/Instrumentation/InstrProfiling/icall.ll +++ b/llvm/test/Instrumentation/InstrProfiling/icall.ll @@ -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)