diff options
-rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 105 | ||||
-rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineInternal.h | 4 |
2 files changed, 64 insertions, 45 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index db4c75cd1dc..b0802a32c9b 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1389,65 +1389,29 @@ Instruction *InstCombiner::foldICmpXorConstant(ICmpInst &Cmp, return nullptr; } -/// Fold icmp (and X, C2), C1. -Instruction *InstCombiner::foldICmpAndConstConst(ICmpInst &Cmp, - BinaryOperator *And, - const APInt *C1) { +/// Fold icmp (and (sh X, Y), C2), C1. +Instruction *InstCombiner::foldICmpAndShift(ICmpInst &Cmp, BinaryOperator *And, + const APInt *C1) { // FIXME: This check restricts all folds under here to scalar types. ConstantInt *RHS = dyn_cast<ConstantInt>(Cmp.getOperand(1)); if (!RHS) return nullptr; + // FIXME: This could be passed in as APInt. auto *C2 = dyn_cast<ConstantInt>(And->getOperand(1)); if (!C2) return nullptr; - if (!And->hasOneUse() || !And->getOperand(0)->hasOneUse()) - return nullptr; - - // If the LHS is an AND of a truncating cast, we can widen the and/compare to - // be the input width without changing the value produced, eliminating a cast. - if (TruncInst *Cast = dyn_cast<TruncInst>(And->getOperand(0))) { - // We can do this transformation if either the AND constant does not have - // its sign bit set or if it is an equality comparison. Extending a - // relational comparison when we're checking the sign bit would not work. - if (Cmp.isEquality() || (!C2->isNegative() && C1->isNonNegative())) { - Value *NewAnd = Builder->CreateAnd( - Cast->getOperand(0), ConstantExpr::getZExt(C2, Cast->getSrcTy())); - NewAnd->takeName(And); - return new ICmpInst(Cmp.getPredicate(), NewAnd, - ConstantExpr::getZExt(RHS, Cast->getSrcTy())); - } - } - - // If the LHS is an AND of a zext, and we have an equality compare, we can - // shrink the and/compare to the smaller type, eliminating the cast. - if (ZExtInst *Cast = dyn_cast<ZExtInst>(And->getOperand(0))) { - IntegerType *Ty = cast<IntegerType>(Cast->getSrcTy()); - // Make sure we don't compare the upper bits, SimplifyDemandedBits - // should fold the icmp to true/false in that case. - if (Cmp.isEquality() && C1->getActiveBits() <= Ty->getBitWidth()) { - Value *NewAnd = Builder->CreateAnd(Cast->getOperand(0), - ConstantExpr::getTrunc(C2, Ty)); - NewAnd->takeName(And); - return new ICmpInst(Cmp.getPredicate(), NewAnd, - ConstantExpr::getTrunc(RHS, Ty)); - } - } - // If this is: (X >> C3) & C2 != C1 (where any shift and any compare could // exist), turn it into (X & (C2 << C3)) != (C1 << C3). This happens a LOT in // code produced by the clang front-end, for bitfield access. BinaryOperator *Shift = dyn_cast<BinaryOperator>(And->getOperand(0)); - if (Shift && !Shift->isShift()) - Shift = nullptr; - - ConstantInt *ShAmt; - ShAmt = Shift ? dyn_cast<ConstantInt>(Shift->getOperand(1)) : nullptr; + if (!Shift || !Shift->isShift()) + return nullptr; // This seemingly simple opportunity to fold away a shift turns out to be // rather complicated. See PR17827 for details. - if (ShAmt) { + if (auto *ShAmt = dyn_cast<ConstantInt>(Shift->getOperand(1))) { bool CanFold = false; unsigned ShiftOpcode = Shift->getOpcode(); if (ShiftOpcode == Instruction::AShr) { @@ -1513,7 +1477,7 @@ Instruction *InstCombiner::foldICmpAndConstConst(ICmpInst &Cmp, // Turn ((X >> Y) & C2) == 0 into (X & (C2 << Y)) == 0. The latter is // preferable because it allows the C2 << Y expression to be hoisted out of a // loop if Y is invariant and X is not. - if (Shift && Shift->hasOneUse() && *C1 == 0 && Cmp.isEquality() && + if (Shift->hasOneUse() && *C1 == 0 && Cmp.isEquality() && !Shift->isArithmeticShift() && !isa<Constant>(Shift->getOperand(0))) { // Compute C2 << Y. Value *NS; @@ -1532,6 +1496,59 @@ Instruction *InstCombiner::foldICmpAndConstConst(ICmpInst &Cmp, return &Cmp; } + return nullptr; +} + +/// Fold icmp (and X, C2), C1. +Instruction *InstCombiner::foldICmpAndConstConst(ICmpInst &Cmp, + BinaryOperator *And, + const APInt *C1) { + // FIXME: This check restricts all folds under here to scalar types. + ConstantInt *RHS = dyn_cast<ConstantInt>(Cmp.getOperand(1)); + if (!RHS) + return nullptr; + + // FIXME: Use m_APInt. + auto *C2 = dyn_cast<ConstantInt>(And->getOperand(1)); + if (!C2) + return nullptr; + + if (!And->hasOneUse() || !And->getOperand(0)->hasOneUse()) + return nullptr; + + // If the LHS is an AND of a truncating cast, we can widen the and/compare to + // be the input width without changing the value produced, eliminating a cast. + if (TruncInst *Cast = dyn_cast<TruncInst>(And->getOperand(0))) { + // We can do this transformation if either the AND constant does not have + // its sign bit set or if it is an equality comparison. Extending a + // relational comparison when we're checking the sign bit would not work. + if (Cmp.isEquality() || (!C2->isNegative() && C1->isNonNegative())) { + Value *NewAnd = Builder->CreateAnd( + Cast->getOperand(0), ConstantExpr::getZExt(C2, Cast->getSrcTy())); + NewAnd->takeName(And); + return new ICmpInst(Cmp.getPredicate(), NewAnd, + ConstantExpr::getZExt(RHS, Cast->getSrcTy())); + } + } + + // If the LHS is an AND of a zext, and we have an equality compare, we can + // shrink the and/compare to the smaller type, eliminating the cast. + if (ZExtInst *Cast = dyn_cast<ZExtInst>(And->getOperand(0))) { + IntegerType *Ty = cast<IntegerType>(Cast->getSrcTy()); + // Make sure we don't compare the upper bits, SimplifyDemandedBits + // should fold the icmp to true/false in that case. + if (Cmp.isEquality() && C1->getActiveBits() <= Ty->getBitWidth()) { + Value *NewAnd = Builder->CreateAnd(Cast->getOperand(0), + ConstantExpr::getTrunc(C2, Ty)); + NewAnd->takeName(And); + return new ICmpInst(Cmp.getPredicate(), NewAnd, + ConstantExpr::getTrunc(RHS, Ty)); + } + } + + if (Instruction *I = foldICmpAndShift(Cmp, And, C1)) + return I; + // (icmp pred (and (or (lshr A, B), A), 1), 0) --> // (icmp pred (and A, (or (shl 1, B), 1), 0)) // diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h index 8619ac6fcf2..91d937c4a15 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -580,7 +580,9 @@ private: Instruction *foldICmpAddConstant(ICmpInst &Cmp, BinaryOperator *Add, const APInt *C); Instruction *foldICmpAndConstConst(ICmpInst &Cmp, BinaryOperator *And, - const APInt *C); + const APInt *C1); + Instruction *foldICmpAndShift(ICmpInst &Cmp, BinaryOperator *And, + const APInt *C1); Instruction *foldICmpEqualityWithConstant(ICmpInst &ICI); Instruction *foldICmpIntrinsicWithConstant(ICmpInst &ICI); |