bool RangeCheck::IsMonotonicallyIncreasing(GenTreePtr expr, SearchPath* path) { JITDUMP("[RangeCheck::IsMonotonicallyIncreasing] %p\n", dspPtr(expr)); if (path->Lookup(expr)) { return true; } // Add hashtable entry for expr. path->Set(expr, NULL); // Remove hashtable entry for expr when we exit the present scope. auto code = [&] { path->Remove(expr); }; jitstd::utility::scoped_code<decltype(code)> finally(code); // If the rhs expr is constant, then it is not part of the dependency // loop which has to increase monotonically. ValueNum vn = expr->gtVNPair.GetConservative(); if (m_pCompiler->vnStore->IsVNConstant(vn)) { return true; } // If the rhs expr is local, then try to find the def of the local. else if (expr->IsLocal()) { Location* loc = GetDef(expr); if (loc == nullptr) { return false; } GenTreePtr asg = loc->parent; assert(asg->OperKind() & GTK_ASGOP); switch (asg->OperGet()) { case GT_ASG: return IsMonotonicallyIncreasing(asg->gtGetOp2(), path); case GT_ASG_ADD: return IsBinOpMonotonicallyIncreasing(asg->gtGetOp1(), asg->gtGetOp2(), GT_ADD, path); } JITDUMP("Unknown local definition type\n"); return false; } else if (expr->OperGet() == GT_ADD) { return IsBinOpMonotonicallyIncreasing(expr->gtGetOp1(), expr->gtGetOp2(), GT_ADD, path); } else if (expr->OperGet() == GT_PHI) { for (GenTreeArgList* args = expr->gtOp.gtOp1->AsArgList(); args != nullptr; args = args->Rest()) { // If the arg is already in the path, skip. if (path->Lookup(args->Current())) { continue; } if (!IsMonotonicallyIncreasing(args->Current(), path)) { JITDUMP("Phi argument not monotonic\n"); return false; } } return true; } JITDUMP("Unknown tree type\n"); return false; }
// The parameter rejectNegativeConst is true when we are adding two local vars (see above) bool RangeCheck::IsMonotonicallyIncreasing(GenTree* expr, bool rejectNegativeConst) { JITDUMP("[RangeCheck::IsMonotonicallyIncreasing] [%06d]\n", Compiler::dspTreeID(expr)); // Add hashtable entry for expr. bool alreadyPresent = !m_pSearchPath->Set(expr, nullptr, SearchPath::Overwrite); if (alreadyPresent) { return true; } // Remove hashtable entry for expr when we exit the present scope. auto code = [this, expr] { m_pSearchPath->Remove(expr); }; jitstd::utility::scoped_code<decltype(code)> finally(code); if (m_pSearchPath->GetCount() > MAX_SEARCH_DEPTH) { return false; } // If expr is constant, then it is not part of the dependency // loop which has to increase monotonically. ValueNum vn = expr->gtVNPair.GetConservative(); if (m_pCompiler->vnStore->IsVNInt32Constant(vn)) { if (rejectNegativeConst) { int cons = m_pCompiler->vnStore->ConstantValue<int>(vn); return (cons >= 0); } else { return true; } } // If the rhs expr is local, then try to find the def of the local. else if (expr->IsLocal()) { BasicBlock* asgBlock; GenTreeOp* asg = GetSsaDefAsg(expr->AsLclVarCommon(), &asgBlock); return (asg != nullptr) && IsMonotonicallyIncreasing(asg->gtGetOp2(), rejectNegativeConst); } else if (expr->OperGet() == GT_ADD) { return IsBinOpMonotonicallyIncreasing(expr->AsOp()); } else if (expr->OperGet() == GT_PHI) { for (GenTreeArgList* args = expr->gtOp.gtOp1->AsArgList(); args != nullptr; args = args->Rest()) { // If the arg is already in the path, skip. if (m_pSearchPath->Lookup(args->Current())) { continue; } if (!IsMonotonicallyIncreasing(args->Current(), rejectNegativeConst)) { JITDUMP("Phi argument not monotonic\n"); return false; } } return true; } JITDUMP("Unknown tree type\n"); return false; }