From: Duncan P. N. Exon Smith Date: Fri, 28 Mar 2014 17:53:22 +0000 (+0000) Subject: InstrProf: Emit runtime hook directly in IRGen X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=97140c9270fdadc8af2c6e0a8ff06f090ec7eaa7;p=clang InstrProf: Emit runtime hook directly in IRGen -u behaviour is apparently not portable between linkers (see cfe-commits discussions for r204379 and r205012). I've moved the logic to IRGen, where it should have been in the first place. I don't have a Linux system to test this on, so it's possible this logic *still* doesn't pull in the instrumented profiling runtime on Linux. I'm in the process of getting tests going on the compiler-rt side (llvm-commits "[PATCH] InstrProf: Add initial compiler-rt test"). Once we have tests for the full flow there, the runtime logic should get a whole lot less brittle. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@205023 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CodeGenPGO.cpp b/lib/CodeGen/CodeGenPGO.cpp index 7b45650572..ef490ff679 100644 --- a/lib/CodeGen/CodeGenPGO.cpp +++ b/lib/CodeGen/CodeGenPGO.cpp @@ -814,6 +814,35 @@ namespace { }; } +static void emitRuntimeHook(CodeGenModule &CGM) { + constexpr const char *RuntimeVarName = "__llvm_profile_runtime"; + constexpr const char *RuntimeUserName = "__llvm_profile_runtime_user"; + if (CGM.getModule().getGlobalVariable(RuntimeVarName)) + return; + + // Declare the runtime hook. + llvm::LLVMContext &Ctx = CGM.getLLVMContext(); + auto *Int32Ty = llvm::Type::getInt32Ty(Ctx); + auto *Var = new llvm::GlobalVariable(CGM.getModule(), Int32Ty, false, + llvm::GlobalValue::ExternalLinkage, + nullptr, RuntimeVarName); + + // Make a function that uses it. + auto *User = llvm::Function::Create(llvm::FunctionType::get(Int32Ty, false), + llvm::GlobalValue::LinkOnceODRLinkage, + RuntimeUserName, &CGM.getModule()); + User->addFnAttr(llvm::Attribute::NoInline); + if (CGM.getCodeGenOpts().DisableRedZone) + User->addFnAttr(llvm::Attribute::NoRedZone); + CGBuilderTy Builder(llvm::BasicBlock::Create(CGM.getLLVMContext(), "", User)); + auto *Load = Builder.CreateLoad(Var); + Builder.CreateRet(Load); + + // Create a use of the function. Now the definition of the runtime variable + // should get pulled in, along with any static initializears. + CGM.addUsedGlobal(User); +} + void CodeGenPGO::assignRegionCounters(const Decl *D, llvm::Function *Fn) { bool InstrumentRegions = CGM.getCodeGenOpts().ProfileInstrGenerate; PGOProfileData *PGOData = CGM.getPGOData(); @@ -839,8 +868,10 @@ void CodeGenPGO::assignRegionCounters(const Decl *D, llvm::Function *Fn) { } mapRegionCounters(D); - if (InstrumentRegions) + if (InstrumentRegions) { + emitRuntimeHook(CGM); emitCounterVariables(); + } if (PGOData) { loadRegionCounts(PGOData); computeRegionCounts(D); diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index b348d6c24d..4bb8332ea7 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -325,13 +325,6 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, Args.hasArg(options::OPT_fprofile_instr_generate) || Args.hasArg(options::OPT_fcreate_profile) || Args.hasArg(options::OPT_coverage)) { - // Pull in runtime for -fprofile-inst-generate. This is required since - // there are no calls to the runtime in the code. - if (Args.hasArg(options::OPT_fprofile_instr_generate)) { - CmdArgs.push_back("-u"); - CmdArgs.push_back("___llvm_profile_runtime"); - } - // Select the appropriate runtime library for the target. if (isTargetIOSBased()) AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_ios.a"); diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 2141cc9656..9a31eb9f9d 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -1817,13 +1817,6 @@ static void addProfileRT( Args.hasArg(options::OPT_coverage))) return; - // Pull in runtime for -fprofile-inst-generate. This is required since there - // are no calls to the runtime in the code. - if (Args.hasArg(options::OPT_fprofile_instr_generate)) { - CmdArgs.push_back("-u"); - CmdArgs.push_back("___llvm_profile_runtime"); - } - SmallString<128> LibProfile = getCompilerRTLibDir(TC); llvm::sys::path::append(LibProfile, Twine("libclang_rt.profile-") + getArchNameForCompilerRTLib(TC) + ".a"); diff --git a/test/Profile/c-linkage.c b/test/Profile/c-linkage.c index a688197d49..72eae1f0f3 100644 --- a/test/Profile/c-linkage.c +++ b/test/Profile/c-linkage.c @@ -1,6 +1,7 @@ // Check the data structures emitted by instrumentation. // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-linkage.c %s -o - -emit-llvm -fprofile-instr-generate | FileCheck %s +// CHECK: @__llvm_profile_runtime = external global i32 // CHECK: @__llvm_profile_counters_foo = global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 // CHECK: @__llvm_profile_name_foo = constant [3 x i8] c"foo", section "__DATA,__llvm_prf_names", align 1 // CHECK: @__llvm_profile_data_foo = constant { i32, i32, i64, i8*, i64* } { i32 3, i32 1, i64 1, i8* getelementptr inbounds ([3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_foo, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8 @@ -28,4 +29,9 @@ int main(void) { // CHECK: @__llvm_profile_data_foo_internal = internal constant { i32, i32, i64, i8*, i64* } { i32 24, i32 3, i64 3, i8* getelementptr inbounds ([24 x i8]* @__llvm_profile_name_foo_internal, i32 0, i32 0), i64* getelementptr inbounds ([3 x i64]* @__llvm_profile_counters_foo_internal, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8 static void foo_internal(void) { if (0){} if (0){} } -// CHECK: @llvm.used = appending global [4 x i8*] [i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo_weak to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_main to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo_internal to i8*)], section "llvm.metadata" +// CHECK: @llvm.used = appending global [5 x i8*] [i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo_weak to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_main to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo_internal to i8*)], section "llvm.metadata" + +// CHECK: define linkonce_odr i32 @__llvm_profile_runtime_user() {{.*}} { +// CHECK: %[[REG:.*]] = load i32* @__llvm_profile_runtime +// CHECK: ret i32 %[[REG]] +// CHECK: } diff --git a/test/Profile/cxx-linkage.cpp b/test/Profile/cxx-linkage.cpp index 16f84a68b0..44c1983c84 100644 --- a/test/Profile/cxx-linkage.cpp +++ b/test/Profile/cxx-linkage.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9.0 -emit-llvm -main-file-name cxx-linkage.cpp %s -o - -fprofile-instr-generate | FileCheck %s +// CHECK: @__llvm_profile_runtime = external global i32 // CHECK: @__llvm_profile_counters__Z3foov = global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 // CHECK: @__llvm_profile_name__Z3foov = constant [7 x i8] c"_Z3foov", section "__DATA,__llvm_prf_names", align 1 // CHECK: @__llvm_profile_data__Z3foov = constant { i32, i32, i64, i8*, i64* } { i32 7, i32 1, i64 1, i8* getelementptr inbounds ([7 x i8]* @__llvm_profile_name__Z3foov, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters__Z3foov, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8 @@ -27,4 +28,9 @@ int main(void) { // CHECK: @__llvm_profile_data__Z10foo_inlinev = linkonce_odr constant { i32, i32, i64, i8*, i64* } { i32 15, i32 7, i64 7, i8* getelementptr inbounds ([15 x i8]* @__llvm_profile_name__Z10foo_inlinev, i32 0, i32 0), i64* getelementptr inbounds ([7 x i64]* @__llvm_profile_counters__Z10foo_inlinev, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8 inline void foo_inline(void) { if (0){} if (0){} if (0){} if (0){} if (0){} if (0){}} -// CHECK: @llvm.used = appending global [4 x i8*] [i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z3foov to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z8foo_weakv to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_main to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z10foo_inlinev to i8*)], section "llvm.metadata" +// CHECK: @llvm.used = appending global [5 x i8*] [i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z3foov to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z8foo_weakv to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_main to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z10foo_inlinev to i8*)], section "llvm.metadata" + +// CHECK: define linkonce_odr i32 @__llvm_profile_runtime_user() {{.*}} { +// CHECK: %[[REG:.*]] = load i32* @__llvm_profile_runtime +// CHECK: ret i32 %[[REG]] +// CHECK: }