Index: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -2570,6 +2570,22 @@ 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, b) + if (match(CondVal, m_Or(m_Not(m_Value(TrueVal)), m_Value(C))) && + CondVal->hasOneUse()) { + if (!llvm::isGuaranteedNotToBePoison(FalseVal)) + FalseVal = Builder.CreateFreeze(FalseVal); + return BinaryOperator::CreateAnd(TrueVal, Builder.CreateOr(C, FalseVal)); + } + // select (~c & b), a, b -> and b, (or a, c) + if (match(CondVal, m_And(m_Not(m_Value(C)), m_Value(FalseVal))) && + CondVal->hasOneUse()) { + if (!llvm::isGuaranteedNotToBePoison(TrueVal)) + 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)) Index: llvm/test/Transforms/InstCombine/select-and-or.ll =================================================================== --- llvm/test/Transforms/InstCombine/select-and-or.ll +++ llvm/test/Transforms/InstCombine/select-and-or.ll @@ -448,3 +448,83 @@ %C15 = select i1 %not.L, i1 true, i1 xor (i1 and (i1 icmp eq (i16* getelementptr inbounds (i16, i16* @g2, i64 1), i16* @g1), i1 icmp ne (i16* getelementptr inbounds (i16, i16* @g2, i64 1), i16* @g1)), i1 true) ret i1 %C15 } + +define i1 @and_or1(i1 %a, i1 %b, i1 %c) { +; CHECK-LABEL: @and_or1( +; 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 + %cond = or i1 %nota, %c + %r = select i1 %cond, i1 %a, i1 %b + ret i1 %r +} + +define i1 @and_or2(i1 %a, i1 %b, i1 %c) { +; CHECK-LABEL: @and_or2( +; 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 + %cond = and i1 %notc, %b + %r = select i1 %cond, i1 %a, i1 %b + ret i1 %r +} + +define i1 @and_or1_bundef(i1 %a, i1 noundef %b, i1 %c) { +; CHECK-LABEL: @and_or1_bundef( +; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[C:%.*]], [[B:%.*]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[A:%.*]] +; CHECK-NEXT: ret i1 [[R]] +; + %nota = xor i1 %a, true + %cond = or i1 %nota, %c + %r = select i1 %cond, i1 %a, i1 %b + ret i1 %r +} + +define i1 @and_or2_aundef(i1 noundef %a, i1 %b, i1 %c) { +; CHECK-LABEL: @and_or2_aundef( +; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[C:%.*]], [[A:%.*]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[B:%.*]] +; CHECK-NEXT: ret i1 [[R]] +; + %notc = xor i1 %c, true + %cond = and i1 %notc, %b + %r = select i1 %cond, i1 %a, i1 %b + ret i1 %r +} + +define i1 @no_and_or1_bundef(i1 %a, i1 noundef %b, i1 %c) { +; CHECK-LABEL: @no_and_or1_bundef( +; CHECK-NEXT: [[NOTA:%.*]] = xor i1 [[A:%.*]], true +; CHECK-NEXT: [[COND:%.*]] = or i1 [[NOTA]], [[C:%.*]] +; CHECK-NEXT: call void @use(i1 [[COND]]) +; CHECK-NEXT: [[R:%.*]] = select i1 [[COND]], i1 [[A]], i1 [[B:%.*]] +; CHECK-NEXT: ret i1 [[R]] +; + %nota = xor i1 %a, true + %cond = or i1 %nota, %c + call void @use(i1 %cond) + %r = select i1 %cond, i1 %a, i1 %b + ret i1 %r +} + +define i1 @no_and_or2_aundef(i1 noundef %a, i1 %b, i1 %c) { +; CHECK-LABEL: @no_and_or2_aundef( +; CHECK-NEXT: [[NOTC:%.*]] = xor i1 [[C:%.*]], true +; CHECK-NEXT: [[COND:%.*]] = and i1 [[NOTC]], [[B:%.*]] +; CHECK-NEXT: call void @use(i1 [[COND]]) +; CHECK-NEXT: [[R:%.*]] = select i1 [[COND]], i1 [[A:%.*]], i1 [[B]] +; CHECK-NEXT: ret i1 [[R]] +; + %notc = xor i1 %c, true + %cond = and i1 %notc, %b + call void @use(i1 %cond) + %r = select i1 %cond, i1 %a, i1 %b + ret i1 %r +}