Skip to content

Commit

Permalink
JIT: add some devirtualization info to the inline context (dotnet#20395)
Browse files Browse the repository at this point in the history
Allows the jit to remember which calls were devirtualized and which
of those were then optimized to use an unboxed entry point. This info
is then dumped out as part of the inline tree.

Also remove some of the clutter from the COMPlus_JitPrintInlinedMethods
output stream -- we don't need to see both the in-stream results and
the final results, and we don't really need to know about the budget.
This information is still dumped for COMPlus_JitDump.
  • Loading branch information
AndyAyersMS authored and A-And committed Nov 20, 2018
1 parent a3097e4 commit d5ce249
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 43 deletions.
7 changes: 4 additions & 3 deletions src/jit/flowgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21878,8 +21878,9 @@ void Compiler::fgInline()

if (verbose || fgPrintInlinedMethods)
{
printf("**************** Inline Tree\n");
m_inlineStrategy->Dump();
JITDUMP("**************** Inline Tree");
printf("\n");
m_inlineStrategy->Dump(verbose);
}

#endif // DEBUG
Expand Down Expand Up @@ -22573,7 +22574,7 @@ void Compiler::fgInvokeInlineeCompiler(GenTreeCall* call, InlineResult* inlineRe

#ifdef DEBUG

if (verbose || fgPrintInlinedMethods)
if (verbose)
{
printf("Successfully inlined %s (%d IL bytes) (depth %d) [%s]\n", eeGetMethodFullName(fncHandle),
inlineCandidateInfo->methInfo.ILCodeSize, inlineDepth, inlineResult->ReasonString());
Expand Down
12 changes: 12 additions & 0 deletions src/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -3537,6 +3537,8 @@ struct GenTreeCall final : public GenTree
// stubs, because executable code cannot be generated at runtime.
#define GTF_CALL_M_HELPER_SPECIAL_DCE 0x00020000 // GT_CALL -- this helper call can be removed if it is part of a comma and
// the comma result is unused.
#define GTF_CALL_M_DEVIRTUALIZED 0x00040000 // GT_CALL -- this call was devirtualized
#define GTF_CALL_M_UNBOXED 0x00080000 // GT_CALL -- this call was optimized to use the unboxed entry point

// clang-format on

Expand Down Expand Up @@ -3743,6 +3745,16 @@ struct GenTreeCall final : public GenTree
gtCallMoreFlags |= GTF_CALL_M_FAT_POINTER_CHECK;
}

bool IsDevirtualized() const
{
return (gtCallMoreFlags & GTF_CALL_M_DEVIRTUALIZED) != 0;
}

bool IsUnboxed() const
{
return (gtCallMoreFlags & GTF_CALL_M_UNBOXED) != 0;
}

unsigned gtCallMoreFlags; // in addition to gtFlags

unsigned char gtCallType : 3; // value from the gtCallTypes enumeration
Expand Down
5 changes: 4 additions & 1 deletion src/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19631,6 +19631,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
call->gtFlags &= ~GTF_CALL_VIRT_STUB;
call->gtCallMethHnd = derivedMethod;
call->gtCallType = CT_USER_FUNC;
call->gtCallMoreFlags |= GTF_CALL_M_DEVIRTUALIZED;

// Virtual calls include an implicit null check, which we may
// now need to make explicit.
Expand Down Expand Up @@ -19695,6 +19696,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
// Pass the local var as this and the type handle as a new arg
JITDUMP("Success! invoking unboxed entry point on local copy, and passing method table arg\n");
call->gtCallObjp = localCopyThis;
call->gtCallMoreFlags |= GTF_CALL_M_UNBOXED;

// Prepend for R2L arg passing or empty L2R passing
if ((Target::g_tgtArgOrder == Target::ARG_ORDER_R2L) || (call->gtCallArgs == nullptr))
Expand Down Expand Up @@ -19742,7 +19744,8 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
JITDUMP("Success! invoking unboxed entry point on local copy\n");
call->gtCallObjp = localCopyThis;
call->gtCallMethHnd = unboxedEntryMethod;
derivedMethod = unboxedEntryMethod;
call->gtCallMoreFlags |= GTF_CALL_M_UNBOXED;
derivedMethod = unboxedEntryMethod;
}
else
{
Expand Down
72 changes: 44 additions & 28 deletions src/jit/inline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@ InlineContext::InlineContext(InlineStrategy* strategy)
, m_Observation(InlineObservation::CALLEE_UNUSED_INITIAL)
, m_CodeSizeEstimate(0)
, m_Success(true)
, m_Devirtualized(false)
, m_Unboxed(false)
#if defined(DEBUG) || defined(INLINE_DATA)
, m_Policy(nullptr)
, m_Callee(nullptr)
Expand Down Expand Up @@ -392,19 +394,21 @@ void InlineContext::Dump(unsigned indent)
else
{
// Inline attempt.
const char* inlineReason = InlGetObservationString(m_Observation);
const char* inlineResult = m_Success ? "" : "FAILED: ";
const char* inlineReason = InlGetObservationString(m_Observation);
const char* inlineResult = m_Success ? "" : "FAILED: ";
const char* devirtualized = m_Devirtualized ? " devirt" : "";
const char* unboxed = m_Unboxed ? " unboxed" : "";

if (m_Offset == BAD_IL_OFFSET)
{
printf("%*s[%u IL=???? TR=%06u %08X] [%s%s] %s\n", indent, "", m_Ordinal, m_TreeID, calleeToken,
inlineResult, inlineReason, calleeName);
printf("%*s[%u IL=???? TR=%06u %08X] [%s%s%s%s] %s\n", indent, "", m_Ordinal, m_TreeID, calleeToken,
inlineResult, inlineReason, devirtualized, unboxed, calleeName);
}
else
{
IL_OFFSET offset = jitGetILoffs(m_Offset);
printf("%*s[%u IL=%04d TR=%06u %08X] [%s%s] %s\n", indent, "", m_Ordinal, offset, m_TreeID, calleeToken,
inlineResult, inlineReason, calleeName);
printf("%*s[%u IL=%04d TR=%06u %08X] [%s%s%s%s] %s\n", indent, "", m_Ordinal, offset, m_TreeID, calleeToken,
inlineResult, inlineReason, devirtualized, unboxed, calleeName);
}
}

Expand Down Expand Up @@ -1172,7 +1176,6 @@ InlineContext* InlineStrategy::NewRoot()
// and link it into the context tree
//
// Arguments:
// stmt - statement containing call being inlined
// inlineInfo - information about this inline
//
// Return Value:
Expand All @@ -1186,6 +1189,7 @@ InlineContext* InlineStrategy::NewSuccess(InlineInfo* inlineInfo)
BYTE* calleeIL = inlineInfo->inlineCandidateInfo->methInfo.ILCode;
unsigned calleeILSize = inlineInfo->inlineCandidateInfo->methInfo.ILCodeSize;
InlineContext* parentContext = stmt->gtInlineContext;
GenTreeCall* originalCall = inlineInfo->inlineResult->GetCall();

noway_assert(parentContext != nullptr);

Expand All @@ -1194,12 +1198,14 @@ InlineContext* InlineStrategy::NewSuccess(InlineInfo* inlineInfo)
calleeContext->m_Parent = parentContext;
// Push on front here will put siblings in reverse lexical
// order which we undo in the dumper
calleeContext->m_Sibling = parentContext->m_Child;
parentContext->m_Child = calleeContext;
calleeContext->m_Child = nullptr;
calleeContext->m_Offset = stmt->AsStmt()->gtStmtILoffsx;
calleeContext->m_Observation = inlineInfo->inlineResult->GetObservation();
calleeContext->m_Success = true;
calleeContext->m_Sibling = parentContext->m_Child;
parentContext->m_Child = calleeContext;
calleeContext->m_Child = nullptr;
calleeContext->m_Offset = stmt->gtStmtILoffsx;
calleeContext->m_Observation = inlineInfo->inlineResult->GetObservation();
calleeContext->m_Success = true;
calleeContext->m_Devirtualized = originalCall->IsDevirtualized();
calleeContext->m_Unboxed = originalCall->IsUnboxed();

#if defined(DEBUG) || defined(INLINE_DATA)

Expand All @@ -1211,13 +1217,13 @@ InlineContext* InlineStrategy::NewSuccess(InlineInfo* inlineInfo)
// +1 here since we set this before calling NoteOutcome.
calleeContext->m_Ordinal = m_InlineCount + 1;
// Update offset with more accurate info
calleeContext->m_Offset = inlineInfo->inlineResult->GetCall()->gtRawILOffset;
calleeContext->m_Offset = originalCall->gtRawILOffset;

#endif // defined(DEBUG) || defined(INLINE_DATA)

#if defined(DEBUG)

calleeContext->m_TreeID = inlineInfo->inlineResult->GetCall()->gtTreeID;
calleeContext->m_TreeID = originalCall->gtTreeID;

#endif // defined(DEBUG)

Expand All @@ -1237,8 +1243,7 @@ InlineContext* InlineStrategy::NewSuccess(InlineInfo* inlineInfo)
// inlineResult - inlineResult for the attempt
//
// Return Value:
// A new InlineContext for diagnostic purposes, or nullptr if
// the desired context could not be created.
// A new InlineContext for diagnostic purposes

InlineContext* InlineStrategy::NewFailure(GenTreeStmt* stmt, InlineResult* inlineResult)
{
Expand All @@ -1247,31 +1252,34 @@ InlineContext* InlineStrategy::NewFailure(GenTreeStmt* stmt, InlineResult* inlin
InlineContext* parentContext = stmt->gtInlineContext;
assert(parentContext != nullptr);
InlineContext* failedContext = new (m_Compiler, CMK_Inlining) InlineContext(this);
GenTreeCall* originalCall = inlineResult->GetCall();

// Pushing the new context on the front of the parent child list
// will put siblings in reverse lexical order which we undo in the
// dumper.
failedContext->m_Parent = parentContext;
failedContext->m_Sibling = parentContext->m_Child;
parentContext->m_Child = failedContext;
failedContext->m_Child = nullptr;
failedContext->m_Offset = stmt->gtStmtILoffsx;
failedContext->m_Observation = inlineResult->GetObservation();
failedContext->m_Callee = inlineResult->GetCallee();
failedContext->m_Success = false;
failedContext->m_Parent = parentContext;
failedContext->m_Sibling = parentContext->m_Child;
parentContext->m_Child = failedContext;
failedContext->m_Child = nullptr;
failedContext->m_Offset = stmt->gtStmtILoffsx;
failedContext->m_Observation = inlineResult->GetObservation();
failedContext->m_Callee = inlineResult->GetCallee();
failedContext->m_Success = false;
failedContext->m_Devirtualized = originalCall->IsDevirtualized();
failedContext->m_Unboxed = originalCall->IsUnboxed();

assert(InlIsValidObservation(failedContext->m_Observation));

#if defined(DEBUG) || defined(INLINE_DATA)

// Update offset with more accurate info
failedContext->m_Offset = inlineResult->GetCall()->gtRawILOffset;
failedContext->m_Offset = originalCall->gtRawILOffset;

#endif // #if defined(DEBUG) || defined(INLINE_DATA)

#if defined(DEBUG)

failedContext->m_TreeID = inlineResult->GetCall()->gtTreeID;
failedContext->m_TreeID = originalCall->gtTreeID;

#endif // defined(DEBUG)

Expand All @@ -1282,11 +1290,19 @@ InlineContext* InlineStrategy::NewFailure(GenTreeStmt* stmt, InlineResult* inlin

//------------------------------------------------------------------------
// Dump: dump description of inline behavior
//
// Arguments:
// showBudget - also dump final budget values

void InlineStrategy::Dump()
void InlineStrategy::Dump(bool showBudget)
{
m_RootContext->Dump();

if (!showBudget)
{
return;
}

printf("Budget: initialTime=%d, finalTime=%d, initialBudget=%d, currentBudget=%d\n", m_InitialTimeEstimate,
m_CurrentTimeEstimate, m_InitialTimeBudget, m_CurrentTimeBudget);

Expand Down
34 changes: 23 additions & 11 deletions src/jit/inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -677,20 +677,32 @@ class InlineContext
return m_Parent == nullptr;
}

bool IsDevirtualized() const
{
return m_Devirtualized;
}

bool IsUnboxed() const
{
return m_Unboxed;
}

private:
InlineContext(InlineStrategy* strategy);

private:
InlineStrategy* m_InlineStrategy; // overall strategy
InlineContext* m_Parent; // logical caller (parent)
InlineContext* m_Child; // first child
InlineContext* m_Sibling; // next child of the parent
BYTE* m_Code; // address of IL buffer for the method
unsigned m_ILSize; // size of IL buffer for the method
IL_OFFSETX m_Offset; // call site location within parent
InlineObservation m_Observation; // what lead to this inline
int m_CodeSizeEstimate; // in bytes * 10
bool m_Success; // true if this was a successful inline
InlineStrategy* m_InlineStrategy; // overall strategy
InlineContext* m_Parent; // logical caller (parent)
InlineContext* m_Child; // first child
InlineContext* m_Sibling; // next child of the parent
BYTE* m_Code; // address of IL buffer for the method
unsigned m_ILSize; // size of IL buffer for the method
IL_OFFSETX m_Offset; // call site location within parent
InlineObservation m_Observation; // what lead to this inline
int m_CodeSizeEstimate; // in bytes * 10
bool m_Success : 1; // true if this was a successful inline
bool m_Devirtualized : 1; // true if this was a devirtualized call
bool m_Unboxed : 1; // true if this call now invokes the unboxed entry

#if defined(DEBUG) || defined(INLINE_DATA)

Expand Down Expand Up @@ -817,7 +829,7 @@ class InlineStrategy
#if defined(DEBUG) || defined(INLINE_DATA)

// Dump textual description of inlines done so far.
void Dump();
void Dump(bool showBudget);

// Dump data-format description of inlines done so far.
void DumpData();
Expand Down

0 comments on commit d5ce249

Please sign in to comment.