From 14e0e18d7663ed4b091f9dbe5042701e77700b76 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Fri, 26 Aug 2016 18:28:46 +0000 Subject: [PATCH] [InstCombine] add helper function for icmp (and (sh X, Y), C2), C1 ; NFC Like other recent changes near here, the goal is to allow vector types for all of these folds. Splitting things up makes it easier to incrementally enhance the code and easier to read. llvm-svn: 279851 --- .../Transforms/InstCombine/InstCombineCompares.cpp | 105 ++++++++++++--------- .../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 db4c75c..b0802a3 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(Cmp.getOperand(1)); if (!RHS) return nullptr; + // FIXME: This could be passed in as APInt. auto *C2 = dyn_cast(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(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(And->getOperand(0))) { - IntegerType *Ty = cast(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(And->getOperand(0)); - if (Shift && !Shift->isShift()) - Shift = nullptr; - - ConstantInt *ShAmt; - ShAmt = Shift ? dyn_cast(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(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(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(Cmp.getOperand(1)); + if (!RHS) + return nullptr; + + // FIXME: Use m_APInt. + auto *C2 = dyn_cast(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(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(And->getOperand(0))) { + IntegerType *Ty = cast(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 8619ac6..91d937c 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); -- 2.7.4