diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2021-07-29 20:15:26 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2021-07-29 20:15:26 +0000 |
commit | 344a3780b2e33f6ca763666c380202b18aab72a3 (patch) | |
tree | f0b203ee6eb71d7fdd792373e3c81eb18d6934dd /llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp | |
parent | b60736ec1405bb0a8dd40989f67ef4c93da068ab (diff) | |
download | src-344a3780b2e33f6ca763666c380202b18aab72a3.tar.gz src-344a3780b2e33f6ca763666c380202b18aab72a3.zip |
Vendor import of llvm-project main 88e66fa60ae5, the last commit beforevendor/llvm-project/llvmorg-13-init-16847-g88e66fa60ae5vendor/llvm-project/llvmorg-12.0.1-rc2-0-ge7dac564cd0evendor/llvm-project/llvmorg-12.0.1-0-gfed41342a82f
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.cpp | 334 |
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 |