[llvm] [GISel][X86] port X86PreLegalizerCombiner to npm (PR #182638)

Gergo Stomfai via llvm-commits llvm-commits at lists.llvm.org
Sat Feb 21 12:35:37 PST 2026


https://github.com/stomfaig updated https://github.com/llvm/llvm-project/pull/182638

>From 5489c59880d37b6f923a2ee6d2238da0473c8d1c Mon Sep 17 00:00:00 2001
From: stomfaig <stomfaig at gmail.com>
Date: Sat, 21 Feb 2026 00:45:17 +0000
Subject: [PATCH 1/3] port X86PreLegalizerCombiner to npm

---
 .../X86/GISel/X86PreLegalizerCombiner.cpp     | 38 +++++++++++++++++++
 llvm/lib/Target/X86/X86.h                     |  8 ++++
 llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp |  6 +++
 llvm/lib/Target/X86/X86PassRegistry.def       |  1 +
 4 files changed, 53 insertions(+)

diff --git a/llvm/lib/Target/X86/GISel/X86PreLegalizerCombiner.cpp b/llvm/lib/Target/X86/GISel/X86PreLegalizerCombiner.cpp
index 01c3473d16292..14195766bd887 100644
--- a/llvm/lib/Target/X86/GISel/X86PreLegalizerCombiner.cpp
+++ b/llvm/lib/Target/X86/GISel/X86PreLegalizerCombiner.cpp
@@ -171,6 +171,44 @@ INITIALIZE_PASS_END(X86PreLegalizerCombiner, DEBUG_TYPE,
                     false)
 
 namespace llvm {
+
+PreservedAnalyses
+X86PreLegalizerCombinerPass::run(MachineFunction &MF,
+                                 MachineFunctionAnalysisManager &MFAM) {
+  if (MF.getProperties().hasFailedISel())
+    return PreservedAnalyses::all();
+
+  X86PreLegalizerCombinerImplRuleConfig RuleConfig;
+  if (!RuleConfig.parseCommandLineOption())
+    report_fatal_error("Invalid rule identifier");
+
+  auto &CSEInfo = MFAM.getResult<GISelCSEAnalysis>(MF);
+
+  const X86Subtarget &ST = MF.getSubtarget<X86Subtarget>();
+  const LegalizerInfo *LI = ST.getLegalizerInfo();
+
+  const Function &F = MF.getFunction();
+  bool EnableOpt = MF.getTarget().getOptLevel() != CodeGenOptLevel::None;
+  GISelValueTracking &VT = MFAM.getResult<GISelValueTrackingAnalysis>(MF);
+  MachineDominatorTree &MDT = MFAM.getResult<MachineDominatorTreeAnalysis>(MF);
+  CombinerInfo CInfo(/*AllowIllegalOps=*/true, /*ShouldLegalizeIllegal=*/false,
+                     /*LegalizerInfo=*/LI, EnableOpt, F.hasOptSize(),
+                     F.hasMinSize());
+
+  // This is the first Combiner, so the input IR might contain dead
+  // instructions.
+  CInfo.EnableFullDCE = true;
+  X86PreLegalizerCombinerImpl Impl(MF, CInfo, nullptr, VT, CSEInfo.get(),
+                                   RuleConfig, ST, &MDT, LI);
+  Impl.combineMachineInstrs();
+
+  PreservedAnalyses PA = getMachineFunctionPassPreservedAnalyses();
+  PA.preserve<GISelCSEAnalysis>();
+  PA.preserve<GISelValueTrackingAnalysis>();
+  PA.preserve<MachineDominatorTreeAnalysis>();
+  return PA;
+}
+
 FunctionPass *createX86PreLegalizerCombiner() {
   return new X86PreLegalizerCombiner();
 }
diff --git a/llvm/lib/Target/X86/X86.h b/llvm/lib/Target/X86/X86.h
index 9e67c71427853..df259347cce9a 100644
--- a/llvm/lib/Target/X86/X86.h
+++ b/llvm/lib/Target/X86/X86.h
@@ -392,6 +392,14 @@ InstructionSelector *createX86InstructionSelector(const X86TargetMachine &TM,
                                                   const X86RegisterBankInfo &);
 
 FunctionPass *createX86PostLegalizerCombiner();
+
+class X86PreLegalizerCombinerPass
+    : public PassInfoMixin<X86PreLegalizerCombinerPass> {
+public:
+  PreservedAnalyses run(MachineFunction &MF,
+                        MachineFunctionAnalysisManager &MFAM);
+};
+
 FunctionPass *createX86PreLegalizerCombiner();
 
 class X86LoadValueInjectionLoadHardeningPass
diff --git a/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp b/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
index 11d843c8d371e..4f237437a8ca8 100644
--- a/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
+++ b/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
@@ -56,6 +56,7 @@ class X86CodeGenPassBuilder
   // TODO(boomanaiden154): We need to add addRegAssignAndRewriteOptimized here
   // once it is available to support AMX.
   void addAsmPrinter(PassManagerWrapper &PMW, CreateMCStreamer) const;
+  void addPreLegalizeMachineIR(PassManagerWrapper &PMW) const;
 };
 
 void X86CodeGenPassBuilder::addIRPasses(PassManagerWrapper &PMW) const {
@@ -250,6 +251,11 @@ void X86CodeGenPassBuilder::addPreEmitPass2(PassManagerWrapper &PMW) const {
   }
 }
 
+void X86CodeGenPassBuilder::addPreLegalizeMachineIR(
+    PassManagerWrapper &PMW) const {
+  addMachineFunctionPass(X86PreLegalizerCombinerPass(), PMW);
+}
+
 void X86CodeGenPassBuilder::addAsmPrinter(PassManagerWrapper &PMW,
                                           CreateMCStreamer) const {
   // TODO: Add AsmPrinter.
diff --git a/llvm/lib/Target/X86/X86PassRegistry.def b/llvm/lib/Target/X86/X86PassRegistry.def
index 14235f27a55f9..cc2a88d38a0de 100644
--- a/llvm/lib/Target/X86/X86PassRegistry.def
+++ b/llvm/lib/Target/X86/X86PassRegistry.def
@@ -57,6 +57,7 @@ MACHINE_FUNCTION_PASS("x86-lvi-load", X86LoadValueInjectionLoadHardeningPass())
 MACHINE_FUNCTION_PASS("x86-lvi-ret", X86LoadValueInjectionRetHardeningPass())
 MACHINE_FUNCTION_PASS("x86-optimize-leas", X86OptimizeLEAsPass())
 MACHINE_FUNCTION_PASS("x86-pre-tile-config", X86PreTileConfigPass())
+MACHINE_FUNCTION_PASS("x86-pre-legalizer-combiner-pass", X86PreLegalizerCombinerPass())
 MACHINE_FUNCTION_PASS("x86-return-thunks", X86ReturnThunksPass())
 MACHINE_FUNCTION_PASS("x86-seses", X86SpeculativeExecutionSideEffectSuppressionPass())
 MACHINE_FUNCTION_PASS("x86-slh", X86SpeculativeLoadHardeningPass())

>From 88a7a5783a3c8a5eb6afa8042e46a03b5159d4ed Mon Sep 17 00:00:00 2001
From: stomfaig <stomfaig at gmail.com>
Date: Sat, 21 Feb 2026 20:07:57 +0000
Subject: [PATCH 2/3] resolve comments

---
 .../X86/GISel/X86PreLegalizerCombiner.cpp     |  13 +-
 llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp |  12 +-
 .../prelegalizercombiner-trivial-arith.mir    | 520 ++++++++++++++++++
 3 files changed, 532 insertions(+), 13 deletions(-)
 create mode 100644 llvm/test/CodeGen/X86/GlobalISel/prelegalizercombiner-trivial-arith.mir

diff --git a/llvm/lib/Target/X86/GISel/X86PreLegalizerCombiner.cpp b/llvm/lib/Target/X86/GISel/X86PreLegalizerCombiner.cpp
index 14195766bd887..706aab0ec3786 100644
--- a/llvm/lib/Target/X86/GISel/X86PreLegalizerCombiner.cpp
+++ b/llvm/lib/Target/X86/GISel/X86PreLegalizerCombiner.cpp
@@ -55,8 +55,7 @@ class X86PreLegalizerCombinerImpl : public Combiner {
       MachineFunction &MF, CombinerInfo &CInfo, const TargetPassConfig *TPC,
       GISelValueTracking &VT, GISelCSEInfo *CSEInfo,
       const X86PreLegalizerCombinerImplRuleConfig &RuleConfig,
-      const X86Subtarget &STI, MachineDominatorTree *MDT,
-      const LegalizerInfo *LI);
+      MachineDominatorTree *MDT, const LegalizerInfo *LI);
 
   static const char *getName() { return "X86PreLegalizerCombiner"; }
 
@@ -78,10 +77,10 @@ X86PreLegalizerCombinerImpl::X86PreLegalizerCombinerImpl(
     MachineFunction &MF, CombinerInfo &CInfo, const TargetPassConfig *TPC,
     GISelValueTracking &VT, GISelCSEInfo *CSEInfo,
     const X86PreLegalizerCombinerImplRuleConfig &RuleConfig,
-    const X86Subtarget &STI, MachineDominatorTree *MDT, const LegalizerInfo *LI)
+    MachineDominatorTree *MDT, const LegalizerInfo *LI)
     : Combiner(MF, CInfo, TPC, &VT, CSEInfo),
       Helper(Observer, B, /*IsPreLegalize=*/true, &VT, MDT, LI),
