[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