bool RangeCheck::IsBinOpMonotonicallyIncreasing(GenTreePtr op1, GenTreePtr op2, genTreeOps oper, SearchPath* path) { JITDUMP("[RangeCheck::IsBinOpMonotonicallyIncreasing] %p, %p\n", dspPtr(op1), dspPtr(op2)); // Check if we have a var + const. if (op2->OperGet() == GT_LCL_VAR) { jitstd::swap(op1, op2); } if (op1->OperGet() != GT_LCL_VAR) { JITDUMP("Not monotonic because op1 is not lclVar.\n"); return false; } switch (op2->OperGet()) { case GT_LCL_VAR: return IsMonotonicallyIncreasing(op1, path) && IsMonotonicallyIncreasing(op2, path); case GT_CNS_INT: return oper == GT_ADD && op2->AsIntConCommon()->IconValue() >= 0 && IsMonotonicallyIncreasing(op1, path); default: JITDUMP("Not monotonic because expression is not recognized.\n"); return false; } }
void CodeGen::UnspillFloat(RegSet::SpillDsc *spillDsc) { JITDUMP("UnspillFloat() for SpillDsc [%08p]\n", dspPtr(spillDsc)); RemoveSpillDsc(spillDsc); UnspillFloatMachineDep(spillDsc); RegSet::SpillDsc::freeDsc(®Set, spillDsc); compiler->tmpRlsTemp(spillDsc->spillTemp); }
void CodeGen::UnspillFloat(LclVarDsc * varDsc) { JITDUMP("UnspillFloat() for var [%08p]\n", dspPtr(varDsc)); RegSet::SpillDsc* cur = regSet.rsSpillFloat; assert(cur); while (cur->spillVarDsc != varDsc) cur = cur->spillNext; UnspillFloat(cur); }
// Add the def location to the hash table. void RangeCheck::SetDef(UINT64 hash, Location* loc) { if (m_pDefTable == nullptr) { m_pDefTable = new (m_pCompiler->getAllocator()) VarToLocMap(m_pCompiler->getAllocator()); } #ifdef DEBUG Location* loc2; if (m_pDefTable->Lookup(hash, &loc2)) { JITDUMP("Already have BB%02d, %08X, %08X for hash => %0I64X", loc2->block->bbNum, dspPtr(loc2->stmt), dspPtr(loc2->tree), hash); assert(false); } #endif m_pDefTable->Set(hash, loc); }
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; }
case GT_LE: pRange->uLimit = limit; break; } JITDUMP("The range after edge merging:"); JITDUMP(pRange->ToString(m_pCompiler->getAllocatorDebugOnly())); JITDUMP("\n"); } } // Merge assertions from the pred edges of the block, i.e., check for any assertions about "op's" value numbers for phi arguments. // If not a phi argument, check if we assertions about local variables. void RangeCheck::MergeAssertion(BasicBlock* block, GenTreePtr stmt, GenTreePtr op, SearchPath* path, Range* pRange DEBUGARG(int indent)) { JITDUMP("Merging assertions from pred edges of BB%02d for op(%p) $%03x\n", block->bbNum, dspPtr(op), op->gtVNPair.GetConservative()); EXPSET_TP assertions = 0; // If we have a phi arg, we can get to the block from it and use its assertion out. if (op->gtOper == GT_PHI_ARG) { GenTreePhiArg* arg = (GenTreePhiArg*) op; BasicBlock* pred = arg->gtPredBB; if (pred->bbFallsThrough() && pred->bbNext == block) { assertions = pred->bbAssertionOut; JITDUMP("Merge assertions from pred BB%02d edge: %0I64X\n", pred->bbNum, assertions); } else if ((pred->bbJumpKind == BBJ_COND || pred->bbJumpKind == BBJ_ALWAYS) && pred->bbJumpDest == block) { if (m_pCompiler->bbJtrueAssertionOut != NULL)
default: // All other 'cmpOper' kinds leave lLimit/uLimit unchanged break; } JITDUMP("The range after edge merging:"); JITDUMP(pRange->ToString(m_pCompiler->getAllocatorDebugOnly())); JITDUMP("\n"); } } // Merge assertions from the pred edges of the block, i.e., check for any assertions about "op's" value numbers for phi // arguments. If not a phi argument, check if we assertions about local variables. void RangeCheck::MergeAssertion( BasicBlock* block, GenTreePtr stmt, GenTreePtr op, SearchPath* path, Range* pRange DEBUGARG(int indent)) { JITDUMP("Merging assertions from pred edges of BB%02d for op(%p) $%03x\n", block->bbNum, dspPtr(op), op->gtVNPair.GetConservative()); ASSERT_TP assertions = BitVecOps::UninitVal(); // If we have a phi arg, we can get to the block from it and use its assertion out. if (op->gtOper == GT_PHI_ARG) { GenTreePhiArg* arg = (GenTreePhiArg*)op; BasicBlock* pred = arg->gtPredBB; if (pred->bbFallsThrough() && pred->bbNext == block) { assertions = pred->bbAssertionOut; JITDUMP("Merge assertions from pred BB%02d edge: %s\n", pred->bbNum, BitVecOps::ToString(m_pCompiler->apTraits, assertions)); } else if ((pred->bbJumpKind == BBJ_COND || pred->bbJumpKind == BBJ_ALWAYS) && pred->bbJumpDest == block)