diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2018-08-02 17:32:43 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2018-08-02 17:32:43 +0000 | 
| commit | b7eb8e35e481a74962664b63dfb09483b200209a (patch) | |
| tree | 1937fb4a348458ce2d02ade03ac3bb0aa18d2fcd /lib/Analysis/InstructionSimplify.cpp | |
| parent | eb11fae6d08f479c0799db45860a98af528fa6e7 (diff) | |
Notes
Diffstat (limited to 'lib/Analysis/InstructionSimplify.cpp')
| -rw-r--r-- | lib/Analysis/InstructionSimplify.cpp | 325 | 
1 files changed, 191 insertions, 134 deletions
| diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp index 519d6d67be51..7fc7c15a0c25 100644 --- a/lib/Analysis/InstructionSimplify.cpp +++ b/lib/Analysis/InstructionSimplify.cpp @@ -65,6 +65,48 @@ static Value *SimplifyCastInst(unsigned, Value *, Type *,  static Value *SimplifyGEPInst(Type *, ArrayRef<Value *>, const SimplifyQuery &,                                unsigned); +static Value *foldSelectWithBinaryOp(Value *Cond, Value *TrueVal, +                                     Value *FalseVal) { +  BinaryOperator::BinaryOps BinOpCode; +  if (auto *BO = dyn_cast<BinaryOperator>(Cond)) +    BinOpCode = BO->getOpcode(); +  else +    return nullptr; + +  CmpInst::Predicate ExpectedPred, Pred1, Pred2; +  if (BinOpCode == BinaryOperator::Or) { +    ExpectedPred = ICmpInst::ICMP_NE; +  } else if (BinOpCode == BinaryOperator::And) { +    ExpectedPred = ICmpInst::ICMP_EQ; +  } else +    return nullptr; + +  // %A = icmp eq %TV, %FV +  // %B = icmp eq %X, %Y (and one of these is a select operand) +  // %C = and %A, %B +  // %D = select %C, %TV, %FV +  // --> +  // %FV + +  // %A = icmp ne %TV, %FV +  // %B = icmp ne %X, %Y (and one of these is a select operand) +  // %C = or %A, %B +  // %D = select %C, %TV, %FV +  // --> +  // %TV +  Value *X, *Y; +  if (!match(Cond, m_c_BinOp(m_c_ICmp(Pred1, m_Specific(TrueVal), +                                      m_Specific(FalseVal)), +                             m_ICmp(Pred2, m_Value(X), m_Value(Y)))) || +      Pred1 != Pred2 || Pred1 != ExpectedPred) +    return nullptr; + +  if (X == TrueVal || X == FalseVal || Y == TrueVal || Y == FalseVal) +    return BinOpCode == BinaryOperator::Or ? TrueVal : FalseVal; + +  return nullptr; +} +  /// For a boolean type or a vector of boolean type, return false or a vector  /// with every element false.  static Constant *getFalse(Type *Ty) { @@ -1283,6 +1325,23 @@ static Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact,    if (match(Op0, m_NUWShl(m_Value(X), m_Specific(Op1))))      return X; +  // ((X << A) | Y) >> A -> X  if effective width of Y is not larger than A. +  // We can return X as we do in the above case since OR alters no bits in X. +  // SimplifyDemandedBits in InstCombine can do more general optimization for +  // bit manipulation. This pattern aims to provide opportunities for other +  // optimizers by supporting a simple but common case in InstSimplify. +  Value *Y; +  const APInt *ShRAmt, *ShLAmt; +  if (match(Op1, m_APInt(ShRAmt)) && +      match(Op0, m_c_Or(m_NUWShl(m_Value(X), m_APInt(ShLAmt)), m_Value(Y))) && +      *ShRAmt == *ShLAmt) { +    const KnownBits YKnown = computeKnownBits(Y, Q.DL, 0, Q.AC, Q.CxtI, Q.DT); +    const unsigned Width = Op0->getType()->getScalarSizeInBits(); +    const unsigned EffWidthY = Width - YKnown.countMinLeadingZeros(); +    if (EffWidthY <= ShRAmt->getZExtValue()) +      return X; +  } +    return nullptr;  } @@ -3752,6 +3811,9 @@ static Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,            simplifySelectWithICmpCond(Cond, TrueVal, FalseVal, Q, MaxRecurse))      return V; +  if (Value *V = foldSelectWithBinaryOp(Cond, TrueVal, FalseVal)) +    return V; +    return nullptr;  } @@ -4604,149 +4666,131 @@ static bool maskIsAllZeroOrUndef(Value *Mask) {    return true;  } -template <typename IterTy> -static Value *SimplifyIntrinsic(Function *F, IterTy ArgBegin, IterTy ArgEnd, -                                const SimplifyQuery &Q, unsigned MaxRecurse) { +static Value *simplifyUnaryIntrinsic(Function *F, Value *Op0, +                                     const SimplifyQuery &Q) { +  // Idempotent functions return the same result when called repeatedly.    Intrinsic::ID IID = F->getIntrinsicID(); -  unsigned NumOperands = std::distance(ArgBegin, ArgEnd); - -  // Unary Ops -  if (NumOperands == 1) { -    // Perform idempotent optimizations -    if (IsIdempotent(IID)) { -      if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(*ArgBegin)) { -        if (II->getIntrinsicID() == IID) -          return II; -      } -    } +  if (IsIdempotent(IID)) +    if (auto *II = dyn_cast<IntrinsicInst>(Op0)) +      if (II->getIntrinsicID() == IID) +        return II; -    Value *IIOperand = *ArgBegin; -    Value *X; -    switch (IID) { -    case Intrinsic::fabs: { -      if (SignBitMustBeZero(IIOperand, Q.TLI)) -        return IIOperand; -      return nullptr; -    } -    case Intrinsic::bswap: { -      // bswap(bswap(x)) -> x -      if (match(IIOperand, m_BSwap(m_Value(X)))) -        return X; -      return nullptr; -    } -    case Intrinsic::bitreverse: { -      // bitreverse(bitreverse(x)) -> x -      if (match(IIOperand, m_BitReverse(m_Value(X)))) -        return X; -      return nullptr; -    } -    case Intrinsic::exp: { -      // exp(log(x)) -> x -      if (Q.CxtI->hasAllowReassoc() && -          match(IIOperand, m_Intrinsic<Intrinsic::log>(m_Value(X)))) -        return X; -      return nullptr; -    } -    case Intrinsic::exp2: { -      // exp2(log2(x)) -> x -      if (Q.CxtI->hasAllowReassoc() && -          match(IIOperand, m_Intrinsic<Intrinsic::log2>(m_Value(X)))) -        return X; -      return nullptr; -    } -    case Intrinsic::log: { -      // log(exp(x)) -> x -      if (Q.CxtI->hasAllowReassoc() && -          match(IIOperand, m_Intrinsic<Intrinsic::exp>(m_Value(X)))) -        return X; -      return nullptr; -    } -    case Intrinsic::log2: { -      // log2(exp2(x)) -> x -      if (Q.CxtI->hasAllowReassoc() && -          match(IIOperand, m_Intrinsic<Intrinsic::exp2>(m_Value(X)))) { -        return X; -      } -      return nullptr; -    } -    default: -      return nullptr; -    } +  Value *X; +  switch (IID) { +  case Intrinsic::fabs: +    if (SignBitMustBeZero(Op0, Q.TLI)) return Op0; +    break; +  case Intrinsic::bswap: +    // bswap(bswap(x)) -> x +    if (match(Op0, m_BSwap(m_Value(X)))) return X; +    break; +  case Intrinsic::bitreverse: +    // bitreverse(bitreverse(x)) -> x +    if (match(Op0, m_BitReverse(m_Value(X)))) return X; +    break; +  case Intrinsic::exp: +    // exp(log(x)) -> x +    if (Q.CxtI->hasAllowReassoc() && +        match(Op0, m_Intrinsic<Intrinsic::log>(m_Value(X)))) return X; +    break; +  case Intrinsic::exp2: +    // exp2(log2(x)) -> x +    if (Q.CxtI->hasAllowReassoc() && +        match(Op0, m_Intrinsic<Intrinsic::log2>(m_Value(X)))) return X; +    break; +  case Intrinsic::log: +    // log(exp(x)) -> x +    if (Q.CxtI->hasAllowReassoc() && +        match(Op0, m_Intrinsic<Intrinsic::exp>(m_Value(X)))) return X; +    break; +  case Intrinsic::log2: +    // log2(exp2(x)) -> x +    if (Q.CxtI->hasAllowReassoc() && +        match(Op0, m_Intrinsic<Intrinsic::exp2>(m_Value(X)))) return X; +    break; +  default: +    break;    } -  // Binary Ops -  if (NumOperands == 2) { -    Value *LHS = *ArgBegin; -    Value *RHS = *(ArgBegin + 1); -    Type *ReturnType = F->getReturnType(); +  return nullptr; +} -    switch (IID) { -    case Intrinsic::usub_with_overflow: -    case Intrinsic::ssub_with_overflow: { -      // X - X -> { 0, false } -      if (LHS == RHS) -        return Constant::getNullValue(ReturnType); +static Value *simplifyBinaryIntrinsic(Function *F, Value *Op0, Value *Op1, +                                      const SimplifyQuery &Q) { +  Intrinsic::ID IID = F->getIntrinsicID(); +  Type *ReturnType = F->getReturnType(); +  switch (IID) { +  case Intrinsic::usub_with_overflow: +  case Intrinsic::ssub_with_overflow: +    // X - X -> { 0, false } +    if (Op0 == Op1) +      return Constant::getNullValue(ReturnType); +    // X - undef -> undef +    // undef - X -> undef +    if (isa<UndefValue>(Op0) || isa<UndefValue>(Op1)) +      return UndefValue::get(ReturnType); +    break; +  case Intrinsic::uadd_with_overflow: +  case Intrinsic::sadd_with_overflow: +    // X + undef -> undef +    if (isa<UndefValue>(Op0) || isa<UndefValue>(Op1)) +      return UndefValue::get(ReturnType); +    break; +  case Intrinsic::umul_with_overflow: +  case Intrinsic::smul_with_overflow: +    // 0 * X -> { 0, false } +    // X * 0 -> { 0, false } +    if (match(Op0, m_Zero()) || match(Op1, m_Zero())) +      return Constant::getNullValue(ReturnType); +    // undef * X -> { 0, false } +    // X * undef -> { 0, false } +    if (match(Op0, m_Undef()) || match(Op1, m_Undef())) +      return Constant::getNullValue(ReturnType); +    break; +  case Intrinsic::load_relative: +    if (auto *C0 = dyn_cast<Constant>(Op0)) +      if (auto *C1 = dyn_cast<Constant>(Op1)) +        return SimplifyRelativeLoad(C0, C1, Q.DL); +    break; +  case Intrinsic::powi: +    if (auto *Power = dyn_cast<ConstantInt>(Op1)) { +      // powi(x, 0) -> 1.0 +      if (Power->isZero()) +        return ConstantFP::get(Op0->getType(), 1.0); +      // powi(x, 1) -> x +      if (Power->isOne()) +        return Op0; +    } +    break; +  case Intrinsic::maxnum: +  case Intrinsic::minnum: +    // If one argument is NaN, return the other argument. +    if (match(Op0, m_NaN())) return Op1; +    if (match(Op1, m_NaN())) return Op0; +    break; +  default: +    break; +  } -      // X - undef -> undef -      // undef - X -> undef -      if (isa<UndefValue>(LHS) || isa<UndefValue>(RHS)) -        return UndefValue::get(ReturnType); +  return nullptr; +} -      return nullptr; -    } -    case Intrinsic::uadd_with_overflow: -    case Intrinsic::sadd_with_overflow: { -      // X + undef -> undef -      if (isa<UndefValue>(LHS) || isa<UndefValue>(RHS)) -        return UndefValue::get(ReturnType); +template <typename IterTy> +static Value *simplifyIntrinsic(Function *F, IterTy ArgBegin, IterTy ArgEnd, +                                const SimplifyQuery &Q) { +  // Intrinsics with no operands have some kind of side effect. Don't simplify. +  unsigned NumOperands = std::distance(ArgBegin, ArgEnd); +  if (NumOperands == 0) +    return nullptr; -      return nullptr; -    } -    case Intrinsic::umul_with_overflow: -    case Intrinsic::smul_with_overflow: { -      // 0 * X -> { 0, false } -      // X * 0 -> { 0, false } -      if (match(LHS, m_Zero()) || match(RHS, m_Zero())) -        return Constant::getNullValue(ReturnType); - -      // undef * X -> { 0, false } -      // X * undef -> { 0, false } -      if (match(LHS, m_Undef()) || match(RHS, m_Undef())) -        return Constant::getNullValue(ReturnType); +  Intrinsic::ID IID = F->getIntrinsicID(); +  if (NumOperands == 1) +    return simplifyUnaryIntrinsic(F, ArgBegin[0], Q); -      return nullptr; -    } -    case Intrinsic::load_relative: { -      Constant *C0 = dyn_cast<Constant>(LHS); -      Constant *C1 = dyn_cast<Constant>(RHS); -      if (C0 && C1) -        return SimplifyRelativeLoad(C0, C1, Q.DL); -      return nullptr; -    } -    case Intrinsic::powi: -      if (ConstantInt *Power = dyn_cast<ConstantInt>(RHS)) { -        // powi(x, 0) -> 1.0 -        if (Power->isZero()) -          return ConstantFP::get(LHS->getType(), 1.0); -        // powi(x, 1) -> x -        if (Power->isOne()) -          return LHS; -      } -      return nullptr; -    case Intrinsic::maxnum: -    case Intrinsic::minnum: -      // If one argument is NaN, return the other argument. -      if (match(LHS, m_NaN())) -        return RHS; -      if (match(RHS, m_NaN())) -        return LHS; -      return nullptr; -    default: -      return nullptr; -    } -  } +  if (NumOperands == 2) +    return simplifyBinaryIntrinsic(F, ArgBegin[0], ArgBegin[1], Q); -  // Simplify calls to llvm.masked.load.* +  // Handle intrinsics with 3 or more arguments.    switch (IID) {    case Intrinsic::masked_load: {      Value *MaskArg = ArgBegin[2]; @@ -4756,6 +4800,19 @@ static Value *SimplifyIntrinsic(Function *F, IterTy ArgBegin, IterTy ArgEnd,        return PassthruArg;      return nullptr;    } +  case Intrinsic::fshl: +  case Intrinsic::fshr: { +    Value *ShAmtArg = ArgBegin[2]; +    const APInt *ShAmtC; +    if (match(ShAmtArg, m_APInt(ShAmtC))) { +      // If there's effectively no shift, return the 1st arg or 2nd arg. +      // TODO: For vectors, we could check each element of a non-splat constant. +      APInt BitWidth = APInt(ShAmtC->getBitWidth(), ShAmtC->getBitWidth()); +      if (ShAmtC->urem(BitWidth).isNullValue()) +        return ArgBegin[IID == Intrinsic::fshl ? 0 : 1]; +    } +    return nullptr; +  }    default:      return nullptr;    } @@ -4780,7 +4837,7 @@ static Value *SimplifyCall(ImmutableCallSite CS, Value *V, IterTy ArgBegin,      return nullptr;    if (F->isIntrinsic()) -    if (Value *Ret = SimplifyIntrinsic(F, ArgBegin, ArgEnd, Q, MaxRecurse)) +    if (Value *Ret = simplifyIntrinsic(F, ArgBegin, ArgEnd, Q))        return Ret;    if (!canConstantFoldCallTo(CS, F)) | 
