diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h --- a/llvm/include/llvm/IR/PatternMatch.h +++ b/llvm/include/llvm/IR/PatternMatch.h @@ -2446,6 +2446,11 @@ return LogicalOp_match(L, R); } +template +inline auto m_c_LogicalAnd(const LHS &L, const RHS &R) { + return m_CombineOr(m_LogicalAnd(L, R), m_LogicalAnd(R, L)); +} + /// Matches L || R either in the form of L | R or L ? true : R. /// Note that the latter form is poison-blocking. template @@ -2459,6 +2464,11 @@ return m_LogicalOr(m_Value(), m_Value()); } +template +inline auto m_c_LogicalOr(const LHS &L, const RHS &R) { + return m_CombineOr(m_LogicalOr(L, R), m_LogicalOr(R, L)); +} + } // end namespace PatternMatch } // end namespace llvm diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4859,6 +4859,10 @@ if (match(I, m_ExtractValue(m_WithOverflowInst(II))) && match(ValAssumedPoison, m_ExtractValue(m_Specific(II)))) return true; + + // 'select ValAssumedPoison, _, _' is poison. + if (match(I, m_Select(m_Specific(ValAssumedPoison), m_Value(), m_Value()))) + return true; } return false; } 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 @@ -2628,6 +2628,25 @@ if (match(FalseVal, m_Not(m_Specific(CondVal)))) return SelectInst::Create(FalseVal, ConstantInt::getTrue(SelType), TrueVal); + + // select a, (a /\ b), false -> select a, b, false + Value *A, *B; + if (match(TrueVal, m_c_LogicalAnd(m_Specific(CondVal), m_Value(B))) && + match(FalseVal, m_Zero())) + return replaceOperand(SI, 1, B); + // select a, true, (a \/ b) -> select a, true, b + if (match(TrueVal, m_One()) && + match(FalseVal, m_c_LogicalOr(m_Specific(CondVal), m_Value(B)))) + return replaceOperand(SI, 2, B); + + // select (select a, true, b), true, b -> select a, true, b + if (match(CondVal, m_Select(m_Value(A), m_One(), m_Value(B))) && + match(TrueVal, m_One()) && match(FalseVal, m_Specific(B))) + return replaceOperand(SI, 0, A); + // select (select a, b, false), b, false -> select a, b, false + if (match(CondVal, m_Select(m_Value(A), m_Value(B), m_Zero())) && + match(TrueVal, m_Specific(B)) && match(FalseVal, m_Zero())) + return replaceOperand(SI, 0, A); } // Selecting between two integer or vector splat integer constants? diff --git a/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll b/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll --- a/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll +++ b/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll @@ -1,9 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -instcombine-unsafe-select-transform=0 -instcombine -S | FileCheck %s -; TODO: All of these should be optimized to a single instruction of select/ -; and/or. - ; 1. --- X /\ (X /\ Y) --- define i1 @merge_logical_and_and(i1 %X, i1 %Y) { @@ -28,8 +25,7 @@ define i1 @merge_and_logical_and(i1 %X, i1 %Y) { ; CHECK-LABEL: @merge_and_logical_and( -; CHECK-NEXT: [[C:%.*]] = and i1 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[RES:%.*]] = select i1 [[X]], i1 [[C]], i1 false +; CHECK-NEXT: [[RES:%.*]] = select i1 [[X:%.*]], i1 [[Y:%.*]], i1 false ; CHECK-NEXT: ret i1 [[RES]] ; %c = and i1 %X, %Y @@ -52,8 +48,8 @@ define i1 @merge_two_logical_ands2(i1 %X, i1 %Y) { ; CHECK-LABEL: @merge_two_logical_ands2( -; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: ret i1 [[TMP1]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[X:%.*]], i1 [[Y:%.*]], i1 false +; CHECK-NEXT: ret i1 [[RES]] ; %c = select i1 %Y, i1 %X, i1 false %res = select i1 %X, i1 %c, i1 false @@ -62,8 +58,7 @@ define i1 @merge_and_logical_and2(i1 %X, i1 %Y) { ; CHECK-LABEL: @merge_and_logical_and2( -; CHECK-NEXT: [[C:%.*]] = and i1 [[Y:%.*]], [[X:%.*]] -; CHECK-NEXT: [[RES:%.*]] = select i1 [[X]], i1 [[C]], i1 false +; CHECK-NEXT: [[RES:%.*]] = select i1 [[X:%.*]], i1 [[Y:%.*]], i1 false ; CHECK-NEXT: ret i1 [[RES]] ; %c = and i1 %Y, %X @@ -86,8 +81,7 @@ define i1 @merge_two_logical_ands3(i1 %X, i1 %Y) { ; CHECK-LABEL: @merge_two_logical_ands3( ; CHECK-NEXT: [[C:%.*]] = select i1 [[X:%.*]], i1 [[Y:%.*]], i1 false -; CHECK-NEXT: [[RES:%.*]] = select i1 [[C]], i1 [[X]], i1 false -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[C]] ; %c = select i1 %X, i1 %Y, i1 false %res = select i1 %c, i1 %X, i1 false @@ -120,8 +114,7 @@ define i1 @merge_two_logical_ands4(i1 %X, i1 %Y) { ; CHECK-LABEL: @merge_two_logical_ands4( -; CHECK-NEXT: [[C:%.*]] = select i1 [[Y:%.*]], i1 [[X:%.*]], i1 false -; CHECK-NEXT: [[RES:%.*]] = select i1 [[C]], i1 [[X]], i1 false +; CHECK-NEXT: [[RES:%.*]] = select i1 [[Y:%.*]], i1 [[X:%.*]], i1 false ; CHECK-NEXT: ret i1 [[RES]] ; %c = select i1 %Y, i1 %X, i1 false @@ -165,8 +158,7 @@ define i1 @merge_or_logical_or(i1 %X, i1 %Y) { ; CHECK-LABEL: @merge_or_logical_or( -; CHECK-NEXT: [[C:%.*]] = or i1 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[RES:%.*]] = select i1 [[X]], i1 true, i1 [[C]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[Y:%.*]] ; CHECK-NEXT: ret i1 [[RES]] ; %c = or i1 %X, %Y @@ -189,8 +181,8 @@ define i1 @merge_two_logical_ors2(i1 %X, i1 %Y) { ; CHECK-LABEL: @merge_two_logical_ors2( -; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: ret i1 [[TMP1]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[Y:%.*]] +; CHECK-NEXT: ret i1 [[RES]] ; %c = select i1 %Y, i1 true, i1 %X %res = select i1 %X, i1 true, i1 %c @@ -199,8 +191,7 @@ define i1 @merge_or_logical_or2(i1 %X, i1 %Y) { ; CHECK-LABEL: @merge_or_logical_or2( -; CHECK-NEXT: [[C:%.*]] = or i1 [[Y:%.*]], [[X:%.*]] -; CHECK-NEXT: [[RES:%.*]] = select i1 [[X]], i1 true, i1 [[C]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[Y:%.*]] ; CHECK-NEXT: ret i1 [[RES]] ; %c = or i1 %Y, %X @@ -223,8 +214,7 @@ define i1 @merge_two_logical_ors3(i1 %X, i1 %Y) { ; CHECK-LABEL: @merge_two_logical_ors3( ; CHECK-NEXT: [[C:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[Y:%.*]] -; CHECK-NEXT: [[RES:%.*]] = select i1 [[C]], i1 true, i1 [[X]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[C]] ; %c = select i1 %X, i1 true, i1 %Y %res = select i1 %c, i1 true, i1 %X @@ -257,8 +247,7 @@ define i1 @merge_two_logical_ors4(i1 %X, i1 %Y) { ; CHECK-LABEL: @merge_two_logical_ors4( -; CHECK-NEXT: [[C:%.*]] = select i1 [[Y:%.*]], i1 true, i1 [[X:%.*]] -; CHECK-NEXT: [[RES:%.*]] = select i1 [[C]], i1 true, i1 [[X]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[Y:%.*]], i1 true, i1 [[X:%.*]] ; CHECK-NEXT: ret i1 [[RES]] ; %c = select i1 %Y, i1 true, i1 %X