-      RuleConfig(RuleConfig), STI(STI),
+      RuleConfig(RuleConfig), STI(MF.getSubtarget<X86Subtarget>()),
 #define GET_GICOMBINER_CONSTRUCTOR_INITS
 #include "X86GenPreLegalizeGICombiner.inc"
 #undef GET_GICOMBINER_CONSTRUCTOR_INITS
@@ -155,7 +154,7 @@ bool X86PreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {
   // instructions.
   CInfo.EnableFullDCE = true;
   X86PreLegalizerCombinerImpl Impl(MF, CInfo, &TPC, *VT, CSEInfo, RuleConfig,
-                                   ST, MDT, LI);
+                                   MDT, LI);
   return Impl.combineMachineInstrs();
 }
 
@@ -199,13 +198,13 @@ X86PreLegalizerCombinerPass::run(MachineFunction &MF,
   // instructions.
   CInfo.EnableFullDCE = true;
   X86PreLegalizerCombinerImpl Impl(MF, CInfo, nullptr, VT, CSEInfo.get(),
-                                   RuleConfig, ST, &MDT, LI);
+                                   RuleConfig, &MDT, LI);
   Impl.combineMachineInstrs();
 
   PreservedAnalyses PA = getMachineFunctionPassPreservedAnalyses();
