Skip to content

Commit 389dc94

Browse files
committed
[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 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
1 parent c0c1c3c commit 389dc94

File tree

6 files changed

+48
-37
lines changed

6 files changed

+48
-37
lines changed

clang/docs/UsersManual.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2345,6 +2345,14 @@ In these cases, you can use the flag ``-fno-profile-instr-generate`` (or
23452345
Note that these flags should appear after the corresponding profile
23462346
flags to have an effect.
23472347

2348+
.. note::
2349+
2350+
When none of the translation units inside a binary is instrumented, in the
2351+
case of Fuchsia the profile runtime will not be linked into the binary and
2352+
no profile will be produced, while on other platforms the profile runtime
2353+
will be linked and profile will be produced but there will not be any
2354+
counters.
2355+
23482356
Instrumenting only selected files or functions
23492357
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23502358

clang/lib/Driver/ToolChains/Fuchsia.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -437,13 +437,3 @@ SanitizerMask Fuchsia::getDefaultSanitizers() const {
437437
}
438438
return Res;
439439
}
440-
441-
void Fuchsia::addProfileRTLibs(const llvm::opt::ArgList &Args,
442-
llvm::opt::ArgStringList &CmdArgs) const {
443-
// Add linker option -u__llvm_profile_runtime to cause runtime
444-
// initialization module to be linked in.
445-
if (needsProfileRT(Args))
446-
CmdArgs.push_back(Args.MakeArgString(
447-
Twine("-u", llvm::getInstrProfRuntimeHookVarName())));
448-
ToolChain::addProfileRTLibs(Args, CmdArgs);
449-
}

clang/lib/Driver/ToolChains/Fuchsia.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,6 @@ class LLVM_LIBRARY_VISIBILITY Fuchsia : public ToolChain {
7171
SanitizerMask getSupportedSanitizers() const override;
7272
SanitizerMask getDefaultSanitizers() const override;
7373

74-
void addProfileRTLibs(const llvm::opt::ArgList &Args,
75-
llvm::opt::ArgStringList &CmdArgs) const override;
76-
7774
RuntimeLibType
7875
GetRuntimeLibType(const llvm::opt::ArgList &Args) const override;
7976
CXXStdlibType

clang/test/Driver/fuchsia.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,6 @@
249249
// RUN: -fuse-ld=lld 2>&1 \
250250
// RUN: | FileCheck %s -check-prefix=CHECK-PROFRT-AARCH64
251251
// CHECK-PROFRT-AARCH64: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]"
252-
// CHECK-PROFRT-AARCH64: "-u__llvm_profile_runtime"
253252
// CHECK-PROFRT-AARCH64: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aarch64-unknown-fuchsia{{/|\\\\}}libclang_rt.profile.a"
254253

255254
// RUN: %clang %s -### --target=x86_64-unknown-fuchsia \
@@ -258,5 +257,4 @@
258257
// RUN: -fuse-ld=lld 2>&1 \
259258
// RUN: | FileCheck %s -check-prefix=CHECK-PROFRT-X86_64
260259
// CHECK-PROFRT-X86_64: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]"
261-
// CHECK-PROFRT-X86_64: "-u__llvm_profile_runtime"
262260
// CHECK-PROFRT-X86_64: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}x86_64-unknown-fuchsia{{/|\\\\}}libclang_rt.profile.a"

llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,14 @@ void InstrProfiling::promoteCounterLoadStores(Function *F) {
520520
}
521521
}
522522

523+
static bool needsRuntimeHookUnconditionally(const Triple &TT) {
524+
// On Fuchsia, we only need runtime hook if any counters are present.
525+
if (TT.isOSFuchsia())
526+
return false;
527+
528+
return true;
529+
}
530+
523531
/// Check if the module contains uses of any profiling intrinsics.
524532
static bool containsProfilingIntrinsics(Module &M) {
525533
if (auto *F = M.getFunction(
@@ -548,8 +556,11 @@ bool InstrProfiling::run(
548556
UsedVars.clear();
549557
TT = Triple(M.getTargetTriple());
550558

559+
bool MadeChange;
560+
551561
// Emit the runtime hook even if no counters are present.
552-
bool MadeChange = emitRuntimeHook();
562+
if (needsRuntimeHookUnconditionally(TT))
563+
MadeChange = emitRuntimeHook();
553564

554565
// Improve compile time by avoiding linear scans when there is no work.
555566
GlobalVariable *CoverageNamesVar =
@@ -588,6 +599,7 @@ bool InstrProfiling::run(
588599

589600
emitVNodes();
590601
emitNameData();
602+
emitRuntimeHook();
591603
emitRegistration();
592604
emitUses();
593605
emitInitialization();
@@ -1109,9 +1121,9 @@ void InstrProfiling::emitRegistration() {
11091121
}
11101122

11111123
bool InstrProfiling::emitRuntimeHook() {
1112-
// We expect the linker to be invoked with -u<hook_var> flag for Linux or
1113-
// Fuchsia, in which case there is no need to emit the user function.
1114-
if (TT.isOSLinux() || TT.isOSFuchsia())
1124+
// We expect the linker to be invoked with -u<hook_var> flag for Linux
1125+
// in which case there is no need to emit the external variable.
1126+
if (TT.isOSLinux())
11151127
return false;
11161128

11171129
// If the module's provided its own runtime, we don't need to do anything.
@@ -1124,23 +1136,28 @@ bool InstrProfiling::emitRuntimeHook() {
11241136
new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage,
11251137
nullptr, getInstrProfRuntimeHookVarName());
11261138

1127-
// Make a function that uses it.
1128-
auto *User = Function::Create(FunctionType::get(Int32Ty, false),
1129-
GlobalValue::LinkOnceODRLinkage,
1130-
getInstrProfRuntimeHookVarUseFuncName(), M);
1131-
User->addFnAttr(Attribute::NoInline);
1132-
if (Options.NoRedZone)
1133-
User->addFnAttr(Attribute::NoRedZone);
1134-
User->setVisibility(GlobalValue::HiddenVisibility);
1135-
if (TT.supportsCOMDAT())
1136-
User->setComdat(M->getOrInsertComdat(User->getName()));
1137-
1138-
IRBuilder<> IRB(BasicBlock::Create(M->getContext(), "", User));
1139-
auto *Load = IRB.CreateLoad(Int32Ty, Var);
1140-
IRB.CreateRet(Load);
1141-
1142-
// Mark the user variable as used so that it isn't stripped out.
1143-
CompilerUsedVars.push_back(User);
1139+
if (TT.isOSBinFormatELF()) {
1140+
// Mark the user variable as used so that it isn't stripped out.
1141+
CompilerUsedVars.push_back(Var);
1142+
} else {
1143+
// Make a function that uses it.
1144+
auto *User = Function::Create(FunctionType::get(Int32Ty, false),
1145+
GlobalValue::LinkOnceODRLinkage,
1146+
getInstrProfRuntimeHookVarUseFuncName(), M);
1147+
User->addFnAttr(Attribute::NoInline);
1148+
if (Options.NoRedZone)
1149+
User->addFnAttr(Attribute::NoRedZone);
1150+
User->setVisibility(GlobalValue::HiddenVisibility);
1151+
if (TT.supportsCOMDAT())
1152+
User->setComdat(M->getOrInsertComdat(User->getName()));
1153+
1154+
IRBuilder<> IRB(BasicBlock::Create(M->getContext(), "", User));
1155+
auto *Load = IRB.CreateLoad(Int32Ty, Var);
1156+
IRB.CreateRet(Load);
1157+
1158+
// Mark the function as used so that it isn't stripped out.
1159+
CompilerUsedVars.push_back(User);
1160+
}
11441161
return true;
11451162
}
11461163

llvm/test/Instrumentation/InstrProfiling/profiling.ll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,12 @@ define void @baz() {
5454

5555
declare void @llvm.instrprof.increment(i8*, i64, i32, i32)
5656

57-
; ELF: @llvm.compiler.used = appending global {{.*}} @__llvm_profile_runtime_user {{.*}} @__profd_foo {{.*}} @__profd_bar {{.*}} @__profd_baz
57+
; ELF: @llvm.compiler.used = appending global {{.*}} @__llvm_profile_runtime {{.*}} @__profd_foo {{.*}} @__profd_bar {{.*}} @__profd_baz
5858
; MACHO: @llvm.used = appending global {{.*}} @__llvm_profile_runtime_user {{.*}} @__profd_foo {{.*}} @__profd_bar {{.*}} @__profd_baz
5959
; WIN: @llvm.compiler.used = appending global {{.*}} @__llvm_profile_runtime_user {{.*}} @__profd_foo {{.*}} @__profd_bar {{.*}} @__profd_baz
6060

6161
; ELF_GENERIC: define internal void @__llvm_profile_register_functions() unnamed_addr {
62+
; ELF_GENERIC-NEXT: call void @__llvm_profile_register_function(i8* bitcast (i32* @__llvm_profile_runtime to i8*))
6263
; ELF_GENERIC-NEXT: call void @__llvm_profile_register_function(i8* bitcast ({ i64, i64, i64, i8*, i8*, i32, [2 x i16] }* @__profd_foo to i8*))
6364
; ELF_GENERIC-NEXT: call void @__llvm_profile_register_function(i8* bitcast ({ i64, i64, i64, i8*, i8*, i32, [2 x i16] }* @__profd_bar to i8*))
6465
; ELF_GENERIC-NEXT: call void @__llvm_profile_register_function(i8* bitcast ({ i64, i64, i64, i8*, i8*, i32, [2 x i16] }* @__profd_baz to i8*))

0 commit comments

Comments
 (0)