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 @@ -2984,6 +2984,10 @@ 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); + // select a, (select ~a, true, b), false -> select a, b, false + if (match(TrueVal, m_c_LogicalOr(m_Not(m_Specific(CondVal)), m_Value(B))) && + match(FalseVal, m_Zero())) + return replaceOperand(SI, 1, B); // ~(A & B) & (A | B) --> A ^ B if (match(&SI, m_c_LogicalAnd(m_Not(m_LogicalAnd(m_Value(A), m_Value(B))), diff --git a/llvm/test/Transforms/InstCombine/logical-select.ll b/llvm/test/Transforms/InstCombine/logical-select.ll --- a/llvm/test/Transforms/InstCombine/logical-select.ll +++ b/llvm/test/Transforms/InstCombine/logical-select.ll @@ -1121,3 +1121,68 @@ call void @use1(i1 %and1) ret i1 %r } + +; A & (~A | B) --> A & B +define i1 @and_commute1(i1 %a, i1 %b) { +; CHECK-LABEL: @and_commute1( +; CHECK-NEXT: [[AND:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false +; CHECK-NEXT: ret i1 [[AND]] +; + %not = xor i1 %a, true + %or = or i1 %not, %b + %and = select i1 %a, i1 %or, i1 zeroinitializer + ret i1 %and +} + +; A & (~A | B) --> A & B +define <2 x i1> @and_commute1_vec(<2 x i1> %a, <2 x i1> %b) { +; CHECK-LABEL: @and_commute1_vec( +; CHECK-NEXT: [[AND:%.*]] = select <2 x i1> [[A:%.*]], <2 x i1> [[B:%.*]], <2 x i1> zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[AND]] +; + %not = xor <2 x i1> %a, + %or = or <2 x i1> %not, %b + %and = select <2 x i1> %a, <2 x i1> %or, <2 x i1> zeroinitializer + ret <2 x i1> %and +} + +; A & (~A | B) --> A & B +define i1 @and_commute2(i1 %a, i1 %b) { +; CHECK-LABEL: @and_commute2( +; CHECK-NEXT: [[AND:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false +; CHECK-NEXT: ret i1 [[AND]] +; + %not = xor i1 %a, true + %or = select i1 %not, i1 true, i1 %b + %and = select i1 %a, i1 %or, i1 zeroinitializer + ret i1 %and +} + +; A & (~A | B) --> A & B +define <2 x i1> @and_commute2_vec(<2 x i1> %a, <2 x i1> %b) { +; CHECK-LABEL: @and_commute2_vec( +; CHECK-NEXT: [[AND:%.*]] = select <2 x i1> [[A:%.*]], <2 x i1> [[B:%.*]], <2 x i1> zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[AND]] +; + %not = xor <2 x i1> %a, + %or = select <2 x i1> %not, <2 x i1> , <2 x i1> %b + %and = select <2 x i1> %a, <2 x i1> %or, <2 x i1> zeroinitializer + ret <2 x i1> %and +} + +; A & (~A | B) --> A & B +; As commute1 but with %or's operands switched +define i1 @and_commute3(i1 %a) { +; CHECK-LABEL: @and_commute3( +; CHECK-NEXT: [[B:%.*]] = call i1 @gen() +; CHECK-NEXT: [[AND:%.*]] = select i1 [[A:%.*]], i1 [[B]], i1 false +; CHECK-NEXT: ret i1 [[AND]] +; + %b = call i1 @gen() + %not = xor i1 %a, true + %or = or i1 %b, %not + %and = select i1 %a, i1 %or, i1 zeroinitializer + ret i1 %and +} + +declare i1 @gen()