+  PA.preserveSet<CFGAnalyses>();
   PA.preserve<GISelCSEAnalysis>();
   PA.preserve<GISelValueTrackingAnalysis>();
-  PA.preserve<MachineDominatorTreeAnalysis>();
   return PA;
 }
 
diff --git a/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp b/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
index 4f237437a8ca8..48d768c7c12ac 100644
--- a/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
+++ b/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
@@ -44,6 +44,7 @@ class X86CodeGenPassBuilder
   void addIRPasses(PassManagerWrapper &PMW) const;
   void addPreISel(PassManagerWrapper &PMW) const;
   Error addInstSelector(PassManagerWrapper &PMW) const;
+  void addPreLegalizeMachineIR(PassManagerWrapper &PMW) const;
   void addILPOpts(PassManagerWrapper &PMW) const;
   void addMachineSSAOptimization(PassManagerWrapper &PMW) const;
   void addPreRegAlloc(PassManagerWrapper &PMW) const;
@@ -56,7 +57,6 @@ class X86CodeGenPassBuilder
   // TODO(boomanaiden154): We need to add addRegAssignAndRewriteOptimized here
   // once it is available to support AMX.
   void addAsmPrinter(PassManagerWrapper &PMW, CreateMCStreamer) const;
-  void addPreLegalizeMachineIR(PassManagerWrapper &PMW) const;
 };
 
 void X86CodeGenPassBuilder::addIRPasses(PassManagerWrapper &PMW) const {
@@ -115,6 +115,11 @@ Error X86CodeGenPassBuilder::addInstSelector(PassManagerWrapper &PMW) const {
   return Error::success();
 }
 
+void X86CodeGenPassBuilder::addPreLegalizeMachineIR(
+    PassManagerWrapper &PMW) const {
+  addMachineFunctionPass(X86PreLegalizerCombinerPass(), PMW);
+}
+
 void X86CodeGenPassBuilder::addILPOpts(PassManagerWrapper &PMW) const {
   addMachineFunctionPass(EarlyIfConverterPass(), PMW);
   if (X86EnableMachineCombinerPass) {
@@ -251,11 +256,6 @@ void X86CodeGenPassBuilder::addPreEmitPass2(PassManagerWrapper &PMW) const {
   }
 }
 
-void X86CodeGenPassBuilder::addPreLegalizeMachineIR(
-    PassManagerWrapper &PMW) const {
-  addMachineFunctionPass(X86PreLegalizerCombinerPass(), PMW);
-}
-
 void X86CodeGenPassBuilder::addAsmPrinter(PassManagerWrapper &PMW,
                                           CreateMCStreamer) const {
   // TODO: Add AsmPrinter.
diff --git a/llvm/test/CodeGen/X86/GlobalISel/prelegalizercombiner-trivial-arith.mir b/llvm/test/CodeGen/X86/GlobalISel/prelegalizercombiner-trivial-arith.mir
new file mode 100644
index 0000000000000..c85421a434208
--- /dev/null
+++ b/llvm/test/CodeGen/X86/GlobalISel/prelegalizercombiner-trivial-arith.mir
@@ -0,0 +1,520 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple x86_64 -run-pass=x86-prelegalizer-combiner %s -o - | FileCheck %s
+
+---
+name:            right_ident_sub
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $eax
+    ; Fold (x - 0) -> x
+    ; CHECK-LABEL: name: right_ident_sub
+    ; CHECK: liveins: $eax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(s32) = COPY $eax
+    ; CHECK-NEXT: $eax = COPY %x(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %x:_(s32) = COPY $eax
+    %cst:_(s32) = G_CONSTANT i32 0
+    %op:_(s32) = G_SUB %x(s32), %cst
+    $eax = COPY %op(s32)
+    RET implicit $eax
+
+...
+---
+name:            right_ident_add
+tracksRegLiveness: true
+body:             |
+  bb.1.entry:
+    liveins: $eax
+    ; Fold (x + 0) -> x
+    ; CHECK-LABEL: name: right_ident_add
+    ; CHECK: liveins: $eax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(s32) = COPY $eax
+    ; CHECK-NEXT: $eax = COPY %x(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %x:_(s32) = COPY $eax
+    %cst:_(s32) = G_CONSTANT i32 0
+    %op:_(s32) = G_ADD %x(s32), %cst
+    $eax = COPY %op(s32)
+    RET implicit $eax
+...
+---
+name:            mul_0
+tracksRegLiveness: true
+body:             |
+  bb.1.entry:
+    liveins: $eax
+    ; Fold (x * 0) -> 0
+    ; CHECK-LABEL: name: mul_0
+    ; CHECK: liveins: $eax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %cst:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: $eax = COPY %cst(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %x:_(s32) = COPY $eax
+    %cst:_(s32) = G_CONSTANT i32 0
+    %op:_(s32) = G_MUL %x(s32), %cst
+    $eax = COPY %op(s32)
+    RET implicit $eax
+...
+---
+name:            mul_0_cant_replace
+tracksRegLiveness: true
+body:             |
+  bb.1.entry:
+    liveins: $eax
+    ; Fold (x * 0) -> 0
+    ; CHECK-LABEL: name: mul_0_cant_replace
+    ; CHECK: liveins: $eax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(s32) = COPY $eax
+    ; CHECK-NEXT: %cst:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %op:gpr(s32) = G_MUL %x, %cst
+    ; CHECK-NEXT: $eax = COPY %op(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %x:_(s32) = COPY $eax
+    %cst:_(s32) = G_CONSTANT i32 0
+    %op:gpr(s32) = G_MUL %x(s32), %cst
+    $eax = COPY %op(s32)
+    RET implicit $eax
+...
+---
+name:            sdiv_0
+tracksRegLiveness: true
+body:             |
+  bb.1.entry:
+    liveins: $eax
+    ; Fold (0 / x) -> 0
+    ; CHECK-LABEL: name: sdiv_0
+    ; CHECK: liveins: $eax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %cst:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: $eax = COPY %cst(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %x:_(s32) = COPY $eax
+    %cst:_(s32) = G_CONSTANT i32 0
+    %op:_(s32) = G_SDIV %cst, %x
+    $eax = COPY %op(s32)
+    RET implicit $eax
+...
+---
+name:            udiv_0
+tracksRegLiveness: true
+body:             |
+  bb.1.entry:
+    liveins: $eax
+    ; Fold (0 / x) -> 0
+    ; CHECK-LABEL: name: udiv_0
+    ; CHECK: liveins: $eax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %cst:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: $eax = COPY %cst(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %x:_(s32) = COPY $eax
+    %cst:_(s32) = G_CONSTANT i32 0
+    %op:_(s32) = G_UDIV %cst, %x
+    $eax = COPY %op(s32)
+    RET implicit $eax
+...
+---
+name:            srem_0
+tracksRegLiveness: true
+body:             |
+  bb.1.entry:
+    liveins: $eax
+    ; Fold (0 % x) -> 0
+    ; CHECK-LABEL: name: srem_0
+    ; CHECK: liveins: $eax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %cst:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: $eax = COPY %cst(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %x:_(s32) = COPY $eax
+    %cst:_(s32) = G_CONSTANT i32 0
+    %op:_(s32) = G_SREM %cst, %x
+    $eax = COPY %op(s32)
+    RET implicit $eax
+...
+
+---
+name:            urem_0
+tracksRegLiveness: true
+body:             |
+  bb.1.entry:
+    liveins: $eax
+    ; Fold (0 % x) -> 0
+    ; CHECK-LABEL: name: urem_0
+    ; CHECK: liveins: $eax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %cst:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: $eax = COPY %cst(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %x:_(s32) = COPY $eax
+    %cst:_(s32) = G_CONSTANT i32 0
+    %op:_(s32) = G_UREM %cst, %x
+    $eax = COPY %op(s32)
+    RET implicit $eax
+...
+---
+name:            right_ident_or
+tracksRegLiveness: true
+body:             |
+  bb.1.entry:
+    liveins: $eax
+    ; Fold (x || 0) -> x
+    ; CHECK-LABEL: name: right_ident_or
+    ; CHECK: liveins: $eax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(s32) = COPY $eax
+    ; CHECK-NEXT: $eax = COPY %x(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %x:_(s32) = COPY $eax
+    %cst:_(s32) = G_CONSTANT i32 0
+    %op:_(s32) = G_OR %x(s32), %cst
+    $eax = COPY %op(s32)
+    RET implicit $eax
+...
+
+---
+name:            right_ident_xor
+tracksRegLiveness: true
+body:             |
+  bb.1.entry:
+    liveins: $eax
+    ; Fold (x | 0) -> x
+    ; CHECK-LABEL: name: right_ident_xor
+    ; CHECK: liveins: $eax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(s32) = COPY $eax
+    ; CHECK-NEXT: $eax = COPY %x(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %x:_(s32) = COPY $eax
+    %cst:_(s32) = G_CONSTANT i32 0
+    %op:_(s32) = G_XOR %x(s32), %cst
+    $eax = COPY %op(s32)
+    RET implicit $eax
+...
+---
+name:            right_ident_shl
+tracksRegLiveness: true
+body:             |
+  bb.1.entry:
+    liveins: $eax
+    ; Fold (x << 0) -> x
+    ; CHECK-LABEL: name: right_ident_shl
+    ; CHECK: liveins: $eax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(s32) = COPY $eax
+    ; CHECK-NEXT: $eax = COPY %x(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %x:_(s32) = COPY $eax
+    %cst:_(s32) = G_CONSTANT i32 0
+    %op:_(s32) = G_SHL %x(s32), %cst
+    $eax = COPY %op(s32)
+    RET implicit $eax
+...
+---
+name:            right_ident_ashr
+tracksRegLiveness: true
+body:             |
+  bb.1.entry:
+    liveins: $eax
+    ; Fold (x ashr 0) -> x
+    ; CHECK-LABEL: name: right_ident_ashr
+    ; CHECK: liveins: $eax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(s32) = COPY $eax
+    ; CHECK-NEXT: $eax = COPY %x(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %x:_(s32) = COPY $eax
+    %cst:_(s32) = G_CONSTANT i32 0
+    %op:_(s32) = G_ASHR %x(s32), %cst
+    $eax = COPY %op(s32)
+    RET implicit $eax
+...
+---
+name:            right_ident_lshr
+tracksRegLiveness: true
+body:             |
+  bb.1.entry:
+    liveins: $eax
+    ; Fold (x lshr 0) -> x
+    ; CHECK-LABEL: name: right_ident_lshr
+    ; CHECK: liveins: $eax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(s32) = COPY $eax
+    ; CHECK-NEXT: $eax = COPY %x(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %x:_(s32) = COPY $eax
+    %cst:_(s32) = G_CONSTANT i32 0
+    %op:_(s32) = G_LSHR %x(s32), %cst
+    $eax = COPY %op(s32)
+    RET implicit $eax
+...
+---
+name:            dont_fold_sub
+tracksRegLiveness: true
+body:             |
+  bb.1.entry:
+    liveins: $eax
+    ; Not an identity, no folding.
+    ; CHECK-LABEL: name: dont_fold_sub
+    ; CHECK: liveins: $eax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(s32) = COPY $eax
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 -1
+    ; CHECK-NEXT: %op:_(s32) = G_ADD %x, [[C]]
+    ; CHECK-NEXT: $eax = COPY %op(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %x:_(s32) = COPY $eax
+    %cst:_(s32) = G_CONSTANT i32 1
+    %op:_(s32) = G_SUB %x(s32), %cst
+    $eax = COPY %op(s32)
+    RET implicit $eax
+...
+---
+name:            look_through_zext
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $rax
+    ; CHECK-LABEL: name: look_through_zext
+    ; CHECK: liveins: $rax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %zero:_(s8) = G_CONSTANT i8 0
+    ; CHECK-NEXT: %zext_zero:_(s64) = G_ZEXT %zero(s8)
+    ; CHECK-NEXT: $rax = COPY %zext_zero(s64)
+    ; CHECK-NEXT: RET implicit $rax
+    %zero:_(s8) = G_CONSTANT i8 0
+    %zext_zero:_(s64) = G_ZEXT %zero(s8)
+    %c:_(s64) = G_CONSTANT i64 72340172838076673
+    %mul:_(s64) = G_MUL %c, %zext_zero
+    $rax = COPY %mul(s64)
+    RET implicit $rax
+...
+---
+name:            right_ident_ptr_add
+tracksRegLiveness: true
+body:             |
+  bb.1.entry:
+    liveins: $rax
+    ; Fold (x + 0) -> x
+    ; CHECK-LABEL: name: right_ident_ptr_add
+    ; CHECK: liveins: $rax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(p0) = COPY $rax
+    ; CHECK-NEXT: $rax = COPY %x(p0)
+    ; CHECK-NEXT: RET implicit $rax
+    %x:_(p0) = COPY $rax
+    %cst:_(s64) = G_CONSTANT i64 0
+    %op:_(p0) = G_PTR_ADD %x(p0), %cst
+    $rax = COPY %op(p0)
+    RET implicit $rax
+...
+---
+name:            right_identity_rotl
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $eax, $ebx
+    ; CHECK-LABEL: name: right_identity_rotl
+    ; CHECK: liveins: $eax, $ebx
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %copy:_(s32) = COPY $eax
+    ; CHECK-NEXT: $eax = COPY %copy(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %copy:_(s32) = COPY $eax
+    %zero:_(s32) = G_CONSTANT i32 0
+    %rot:_(s32) = G_ROTL %copy(s32), %zero(s32)
+    $eax = COPY %rot(s32)
+    RET implicit $eax
+...
+---
+name:            right_identity_rotr
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $eax, $ebx
+    ; CHECK-LABEL: name: right_identity_rotr
+    ; CHECK: liveins: $eax, $ebx
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %copy:_(s32) = COPY $eax
+    ; CHECK-NEXT: $eax = COPY %copy(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %copy:_(s32) = COPY $eax
+    %zero:_(s32) = G_CONSTANT i32 0
+    %rot:_(s32) = G_ROTR %copy(s32), %zero(s32)
+    $eax = COPY %rot(s32)
+    RET implicit $eax
+...
+---
+name: lshr_of_vec_zero
+body:             |
+  bb.1:
+  liveins: $xmm0
+    ; CHECK-LABEL: name: lshr_of_vec_zero
+    ; CHECK: liveins: $xmm0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<8 x s16>) = COPY $xmm0
+    ; CHECK-NEXT: $xmm0 = COPY [[COPY]](<8 x s16>)
+    ; CHECK-NEXT: RET implicit $xmm0
+    %0:_(<8 x s16>) = COPY $xmm0
+    %5:_(s16) = G_CONSTANT i16 0
+    %zero_vec:_(<8 x s16>) = G_BUILD_VECTOR %5(s16), %5(s16), %5(s16), %5(s16), %5(s16), %5(s16), %5(s16), %5(s16)
+    %shift:_(<8 x s16>) = G_LSHR %0, %zero_vec(<8 x s16>)
+    $xmm0 = COPY %shift(<8 x s16>)
+    RET implicit $xmm0
+...
+---
+name: ptradd_of_vec_zero
+body:             |
+  bb.1:
+  liveins: $xmm0
+    ; CHECK-LABEL: name: ptradd_of_vec_zero
+    ; CHECK: liveins: $xmm0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<2 x p0>) = COPY $xmm0
+    ; CHECK-NEXT: $xmm0 = COPY [[COPY]](<2 x p0>)
+    ; CHECK-NEXT: RET implicit $xmm0
+    %0:_(<2 x p0>) = COPY $xmm0
+    %5:_(s64) = G_CONSTANT i64 0
+    %zero_vec:_(<2 x s64>) = G_BUILD_VECTOR %5(s64), %5(s64)
+    %ptr:_(<2 x p0>) = G_PTR_ADD %0, %zero_vec(<2 x s64>)
+    $xmm0 = COPY %ptr(<2 x p0>)
+    RET implicit $xmm0
+...
+---
+name:            i128_or_cst
+liveins:
+  - { reg: '$rax' }
+body:             |
+  bb.1:
+    liveins: $rax
+
+    ; CHECK-LABEL: name: i128_or_cst
+    ; CHECK: liveins: $rax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $rax
+    ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(s128) = G_LOAD [[COPY]](p0) :: (load (s128))
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s128) = G_CONSTANT i128 9223372036854775808
+    ; CHECK-NEXT: [[OR:%[0-9]+]]:_(s128) = G_OR [[LOAD]], [[C]]
+    ; CHECK-NEXT: G_STORE [[OR]](s128), [[COPY]](p0) :: (store (s128), align 4)
+    ; CHECK-NEXT: RET 0
+    %0:_(p0) = COPY $rax
+    %2:_(s128) = G_LOAD %0(p0) :: (load (s128))
+    %4:_(s128) = G_CONSTANT i128 9223372036854775808
+    %5:_(s128) = G_OR %2, %4
+    G_STORE %5(s128), %0(p0) :: (store (s128), align 4)
+    RET 0
+...
+---
+name:            mul_1_shift_of_shift
+liveins:
+  - { reg: '$rax' }
+body:             |
+  bb.1:
+    liveins: $rax
+
+    ; CHECK-LABEL: name: mul_1_shift_of_shift
+    ; CHECK: liveins: $rax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $rax
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+    ; CHECK-NEXT: [[SHL:%[0-9]+]]:_(s64) = G_SHL [[COPY]], [[C]](s64)
+    ; CHECK-NEXT: [[OR:%[0-9]+]]:_(s64) = G_OR [[SHL]], [[C]]
+    ; CHECK-NEXT: $rax = COPY [[OR]](s64)
+    ; CHECK-NEXT: RET implicit $rax
+    %0:_(s64) = COPY $rax
+    %1:_(s64) = G_CONSTANT i64 1
+    %2:_(s64) = G_SHL %0, %1(s64)
+    %3:_(s64) = G_OR %2, %1
+    %4:_(s64) = G_MUL %3, %1
+    $rax = COPY %4(s64)
+    RET implicit $rax
+...
+---
+name:            sub_to_add
+tracksRegLiveness: true
+body:             |
+  bb.1.entry:
+    liveins: $eax
+    ; CHECK-LABEL: name: sub_to_add
+    ; CHECK: liveins: $eax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(s32) = COPY $eax
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 -1
+    ; CHECK-NEXT: %op:_(s32) = G_ADD %x, [[C]]
+    ; CHECK-NEXT: $eax = COPY %op(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %x:_(s32) = COPY $eax
+    %cst:_(s32) = G_CONSTANT i32 1
+    %op:_(s32) = G_SUB %x(s32), %cst
+    $eax = COPY %op(s32)
+    RET implicit $eax
+...
+---
+name:            sub_to_add_nuw
+tracksRegLiveness: true
+body:             |
+  bb.1.entry:
+    liveins: $eax
+    ; CHECK-LABEL: name: sub_to_add_nuw
+    ; CHECK: liveins: $eax
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(s32) = COPY $eax
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 -1
+    ; CHECK-NEXT: %op:_(s32) = G_ADD %x, [[C]]
+    ; CHECK-NEXT: $eax = COPY %op(s32)
+    ; CHECK-NEXT: RET implicit $eax
+    %x:_(s32) = COPY $eax
+    %cst:_(s32) = G_CONSTANT i32 1
+    %op:_(s32) = nuw G_SUB %x(s32), %cst
+    $eax = COPY %op(s32)
+    RET implicit $eax
+...
+---
+name:   sub_to_add_nsw_128
+body:             |
+  bb.0:
+    liveins: $eax, $ebx
+
+    ; CHECK-LABEL: name: sub_to_add_nsw_128
+    ; CHECK: liveins: $eax, $ebx
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %a:_(s32) = COPY $eax
+    ; CHECK-NEXT: %b:_(s8) = G_TRUNC %a(s32)
+    ; CHECK-NEXT: %c:_(s8) = G_CONSTANT i8 -128
+    ; CHECK-NEXT: %add:_(s8) = G_ADD %b, %c
+    ; CHECK-NEXT: %d:_(s32) = G_ZEXT %add(s8)
+    ; CHECK-NEXT: $eax = COPY %d(s32)
+    ; CHECK-NEXT: RET implicit $rax
+    %a:_(s32) = COPY $eax
+    %b:_(s8) = G_TRUNC %a
+    %c:_(s8) = G_CONSTANT i8 -128
+    %add:_(s8) = nsw nuw G_SUB %b, %c
+    %d:_(s32) = G_ZEXT %add
+    $eax = COPY %d
+    RET implicit $rax
+...
+---
+name:   sub_to_add_nsw_intmin
+body:             |
+  bb.0:
+    liveins: $eax, $ebx
+
+    ; CHECK-LABEL: name: sub_to_add_nsw_intmin
+    ; CHECK: liveins: $eax, $ebx
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %a:_(s32) = COPY $eax
+    ; CHECK-NEXT: %c:_(s32) = G_CONSTANT i32 -2147483648
+    ; CHECK-NEXT: %add:_(s32) = G_ADD %a, %c
+    ; CHECK-NEXT: $eax = COPY %add(s32)
+    ; CHECK-NEXT: RET implicit $rax
+    %a:_(s32) = COPY $eax
+    %c:_(s32) = G_CONSTANT i32 -2147483648
+    %add:_(s32) = nsw nuw G_SUB %a, %c
+    $eax = COPY %add
+    RET implicit $rax
+...

>From 4997a0a213b0c0b25a458b9870c4cd3c8db0bf7c Mon Sep 17 00:00:00 2001
From: stomfaig <stomfaig at gmail.com>
Date: Sat, 21 Feb 2026 20:35:04 +0000
Subject: [PATCH 3/3] remove LI duplicated dependence

---
 llvm/lib/Target/X86/GISel/X86PreLegalizerCombiner.cpp | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Target/X86/GISel/X86PreLegalizerCombiner.cpp b/llvm/lib/Target/X86/GISel/X86PreLegalizerCombiner.cpp
index 706aab0ec3786..5ab3b4b06771e 100644
--- a/llvm/lib/Target/X86/GISel/X86PreLegalizerCombiner.cpp
+++ b/llvm/lib/Target/X86/GISel/X86PreLegalizerCombiner.cpp
@@ -55,7 +55,7 @@ class X86PreLegalizerCombinerImpl : public Combiner {
       MachineFunction &MF, CombinerInfo &CInfo, const TargetPassConfig *TPC,
       GISelValueTracking &VT, GISelCSEInfo *CSEInfo,
       const X86PreLegalizerCombinerImplRuleConfig &RuleConfig,
-      MachineDominatorTree *MDT, const LegalizerInfo *LI);
+      MachineDominatorTree *MDT);
 
   static const char *getName() { return "X86PreLegalizerCombiner"; }
 
@@ -77,9 +77,10 @@ X86PreLegalizerCombinerImpl::X86PreLegalizerCombinerImpl(
     MachineFunction &MF, CombinerInfo &CInfo, const TargetPassConfig *TPC,
     GISelValueTracking &VT, GISelCSEInfo *CSEInfo,
     const X86PreLegalizerCombinerImplRuleConfig &RuleConfig,
-    MachineDominatorTree *MDT, const LegalizerInfo *LI)
+    MachineDominatorTree *MDT)
     : Combiner(MF, CInfo, TPC, &VT, CSEInfo),
-      Helper(Observer, B, /*IsPreLegalize=*/true, &VT, MDT, LI),
+      Helper(Observer, B, /*IsPreLegalize=*/true, &VT, MDT,
+             MF.getSubtarget<X86Subtarget>().getLegalizerInfo()),
       RuleConfig(RuleConfig), STI(MF.getSubtarget<X86Subtarget>()),
 #define GET_GICOMBINER_CONSTRUCTOR_INITS
 #include "X86GenPreLegalizeGICombiner.inc"
@@ -154,7 +155,7 @@ bool X86PreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {
   // instructions.
   CInfo.EnableFullDCE = true;
   X86PreLegalizerCombinerImpl Impl(MF, CInfo, &TPC, *VT, CSEInfo, RuleConfig,
-                                   MDT, LI);
+                                   MDT);
   return Impl.combineMachineInstrs();
 }
 
@@ -198,7 +199,7 @@ X86PreLegalizerCombinerPass::run(MachineFunction &MF,
   // instructions.
   CInfo.EnableFullDCE = true;
   X86PreLegalizerCombinerImpl Impl(MF, CInfo, nullptr, VT, CSEInfo.get(),
-                                   RuleConfig, &MDT, LI);
+                                   RuleConfig, &MDT);
   Impl.combineMachineInstrs();
 
   PreservedAnalyses PA = getMachineFunctionPassPreservedAnalyses();



More information about the llvm-commits mailing list