[llvm] [CodeGen] Preserve branch weights from PGO profile during instruction selection at -O0 (PR #161620)

Grigory Pastukhov via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 9 10:34:22 PDT 2025


https://github.com/grigorypas updated https://github.com/llvm/llvm-project/pull/161620

>From c55f594bdb1c22cb1cc6e9214b5a62f5d9426402 Mon Sep 17 00:00:00 2001
From: Grigory Pastukhov <gpastukhov at meta.com>
Date: Wed, 1 Oct 2025 15:39:11 -0700
Subject: [PATCH 1/7] Calculate edge weights in MIR if PGO is available in O0

---
 .../CodeGen/SelectionDAG/SelectionDAGISel.cpp | 15 +++---
 llvm/test/CodeGen/AArch64/O0-pipeline.ll      |  6 +++
 llvm/test/CodeGen/AMDGPU/llc-pipeline.ll      |  5 ++
 llvm/test/CodeGen/LoongArch/O0-pipeline.ll    |  6 +++
 llvm/test/CodeGen/PowerPC/O0-pipeline.ll      |  6 +++
 llvm/test/CodeGen/RISCV/O0-pipeline.ll        |  6 +++
 llvm/test/CodeGen/X86/O0-pipeline.ll          |  6 +++
 llvm/test/CodeGen/X86/pgo-profile-o0.ll       | 49 +++++++++++++++++++
 8 files changed, 91 insertions(+), 8 deletions(-)
 create mode 100644 llvm/test/CodeGen/X86/pgo-profile-o0.ll

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index e61558c59bf0d..c7728ef1d28ec 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -398,15 +398,14 @@ void SelectionDAGISelLegacy::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.addRequired<TargetLibraryInfoWrapperPass>();
   AU.addRequired<TargetTransformInfoWrapperPass>();
   AU.addRequired<AssumptionCacheTracker>();
-  if (UseMBPI && OptLevel != CodeGenOptLevel::None)
-      AU.addRequired<BranchProbabilityInfoWrapperPass>();
+  if (UseMBPI)
+    AU.addRequired<BranchProbabilityInfoWrapperPass>();
   AU.addRequired<ProfileSummaryInfoWrapperPass>();
   // AssignmentTrackingAnalysis only runs if assignment tracking is enabled for
   // the module.
   AU.addRequired<AssignmentTrackingAnalysis>();
   AU.addPreserved<AssignmentTrackingAnalysis>();
-  if (OptLevel != CodeGenOptLevel::None)
-      LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU);
+  LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU);
   MachineFunctionPass::getAnalysisUsage(AU);
 }
 
