[llvm] 66e8cc5 - [ConstraintElim] Handle (X | Y) >s -1 as X >s -1 && Y >s -1. (#209743)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 16 05:51:34 PDT 2026
Author: Florian Hahn
Date: 2026-07-16T13:51:29+01:00
New Revision: 66e8cc5ec83d7ec5e506c53b11c1d22887c0c418
URL: https://github.com/llvm/llvm-project/commit/66e8cc5ec83d7ec5e506c53b11c1d22887c0c418
DIFF: https://github.com/llvm/llvm-project/commit/66e8cc5ec83d7ec5e506c53b11c1d22887c0c418.diff
LOG: [ConstraintElim] Handle (X | Y) >s -1 as X >s -1 && Y >s -1. (#209743)
InstCombine canonicalizes X >=s 0 && Y >=s 0 as (X | Y) >=s 0. Teach
ConstraintElimination to recover the signed-positive information by
looking through compares of binary ORs.
Alive2 Proof: https://alive2.llvm.org/ce/z/sqNF8M
Compile-time impact is neutral
https://llvm-compile-time-tracker.com/compare.php?from=88acd428fd72f44312408c3fb6165992fb3b043a&to=a2aa4cacb953b32d6319939b9aee3226a7294334&stat=instructions%3Au
PR: https://github.com/llvm/llvm-project/pull/209743
Added:
Modified:
llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
llvm/test/Transforms/ConstraintElimination/or-non-negative.ll
llvm/test/Transforms/PhaseOrdering/constraint-eliminiation-interactions.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index b244445c6e51f..f1f800cd69d60 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1996,6 +1996,26 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
DFSInStack);
}
+ // (X | Y) >s -1 implies X >s -1 and Y >s -1, because the sign bit of an
+ // OR is the OR of the operand sign bits. Look through this
+ // canonicalization by InstCombine.
+ if (Pred == CmpInst::ICMP_SGT && match(B, m_AllOnes())) {
+ SmallVector<Value *> OrWorklist = {A};
+ SmallPtrSet<Value *, 4> SeenOr;
+ Value *X, *Y;
+ while (!OrWorklist.empty()) {
+ Value *Cur = OrWorklist.pop_back_val();
+ if (!match(Cur, m_Or(m_Value(X), m_Value(Y))))
+ continue;
+ for (Value *Op : {X, Y}) {
+ if (!SeenOr.insert(Op).second)
+ continue;
+ OrWorklist.push_back(Op);
+ Info.addFact(Pred, Op, B, CB.NumIn, CB.NumOut, DFSInStack);
+ }
+ }
+ }
+
if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size()) {
// Add dummy entries to ReproducerCondStack to keep it in sync with
// DFSInStack.
diff --git a/llvm/test/Transforms/ConstraintElimination/or-non-negative.ll b/llvm/test/Transforms/ConstraintElimination/or-non-negative.ll
index b8413acbbf2cf..138ea41198b91 100644
--- a/llvm/test/Transforms/ConstraintElimination/or-non-negative.ll
+++ b/llvm/test/Transforms/ConstraintElimination/or-non-negative.ll
@@ -17,8 +17,7 @@ define i1 @or_non_negative_bounds(i64 %a, i64 %b, i64 %c, i64 %d) {
; CHECK-NEXT: br i1 [[AND_3]], label %[[THEN:.*]], label %[[ELSE:.*]]
; CHECK: [[THEN]]:
; CHECK-NEXT: [[IDX:%.*]] = add nsw i64 [[D]], [[B]]
-; CHECK-NEXT: [[RES:%.*]] = icmp ult i64 [[IDX]], [[A]]
-; CHECK-NEXT: ret i1 [[RES]]
+; CHECK-NEXT: ret i1 true
; CHECK: [[ELSE]]:
; CHECK-NEXT: ret i1 false
;
@@ -76,8 +75,7 @@ define i1 @or_non_negative_nested(i64 %a, i64 %b, i64 %c) {
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[O2]], -1
; CHECK-NEXT: br i1 [[CMP]], label %[[THEN:.*]], label %[[ELSE:.*]]
; CHECK: [[THEN]]:
-; CHECK-NEXT: [[RES:%.*]] = icmp sge i64 [[C]], 0
-; CHECK-NEXT: ret i1 [[RES]]
+; CHECK-NEXT: ret i1 true
; CHECK: [[ELSE]]:
; CHECK-NEXT: ret i1 false
;
diff --git a/llvm/test/Transforms/PhaseOrdering/constraint-eliminiation-interactions.ll b/llvm/test/Transforms/PhaseOrdering/constraint-eliminiation-interactions.ll
index a5a1fcb97541a..375649d8790e9 100644
--- a/llvm/test/Transforms/PhaseOrdering/constraint-eliminiation-interactions.ll
+++ b/llvm/test/Transforms/PhaseOrdering/constraint-eliminiation-interactions.ll
@@ -70,16 +70,10 @@ define noundef i64 @or_sge_canonicalization(ptr noundef %p, i64 noundef %a, i64
; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i64 [[TMP1]], -1
; CHECK-NEXT: [[AND_3:%.*]] = and i1 [[CMP_3]], [[TMP2]]
; CHECK-NEXT: [[AND_4:%.*]] = and i1 [[CMP_5]], [[AND_3]]
-; CHECK-NEXT: br i1 [[AND_4]], label %[[THEN:.*]], label %[[ELSE:.*]]
-; CHECK: [[THEN]]:
-; CHECK-NEXT: [[IDX:%.*]] = add nuw nsw i64 [[D]], [[B]]
-; CHECK-NEXT: [[OOB_NOT:%.*]] = icmp ult i64 [[IDX]], [[A]]
-; CHECK-NEXT: br i1 [[OOB_NOT]], label %[[CONT:.*]], label %[[TRAP:.*]]
-; CHECK: [[TRAP]]:
-; CHECK-NEXT: tail call void @llvm.trap()
-; CHECK-NEXT: unreachable
+; CHECK-NEXT: br i1 [[AND_4]], label %[[CONT:.*]], label %[[ELSE:.*]]
; CHECK: [[CONT]]:
-; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [8 x i8], ptr [[P]], i64 [[IDX]]
+; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw [8 x i8], ptr [[P]], i64 [[D]]
+; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [8 x i8], ptr [[TMP3]], i64 [[B]]
; CHECK-NEXT: [[V:%.*]] = load i64, ptr [[ARRAYIDX]], align 8
; CHECK-NEXT: br label %[[ELSE]]
; CHECK: [[ELSE]]:
More information about the llvm-commits
mailing list