Index: llvm/include/llvm/ProfileData/InstrProf.h
===================================================================
--- llvm/include/llvm/ProfileData/InstrProf.h
+++ 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);
Index: llvm/lib/ProfileData/InstrProf.cpp
===================================================================
--- llvm/lib/ProfileData/InstrProf.cpp
+++ 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.
Index: llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
===================================================================
--- llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
+++ 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 <algorithm>
 #include <cassert>
 #include <cstdint>
@@ -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<Comdat *, GlobalValue *> 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();
 }
 
Index: llvm/test/Transforms/PGOProfile/Inputs/thinlto_cspgo_bar_gen.ll
===================================================================
--- llvm/test/Transforms/PGOProfile/Inputs/thinlto_cspgo_bar_gen.ll
+++ 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:
Index: llvm/test/Transforms/PGOProfile/lto_cspgo_gen.ll
===================================================================
--- /dev/null
+++ llvm/test/Transforms/PGOProfile/lto_cspgo_gen.ll
@@ -0,0 +1,32 @@
+; REQUIRES: x86-registered-target
+
+; RUN: opt -passes='thinlto-pre-link<O2>' --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}
Index: llvm/test/Transforms/PGOProfile/thinlto_cspgo_gen.ll
===================================================================
--- llvm/test/Transforms/PGOProfile/thinlto_cspgo_gen.ll
+++ 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<O2>' --cs-profilegen-file=alloc -cspgo-kind=cspgo-instr-gen-pipeline -module-summary %s -o %t1.bc
+; RUN: opt -passes='thinlto-pre-link<O2>' --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