diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -2697,6 +2697,42 @@ if (Value *S = SimplifyWithOpReplaced(FalseVal, CondVal, Zero, SQ, /* AllowRefinement */ true)) return replaceOperand(SI, 2, S); + + // select (select a, true, b), c, false -> select a, c, false + // select c, (select a, true, b), false -> select c, a, false + // if c implies that b is false. + if (match(CondVal, m_Select(m_Value(A), m_One(), m_Value(B))) && + match(FalseVal, m_Zero())) { + auto Res = isImpliedCondition(TrueVal, B, DL); + if (Res && *Res == false) + return replaceOperand(SI, 0, A); + } + if (match(TrueVal, m_Select(m_Value(A), m_One(), m_Value(B))) && + match(FalseVal, m_Zero())) { + auto Res = isImpliedCondition(CondVal, B, DL); + if (Res && *Res == false) + return replaceOperand(SI, 1, A); + } + + // sel (sel c, a, false), true, (sel !c, b, false) -> sel c, a, b + // sel (sel !c, a, false), true, (sel c, b, false) -> sel c, b, a + Value *C1, *C2; + if (match(CondVal, m_Select(m_Value(C1), m_Value(A), m_Zero())) && + match(TrueVal, m_One()) && + match(FalseVal, m_Select(m_Value(C2), m_Value(B), m_Zero()))) { + int AIdx = 0; + if (match(C2, m_Not(m_Specific(C1)))) // first case + AIdx = 1; + else if (match(C1, m_Not(m_Specific(C2)))) // second case + AIdx = 2; + + if (AIdx) { + replaceOperand(SI, 0, AIdx == 1 ? C1 : C2); + replaceOperand(SI, AIdx, A); + replaceOperand(SI, 3 - AIdx, B); + return &SI; + } + } } // Selecting between two integer or vector splat integer constants? diff --git a/llvm/test/Transforms/InstCombine/select-safe-transforms.ll b/llvm/test/Transforms/InstCombine/select-safe-transforms.ll --- a/llvm/test/Transforms/InstCombine/select-safe-transforms.ll +++ b/llvm/test/Transforms/InstCombine/select-safe-transforms.ll @@ -132,10 +132,8 @@ define i1 @and_orn_cmp_1_logical(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @and_orn_cmp_1_logical( ; CHECK-NEXT: [[X:%.*]] = icmp sgt i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[X_INV:%.*]] = icmp sle i32 [[A]], [[B]] ; CHECK-NEXT: [[Y:%.*]] = icmp ugt i32 [[C:%.*]], 42 -; CHECK-NEXT: [[OR:%.*]] = select i1 [[Y]], i1 true, i1 [[X_INV]] -; CHECK-NEXT: [[AND:%.*]] = select i1 [[X]], i1 [[OR]], i1 false +; CHECK-NEXT: [[AND:%.*]] = select i1 [[X]], i1 [[Y]], i1 false ; CHECK-NEXT: ret i1 [[AND]] ; %x = icmp sgt i32 %a, %b @@ -148,11 +146,9 @@ define i1 @andn_or_cmp_1_logical(i37 %a, i37 %b, i37 %c) { ; CHECK-LABEL: @andn_or_cmp_1_logical( -; CHECK-NEXT: [[X:%.*]] = icmp sgt i37 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[X_INV:%.*]] = icmp sle i37 [[A]], [[B]] +; CHECK-NEXT: [[X_INV:%.*]] = icmp sle i37 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[Y:%.*]] = icmp ugt i37 [[C:%.*]], 42 -; CHECK-NEXT: [[OR:%.*]] = select i1 [[Y]], i1 true, i1 [[X]] -; CHECK-NEXT: [[AND:%.*]] = select i1 [[X_INV]], i1 [[OR]], i1 false +; CHECK-NEXT: [[AND:%.*]] = select i1 [[X_INV]], i1 [[Y]], i1 false ; CHECK-NEXT: ret i1 [[AND]] ; %x = icmp sgt i37 %a, %b @@ -165,11 +161,9 @@ define i1 @andn_or_cmp_2_logical(i16 %a, i16 %b, i16 %c) { ; CHECK-LABEL: @andn_or_cmp_2_logical( -; CHECK-NEXT: [[X:%.*]] = icmp sge i16 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[X_INV:%.*]] = icmp slt i16 [[A]], [[B]] +; CHECK-NEXT: [[X_INV:%.*]] = icmp slt i16 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[Y:%.*]] = icmp ugt i16 [[C:%.*]], 42 -; CHECK-NEXT: [[OR:%.*]] = select i1 [[Y]], i1 true, i1 [[X]] -; CHECK-NEXT: [[AND:%.*]] = select i1 [[OR]], i1 [[X_INV]], i1 false +; CHECK-NEXT: [[AND:%.*]] = select i1 [[Y]], i1 [[X_INV]], i1 false ; CHECK-NEXT: ret i1 [[AND]] ; %x = icmp sge i16 %a, %b @@ -182,10 +176,7 @@ define i1 @bools_logical(i1 %a, i1 %b, i1 %c) { ; CHECK-LABEL: @bools_logical( -; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[C:%.*]], true -; CHECK-NEXT: [[AND1:%.*]] = select i1 [[NOT]], i1 [[A:%.*]], i1 false -; CHECK-NEXT: [[AND2:%.*]] = select i1 [[C]], i1 [[B:%.*]], i1 false -; CHECK-NEXT: [[OR:%.*]] = select i1 [[AND1]], i1 true, i1 [[AND2]] +; CHECK-NEXT: [[OR:%.*]] = select i1 [[C:%.*]], i1 [[B:%.*]], i1 [[A:%.*]] ; CHECK-NEXT: ret i1 [[OR]] ; %not = xor i1 %c, -1