/*****************************************************************************
*
- * Walk the instrs to create the basic blocks.
+ * Walk the instrs to create the basic blocks. Returns the number of BBJ_RETURN in method
*/
-void Compiler::fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE* jumpTarget)
+unsigned Compiler::fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE* jumpTarget)
{
+ unsigned retBlocks;
const BYTE* codeBegp = codeAddr;
const BYTE* codeEndp = codeAddr + codeSize;
bool tailCall = false;
unsigned curBBoffs;
BasicBlock* curBBdesc;
+ retBlocks = 0;
/* Clear the beginning offset for the first BB */
curBBoffs = 0;
// TODO-CQ: We can inline some callees with explicit tail calls if we can guarantee that the calls
// can be dispatched as tail calls from the caller.
compInlineResult->NoteFatal(InlineObservation::CALLEE_EXPLICIT_TAIL_PREFIX);
- return;
+ retBlocks++;
+ return retBlocks;
}
__fallthrough;
But instead of directly returning to the caller we jump and
execute something else in between */
case CEE_RET:
+ retBlocks++;
jmpKind = BBJ_RETURN;
break;
/* Finally link up the bbJumpDest of the blocks together */
fgLinkBasicBlocks();
+
+ return retBlocks;
}
/*****************************************************************************
/* Now create the basic blocks */
- fgMakeBasicBlocks(info.compCode, info.compILCodeSize, jumpTarget);
+ unsigned retBlocks = fgMakeBasicBlocks(info.compCode, info.compILCodeSize, jumpTarget);
if (compIsForInlining())
{
return;
}
- bool hasReturnBlocks = false;
- bool hasMoreThanOneReturnBlock = false;
-
- for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
- {
- if (block->bbJumpKind == BBJ_RETURN)
- {
- if (hasReturnBlocks)
- {
- hasMoreThanOneReturnBlock = true;
- break;
- }
-
- hasReturnBlocks = true;
- }
- }
+ // If fgFindJumpTargets marked this as "no return" there really should be no BBJ_RETURN blocks in the method
+ assert(retBlocks == 0 || ((impInlineInfo->iciCall->gtCallMoreFlags & GTF_CALL_M_DOES_NOT_RETURN) == 0));
- if (!hasReturnBlocks && !compInlineResult->UsesLegacyPolicy())
+ if (retBlocks == 0 && !compInlineResult->UsesLegacyPolicy())
{
//
// Mark the call node as "no return". The inliner might ignore CALLEE_DOES_NOT_RETURN and
impInlineInfo->iciCall->gtCallMoreFlags |= GTF_CALL_M_DOES_NOT_RETURN;
}
- compInlineResult->NoteBool(InlineObservation::CALLEE_DOES_NOT_RETURN, !hasReturnBlocks);
+ compInlineResult->NoteBool(InlineObservation::CALLEE_DOES_NOT_RETURN, retBlocks == 0);
if (compInlineResult->IsFailure())
{
compHndBBtabCount = impInlineInfo->InlinerCompiler->compHndBBtabCount;
info.compXcptnsCount = impInlineInfo->InlinerCompiler->info.compXcptnsCount;
- if (info.compRetNativeType != TYP_VOID && hasMoreThanOneReturnBlock)
+ if (info.compRetNativeType != TYP_VOID && retBlocks > 1)
{
// The lifetime of this var might expand multiple BBs. So it is a long lifetime compiler temp.
lvaInlineeReturnSpillTemp = lvaGrabTemp(false DEBUGARG("Inline candidate multiple BBJ_RETURN spill temp"));