Skip to content

Commit

Permalink
[InstrProfiling] Generate runtime hook for Fuchsia
Browse files Browse the repository at this point in the history
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 9a041a7, 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
  • Loading branch information
petrhosek committed Aug 11, 2021
1 parent c0c1c3c commit 389dc94
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 37 deletions.
8 changes: 8 additions & 0 deletions clang/docs/UsersManual.rst
Expand Up @@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
10 changes: 0 additions & 10 deletions clang/lib/Driver/ToolChains/Fuchsia.cpp
Expand Up @@ -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);
}
3 changes: 0 additions & 3 deletions clang/lib/Driver/ToolChains/Fuchsia.h
Expand Up @@ -71,9 +71,6 @@ class LLVM_LIBRARY_VISIBILITY Fuchsia : public ToolChain {
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
Expand Down
2 changes: 0 additions & 2 deletions clang/test/Driver/fuchsia.c
Expand Up @@ -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 \
Expand All @@ -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"
59 changes: 38 additions & 21 deletions llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
Expand Up @@ -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(
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -588,6 +599,7 @@ bool InstrProfiling::run(

emitVNodes();
emitNameData();
emitRuntimeHook();
emitRegistration();
emitUses();
emitInitialization();
Expand Down Expand Up @@ -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.
Expand All @@ -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()));

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);
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);

// Mark the function as used so that it isn't stripped out.
CompilerUsedVars.push_back(User);
}
return true;
}

Expand Down
3 changes: 2 additions & 1 deletion llvm/test/Instrumentation/InstrProfiling/profiling.ll
Expand Up @@ -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*))
Expand Down

0 comments on commit 389dc94

Please sign in to comment.