diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h --- a/llvm/include/llvm/ProfileData/InstrProf.h +++ b/llvm/include/llvm/ProfileData/InstrProf.h @@ -1143,8 +1143,8 @@ // Create a COMDAT variable INSTR_PROF_RAW_VERSION_VAR to make the runtime // aware this is an ir_level profile so it can set the version flag. -void createIRLevelProfileFlagVar(Module &M, bool IsCS, - bool InstrEntryBBEnabled); +GlobalVariable *createIRLevelProfileFlagVar(Module &M, bool IsCS, + bool InstrEntryBBEnabled); // Create the variable for the profile file name. void createProfileFileNameVar(Module &M, StringRef InstrProfileOutput); diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp --- a/llvm/lib/ProfileData/InstrProf.cpp +++ b/llvm/lib/ProfileData/InstrProf.cpp @@ -1098,10 +1098,14 @@ bool isIRPGOFlagSet(const Module *M) { auto IRInstrVar = M->getNamedGlobal(INSTR_PROF_QUOTE(INSTR_PROF_RAW_VERSION_VAR)); - if (!IRInstrVar || IRInstrVar->isDeclaration() || - IRInstrVar->hasLocalLinkage()) + if (!IRInstrVar || IRInstrVar->hasLocalLinkage()) return false; + // For CSPGO+LTO, this variable might be marked as non-prevailing and we only + // have the decl. + if (IRInstrVar->isDeclaration()) + return true; + // Check if the flag is set. if (!IRInstrVar->hasInitializer()) return false; @@ -1137,8 +1141,8 @@ // Create a COMDAT variable INSTR_PROF_RAW_VERSION_VAR to make the runtime // aware this is an ir_level profile so it can set the version flag. -void createIRLevelProfileFlagVar(Module &M, bool IsCS, - bool InstrEntryBBEnabled) { +GlobalVariable *createIRLevelProfileFlagVar(Module &M, bool IsCS, + bool InstrEntryBBEnabled) { const StringRef VarName(INSTR_PROF_QUOTE(INSTR_PROF_RAW_VERSION_VAR)); Type *IntTy64 = Type::getInt64Ty(M.getContext()); uint64_t ProfileVersion = (INSTR_PROF_RAW_VERSION | VARIANT_MASK_IR_PROF); @@ -1155,6 +1159,7 @@ IRLevelVersionVariable->setLinkage(GlobalValue::ExternalLinkage); IRLevelVersionVariable->setComdat(M.getOrInsertComdat(VarName)); } + return IRLevelVersionVariable; } // Create the variable for the profile file name. diff --git a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp --- a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp +++ b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp @@ -110,6 +110,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" #include #include #include @@ -464,7 +465,10 @@ private: bool runOnModule(Module &M) override { createProfileFileNameVar(M, InstrProfileOutput); - createIRLevelProfileFlagVar(M, /* IsCS */ true, PGOInstrumentEntry); + // The variable in a comdat may be discarded by LTO. Ensure the + // declaration will be retained. + appendToCompilerUsed( + M, createIRLevelProfileFlagVar(M, /*IsCS=*/true, PGOInstrumentEntry)); return false; } std::string InstrProfileOutput; @@ -1612,7 +1616,7 @@ // For the context-sensitve instrumentation, we should have a separated pass // (before LTO/ThinLTO linking) to create these variables. if (!IsCS) - createIRLevelProfileFlagVar(M, /* IsCS */ false, PGOInstrumentEntry); + createIRLevelProfileFlagVar(M, /*IsCS=*/false, PGOInstrumentEntry); std::unordered_multimap ComdatMembers; collectComdatMembers(M, ComdatMembers); @@ -1632,7 +1636,10 @@ PreservedAnalyses PGOInstrumentationGenCreateVar::run(Module &M, ModuleAnalysisManager &AM) { createProfileFileNameVar(M, CSInstrName); - createIRLevelProfileFlagVar(M, /* IsCS */ true, PGOInstrumentEntry); + // The variable in a comdat may be discarded by LTO. Ensure the declaration + // will be retained. + appendToCompilerUsed( + M, createIRLevelProfileFlagVar(M, /*IsCS=*/true, PGOInstrumentEntry)); return PreservedAnalyses::all(); } diff --git a/llvm/test/Transforms/PGOProfile/Inputs/thinlto_cspgo_bar_gen.ll b/llvm/test/Transforms/PGOProfile/Inputs/thinlto_cspgo_bar_gen.ll --- a/llvm/test/Transforms/PGOProfile/Inputs/thinlto_cspgo_bar_gen.ll +++ b/llvm/test/Transforms/PGOProfile/Inputs/thinlto_cspgo_bar_gen.ll @@ -1,13 +1,8 @@ target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" -$__llvm_profile_filename = comdat any -$__llvm_profile_raw_version = comdat any - @odd = common dso_local global i32 0, align 4 @even = common dso_local global i32 0, align 4 -@__llvm_profile_filename = constant [25 x i8] c"pass2/default_%m.profraw\00", comdat -@__llvm_profile_raw_version = constant i64 216172782113783812, comdat define dso_local void @bar(i32 %n) !prof !29 { entry: diff --git a/llvm/test/Transforms/PGOProfile/lto_cspgo_gen.ll b/llvm/test/Transforms/PGOProfile/lto_cspgo_gen.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/PGOProfile/lto_cspgo_gen.ll @@ -0,0 +1,32 @@ +; REQUIRES: x86-registered-target + +; RUN: opt -passes='thinlto-pre-link' --cs-profilegen-file=alloc -cspgo-kind=cspgo-instr-gen-pipeline -module-summary %s -o %t.bc +; RUN: llvm-dis %t.bc -o - | FileCheck %s --check-prefix=IRPGOPRE + +;; Symbol __llvm_profile_filename and __llvm_profile_raw_version are non-prevailing here. +; RUN: llvm-lto2 run -lto-cspgo-profile-file=alloc -lto-cspgo-gen -save-temps -o %t %t.bc \ +; RUN: -r=%t.bc,f,px \ +; RUN: -r=%t.bc,__llvm_profile_filename,x \ +; RUN: -r=%t.bc,__llvm_profile_raw_version,x +; RUN: llvm-dis %t.0.0.preopt.bc -o - | FileCheck %s --check-prefix=IRPGOBE + +;; Before LTO, we should have the __llvm_profile_raw_version definition. +; IRPGOPRE: @__llvm_profile_raw_version = constant i64 + +;; Non-prevailing __llvm_profile_raw_version is discarded by LTO. Ensure the +;; declaration is retained. +; IRPGOBE: @__llvm_profile_raw_version = external constant i64 + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +$f = comdat any + +; Function Attrs: nofree norecurse nosync nounwind readnone uwtable willreturn mustprogress +define i32 @f() { +entry: + ret i32 1 +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"ThinLTO", i32 0} diff --git a/llvm/test/Transforms/PGOProfile/thinlto_cspgo_gen.ll b/llvm/test/Transforms/PGOProfile/thinlto_cspgo_gen.ll --- a/llvm/test/Transforms/PGOProfile/thinlto_cspgo_gen.ll +++ b/llvm/test/Transforms/PGOProfile/thinlto_cspgo_gen.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86-registered-target -; RUN: opt -module-summary %s -o %t1.bc -; RUN: opt -module-summary %S/Inputs/thinlto_cspgo_bar_gen.ll -o %t2.bc +; RUN: opt -passes='thinlto-pre-link' --cs-profilegen-file=alloc -cspgo-kind=cspgo-instr-gen-pipeline -module-summary %s -o %t1.bc +; RUN: opt -passes='thinlto-pre-link' --cs-profilegen-file=alloc -cspgo-kind=cspgo-instr-gen-pipeline -module-summary %S/Inputs/thinlto_cspgo_bar_gen.ll -o %t2.bc ; RUN: llvm-lto2 run -lto-cspgo-profile-file=alloc -lto-cspgo-gen -save-temps -o %t %t1.bc %t2.bc \ ; RUN: -r=%t1.bc,foo,pl \ ; RUN: -r=%t1.bc,bar,l \ @@ -13,8 +13,15 @@ ; RUN: -r=%t2.bc,even,pl \ ; RUN: -r=%t2.bc,__llvm_profile_filename,x \ ; RUN: -r=%t2.bc,__llvm_profile_raw_version,x -; RUN: llvm-dis %t.1.4.opt.bc -o - | FileCheck %s --check-prefix=CSGEN +; RUN: llvm-dis %t.1.4.opt.bc -o - | FileCheck %s --check-prefixes=CSGEN,PREVAILING +; RUN: llvm-dis %t.2.4.opt.bc -o - | FileCheck %s --check-prefixes=CSGEN,NOPREVAILING +;; Prevailing __llvm_profile_raw_version is kept by LTO. +; PREVAILING: @__llvm_profile_raw_version = constant i64 + +;; Non-prevailing __llvm_profile_raw_version is discarded by LTO. Ensure the +;; declaration is retained. +; NOPREVAILING: @__llvm_profile_raw_version = external constant i64 ; CSGEN: @__profc_ ; CSGEN: @__profd_ @@ -22,11 +29,6 @@ target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" -$__llvm_profile_filename = comdat any -$__llvm_profile_raw_version = comdat any -@__llvm_profile_filename = constant [25 x i8] c"pass2/default_%m.profraw\00", comdat -@__llvm_profile_raw_version = constant i64 216172782113783812, comdat - define dso_local void @foo() #0 !prof !29 { entry: br label %for.body