Skip to content

Conversation

@dtcxzyw
Copy link
Member

@dtcxzyw dtcxzyw commented Sep 10, 2023

This patch simplifies the pattern icmp X and/or C1, X and/or C2 when one constant mask is the subset of the other.
If C1 & C2 == C1, A = X and/or C1, B = X and/or C2, we can do the following folds:
icmp ule A, B -> true
icmp ugt A, B -> false
We can apply similar folds for signed predicates when C1 and C2 are the same sign:
icmp sle A, B -> true
icmp sgt A, B -> false

Alive2: https://alive2.llvm.org/ce/z/Q4ekP5
Fixes #65833.

@dtcxzyw dtcxzyw requested review from goldsteinn and nikic September 10, 2023 18:21
@dtcxzyw dtcxzyw requested review from a team as code owners September 10, 2023 18:21
@llvmbot llvmbot added the llvm:analysis Includes value tracking, cost tables and constant folding label Sep 10, 2023
@llvmbot
Copy link
Member

llvmbot commented Sep 10, 2023

@llvm/pr-subscribers-llvm-analysis

Changes

This patch simplifies the pattern icmp X & C1, X & C2 when one constant mask is the subset of the other.
Alive2: https://alive2.llvm.org/ce/z/s-IEK7
Fixes #65833.

--
Full diff: https://github.com/llvm/llvm-project/pull/65905.diff

