[llvm] [NewPM][AArch64][GlobalISel] Port AArch64PostLegalizerCombiner to NewPM (PR #194156)

Anshul Nigham via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 3 22:25:56 PDT 2026


https://github.com/nigham updated https://github.com/llvm/llvm-project/pull/194156

>From 4520860758c347d4e268afd5b10929b96afc6445 Mon Sep 17 00:00:00 2001
From: Anshul Nigham <nigham at google.com>
Date: Sat, 25 Apr 2026 08:52:20 -0700
Subject: [PATCH 1/7] [NewPM][AArch64][GlobalISel] Port
 AArch64PostLegalizerCombiner to NewPM

---
 llvm/lib/Target/AArch64/AArch64.h             |  16 +-
 .../Target/AArch64/AArch64PassRegistry.def    |   2 +
 .../Target/AArch64/AArch64TargetMachine.cpp   |   2 +-
 .../GISel/AArch64PostLegalizerCombiner.cpp    | 253 +++++++++++-------
 .../AArch64/GlobalISel/combine-cast.mir       |   1 +
 .../AArch64/GlobalISel/combine-trunc.mir      |   1 +
 .../form-bitfield-extract-from-and.mir        |   1 +
 .../opt-overlapping-and-postlegalize.mir      |   1 +
 .../postlegalizer-combine-ptr-add-chain.mir   |   1 +
 .../prelegalizercombiner-hoist-same-hands.mir |   1 +
 10 files changed, 175 insertions(+), 104 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64.h b/llvm/lib/Target/AArch64/AArch64.h
index 8cc60d3116a17..7169244c8e7eb 100644
--- a/llvm/lib/Target/AArch64/AArch64.h
+++ b/llvm/lib/Target/AArch64/AArch64.h
@@ -26,6 +26,7 @@
 
 struct AArch64O0PreLegalizerCombinerImplRuleConfig;
 struct AArch64PreLegalizerCombinerImplRuleConfig;
+struct AArch64PostLegalizerCombinerImplRuleConfig;
 struct AArch64PostLegalizerLoweringImplRuleConfig;
 
 namespace llvm {
@@ -102,6 +103,19 @@ class AArch64PreLegalizerCombinerPass
                         MachineFunctionAnalysisManager &MFAM);
 };
 
