-
Notifications
You must be signed in to change notification settings - Fork 10.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[InstSimplify] Fold icmp of X and/or C1
and X and/or C2
into constant
#65905
Conversation
@llvm/pr-subscribers-llvm-analysis ChangesThis patch simplifies the pattern -- 3 Files Affected:
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 +} |
@llvm/pr-subscribers-llvm-transforms ChangesThis patch simplifies the pattern Full diff: https://github.com/llvm/llvm-project/pull/65905.diff 3 Files Affected:
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
|
icmp X & C1, X & C2
when (C1 & C2) == C1/C2
X and/or C1
and X and/or C2
into constant
LGTM, but please cleanup commits. |
GitHub will squash commits into a single commit. |
…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.
…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.
…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.
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
andC2
are the same sign:icmp sle A, B -> true
icmp sgt A, B -> false
Alive2: https://alive2.llvm.org/ce/z/Q4ekP5
Fixes #65833.