Skip to content

Commit

Permalink
[InstCombine] Support sinking not into logical operand with inverti…
Browse files Browse the repository at this point in the history
…ble hands

The important bit here is that we gracefully handle other uses,
iff they can be adapted to inversion.

I'll note, the previous logic was actively bad,
it increased instruction count since it didn't actually ensure
that the inversions happened.
  • Loading branch information
LebedevRI committed Dec 19, 2022
1 parent ba9c6ad commit b20cccc
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 140 deletions.
70 changes: 53 additions & 17 deletions llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
Expand Up @@ -3609,6 +3609,55 @@ static Instruction *canonicalizeAbs(BinaryOperator &Xor,
return nullptr;
}

// Transform
// z = ~(x &/| y)
// into:
// z = ((~x) |/& (~y))
// iff both x and y are free to invert and all uses of z can be freely updated.
bool InstCombinerImpl::sinkNotIntoLogicalOp(Instruction &I) {
Value *Op0, *Op1;
if (!match(&I, m_LogicalOp(m_Value(Op0), m_Value(Op1))))
return false;
Instruction::BinaryOps NewOpc =
match(&I, m_LogicalAnd()) ? Instruction::Or : Instruction::And;
bool IsBinaryOp = isa<BinaryOperator>(I);

// Can our users be adapted?
if (!InstCombiner::canFreelyInvertAllUsersOf(&I, /*IgnoredUser=*/nullptr))
return false;

// And can the operands be adapted?
for (Value *Op : {Op0, Op1})
if (!InstCombiner::isFreeToInvert(Op, /*WillInvertAllUses=*/true) ||
!InstCombiner::canFreelyInvertAllUsersOf(Op, /*IgnoredUser=*/&I))
return false;

for (Value **Op : {&Op0, &Op1}) {
Builder.SetInsertPoint(
&*cast<Instruction>(*Op)->getInsertionPointAfterDef());
Value *NotOp = Builder.CreateNot(*Op, (*Op)->getName() + ".not");
(*Op)->replaceUsesWithIf(NotOp,
[NotOp](Use &U) { return U.getUser() != NotOp; });
freelyInvertAllUsersOf(NotOp, /*IgnoredUser=*/&I);
*Op = NotOp;
}

Builder.SetInsertPoint(I.getInsertionPointAfterDef());
Value *NewLogicOp;
if (IsBinaryOp)
NewLogicOp = Builder.CreateBinOp(NewOpc, Op0, Op1, I.getName() + ".not");
else
NewLogicOp =
Builder.CreateLogicalOp(NewOpc, Op0, Op1, I.getName() + ".not");

replaceInstUsesWith(I, NewLogicOp);
// We can not just create an outer `not`, it will most likely be immediately
// folded back, reconstructing our initial pattern, and causing an
// infinite combine loop, so immediately manually fold it away.
freelyInvertAllUsersOf(NewLogicOp);
return true;
}

