Index: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2265,6 +2265,31 @@ } } + // Change (or (select (cmp Pred1, A, B), C, 0), (select (cmp Pred2, A, B), D, 0)) --> (select (cmp Pred1, A, B), C, D) + // when Pred1 is the inverse of Pred2. That is, if the or is based on the + // results of two select instructions, check whether the conditions of those + // select instructions are inverse icmp instructions with zero operands. If + // so, simplify to a single select on one of the conditions. + { + Value *X = nullptr, *Y = nullptr; + // Match both: + // (or (X ? 0 : A), (!X ? 0 : C)) + // (or (X ? A : 0), (!X ? C : 0)) + if ((match(Op0, m_Select(m_Value(X), m_Value(C), m_Zero())) && + match(Op1, m_Select(m_Value(Y), m_Value(D), m_Zero()))) || + (match(Op0, m_Select(m_Value(Y), m_Zero(), m_Value(C))) && + match(Op1, m_Select(m_Value(X), m_Zero(), m_Value(D))))) { + // Only transform into a select if X and Y have inverted predicates + // with identical operands. + CmpInst::Predicate Pred1, Pred2; + if (match(X, m_Cmp(Pred1, m_Value(A), m_Value(B))) && + match(Y, m_Cmp(Pred2, m_Specific(A), m_Specific(B))) && + CmpInst::getInversePredicate(Pred1) == Pred2) { + return SelectInst::Create(X, C, D); + } + } + } + return Changed ? &I : nullptr; } Index: test/Transforms/InstCombine/logical-select.ll =================================================================== --- test/Transforms/InstCombine/logical-select.ll +++ test/Transforms/InstCombine/logical-select.ll @@ -71,12 +71,9 @@ ; Fold two selects with inverted predicates and zero operands. define i32 @fold_inverted_icmp_preds(i32 %a, i32 %b, i32 %c, i32 %d) { ; CHECK-LABEL: @fold_inverted_icmp_preds( -; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 %a, %b -; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CMP1]], i32 %c, i32 0 -; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 %a, %b -; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i32 %d, i32 0 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[SEL1]], [[SEL2]] -; CHECK-NEXT: ret i32 [[OR]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 %a, %b +; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 %c, i32 %d +; CHECK-NEXT: ret i32 [[SEL]] ; %cmp1 = icmp slt i32 %a, %b %sel1 = select i1 %cmp1, i32 %c, i32 0 @@ -88,12 +85,9 @@ define i32 @fold_inverted_icmp_preds_reverse(i32 %a, i32 %b, i32 %c, i32 %d) { ; CHECK-LABEL: @fold_inverted_icmp_preds_reverse( -; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 %a, %b -; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CMP1]], i32 0, i32 %c -; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 %a, %b -; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i32 0, i32 %d -; CHECK-NEXT: [[OR:%.*]] = or i32 [[SEL1]], [[SEL2]] -; CHECK-NEXT: ret i32 [[OR]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 %a, %b +; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 %c, i32 %d +; CHECK-NEXT: ret i32 [[SEL]] ; %cmp1 = icmp slt i32 %a, %b %sel1 = select i1 %cmp1, i32 0, i32 %c @@ -105,12 +99,9 @@ define i32 @fold_inverted_fcmp_preds(float %a, float %b, i32 %c, i32 %d) { ; CHECK-LABEL: @fold_inverted_fcmp_preds( -; CHECK-NEXT: [[CMP1:%.*]] = fcmp olt float %a, %b -; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CMP1]], i32 %c, i32 0 -; CHECK-NEXT: [[CMP2:%.*]] = fcmp uge float %a, %b -; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i32 %d, i32 0 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[SEL1]], [[SEL2]] -; CHECK-NEXT: ret i32 [[OR]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float %a, %b +; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 %c, i32 %d +; CHECK-NEXT: ret i32 [[SEL]] ; %cmp1 = fcmp olt float %a, %b %sel1 = select i1 %cmp1, i32 %c, i32 0 @@ -122,12 +113,9 @@ define <2 x i32> @fold_inverted_icmp_vector_preds(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c, <2 x i32> %d) { ; CHECK-LABEL: @fold_inverted_icmp_vector_preds( -; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> %a, %b -; CHECK-NEXT: [[SEL1:%.*]] = select <2 x i1> [[CMP1]], <2 x i32> %c, <2 x i32> zeroinitializer -; CHECK-NEXT: [[CMP2:%.*]] = icmp eq <2 x i32> %a, %b -; CHECK-NEXT: [[SEL2:%.*]] = select <2 x i1> [[CMP2]], <2 x i32> %d, <2 x i32> zeroinitializer -; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[SEL1]], [[SEL2]] -; CHECK-NEXT: ret <2 x i32> [[OR]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> %a, %b +; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i32> %c, <2 x i32> %d +; CHECK-NEXT: ret <2 x i32> [[SEL]] ; %cmp1 = icmp ne <2 x i32> %a, %b %sel1 = select <2 x i1> %cmp1, <2 x i32> %c, <2 x i32>