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,14 @@ 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); + // select a, true, (select ~a, b, false) -> select a, true, b + if (match(FalseVal, m_c_LogicalAnd(m_Not(m_Specific(CondVal)), m_Value(B))) && + match(TrueVal, m_One())) + return replaceOperand(SI, 2, 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,131 @@ 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 and_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 +} + +; A | (~A & B) -> A | B +define i1 @or_commute1(i1 %a, i1 %b) { +; CHECK-LABEL: @or_commute1( +; CHECK-NEXT: [[OR:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]] +; CHECK-NEXT: ret i1 [[OR]] +; + %not = xor i1 %a, true + %and = and i1 %not, %b + %or = select i1 %a, i1 true, i1 %and + ret i1 %or +} + +; A | (~A & B) -> A | B +define <2 x i1> @or_commute1_vec(<2 x i1> %a, <2 x i1> %b) { +; CHECK-LABEL: @or_commute1_vec( +; CHECK-NEXT: [[OR:%.*]] = select <2 x i1> [[A:%.*]], <2 x i1> , <2 x i1> [[B:%.*]] +; CHECK-NEXT: ret <2 x i1> [[OR]] +; + %not = xor <2 x i1> %a, + %and = and <2 x i1> %not, %b + %or = select <2 x i1> %a, <2 x i1> , <2 x i1> %and + ret <2 x i1> %or +} + +; A | (~A & B) -> A | B +define i1 @or_commute2(i1 %a, i1 %b) { +; CHECK-LABEL: @or_commute2( +; CHECK-NEXT: [[OR:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]] +; CHECK-NEXT: ret i1 [[OR]] +; + %not = xor i1 %a, true + %and = select i1 %not, i1 %b, i1 false + %or = select i1 %a, i1 true, i1 %and + ret i1 %or +} + +; A | (~A & B) -> A | B +define <2 x i1> @or_commute2_vec(<2 x i1> %a, <2 x i1> %b) { +; CHECK-LABEL: @or_commute2_vec( +; CHECK-NEXT: [[OR:%.*]] = select <2 x i1> [[A:%.*]], <2 x i1> , <2 x i1> [[B:%.*]] +; CHECK-NEXT: ret <2 x i1> [[OR]] +; + %not = xor <2 x i1> %a, + %and = select <2 x i1> %not, <2 x i1> %b, <2 x i1> zeroinitializer + %or = select <2 x i1> %a, <2 x i1> , <2 x i1> %and + ret <2 x i1> %or +} + +; A | (~A & B) -> A | B +; As or_commute1 but with %and's operands switched +define i1 @or_commute3(i1 %a) { +; CHECK-LABEL: @or_commute3( +; CHECK-NEXT: [[B:%.*]] = call i1 @gen() +; CHECK-NEXT: [[OR:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B]] +; CHECK-NEXT: ret i1 [[OR]] +; + %b = call i1 @gen() + %not = xor i1 %a, true + %and = and i1 %b, %not + %or = select i1 %a, i1 true, i1 %and + ret i1 %or +} + +declare i1 @gen()