if ((expr->gtOper == GT_CALL) && ((expr->gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0))
{
GenTreeCall* call = expr->AsCall();
- InlineResult inlineResult(this, call, stmt->gtInlineContext, "fgInline");
+ InlineResult inlineResult(this, call, stmt, "fgInline");
fgMorphStmt = stmt;
if (m_Parent == nullptr)
{
// Root method... cons up a policy so we can display the name
- InlinePolicy* policy = InlinePolicy::GetPolicy(compiler, nullptr, true);
+ InlinePolicy* policy = InlinePolicy::GetPolicy(compiler, true);
printf("\nInlines [%u] into \"%s\" [%s]\n",
m_InlineStrategy->GetInlineCount(),
calleeName,
// Arguments:
// compiler - the compiler instance examining a call for inlining
// call - the call in question
-// inlineContext - the inline context for the inline, if known
+// stmt - statement containing the call (if known)
// description - string describing the context of the decision
InlineResult::InlineResult(Compiler* compiler,
GenTreeCall* call,
- InlineContext* inlineContext,
+ GenTreeStmt* stmt,
const char* description)
: m_RootCompiler(nullptr)
, m_Policy(nullptr)
, m_Call(call)
- , m_InlineContext(inlineContext)
+ , m_InlineContext(nullptr)
, m_Caller(nullptr)
, m_Callee(nullptr)
, m_Description(description)
// Set the policy
const bool isPrejitRoot = false;
- m_Policy = InlinePolicy::GetPolicy(m_RootCompiler, m_InlineContext, isPrejitRoot);
+ m_Policy = InlinePolicy::GetPolicy(m_RootCompiler, isPrejitRoot);
+
+ // Pass along some optional information to the policy.
+ if (stmt != nullptr)
+ {
+ m_InlineContext = stmt->gtInlineContext;
+ m_Policy->NoteContext(m_InlineContext);
+
+#if defined(DEBUG) || defined(INLINE_DATA)
+ m_Policy->NoteOffset(call->gtRawILOffset);
+#else
+ m_Policy->NoteOffset(stmt->gtStmtILoffsx);
+#endif // defined(DEBUG) || defined(INLINE_DATA)
+ }
// Get method handle for caller. Note we use the
// handle for the "immediate" caller here.
// Set the policy
const bool isPrejitRoot = true;
- m_Policy = InlinePolicy::GetPolicy(m_RootCompiler, nullptr, isPrejitRoot);
+ m_Policy = InlinePolicy::GetPolicy(m_RootCompiler, isPrejitRoot);
}
//------------------------------------------------------------------------
calleeContext->m_Callee = inlineInfo->fncHandle;
// +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;
#endif // defined(DEBUG) || defined(INLINE_DATA)
failedContext->m_Callee = inlineResult->GetCallee();
failedContext->m_Success = false;
+#if defined(DEBUG) || defined(INLINE_DATA)
+
+ // Update offset with more accurate info
+ failedContext->m_Offset = inlineResult->GetCall()->gtRawILOffset;
+
+#endif // #if defined(DEBUG) || defined(INLINE_DATA)
+
#if defined(DEBUG)
failedContext->m_TreeID = inlineResult->GetCall()->gtTreeID;
if (m_LastSuccessfulPolicy == nullptr)
{
const bool isPrejitRoot = (opts.eeFlags & CORJIT_FLG_PREJIT) != 0;
- m_LastSuccessfulPolicy = InlinePolicy::GetPolicy(m_Compiler, nullptr, isPrejitRoot);
+ m_LastSuccessfulPolicy = InlinePolicy::GetPolicy(m_Compiler, isPrejitRoot);
// Add in a bit of data....
const bool isForceInline = (info.compFlags & CORINFO_FLG_FORCEINLINE) != 0;
public:
// Factory method for getting policies
- static InlinePolicy* GetPolicy(Compiler* compiler, InlineContext* context, bool isPrejitRoot);
+ static InlinePolicy* GetPolicy(Compiler* compiler, bool isPrejitRoot);
// Obligatory virtual dtor
virtual ~InlinePolicy() {}
virtual void NoteFatal(InlineObservation obs) = 0;
virtual void NoteInt(InlineObservation obs, int value) = 0;
+ // Optional observations. Most policies ignore these.
+ virtual void NoteContext(InlineContext* context) { (void) context; }
+ virtual void NoteOffset(IL_OFFSETX offset) { (void) offset; }
+
// Policy determinations
virtual void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) = 0;
// particular call for inlining.
InlineResult(Compiler* compiler,
GenTreeCall* call,
- InlineContext* inlineContext,
+ GenTreeStmt* stmt,
const char* description);
// Construct a new InlineResult to evaluate a particular
return m_CodeSizeEstimate;
}
+ // Get the offset of the call site
+ IL_OFFSETX GetOffset() const
+ {
+ return m_Offset;
+ }
+
// True if this is the root context
bool IsRoot() const
{
//
// Arguments:
// compiler - the compiler instance that will evaluate inlines
-// inlineContext - the context of the inline
// isPrejitRoot - true if this policy is evaluating a prejit root
//
// Return Value:
// Determines which of the various policies should apply,
// and creates (or reuses) a policy instance to use.
-InlinePolicy* InlinePolicy::GetPolicy(Compiler* compiler, InlineContext* inlineContext, bool isPrejitRoot)
+InlinePolicy* InlinePolicy::GetPolicy(Compiler* compiler, bool isPrejitRoot)
{
- // inlineContext only conditionally used below.
- (void) inlineContext;
-
#ifdef DEBUG
// Optionally install the RandomPolicy.
if (useReplayPolicy)
{
- return new (compiler, CMK_Inlining) ReplayPolicy(compiler, inlineContext, isPrejitRoot);
+ return new (compiler, CMK_Inlining) ReplayPolicy(compiler, isPrejitRoot);
}
// Optionally install the SizePolicy.
//
// Arguments:
// compiler -- compiler instance doing the inlining (root compiler)
-// inlineContext -- inline context for the inline
// isPrejitRoot -- true if this compiler is prejitting the root method
-ReplayPolicy::ReplayPolicy(Compiler* compiler, InlineContext* inlineContext, bool isPrejitRoot)
+ReplayPolicy::ReplayPolicy(Compiler* compiler, bool isPrejitRoot)
: DiscretionaryPolicy(compiler, isPrejitRoot)
- , m_InlineContext(inlineContext)
+ , m_InlineContext(nullptr)
{
// Is there a log file open already? If so, we can use it.
if (s_ReplayFile == nullptr)
unsigned contextHash =
m_RootCompiler->info.compCompHnd->getMethodHash(
context->GetCallee());
+ unsigned contextOffset = (unsigned) context->GetOffset();
- return FindInline(contextToken, contextHash);
+ return FindInline(contextToken, contextHash, contextOffset);
}
//------------------------------------------------------------------------
// Arguments:
// token -- token describing the inline
// hash -- hash describing the inline
+// offset -- IL offset of the call site in the parent method
//
// ReturnValue:
// true if the inline entry was found
// particular inline, if there are multiple calls to the same
// method.
-bool ReplayPolicy::FindInline(unsigned token, unsigned hash)
+bool ReplayPolicy::FindInline(unsigned token, unsigned hash, unsigned offset)
{
char buffer[256];
bool foundInline = false;
break;
}
+ // Match token
unsigned inlineToken = 0;
int count = sscanf(buffer, " <Token>%u</Token> ", &inlineToken);
- // Need a secondary check here for callsite.
- // ...offset or similar.
if ((count != 1) || (inlineToken != token))
{
continue;
break;
}
+ // Match hash
unsigned inlineHash = 0;
count = sscanf(buffer, " <Hash>%u</Hash> ", &inlineHash);
- // Need a secondary check here for callsite ID
- // ... offset or similar.
if ((count != 1) || (inlineHash != hash))
{
continue;
}
+ // Get next line
+ if (fgets(buffer, sizeof(buffer), s_ReplayFile) == nullptr)
+ {
+ break;
+ }
+
+ // Match offset
+ unsigned inlineOffset = 0;
+ count = sscanf(buffer, " <Offset>%u</Offset> ", &inlineOffset);
+ if ((count != 1) || (inlineOffset != offset))
+ {
+ continue;
+ }
+
+ // Token,Hash,Offset may still not be unique enough, but it's
+ // all we have right now.
+
// We're good!
foundInline = true;
break;
unsigned calleeHash =
m_RootCompiler->info.compCompHnd->getMethodHash(callee);
- bool foundInline = FindInline(calleeToken, calleeHash);
+ // Abstract this or just pass through raw bits
+ // See matching code in xml writer
+ int offset = -1;
+ if (m_Offset != BAD_IL_OFFSET)
+ {
+ offset = (int) jitGetILoffs(m_Offset);
+ }
+
+ unsigned calleeOffset = (unsigned) offset;
+
+ bool foundInline = FindInline(calleeToken, calleeHash, calleeOffset);
return foundInline;
}
public:
// Construct a ReplayPolicy
- ReplayPolicy(Compiler* compiler, InlineContext* inlineContext, bool isPrejitRoot);
+ ReplayPolicy(Compiler* compiler, bool isPrejitRoot);
+
+ // Optional observations
+ void NoteContext(InlineContext* context) override
+ {
+ m_InlineContext = context;
+ }
+
+ void NoteOffset(IL_OFFSETX offset) override
+ {
+ m_Offset = offset;
+ }
// Policy determinations
void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;
bool FindMethod();
bool FindContext(InlineContext* context);
bool FindInline(CORINFO_METHOD_HANDLE callee);
- bool FindInline(unsigned token, unsigned hash);
+ bool FindInline(unsigned token, unsigned hash, unsigned offset);
static bool s_WroteReplayBanner;
static FILE* s_ReplayFile;
static CritSecObject s_XmlReaderLock;
InlineContext* m_InlineContext;
+ IL_OFFSETX m_Offset;
};
#endif // defined(DEBUG) || defined(INLINE_DATA)