@@ -469,7 +468,7 @@ void SelectionDAGISel::initializeAnalysisResults(
   auto *PSI = MAMP.getCachedResult<ProfileSummaryAnalysis>(*Fn.getParent());
   BlockFrequencyInfo *BFI = nullptr;
   FAM.getResult<BlockFrequencyAnalysis>(Fn);
-  if (PSI && PSI->hasProfileSummary() && OptLevel != CodeGenOptLevel::None)
+  if (PSI && PSI->hasProfileSummary())
     BFI = &FAM.getResult<BlockFrequencyAnalysis>(Fn);
 
   FunctionVarLocs const *FnVarLocs = nullptr;
@@ -487,7 +486,7 @@ void SelectionDAGISel::initializeAnalysisResults(
   // into account).  That's unfortunate but OK because it just means we won't
   // ask for passes that have been required anyway.
 
-  if (UseMBPI && OptLevel != CodeGenOptLevel::None)
+  if (UseMBPI && (Fn.hasProfileData() || OptLevel != CodeGenOptLevel::None))
     FuncInfo->BPI = &FAM.getResult<BranchProbabilityAnalysis>(Fn);
   else
     FuncInfo->BPI = nullptr;
@@ -523,7 +522,7 @@ void SelectionDAGISel::initializeAnalysisResults(MachineFunctionPass &MFP) {
   AC = &MFP.getAnalysis<AssumptionCacheTracker>().getAssumptionCache(Fn);
   auto *PSI = &MFP.getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
   BlockFrequencyInfo *BFI = nullptr;
-  if (PSI && PSI->hasProfileSummary() && OptLevel != CodeGenOptLevel::None)
+  if (PSI && PSI->hasProfileSummary())
     BFI = &MFP.getAnalysis<LazyBlockFrequencyInfoPass>().getBFI();
 
   FunctionVarLocs const *FnVarLocs = nullptr;
@@ -544,7 +543,7 @@ void SelectionDAGISel::initializeAnalysisResults(MachineFunctionPass &MFP) {
   // into account).  That's unfortunate but OK because it just means we won't
   // ask for passes that have been required anyway.
 
-  if (UseMBPI && OptLevel != CodeGenOptLevel::None)
+  if (UseMBPI && (Fn.hasProfileData() || OptLevel != CodeGenOptLevel::None))
     FuncInfo->BPI =
         &MFP.getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
   else
diff --git a/llvm/test/CodeGen/AArch64/O0-pipeline.ll b/llvm/test/CodeGen/AArch64/O0-pipeline.ll
index abc67eec32391..6029d3d4927ca 100644
--- a/llvm/test/CodeGen/AArch64/O0-pipeline.ll
+++ b/llvm/test/CodeGen/AArch64/O0-pipeline.ll
@@ -50,7 +50,13 @@
 ; CHECK-NEXT:       Analysis for ComputingKnownBits
 ; CHECK-NEXT:       InstructionSelect
 ; CHECK-NEXT:       ResetMachineFunction
+; CHECK-NEXT:       Dominator Tree Construction
+; CHECK-NEXT:       Natural Loop Information
+; CHECK-NEXT:       Post-Dominator Tree Construction
+; CHECK-NEXT:       Branch Probability Analysis
 ; CHECK-NEXT:       Assignment Tracking Analysis
+; CHECK-NEXT:       Lazy Branch Probability Analysis
+; CHECK-NEXT:       Lazy Block Frequency Analysis
 ; CHECK-NEXT:       AArch64 Instruction Selection
 ; CHECK-NEXT:       Finalize ISel and expand pseudo-instructions
 ; CHECK-NEXT:       Local Stack Slot Allocation
diff --git a/llvm/test/CodeGen/AMDGPU/llc-pipeline.ll b/llvm/test/CodeGen/AMDGPU/llc-pipeline.ll
index 65d0102a9d0dc..471c90ec73012 100644
--- a/llvm/test/CodeGen/AMDGPU/llc-pipeline.ll
+++ b/llvm/test/CodeGen/AMDGPU/llc-pipeline.ll
@@ -94,7 +94,12 @@
 ; GCN-O0-NEXT:        Dominator Tree Construction
 ; GCN-O0-NEXT:        Cycle Info Analysis
 ; GCN-O0-NEXT:        Uniformity Analysis
+; GCN-O0-NEXT:        Natural Loop Information
+; GCN-O0-NEXT:        Post-Dominator Tree Construction
+; GCN-O0-NEXT:        Branch Probability Analysis
 ; GCN-O0-NEXT:        Assignment Tracking Analysis
+; GCN-O0-NEXT:        Lazy Branch Probability Analysis
+; GCN-O0-NEXT:        Lazy Block Frequency Analysis
 ; GCN-O0-NEXT:        AMDGPU DAG->DAG Pattern Instruction Selection
 ; GCN-O0-NEXT:        MachineDominator Tree Construction
 ; GCN-O0-NEXT:        SI Fix SGPR copies
diff --git a/llvm/test/CodeGen/LoongArch/O0-pipeline.ll b/llvm/test/CodeGen/LoongArch/O0-pipeline.ll
index 9006b5c8d6fe1..7f368e59133a0 100644
--- a/llvm/test/CodeGen/LoongArch/O0-pipeline.ll
+++ b/llvm/test/CodeGen/LoongArch/O0-pipeline.ll
@@ -34,7 +34,13 @@
 ; CHECK-NEXT:       Safe Stack instrumentation pass
 ; CHECK-NEXT:       Insert stack protectors
 ; CHECK-NEXT:       Module Verifier
+; CHECK-NEXT:       Dominator Tree Construction
+; CHECK-NEXT:       Natural Loop Information
+; CHECK-NEXT:       Post-Dominator Tree Construction
+; CHECK-NEXT:       Branch Probability Analysis
 ; CHECK-NEXT:       Assignment Tracking Analysis
+; CHECK-NEXT:       Lazy Branch Probability Analysis
+; CHECK-NEXT:       Lazy Block Frequency Analysis
 ; CHECK-NEXT:       LoongArch DAG->DAG Pattern Instruction Selection
 ; CHECK-NEXT:       Finalize ISel and expand pseudo-instructions
 ; CHECK-NEXT:       Local Stack Slot Allocation
diff --git a/llvm/test/CodeGen/PowerPC/O0-pipeline.ll b/llvm/test/CodeGen/PowerPC/O0-pipeline.ll
index 38b1074e55d22..a4a6d831d64fc 100644
--- a/llvm/test/CodeGen/PowerPC/O0-pipeline.ll
+++ b/llvm/test/CodeGen/PowerPC/O0-pipeline.ll
@@ -33,7 +33,13 @@
 ; CHECK-NEXT:       Safe Stack instrumentation pass
 ; CHECK-NEXT:       Insert stack protectors
 ; CHECK-NEXT:       Module Verifier
+; CHECK-NEXT:       Dominator Tree Construction
+; CHECK-NEXT:       Natural Loop Information
+; CHECK-NEXT:       Post-Dominator Tree Construction
+; CHECK-NEXT:       Branch Probability Analysis
 ; CHECK-NEXT:       Assignment Tracking Analysis
+; CHECK-NEXT:       Lazy Branch Probability Analysis
+; CHECK-NEXT:       Lazy Block Frequency Analysis
 ; CHECK-NEXT:       PowerPC DAG->DAG Pattern Instruction Selection
 ; CHECK-NEXT:       PowerPC VSX Copy Legalization
 ; CHECK-NEXT:       Finalize ISel and expand pseudo-instructions
diff --git a/llvm/test/CodeGen/RISCV/O0-pipeline.ll b/llvm/test/CodeGen/RISCV/O0-pipeline.ll
index 8714b286374a5..83379754a7507 100644
--- a/llvm/test/CodeGen/RISCV/O0-pipeline.ll
+++ b/llvm/test/CodeGen/RISCV/O0-pipeline.ll
@@ -35,7 +35,13 @@
 ; CHECK-NEXT:       Safe Stack instrumentation pass
 ; CHECK-NEXT:       Insert stack protectors
 ; CHECK-NEXT:       Module Verifier
+; CHECK-NEXT:       Dominator Tree Construction
+; CHECK-NEXT:       Natural Loop Information
+; CHECK-NEXT:       Post-Dominator Tree Construction
+; CHECK-NEXT:       Branch Probability Analysis
 ; CHECK-NEXT:       Assignment Tracking Analysis
+; CHECK-NEXT:       Lazy Branch Probability Analysis
+; CHECK-NEXT:       Lazy Block Frequency Analysis
 ; CHECK-NEXT:       RISC-V DAG->DAG Pattern Instruction Selection
 ; CHECK-NEXT:       Finalize ISel and expand pseudo-instructions
 ; CHECK-NEXT:       Local Stack Slot Allocation
diff --git a/llvm/test/CodeGen/X86/O0-pipeline.ll b/llvm/test/CodeGen/X86/O0-pipeline.ll
index 0fbfb42d2a4dd..6aea51d8e87dc 100644
--- a/llvm/test/CodeGen/X86/O0-pipeline.ll
+++ b/llvm/test/CodeGen/X86/O0-pipeline.ll
@@ -35,7 +35,13 @@
 ; CHECK-NEXT:       Safe Stack instrumentation pass
 ; CHECK-NEXT:       Insert stack protectors
 ; CHECK-NEXT:       Module Verifier
+; CHECK-NEXT:       Dominator Tree Construction
+; CHECK-NEXT:       Natural Loop Information
+; CHECK-NEXT:       Post-Dominator Tree Construction
+; CHECK-NEXT:       Branch Probability Analysis
 ; CHECK-NEXT:       Assignment Tracking Analysis
+; CHECK-NEXT:       Lazy Branch Probability Analysis
+; CHECK-NEXT:       Lazy Block Frequency Analysis
 ; CHECK-NEXT:       X86 DAG->DAG Instruction Selection
 ; CHECK-NEXT:       X86 PIC Global Base Reg Initialization
 ; CHECK-NEXT:       Argument Stack Rebase
diff --git a/llvm/test/CodeGen/X86/pgo-profile-o0.ll b/llvm/test/CodeGen/X86/pgo-profile-o0.ll
new file mode 100644
index 0000000000000..009721fcbba78
--- /dev/null
+++ b/llvm/test/CodeGen/X86/pgo-profile-o0.ll
@@ -0,0 +1,49 @@
+; RUN: llc -mtriple=x86_64-- -O0 -debug-pass=Structure %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=PASSES
+; RUN: llc -mtriple=x86_64-- -O0 -debug-only=branch-prob %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=BRANCH_PROB
+; RUN: llc -mtriple=x86_64-- -O0 -stop-after=finalize-isel %s -o - | FileCheck %s --check-prefix=MIR
+
+; REQUIRES: asserts
+
+; This test verifies that PGO profile information (branch weights) is preserved
+; during instruction selection at -O0.
+
+; Test function with explicit branch weights from PGO.
+define i32 @test_pgo_preservation(i32 %x) !prof !15 {
+entry:
+  %cmp = icmp sgt i32 %x, 10
+  ; This branch has bias: 97 taken vs 3 not taken
+  br i1 %cmp, label %if.then, label %if.else, !prof !16
+
+if.then:
+  ; Hot path - should have high frequency
+  %add = add nsw i32 %x, 100
+  br label %if.end
+
+if.else:
+  ; Cold path - should have low frequency
+  %sub = sub nsw i32 %x, 50
+  br label %if.end
+
+if.end:
+  %result = phi i32 [ %add, %if.then ], [ %sub, %if.else ]
+  ret i32 %result
+}
+
+; Profile metadata with branch weights 97:3.
+!15 = !{!"function_entry_count", i64 100}
+!16 = !{!"branch_weights", i32 97, i32 3}
+
+; Verify that Branch Probability Analysis runs at O0.
+; PASSES: Branch Probability Analysis
+
+; Verify that the branch probabilities reflect the exact profile data.
+; BRANCH_PROB: ---- Branch Probability Info : test_pgo_preservation ----
+; BRANCH_PROB: set edge entry -> 0 successor probability to {{.*}} = 97.00%
+; BRANCH_PROB: set edge entry -> 1 successor probability to {{.*}} = 3.00%
+
+; Verify that machine IR preserves the branch probabilities from profile data
+; MIR: bb.0.entry:
+; MIR-NEXT: successors: %bb.{{[0-9]+}}({{0x03d70a3d|0x7c28f5c3}}), %bb.{{[0-9]+}}({{0x7c28f5c3|0x03d70a3d}})
+; The two successor probability values should be:
+; - 0x7c28f5c3: approximately 97% (high probability successor)
+; - 0x03d70a3d: approximately 3% (low probability successor)

>From 6e4ebda9189867a3c076bcf1f7b4ffce6328a8a7 Mon Sep 17 00:00:00 2001
From: Grigory Pastukhov <gpastukhov at meta.com>
Date: Thu, 2 Oct 2025 16:06:53 -0700
Subject: [PATCH 2/7] Register analysis only if PGO is present

---
 .../CodeGen/SelectionDAG/SelectionDAGISel.cpp |  28 +++-
 llvm/test/CodeGen/AArch64/O0-pipeline.ll      |   6 -
 llvm/test/CodeGen/AMDGPU/llc-pipeline.ll      |   5 -
 llvm/test/CodeGen/LoongArch/O0-pipeline.ll    |   6 -
 llvm/test/CodeGen/PowerPC/O0-pipeline.ll      |   6 -
 llvm/test/CodeGen/RISCV/O0-pipeline.ll        |   6 -
 llvm/test/CodeGen/X86/O0-pipeline.ll          |   6 -
 llvm/test/CodeGen/X86/pgo-profile-o0.ll       |   6 +-
 llvm/tools/llc/llc.cpp                        | 146 ++++++++++++++++++
 9 files changed, 171 insertions(+), 44 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index c7728ef1d28ec..1b5e2d987dcb5 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -229,6 +229,17 @@ static bool dontUseFastISelFor(const Function &Fn) {
   });
 }
 
+static bool shouldRegisterPGOPasses(const TargetMachine &TM,
+                                    CodeGenOptLevel OptLevel) {
+  bool RegisterPGOPasses = OptLevel != CodeGenOptLevel::None;
+  if (!RegisterPGOPasses && TM.getPGOOption()) {
+    const PGOOptions &Options = *TM.getPGOOption();
+    RegisterPGOPasses = Options.Action != PGOOptions::PGOAction::NoAction ||
+                        Options.CSAction != PGOOptions::CSPGOAction::NoCSAction;
+  }
+  return RegisterPGOPasses;
+}
+
 namespace llvm {
 
   //===--------------------------------------------------------------------===//
@@ -390,6 +401,8 @@ SelectionDAGISel::~SelectionDAGISel() { delete CurDAG; }
 
 void SelectionDAGISelLegacy::getAnalysisUsage(AnalysisUsage &AU) const {
   CodeGenOptLevel OptLevel = Selector->OptLevel;
+  bool RegisterPGOPasses =
+      shouldRegisterPGOPasses(Selector->TM, Selector->OptLevel);
   if (OptLevel != CodeGenOptLevel::None)
       AU.addRequired<AAResultsWrapperPass>();
   AU.addRequired<GCModuleInfo>();
@@ -398,14 +411,15 @@ void SelectionDAGISelLegacy::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.addRequired<TargetLibraryInfoWrapperPass>();
   AU.addRequired<TargetTransformInfoWrapperPass>();
   AU.addRequired<AssumptionCacheTracker>();
-  if (UseMBPI)
+  if (UseMBPI && RegisterPGOPasses)
     AU.addRequired<BranchProbabilityInfoWrapperPass>();
   AU.addRequired<ProfileSummaryInfoWrapperPass>();
   // AssignmentTrackingAnalysis only runs if assignment tracking is enabled for
   // the module.
   AU.addRequired<AssignmentTrackingAnalysis>();
   AU.addPreserved<AssignmentTrackingAnalysis>();
-  LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU);
+  if (RegisterPGOPasses)
+    LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU);
   MachineFunctionPass::getAnalysisUsage(AU);
 }
 
@@ -458,6 +472,7 @@ void SelectionDAGISel::initializeAnalysisResults(
   (void)MatchFilterFuncName;
 #endif
 
+  bool RegisterPGOPasses = shouldRegisterPGOPasses(TM, OptLevel);
   TII = MF->getSubtarget().getInstrInfo();
   TLI = MF->getSubtarget().getTargetLowering();
   RegInfo = &MF->getRegInfo();
@@ -468,7 +483,7 @@ void SelectionDAGISel::initializeAnalysisResults(
   auto *PSI = MAMP.getCachedResult<ProfileSummaryAnalysis>(*Fn.getParent());
   BlockFrequencyInfo *BFI = nullptr;
   FAM.getResult<BlockFrequencyAnalysis>(Fn);
-  if (PSI && PSI->hasProfileSummary())
+  if (PSI && PSI->hasProfileSummary() && RegisterPGOPasses)
     BFI = &FAM.getResult<BlockFrequencyAnalysis>(Fn);
 
   FunctionVarLocs const *FnVarLocs = nullptr;
@@ -486,7 +501,7 @@ void SelectionDAGISel::initializeAnalysisResults(
   // into account).  That's unfortunate but OK because it just means we won't
   // ask for passes that have been required anyway.
 
-  if (UseMBPI && (Fn.hasProfileData() || OptLevel != CodeGenOptLevel::None))
+  if (UseMBPI && RegisterPGOPasses)
     FuncInfo->BPI = &FAM.getResult<BranchProbabilityAnalysis>(Fn);
   else
     FuncInfo->BPI = nullptr;
@@ -512,6 +527,7 @@ void SelectionDAGISel::initializeAnalysisResults(MachineFunctionPass &MFP) {
   (void)MatchFilterFuncName;
 #endif
 
+  bool RegisterPGOPasses = shouldRegisterPGOPasses(TM, OptLevel);
   TII = MF->getSubtarget().getInstrInfo();
   TLI = MF->getSubtarget().getTargetLowering();
   RegInfo = &MF->getRegInfo();
@@ -522,7 +538,7 @@ void SelectionDAGISel::initializeAnalysisResults(MachineFunctionPass &MFP) {
   AC = &MFP.getAnalysis<AssumptionCacheTracker>().getAssumptionCache(Fn);
   auto *PSI = &MFP.getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
   BlockFrequencyInfo *BFI = nullptr;
-  if (PSI && PSI->hasProfileSummary())
+  if (PSI && PSI->hasProfileSummary() && RegisterPGOPasses)
     BFI = &MFP.getAnalysis<LazyBlockFrequencyInfoPass>().getBFI();
 
   FunctionVarLocs const *FnVarLocs = nullptr;
@@ -543,7 +559,7 @@ void SelectionDAGISel::initializeAnalysisResults(MachineFunctionPass &MFP) {
   // into account).  That's unfortunate but OK because it just means we won't
   // ask for passes that have been required anyway.
 
-  if (UseMBPI && (Fn.hasProfileData() || OptLevel != CodeGenOptLevel::None))
+  if (UseMBPI && RegisterPGOPasses)
     FuncInfo->BPI =
         &MFP.getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
   else
diff --git a/llvm/test/CodeGen/AArch64/O0-pipeline.ll b/llvm/test/CodeGen/AArch64/O0-pipeline.ll
index 6029d3d4927ca..abc67eec32391 100644
--- a/llvm/test/CodeGen/AArch64/O0-pipeline.ll
+++ b/llvm/test/CodeGen/AArch64/O0-pipeline.ll
@@ -50,13 +50,7 @@
 ; CHECK-NEXT:       Analysis for ComputingKnownBits
 ; CHECK-NEXT:       InstructionSelect
 ; CHECK-NEXT:       ResetMachineFunction
-; CHECK-NEXT:       Dominator Tree Construction
-; CHECK-NEXT:       Natural Loop Information
-; CHECK-NEXT:       Post-Dominator Tree Construction
-; CHECK-NEXT:       Branch Probability Analysis
 ; CHECK-NEXT:       Assignment Tracking Analysis
-; CHECK-NEXT:       Lazy Branch Probability Analysis
-; CHECK-NEXT:       Lazy Block Frequency Analysis
 ; CHECK-NEXT:       AArch64 Instruction Selection
 ; CHECK-NEXT:       Finalize ISel and expand pseudo-instructions
 ; CHECK-NEXT:       Local Stack Slot Allocation
diff --git a/llvm/test/CodeGen/AMDGPU/llc-pipeline.ll b/llvm/test/CodeGen/AMDGPU/llc-pipeline.ll
index 471c90ec73012..65d0102a9d0dc 100644
--- a/llvm/test/CodeGen/AMDGPU/llc-pipeline.ll
+++ b/llvm/test/CodeGen/AMDGPU/llc-pipeline.ll
@@ -94,12 +94,7 @@
 ; GCN-O0-NEXT:        Dominator Tree Construction
 ; GCN-O0-NEXT:        Cycle Info Analysis
 ; GCN-O0-NEXT:        Uniformity Analysis
-; GCN-O0-NEXT:        Natural Loop Information
-; GCN-O0-NEXT:        Post-Dominator Tree Construction
-; GCN-O0-NEXT:        Branch Probability Analysis
 ; GCN-O0-NEXT:        Assignment Tracking Analysis
-; GCN-O0-NEXT:        Lazy Branch Probability Analysis
-; GCN-O0-NEXT:        Lazy Block Frequency Analysis
 ; GCN-O0-NEXT:        AMDGPU DAG->DAG Pattern Instruction Selection
 ; GCN-O0-NEXT:        MachineDominator Tree Construction
 ; GCN-O0-NEXT:        SI Fix SGPR copies
diff --git a/llvm/test/CodeGen/LoongArch/O0-pipeline.ll b/llvm/test/CodeGen/LoongArch/O0-pipeline.ll
index 7f368e59133a0..9006b5c8d6fe1 100644
--- a/llvm/test/CodeGen/LoongArch/O0-pipeline.ll
+++ b/llvm/test/CodeGen/LoongArch/O0-pipeline.ll
@@ -34,13 +34,7 @@
 ; CHECK-NEXT:       Safe Stack instrumentation pass
 ; CHECK-NEXT:       Insert stack protectors
 ; CHECK-NEXT:       Module Verifier
-; CHECK-NEXT:       Dominator Tree Construction
-; CHECK-NEXT:       Natural Loop Information
-; CHECK-NEXT:       Post-Dominator Tree Construction
-; CHECK-NEXT:       Branch Probability Analysis
 ; CHECK-NEXT:       Assignment Tracking Analysis
-; CHECK-NEXT:       Lazy Branch Probability Analysis
-; CHECK-NEXT:       Lazy Block Frequency Analysis
 ; CHECK-NEXT:       LoongArch DAG->DAG Pattern Instruction Selection
 ; CHECK-NEXT:       Finalize ISel and expand pseudo-instructions
 ; CHECK-NEXT:       Local Stack Slot Allocation
diff --git a/llvm/test/CodeGen/PowerPC/O0-pipeline.ll b/llvm/test/CodeGen/PowerPC/O0-pipeline.ll
index a4a6d831d64fc..38b1074e55d22 100644
--- a/llvm/test/CodeGen/PowerPC/O0-pipeline.ll
+++ b/llvm/test/CodeGen/PowerPC/O0-pipeline.ll
@@ -33,13 +33,7 @@
 ; CHECK-NEXT:       Safe Stack instrumentation pass
 ; CHECK-NEXT:       Insert stack protectors
 ; CHECK-NEXT:       Module Verifier
-; CHECK-NEXT:       Dominator Tree Construction
-; CHECK-NEXT:       Natural Loop Information
-; CHECK-NEXT:       Post-Dominator Tree Construction
-; CHECK-NEXT:       Branch Probability Analysis
 ; CHECK-NEXT:       Assignment Tracking Analysis
-; CHECK-NEXT:       Lazy Branch Probability Analysis
-; CHECK-NEXT:       Lazy Block Frequency Analysis
 ; CHECK-NEXT:       PowerPC DAG->DAG Pattern Instruction Selection
 ; CHECK-NEXT:       PowerPC VSX Copy Legalization
 ; CHECK-NEXT:       Finalize ISel and expand pseudo-instructions
diff --git a/llvm/test/CodeGen/RISCV/O0-pipeline.ll b/llvm/test/CodeGen/RISCV/O0-pipeline.ll
index 83379754a7507..8714b286374a5 100644
--- a/llvm/test/CodeGen/RISCV/O0-pipeline.ll
+++ b/llvm/test/CodeGen/RISCV/O0-pipeline.ll
@@ -35,13 +35,7 @@
 ; CHECK-NEXT:       Safe Stack instrumentation pass
 ; CHECK-NEXT:       Insert stack protectors
 ; CHECK-NEXT:       Module Verifier
-; CHECK-NEXT:       Dominator Tree Construction
-; CHECK-NEXT:       Natural Loop Information
-; CHECK-NEXT:       Post-Dominator Tree Construction
-; CHECK-NEXT:       Branch Probability Analysis
 ; CHECK-NEXT:       Assignment Tracking Analysis
-; CHECK-NEXT:       Lazy Branch Probability Analysis
-; CHECK-NEXT:       Lazy Block Frequency Analysis
 ; CHECK-NEXT:       RISC-V DAG->DAG Pattern Instruction Selection
 ; CHECK-NEXT:       Finalize ISel and expand pseudo-instructions
 ; CHECK-NEXT:       Local Stack Slot Allocation
diff --git a/llvm/test/CodeGen/X86/O0-pipeline.ll b/llvm/test/CodeGen/X86/O0-pipeline.ll
index 6aea51d8e87dc..0fbfb42d2a4dd 100644
--- a/llvm/test/CodeGen/X86/O0-pipeline.ll
+++ b/llvm/test/CodeGen/X86/O0-pipeline.ll
@@ -35,13 +35,7 @@
 ; CHECK-NEXT:       Safe Stack instrumentation pass
 ; CHECK-NEXT:       Insert stack protectors
 ; CHECK-NEXT:       Module Verifier
-; CHECK-NEXT:       Dominator Tree Construction
-; CHECK-NEXT:       Natural Loop Information
-; CHECK-NEXT:       Post-Dominator Tree Construction
-; CHECK-NEXT:       Branch Probability Analysis
 ; CHECK-NEXT:       Assignment Tracking Analysis
-; CHECK-NEXT:       Lazy Branch Probability Analysis
-; CHECK-NEXT:       Lazy Block Frequency Analysis
 ; CHECK-NEXT:       X86 DAG->DAG Instruction Selection
 ; CHECK-NEXT:       X86 PIC Global Base Reg Initialization
 ; CHECK-NEXT:       Argument Stack Rebase
diff --git a/llvm/test/CodeGen/X86/pgo-profile-o0.ll b/llvm/test/CodeGen/X86/pgo-profile-o0.ll
index 009721fcbba78..f9704fcf0ec3a 100644
--- a/llvm/test/CodeGen/X86/pgo-profile-o0.ll
+++ b/llvm/test/CodeGen/X86/pgo-profile-o0.ll
@@ -1,6 +1,6 @@
-; RUN: llc -mtriple=x86_64-- -O0 -debug-pass=Structure %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=PASSES
-; RUN: llc -mtriple=x86_64-- -O0 -debug-only=branch-prob %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=BRANCH_PROB
-; RUN: llc -mtriple=x86_64-- -O0 -stop-after=finalize-isel %s -o - | FileCheck %s --check-prefix=MIR
+; RUN: llc -mtriple=x86_64-- -O0 -pgo-kind=pgo-sample-use-pipeline -debug-pass=Structure %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=PASSES
+; RUN: llc -mtriple=x86_64-- -O0 -pgo-kind=pgo-sample-use-pipeline -debug-only=branch-prob %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=BRANCH_PROB
+; RUN: llc -mtriple=x86_64-- -O0 -pgo-kind=pgo-sample-use-pipeline -stop-after=finalize-isel %s -o - | FileCheck %s --check-prefix=MIR
 
 ; REQUIRES: asserts
 
diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp
index a2327fbc3b66a..c117b71ba0a47 100644
--- a/llvm/tools/llc/llc.cpp
+++ b/llvm/tools/llc/llc.cpp
@@ -44,6 +44,7 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FormattedStream.h"
 #include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/PGOOptions.h"
 #include "llvm/Support/PluginLoader.h"
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Support/TargetSelect.h"
@@ -239,6 +240,145 @@ static cl::opt<RunPassOption, true, cl::parser<std::string>> RunPass(
     cl::desc("Run compiler only for specified passes (comma separated list)"),
     cl::value_desc("pass-name"), cl::location(RunPassOpt));
 
+// PGO command line options
+enum PGOKind {
+  NoPGO,
+  InstrGen,
+  InstrUse,
+  SampleUse,
+};
+
+enum CSPGOKind {
+  NoCSPGO,
+  CSInstrGen,
+  CSInstrUse,
+};
+
+static cl::opt<PGOKind>
+    PGOKindFlag("pgo-kind", cl::init(NoPGO), cl::Hidden,
+                cl::desc("The kind of profile guided optimization"),
+                cl::values(clEnumValN(NoPGO, "nopgo", "Do not use PGO."),
+                           clEnumValN(InstrGen, "pgo-instr-gen-pipeline",
+                                      "Instrument the IR to generate profile."),
+                           clEnumValN(InstrUse, "pgo-instr-use-pipeline",
+                                      "Use instrumented profile to guide PGO."),
+                           clEnumValN(SampleUse, "pgo-sample-use-pipeline",
+                                      "Use sampled profile to guide PGO.")));
+
+static cl::opt<std::string>
+    ProfileFile("profile-file", cl::desc("Path to the profile."), cl::Hidden);
+
+static cl::opt<std::string>
+    MemoryProfileFile("memory-profile-file",
+                      cl::desc("Path to the memory profile."), cl::Hidden);
+
+static cl::opt<CSPGOKind> CSPGOKindFlag(
+    "cspgo-kind", cl::init(NoCSPGO), cl::Hidden,
+    cl::desc("The kind of context sensitive profile guided optimization"),
+    cl::values(
+        clEnumValN(NoCSPGO, "nocspgo", "Do not use CSPGO."),
+        clEnumValN(
+            CSInstrGen, "cspgo-instr-gen-pipeline",
+            "Instrument (context sensitive) the IR to generate profile."),
+        clEnumValN(
+            CSInstrUse, "cspgo-instr-use-pipeline",
+            "Use instrumented (context sensitive) profile to guide PGO.")));
+
+static cl::opt<std::string> CSProfileGenFile(
+    "cs-profilegen-file",
+    cl::desc("Path to the instrumented context sensitive profile."),
+    cl::Hidden);
+
+static cl::opt<std::string>
+    ProfileRemappingFile("profile-remapping-file",
+                         cl::desc("Path to the profile remapping file."),
+                         cl::Hidden);
+
+static cl::opt<PGOOptions::ColdFuncOpt> PGOColdFuncAttr(
+    "pgo-cold-func-opt", cl::init(PGOOptions::ColdFuncOpt::Default), cl::Hidden,
+    cl::desc(
+        "Function attribute to apply to cold functions as determined by PGO"),
+    cl::values(clEnumValN(PGOOptions::ColdFuncOpt::Default, "default",
+                          "Default (no attribute)"),
+               clEnumValN(PGOOptions::ColdFuncOpt::OptSize, "optsize",
+                          "Mark cold functions with optsize."),
+               clEnumValN(PGOOptions::ColdFuncOpt::MinSize, "minsize",
+                          "Mark cold functions with minsize."),
+               clEnumValN(PGOOptions::ColdFuncOpt::OptNone, "optnone",
+                          "Mark cold functions with optnone.")));
+
+static cl::opt<bool> DebugInfoForProfiling(
+    "debug-info-for-profiling", cl::init(false), cl::Hidden,
+    cl::desc("Emit special debug info to enable PGO profile generation."));
+
+static cl::opt<bool> PseudoProbeForProfiling(
+    "pseudo-probe-for-profiling", cl::init(false), cl::Hidden,
+    cl::desc("Emit pseudo probes to enable PGO profile generation."));
+
+// Function to set PGO options on TargetMachine based on command line flags
+static void setPGOOptions(TargetMachine &TM) {
+  std::optional<PGOOptions> PGOOpt;
+
+  switch (PGOKindFlag) {
+  case InstrGen:
+    PGOOpt =
+        PGOOptions(ProfileFile, "", "", MemoryProfileFile, PGOOptions::IRInstr,
+                   PGOOptions::NoCSAction, PGOColdFuncAttr);
+    break;
+  case InstrUse:
+    PGOOpt =
+        PGOOptions(ProfileFile, "", ProfileRemappingFile, MemoryProfileFile,
+                   PGOOptions::IRUse, PGOOptions::NoCSAction, PGOColdFuncAttr);
+    break;
+  case SampleUse:
+    PGOOpt = PGOOptions(ProfileFile, "", ProfileRemappingFile,
+                        MemoryProfileFile, PGOOptions::SampleUse,
+                        PGOOptions::NoCSAction, PGOColdFuncAttr);
+    break;
+  case NoPGO:
+    if (DebugInfoForProfiling || PseudoProbeForProfiling ||
+        !MemoryProfileFile.empty())
+      PGOOpt = PGOOptions("", "", "", MemoryProfileFile, PGOOptions::NoAction,
+                          PGOOptions::NoCSAction, PGOColdFuncAttr,
+                          DebugInfoForProfiling, PseudoProbeForProfiling);
+    else
+      PGOOpt = std::nullopt;
+    break;
+  }
+
+  // Handle context-sensitive PGO options
+  if (CSPGOKindFlag != NoCSPGO) {
+    if (PGOOpt && (PGOOpt->Action == PGOOptions::IRInstr ||
+                   PGOOpt->Action == PGOOptions::SampleUse)) {
+      errs() << "CSPGOKind cannot be used with IRInstr or SampleUse";
+      exit(1);
+    }
+    if (CSPGOKindFlag == CSInstrGen) {
+      if (CSProfileGenFile.empty()) {
+        errs() << "CSInstrGen needs to specify CSProfileGenFile";
+        exit(1);
+      }
+      if (PGOOpt) {
+        PGOOpt->CSAction = PGOOptions::CSIRInstr;
+        PGOOpt->CSProfileGenFile = CSProfileGenFile;
+      } else {
+        PGOOpt = PGOOptions("", CSProfileGenFile, ProfileRemappingFile,
+                            /*MemoryProfile=*/"", PGOOptions::NoAction,
+                            PGOOptions::CSIRInstr);
+      }
+    } else /* CSPGOKindFlag == CSInstrUse */ {
+      if (!PGOOpt) {
+        errs() << "CSInstrUse needs to be together with InstrUse";
+        exit(1);
+      }
+      PGOOpt->CSAction = PGOOptions::CSIRUse;
+    }
+  }
+
+  if (PGOOpt)
+    TM.setPGOOption(PGOOpt);
+}
+
 static int compileModule(char **, LLVMContext &);
 
 [[noreturn]] static void reportError(Twine Msg, StringRef Filename = "") {
@@ -554,6 +694,9 @@ static int compileModule(char **argv, LLVMContext &Context) {
           TheTriple, CPUStr, FeaturesStr, Options, RM, CM, OLvl));
       assert(Target && "Could not allocate target machine!");
 
+      // Set PGO options based on command line flags
+      setPGOOptions(*Target);
+
       return Target->createDataLayout().getStringRepresentation();
     };
     if (InputLanguage == "mir" ||
@@ -597,6 +740,9 @@ static int compileModule(char **argv, LLVMContext &Context) {
         TheTriple, CPUStr, FeaturesStr, Options, RM, CM, OLvl));
     assert(Target && "Could not allocate target machine!");
 
+    // Set PGO options based on command line flags
+    setPGOOptions(*Target);
+
     // If we don't have a module then just exit now. We do this down
     // here since the CPU/Feature help is underneath the target machine
     // creation.

>From 0af0751d2293f9247fd1e240e4a0fd402c231460 Mon Sep 17 00:00:00 2001
From: Grigory Pastukhov <gpastukhov at meta.com>
Date: Mon, 6 Oct 2025 10:26:16 -0700
Subject: [PATCH 3/7] Keep only pgo-kind option

---
 llvm/tools/llc/llc.cpp | 115 ++---------------------------------------
 1 file changed, 4 insertions(+), 111 deletions(-)

diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp
index c117b71ba0a47..2a89933c1dfe3 100644
--- a/llvm/tools/llc/llc.cpp
+++ b/llvm/tools/llc/llc.cpp
@@ -243,138 +243,31 @@ static cl::opt<RunPassOption, true, cl::parser<std::string>> RunPass(
 // PGO command line options
 enum PGOKind {
   NoPGO,
-  InstrGen,
-  InstrUse,
   SampleUse,
 };
 
-enum CSPGOKind {
-  NoCSPGO,
-  CSInstrGen,
-  CSInstrUse,
-};
-
 static cl::opt<PGOKind>
     PGOKindFlag("pgo-kind", cl::init(NoPGO), cl::Hidden,
                 cl::desc("The kind of profile guided optimization"),
                 cl::values(clEnumValN(NoPGO, "nopgo", "Do not use PGO."),
-                           clEnumValN(InstrGen, "pgo-instr-gen-pipeline",
-                                      "Instrument the IR to generate profile."),
-                           clEnumValN(InstrUse, "pgo-instr-use-pipeline",
-                                      "Use instrumented profile to guide PGO."),
                            clEnumValN(SampleUse, "pgo-sample-use-pipeline",
                                       "Use sampled profile to guide PGO.")));
 
-static cl::opt<std::string>
-    ProfileFile("profile-file", cl::desc("Path to the profile."), cl::Hidden);
-
-static cl::opt<std::string>
-    MemoryProfileFile("memory-profile-file",
-                      cl::desc("Path to the memory profile."), cl::Hidden);
-
-static cl::opt<CSPGOKind> CSPGOKindFlag(
-    "cspgo-kind", cl::init(NoCSPGO), cl::Hidden,
-    cl::desc("The kind of context sensitive profile guided optimization"),
-    cl::values(
-        clEnumValN(NoCSPGO, "nocspgo", "Do not use CSPGO."),
-        clEnumValN(
-            CSInstrGen, "cspgo-instr-gen-pipeline",
-            "Instrument (context sensitive) the IR to generate profile."),
-        clEnumValN(
-            CSInstrUse, "cspgo-instr-use-pipeline",
-            "Use instrumented (context sensitive) profile to guide PGO.")));
-
-static cl::opt<std::string> CSProfileGenFile(
-    "cs-profilegen-file",
-    cl::desc("Path to the instrumented context sensitive profile."),
-    cl::Hidden);
-
-static cl::opt<std::string>
-    ProfileRemappingFile("profile-remapping-file",
-                         cl::desc("Path to the profile remapping file."),
-                         cl::Hidden);
-
-static cl::opt<PGOOptions::ColdFuncOpt> PGOColdFuncAttr(
-    "pgo-cold-func-opt", cl::init(PGOOptions::ColdFuncOpt::Default), cl::Hidden,
-    cl::desc(
-        "Function attribute to apply to cold functions as determined by PGO"),
-    cl::values(clEnumValN(PGOOptions::ColdFuncOpt::Default, "default",
-                          "Default (no attribute)"),
-               clEnumValN(PGOOptions::ColdFuncOpt::OptSize, "optsize",
-                          "Mark cold functions with optsize."),
-               clEnumValN(PGOOptions::ColdFuncOpt::MinSize, "minsize",
-                          "Mark cold functions with minsize."),
-               clEnumValN(PGOOptions::ColdFuncOpt::OptNone, "optnone",
-                          "Mark cold functions with optnone.")));
-
-static cl::opt<bool> DebugInfoForProfiling(
-    "debug-info-for-profiling", cl::init(false), cl::Hidden,
-    cl::desc("Emit special debug info to enable PGO profile generation."));
-
-static cl::opt<bool> PseudoProbeForProfiling(
-    "pseudo-probe-for-profiling", cl::init(false), cl::Hidden,
-    cl::desc("Emit pseudo probes to enable PGO profile generation."));
-
 // Function to set PGO options on TargetMachine based on command line flags
 static void setPGOOptions(TargetMachine &TM) {
   std::optional<PGOOptions> PGOOpt;
 
   switch (PGOKindFlag) {
-  case InstrGen:
-    PGOOpt =
-        PGOOptions(ProfileFile, "", "", MemoryProfileFile, PGOOptions::IRInstr,
-                   PGOOptions::NoCSAction, PGOColdFuncAttr);
-    break;
-  case InstrUse:
-    PGOOpt =
-        PGOOptions(ProfileFile, "", ProfileRemappingFile, MemoryProfileFile,
-                   PGOOptions::IRUse, PGOOptions::NoCSAction, PGOColdFuncAttr);
-    break;
   case SampleUse:
-    PGOOpt = PGOOptions(ProfileFile, "", ProfileRemappingFile,
-                        MemoryProfileFile, PGOOptions::SampleUse,
-                        PGOOptions::NoCSAction, PGOColdFuncAttr);
+    // Use default values for other PGOOptions parameters
+    PGOOpt = PGOOptions("", "", "", "", PGOOptions::SampleUse,
+                        PGOOptions::NoCSAction);
     break;
   case NoPGO:
-    if (DebugInfoForProfiling || PseudoProbeForProfiling ||
-        !MemoryProfileFile.empty())
-      PGOOpt = PGOOptions("", "", "", MemoryProfileFile, PGOOptions::NoAction,
-                          PGOOptions::NoCSAction, PGOColdFuncAttr,
-                          DebugInfoForProfiling, PseudoProbeForProfiling);
-    else
-      PGOOpt = std::nullopt;
+    PGOOpt = std::nullopt;
     break;
   }
 
-  // Handle context-sensitive PGO options
-  if (CSPGOKindFlag != NoCSPGO) {
-    if (PGOOpt && (PGOOpt->Action == PGOOptions::IRInstr ||
-                   PGOOpt->Action == PGOOptions::SampleUse)) {
-      errs() << "CSPGOKind cannot be used with IRInstr or SampleUse";
-      exit(1);
-    }
-    if (CSPGOKindFlag == CSInstrGen) {
-      if (CSProfileGenFile.empty()) {
-        errs() << "CSInstrGen needs to specify CSProfileGenFile";
-        exit(1);
-      }
-      if (PGOOpt) {
-        PGOOpt->CSAction = PGOOptions::CSIRInstr;
-        PGOOpt->CSProfileGenFile = CSProfileGenFile;
-      } else {
-        PGOOpt = PGOOptions("", CSProfileGenFile, ProfileRemappingFile,
-                            /*MemoryProfile=*/"", PGOOptions::NoAction,
-                            PGOOptions::CSIRInstr);
-      }
-    } else /* CSPGOKindFlag == CSInstrUse */ {
-      if (!PGOOpt) {
-        errs() << "CSInstrUse needs to be together with InstrUse";
-        exit(1);
-      }
-      PGOOpt->CSAction = PGOOptions::CSIRUse;
-    }
-  }
-
   if (PGOOpt)
     TM.setPGOOption(PGOOpt);
 }

>From 67050dd124f5d89ee41b4d3e09053064a9f68238 Mon Sep 17 00:00:00 2001
From: Grigory Pastukhov <gpastukhov at meta.com>
Date: Mon, 6 Oct 2025 10:58:55 -0700
Subject: [PATCH 4/7] Turn on PGO passes only if PGO enums are set to use

---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 1b5e2d987dcb5..931c57e84d176 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -231,13 +231,15 @@ static bool dontUseFastISelFor(const Function &Fn) {
 
 static bool shouldRegisterPGOPasses(const TargetMachine &TM,
                                     CodeGenOptLevel OptLevel) {
-  bool RegisterPGOPasses = OptLevel != CodeGenOptLevel::None;
-  if (!RegisterPGOPasses && TM.getPGOOption()) {
+  if (OptLevel != CodeGenOptLevel::None)
+    return true;
+  if (TM.getPGOOption()) {
     const PGOOptions &Options = *TM.getPGOOption();
-    RegisterPGOPasses = Options.Action != PGOOptions::PGOAction::NoAction ||
-                        Options.CSAction != PGOOptions::CSPGOAction::NoCSAction;
+    return Options.Action == PGOOptions::PGOAction::IRUse ||
+           Options.Action == PGOOptions::PGOAction::SampleUse ||
+           Options.CSAction != PGOOptions::CSPGOAction::CSIRUse;
   }
-  return RegisterPGOPasses;
+  return false;
 }
 
 namespace llvm {

>From 293b0959aad36b967984c7810e75b598566e5895 Mon Sep 17 00:00:00 2001
From: Grigory Pastukhov <gpastukhov at meta.com>
Date: Mon, 6 Oct 2025 17:09:42 -0700
Subject: [PATCH 5/7] Addressed comments

---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 2 +-
 llvm/tools/llc/llc.cpp                             | 5 +++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 931c57e84d176..f28dbd784d86a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -237,7 +237,7 @@ static bool shouldRegisterPGOPasses(const TargetMachine &TM,
     const PGOOptions &Options = *TM.getPGOOption();
     return Options.Action == PGOOptions::PGOAction::IRUse ||
            Options.Action == PGOOptions::PGOAction::SampleUse ||
-           Options.CSAction != PGOOptions::CSPGOAction::CSIRUse;
+           Options.CSAction != PGOOptions::CSPGOAction::NoCSAction;
   }
   return false;
 }
diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp
index 2a89933c1dfe3..9d51e952fa341 100644
--- a/llvm/tools/llc/llc.cpp
+++ b/llvm/tools/llc/llc.cpp
@@ -253,13 +253,14 @@ static cl::opt<PGOKind>
                            clEnumValN(SampleUse, "pgo-sample-use-pipeline",
                                       "Use sampled profile to guide PGO.")));
 
-// Function to set PGO options on TargetMachine based on command line flags
+// Function to set PGO options on TargetMachine based on command line flags.
 static void setPGOOptions(TargetMachine &TM) {
   std::optional<PGOOptions> PGOOpt;
 
   switch (PGOKindFlag) {
   case SampleUse:
-    // Use default values for other PGOOptions parameters
+    // Use default values for other PGOOptions parameters. This parameter
+    // is used to test that PGO data is preserved at -O0.
     PGOOpt = PGOOptions("", "", "", "", PGOOptions::SampleUse,
                         PGOOptions::NoCSAction);
     break;

>From a4773d92e41f59210031aec951aee52a19f4161e Mon Sep 17 00:00:00 2001
From: Grigory Pastukhov <gpastukhov at meta.com>
Date: Tue, 7 Oct 2025 12:58:20 -0700
Subject: [PATCH 6/7] Changed PGOOptions check for CSPGO

---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index f28dbd784d86a..de01fdde27ae7 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -237,7 +237,7 @@ static bool shouldRegisterPGOPasses(const TargetMachine &TM,
     const PGOOptions &Options = *TM.getPGOOption();
     return Options.Action == PGOOptions::PGOAction::IRUse ||
            Options.Action == PGOOptions::PGOAction::SampleUse ||
-           Options.CSAction != PGOOptions::CSPGOAction::NoCSAction;
+           Options.CSAction == PGOOptions::CSPGOAction::CSIRUse;
   }
   return false;
 }

>From b870ddd907780708a9274849e69cde247d5b55c9 Mon Sep 17 00:00:00 2001
From: Grigory Pastukhov <gpastukhov at meta.com>
Date: Thu, 9 Oct 2025 10:33:53 -0700
Subject: [PATCH 7/7] Changed function name

---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index de01fdde27ae7..c1f570d688793 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -229,8 +229,8 @@ static bool dontUseFastISelFor(const Function &Fn) {
   });
 }
 
-static bool shouldRegisterPGOPasses(const TargetMachine &TM,
-                                    CodeGenOptLevel OptLevel) {
+static bool maintainPGOProfile(const TargetMachine &TM,
+                               CodeGenOptLevel OptLevel) {
   if (OptLevel != CodeGenOptLevel::None)
     return true;
   if (TM.getPGOOption()) {
@@ -403,8 +403,7 @@ SelectionDAGISel::~SelectionDAGISel() { delete CurDAG; }
 
 void SelectionDAGISelLegacy::getAnalysisUsage(AnalysisUsage &AU) const {
   CodeGenOptLevel OptLevel = Selector->OptLevel;
-  bool RegisterPGOPasses =
-      shouldRegisterPGOPasses(Selector->TM, Selector->OptLevel);
+  bool RegisterPGOPasses = maintainPGOProfile(Selector->TM, Selector->OptLevel);
   if (OptLevel != CodeGenOptLevel::None)
       AU.addRequired<AAResultsWrapperPass>();
   AU.addRequired<GCModuleInfo>();
@@ -474,7 +473,7 @@ void SelectionDAGISel::initializeAnalysisResults(
   (void)MatchFilterFuncName;
 #endif
 
-  bool RegisterPGOPasses = shouldRegisterPGOPasses(TM, OptLevel);
+  bool RegisterPGOPasses = maintainPGOProfile(TM, OptLevel);
   TII = MF->getSubtarget().getInstrInfo();
   TLI = MF->getSubtarget().getTargetLowering();
   RegInfo = &MF->getRegInfo();
@@ -529,7 +528,7 @@ void SelectionDAGISel::initializeAnalysisResults(MachineFunctionPass &MFP) {
   (void)MatchFilterFuncName;
 #endif
 
-  bool RegisterPGOPasses = shouldRegisterPGOPasses(TM, OptLevel);
+  bool RegisterPGOPasses = maintainPGOProfile(TM, OptLevel);
   TII = MF->getSubtarget().getInstrInfo();
   TLI = MF->getSubtarget().getTargetLowering();
   RegInfo = &MF->getRegInfo();



More information about the llvm-commits mailing list