diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -2345,6 +2345,14 @@ 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 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Driver/ToolChains/Fuchsia.h b/clang/lib/Driver/ToolChains/Fuchsia.h --- a/clang/lib/Driver/ToolChains/Fuchsia.h +++ b/clang/lib/Driver/ToolChains/Fuchsia.h @@ -71,9 +71,6 @@ 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 diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp --- a/clang/lib/Driver/ToolChains/Fuchsia.cpp +++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -437,13 +437,3 @@ } 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); -} diff --git a/clang/test/Driver/fuchsia.c b/clang/test/Driver/fuchsia.c --- a/clang/test/Driver/fuchsia.c +++ b/clang/test/Driver/fuchsia.c @@ -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" diff --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp --- a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp +++ b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -520,6 +520,14 @@ } } +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 @@ 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 @@ emitVNodes(); emitNameData(); + emitRuntimeHook(); emitRegistration(); emitUses(); emitInitialization(); @@ -1109,9 +1121,9 @@ } bool InstrProfiling::emitRuntimeHook() { - // We expect the linker to be invoked with -u 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 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 @@ 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; } diff --git a/llvm/test/Instrumentation/InstrProfiling/profiling.ll b/llvm/test/Instrumentation/InstrProfiling/profiling.ll --- a/llvm/test/Instrumentation/InstrProfiling/profiling.ll +++ b/llvm/test/Instrumentation/InstrProfiling/profiling.ll @@ -54,11 +54,12 @@ 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*))