3 Files Affected:

  • (modified) llvm/lib/Analysis/InstructionSimplify.cpp (+27-1)
  • (modified) llvm/test/Transforms/InstSimplify/compare.ll (+194)
  • (modified) llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll (+97)
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index d0cc56ebc2be319..734029f1ad0bef5 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -3427,7 +3427,7 @@ static Value *simplifyICmpWithBinOp(CmpInst::Predicate Pred, Value *LHS, switch (LBO->getOpcode()) { default: break; - case Instruction::Shl: + case Instruction::Shl: { bool NUW = Q.IIQ.hasNoUnsignedWrap(LBO) && Q.IIQ.hasNoUnsignedWrap(RBO); bool NSW = Q.IIQ.hasNoSignedWrap(LBO) && Q.IIQ.hasNoSignedWrap(RBO); if (!NUW || (ICmpInst::isSigned(Pred) && !NSW) || @@ -3436,6 +3436,32 @@ static Value *simplifyICmpWithBinOp(CmpInst::Predicate Pred, Value *LHS, if (Value *V = simplifyICmpInst(Pred, LBO->getOperand(1), RBO->getOperand(1), Q, MaxRecurse - 1)) return V; + break; + } + // icmp X & C1, X & C2 where (C1 & C2) == C1/C2 + // icmp X | C1, X | C2 where (C1 & C2) == C1/C2 + case Instruction::And: + case Instruction::Or: { + if (ICmpInst::isUnsigned(Pred)) { + const APInt *C1, *C2; + if (match(LBO->getOperand(1), m_APInt(C1)) && + match(RBO->getOperand(1), m_APInt(C2))) { + if (C1->isSubsetOf(*C2)) { + if (Pred == ICmpInst::ICMP_ULE) + return ConstantInt::getTrue(getCompareTy(LHS)); + if (Pred == ICmpInst::ICMP_UGT) + return ConstantInt::getFalse(getCompareTy(LHS)); + } + if (C2->isSubsetOf(*C1)) { + if (Pred == ICmpInst::ICMP_UGE) + return ConstantInt::getTrue(getCompareTy(LHS)); + if (Pred == ICmpInst::ICMP_ULT) + return ConstantInt::getFalse(getCompareTy(LHS)); + } + } + } + break; + } } } diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll index c6c104a41c8be70..d21af97494c88bc 100644 --- a/llvm/test/Transforms/InstSimplify/compare.ll +++ b/llvm/test/Transforms/InstSimplify/compare.ll @@ -1919,6 +1919,200 @@ define i1 @tautological8(i32 %A, i32 %B) { ret i1 %D } +define i1 @tautological9(i32 %A) { +; CHECK-LABEL: @tautological9( +; CHECK-NEXT: ret i1 false +; + %C1 = and i32 %A, 1 + %C2 = and i32 %A, 3 + %D = icmp ugt i32 %C1, %C2 + ret i1 %D +} + +define <2 x i1> @tautological9_vec(<2 x i32> %A) { +; CHECK-LABEL: @tautological9_vec( +; CHECK-NEXT: ret <2 x i1> zeroinitializer +; + %C1 = and <2 x i32> %A, + %C2 = and <2 x i32> %A, + %D = icmp ugt <2 x i32> %C1, %C2 + ret <2 x i1> %D +} + +define i1 @tautological10(i32 %A) { +; CHECK-LABEL: @tautological10( +; CHECK-NEXT: ret i1 true +; + %C1 = and i32 %A, 1 + %C2 = and i32 %A, 3 + %D = icmp ule i32 %C1, %C2 + ret i1 %D +} + +define i1 @tautological11(i32 %A) { +; CHECK-LABEL: @tautological11( +; CHECK-NEXT: ret i1 true +; + %C1 = or i32 %A, 1 + %C2 = or i32 %A, 3 + %D = icmp ule i32 %C1, %C2 + ret i1 %D +} + +define i1 @tautological12(i32 %A) { +; CHECK-LABEL: @tautological12( +; CHECK-NEXT: ret i1 false +; + %C1 = or i32 %A, 1 + %C2 = or i32 %A, 3 + %D = icmp ugt i32 %C1, %C2 + ret i1 %D +} + +define i1 @tautological13(i32 %A) { +; CHECK-LABEL: @tautological13( +; CHECK-NEXT: ret i1 false +; + %C1 = or i32 %A, 1 + %C2 = or i32 %A, 3 + %D = icmp ult i32 %C2, %C1 + ret i1 %D +} + +define i1 @tautological14(i32 %A) { +; CHECK-LABEL: @tautological14( +; CHECK-NEXT: ret i1 true +; + %C1 = or i32 %A, 1 + %C2 = or i32 %A, 3 + %D = icmp uge i32 %C2, %C1 + ret i1 %D +} + +define i1 @tautological15(i32 %A) { +; CHECK-LABEL: @tautological15( +; CHECK-NEXT: ret i1 true +; + %C1 = and i32 %A, 1 + %C2 = and i32 %A, 3 + %D = icmp uge i32 %C2, %C1 + ret i1 %D +} + +define i1 @tautological16(i32 %A) { +; CHECK-LABEL: @tautological16( +; CHECK-NEXT: ret i1 false +; + %C1 = and i32 %A, 1 + %C2 = and i32 %A, 3 + %D = icmp ult i32 %C2, %C1 + ret i1 %D +} + +define i1 @tautological9_negative(i32 %A) { +; CHECK-LABEL: @tautological9_negative( +; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1 +; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 2 +; CHECK-NEXT: [[D:%.*]] = icmp ugt i32 [[C1]], [[C2]] +; CHECK-NEXT: ret i1 [[D]] +; + %C1 = and i32 %A, 1 + %C2 = and i32 %A, 2 + %D = icmp ugt i32 %C1, %C2 + ret i1 %D +} + +define i1 @tautological10_negative(i32 %A) { +; CHECK-LABEL: @tautological10_negative( +; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1 +; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 2 +; CHECK-NEXT: [[D:%.*]] = icmp ule i32 [[C1]], [[C2]] +; CHECK-NEXT: ret i1 [[D]] +; + %C1 = and i32 %A, 1 + %C2 = and i32 %A, 2 + %D = icmp ule i32 %C1, %C2 + ret i1 %D +} + +define i1 @tautological11_negative(i32 %A) { +; CHECK-LABEL: @tautological11_negative( +; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1 +; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 2 +; CHECK-NEXT: [[D:%.*]] = icmp ule i32 [[C1]], [[C2]] +; CHECK-NEXT: ret i1 [[D]] +; + %C1 = or i32 %A, 1 + %C2 = or i32 %A, 2 + %D = icmp ule i32 %C1, %C2 + ret i1 %D +} + +define i1 @tautological12_negative(i32 %A) { +; CHECK-LABEL: @tautological12_negative( +; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1 +; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 2 +; CHECK-NEXT: [[D:%.*]] = icmp ugt i32 [[C1]], [[C2]] +; CHECK-NEXT: ret i1 [[D]] +; + %C1 = or i32 %A, 1 + %C2 = or i32 %A, 2 + %D = icmp ugt i32 %C1, %C2 + ret i1 %D +} + +define i1 @tautological13_negative(i32 %A) { +; CHECK-LABEL: @tautological13_negative( +; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1 +; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 2 +; CHECK-NEXT: [[D:%.*]] = icmp ult i32 [[C2]], [[C1]] +; CHECK-NEXT: ret i1 [[D]] +; + %C1 = or i32 %A, 1 + %C2 = or i32 %A, 2 + %D = icmp ult i32 %C2, %C1 + ret i1 %D +} + +define i1 @tautological14_negative(i32 %A) { +; CHECK-LABEL: @tautological14_negative( +; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1 +; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 2 +; CHECK-NEXT: [[D:%.*]] = icmp uge i32 [[C2]], [[C1]] +; CHECK-NEXT: ret i1 [[D]] +; + %C1 = or i32 %A, 1 + %C2 = or i32 %A, 2 + %D = icmp uge i32 %C2, %C1 + ret i1 %D +} + +define i1 @tautological15_negative(i32 %A) { +; CHECK-LABEL: @tautological15_negative( +; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1 +; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 2 +; CHECK-NEXT: [[D:%.*]] = icmp uge i32 [[C2]], [[C1]] +; CHECK-NEXT: ret i1 [[D]] +; + %C1 = and i32 %A, 1 + %C2 = and i32 %A, 2 + %D = icmp uge i32 %C2, %C1 + ret i1 %D +} + +define i1 @tautological16_negative(i32 %A) { +; CHECK-LABEL: @tautological16_negative( +; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1 +; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 2 +; CHECK-NEXT: [[D:%.*]] = icmp ult i32 [[C2]], [[C1]] +; CHECK-NEXT: ret i1 [[D]] +; + %C1 = and i32 %A, 1 + %C2 = and i32 %A, 2 + %D = icmp ult i32 %C2, %C1 + ret i1 %D +} + declare void @helper_i1(i1) ; Series of tests for icmp s[lt|ge] (or A, B), A and icmp s[gt|le] A, (or A, B) define void @icmp_slt_sge_or(i32 %Ax, i32 %Bx) { diff --git a/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll b/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll index e7123b208084927..8828378b5315df0 100644 --- a/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll +++ b/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll @@ -2332,3 +2332,100 @@ false: %m2 = call i8 @llvm.smin.i8(i8 %x, i8 %y) ret i8 %m2 } + +; Tests from PR65833 +define i8 @umin_and_mask(i8 %x) { +; CHECK-LABEL: @umin_and_mask( +; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X:%.*]], 1 +; CHECK-NEXT: ret i8 [[AND1]] +; + %and1 = and i8 %x, 1 + %and2 = and i8 %x, 3 + %val = call i8 @llvm.umin.i8(i8 %and1, i8 %and2) + ret i8 %val +} + +define i8 @umax_and_mask(i8 %x) { +; CHECK-LABEL: @umax_and_mask( +; CHECK-NEXT: [[AND2:%.*]] = and i8 [[X:%.*]], 3 +; CHECK-NEXT: ret i8 [[AND2]] +; + %and1 = and i8 %x, 1 + %and2 = and i8 %x, 3 + %val = call i8 @llvm.umax.i8(i8 %and1, i8 %and2) + ret i8 %val +} + +define i8 @umin_or_mask(i8 %x) { +; CHECK-LABEL: @umin_or_mask( +; CHECK-NEXT: [[AND1:%.*]] = or i8 [[X:%.*]], 1 +; CHECK-NEXT: ret i8 [[AND1]] +; + %and1 = or i8 %x, 1 + %and2 = or i8 %x, 3 + %val = call i8 @llvm.umin.i8(i8 %and1, i8 %and2) + ret i8 %val +} + +define i8 @umax_or_mask(i8 %x) { +; CHECK-LABEL: @umax_or_mask( +; CHECK-NEXT: [[AND2:%.*]] = or i8 [[X:%.*]], 3 +; CHECK-NEXT: ret i8 [[AND2]] +; + %and1 = or i8 %x, 1 + %and2 = or i8 %x, 3 + %val = call i8 @llvm.umax.i8(i8 %and1, i8 %and2) + ret i8 %val +} + +define i8 @umin_and_mask_negative(i8 %x) { +; CHECK-LABEL: @umin_and_mask_negative( +; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X:%.*]], 1 +; CHECK-NEXT: [[AND2:%.*]] = and i8 [[X]], 2 +; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umin.i8(i8 [[AND1]], i8 [[AND2]]) +; CHECK-NEXT: ret i8 [[VAL]] +; + %and1 = and i8 %x, 1 + %and2 = and i8 %x, 2 + %val = call i8 @llvm.umin.i8(i8 %and1, i8 %and2) + ret i8 %val +} + +define i8 @umax_and_mask_negative(i8 %x) { +; CHECK-LABEL: @umax_and_mask_negative( +; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X:%.*]], 1 +; CHECK-NEXT: [[AND2:%.*]] = and i8 [[X]], 2 +; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umax.i8(i8 [[AND1]], i8 [[AND2]]) +; CHECK-NEXT: ret i8 [[VAL]] +; + %and1 = and i8 %x, 1 + %and2 = and i8 %x, 2 + %val = call i8 @llvm.umax.i8(i8 %and1, i8 %and2) + ret i8 %val +} + +define i8 @umin_or_mask_negative(i8 %x) { +; CHECK-LABEL: @umin_or_mask_negative( +; CHECK-NEXT: [[AND1:%.*]] = or i8 [[X:%.*]], 1 +; CHECK-NEXT: [[AND2:%.*]] = or i8 [[X]], 2 +; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umin.i8(i8 [[AND1]], i8 [[AND2]]) +; CHECK-NEXT: ret i8 [[VAL]] +; + %and1 = or i8 %x, 1 + %and2 = or i8 %x, 2 + %val = call i8 @llvm.umin.i8(i8 %and1, i8 %and2) + ret i8 %val +} + +define i8 @umax_or_mask_negative(i8 %x) { +; CHECK-LABEL: @umax_or_mask_negative( +; CHECK-NEXT: [[AND1:%.*]] = or i8 [[X:%.*]], 1 +; CHECK-NEXT: [[AND2:%.*]] = or i8 [[X]], 2 +; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umax.i8(i8 [[AND1]], i8 [[AND2]]) +; CHECK-NEXT: ret i8 [[VAL]] +; + %and1 = or i8 %x, 1 + %and2 = or i8 %x, 2 + %val = call i8 @llvm.umax.i8(i8 %and1, i8 %and2) + ret i8 %val +} 
@llvmbot
Copy link
Member

llvmbot commented Sep 17, 2023

@llvm/pr-subscribers-llvm-transforms

Changes

This patch simplifies the pattern icmp X &amp; C1, X &amp; C2 when one constant mask is the subset of the other.
Alive2: https://alive2.llvm.org/ce/z/s-IEK7
Fixes #65833.


Full diff: https://github.com/llvm/llvm-project/pull/65905.diff

3 Files Affected:

  • (modified) llvm/lib/Analysis/InstructionSimplify.cpp (+27-1)
  • (modified) llvm/test/Transforms/InstSimplify/compare.ll (+9-36)
  • (modified) llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll (+6-14)
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 2a3011075e47ed7..1ca1f27b9ab992d 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -3427,7 +3427,7 @@ static Value *simplifyICmpWithBinOp(CmpInst::Predicate Pred, Value *LHS, switch (LBO->getOpcode()) { default: break; - case Instruction::Shl: + case Instruction::Shl: { bool NUW = Q.IIQ.hasNoUnsignedWrap(LBO) && Q.IIQ.hasNoUnsignedWrap(RBO); bool NSW = Q.IIQ.hasNoSignedWrap(LBO) && Q.IIQ.hasNoSignedWrap(RBO); if (!NUW || (ICmpInst::isSigned(Pred) && !NSW) || @@ -3436,6 +3436,32 @@ static Value *simplifyICmpWithBinOp(CmpInst::Predicate Pred, Value *LHS, if (Value *V = simplifyICmpInst(Pred, LBO->getOperand(1), RBO->getOperand(1), Q, MaxRecurse - 1)) return V; + break; + } + // icmp X & C1, X & C2 where (C1 & C2) == C1/C2 + // icmp X | C1, X | C2 where (C1 & C2) == C1/C2 + case Instruction::And: + case Instruction::Or: { + if (ICmpInst::isUnsigned(Pred)) { + const APInt *C1, *C2; + if (match(LBO->getOperand(1), m_APInt(C1)) && + match(RBO->getOperand(1), m_APInt(C2))) { + if (C1->isSubsetOf(*C2)) { + if (Pred == ICmpInst::ICMP_ULE) + return ConstantInt::getTrue(getCompareTy(LHS)); + if (Pred == ICmpInst::ICMP_UGT) + return ConstantInt::getFalse(getCompareTy(LHS)); + } + if (C2->isSubsetOf(*C1)) { + if (Pred == ICmpInst::ICMP_UGE) + return ConstantInt::getTrue(getCompareTy(LHS)); + if (Pred == ICmpInst::ICMP_ULT) + return ConstantInt::getFalse(getCompareTy(LHS)); + } + } + } + break; + } } } diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll index cb3805932cbc5be..d21af97494c88bc 100644 --- a/llvm/test/Transforms/InstSimplify/compare.ll +++ b/llvm/test/Transforms/InstSimplify/compare.ll @@ -1921,10 +1921,7 @@ define i1 @tautological8(i32 %A, i32 %B) { define i1 @tautological9(i32 %A) { ; CHECK-LABEL: @tautological9( -; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp ugt i32 [[C1]], [[C2]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 false ; %C1 = and i32 %A, 1 %C2 = and i32 %A, 3 @@ -1934,10 +1931,7 @@ define i1 @tautological9(i32 %A) { define <2 x i1> @tautological9_vec(<2 x i32> %A) { ; CHECK-LABEL: @tautological9_vec( -; CHECK-NEXT: [[C1:%.*]] = and <2 x i32> [[A:%.*]], <i32 1, i32 1> -; CHECK-NEXT: [[C2:%.*]] = and <2 x i32> [[A]], <i32 3, i32 3> -; CHECK-NEXT: [[D:%.*]] = icmp ugt <2 x i32> [[C1]], [[C2]] -; CHECK-NEXT: ret <2 x i1> [[D]] +; CHECK-NEXT: ret <2 x i1> zeroinitializer ; %C1 = and <2 x i32> %A, <i32 1, i32 1> %C2 = and <2 x i32> %A, <i32 3, i32 3> @@ -1947,10 +1941,7 @@ define <2 x i1> @tautological9_vec(<2 x i32> %A) { define i1 @tautological10(i32 %A) { ; CHECK-LABEL: @tautological10( -; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp ule i32 [[C1]], [[C2]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 true ; %C1 = and i32 %A, 1 %C2 = and i32 %A, 3 @@ -1960,10 +1951,7 @@ define i1 @tautological10(i32 %A) { define i1 @tautological11(i32 %A) { ; CHECK-LABEL: @tautological11( -; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp ule i32 [[C1]], [[C2]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 true ; %C1 = or i32 %A, 1 %C2 = or i32 %A, 3 @@ -1973,10 +1961,7 @@ define i1 @tautological11(i32 %A) { define i1 @tautological12(i32 %A) { ; CHECK-LABEL: @tautological12( -; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp ugt i32 [[C1]], [[C2]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 false ; %C1 = or i32 %A, 1 %C2 = or i32 %A, 3 @@ -1986,10 +1971,7 @@ define i1 @tautological12(i32 %A) { define i1 @tautological13(i32 %A) { ; CHECK-LABEL: @tautological13( -; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp ult i32 [[C2]], [[C1]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 false ; %C1 = or i32 %A, 1 %C2 = or i32 %A, 3 @@ -1999,10 +1981,7 @@ define i1 @tautological13(i32 %A) { define i1 @tautological14(i32 %A) { ; CHECK-LABEL: @tautological14( -; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp uge i32 [[C2]], [[C1]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 true ; %C1 = or i32 %A, 1 %C2 = or i32 %A, 3 @@ -2012,10 +1991,7 @@ define i1 @tautological14(i32 %A) { define i1 @tautological15(i32 %A) { ; CHECK-LABEL: @tautological15( -; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp uge i32 [[C2]], [[C1]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 true ; %C1 = and i32 %A, 1 %C2 = and i32 %A, 3 @@ -2025,10 +2001,7 @@ define i1 @tautological15(i32 %A) { define i1 @tautological16(i32 %A) { ; CHECK-LABEL: @tautological16( -; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp ult i32 [[C2]], [[C1]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 false ; %C1 = and i32 %A, 1 %C2 = and i32 %A, 3 diff --git a/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll b/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll index 179de804a0c090c..8828378b5315df0 100644 --- a/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll +++ b/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll @@ -2337,9 +2337,7 @@ false: define i8 @umin_and_mask(i8 %x) { ; CHECK-LABEL: @umin_and_mask( ; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X:%.*]], 1 -; CHECK-NEXT: [[AND2:%.*]] = and i8 [[X]], 3 -; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umin.i8(i8 [[AND1]], i8 [[AND2]]) -; CHECK-NEXT: ret i8 [[VAL]] +; CHECK-NEXT: ret i8 [[AND1]] ; %and1 = and i8 %x, 1 %and2 = and i8 %x, 3 @@ -2349,10 +2347,8 @@ define i8 @umin_and_mask(i8 %x) { define i8 @umax_and_mask(i8 %x) { ; CHECK-LABEL: @umax_and_mask( -; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X:%.*]], 1 -; CHECK-NEXT: [[AND2:%.*]] = and i8 [[X]], 3 -; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umax.i8(i8 [[AND1]], i8 [[AND2]]) -; CHECK-NEXT: ret i8 [[VAL]] +; CHECK-NEXT: [[AND2:%.*]] = and i8 [[X:%.*]], 3 +; CHECK-NEXT: ret i8 [[AND2]] ; %and1 = and i8 %x, 1 %and2 = and i8 %x, 3 @@ -2363,9 +2359,7 @@ define i8 @umax_and_mask(i8 %x) { define i8 @umin_or_mask(i8 %x) { ; CHECK-LABEL: @umin_or_mask( ; CHECK-NEXT: [[AND1:%.*]] = or i8 [[X:%.*]], 1 -; CHECK-NEXT: [[AND2:%.*]] = or i8 [[X]], 3 -; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umin.i8(i8 [[AND1]], i8 [[AND2]]) -; CHECK-NEXT: ret i8 [[VAL]] +; CHECK-NEXT: ret i8 [[AND1]] ; %and1 = or i8 %x, 1 %and2 = or i8 %x, 3 @@ -2375,10 +2369,8 @@ define i8 @umin_or_mask(i8 %x) { define i8 @umax_or_mask(i8 %x) { ; CHECK-LABEL: @umax_or_mask( -; CHECK-NEXT: [[AND1:%.*]] = or i8 [[X:%.*]], 1 -; CHECK-NEXT: [[AND2:%.*]] = or i8 [[X]], 3 -; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umax.i8(i8 [[AND1]], i8 [[AND2]]) -; CHECK-NEXT: ret i8 [[VAL]] +; CHECK-NEXT: [[AND2:%.*]] = or i8 [[X:%.*]], 3 +; CHECK-NEXT: ret i8 [[AND2]] ; %and1 = or i8 %x, 1 %and2 = or i8 %x, 3 
@dtcxzyw dtcxzyw changed the title [InstSimplify] Simplify icmp X & C1, X & C2 when (C1 & C2) == C1/C2 [InstSimplify] Fold icmp of X and/or C1 and X and/or C2 into constant Sep 17, 2023
@dtcxzyw dtcxzyw requested a review from goldsteinn September 17, 2023 17:26
@goldsteinn
Copy link
Contributor

LGTM, but please cleanup commits.

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Sep 18, 2023

LGTM, but please cleanup commits.

GitHub will squash commits into a single commit.

@dtcxzyw dtcxzyw merged commit be2723d into llvm:main Sep 18, 2023
@dtcxzyw dtcxzyw deleted the icmp-and-or-mask branch September 18, 2023 13:32
ZijunZhaoCCK pushed a commit to ZijunZhaoCCK/llvm-project that referenced this pull request Sep 19, 2023
…tant (llvm#65905) This patch simplifies the pattern `icmp X and/or C1, X and/or C2` when one constant mask is the subset of the other. If `C1 & C2 == C1`, `A = X and/or C1`, `B = X and/or C2`, we can do the following folds: `icmp ule A, B -> true` `icmp ugt A, B -> false` We can apply similar folds for signed predicates when `C1` and `C2` are the same sign: `icmp sle A, B -> true` `icmp sgt A, B -> false` Alive2: https://alive2.llvm.org/ce/z/Q4ekP5 Fixes llvm#65833.
zahiraam pushed a commit to tahonermann/llvm-project that referenced this pull request Oct 24, 2023
…tant (llvm#65905) This patch simplifies the pattern `icmp X and/or C1, X and/or C2` when one constant mask is the subset of the other. If `C1 & C2 == C1`, `A = X and/or C1`, `B = X and/or C2`, we can do the following folds: `icmp ule A, B -> true` `icmp ugt A, B -> false` We can apply similar folds for signed predicates when `C1` and `C2` are the same sign: `icmp sle A, B -> true` `icmp sgt A, B -> false` Alive2: https://alive2.llvm.org/ce/z/Q4ekP5 Fixes llvm#65833.
zahiraam pushed a commit to tahonermann/llvm-project that referenced this pull request Oct 24, 2023
…tant (llvm#65905) This patch simplifies the pattern `icmp X and/or C1, X and/or C2` when one constant mask is the subset of the other. If `C1 & C2 == C1`, `A = X and/or C1`, `B = X and/or C2`, we can do the following folds: `icmp ule A, B -> true` `icmp ugt A, B -> false` We can apply similar folds for signed predicates when `C1` and `C2` are the same sign: `icmp sle A, B -> true` `icmp sgt A, B -> false` Alive2: https://alive2.llvm.org/ce/z/Q4ekP5 Fixes llvm#65833.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

llvm:analysis Includes value tracking, cost tables and constant folding llvm:transforms

3 participants