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 @@ -2570,6 +2570,20 @@ match(TrueVal, m_Specific(B)) && match(FalseVal, m_Zero())) return replaceOperand(SI, 0, A); + Value *C; + // select (~a | c), a, b -> and a, (or c, freeze(b)) + if (match(CondVal, m_c_Or(m_Not(m_Specific(TrueVal)), m_Value(C))) && + CondVal->hasOneUse()) { + FalseVal = Builder.CreateFreeze(FalseVal); + return BinaryOperator::CreateAnd(TrueVal, Builder.CreateOr(C, FalseVal)); + } + // select (~c & b), a, b -> and b, (or freeze(a), c) + if (match(CondVal, m_c_And(m_Not(m_Value(C)), m_Specific(FalseVal))) && + CondVal->hasOneUse()) { + TrueVal = Builder.CreateFreeze(TrueVal); + return BinaryOperator::CreateAnd(FalseVal, Builder.CreateOr(C, TrueVal)); + } + if (!SelType->isVectorTy()) { if (Value *S = simplifyWithOpReplaced(TrueVal, CondVal, One, SQ, /* AllowRefinement */ true)) diff --git a/llvm/test/Transforms/InstCombine/select-and-or.ll b/llvm/test/Transforms/InstCombine/select-and-or.ll --- a/llvm/test/Transforms/InstCombine/select-and-or.ll +++ b/llvm/test/Transforms/InstCombine/select-and-or.ll @@ -3,6 +3,7 @@ declare void @use(i1) declare i1 @gen_i1() +declare <2 x i1> @gen_v2i1() ; Should not be converted to "and", which has different poison semantics. define i1 @logical_and(i1 %a, i1 %b) { @@ -452,9 +453,9 @@ define i1 @and_or1(i1 %a, i1 %b, i1 %c) { ; CHECK-LABEL: @and_or1( -; CHECK-NEXT: [[NOTA:%.*]] = xor i1 [[A:%.*]], true -; CHECK-NEXT: [[COND:%.*]] = or i1 [[NOTA]], [[C:%.*]] -; CHECK-NEXT: [[R:%.*]] = select i1 [[COND]], i1 [[A]], i1 [[B:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[C:%.*]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP2]], [[A:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %nota = xor i1 %a, true @@ -465,9 +466,9 @@ define i1 @and_or2(i1 %a, i1 %b, i1 %c) { ; CHECK-LABEL: @and_or2( -; CHECK-NEXT: [[NOTC:%.*]] = xor i1 [[C:%.*]], true -; CHECK-NEXT: [[COND:%.*]] = and i1 [[NOTC]], [[B:%.*]] -; CHECK-NEXT: [[R:%.*]] = select i1 [[COND]], i1 [[A:%.*]], i1 [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[A:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[C:%.*]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP2]], [[B:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %notc = xor i1 %c, true @@ -478,9 +479,8 @@ define i1 @and_or1_bundef(i1 %a, i1 noundef %b, i1 %c) { ; CHECK-LABEL: @and_or1_bundef( -; CHECK-NEXT: [[NOTA:%.*]] = xor i1 [[A:%.*]], true -; CHECK-NEXT: [[COND:%.*]] = or i1 [[NOTA]], [[C:%.*]] -; CHECK-NEXT: [[R:%.*]] = select i1 [[COND]], i1 [[A]], i1 [[B:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[C:%.*]], [[B:%.*]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[A:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %nota = xor i1 %a, true @@ -491,9 +491,8 @@ define i1 @and_or2_aundef(i1 noundef %a, i1 %b, i1 %c) { ; CHECK-LABEL: @and_or2_aundef( -; CHECK-NEXT: [[NOTC:%.*]] = xor i1 [[C:%.*]], true -; CHECK-NEXT: [[COND:%.*]] = and i1 [[NOTC]], [[B:%.*]] -; CHECK-NEXT: [[R:%.*]] = select i1 [[COND]], i1 [[A:%.*]], i1 [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[C:%.*]], [[A:%.*]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[B:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %notc = xor i1 %c, true @@ -535,9 +534,9 @@ define i1 @and_or1_op1not(i1 %a, i1 %b) { ; CHECK-LABEL: @and_or1_op1not( ; CHECK-NEXT: [[C:%.*]] = call i1 @gen_i1() -; CHECK-NEXT: [[NOTA:%.*]] = xor i1 [[A:%.*]], true -; CHECK-NEXT: [[COND:%.*]] = or i1 [[C]], [[NOTA]] -; CHECK-NEXT: [[R:%.*]] = select i1 [[COND]], i1 [[A]], i1 [[B:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[C]], [[TMP1]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP2]], [[A:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %c = call i1 @gen_i1() @@ -547,6 +546,21 @@ ret i1 %r } +define i1 @and_or2_op1not(i1 %a, i1 %c) { +; CHECK-LABEL: @and_or2_op1not( +; CHECK-NEXT: [[B:%.*]] = call i1 @gen_i1() +; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[A:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[C:%.*]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[B]], [[TMP2]] +; CHECK-NEXT: ret i1 [[R]] +; + %b = call i1 @gen_i1() + %notc = xor i1 %c, true + %cond = and i1 %b, %notc + %r = select i1 %cond, i1 %a, i1 %b + ret i1 %r +} + define i1 @neg_and_or1(i1 %a, i1 %b, i1 %c, i1 %d) { ; CHECK-LABEL: @neg_and_or1( ; CHECK-NEXT: [[NOTA:%.*]] = xor i1 [[A:%.*]], true @@ -572,3 +586,18 @@ %r = select i1 %cond, i1 %a, i1 %d ret i1 %r } + +define <2 x i1> @and_or1_op1not_vec(<2 x i1> %a, <2 x i1> %b) { +; CHECK-LABEL: @and_or1_op1not_vec( +; CHECK-NEXT: [[C:%.*]] = call <2 x i1> @gen_v2i1() +; CHECK-NEXT: [[TMP1:%.*]] = freeze <2 x i1> [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = or <2 x i1> [[C]], [[TMP1]] +; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[TMP2]], [[A:%.*]] +; CHECK-NEXT: ret <2 x i1> [[R]] +; + %c = call <2 x i1> @gen_v2i1() + %nota = xor <2 x i1> %a, + %cond = or <2 x i1> %c, %nota + %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b + ret <2 x i1> %r +}