[llvm] b22c8a6 - [ConstraintElimination] Defer removal of simplified ssub.with.overflow (#215135)

via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 10 02:23:51 PDT 2026


Author: Florian Hahn
Date: 2026-08-10T09:23:45Z
New Revision: b22c8a65c266ad3b3aac1a9344d2a5b01e946ded

URL: https://github.com/llvm/llvm-project/commit/b22c8a65c266ad3b3aac1a9344d2a5b01e946ded
DIFF: https://github.com/llvm/llvm-project/commit/b22c8a65c266ad3b3aac1a9344d2a5b01e946ded.diff

LOG: [ConstraintElimination] Defer removal of simplified ssub.with.overflow (#215135)

replaceSubOverflowUses erased the intrinsic as soon as it became dead.
That frees the intrinsic's operand Use array, but the worklist can still
hold UseCheck entries pointing into it, storing a now invalid pointer to
a Use *.

Instead of erasing the intrinsic in place, poison its arguments and push
it onto ToRemove.

PR: https://github.com/llvm/llvm-project/pull/215135

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
    llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index b31ae075e8f4a..f77426f2b6322 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1950,7 +1950,10 @@ static bool replaceSubOverflowUses(IntrinsicInst *II, Value *A, Value *B,
   }
 
   if (II->use_empty()) {
-    II->eraseFromParent();
+    // Do not erase II here: the worklist may still hold Uses of II's operands.
+    for (Use &Arg : II->args())
+      Arg.set(PoisonValue::get(Arg->getType()));
+    ToRemove.push_back(II);
     Changed = true;
   }
   return Changed;

diff  --git a/llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll b/llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll
index 4a270881bebf8..9077c3647589d 100644
--- a/llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll
+++ b/llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll
@@ -2,6 +2,7 @@
 ; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
 
 declare { i8, i1 } @llvm.ssub.with.overflow.i8(i8, i8)
+declare { i1, i1 } @llvm.ssub.with.overflow.i1(i1, i1)
 
 define i8 @ssub_no_overflow_due_to_or_conds(i8 %a, i8 %b) {
 ; CHECK-LABEL: @ssub_no_overflow_due_to_or_conds(
@@ -349,3 +350,48 @@ exit.ok:
 exit.fail:
   ret i8 0
 }
+
+; The arguments of the intrinsic are compares that are themselves checked, and
+; the block holding the intrinsic comes before the block defining them.
+define i1 @ssub_simplified_before_uses_of_arguments(i32 %a) {
+; CHECK-LABEL: @ssub_simplified_before_uses_of_arguments(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[CHECK_1:%.*]]
+; CHECK:       math:
+; CHECK-NEXT:    [[TMP0:%.*]] = sub nsw i1 [[C:%.*]], [[D:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = or i1 [[TMP0]], false
+; CHECK-NEXT:    ret i1 [[R]]
+; CHECK:       check.1:
+; CHECK-NEXT:    [[C]] = icmp sgt i32 [[A:%.*]], 0
+; CHECK-NEXT:    [[D]] = icmp sgt i32 [[A]], 1
+; CHECK-NEXT:    [[C_1:%.*]] = icmp sge i1 [[C]], [[D]]
+; CHECK-NEXT:    br i1 [[C_1]], label [[CHECK_2:%.*]], label [[EXIT:%.*]]
+; CHECK:       check.2:
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i1 [[D]], false
+; CHECK-NEXT:    br i1 [[C_2]], label [[MATH:%.*]], label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  br label %check.1
+
+math:
+  %op = call { i1, i1 } @llvm.ssub.with.overflow.i1(i1 %c, i1 %d)
+  %res = extractvalue { i1, i1 } %op, 0
+  %status = extractvalue { i1, i1 } %op, 1
+  %r = or i1 %res, %status
+  ret i1 %r
+
+check.1:
+  %c = icmp sgt i32 %a, 0
+  %d = icmp sgt i32 %a, 1
+  %c.1 = icmp sge i1 %c, %d
+  br i1 %c.1, label %check.2, label %exit
+
+check.2:
+  %c.2 = icmp sge i1 %d, 0
+  br i1 %c.2, label %math, label %exit
+
+exit:
+  ret i1 false
+}


        


More information about the llvm-commits mailing list