[llvm] [GlobalISel] Drop poison flags by default in combiners (PR #218306)

via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 23 19:45:33 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-globalisel

Author: 陈子昂 (Michael-Chen-NJU)

<details>
<summary>Changes</summary>

GlobalISel TableGen combiners were implicitly copying poison-generating flags from the root instruction to newly-created instructions. This is unsafe because the replacement instruction may not preserve the same `nuw`/`nsw` guarantees.

Drop those flags by default for combiners, while keeping explicit `MIFlags` preservation intact.

Fixes #<!-- -->210470

---
Full diff: https://github.com/llvm/llvm-project/pull/218306.diff


6 Files Affected:

- (modified) llvm/include/llvm/CodeGen/GlobalISel/Combiner.h (+2) 
- (modified) llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h (+5) 
- (modified) llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h (+4-1) 
- (modified) llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h (+9-3) 
- (modified) llvm/test/CodeGen/AArch64/GlobalISel/combine-add.mir (+28) 
- (modified) llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir (+197) 


``````````diff
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/Combiner.h b/llvm/include/llvm/CodeGen/GlobalISel/Combiner.h
index bd9a526eae606..bb4c7be459753 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/Combiner.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/Combiner.h
@@ -67,6 +67,8 @@ class LLVM_ABI Combiner : public GIMatchTableExecutor {
 protected:
   virtual bool canMatchOpcode(unsigned Opc) const { return true; }
 
+  bool shouldDropRootPoisonGeneratingFlags() const override { return true; }
+
   const CombinerInfo &CInfo;
   GISelChangeObserver &Observer;
   MachineIRBuilder &B;
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
index 6e3ccf1923c40..ccce4b79f4419 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
@@ -739,6 +739,11 @@ class GIMatchTableExecutor {
     llvm_unreachable("Subclass does not implement runCustomAction!");
   }
 
+  /// Return true to drop root poison-generating flags from the implicit flag
+  /// propagation performed for newly-built instructions. Explicit MIFlags
+  /// actions in the match table still apply to the output instruction.
+  virtual bool shouldDropRootPoisonGeneratingFlags() const { return false; }
+
   LLVM_ABI bool isOperandImmEqual(const MachineOperand &MO, int64_t Value,
                                   const MachineRegisterInfo &MRI,
                                   bool Splat = false) const;
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
index e0720928c6526..1eb6715c4a249 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
@@ -18,6 +18,7 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h"
 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
+#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
 #include "llvm/CodeGen/GlobalISel/Utils.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -58,7 +59,9 @@ bool GIMatchTableExecutor::executeMatchTable(
   // Bypass the flag check on the instruction, and only look at the MCInstrDesc.
   bool NoFPException = !State.MIs[0]->getDesc().mayRaiseFPException();
 
-  const uint32_t Flags = State.MIs[0]->getFlags();
+  uint32_t Flags = State.MIs[0]->getFlags();
+  if (shouldDropRootPoisonGeneratingFlags())
+    Flags &= ~GenericMachineInstr::getPoisonGeneratingFlags();
   bool BuilderInitialized = false;
   const auto initializeBuilder = [&]() {
     if (BuilderInitialized)
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
index 6daa7f3808f43..1a24434bb388f 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
@@ -26,7 +26,7 @@ namespace llvm {
 
 /// A base class for all GenericMachineInstrs.
 class GenericMachineInstr : public MachineInstr {
-  constexpr static unsigned PoisonFlags =
+  constexpr static unsigned PoisonGeneratingFlags =
       NoUWrap | NoSWrap | NoUSWrap | IsExact | Disjoint | NonNeg | FmNoNans |
       FmNoInfs | SameSign | InBounds;
 
@@ -41,10 +41,16 @@ class GenericMachineInstr : public MachineInstr {
     return isPreISelGenericOpcode(MI->getOpcode());
   }
 
-  bool hasPoisonGeneratingFlags() const { return getFlags() & PoisonFlags; }
+  static constexpr unsigned getPoisonGeneratingFlags() {
+    return PoisonGeneratingFlags;
+  }
+
+  bool hasPoisonGeneratingFlags() const {
+    return getFlags() & PoisonGeneratingFlags;
+  }
 
   void dropPoisonGeneratingFlags() {
-    clearFlags(PoisonFlags);
+    clearFlags(PoisonGeneratingFlags);
     assert(!hasPoisonGeneratingFlags());
   }
 };
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-add.mir
index 1bf856cd6f704..2c06724978f05 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-add.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-add.mir
@@ -359,6 +359,34 @@ body:             |
     RET_ReallyLR implicit $w0
 ...
 
+---
+name:            add_shl_neg_nuw
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1, $w2
+
+    ; CHECK-LABEL: name: add_shl_neg_nuw
+    ; CHECK: liveins: $w0, $w1, $w2
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $w1
+    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(i32) = COPY $w2
+    ; CHECK-NEXT: [[SHL:%[0-9]+]]:_(i32) = G_SHL [[COPY1]], [[COPY2]](i32)
+    ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(i32) = G_SUB [[COPY]], [[SHL]]
+    ; CHECK-NEXT: $w0 = COPY [[SUB]](i32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %0:_(i32) = COPY $w0
+    %1:_(i32) = COPY $w1
+    %2:_(i32) = COPY $w2
+    %3:_(i32) = G_CONSTANT i32 0
+    %4:_(i32) = G_SUB %3, %1
+    %5:_(i32) = G_SHL %4, %2
+    %6:_(i32) = nuw G_ADD %0, %5
+    $w0 = COPY %6
+    RET_ReallyLR implicit $w0
+...
+
 ---
 name:            add_shl_neg_commuted
 tracksRegLiveness: true
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index 3de9527bb3584..3f57fb256873d 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -24,6 +24,29 @@ body:             |
     $x0 = COPY %sub
     RET_ReallyLR implicit $x0
 
+...
+---
+name:   APlusBMinusCMinusB_nuw
+body:             |
+  bb.0:
+    liveins: $x0, $x1, $x2
+    ; CHECK-LABEL: name: APlusBMinusCMinusB_nuw
+    ; CHECK: liveins: $x0, $x1, $x2
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %a:_(i64) = COPY $x0
+    ; CHECK-NEXT: %c:_(i64) = COPY $x2
+    ; CHECK-NEXT: %sub:_(i64) = G_SUB %a, %c
+    ; CHECK-NEXT: $x0 = COPY %sub(i64)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %a:_(i64) = COPY $x0
+    %b:_(i64) = COPY $x1
+    %c:_(i64) = COPY $x2
+    %sub1:_(i64) = G_SUB %b, %c
+    %add1:_(i64) = G_ADD %a, %sub1
+    %sub:_(i64) = nuw G_SUB %add1, %b
+    $x0 = COPY %sub
+    RET_ReallyLR implicit $x0
+
 ...
 ---
 name:   AMinusBMinusCMinusC
@@ -47,6 +70,29 @@ body:             |
     $x0 = COPY %sub
     RET_ReallyLR implicit $x0
 
+...
+---
+name:   AMinusBMinusCMinusC_nuw
+body:             |
+  bb.0:
+    liveins: $x0, $x1, $x2
+    ; CHECK-LABEL: name: AMinusBMinusCMinusC_nuw
+    ; CHECK: liveins: $x0, $x1, $x2
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %a:_(i64) = COPY $x0
+    ; CHECK-NEXT: %b:_(i64) = COPY $x1
+    ; CHECK-NEXT: %sub:_(i64) = G_SUB %a, %b
+    ; CHECK-NEXT: $x0 = COPY %sub(i64)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %a:_(i64) = COPY $x0
+    %b:_(i64) = COPY $x1
+    %c:_(i64) = COPY $x2
+    %sub1:_(i64) = G_SUB %b, %c
+    %sub2:_(i64) = G_SUB %a, %sub1
+    %sub:_(i64) = nuw G_SUB %sub2, %c
+    $x0 = COPY %sub
+    RET_ReallyLR implicit $x0
+
 ...
 ---
 name:   ZeroMinusAPlusB
@@ -190,6 +236,31 @@ body:             |
     $x0 = COPY %add
     RET_ReallyLR implicit $x0
 
+...
+---
+name:   AMinusBPlusCMinusA_nuw
+body:             |
+  bb.0:
+    liveins: $x0, $x1, $x2
+
+    ; CHECK-LABEL: name: AMinusBPlusCMinusA_nuw
+    ; CHECK: liveins: $x0, $x1, $x2
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %b:_(i64) = COPY $x1
+    ; CHECK-NEXT: %c:_(i64) = COPY $x2
+    ; CHECK-NEXT: %add:_(i64) = G_SUB %c, %b
+    ; CHECK-NEXT: $x0 = COPY %add(i64)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %a:_(i64) = COPY $x0
+    %b:_(i64) = COPY $x1
+    %c:_(i64) = COPY $x2
+    %zero:_(i64) = G_CONSTANT i64 0
+    %sub2:_(i64) = G_SUB %c, %a
+    %sub1:_(i64) = G_SUB %a, %b
+    %add:_(i64) = nuw G_ADD %sub1, %sub2
+    $x0 = COPY %add
+    RET_ReallyLR implicit $x0
+
 ...
 ---
 name:   AMinusBPlusBMinusC
@@ -216,6 +287,32 @@ body:             |
     RET_ReallyLR implicit $x0
 
 
+...
+---
+name:   AMinusBPlusBMinusC_nuw
+body:             |
+  bb.0:
+    liveins: $x0, $x1, $x2
+
+    ; CHECK-LABEL: name: AMinusBPlusBMinusC_nuw
+    ; CHECK: liveins: $x0, $x1, $x2
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %a:_(i64) = COPY $x0
+    ; CHECK-NEXT: %c:_(i64) = COPY $x2
+    ; CHECK-NEXT: %add:_(i64) = G_SUB %a, %c
+    ; CHECK-NEXT: $x0 = COPY %add(i64)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %a:_(i64) = COPY $x0
+    %b:_(i64) = COPY $x1
+    %c:_(i64) = COPY $x2
+    %zero:_(i64) = G_CONSTANT i64 0
+    %sub2:_(i64) = G_SUB %b, %c
+    %sub1:_(i64) = G_SUB %a, %b
+    %add:_(i64) = nuw G_ADD %sub1, %sub2
+    $x0 = COPY %add
+    RET_ReallyLR implicit $x0
+
+
 ...
 ---
 name:   APlusBMinusAplusC
@@ -241,6 +338,31 @@ body:             |
     $x0 = COPY %add
     RET_ReallyLR implicit $x0
 
+...
+---
+name:   APlusBMinusAplusC_nuw
+body:             |
+  bb.0:
+    liveins: $x0, $x1, $x2
+
+    ; CHECK-LABEL: name: APlusBMinusAplusC_nuw
+    ; CHECK: liveins: $x0, $x1, $x2
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %b:_(i64) = COPY $x1
+    ; CHECK-NEXT: %c:_(i64) = COPY $x2
+    ; CHECK-NEXT: %add:_(i64) = G_SUB %b, %c
+    ; CHECK-NEXT: $x0 = COPY %add(i64)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %a:_(i64) = COPY $x0
+    %b:_(i64) = COPY $x1
+    %c:_(i64) = COPY $x2
+    %zero:_(i64) = G_CONSTANT i64 0
+    %add1:_(i64) = G_ADD %a, %c
+    %sub1:_(i64) = G_SUB %b, %add1
+    %add:_(i64) = nuw G_ADD %a, %sub1
+    $x0 = COPY %add
+    RET_ReallyLR implicit $x0
+
 ...
 ---
 name:   APlusBMinusCPlusA
@@ -266,6 +388,31 @@ body:             |
     $x0 = COPY %add
     RET_ReallyLR implicit $x0
 
+...
+---
+name:   APlusBMinusCPlusA_nuw
+body:             |
+  bb.0:
+    liveins: $x0, $x1, $x2
+
+    ; CHECK-LABEL: name: APlusBMinusCPlusA_nuw
+    ; CHECK: liveins: $x0, $x1, $x2
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %b:_(i64) = COPY $x1
+    ; CHECK-NEXT: %c:_(i64) = COPY $x2
+    ; CHECK-NEXT: %add:_(i64) = G_SUB %b, %c
+    ; CHECK-NEXT: $x0 = COPY %add(i64)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %a:_(i64) = COPY $x0
+    %b:_(i64) = COPY $x1
+    %c:_(i64) = COPY $x2
+    %zero:_(i64) = G_CONSTANT i64 0
+    %add1:_(i64) = G_ADD %c, %a
+    %sub1:_(i64) = G_SUB %b, %add1
+    %add:_(i64) = nuw G_ADD %a, %sub1
+    $x0 = COPY %add
+    RET_ReallyLR implicit $x0
+
 ...
 ---
 name:   APlusBMinusCPlusA_BV
@@ -496,6 +643,56 @@ body:             |
     $x0 = COPY %sub2
     RET_ReallyLR implicit $x0
 
+...
+---
+name:   AMinusBMinusC_nuw
+body:             |
+  bb.0:
+    liveins: $x0, $x1, $x2
+
+    ; CHECK-LABEL: name: AMinusBMinusC_nuw
+    ; CHECK: liveins: $x0, $x1, $x2
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %a:_(i64) = COPY $x0
+    ; CHECK-NEXT: %b:_(i64) = COPY $x1
+    ; CHECK-NEXT: %c:_(i64) = COPY $x2
+    ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(i64) = G_SUB %c, %b
+    ; CHECK-NEXT: %sub2:_(i64) = G_ADD %a, [[SUB]]
+    ; CHECK-NEXT: $x0 = COPY %sub2(i64)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %a:_(i64) = COPY $x0
+    %b:_(i64) = COPY $x1
+    %c:_(i64) = COPY $x2
+    %sub1:_(i64) = G_SUB %b, %c
+    %sub2:_(i64) = nuw G_SUB %a, %sub1
+    $x0 = COPY %sub2
+    RET_ReallyLR implicit $x0
+
+...
+---
+name:   AMinusBMinusC_nsw
+body:             |
+  bb.0:
+    liveins: $x0, $x1, $x2
+
+    ; CHECK-LABEL: name: AMinusBMinusC_nsw
+    ; CHECK: liveins: $x0, $x1, $x2
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %a:_(i64) = COPY $x0
+    ; CHECK-NEXT: %b:_(i64) = COPY $x1
+    ; CHECK-NEXT: %c:_(i64) = COPY $x2
+    ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(i64) = G_SUB %c, %b
+    ; CHECK-NEXT: %sub2:_(i64) = G_ADD %a, [[SUB]]
+    ; CHECK-NEXT: $x0 = COPY %sub2(i64)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %a:_(i64) = COPY $x0
+    %b:_(i64) = COPY $x1
+    %c:_(i64) = COPY $x2
+    %sub1:_(i64) = G_SUB %b, %c
+    %sub2:_(i64) = nsw G_SUB %a, %sub1
+    $x0 = COPY %sub2
+    RET_ReallyLR implicit $x0
+
 ...
 ---
 name:   AMinusZeroMinusB

``````````

</details>


https://github.com/llvm/llvm-project/pull/218306


More information about the llvm-commits mailing list