[llvm] Fold icmp eq A, 0 | icmp ult B, sub 0, A to overflow (PR #152762)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 8 10:39:10 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: AZero13 (AZero13)
<details>
<summary>Changes</summary>
https://alive2.llvm.org/ce/z/-4HvMR
---
Full diff: https://github.com/llvm/llvm-project/pull/152762.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp (+33)
- (added) llvm/test/Transforms/InstCombine/neg-and-zero.ll (+63)
``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index d7971e8e3caea..17ebc1f34740c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3359,6 +3359,39 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
}
}
+ // Canonicalize the unsigned-add overflow/non-overflow boolean patterns:
+ // (icmp eq A, 0) | (icmp ult B, sub 0, A) --> icmp ule B, ~A
+ // (icmp ne A, 0) & (icmp uge B, sub 0, A) --> icmp ugt B, ~A
+ // Accept commuted order of the two icmps within the or/and, and
+ // commuted operand order within the ULT/UGE compare.
+ {
+ Value *A, *B;
+ // Try (LHS,RHS) order
+ if (PredL == (IsAnd ? ICmpInst::ICMP_NE : ICmpInst::ICMP_EQ) &&
+ match(LHS0, m_Value(A)) && match(LHS1, m_Zero()) &&
+ ((PredR == (IsAnd ? ICmpInst::ICMP_UGE : ICmpInst::ICMP_ULT) &&
+ ((match(RHS0, m_Value(B)) && match(RHS1, m_Neg(m_Specific(A)))) ||
+ (match(RHS1, m_Value(B)) && match(RHS0, m_Neg(m_Specific(A)))))))) {
+ if (IsLogical && !isGuaranteedNotToBePoison(B))
+ return nullptr;
+ Value *NotA = Builder.CreateNot(A);
+ return Builder.CreateICmp(IsAnd ? ICmpInst::ICMP_UGT : ICmpInst::ICMP_ULE,
+ B, NotA);
+ }
+ // Try (RHS,LHS) order
+ if (PredR == (IsAnd ? ICmpInst::ICMP_NE : ICmpInst::ICMP_EQ) &&
+ match(RHS0, m_Value(A)) && match(RHS1, m_Zero()) &&
+ ((PredL == (IsAnd ? ICmpInst::ICMP_UGE : ICmpInst::ICMP_ULT) &&
+ ((match(LHS0, m_Value(B)) && match(LHS1, m_Neg(m_Specific(A)))) ||
+ (match(LHS1, m_Value(B)) && match(LHS0, m_Neg(m_Specific(A)))))))) {
+ if (IsLogical && !isGuaranteedNotToBePoison(B))
+ return nullptr;
+ Value *NotA = Builder.CreateNot(A);
+ return Builder.CreateICmp(IsAnd ? ICmpInst::ICMP_UGT : ICmpInst::ICMP_ULE,
+ B, NotA);
+ }
+ }
+
if (Value *V =
foldAndOrOfICmpEqConstantAndICmp(LHS, RHS, IsAnd, IsLogical, Builder))
return V;
diff --git a/llvm/test/Transforms/InstCombine/neg-and-zero.ll b/llvm/test/Transforms/InstCombine/neg-and-zero.ll
new file mode 100644
index 0000000000000..bb96a865a656a
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/neg-and-zero.ll
@@ -0,0 +1,63 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i32 @non_overflow(i32 %0, i32 %1) {
+; CHECK-LABEL: @non_overflow(
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ule i32 [[TMP1:%.*]], [[TMP3]]
+; CHECK-NEXT: [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT: ret i32 [[TMP5]]
+;
+ %3 = icmp eq i32 %0, 0
+ %4 = sub i32 0, %0
+ %5 = icmp ult i32 %1, %4
+ %6 = or i1 %3, %5
+ %7 = zext i1 %6 to i32
+ ret i32 %7
+}
+
+define i32 @overflow(i32 %0, i32 %1) {
+; CHECK-LABEL: @overflow(
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ugt i32 [[TMP1:%.*]], [[TMP3]]
+; CHECK-NEXT: [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT: ret i32 [[TMP5]]
+;
+ %3 = sub i32 0, %0
+ %4 = icmp ne i32 %0, 0
+ %5 = icmp uge i32 %1, %3
+ %6 = and i1 %4, %5
+ %7 = zext i1 %6 to i32
+ ret i32 %7
+}
+
+
+define i32 @non_overflow_flipped(i32 %0, i32 %1) {
+; CHECK-LABEL: @non_overflow_flipped(
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ule i32 [[TMP1:%.*]], [[TMP3]]
+; CHECK-NEXT: [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT: ret i32 [[TMP5]]
+;
+ %3 = icmp eq i32 %0, 0
+ %4 = sub i32 0, %0
+ %5 = icmp ugt i32 %4, %1
+ %6 = or i1 %3, %5
+ %7 = zext i1 %6 to i32
+ ret i32 %7
+}
+
+define i32 @overflow_flipped(i32 %0, i32 %1) {
+; CHECK-LABEL: @overflow_flipped(
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ugt i32 [[TMP1:%.*]], [[TMP3]]
+; CHECK-NEXT: [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT: ret i32 [[TMP5]]
+;
+ %3 = sub i32 0, %0
+ %4 = icmp ne i32 %0, 0
+ %5 = icmp ule i32 %3, %1
+ %6 = and i1 %4, %5
+ %7 = zext i1 %6 to i32
+ ret i32 %7
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/152762
More information about the llvm-commits
mailing list