Index: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2266,6 +2266,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 @@ -62,6 +62,64 @@ ret i32 %t3 } +; PR32791 - https://bugs.llvm.org//show_bug.cgi?id=32791 +; 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: [[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 + %cmp2 = icmp sge i32 %a, %b + %sel2 = select i1 %cmp2, i32 %d, i32 0 + %or = or i32 %sel1, %sel2 + ret i32 %or +} + +define i32 @fold_inverted_icmp_preds_reverse(i32 %a, i32 %b, i32 %c, i32 %d) { +; CHECK-LABEL: @fold_inverted_icmp_preds_reverse( +; 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 + %cmp2 = icmp sge i32 %a, %b + %sel2 = select i1 %cmp2, i32 0, i32 %d + %or = or i32 %sel1, %sel2 + ret i32 %or +} + +define i32 @fold_inverted_fcmp_preds(float %a, float %b, i32 %c, i32 %d) { +; CHECK-LABEL: @fold_inverted_fcmp_preds( +; 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 + %cmp2 = fcmp uge float %a, %b + %sel2 = select i1 %cmp2, i32 %d, i32 0 + %or = or i32 %sel1, %sel2 + ret i32 %or +} + +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: [[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> + %cmp2 = icmp eq <2 x i32> %a, %b + %sel2 = select <2 x i1> %cmp2, <2 x i32> %d, <2 x i32> + %or = or <2 x i32> %sel1, %sel2 + ret <2 x i32> %or +} + define i32 @par(i32 %a, i32 %b, i32 %c, i32 %d) { ; CHECK-LABEL: @par( ; CHECK-NEXT: [[T0:%.*]] = icmp slt i32 %a, %b