llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-llvm-transforms <details> <summary>Changes</summary> This patch folds the pattern `a ne/eq (zext (a ne/eq c))` into a boolean constant or a compare. Clang vs GCC: https://godbolt.org/z/4ro817WE8 Alive2: https://alive2.llvm.org/ce/z/6z9NRF Fixes #<!-- -->65073. --- Full diff: https://github.com/llvm/llvm-project/pull/65852.diff 2 Files Affected: - (modified) llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp (+62) - (modified) llvm/test/Transforms/InstCombine/icmp-range.ll (+18-58) ``````````diff diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index a219dac7acfbe16..d0b62c17ec94358 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -6380,7 +6380,69 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) { Y->getType()->isIntOrIntVectorTy(1) && Pred == ICmpInst::ICMP_ULE) return BinaryOperator::CreateOr(Builder.CreateIsNull(X), Y); + ICmpInst::Predicate Pred1, Pred2; const APInt *C; + // icmp eq/ne X, (zext (icmp eq/ne X, C)) + if (match(&I, m_c_ICmp(Pred1, m_Value(X), + m_ZExt(m_ICmp(Pred2, m_Deferred(X), m_APInt(C))))) && + ICmpInst::isEquality(Pred1) && ICmpInst::isEquality(Pred2)) { + if (C->isZero()) { + if (Pred2 == ICmpInst::ICMP_EQ) { + // icmp eq X, (zext (icmp eq X, 0)) --> false + // icmp ne X, (zext (icmp eq X, 0)) --> true + return replaceInstUsesWith( + I, + Constant::getIntegerValue( + I.getType(), + APInt(1U, static_cast<uint64_t>(Pred1 == ICmpInst::ICMP_NE)))); + } else { + // icmp eq X, (zext (icmp ne X, 0)) --> icmp ult X, 2 + // icmp ne X, (zext (icmp ne X, 0)) --> icmp ugt X, 1 + return ICmpInst::Create( + Instruction::ICmp, + Pred1 == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGT + : ICmpInst::ICMP_ULT, + X, + Constant::getIntegerValue( + X->getType(), APInt(X->getType()->getScalarSizeInBits(), + Pred1 == ICmpInst::ICMP_NE ? 1 : 2))); + } + } else if (C->isOne()) { + if (Pred2 == ICmpInst::ICMP_NE) { + // icmp eq X, (zext (icmp ne X, 1)) --> false + // icmp ne X, (zext (icmp ne X, 1)) --> true + return replaceInstUsesWith( + I, + Constant::getIntegerValue( + I.getType(), + APInt(1U, static_cast<uint64_t>(Pred1 == ICmpInst::ICMP_NE)))); + } else { + // icmp eq X, (zext (icmp eq X, 1)) --> icmp ult X, 2 + // icmp ne X, (zext (icmp eq X, 1)) --> icmp ugt X, 1 + return ICmpInst::Create( + Instruction::ICmp, + Pred1 == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGT + : ICmpInst::ICMP_ULT, + X, + Constant::getIntegerValue( + X->getType(), APInt(X->getType()->getScalarSizeInBits(), + Pred1 == ICmpInst::ICMP_NE ? 1 : 2))); + } + } else { + // C != 0 && C != 1 + // icmp eq X, (zext (icmp eq X, C)) --> icmp eq X, 0 + // icmp eq X, (zext (icmp ne X, C)) --> icmp eq X, 1 + // icmp ne X, (zext (icmp eq X, C)) --> icmp ne X, 0 + // icmp ne X, (zext (icmp ne X, C)) --> icmp ne X, 1 + return ICmpInst::Create( + Instruction::ICmp, Pred1, X, + Constant::getIntegerValue( + X->getType(), + APInt(X->getType()->getScalarSizeInBits(), + static_cast<uint64_t>(Pred2 == ICmpInst::ICMP_NE)))); + } + } + if (match(I.getOperand(0), m_c_Add(m_ZExt(m_Value(X)), m_SExt(m_Value(Y)))) && match(I.getOperand(1), m_APInt(C)) && X->getType()->isIntOrIntVectorTy(1) && diff --git a/llvm/test/Transforms/InstCombine/icmp-range.ll b/llvm/test/Transforms/InstCombine/icmp-range.ll index a26e760059b43fe..88d5a723747ad5f 100644 --- a/llvm/test/Transforms/InstCombine/icmp-range.ll +++ b/llvm/test/Transforms/InstCombine/icmp-range.ll @@ -1037,10 +1037,7 @@ define i1 @icmp_ne_bool_1(ptr %ptr) { ; Tests from PR65073 define i1 @icmp_ne_zext_eq_zero(i32 %a) { ; CHECK-LABEL: @icmp_ne_zext_eq_zero( -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]] -; CHECK-NEXT: ret i1 [[CMP1]] +; CHECK-NEXT: ret i1 true ; %cmp = icmp eq i32 %a, 0 %conv = zext i1 %cmp to i32 @@ -1050,9 +1047,7 @@ define i1 @icmp_ne_zext_eq_zero(i32 %a) { define i1 @icmp_ne_zext_ne_zero(i32 %a) { ; CHECK-LABEL: @icmp_ne_zext_ne_zero( -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 0 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 [[A:%.*]], 1 ; CHECK-NEXT: ret i1 [[CMP1]] ; %cmp = icmp ne i32 %a, 0 @@ -1063,10 +1058,7 @@ define i1 @icmp_ne_zext_ne_zero(i32 %a) { define i1 @icmp_eq_zext_eq_zero(i32 %a) { ; CHECK-LABEL: @icmp_eq_zext_eq_zero( -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]] -; CHECK-NEXT: ret i1 [[CMP1]] +; CHECK-NEXT: ret i1 false ; %cmp = icmp eq i32 %a, 0 %conv = zext i1 %cmp to i32 @@ -1076,9 +1068,7 @@ define i1 @icmp_eq_zext_eq_zero(i32 %a) { define i1 @icmp_eq_zext_ne_zero(i32 %a) { ; CHECK-LABEL: @icmp_eq_zext_ne_zero( -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 0 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], 2 ; CHECK-NEXT: ret i1 [[CMP1]] ; %cmp = icmp ne i32 %a, 0 @@ -1089,9 +1079,7 @@ define i1 @icmp_eq_zext_ne_zero(i32 %a) { define i1 @icmp_ne_zext_eq_one(i32 %a) { ; CHECK-LABEL: @icmp_ne_zext_eq_one( -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 1 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 [[A:%.*]], 1 ; CHECK-NEXT: ret i1 [[CMP1]] ; %cmp = icmp eq i32 %a, 1 @@ -1102,10 +1090,7 @@ define i1 @icmp_ne_zext_eq_one(i32 %a) { define i1 @icmp_ne_zext_ne_one(i32 %a) { ; CHECK-LABEL: @icmp_ne_zext_ne_one( -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 1 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]] -; CHECK-NEXT: ret i1 [[CMP1]] +; CHECK-NEXT: ret i1 true ; %cmp = icmp ne i32 %a, 1 %conv = zext i1 %cmp to i32 @@ -1115,9 +1100,7 @@ define i1 @icmp_ne_zext_ne_one(i32 %a) { define i1 @icmp_eq_zext_eq_one(i32 %a) { ; CHECK-LABEL: @icmp_eq_zext_eq_one( -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 1 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], 2 ; CHECK-NEXT: ret i1 [[CMP1]] ; %cmp = icmp eq i32 %a, 1 @@ -1128,10 +1111,7 @@ define i1 @icmp_eq_zext_eq_one(i32 %a) { define i1 @icmp_eq_zext_ne_one(i32 %a) { ; CHECK-LABEL: @icmp_eq_zext_ne_one( -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 1 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]] -; CHECK-NEXT: ret i1 [[CMP1]] +; CHECK-NEXT: ret i1 false ; %cmp = icmp ne i32 %a, 1 %conv = zext i1 %cmp to i32 @@ -1141,9 +1121,7 @@ define i1 @icmp_eq_zext_ne_one(i32 %a) { define i1 @icmp_ne_zext_eq_non_boolean(i32 %a) { ; CHECK-LABEL: @icmp_ne_zext_eq_non_boolean( -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 2 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A:%.*]], 0 ; CHECK-NEXT: ret i1 [[CMP1]] ; %cmp = icmp eq i32 %a, 2 @@ -1154,9 +1132,7 @@ define i1 @icmp_ne_zext_eq_non_boolean(i32 %a) { define i1 @icmp_ne_zext_ne_non_boolean(i32 %a) { ; CHECK-LABEL: @icmp_ne_zext_ne_non_boolean( -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 2 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A:%.*]], 1 ; CHECK-NEXT: ret i1 [[CMP1]] ; %cmp = icmp ne i32 %a, 2 @@ -1167,9 +1143,7 @@ define i1 @icmp_ne_zext_ne_non_boolean(i32 %a) { define i1 @icmp_eq_zext_eq_non_boolean(i32 %a) { ; CHECK-LABEL: @icmp_eq_zext_eq_non_boolean( -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 2 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], 0 ; CHECK-NEXT: ret i1 [[CMP1]] ; %cmp = icmp eq i32 %a, 2 @@ -1180,9 +1154,7 @@ define i1 @icmp_eq_zext_eq_non_boolean(i32 %a) { define i1 @icmp_eq_zext_ne_non_boolean(i32 %a) { ; CHECK-LABEL: @icmp_eq_zext_ne_non_boolean( -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 2 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], 1 ; CHECK-NEXT: ret i1 [[CMP1]] ; %cmp = icmp ne i32 %a, 2 @@ -1192,11 +1164,8 @@ define i1 @icmp_eq_zext_ne_non_boolean(i32 %a) { } define <2 x i1> @icmp_ne_zext_eq_zero_vec(<2 x i32> %a) { -; CHECK-LABEL: @icmp_ne_zext_eq_zero_vec( -; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], zeroinitializer -; CHECK-NEXT: [[CONV:%.*]] = zext <2 x i1> [[CMP]] to <2 x i32> -; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]] -; CHECK-NEXT: ret <2 x i1> [[CMP1]] +; CHECK-LABEL: @icmp_ne_zext_eq_zero_vec +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> ; %cmp = icmp eq <2 x i32> %a, <i32 0, i32 0> %conv = zext <2 x i1> %cmp to <2 x i32> @@ -1206,9 +1175,7 @@ define <2 x i1> @icmp_ne_zext_eq_zero_vec(<2 x i32> %a) { define <2 x i1> @icmp_ne_zext_ne_zero_vec(<2 x i32> %a) { ; CHECK-LABEL: @icmp_ne_zext_ne_zero_vec( -; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> [[A:%.*]], zeroinitializer -; CHECK-NEXT: [[CONV:%.*]] = zext <2 x i1> [[CMP]] to <2 x i32> -; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt <2 x i32> [[A:%.*]], <i32 1, i32 1> ; CHECK-NEXT: ret <2 x i1> [[CMP1]] ; %cmp = icmp ne <2 x i32> %a, <i32 0, i32 0> @@ -1219,9 +1186,7 @@ define <2 x i1> @icmp_ne_zext_ne_zero_vec(<2 x i32> %a) { define <2 x i1> @icmp_ne_zext_eq_one_vec(<2 x i32> %a) { ; CHECK-LABEL: @icmp_ne_zext_eq_one_vec( -; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 1, i32 1> -; CHECK-NEXT: [[CONV:%.*]] = zext <2 x i1> [[CMP]] to <2 x i32> -; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt <2 x i32> [[A:%.*]], <i32 1, i32 1> ; CHECK-NEXT: ret <2 x i1> [[CMP1]] ; %cmp = icmp eq <2 x i32> %a, <i32 1, i32 1> @@ -1232,10 +1197,7 @@ define <2 x i1> @icmp_ne_zext_eq_one_vec(<2 x i32> %a) { define <2 x i1> @icmp_ne_zext_ne_one_vec(<2 x i32> %a) { ; CHECK-LABEL: @icmp_ne_zext_ne_one_vec( -; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> [[A:%.*]], <i32 1, i32 1> -; CHECK-NEXT: [[CONV:%.*]] = zext <2 x i1> [[CMP]] to <2 x i32> -; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]] -; CHECK-NEXT: ret <2 x i1> [[CMP1]] +; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true> ; %cmp = icmp ne <2 x i32> %a, <i32 1, i32 1> %conv = zext <2 x i1> %cmp to <2 x i32> @@ -1245,9 +1207,7 @@ define <2 x i1> @icmp_ne_zext_ne_one_vec(<2 x i32> %a) { define <2 x i1> @icmp_ne_zext_eq_non_boolean_vec(<2 x i32> %a) { ; CHECK-LABEL: @icmp_ne_zext_eq_non_boolean_vec( -; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 2, i32 2> -; CHECK-NEXT: [[CONV:%.*]] = zext <2 x i1> [[CMP]] to <2 x i32> -; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[A:%.*]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[CMP1]] ; %cmp = icmp eq <2 x i32> %a, <i32 2, i32 2> `````````` </details> https://github.com/llvm/llvm-project/pull/65852 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits