diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index a064aa1016399..15e4668671807 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -3653,7 +3653,7 @@ static Instruction *foldNestedSelects(SelectInst &OuterSelVal, /// already poison. For example, if ValAssumedPoison is `icmp samesign X, 10` /// and V is `icmp ne X, 5`, impliesPoisonOrCond returns true. static bool impliesPoisonOrCond(const Value *ValAssumedPoison, const Value *V, - bool Expected) { + bool Expected, const SimplifyQuery &SQ) { if (impliesPoison(ValAssumedPoison, V)) return true; @@ -3678,6 +3678,14 @@ static bool impliesPoisonOrCond(const Value *ValAssumedPoison, const Value *V, *RHSC2); } } + Value *A; + if (match(ValAssumedPoison, m_NUWTrunc(m_Value(A))) && + isGuaranteedNotToBePoison(A)) { + assert(ValAssumedPoison->getType()->isIntOrIntVectorTy(1)); + return computeKnownBits( + A, SQ.getWithInstruction(cast(ValAssumedPoison))) + .getMaxValue() == 1; + } return false; } @@ -3703,13 +3711,13 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) { // checks whether folding it does not convert a well-defined value into // poison. if (match(TrueVal, m_One())) { - if (impliesPoisonOrCond(FalseVal, CondVal, /*Expected=*/false)) { + if (impliesPoisonOrCond(FalseVal, CondVal, /*Expected=*/false, SQ)) { // Change: A = select B, true, C --> A = or B, C return BinaryOperator::CreateOr(CondVal, FalseVal); } if (match(CondVal, m_OneUse(m_Select(m_Value(A), m_One(), m_Value(B)))) && - impliesPoisonOrCond(FalseVal, B, /*Expected=*/false)) { + impliesPoisonOrCond(FalseVal, B, /*Expected=*/false, SQ)) { // (A || B) || C --> A || (B | C) Value *LOr = Builder.CreateLogicalOr(A, Builder.CreateOr(B, FalseVal)); if (auto *I = dyn_cast(LOr)) { @@ -3749,13 +3757,13 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) { } if (match(FalseVal, m_Zero())) { - if (impliesPoisonOrCond(TrueVal, CondVal, /*Expected=*/true)) { + if (impliesPoisonOrCond(TrueVal, CondVal, /*Expected=*/true, SQ)) { // Change: A = select B, C, false --> A = and B, C return BinaryOperator::CreateAnd(CondVal, TrueVal); } if (match(CondVal, m_OneUse(m_Select(m_Value(A), m_Value(B), m_Zero()))) && - impliesPoisonOrCond(TrueVal, B, /*Expected=*/true)) { + impliesPoisonOrCond(TrueVal, B, /*Expected=*/true, SQ)) { // (A && B) && C --> A && (B & C) Value *LAnd = Builder.CreateLogicalAnd(A, Builder.CreateAnd(B, TrueVal)); if (auto *I = dyn_cast(LAnd)) { diff --git a/llvm/test/Transforms/InstCombine/logical-select.ll b/llvm/test/Transforms/InstCombine/logical-select.ll index e6de063969a6a..85e8c98455c91 100644 --- a/llvm/test/Transforms/InstCombine/logical-select.ll +++ b/llvm/test/Transforms/InstCombine/logical-select.ll @@ -1637,3 +1637,58 @@ define <2 x i1> @test_logical_and_icmp_samesign_vec_with_poison_tv(<2 x i8> %x) %and = select <2 x i1> %cmp1, <2 x i1> %cmp2, <2 x i1> zeroinitializer ret <2 x i1> %and } + +define i1 @test_logical_and_trunc_nuw(i1 %c, i8 noundef range(i8 0,2) %x) { +; CHECK-LABEL: @test_logical_and_trunc_nuw( +; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i8 [[X:%.*]] to i1 +; CHECK-NEXT: [[AND:%.*]] = and i1 [[C:%.*]], [[TRUNC]] +; CHECK-NEXT: ret i1 [[AND]] +; + %trunc = trunc nuw i8 %x to i1 + %and = select i1 %c, i1 %trunc, i1 false + ret i1 %and +} + +define i1 @test_logical_or_trunc_nuw(i1 %c, i8 noundef range(i8 0,2) %x) { +; CHECK-LABEL: @test_logical_or_trunc_nuw( +; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i8 [[X:%.*]] to i1 +; CHECK-NEXT: [[OR:%.*]] = or i1 [[C:%.*]], [[TRUNC]] +; CHECK-NEXT: ret i1 [[OR]] +; + %trunc = trunc nuw i8 %x to i1 + %or = select i1 %c, i1 true, i1 %trunc + ret i1 %or +} + +define <2 x i1> @test_logical_and_trunc_nuw_vec(<2 x i1> %c, <2 x i8> noundef range(i8 0,2) %x) { +; CHECK-LABEL: @test_logical_and_trunc_nuw_vec( +; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw <2 x i8> [[X:%.*]] to <2 x i1> +; CHECK-NEXT: [[AND:%.*]] = and <2 x i1> [[C:%.*]], [[TRUNC]] +; CHECK-NEXT: ret <2 x i1> [[AND]] +; + %trunc = trunc nuw <2 x i8> %x to <2 x i1> + %and = select <2 x i1> %c, <2 x i1> %trunc, <2 x i1> zeroinitializer + ret <2 x i1> %and +} + +define i1 @neg_test_logical_and_trunc_nuw_no_range(i1 %c, i8 noundef %x) { +; CHECK-LABEL: @neg_test_logical_and_trunc_nuw_no_range( +; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i8 [[X:%.*]] to i1 +; CHECK-NEXT: [[AND:%.*]] = select i1 [[C:%.*]], i1 [[TRUNC]], i1 false +; CHECK-NEXT: ret i1 [[AND]] +; + %trunc = trunc nuw i8 %x to i1 + %and = select i1 %c, i1 %trunc, i1 false + ret i1 %and +} + +define i1 @neg_test_logical_and_trunc_nuw_no_noundef(i1 %c, i8 range(i8 0,2) %x) { +; CHECK-LABEL: @neg_test_logical_and_trunc_nuw_no_noundef( +; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i8 [[X:%.*]] to i1 +; CHECK-NEXT: [[AND:%.*]] = select i1 [[C:%.*]], i1 [[TRUNC]], i1 false +; CHECK-NEXT: ret i1 [[AND]] +; + %trunc = trunc nuw i8 %x to i1 + %and = select i1 %c, i1 %trunc, i1 false + ret i1 %and +}