diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 8fbce8a586e796..8d7709fc7e6e6b 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -17697,6 +17697,9 @@ void Compiler::fgExpandQmarkForCastInstOf(BasicBlock* block, Statement* stmt) assert(qmark->gtFlags & GTF_QMARK_CAST_INSTOF); + const BasicBlock::weight_t currBbWeight = block->bbWeight; + const BasicBlock::weight_t nextBbWeight = (block->bbNext != nullptr) ? block->bbNext->bbWeight : currBbWeight; + // Get cond, true, false exprs for the qmark. GenTree* condExpr = qmark->gtGetOp1(); GenTree* trueExpr = qmark->gtGetOp2()->AsColon()->ThenNode(); @@ -17782,11 +17785,26 @@ void Compiler::fgExpandQmarkForCastInstOf(BasicBlock* block, Statement* stmt) cond1Block->bbJumpDest = remainderBlock; cond2Block->bbJumpDest = remainderBlock; - // Set the weights; some are guesses. + // Currently, we don't instrument internal blocks, so the only way we can set weights to these blocks + // is to analyze successors and take a guess. + BasicBlock::weight_t castSuccessLikelihood = BB_ZERO_WEIGHT; + + // We don't expand casts inside rarely executed blocks, but currently we skip only blocks + // with BBF_RUN_RARELY flag and still can hit zero weight here (in that cases all internal blocks + // will also have zero weight). + if (currBbWeight > BB_ZERO_WEIGHT) + { + castSuccessLikelihood = clamp(nextBbWeight / currBbWeight, BB_ZERO_WEIGHT, 1.0f); + } + asgBlock->inheritWeight(block); cond1Block->inheritWeight(block); - cond2Block->inheritWeightPercentage(cond1Block, 50); - helperBlock->inheritWeightPercentage(cond2Block, 50); + + // cond2Block is always taken if the cast always succeeds (helperBlock will be cold in this case) + // If it always fails the only guess we can make that it's either object is null or of a + // wrong type (50/50). + cond2Block->inheritWeightPercentage(block, (UINT32)(castSuccessLikelihood * 50.0f) + 50); + helperBlock->inheritWeightPercentage(block, 50 - (UINT32)(castSuccessLikelihood * 50.0f)); // Append cond1 as JTRUE to cond1Block GenTree* jmpTree = gtNewOperNode(GT_JTRUE, TYP_VOID, condExpr); diff --git a/src/coreclr/jit/utils.h b/src/coreclr/jit/utils.h index e22320bb1ef635..0a0fb1dd05d2f3 100644 --- a/src/coreclr/jit/utils.h +++ b/src/coreclr/jit/utils.h @@ -41,6 +41,13 @@ inline bool isPow2(T i) return (i > 0 && ((i - 1) & i) == 0); } +// Clamps the given value between the given lower and upper values +template +inline bool clamp(T value, T lower, T upper) +{ + return max(lower, min(value, upper)); +} + // Adapter for iterators to a type that is compatible with C++11 // range-based for loops. template