+class AArch64PostLegalizerCombinerPass
+    : public PassInfoMixin<AArch64PostLegalizerCombinerPass> {
+  std::unique_ptr<AArch64PostLegalizerCombinerImplRuleConfig> RuleConfig;
+
+public:
+  AArch64PostLegalizerCombinerPass();
+  AArch64PostLegalizerCombinerPass(AArch64PostLegalizerCombinerPass &&);
+  ~AArch64PostLegalizerCombinerPass();
+
+  PreservedAnalyses run(MachineFunction &MF,
+                        MachineFunctionAnalysisManager &MFAM);
+};
+
 class AArch64PostSelectOptimizePass
     : public PassInfoMixin<AArch64PostSelectOptimizePass> {
 public:
@@ -156,7 +170,7 @@ void initializeAArch64LowerHomogeneousPrologEpilogPass(PassRegistry &);
 void initializeAArch64MIPeepholeOptLegacyPass(PassRegistry &);
 void initializeAArch64O0PreLegalizerCombinerLegacyPass(PassRegistry &);
 void initializeAArch64PostCoalescerLegacyPass(PassRegistry &);
-void initializeAArch64PostLegalizerCombinerPass(PassRegistry &);
+void initializeAArch64PostLegalizerCombinerLegacyPass(PassRegistry &);
 void initializeAArch64PostSelectOptimizeLegacyPass(PassRegistry &);
 void initializeAArch64PostLegalizerLoweringLegacyPass(PassRegistry &);
 void initializeAArch64PreLegalizerCombinerLegacyPass(PassRegistry &);
diff --git a/llvm/lib/Target/AArch64/AArch64PassRegistry.def b/llvm/lib/Target/AArch64/AArch64PassRegistry.def
index 5f6eed29ae734..ae2b1f73381a9 100644
--- a/llvm/lib/Target/AArch64/AArch64PassRegistry.def
+++ b/llvm/lib/Target/AArch64/AArch64PassRegistry.def
@@ -42,6 +42,8 @@ MACHINE_FUNCTION_PASS("aarch64-post-select-optimize",
                       AArch64PostSelectOptimizePass())
 MACHINE_FUNCTION_PASS("aarch64-postlegalizer-lowering",
                       AArch64PostLegalizerLoweringPass())
+MACHINE_FUNCTION_PASS("aarch64-postlegalizer-combiner",
+                      AArch64PostLegalizerCombinerPass())
 MACHINE_FUNCTION_PASS("aarch64-prelegalizer-combiner",
                       AArch64PreLegalizerCombinerPass())
 MACHINE_FUNCTION_PASS("aarch64-ptrauth", AArch64PointerAuthPass())
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index 04506be1eb28d..56c8108e30292 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -256,7 +256,7 @@ LLVMInitializeAArch64Target() {
   initializeAArch64PreLegalizerCombinerLegacyPass(PR);
   initializeAArch64PointerAuthLegacyPass(PR);
   initializeAArch64PostCoalescerLegacyPass(PR);
-  initializeAArch64PostLegalizerCombinerPass(PR);
+  initializeAArch64PostLegalizerCombinerLegacyPass(PR);
   initializeAArch64PostSelectOptimizeLegacyPass(PR);
   initializeAArch64PostLegalizerLoweringLegacyPass(PR);
   initializeAArch64PromoteConstantPass(PR);
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
index 59349db88289b..8fc07ca4c9edb 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
@@ -19,6 +19,7 @@
 ///
 //===----------------------------------------------------------------------===//
 
+#include "AArch64.h"
 #include "AArch64TargetMachine.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/CodeGen/GlobalISel/CSEInfo.h"
@@ -34,7 +35,9 @@
 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
 #include "llvm/CodeGen/GlobalISel/Utils.h"
 #include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/CodeGen/MachineFunctionAnalysisManager.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachinePassManager.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/TargetOpcodes.h"
 #include "llvm/Support/Debug.h"
@@ -48,12 +51,12 @@
 using namespace llvm;
 using namespace MIPatternMatch;
 
-namespace {
-
 #define GET_GICOMBINER_TYPES
 #include "AArch64GenPostLegalizeGICombiner.inc"
 #undef GET_GICOMBINER_TYPES
 
+namespace {
+
 /// This combine tries do what performExtractVectorEltCombine does in SDAG.
 /// Rewrite for pairwise fadd pattern
 ///   (s32 (g_extract_vector_elt
@@ -630,102 +633,18 @@ AArch64PostLegalizerCombinerImpl::AArch64PostLegalizerCombinerImpl(
 {
 }
 
-class AArch64PostLegalizerCombiner : public MachineFunctionPass {
-public:
-  static char ID;
-
-  AArch64PostLegalizerCombiner(bool IsOptNone = false);
-
-  StringRef getPassName() const override {
-    return "AArch64PostLegalizerCombiner";
-  }
-
-  bool runOnMachineFunction(MachineFunction &MF) override;
-  void getAnalysisUsage(AnalysisUsage &AU) const override;
-
-private:
-  bool IsOptNone;
-  AArch64PostLegalizerCombinerImplRuleConfig RuleConfig;
-
-
-  struct StoreInfo {
-    GStore *St = nullptr;
-    // The G_PTR_ADD that's used by the store. We keep this to cache the
-    // MachineInstr def.
-    GPtrAdd *Ptr = nullptr;
-    // The signed offset to the Ptr instruction.
-    int64_t Offset = 0;
-    LLT StoredType;
-  };
-  bool tryOptimizeConsecStores(SmallVectorImpl<StoreInfo> &Stores,
-                               CSEMIRBuilder &MIB);
-
-  bool optimizeConsecutiveMemOpAddressing(MachineFunction &MF,
-                                          CSEMIRBuilder &MIB);
+struct StoreInfo {
+  GStore *St = nullptr;
+  // The G_PTR_ADD that's used by the store. We keep this to cache the
+  // MachineInstr def.
+  GPtrAdd *Ptr = nullptr;
+  // The signed offset to the Ptr instruction.
+  int64_t Offset = 0;
+  LLT StoredType;
 };
-} // end anonymous namespace
-
-void AArch64PostLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const {
-  AU.setPreservesCFG();
-  getSelectionDAGFallbackAnalysisUsage(AU);
-  AU.addRequired<GISelValueTrackingAnalysisLegacy>();
-  AU.addPreserved<GISelValueTrackingAnalysisLegacy>();
-  if (!IsOptNone) {
-    AU.addRequired<MachineDominatorTreeWrapperPass>();
-    AU.addPreserved<MachineDominatorTreeWrapperPass>();
-    AU.addRequired<GISelCSEAnalysisWrapperPass>();
-    AU.addPreserved<GISelCSEAnalysisWrapperPass>();
-  }
-  MachineFunctionPass::getAnalysisUsage(AU);
-}
-
-AArch64PostLegalizerCombiner::AArch64PostLegalizerCombiner(bool IsOptNone)
-    : MachineFunctionPass(ID), IsOptNone(IsOptNone) {
-  if (!RuleConfig.parseCommandLineOption())
-    report_fatal_error("Invalid rule identifier");
-}
-
-bool AArch64PostLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {
-  if (MF.getProperties().hasFailedISel())
-    return false;
-  assert(MF.getProperties().hasLegalized() && "Expected a legalized function?");
-  const Function &F = MF.getFunction();
-  bool EnableOpt =
-      MF.getTarget().getOptLevel() != CodeGenOptLevel::None && !skipFunction(F);
-
-  const AArch64Subtarget &ST = MF.getSubtarget<AArch64Subtarget>();
-  const auto *LI = ST.getLegalizerInfo();
-
-  GISelValueTracking *VT =
-      &getAnalysis<GISelValueTrackingAnalysisLegacy>().get(MF);
-  MachineDominatorTree *MDT =
-      IsOptNone ? nullptr
-                : &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
-  GISelCSEAnalysisWrapper &Wrapper =
-      getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper();
-  auto *CSEInfo =
-      &Wrapper.get(getStandardCSEConfigForOpt(MF.getTarget().getOptLevel()));
-
-  CombinerInfo CInfo(/*AllowIllegalOps*/ true, /*ShouldLegalizeIllegal*/ false,
-                     /*LegalizerInfo*/ nullptr, EnableOpt, F.hasOptSize(),
-                     F.hasMinSize());
-  // Disable fixed-point iteration to reduce compile-time
-  CInfo.MaxIterations = 1;
-  CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
-  // Legalizer performs DCE, so a full DCE pass is unnecessary.
-  CInfo.EnableFullDCE = false;
-  AArch64PostLegalizerCombinerImpl Impl(MF, CInfo, *VT, CSEInfo, RuleConfig, ST,
-                                        MDT, LI);
-  bool Changed = Impl.combineMachineInstrs();
-
-  auto MIB = CSEMIRBuilder(MF);
-  MIB.setCSEInfo(CSEInfo);
-  Changed |= optimizeConsecutiveMemOpAddressing(MF, MIB);
-  return Changed;
-}
 
-bool AArch64PostLegalizerCombiner::tryOptimizeConsecStores(
-    SmallVectorImpl<StoreInfo> &Stores, CSEMIRBuilder &MIB) {
+static bool tryOptimizeConsecStores(SmallVectorImpl<StoreInfo> &Stores,
+                                    CSEMIRBuilder &MIB) {
   if (Stores.size() <= 2)
     return false;
 
@@ -770,8 +689,8 @@ static cl::opt<bool>
                               cl::desc("Enable consecutive memop optimization "
                                        "in AArch64PostLegalizerCombiner"));
 
-bool AArch64PostLegalizerCombiner::optimizeConsecutiveMemOpAddressing(
-    MachineFunction &MF, CSEMIRBuilder &MIB) {
+static bool optimizeConsecutiveMemOpAddressing(MachineFunction &MF,
+                                               CSEMIRBuilder &MIB) {
   // This combine needs to run after all reassociations/folds on pointer
   // addressing have been done, specifically those that combine two G_PTR_ADDs
   // with constant offsets into a single G_PTR_ADD with a combined offset.
@@ -908,17 +827,147 @@ bool AArch64PostLegalizerCombiner::optimizeConsecutiveMemOpAddressing(
   return Changed;
 }
 
-char AArch64PostLegalizerCombiner::ID = 0;
-INITIALIZE_PASS_BEGIN(AArch64PostLegalizerCombiner, DEBUG_TYPE,
+bool runCombiner(MachineFunction &MF, GISelCSEInfo *CSEInfo,
+                 GISelValueTracking *VT, MachineDominatorTree *MDT,
+                 const AArch64PostLegalizerCombinerImplRuleConfig &RuleConfig,
+                 bool EnableOpt, bool IsOptNone) {
+  if (MF.getProperties().hasFailedISel())
+    return false;
+  assert(MF.getProperties().hasLegalized() && "Expected a legalized function?");
+  const Function &F = MF.getFunction();
+
+  const AArch64Subtarget &ST = MF.getSubtarget<AArch64Subtarget>();
+  const auto *LI = ST.getLegalizerInfo();
+
+  CombinerInfo CInfo(/*AllowIllegalOps=*/true, /*ShouldLegalizeIllegal=*/false,
+                     /*LegalizerInfo=*/nullptr, EnableOpt, F.hasOptSize(),
+                     F.hasMinSize());
+  // Disable fixed-point iteration to reduce compile-time
+  CInfo.MaxIterations = 1;
+  CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
+  // Legalizer performs DCE, so a full DCE pass is unnecessary.
+  CInfo.EnableFullDCE = false;
+  AArch64PostLegalizerCombinerImpl Impl(MF, CInfo, *VT, CSEInfo, RuleConfig, ST,
+                                        MDT, LI);
+  bool Changed = Impl.combineMachineInstrs();
+
+  auto MIB = CSEMIRBuilder(MF);
+  MIB.setCSEInfo(CSEInfo);
+  Changed |= optimizeConsecutiveMemOpAddressing(MF, MIB);
+  return Changed;
+}
+
+class AArch64PostLegalizerCombinerLegacy : public MachineFunctionPass {
+public:
+  static char ID;
+
+  AArch64PostLegalizerCombinerLegacy(bool IsOptNone = false);
+
+  StringRef getPassName() const override {
+    return "AArch64PostLegalizerCombiner";
+  }
+
+  bool runOnMachineFunction(MachineFunction &MF) override;
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+private:
+  bool IsOptNone;
+  AArch64PostLegalizerCombinerImplRuleConfig RuleConfig;
+};
+} // end anonymous namespace
+
+void AArch64PostLegalizerCombinerLegacy::getAnalysisUsage(
+    AnalysisUsage &AU) const {
+  AU.setPreservesCFG();
+  getSelectionDAGFallbackAnalysisUsage(AU);
+  AU.addRequired<GISelValueTrackingAnalysisLegacy>();
+  AU.addPreserved<GISelValueTrackingAnalysisLegacy>();
+  if (!IsOptNone) {
+    AU.addRequired<MachineDominatorTreeWrapperPass>();
+    AU.addPreserved<MachineDominatorTreeWrapperPass>();
+    AU.addRequired<GISelCSEAnalysisWrapperPass>();
+    AU.addPreserved<GISelCSEAnalysisWrapperPass>();
+  }
+  MachineFunctionPass::getAnalysisUsage(AU);
+}
+
+AArch64PostLegalizerCombinerLegacy::AArch64PostLegalizerCombinerLegacy(
+    bool IsOptNone)
+    : MachineFunctionPass(ID), IsOptNone(IsOptNone) {
+  if (!RuleConfig.parseCommandLineOption())
+    report_fatal_error("Invalid rule identifier");
+}
+
+bool AArch64PostLegalizerCombinerLegacy::runOnMachineFunction(
+    MachineFunction &MF) {
+  if (MF.getProperties().hasFailedISel())
+    return false;
+
+  GISelValueTracking *VT =
+      &getAnalysis<GISelValueTrackingAnalysisLegacy>().get(MF);
+  MachineDominatorTree *MDT =
+      IsOptNone ? nullptr
+                : &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
+  GISelCSEAnalysisWrapper &Wrapper =
+      getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper();
+  auto *CSEInfo =
+      &Wrapper.get(getStandardCSEConfigForOpt(MF.getTarget().getOptLevel()));
+
+  bool EnableOpt = MF.getTarget().getOptLevel() != CodeGenOptLevel::None &&
+                   !skipFunction(MF.getFunction());
+
+  return runCombiner(MF, CSEInfo, VT, MDT, RuleConfig, EnableOpt, IsOptNone);
+}
+
+char AArch64PostLegalizerCombinerLegacy::ID = 0;
+INITIALIZE_PASS_BEGIN(AArch64PostLegalizerCombinerLegacy, DEBUG_TYPE,
                       "Combine AArch64 MachineInstrs after legalization", false,
                       false)
 INITIALIZE_PASS_DEPENDENCY(GISelValueTrackingAnalysisLegacy)
-INITIALIZE_PASS_END(AArch64PostLegalizerCombiner, DEBUG_TYPE,
+INITIALIZE_PASS_END(AArch64PostLegalizerCombinerLegacy, DEBUG_TYPE,
                     "Combine AArch64 MachineInstrs after legalization", false,
                     false)
 
+AArch64PostLegalizerCombinerPass::AArch64PostLegalizerCombinerPass()
+    : RuleConfig(
+          std::make_unique<AArch64PostLegalizerCombinerImplRuleConfig>()) {
+  if (!RuleConfig->parseCommandLineOption())
+    reportFatalUsageError("invalid rule identifier");
+}
+
+AArch64PostLegalizerCombinerPass::AArch64PostLegalizerCombinerPass(
+    AArch64PostLegalizerCombinerPass &&) = default;
+
+AArch64PostLegalizerCombinerPass::~AArch64PostLegalizerCombinerPass() = default;
+
+PreservedAnalyses
+AArch64PostLegalizerCombinerPass::run(MachineFunction &MF,
+                                      MachineFunctionAnalysisManager &MFAM) {
+  if (MF.getProperties().hasFailedISel())
+    return PreservedAnalyses::all();
+
+  bool IsOptNone = MF.getTarget().getOptLevel() == CodeGenOptLevel::None;
+  bool EnableOpt = !IsOptNone;
+
+  GISelValueTracking *VT = &MFAM.getResult<GISelValueTrackingAnalysis>(MF);
+  MachineDominatorTree *MDT =
+      IsOptNone ? nullptr : &MFAM.getResult<MachineDominatorTreeAnalysis>(MF);
+  auto *CSEInfo = MFAM.getResult<GISelCSEAnalysis>(MF).get();
+
+  if (!runCombiner(MF, CSEInfo, VT, MDT, *RuleConfig, EnableOpt, IsOptNone))
+    return PreservedAnalyses::all();
+
+  PreservedAnalyses PA = getMachineFunctionPassPreservedAnalyses();
+  PA.preserveSet<CFGAnalyses>();
+  PA.preserve<GISelValueTrackingAnalysis>();
+  if (MDT)
+    PA.preserve<MachineDominatorTreeAnalysis>();
+  PA.preserve<GISelCSEAnalysis>();
+  return PA;
+}
+
 namespace llvm {
 FunctionPass *createAArch64PostLegalizerCombiner(bool IsOptNone) {
-  return new AArch64PostLegalizerCombiner(IsOptNone);
+  return new AArch64PostLegalizerCombinerLegacy(IsOptNone);
 }
 } // end namespace llvm
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-cast.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-cast.mir
index 8eab47171e0d1..5724f36d60183 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-cast.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-cast.mir
@@ -1,6 +1,7 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
 # RUN: llc -o - -mtriple=aarch64-unknown-unknown -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs  %s | FileCheck %s --check-prefixes=CHECK,CHECK-PRE
 # RUN: llc -o - -mtriple=aarch64-unknown-unknown -run-pass=aarch64-postlegalizer-combiner -verify-machineinstrs  %s | FileCheck %s --check-prefixes=CHECK,CHECK-POST
+# RUN: llc -o - -mtriple=aarch64-unknown-unknown -passes=aarch64-postlegalizer-combiner %s | FileCheck %s --check-prefixes=CHECK,CHECK-POST
 
 ---
 name:            test_combine_trunc_select
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-trunc.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-trunc.mir
index 9a2b9dd4b2b60..655e1ddaaa704 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-trunc.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-trunc.mir
@@ -1,6 +1,7 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
 # RUN: llc -o - -mtriple=aarch64-unknown-unknown -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs  %s | FileCheck %s --check-prefixes=CHECK,CHECK-PRE
 # RUN: llc -o - -mtriple=aarch64-unknown-unknown -run-pass=aarch64-postlegalizer-combiner -verify-machineinstrs  %s | FileCheck %s --check-prefixes=CHECK,CHECK-POST
+# RUN: llc -o - -mtriple=aarch64-unknown-unknown -passes=aarch64-postlegalizer-combiner %s | FileCheck %s --check-prefixes=CHECK,CHECK-POST
 
 ---
 name:            test_combine_trunc_undef
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/form-bitfield-extract-from-and.mir b/llvm/test/CodeGen/AArch64/GlobalISel/form-bitfield-extract-from-and.mir
index 16e84a6c1af80..49ffdf4f3ddaf 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/form-bitfield-extract-from-and.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/form-bitfield-extract-from-and.mir
@@ -1,5 +1,6 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
 # RUN: llc -mtriple aarch64 -run-pass=aarch64-postlegalizer-combiner --aarch64postlegalizercombiner-only-enable-rule="bitfield_extract_from_and" -verify-machineinstrs %s -o - | FileCheck %s
+# RUN: llc -mtriple aarch64 -passes=aarch64-postlegalizer-combiner --aarch64postlegalizercombiner-only-enable-rule="bitfield_extract_from_and" %s -o - | FileCheck %s
 # REQUIRES: asserts
 
 # Check that we can combine
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/opt-overlapping-and-postlegalize.mir b/llvm/test/CodeGen/AArch64/GlobalISel/opt-overlapping-and-postlegalize.mir
index 831212d6cb014..eb2dfd10b89f1 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/opt-overlapping-and-postlegalize.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/opt-overlapping-and-postlegalize.mir
@@ -1,5 +1,6 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
 # RUN: llc -debugify-and-strip-all-safe -mtriple arm64-apple-ios -O0 -run-pass=aarch64-postlegalizer-combiner --aarch64postlegalizercombiner-only-enable-rule="overlapping_and" -global-isel -verify-machineinstrs %s -o - | FileCheck %s
+# RUN: llc -debugify-and-strip-all-safe -mtriple arm64-apple-ios -O0 -passes=aarch64-postlegalizer-combiner --aarch64postlegalizercombiner-only-enable-rule="overlapping_and" -global-isel %s -o - | FileCheck %s
 # REQUIRES: asserts
 
 # Test running the overlapping_and combine post-legalization.
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/postlegalizer-combine-ptr-add-chain.mir b/llvm/test/CodeGen/AArch64/GlobalISel/postlegalizer-combine-ptr-add-chain.mir
index cfce267f40096..ec64c9e02791d 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/postlegalizer-combine-ptr-add-chain.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/postlegalizer-combine-ptr-add-chain.mir
@@ -1,5 +1,6 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
 # RUN: llc -mtriple aarch64-apple-ios  -run-pass=aarch64-postlegalizer-combiner --aarch64postlegalizercombiner-only-enable-rule="ptr_add_immed_chain"  %s -o - -verify-machineinstrs | FileCheck %s
+# RUN: llc -mtriple aarch64-apple-ios -passes=aarch64-postlegalizer-combiner --aarch64postlegalizercombiner-only-enable-rule="ptr_add_immed_chain" %s -o - | FileCheck %s
 # REQUIRES: asserts
 
 # Check that we fold two adds of constant offsets with G_PTR_ADD into a single G_PTR_ADD.
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-hoist-same-hands.mir b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-hoist-same-hands.mir
index 1b85cec49226c..7f51b69c1e20e 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-hoist-same-hands.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-hoist-same-hands.mir
@@ -1,6 +1,7 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
 # RUN: llc -mtriple aarch64 -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-PRE
 # RUN: llc -mtriple aarch64 -run-pass=aarch64-postlegalizer-combiner -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-POST
+# RUN: llc -mtriple aarch64 -passes=aarch64-postlegalizer-combiner %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-POST
 
 ---
 name:            or_combine_sext

>From ec69700651b8a8148bf2c8c2471db518bf67006b Mon Sep 17 00:00:00 2001
From: Anshul Nigham <nigham at google.com>
Date: Sat, 25 Apr 2026 13:56:36 -0700
Subject: [PATCH 2/7] Removed redundant MDT preserve

---
 llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
index 29df311bba4dd..12c2754bc167e 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
@@ -962,8 +962,6 @@ AArch64PostLegalizerCombinerPass::run(MachineFunction &MF,
   PreservedAnalyses PA = getMachineFunctionPassPreservedAnalyses();
   PA.preserveSet<CFGAnalyses>();
   PA.preserve<GISelValueTrackingAnalysis>();
-  if (MDT)
-    PA.preserve<MachineDominatorTreeAnalysis>();
   PA.preserve<GISelCSEAnalysis>();
   return PA;
 }

>From de68d8dcae105e4a09fa722a13d86035b18c706a Mon Sep 17 00:00:00 2001
From: Anshul Nigham <nigham at google.com>
Date: Wed, 6 May 2026 23:24:29 -0700
Subject: [PATCH 3/7] Review comments

---
 llvm/lib/Target/AArch64/AArch64.h             |  2 +-
 .../Target/AArch64/AArch64TargetMachine.cpp   | 22 +++++++++++--------
 .../lib/Target/AArch64/AArch64TargetMachine.h |  9 +++++++-
 .../GISel/AArch64PostLegalizerCombiner.cpp    |  6 ++---
 4 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64.h b/llvm/lib/Target/AArch64/AArch64.h
index 730a83cb17114..da4c59b5958e6 100644
--- a/llvm/lib/Target/AArch64/AArch64.h
+++ b/llvm/lib/Target/AArch64/AArch64.h
@@ -143,7 +143,7 @@ class AArch64PostLegalizerLoweringPass
 
 FunctionPass *createAArch64O0PreLegalizerCombiner();
 FunctionPass *createAArch64PreLegalizerCombiner();
-FunctionPass *createAArch64PostLegalizerCombiner(bool IsOptNone);
+FunctionPass *createAArch64PostLegalizerCombinerLegacy(bool IsOptNone);
 FunctionPass *createAArch64PostLegalizerLowering();
 FunctionPass *createAArch64PostSelectOptimize();
 FunctionPass *createAArch64StackTaggingPass(bool IsOptNone);
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index 635ba7fc6fcad..48f7d85b7bcb6 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -281,6 +281,16 @@ LLVMInitializeAArch64Target() {
   initializeAArch64Arm64ECCallLoweringPass(PR);
 }
 
+bool llvm::isGlobalISelOptNone(const TargetMachine *TM) {
+  const bool GlobalISelFlag =
+      getCGPassBuilderOption().EnableGlobalISelOption.value_or(false);
+
+  return TM->getOptLevel() == CodeGenOptLevel::None ||
+         (static_cast<unsigned>(TM->getOptLevel()) >
+              AArch64TargetMachine::getEnableGlobalISelAtO() &&
+          !GlobalISelFlag);
+}
+
 void AArch64TargetMachine::reset() { SubtargetMap.clear(); }
 
 //===----------------------------------------------------------------------===//
@@ -413,7 +423,7 @@ AArch64TargetMachine::AArch64TargetMachine(const Target &T, const Triple &TT,
     setCFIFixup(true);
 }
 
-unsigned AArch64TargetMachine::getEnableGlobalISelAtO() const {
+unsigned AArch64TargetMachine::getEnableGlobalISelAtO() {
   return EnableGlobalISelAtO;
 }
 
@@ -615,13 +625,7 @@ std::unique_ptr<CSEConfigBase> AArch64PassConfig::getCSEConfig() const {
 // globalisel at, and it wasn't enabled via CLI, we know that it must be because
 // of an optnone function.
 bool AArch64PassConfig::isGlobalISelOptNone() const {
-  const bool GlobalISelFlag =
-      getCGPassBuilderOption().EnableGlobalISelOption.value_or(false);
-
-  return getOptLevel() == CodeGenOptLevel::None ||
-         (static_cast<unsigned>(getOptLevel()) >
-              getAArch64TargetMachine().getEnableGlobalISelAtO() &&
-          !GlobalISelFlag);
+  return llvm::isGlobalISelOptNone(&getAArch64TargetMachine());
 }
 
 void AArch64PassConfig::addIRPasses() {
@@ -770,7 +774,7 @@ bool AArch64PassConfig::addLegalizeMachineIR() {
 
 void AArch64PassConfig::addPreRegBankSelect() {
   if (!isGlobalISelOptNone()) {
-    addPass(createAArch64PostLegalizerCombiner(isGlobalISelOptNone()));
+    addPass(createAArch64PostLegalizerCombinerLegacy(isGlobalISelOptNone()));
     if (EnableGISelLoadStoreOptPostLegal)
       addPass(new LoadStoreOpt());
   }
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.h b/llvm/lib/Target/AArch64/AArch64TargetMachine.h
index 209374553d297..09fd5f485da60 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.h
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.h
@@ -21,6 +21,13 @@
 
 namespace llvm {
 
+// This function checks whether the opt level is explicitly set to none,
+// or whether GlobalISel was enabled due to SDAG encountering an optnone
+// function. If the opt level is greater than the level we automatically enable
+// globalisel at, and it wasn't enabled via CLI, we know that it must be because
+// of an optnone function.
+bool isGlobalISelOptNone(const TargetMachine *TM);
+
 class AArch64TargetMachine : public CodeGenTargetMachineImpl {
 protected:
   std::unique_ptr<TargetLoweringObjectFile> TLOF;
@@ -80,7 +87,7 @@ class AArch64TargetMachine : public CodeGenTargetMachineImpl {
       const SmallPtrSetImpl<MachineInstr *> &MIs) const override;
 
   /// Returns the optimisation level that enables GlobalISel.
-  unsigned getEnableGlobalISelAtO() const;
+  static unsigned getEnableGlobalISelAtO();
 
 private:
   bool isLittle;
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
index 12c2754bc167e..313c0bc72f921 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
@@ -948,13 +948,13 @@ AArch64PostLegalizerCombinerPass::run(MachineFunction &MF,
   if (MF.getProperties().hasFailedISel())
     return PreservedAnalyses::all();
 
-  bool IsOptNone = MF.getTarget().getOptLevel() == CodeGenOptLevel::None;
+  bool IsOptNone = llvm::isGlobalISelOptNone(&MF.getTarget());
   bool EnableOpt = !IsOptNone;
 
   GISelValueTracking *VT = &MFAM.getResult<GISelValueTrackingAnalysis>(MF);
   MachineDominatorTree *MDT =
       IsOptNone ? nullptr : &MFAM.getResult<MachineDominatorTreeAnalysis>(MF);
-  auto *CSEInfo = MFAM.getResult<GISelCSEAnalysis>(MF).get();
+  GISelCSEInfo *CSEInfo = MFAM.getResult<GISelCSEAnalysis>(MF).get();
 
   if (!runCombiner(MF, CSEInfo, VT, MDT, *RuleConfig, EnableOpt, IsOptNone))
     return PreservedAnalyses::all();
@@ -967,7 +967,7 @@ AArch64PostLegalizerCombinerPass::run(MachineFunction &MF,
 }
 
 namespace llvm {
-FunctionPass *createAArch64PostLegalizerCombiner(bool IsOptNone) {
+FunctionPass *createAArch64PostLegalizerCombinerLegacy(bool IsOptNone) {
   return new AArch64PostLegalizerCombinerLegacy(IsOptNone);
 }
 } // end namespace llvm

>From e13c5cacfbc67cf2d3eed19c5037d7d430a8d2e8 Mon Sep 17 00:00:00 2001
From: Anshul Nigham <nigham at google.com>
Date: Tue, 12 May 2026 19:50:41 -0700
Subject: [PATCH 4/7] Remove spurious decl

---
 llvm/lib/Target/AArch64/AArch64TargetMachine.h | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.h b/llvm/lib/Target/AArch64/AArch64TargetMachine.h
index 71ae3276d854c..98eaecbb6d2af 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.h
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.h
@@ -21,13 +21,6 @@
 
 namespace llvm {
 
-// This function checks whether the opt level is explicitly set to none,
-// or whether GlobalISel was enabled due to SDAG encountering an optnone
-// function. If the opt level is greater than the level we automatically enable
-// globalisel at, and it wasn't enabled via CLI, we know that it must be because
-// of an optnone function.
-bool isGlobalISelOptNone(const TargetMachine *TM);
-
 class AArch64TargetMachine : public CodeGenTargetMachineImpl {
 protected:
   std::unique_ptr<TargetLoweringObjectFile> TLOF;

>From 5456de4de7b089a7d6ec041a4f079ece6b1c2539 Mon Sep 17 00:00:00 2001
From: Anshul Nigham <nigham at google.com>
Date: Sat, 16 May 2026 12:22:07 -0700
Subject: [PATCH 5/7] Review comments

---
 llvm/lib/Target/AArch64/AArch64.h                         | 4 ++++
 .../Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp | 8 ++++++--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64.h b/llvm/lib/Target/AArch64/AArch64.h
index 5a285c2bd5a16..c85324bf2d998 100644
--- a/llvm/lib/Target/AArch64/AArch64.h
+++ b/llvm/lib/Target/AArch64/AArch64.h
@@ -118,6 +118,10 @@ class AArch64PostLegalizerCombinerPass
 
   PreservedAnalyses run(MachineFunction &MF,
                         MachineFunctionAnalysisManager &MFAM);
+  MachineFunctionProperties getRequiredProperties() const {
+    return MachineFunctionProperties().set(
+        MachineFunctionProperties::Property::Legalized);
+  }
 };
 
 class AArch64PostSelectOptimizePass
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
index 386ede391b972..7073154052d9b 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
@@ -835,11 +835,10 @@ bool runCombiner(MachineFunction &MF, GISelCSEInfo *CSEInfo,
                  bool EnableOpt, bool IsOptNone) {
   if (MF.getProperties().hasFailedISel())
     return false;
-  assert(MF.getProperties().hasLegalized() && "Expected a legalized function?");
   const Function &F = MF.getFunction();
 
   const AArch64Subtarget &ST = MF.getSubtarget<AArch64Subtarget>();
-  const auto *LI = ST.getLegalizerInfo();
+  const LegalizerInfo *LI = ST.getLegalizerInfo();
 
   CombinerInfo CInfo(/*AllowIllegalOps=*/true, /*ShouldLegalizeIllegal=*/false,
                      /*LegalizerInfo=*/nullptr, EnableOpt, F.hasOptSize(),
@@ -872,6 +871,11 @@ class AArch64PostLegalizerCombinerLegacy : public MachineFunctionPass {
   bool runOnMachineFunction(MachineFunction &MF) override;
   void getAnalysisUsage(AnalysisUsage &AU) const override;
 
+  MachineFunctionProperties getRequiredProperties() const override {
+    return MachineFunctionProperties().set(
+        MachineFunctionProperties::Property::Legalized);
+  }
+
 private:
   bool IsOptNone;
   AArch64PostLegalizerCombinerImplRuleConfig RuleConfig;

>From 518204246d348bd5f1724e89836e03f703610315 Mon Sep 17 00:00:00 2001
From: Anshul Nigham <nigham at google.com>
Date: Thu, 21 May 2026 15:36:03 -0700
Subject: [PATCH 6/7] Use Legalizer for CombinerInfo and disallow illegal ops

---
 .../lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
index 7073154052d9b..c57a99a9bccf7 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
@@ -840,8 +840,8 @@ bool runCombiner(MachineFunction &MF, GISelCSEInfo *CSEInfo,
   const AArch64Subtarget &ST = MF.getSubtarget<AArch64Subtarget>();
   const LegalizerInfo *LI = ST.getLegalizerInfo();
 
-  CombinerInfo CInfo(/*AllowIllegalOps=*/true, /*ShouldLegalizeIllegal=*/false,
-                     /*LegalizerInfo=*/nullptr, EnableOpt, F.hasOptSize(),
+  CombinerInfo CInfo(/*AllowIllegalOps=*/false, /*ShouldLegalizeIllegal=*/false,
+                     /*LegalizerInfo=*/LI, EnableOpt, F.hasOptSize(),
                      F.hasMinSize());
   // Disable fixed-point iteration to reduce compile-time
   CInfo.MaxIterations = 1;

>From 4a37b03c964d1358e9208c80822347c860f5e663 Mon Sep 17 00:00:00 2001
From: Anshul Nigham <nigham at google.com>
Date: Wed, 3 Jun 2026 22:25:38 -0700
Subject: [PATCH 7/7] Address review comments

---
 .../Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp   | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
index c57a99a9bccf7..9b30aecb03102 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
@@ -852,7 +852,7 @@ bool runCombiner(MachineFunction &MF, GISelCSEInfo *CSEInfo,
                                         MDT, LI);
   bool Changed = Impl.combineMachineInstrs();
 
-  auto MIB = CSEMIRBuilder(MF);
+  CSEMIRBuilder MIB(MF);
   MIB.setCSEInfo(CSEInfo);
   Changed |= optimizeConsecutiveMemOpAddressing(MF, MIB);
   return Changed;
@@ -901,7 +901,7 @@ AArch64PostLegalizerCombinerLegacy::AArch64PostLegalizerCombinerLegacy(
     bool IsOptNone)
     : MachineFunctionPass(ID), IsOptNone(IsOptNone) {
   if (!RuleConfig.parseCommandLineOption())
-    report_fatal_error("Invalid rule identifier");
+    reportFatalUsageError("Invalid rule identifier");
 }
 
 bool AArch64PostLegalizerCombinerLegacy::runOnMachineFunction(
@@ -954,7 +954,7 @@ AArch64PostLegalizerCombinerPass::run(MachineFunction &MF,
   if (MF.getProperties().hasFailedISel())
     return PreservedAnalyses::all();
 
-  bool IsOptNone = TM->isGlobalISelOptNone();
+  const bool IsOptNone = TM->isGlobalISelOptNone();
   bool EnableOpt = !IsOptNone;
 
   GISelValueTracking *VT = &MFAM.getResult<GISelValueTrackingAnalysis>(MF);



More information about the llvm-commits mailing list