From 7d6888eda95f1e2715a3d77a58972c730465f4c2 Mon Sep 17 00:00:00 2001 From: Bobby Song Date: Thu, 29 May 2025 16:09:45 +0100 Subject: [PATCH 1/5] Add test case for issue 141479 --- .../and-comparison-not-always-false.ll | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll diff --git a/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll b/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll new file mode 100644 index 0000000000000..174d97d30bcf8 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll @@ -0,0 +1,21 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=instcombine -S | FileCheck %s +define i1 @test(i32 %0, i32 %1) { +; CHECK-LABEL: define i1 @test( +; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) { +; CHECK-NEXT: [[COMMON_RET:.*:]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP0]], -1 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ule i32 [[TMP1]], [[TMP2]] +; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: [[TMP5:%.*]] = icmp ugt i32 [[TMP0]], [[TMP4]] +; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = and i1 [[TMP3]], [[TMP5]] +; CHECK-NEXT: ret i1 [[COMMON_RET_OP]] +; +common.ret: + %2 = xor i32 %0, -1 + %3 = icmp ule i32 %1, %2 + %4 = xor i32 %1, -1 + %5 = icmp ugt i32 %0, %4 + %common.ret.op = and i1 %3, %5 + ret i1 %common.ret.op +} From b11691e95f5984138f8ce3ab18280c5db58b1a18 Mon Sep 17 00:00:00 2001 From: Bobby Song Date: Thu, 29 May 2025 18:52:27 +0100 Subject: [PATCH 2/5] Added missed optimization: need optimization for further adaption Add test for optimization Extend the case further to signed intergers and more in/exclusive ranges Update test for optimization --- llvm/lib/Analysis/InstructionSimplify.cpp | 14 ++ .../and-comparison-not-always-false.ll | 125 +++++++++++++++++- 2 files changed, 135 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 23e147ba8c6a1..e626d91a81f0b 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -2178,6 +2178,20 @@ static Value *simplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q, match(Op1, m_Xor(m_Specific(A), m_SpecificInt(~*C1)))) return Constant::getNullValue(Op0->getType()); + // (X <= ~Y) && (Y > ~X) --> 0 + CmpPredicate Pred0, Pred1; + if (match(Op0, + m_c_ICmp(Pred0, m_Value(X), m_c_Xor(m_Value(Y), m_AllOnes()))) && + match(Op1, m_c_ICmp(Pred1, m_Specific(Y), + m_c_Xor(m_Specific(X), m_AllOnes())))) { + if (ICmpInst::isLE(Pred0) && ICmpInst::isGT(Pred1)) + return ConstantInt::getFalse(Op0->getType()); + if (ICmpInst::isLT(Pred0) && ICmpInst::isGE(Pred1)) + return ConstantInt::getFalse(Op0->getType()); + if (ICmpInst::isLT(Pred0) && ICmpInst::isGT(Pred1)) + return ConstantInt::getFalse(Op0->getType()); + } + if (Op0->getType()->isIntOrIntVectorTy(1)) { if (std::optional Implied = isImpliedCondition(Op0, Op1, Q.DL)) { // If Op0 is true implies Op1 is true, then Op0 is a subset of Op1. diff --git a/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll b/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll index 174d97d30bcf8..0ed39decf578c 100644 --- a/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll +++ b/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll @@ -1,13 +1,73 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s -define i1 @test(i32 %0, i32 %1) { -; CHECK-LABEL: define i1 @test( +define i1 @test_pass_et(i32 %0, i32 %1) { +; CHECK-LABEL: define i1 @test_pass_et( +; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) { +; CHECK-NEXT: [[COMMON_RET:.*:]] +; CHECK-NEXT: ret i1 false +; +common.ret: + %2 = xor i32 %0, -1 + %3 = icmp ule i32 %1, %2 + %4 = xor i32 %1, -1 + %5 = icmp ugt i32 %0, %4 + %common.ret.op = and i1 %3, %5 + ret i1 %common.ret.op +} + +define i1 @test_pass_signed(i32 %0, i32 %1) { +; CHECK-LABEL: define i1 @test_pass_signed( +; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) { +; CHECK-NEXT: [[COMMON_RET:.*:]] +; CHECK-NEXT: ret i1 false +; +common.ret: + %2 = xor i32 %0, -1 + %3 = icmp sle i32 %1, %2 + %4 = xor i32 %1, -1 + %5 = icmp sgt i32 %0, %4 + %common.ret.op = and i1 %3, %5 + ret i1 %common.ret.op +} + +define i1 @test_pass_tt(i32 %0, i32 %1) { +; CHECK-LABEL: define i1 @test_pass_tt( +; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) { +; CHECK-NEXT: [[COMMON_RET:.*:]] +; CHECK-NEXT: ret i1 false +; +common.ret: + %2 = xor i32 %0, -1 + %3 = icmp ult i32 %1, %2 + %4 = xor i32 %1, -1 + %5 = icmp ugt i32 %0, %4 + %common.ret.op = and i1 %3, %5 + ret i1 %common.ret.op +} + +define i1 @test_pass_te(i32 %0, i32 %1) { +; CHECK-LABEL: define i1 @test_pass_te( +; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) { +; CHECK-NEXT: [[COMMON_RET:.*:]] +; CHECK-NEXT: ret i1 false +; +common.ret: + %2 = xor i32 %0, -1 + %3 = icmp ult i32 %1, %2 + %4 = xor i32 %1, -1 + %5 = icmp uge i32 %0, %4 + %common.ret.op = and i1 %3, %5 + ret i1 %common.ret.op +} + +define i1 @test_nopass_ee(i32 %0, i32 %1) { +; CHECK-LABEL: define i1 @test_nopass_ee( ; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) { ; CHECK-NEXT: [[COMMON_RET:.*:]] ; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP0]], -1 ; CHECK-NEXT: [[TMP3:%.*]] = icmp ule i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP1]], -1 -; CHECK-NEXT: [[TMP5:%.*]] = icmp ugt i32 [[TMP0]], [[TMP4]] +; CHECK-NEXT: [[TMP5:%.*]] = icmp uge i32 [[TMP0]], [[TMP4]] ; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = and i1 [[TMP3]], [[TMP5]] ; CHECK-NEXT: ret i1 [[COMMON_RET_OP]] ; @@ -15,7 +75,64 @@ common.ret: %2 = xor i32 %0, -1 %3 = icmp ule i32 %1, %2 %4 = xor i32 %1, -1 - %5 = icmp ugt i32 %0, %4 + %5 = icmp uge i32 %0, %4 %common.ret.op = and i1 %3, %5 ret i1 %common.ret.op } + +define i1 @test_no_change_et(i32 %0, i32 %1, i32 %2) { +; CHECK-LABEL: define i1 @test_no_change_et( +; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]]) { +; CHECK-NEXT: [[COMMON_RET:.*:]] +; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0]], -1 +; CHECK-NEXT: [[TMP4:%.*]] = icmp ule i32 [[TMP1]], [[TMP3]] +; CHECK-NEXT: [[TMP5:%.*]] = icmp slt i32 [[TMP1]], 0 +; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = and i1 [[TMP5]], [[TMP4]] +; CHECK-NEXT: ret i1 [[COMMON_RET_OP]] +; +common.ret: + %3 = xor i32 %0, -1 + %4 = icmp ule i32 %1, %3 + %5 = xor i32 %1, -1 + %6 = icmp ugt i32 %1, %5 + %common.ret.op = and i1 %6, %4 + ret i1 %common.ret.op +} + +define i1 @test_no_change_te(i32 %0, i32 %1, i32 %2) { +; CHECK-LABEL: define i1 @test_no_change_te( +; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]]) { +; CHECK-NEXT: [[COMMON_RET:.*:]] +; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0]], -1 +; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 [[TMP1]], [[TMP3]] +; CHECK-NEXT: [[TMP5:%.*]] = icmp slt i32 [[TMP1]], 0 +; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = and i1 [[TMP5]], [[TMP4]] +; CHECK-NEXT: ret i1 [[COMMON_RET_OP]] +; +common.ret: + %3 = xor i32 %0, -1 + %4 = icmp ult i32 %1, %3 + %5 = xor i32 %1, -1 + %6 = icmp uge i32 %1, %5 + %common.ret.op = and i1 %6, %4 + ret i1 %common.ret.op +} + +define i1 @test_no_change_tt(i32 %0, i32 %1, i32 %2) { +; CHECK-LABEL: define i1 @test_no_change_tt( +; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]]) { +; CHECK-NEXT: [[COMMON_RET:.*:]] +; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0]], -1 +; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 [[TMP1]], [[TMP3]] +; CHECK-NEXT: [[TMP5:%.*]] = icmp slt i32 [[TMP1]], 0 +; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = and i1 [[TMP5]], [[TMP4]] +; CHECK-NEXT: ret i1 [[COMMON_RET_OP]] +; +common.ret: + %3 = xor i32 %0, -1 + %4 = icmp ult i32 %1, %3 + %5 = xor i32 %1, -1 + %6 = icmp ugt i32 %1, %5 + %common.ret.op = and i1 %6, %4 + ret i1 %common.ret.op +} From 821f62d052cef4d3d933776f1be5371fb65128a6 Mon Sep 17 00:00:00 2001 From: Bobby SONG Date: Fri, 12 Sep 2025 13:01:21 +0100 Subject: [PATCH 3/5] Update llvm/lib/Analysis/InstructionSimplify.cpp Co-authored-by: Nikita Popov Update llvm/lib/Analysis/InstructionSimplify.cpp Co-authored-by: Nikita Popov --- llvm/lib/Analysis/InstructionSimplify.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 5d9c5c65cf387..622ab752f9013 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -2179,9 +2179,9 @@ static Value *simplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q, // (X <= ~Y) && (Y > ~X) --> 0 CmpPredicate Pred0, Pred1; if (match(Op0, - m_c_ICmp(Pred0, m_Value(X), m_c_Xor(m_Value(Y), m_AllOnes()))) && + m_c_ICmp(Pred0, m_Value(X), m_Not(m_Value(Y)))) && match(Op1, m_c_ICmp(Pred1, m_Specific(Y), - m_c_Xor(m_Specific(X), m_AllOnes())))) { + m_Not(m_Specific(X))))) { if (ICmpInst::isLE(Pred0) && ICmpInst::isGT(Pred1)) return ConstantInt::getFalse(Op0->getType()); if (ICmpInst::isLT(Pred0) && ICmpInst::isGE(Pred1)) From 1c6aab2d0b7ecf3eec48bf16e1482f0f5ffa0ee1 Mon Sep 17 00:00:00 2001 From: Bobby Song Date: Fri, 12 Sep 2025 16:06:37 +0100 Subject: [PATCH 4/5] Change predicate match to expect same sign state --- llvm/lib/Analysis/InstructionSimplify.cpp | 14 +++++++------ .../and-comparison-not-always-false.ll | 20 +++++++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 622ab752f9013..aaa7b0a4ede84 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -2182,12 +2182,14 @@ static Value *simplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q, m_c_ICmp(Pred0, m_Value(X), m_Not(m_Value(Y)))) && match(Op1, m_c_ICmp(Pred1, m_Specific(Y), m_Not(m_Specific(X))))) { - if (ICmpInst::isLE(Pred0) && ICmpInst::isGT(Pred1)) - return ConstantInt::getFalse(Op0->getType()); - if (ICmpInst::isLT(Pred0) && ICmpInst::isGE(Pred1)) - return ConstantInt::getFalse(Op0->getType()); - if (ICmpInst::isLT(Pred0) && ICmpInst::isGT(Pred1)) - return ConstantInt::getFalse(Op0->getType()); + if (ICmpInst::isSigned(Pred0) == ICmpInst::isSigned(Pred1)) { + if (ICmpInst::isLE(Pred0) && ICmpInst::isGT(Pred1)) + return ConstantInt::getFalse(Op0->getType()); + if (ICmpInst::isLT(Pred0) && ICmpInst::isGE(Pred1)) + return ConstantInt::getFalse(Op0->getType()); + if (ICmpInst::isLT(Pred0) && ICmpInst::isGT(Pred1)) + return ConstantInt::getFalse(Op0->getType()); + } } if (Op0->getType()->isIntOrIntVectorTy(1)) { diff --git a/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll b/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll index 0ed39decf578c..e336202079ca3 100644 --- a/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll +++ b/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll @@ -136,3 +136,23 @@ common.ret: %common.ret.op = and i1 %6, %4 ret i1 %common.ret.op } + +define i1 @test_no_change_su(i32 %0, i32 %1) { +; CHECK-LABEL: define i1 @test_no_change_su( +; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) { +; CHECK-NEXT: [[COMMON_RET:.*:]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP0]], -1 +; CHECK-NEXT: [[TMP3:%.*]] = icmp sle i32 [[TMP1]], [[TMP2]] +; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: [[TMP5:%.*]] = icmp ugt i32 [[TMP0]], [[TMP4]] +; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = and i1 [[TMP3]], [[TMP5]] +; CHECK-NEXT: ret i1 [[COMMON_RET_OP]] +; +common.ret: + %2 = xor i32 %0, -1 + %3 = icmp sle i32 %1, %2 + %4 = xor i32 %1, -1 + %5 = icmp ugt i32 %0, %4 + %common.ret.op = and i1 %3, %5 + ret i1 %common.ret.op +} From 893bbf8c74e5481b7fdda6b062a21f7a2908f58c Mon Sep 17 00:00:00 2001 From: Bobby Song Date: Mon, 15 Sep 2025 10:28:18 +0100 Subject: [PATCH 5/5] Fix formatting --- llvm/lib/Analysis/InstructionSimplify.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index aaa7b0a4ede84..f899c7929a017 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -2178,10 +2178,8 @@ static Value *simplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q, // (X <= ~Y) && (Y > ~X) --> 0 CmpPredicate Pred0, Pred1; - if (match(Op0, - m_c_ICmp(Pred0, m_Value(X), m_Not(m_Value(Y)))) && - match(Op1, m_c_ICmp(Pred1, m_Specific(Y), - m_Not(m_Specific(X))))) { + if (match(Op0, m_c_ICmp(Pred0, m_Value(X), m_Not(m_Value(Y)))) && + match(Op1, m_c_ICmp(Pred1, m_Specific(Y), m_Not(m_Specific(X))))) { if (ICmpInst::isSigned(Pred0) == ICmpInst::isSigned(Pred1)) { if (ICmpInst::isLE(Pred0) && ICmpInst::isGT(Pred1)) return ConstantInt::getFalse(Op0->getType());