// Transform
// z = (~x) &/| y
// into:
Expand Down Expand Up @@ -3694,23 +3743,6 @@ Instruction *InstCombinerImpl::foldNot(BinaryOperator &I) {
// Is this a 'not' (~) fed by a binary operator?
BinaryOperator *NotVal;
if (match(NotOp, m_BinOp(NotVal))) {
if (NotVal->getOpcode() == Instruction::And ||
NotVal->getOpcode() == Instruction::Or) {
// Apply DeMorgan's Law when inverts are free:
// ~(X & Y) --> (~X | ~Y)
// ~(X | Y) --> (~X & ~Y)
if (isFreeToInvert(NotVal->getOperand(0),
NotVal->getOperand(0)->hasOneUse()) &&
isFreeToInvert(NotVal->getOperand(1),
NotVal->getOperand(1)->hasOneUse())) {
Value *NotX = Builder.CreateNot(NotVal->getOperand(0), "notlhs");
Value *NotY = Builder.CreateNot(NotVal->getOperand(1), "notrhs");
if (NotVal->getOpcode() == Instruction::And)
return BinaryOperator::CreateOr(NotX, NotY);
return BinaryOperator::CreateAnd(NotX, NotY);
}
}

// ~((-X) | Y) --> (X - 1) & (~Y)
if (match(NotVal,
m_OneUse(m_c_Or(m_OneUse(m_Neg(m_Value(X))), m_Value(Y))))) {
Expand Down Expand Up @@ -3775,6 +3807,10 @@ Instruction *InstCombinerImpl::foldNot(BinaryOperator &I) {
return &I;
}

if (auto *NotOpI = dyn_cast<Instruction>(NotOp))
if (sinkNotIntoLogicalOp(*NotOpI))
return &I;

// Eliminate a bitwise 'not' op of 'not' min/max by inverting the min/max:
// ~min(~X, ~Y) --> max(X, Y)
// ~max(~X, Y) --> min(X, ~Y)
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Transforms/InstCombine/InstCombineInternal.h
Expand Up @@ -106,6 +106,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
Value *simplifyRangeCheck(ICmpInst *Cmp0, ICmpInst *Cmp1, bool Inverted);
Instruction *visitAnd(BinaryOperator &I);
Instruction *visitOr(BinaryOperator &I);
bool sinkNotIntoLogicalOp(Instruction &I);
bool sinkNotIntoOtherHandOfLogicalOp(Instruction &I);
Instruction *visitXor(BinaryOperator &I);
Instruction *visitShl(BinaryOperator &I);
Expand Down Expand Up @@ -330,7 +331,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
Instruction *matchSAddSubSat(IntrinsicInst &MinMax1);
Instruction *foldNot(BinaryOperator &I);

void freelyInvertAllUsersOf(Value *V);
void freelyInvertAllUsersOf(Value *V, Value *IgnoredUser = nullptr);

/// Determine if a pair of casts can be replaced by a single cast.
///
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Expand Up @@ -947,8 +947,10 @@ Value *InstCombinerImpl::SimplifySelectsFeedingBinaryOp(BinaryOperator &I,

/// Freely adapt every user of V as-if V was changed to !V.
/// WARNING: only if canFreelyInvertAllUsersOf() said this can be done.
void InstCombinerImpl::freelyInvertAllUsersOf(Value *I) {
for (User *U : I->users()) {
void InstCombinerImpl::freelyInvertAllUsersOf(Value *I, Value *IgnoredUser) {
for (User *U : make_early_inc_range(I->users())) {
if (U == IgnoredUser)
continue; // Don't consider this user.
switch (cast<Instruction>(U)->getOpcode()) {
case Instruction::Select: {
auto *SI = cast<SelectInst>(U);
Expand Down
58 changes: 24 additions & 34 deletions llvm/test/Transforms/InstCombine/sink-not-into-and.ll
Expand Up @@ -14,8 +14,8 @@ define i1 @t0(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; CHECK-LABEL: @t0(
; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I4:%.*]] = or i1 [[I2]], [[I1]]
; CHECK-NEXT: ret i1 [[I4]]
; CHECK-NEXT: [[I3_NOT:%.*]] = or i1 [[I2]], [[I1]]
; CHECK-NEXT: ret i1 [[I3_NOT]]
;
%i1 = icmp eq i32 %v0, %v1
%i2 = icmp eq i32 %v2, %v3
Expand Down Expand Up @@ -115,13 +115,11 @@ define i1 @n6(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; Hands have invertible uses
define i1 @t7(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; CHECK-LABEL: @t7(
; CHECK-NEXT: [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I1_NOT:%.*]] = xor i1 [[I1]], true
; CHECK-NEXT: call void @use1(i1 [[I1_NOT]])
; CHECK-NEXT: [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I3:%.*]] = and i1 [[I2]], [[I1]]
; CHECK-NEXT: [[I4:%.*]] = xor i1 [[I3]], true
; CHECK-NEXT: ret i1 [[I4]]
; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: call void @use1(i1 [[I1]])
; CHECK-NEXT: [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I3_NOT:%.*]] = or i1 [[I2]], [[I1]]
; CHECK-NEXT: ret i1 [[I3_NOT]]
;
%i1 = icmp eq i32 %v0, %v1
%i1.not = xor i1 %i1, -1
Expand All @@ -133,13 +131,11 @@ define i1 @t7(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
}
define i1 @t8(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; CHECK-LABEL: @t8(
; CHECK-NEXT: [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I2_NOT:%.*]] = xor i1 [[I2]], true
; CHECK-NEXT: call void @use1(i1 [[I2_NOT]])
; CHECK-NEXT: [[I3:%.*]] = and i1 [[I2]], [[I1]]
; CHECK-NEXT: [[I4:%.*]] = xor i1 [[I3]], true
; CHECK-NEXT: ret i1 [[I4]]
; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: call void @use1(i1 [[I2]])
; CHECK-NEXT: [[I3_NOT:%.*]] = or i1 [[I2]], [[I1]]
; CHECK-NEXT: ret i1 [[I3_NOT]]
;
%i1 = icmp eq i32 %v0, %v1
%i2 = icmp eq i32 %v2, %v3
Expand All @@ -151,15 +147,12 @@ define i1 @t8(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
}
define i1 @t9(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; CHECK-LABEL: @t9(
; CHECK-NEXT: [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I1_NOT:%.*]] = xor i1 [[I1]], true
; CHECK-NEXT: call void @use1(i1 [[I1_NOT]])
; CHECK-NEXT: [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I2_NOT:%.*]] = xor i1 [[I2]], true
; CHECK-NEXT: call void @use1(i1 [[I2_NOT]])
; CHECK-NEXT: [[I3:%.*]] = and i1 [[I2]], [[I1]]
; CHECK-NEXT: [[I4:%.*]] = xor i1 [[I3]], true
; CHECK-NEXT: ret i1 [[I4]]
; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: call void @use1(i1 [[I1]])
; CHECK-NEXT: [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: call void @use1(i1 [[I2]])
; CHECK-NEXT: [[I3_NOT:%.*]] = or i1 [[I2]], [[I1]]
; CHECK-NEXT: ret i1 [[I3_NOT]]
;
%i1 = icmp eq i32 %v0, %v1
%i1.not = xor i1 %i1, -1
Expand All @@ -181,8 +174,7 @@ define i1 @n10(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; CHECK-NEXT: [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I3:%.*]] = and i1 [[I2]], [[I1]]
; CHECK-NEXT: call void @use1(i1 [[I3]])
; CHECK-NEXT: [[I4_DEMORGAN:%.*]] = and i1 [[I2]], [[I1]]
; CHECK-NEXT: [[I4:%.*]] = xor i1 [[I4_DEMORGAN]], true
; CHECK-NEXT: [[I4:%.*]] = xor i1 [[I3]], true
; CHECK-NEXT: ret i1 [[I4]]
;
%i1 = icmp eq i32 %v0, %v1
Expand All @@ -196,14 +188,12 @@ define i1 @n10(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; All other uses can be adapted.
define i1 @t11(i32 %v0, i32 %v1, i32 %v2, i32 %v3, i1 %v4, i1 %v5) {
; CHECK-LABEL: @t11(
; CHECK-NEXT: [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I3:%.*]] = and i1 [[I2]], [[I1]]
; CHECK-NEXT: [[I4_DEMORGAN:%.*]] = and i1 [[I2]], [[I1]]
; CHECK-NEXT: [[I4:%.*]] = xor i1 [[I4_DEMORGAN]], true
; CHECK-NEXT: [[I5:%.*]] = select i1 [[I3]], i1 [[V4:%.*]], i1 [[V5:%.*]]
; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I3_NOT:%.*]] = or i1 [[I2]], [[I1]]
; CHECK-NEXT: [[I5:%.*]] = select i1 [[I3_NOT]], i1 [[V5:%.*]], i1 [[V4:%.*]]
; CHECK-NEXT: call void @use1(i1 [[I5]])
; CHECK-NEXT: ret i1 [[I4]]
; CHECK-NEXT: ret i1 [[I3_NOT]]
;
%i1 = icmp eq i32 %v0, %v1
%i2 = icmp eq i32 %v2, %v3
Expand Down
46 changes: 20 additions & 26 deletions llvm/test/Transforms/InstCombine/sink-not-into-logical-and.ll
Expand Up @@ -14,8 +14,8 @@ define i1 @t0(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; CHECK-LABEL: @t0(
; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I3:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
; CHECK-NEXT: ret i1 [[I3]]
; CHECK-NEXT: [[I3_NOT:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
; CHECK-NEXT: ret i1 [[I3_NOT]]
;
%i1 = icmp eq i32 %v0, %v1
%i2 = icmp eq i32 %v2, %v3
Expand Down Expand Up @@ -115,13 +115,11 @@ define i1 @n6(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; Hands have invertible uses
define i1 @t7(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; CHECK-LABEL: @t7(
; CHECK-NEXT: [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I1_NOT:%.*]] = xor i1 [[I1]], true
; CHECK-NEXT: call void @use1(i1 [[I1_NOT]])
; CHECK-NEXT: [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I3:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
; CHECK-NEXT: [[I4:%.*]] = xor i1 [[I3]], true
; CHECK-NEXT: ret i1 [[I4]]
; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: call void @use1(i1 [[I1]])
; CHECK-NEXT: [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I3_NOT:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
; CHECK-NEXT: ret i1 [[I3_NOT]]
;
%i1 = icmp eq i32 %v0, %v1
%i1.not = xor i1 %i1, -1
Expand All @@ -136,8 +134,8 @@ define i1 @t8(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: call void @use1(i1 [[I2]])
; CHECK-NEXT: [[I3:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
; CHECK-NEXT: ret i1 [[I3]]
; CHECK-NEXT: [[I3_NOT:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
; CHECK-NEXT: ret i1 [[I3_NOT]]
;
%i1 = icmp eq i32 %v0, %v1
%i2 = icmp eq i32 %v2, %v3
Expand All @@ -149,15 +147,12 @@ define i1 @t8(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
}
define i1 @t9(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; CHECK-LABEL: @t9(
; CHECK-NEXT: [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I1_NOT:%.*]] = xor i1 [[I1]], true
; CHECK-NEXT: call void @use1(i1 [[I1_NOT]])
; CHECK-NEXT: [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I2_NOT:%.*]] = xor i1 [[I2]], true
; CHECK-NEXT: call void @use1(i1 [[I2_NOT]])
; CHECK-NEXT: [[I3:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
; CHECK-NEXT: [[I4:%.*]] = xor i1 [[I3]], true
; CHECK-NEXT: ret i1 [[I4]]
; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: call void @use1(i1 [[I1]])
; CHECK-NEXT: [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: call void @use1(i1 [[I2]])
; CHECK-NEXT: [[I3_NOT:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
; CHECK-NEXT: ret i1 [[I3_NOT]]
;
%i1 = icmp eq i32 %v0, %v1
%i1.not = xor i1 %i1, -1
Expand Down Expand Up @@ -193,13 +188,12 @@ define i1 @n10(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; All other uses can be adapted.
define i1 @t11(i32 %v0, i32 %v1, i32 %v2, i32 %v3, i1 %v4, i1 %v5) {
; CHECK-LABEL: @t11(
; CHECK-NEXT: [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I3:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
; CHECK-NEXT: [[I4:%.*]] = xor i1 [[I3]], true
; CHECK-NEXT: [[I5:%.*]] = select i1 [[I3]], i1 [[V4:%.*]], i1 [[V5:%.*]]
; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I3_NOT:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
; CHECK-NEXT: [[I5:%.*]] = select i1 [[I3_NOT]], i1 [[V5:%.*]], i1 [[V4:%.*]]
; CHECK-NEXT: call void @use1(i1 [[I5]])
; CHECK-NEXT: ret i1 [[I4]]
; CHECK-NEXT: ret i1 [[I3_NOT]]
;
%i1 = icmp eq i32 %v0, %v1
%i2 = icmp eq i32 %v2, %v3
Expand Down
46 changes: 20 additions & 26 deletions llvm/test/Transforms/InstCombine/sink-not-into-logical-or.ll
Expand Up @@ -14,8 +14,8 @@ define i1 @t0(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; CHECK-LABEL: @t0(
; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I3:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
; CHECK-NEXT: ret i1 [[I3]]
; CHECK-NEXT: [[I3_NOT:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
; CHECK-NEXT: ret i1 [[I3_NOT]]
;
%i1 = icmp eq i32 %v0, %v1
%i2 = icmp eq i32 %v2, %v3
Expand Down Expand Up @@ -115,13 +115,11 @@ define i1 @n6(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; Hands have invertible uses
define i1 @t7(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; CHECK-LABEL: @t7(
; CHECK-NEXT: [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I1_NOT:%.*]] = xor i1 [[I1]], true
; CHECK-NEXT: call void @use1(i1 [[I1_NOT]])
; CHECK-NEXT: [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I3:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
; CHECK-NEXT: [[I4:%.*]] = xor i1 [[I3]], true
; CHECK-NEXT: ret i1 [[I4]]
; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: call void @use1(i1 [[I1]])
; CHECK-NEXT: [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I3_NOT:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
; CHECK-NEXT: ret i1 [[I3_NOT]]
;
%i1 = icmp eq i32 %v0, %v1
%i1.not = xor i1 %i1, -1
Expand All @@ -136,8 +134,8 @@ define i1 @t8(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: call void @use1(i1 [[I2]])
; CHECK-NEXT: [[I3:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
; CHECK-NEXT: ret i1 [[I3]]
; CHECK-NEXT: [[I3_NOT:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
; CHECK-NEXT: ret i1 [[I3_NOT]]
;
%i1 = icmp eq i32 %v0, %v1
%i2 = icmp eq i32 %v2, %v3
Expand All @@ -149,15 +147,12 @@ define i1 @t8(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
}
define i1 @t9(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; CHECK-LABEL: @t9(
; CHECK-NEXT: [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I1_NOT:%.*]] = xor i1 [[I1]], true
; CHECK-NEXT: call void @use1(i1 [[I1_NOT]])
; CHECK-NEXT: [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I2_NOT:%.*]] = xor i1 [[I2]], true
; CHECK-NEXT: call void @use1(i1 [[I2_NOT]])
; CHECK-NEXT: [[I3:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
; CHECK-NEXT: [[I4:%.*]] = xor i1 [[I3]], true
; CHECK-NEXT: ret i1 [[I4]]
; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: call void @use1(i1 [[I1]])
; CHECK-NEXT: [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: call void @use1(i1 [[I2]])
; CHECK-NEXT: [[I3_NOT:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
; CHECK-NEXT: ret i1 [[I3_NOT]]
;
%i1 = icmp eq i32 %v0, %v1
%i1.not = xor i1 %i1, -1
Expand Down Expand Up @@ -193,13 +188,12 @@ define i1 @n10(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; All other uses can be adapted.
define i1 @t11(i32 %v0, i32 %v1, i32 %v2, i32 %v3, i1 %v4, i1 %v5) {
; CHECK-LABEL: @t11(
; CHECK-NEXT: [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I3:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
; CHECK-NEXT: [[I4:%.*]] = xor i1 [[I3]], true
; CHECK-NEXT: [[I5:%.*]] = select i1 [[I3]], i1 [[V4:%.*]], i1 [[V5:%.*]]
; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
; CHECK-NEXT: [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: [[I3_NOT:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
; CHECK-NEXT: [[I5:%.*]] = select i1 [[I3_NOT]], i1 [[V5:%.*]], i1 [[V4:%.*]]
; CHECK-NEXT: call void @use1(i1 [[I5]])
; CHECK-NEXT: ret i1 [[I4]]
; CHECK-NEXT: ret i1 [[I3_NOT]]
;
%i1 = icmp eq i32 %v0, %v1
%i2 = icmp eq i32 %v2, %v3
Expand Down

1 comment on commit b20cccc

@gregbedwell
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LebedevRI : Note that #59613 was bisected back to this commit

Please sign in to comment.