aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
commit344a3780b2e33f6ca763666c380202b18aab72a3 (patch)
treef0b203ee6eb71d7fdd792373e3c81eb18d6934dd /llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
parentb60736ec1405bb0a8dd40989f67ef4c93da068ab (diff)
downloadsrc-344a3780b2e33f6ca763666c380202b18aab72a3.tar.gz
src-344a3780b2e33f6ca763666c380202b18aab72a3.zip
the upstream release/13.x branch was created.
Diffstat (limited to 'llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp')
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp334
1 files changed, 239 insertions, 95 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 68c4156af2c4..120852c44474 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -798,36 +798,35 @@ foldAndOrOfEqualityCmpsWithConstants(ICmpInst *LHS, ICmpInst *RHS,
// Fold (!iszero(A & K1) & !iszero(A & K2)) -> (A & (K1 | K2)) == (K1 | K2)
Value *InstCombinerImpl::foldAndOrOfICmpsOfAndWithPow2(ICmpInst *LHS,
ICmpInst *RHS,
- BinaryOperator &Logic) {
- bool JoinedByAnd = Logic.getOpcode() == Instruction::And;
- assert((JoinedByAnd || Logic.getOpcode() == Instruction::Or) &&
- "Wrong opcode");
- ICmpInst::Predicate Pred = LHS->getPredicate();
- if (Pred != RHS->getPredicate())
- return nullptr;
- if (JoinedByAnd && Pred != ICmpInst::ICMP_NE)
- return nullptr;
- if (!JoinedByAnd && Pred != ICmpInst::ICMP_EQ)
+ Instruction *CxtI,
+ bool IsAnd,
+ bool IsLogical) {
+ CmpInst::Predicate Pred = IsAnd ? CmpInst::ICMP_NE : CmpInst::ICMP_EQ;
+ if (LHS->getPredicate() != Pred || RHS->getPredicate() != Pred)
return nullptr;
if (!match(LHS->getOperand(1), m_Zero()) ||
!match(RHS->getOperand(1), m_Zero()))
return nullptr;
- Value *A, *B, *C, *D;
- if (match(LHS->getOperand(0), m_And(m_Value(A), m_Value(B))) &&
- match(RHS->getOperand(0), m_And(m_Value(C), m_Value(D)))) {
- if (A == D || B == D)
- std::swap(C, D);
- if (B == C)
- std::swap(A, B);
-
- if (A == C &&
- isKnownToBeAPowerOfTwo(B, false, 0, &Logic) &&
- isKnownToBeAPowerOfTwo(D, false, 0, &Logic)) {
- Value *Mask = Builder.CreateOr(B, D);
- Value *Masked = Builder.CreateAnd(A, Mask);
- auto NewPred = JoinedByAnd ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE;
+ Value *L1, *L2, *R1, *R2;
+ if (match(LHS->getOperand(0), m_And(m_Value(L1), m_Value(L2))) &&
+ match(RHS->getOperand(0), m_And(m_Value(R1), m_Value(R2)))) {
+ if (L1 == R2 || L2 == R2)
+ std::swap(R1, R2);
+ if (L2 == R1)
+ std::swap(L1, L2);
+
+ if (L1 == R1 &&
+ isKnownToBeAPowerOfTwo(L2, false, 0, CxtI) &&
+ isKnownToBeAPowerOfTwo(R2, false, 0, CxtI)) {
+ // If this is a logical and/or, then we must prevent propagation of a
+ // poison value from the RHS by inserting freeze.
+ if (IsLogical)
+ R2 = Builder.CreateFreeze(R2);
+ Value *Mask = Builder.CreateOr(L2, R2);
+ Value *Masked = Builder.CreateAnd(L1, Mask);
+ auto NewPred = IsAnd ? CmpInst::ICMP_EQ : CmpInst::ICMP_NE;
return Builder.CreateICmp(NewPred, Masked, Mask);
}
}
@@ -1076,6 +1075,87 @@ static Value *foldUnsignedUnderflowCheck(ICmpInst *ZeroICmp,
return nullptr;
}
+struct IntPart {
+ Value *From;
+ unsigned StartBit;
+ unsigned NumBits;
+};
+
+/// Match an extraction of bits from an integer.
+static Optional<IntPart> matchIntPart(Value *V) {
+ Value *X;
+ if (!match(V, m_OneUse(m_Trunc(m_Value(X)))))
+ return None;
+
+ unsigned NumOriginalBits = X->getType()->getScalarSizeInBits();
+ unsigned NumExtractedBits = V->getType()->getScalarSizeInBits();
+ Value *Y;
+ const APInt *Shift;
+ // For a trunc(lshr Y, Shift) pattern, make sure we're only extracting bits
+ // from Y, not any shifted-in zeroes.
+ if (match(X, m_OneUse(m_LShr(m_Value(Y), m_APInt(Shift)))) &&
+ Shift->ule(NumOriginalBits - NumExtractedBits))
+ return {{Y, (unsigned)Shift->getZExtValue(), NumExtractedBits}};
+ return {{X, 0, NumExtractedBits}};
+}
+
+/// Materialize an extraction of bits from an integer in IR.
+static Value *extractIntPart(const IntPart &P, IRBuilderBase &Builder) {
+ Value *V = P.From;
+ if (P.StartBit)
+ V = Builder.CreateLShr(V, P.StartBit);
+ Type *TruncTy = V->getType()->getWithNewBitWidth(P.NumBits);
+ if (TruncTy != V->getType())
+ V = Builder.CreateTrunc(V, TruncTy);
+ return V;
+}
+
+/// (icmp eq X0, Y0) & (icmp eq X1, Y1) -> icmp eq X01, Y01
+/// (icmp ne X0, Y0) | (icmp ne X1, Y1) -> icmp ne X01, Y01
+/// where X0, X1 and Y0, Y1 are adjacent parts extracted from an integer.
+static Value *foldEqOfParts(ICmpInst *Cmp0, ICmpInst *Cmp1, bool IsAnd,
+ InstCombiner::BuilderTy &Builder) {
+ if (!Cmp0->hasOneUse() || !Cmp1->hasOneUse())
+ return nullptr;
+
+ CmpInst::Predicate Pred = IsAnd ? CmpInst::ICMP_EQ : CmpInst::ICMP_NE;
+ if (Cmp0->getPredicate() != Pred || Cmp1->getPredicate() != Pred)
+ return nullptr;
+
+ Optional<IntPart> L0 = matchIntPart(Cmp0->getOperand(0));
+ Optional<IntPart> R0 = matchIntPart(Cmp0->getOperand(1));
+ Optional<IntPart> L1 = matchIntPart(Cmp1->getOperand(0));
+ Optional<IntPart> R1 = matchIntPart(Cmp1->getOperand(1));
+ if (!L0 || !R0 || !L1 || !R1)
+ return nullptr;
+
+ // Make sure the LHS/RHS compare a part of the same value, possibly after
+ // an operand swap.
+ if (L0->From != L1->From || R0->From != R1->From) {
+ if (L0->From != R1->From || R0->From != L1->From)
+ return nullptr;
+ std::swap(L1, R1);
+ }
+
+ // Make sure the extracted parts are adjacent, canonicalizing to L0/R0 being
+ // the low part and L1/R1 being the high part.
+ if (L0->StartBit + L0->NumBits != L1->StartBit ||
+ R0->StartBit + R0->NumBits != R1->StartBit) {
+ if (L1->StartBit + L1->NumBits != L0->StartBit ||
+ R1->StartBit + R1->NumBits != R0->StartBit)
+ return nullptr;
+ std::swap(L0, L1);
+ std::swap(R0, R1);
+ }
+
+ // We can simplify to a comparison of these larger parts of the integers.
+ IntPart L = {L0->From, L0->StartBit, L0->NumBits + L1->NumBits};
+ IntPart R = {R0->From, R0->StartBit, R0->NumBits + R1->NumBits};
+ Value *LValue = extractIntPart(L, Builder);
+ Value *RValue = extractIntPart(R, Builder);
+ return Builder.CreateICmp(Pred, LValue, RValue);
+}
+
/// Reduce logic-of-compares with equality to a constant by substituting a
/// common operand with the constant. Callers are expected to call this with
/// Cmp0/Cmp1 switched to handle logic op commutativity.
@@ -1129,7 +1209,8 @@ Value *InstCombinerImpl::foldAndOfICmps(ICmpInst *LHS, ICmpInst *RHS,
// Fold (!iszero(A & K1) & !iszero(A & K2)) -> (A & (K1 | K2)) == (K1 | K2)
// if K1 and K2 are a one-bit mask.
- if (Value *V = foldAndOrOfICmpsOfAndWithPow2(LHS, RHS, And))
+ if (Value *V = foldAndOrOfICmpsOfAndWithPow2(LHS, RHS, &And,
+ /* IsAnd */ true))
return V;
ICmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate();
@@ -1181,6 +1262,9 @@ Value *InstCombinerImpl::foldAndOfICmps(ICmpInst *LHS, ICmpInst *RHS,
foldUnsignedUnderflowCheck(RHS, LHS, /*IsAnd=*/true, Q, Builder))
return X;
+ if (Value *X = foldEqOfParts(LHS, RHS, /*IsAnd=*/true, Builder))
+ return X;
+
// This only handles icmp of constants: (icmp1 A, C1) & (icmp2 B, C2).
Value *LHS0 = LHS->getOperand(0), *RHS0 = RHS->getOperand(0);
@@ -1876,6 +1960,19 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
if (Instruction *Z = narrowMaskedBinOp(I))
return Z;
+ if (I.getType()->isIntOrIntVectorTy(1)) {
+ if (auto *SI0 = dyn_cast<SelectInst>(Op0)) {
+ if (auto *I =
+ foldAndOrOfSelectUsingImpliedCond(Op1, *SI0, /* IsAnd */ true))
+ return I;
+ }
+ if (auto *SI1 = dyn_cast<SelectInst>(Op1)) {
+ if (auto *I =
+ foldAndOrOfSelectUsingImpliedCond(Op0, *SI1, /* IsAnd */ true))
+ return I;
+ }
+ }
+
if (Instruction *FoldedLogic = foldBinOpIntoSelectOrPhi(I))
return FoldedLogic;
@@ -1987,48 +2084,20 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
if (sinkNotIntoOtherHandOfAndOrOr(I))
return &I;
+ // An and recurrence w/loop invariant step is equivelent to (and start, step)
+ PHINode *PN = nullptr;
+ Value *Start = nullptr, *Step = nullptr;
+ if (matchSimpleRecurrence(&I, PN, Start, Step) && DT.dominates(Step, PN))
+ return replaceInstUsesWith(I, Builder.CreateAnd(Start, Step));
+
return nullptr;
}
-Instruction *InstCombinerImpl::matchBSwapOrBitReverse(BinaryOperator &Or,
+Instruction *InstCombinerImpl::matchBSwapOrBitReverse(Instruction &I,
bool MatchBSwaps,
bool MatchBitReversals) {
- assert(Or.getOpcode() == Instruction::Or && "bswap requires an 'or'");
- Value *Op0 = Or.getOperand(0), *Op1 = Or.getOperand(1);
-
- // Look through zero extends.
- if (Instruction *Ext = dyn_cast<ZExtInst>(Op0))
- Op0 = Ext->getOperand(0);
-
- if (Instruction *Ext = dyn_cast<ZExtInst>(Op1))
- Op1 = Ext->getOperand(0);
-
- // (A | B) | C and A | (B | C) -> bswap if possible.
- bool OrWithOrs = match(Op0, m_Or(m_Value(), m_Value())) ||
- match(Op1, m_Or(m_Value(), m_Value()));
-
- // (A >> B) | C and (A << B) | C -> bswap if possible.
- bool OrWithShifts = match(Op0, m_LogicalShift(m_Value(), m_Value())) ||
- match(Op1, m_LogicalShift(m_Value(), m_Value()));
-
- // (A & B) | C and A | (B & C) -> bswap if possible.
- bool OrWithAnds = match(Op0, m_And(m_Value(), m_Value())) ||
- match(Op1, m_And(m_Value(), m_Value()));
-
- // fshl(A,B,C) | D and A | fshl(B,C,D) -> bswap if possible.
- // fshr(A,B,C) | D and A | fshr(B,C,D) -> bswap if possible.
- bool OrWithFunnels = match(Op0, m_FShl(m_Value(), m_Value(), m_Value())) ||
- match(Op0, m_FShr(m_Value(), m_Value(), m_Value())) ||
- match(Op0, m_FShl(m_Value(), m_Value(), m_Value())) ||
- match(Op0, m_FShr(m_Value(), m_Value(), m_Value()));
-
- // TODO: Do we need all these filtering checks or should we just rely on
- // recognizeBSwapOrBitReverseIdiom + collectBitParts to reject them quickly?
- if (!OrWithOrs && !OrWithShifts && !OrWithAnds && !OrWithFunnels)
- return nullptr;
-
SmallVector<Instruction *, 4> Insts;
- if (!recognizeBSwapOrBitReverseIdiom(&Or, MatchBSwaps, MatchBitReversals,
+ if (!recognizeBSwapOrBitReverseIdiom(&I, MatchBSwaps, MatchBitReversals,
Insts))
return nullptr;
Instruction *LastInst = Insts.pop_back_val();
@@ -2138,7 +2207,7 @@ static Instruction *matchFunnelShift(Instruction &Or, InstCombinerImpl &IC) {
Intrinsic::ID IID = IsFshl ? Intrinsic::fshl : Intrinsic::fshr;
Function *F = Intrinsic::getDeclaration(Or.getModule(), IID, Or.getType());
- return IntrinsicInst::Create(F, {ShVal0, ShVal1, ShAmt});
+ return CallInst::Create(F, {ShVal0, ShVal1, ShAmt});
}
/// Attempt to combine or(zext(x),shl(zext(y),bw/2) concat packing patterns.
@@ -2298,7 +2367,8 @@ Value *InstCombinerImpl::foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
// Fold (iszero(A & K1) | iszero(A & K2)) -> (A & (K1 | K2)) != (K1 | K2)
// if K1 and K2 are a one-bit mask.
- if (Value *V = foldAndOrOfICmpsOfAndWithPow2(LHS, RHS, Or))
+ if (Value *V = foldAndOrOfICmpsOfAndWithPow2(LHS, RHS, &Or,
+ /* IsAnd */ false))
return V;
ICmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate();
@@ -2426,6 +2496,9 @@ Value *InstCombinerImpl::foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
foldUnsignedUnderflowCheck(RHS, LHS, /*IsAnd=*/false, Q, Builder))
return X;
+ if (Value *X = foldEqOfParts(LHS, RHS, /*IsAnd=*/false, Builder))
+ return X;
+
// (icmp ne A, 0) | (icmp ne B, 0) --> (icmp ne (A|B), 0)
// TODO: Remove this when foldLogOpOfMaskedICmps can handle vectors.
if (PredL == ICmpInst::ICMP_NE && match(LHS1, m_Zero()) &&
@@ -2581,12 +2654,26 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
if (Value *V = SimplifyBSwap(I, Builder))
return replaceInstUsesWith(I, V);
+ Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
+ if (I.getType()->isIntOrIntVectorTy(1)) {
+ if (auto *SI0 = dyn_cast<SelectInst>(Op0)) {
+ if (auto *I =
+ foldAndOrOfSelectUsingImpliedCond(Op1, *SI0, /* IsAnd */ false))
+ return I;
+ }
+ if (auto *SI1 = dyn_cast<SelectInst>(Op1)) {
+ if (auto *I =
+ foldAndOrOfSelectUsingImpliedCond(Op0, *SI1, /* IsAnd */ false))
+ return I;
+ }
+ }
+
if (Instruction *FoldedLogic = foldBinOpIntoSelectOrPhi(I))
return FoldedLogic;
- if (Instruction *BSwap = matchBSwapOrBitReverse(I, /*MatchBSwaps*/ true,
- /*MatchBitReversals*/ false))
- return BSwap;
+ if (Instruction *BitOp = matchBSwapOrBitReverse(I, /*MatchBSwaps*/ true,
+ /*MatchBitReversals*/ true))
+ return BitOp;
if (Instruction *Funnel = matchFunnelShift(I, *this))
return Funnel;
@@ -2605,7 +2692,6 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
}
// (A & C)|(B & D)
- Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
Value *A, *B, *C, *D;
if (match(Op0, m_And(m_Value(A), m_Value(C))) &&
match(Op1, m_And(m_Value(B), m_Value(D)))) {
@@ -2871,6 +2957,23 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
if (sinkNotIntoOtherHandOfAndOrOr(I))
return &I;
+ // Improve "get low bit mask up to and including bit X" pattern:
+ // (1 << X) | ((1 << X) + -1) --> -1 l>> (bitwidth(x) - 1 - X)
+ if (match(&I, m_c_Or(m_Add(m_Shl(m_One(), m_Value(X)), m_AllOnes()),
+ m_Shl(m_One(), m_Deferred(X)))) &&
+ match(&I, m_c_Or(m_OneUse(m_Value()), m_Value()))) {
+ Type *Ty = X->getType();
+ Value *Sub = Builder.CreateSub(
+ ConstantInt::get(Ty, Ty->getScalarSizeInBits() - 1), X);
+ return BinaryOperator::CreateLShr(Constant::getAllOnesValue(Ty), Sub);
+ }
+
+ // An or recurrence w/loop invariant step is equivelent to (or start, step)
+ PHINode *PN = nullptr;
+ Value *Start = nullptr, *Step = nullptr;
+ if (matchSimpleRecurrence(&I, PN, Start, Step) && DT.dominates(Step, PN))
+ return replaceInstUsesWith(I, Builder.CreateOr(Start, Step));
+
return nullptr;
}
@@ -3097,6 +3200,39 @@ static Instruction *sinkNotIntoXor(BinaryOperator &I,
return BinaryOperator::CreateXor(NotX, Y, I.getName() + ".demorgan");
}
+/// Canonicalize a shifty way to code absolute value to the more common pattern
+/// that uses negation and select.
+static Instruction *canonicalizeAbs(BinaryOperator &Xor,
+ InstCombiner::BuilderTy &Builder) {
+ assert(Xor.getOpcode() == Instruction::Xor && "Expected an xor instruction.");
+
+ // There are 4 potential commuted variants. Move the 'ashr' candidate to Op1.
+ // We're relying on the fact that we only do this transform when the shift has
+ // exactly 2 uses and the add has exactly 1 use (otherwise, we might increase
+ // instructions).
+ Value *Op0 = Xor.getOperand(0), *Op1 = Xor.getOperand(1);
+ if (Op0->hasNUses(2))
+ std::swap(Op0, Op1);
+
+ Type *Ty = Xor.getType();
+ Value *A;
+ const APInt *ShAmt;
+ if (match(Op1, m_AShr(m_Value(A), m_APInt(ShAmt))) &&
+ Op1->hasNUses(2) && *ShAmt == Ty->getScalarSizeInBits() - 1 &&
+ match(Op0, m_OneUse(m_c_Add(m_Specific(A), m_Specific(Op1))))) {
+ // Op1 = ashr i32 A, 31 ; smear the sign bit
+ // xor (add A, Op1), Op1 ; add -1 and flip bits if negative
+ // --> (A < 0) ? -A : A
+ Value *Cmp = Builder.CreateICmpSLT(A, ConstantInt::getNullValue(Ty));
+ // Copy the nuw/nsw flags from the add to the negate.
+ auto *Add = cast<BinaryOperator>(Op0);
+ Value *Neg = Builder.CreateNeg(A, "", Add->hasNoUnsignedWrap(),
+ Add->hasNoSignedWrap());
+ return SelectInst::Create(Cmp, Neg, A);
+ }
+ return nullptr;
+}
+
// Transform
// z = (~x) &/| y
// into:
@@ -3221,10 +3357,13 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
}
}
- // ~(X - Y) --> ~X + Y
- if (match(NotVal, m_Sub(m_Value(X), m_Value(Y))))
- if (isa<Constant>(X) || NotVal->hasOneUse())
- return BinaryOperator::CreateAdd(Builder.CreateNot(X), Y);
+ // ~((-X) | Y) --> (X - 1) & (~Y)
+ if (match(NotVal,
+ m_OneUse(m_c_Or(m_OneUse(m_Neg(m_Value(X))), m_Value(Y))))) {
+ Value *DecX = Builder.CreateAdd(X, ConstantInt::getAllOnesValue(Ty));
+ Value *NotY = Builder.CreateNot(Y);
+ return BinaryOperator::CreateAnd(DecX, NotY);
+ }
// ~(~X >>s Y) --> (X >>s Y)
if (match(NotVal, m_AShr(m_Not(m_Value(X)), m_Value(Y))))
@@ -3256,9 +3395,15 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
return BinaryOperator::CreateAShr(ConstantExpr::getNot(C), Y);
}
- // ~(X + C) --> -(C + 1) - X
- if (match(Op0, m_Add(m_Value(X), m_Constant(C))))
- return BinaryOperator::CreateSub(ConstantExpr::getNeg(AddOne(C)), X);
+ // ~(X + C) --> ~C - X
+ if (match(NotVal, m_c_Add(m_Value(X), m_ImmConstant(C))))
+ return BinaryOperator::CreateSub(ConstantExpr::getNot(C), X);
+
+ // ~(X - Y) --> ~X + Y
+ // FIXME: is it really beneficial to sink the `not` here?
+ if (match(NotVal, m_Sub(m_Value(X), m_Value(Y))))
+ if (isa<Constant>(X) || NotVal->hasOneUse())
+ return BinaryOperator::CreateAdd(Builder.CreateNot(X), Y);
// ~(~X + Y) --> X - Y
if (match(NotVal, m_c_Add(m_Not(m_Value(X)), m_Value(Y))))
@@ -3427,29 +3572,25 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
if (Instruction *CastedXor = foldCastedBitwiseLogic(I))
return CastedXor;
- // Canonicalize a shifty way to code absolute value to the common pattern.
- // There are 4 potential commuted variants. Move the 'ashr' candidate to Op1.
- // We're relying on the fact that we only do this transform when the shift has
- // exactly 2 uses and the add has exactly 1 use (otherwise, we might increase
- // instructions).
- if (Op0->hasNUses(2))
- std::swap(Op0, Op1);
-
- const APInt *ShAmt;
- if (match(Op1, m_AShr(m_Value(A), m_APInt(ShAmt))) &&
- Op1->hasNUses(2) && *ShAmt == Ty->getScalarSizeInBits() - 1 &&
- match(Op0, m_OneUse(m_c_Add(m_Specific(A), m_Specific(Op1))))) {
- // B = ashr i32 A, 31 ; smear the sign bit
- // xor (add A, B), B ; add -1 and flip bits if negative
- // --> (A < 0) ? -A : A
- Value *Cmp = Builder.CreateICmpSLT(A, ConstantInt::getNullValue(Ty));
- // Copy the nuw/nsw flags from the add to the negate.
- auto *Add = cast<BinaryOperator>(Op0);
- Value *Neg = Builder.CreateNeg(A, "", Add->hasNoUnsignedWrap(),
- Add->hasNoSignedWrap());
- return SelectInst::Create(Cmp, Neg, A);
+ // 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)
+ auto *II = dyn_cast<IntrinsicInst>(Op0);
+ if (II && match(Op1, m_AllOnes())) {
+ if (match(Op0, m_MaxOrMin(m_Not(m_Value(X)), m_Not(m_Value(Y))))) {
+ Intrinsic::ID InvID = getInverseMinMaxIntrinsic(II->getIntrinsicID());
+ Value *InvMaxMin = Builder.CreateBinaryIntrinsic(InvID, X, Y);
+ return replaceInstUsesWith(I, InvMaxMin);
+ }
+ if (match(Op0, m_OneUse(m_c_MaxOrMin(m_Not(m_Value(X)), m_Value(Y))))) {
+ Intrinsic::ID InvID = getInverseMinMaxIntrinsic(II->getIntrinsicID());
+ Value *NotY = Builder.CreateNot(Y);
+ Value *InvMaxMin = Builder.CreateBinaryIntrinsic(InvID, X, NotY);
+ return replaceInstUsesWith(I, InvMaxMin);
+ }
}
+ // TODO: Remove folds if we canonicalize to intrinsics (see above).
// Eliminate a bitwise 'not' op of 'not' min/max by inverting the min/max:
//
// %notx = xor i32 %x, -1
@@ -3526,6 +3667,9 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
if (Instruction *NewXor = sinkNotIntoXor(I, Builder))
return NewXor;
+ if (Instruction *Abs = canonicalizeAbs(I, Builder))
+ return Abs;
+
// Otherwise, if all else failed, try to hoist the xor-by-constant:
// (X ^ C) ^ Y --> (X ^ Y) ^ C
// Just like we do in other places, we completely avoid the fold