[InstrProfiling] Generate runtime hook for Fuchsia
When none of the translation units in the binary have been instrumented
we shouldn't need to link the profile runtime. However, because we pass
-u__llvm_profile_runtime on Linux and Fuchsia, the runtime would still
be pulled in and incur some overhead. On Fuchsia which uses runtime
counter relocation, it also means that we cannot reference the bias
variable unconditionally.
This change modifies the InstrProfiling pass to pull in the profile
runtime only when needed by declaring the __llvm_profile_runtime symbol
in the translation unit only when needed. For now we restrict this only
for Fuchsia, but this can be later expanded to other platforms. This
approach was already used prior to 9a041a7522, but we changed it
to always generate the __llvm_profile_runtime due to a TAPI limitation,
but that limitation may no longer apply, and it certainly doesn't apply
on platforms like Fuchsia.
Differential Revision: https://reviews.llvm.org/D98061
This commit is contained in:
@@ -2345,6 +2345,14 @@ In these cases, you can use the flag ``-fno-profile-instr-generate`` (or
|
||||
Note that these flags should appear after the corresponding profile
|
||||
flags to have an effect.
|
||||
|
||||
.. note::
|
||||
|
||||
When none of the translation units inside a binary is instrumented, in the
|
||||
case of Fuchsia the profile runtime will not be linked into the binary and
|
||||
no profile will be produced, while on other platforms the profile runtime
|
||||
will be linked and profile will be produced but there will not be any
|
||||
counters.
|
||||
|
||||
Instrumenting only selected files or functions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@@ -437,13 +437,3 @@ SanitizerMask Fuchsia::getDefaultSanitizers() const {
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
|
||||
void Fuchsia::addProfileRTLibs(const llvm::opt::ArgList &Args,
|
||||
llvm::opt::ArgStringList &CmdArgs) const {
|
||||
// Add linker option -u__llvm_profile_runtime to cause runtime
|
||||
// initialization module to be linked in.
|
||||
if (needsProfileRT(Args))
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
Twine("-u", llvm::getInstrProfRuntimeHookVarName())));
|
||||
ToolChain::addProfileRTLibs(Args, CmdArgs);
|
||||
}
|
||||
|
||||
@@ -71,9 +71,6 @@ public:
|
||||
SanitizerMask getSupportedSanitizers() const override;
|
||||
SanitizerMask getDefaultSanitizers() const override;
|
||||
|
||||
void addProfileRTLibs(const llvm::opt::ArgList &Args,
|
||||
llvm::opt::ArgStringList &CmdArgs) const override;
|
||||
|
||||
RuntimeLibType
|
||||
GetRuntimeLibType(const llvm::opt::ArgList &Args) const override;
|
||||
CXXStdlibType
|
||||
|
||||
@@ -249,7 +249,6 @@
|
||||
// RUN: -fuse-ld=lld 2>&1 \
|
||||
// RUN: | FileCheck %s -check-prefix=CHECK-PROFRT-AARCH64
|
||||
// CHECK-PROFRT-AARCH64: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]"
|
||||
// CHECK-PROFRT-AARCH64: "-u__llvm_profile_runtime"
|
||||
// CHECK-PROFRT-AARCH64: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aarch64-unknown-fuchsia{{/|\\\\}}libclang_rt.profile.a"
|
||||
|
||||
// RUN: %clang %s -### --target=x86_64-unknown-fuchsia \
|
||||
@@ -258,5 +257,4 @@
|
||||
// RUN: -fuse-ld=lld 2>&1 \
|
||||
// RUN: | FileCheck %s -check-prefix=CHECK-PROFRT-X86_64
|
||||
// CHECK-PROFRT-X86_64: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]"
|
||||
// CHECK-PROFRT-X86_64: "-u__llvm_profile_runtime"
|
||||
// CHECK-PROFRT-X86_64: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}x86_64-unknown-fuchsia{{/|\\\\}}libclang_rt.profile.a"
|
||||
|
||||
@@ -520,6 +520,14 @@ void InstrProfiling::promoteCounterLoadStores(Function *F) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool needsRuntimeHookUnconditionally(const Triple &TT) {
|
||||
// On Fuchsia, we only need runtime hook if any counters are present.
|
||||
if (TT.isOSFuchsia())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Check if the module contains uses of any profiling intrinsics.
|
||||
static bool containsProfilingIntrinsics(Module &M) {
|
||||
if (auto *F = M.getFunction(
|
||||
@@ -548,8 +556,11 @@ bool InstrProfiling::run(
|
||||
UsedVars.clear();
|
||||
TT = Triple(M.getTargetTriple());
|
||||
|
||||
bool MadeChange;
|
||||
|
||||
// Emit the runtime hook even if no counters are present.
|
||||
bool MadeChange = emitRuntimeHook();
|
||||
if (needsRuntimeHookUnconditionally(TT))
|
||||
MadeChange = emitRuntimeHook();
|
||||
|
||||
// Improve compile time by avoiding linear scans when there is no work.
|
||||
GlobalVariable *CoverageNamesVar =
|
||||
@@ -588,6 +599,7 @@ bool InstrProfiling::run(
|
||||
|
||||
emitVNodes();
|
||||
emitNameData();
|
||||
emitRuntimeHook();
|
||||
emitRegistration();
|
||||
emitUses();
|
||||
emitInitialization();
|
||||
@@ -1109,9 +1121,9 @@ void InstrProfiling::emitRegistration() {
|
||||
}
|
||||
|
||||
bool InstrProfiling::emitRuntimeHook() {
|
||||
// We expect the linker to be invoked with -u<hook_var> flag for Linux or
|
||||
// Fuchsia, in which case there is no need to emit the user function.
|
||||
if (TT.isOSLinux() || TT.isOSFuchsia())
|
||||
// We expect the linker to be invoked with -u<hook_var> flag for Linux
|
||||
// in which case there is no need to emit the external variable.
|
||||
if (TT.isOSLinux())
|
||||
return false;
|
||||
|
||||
// If the module's provided its own runtime, we don't need to do anything.
|
||||
@@ -1124,23 +1136,28 @@ bool InstrProfiling::emitRuntimeHook() {
|
||||
new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage,
|
||||
nullptr, getInstrProfRuntimeHookVarName());
|
||||
|
||||
// Make a function that uses it.
|
||||
auto *User = Function::Create(FunctionType::get(Int32Ty, false),
|
||||
GlobalValue::LinkOnceODRLinkage,
|
||||
getInstrProfRuntimeHookVarUseFuncName(), M);
|
||||
User->addFnAttr(Attribute::NoInline);
|
||||
if (Options.NoRedZone)
|
||||
User->addFnAttr(Attribute::NoRedZone);
|
||||
User->setVisibility(GlobalValue::HiddenVisibility);
|
||||
if (TT.supportsCOMDAT())
|
||||
User->setComdat(M->getOrInsertComdat(User->getName()));
|
||||
if (TT.isOSBinFormatELF()) {
|
||||
// Mark the user variable as used so that it isn't stripped out.
|
||||
CompilerUsedVars.push_back(Var);
|
||||
} else {
|
||||
// Make a function that uses it.
|
||||
auto *User = Function::Create(FunctionType::get(Int32Ty, false),
|
||||
GlobalValue::LinkOnceODRLinkage,
|
||||
getInstrProfRuntimeHookVarUseFuncName(), M);
|
||||
User->addFnAttr(Attribute::NoInline);
|
||||
if (Options.NoRedZone)
|
||||
User->addFnAttr(Attribute::NoRedZone);
|
||||
User->setVisibility(GlobalValue::HiddenVisibility);
|
||||
if (TT.supportsCOMDAT())
|
||||
User->setComdat(M->getOrInsertComdat(User->getName()));
|
||||
|
||||
IRBuilder<> IRB(BasicBlock::Create(M->getContext(), "", User));
|
||||
auto *Load = IRB.CreateLoad(Int32Ty, Var);
|
||||
IRB.CreateRet(Load);
|
||||
IRBuilder<> IRB(BasicBlock::Create(M->getContext(), "", User));
|
||||
auto *Load = IRB.CreateLoad(Int32Ty, Var);
|
||||
IRB.CreateRet(Load);
|
||||
|
||||
// Mark the user variable as used so that it isn't stripped out.
|
||||
CompilerUsedVars.push_back(User);
|
||||
// Mark the function as used so that it isn't stripped out.
|
||||
CompilerUsedVars.push_back(User);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,11 +54,12 @@ define void @baz() {
|
||||
|
||||
declare void @llvm.instrprof.increment(i8*, i64, i32, i32)
|
||||
|
||||
; ELF: @llvm.compiler.used = appending global {{.*}} @__llvm_profile_runtime_user {{.*}} @__profd_foo {{.*}} @__profd_bar {{.*}} @__profd_baz
|
||||
; ELF: @llvm.compiler.used = appending global {{.*}} @__llvm_profile_runtime {{.*}} @__profd_foo {{.*}} @__profd_bar {{.*}} @__profd_baz
|
||||
; MACHO: @llvm.used = appending global {{.*}} @__llvm_profile_runtime_user {{.*}} @__profd_foo {{.*}} @__profd_bar {{.*}} @__profd_baz
|
||||
; WIN: @llvm.compiler.used = appending global {{.*}} @__llvm_profile_runtime_user {{.*}} @__profd_foo {{.*}} @__profd_bar {{.*}} @__profd_baz
|
||||
|
||||
; ELF_GENERIC: define internal void @__llvm_profile_register_functions() unnamed_addr {
|
||||
; ELF_GENERIC-NEXT: call void @__llvm_profile_register_function(i8* bitcast (i32* @__llvm_profile_runtime to i8*))
|
||||
; ELF_GENERIC-NEXT: call void @__llvm_profile_register_function(i8* bitcast ({ i64, i64, i64, i8*, i8*, i32, [2 x i16] }* @__profd_foo to i8*))
|
||||
; ELF_GENERIC-NEXT: call void @__llvm_profile_register_function(i8* bitcast ({ i64, i64, i64, i8*, i8*, i32, [2 x i16] }* @__profd_bar to i8*))
|
||||
; ELF_GENERIC-NEXT: call void @__llvm_profile_register_function(i8* bitcast ({ i64, i64, i64, i8*, i8*, i32, [2 x i16] }* @__profd_baz to i8*))
|
||||
|
||||
Reference in New Issue
Block a user