Skip to content

Commit

Permalink
Multiple GDV: ignore non-inlineable candidates (#86835)
Browse files Browse the repository at this point in the history
  • Loading branch information
EgorBo authored May 27, 2023
1 parent e6a8f5e commit d58754b
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 20 deletions.
49 changes: 44 additions & 5 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2194,7 +2194,12 @@ void GenTreeCall::SetSingleInlineCandidateInfo(InlineCandidateInfo* candidateInf
InlineCandidateInfo* GenTreeCall::GetGDVCandidateInfo(uint8_t index)
{
assert(index < gtInlineInfoCount);
return &gtInlineCandidateInfo[index];
if (gtInlineInfoCount > 1)
{
// In this case we should access it through gtInlineCandidateInfoList
return gtInlineCandidateInfoList->at(index);
}
return gtInlineCandidateInfo;
}

//-------------------------------------------------------------------------
Expand All @@ -2212,22 +2217,56 @@ void GenTreeCall::AddGDVCandidateInfo(Compiler* comp, InlineCandidateInfo* candi

if (gtInlineInfoCount == 0)
{
// Most calls are monomorphic, so we don't need to allocate a vector
gtInlineCandidateInfo = candidateInfo;
}
else if (gtInlineInfoCount == 1)
{
gtInlineCandidateInfo =
new (comp, CMK_Inlining) InlineCandidateInfo[MAX_GDV_TYPE_CHECKS]{*gtInlineCandidateInfo, *candidateInfo};
// Upgrade gtInlineCandidateInfo to gtInlineCandidateInfoList (vector)
CompAllocator allocator = comp->getAllocator(CMK_Inlining);
InlineCandidateInfo* firstCandidate = gtInlineCandidateInfo;
gtInlineCandidateInfoList = new (allocator) jitstd::vector<InlineCandidateInfo*>(allocator);
gtInlineCandidateInfoList->push_back(firstCandidate);
gtInlineCandidateInfoList->push_back(candidateInfo);
}
else
{
gtInlineCandidateInfo[gtInlineInfoCount] = *candidateInfo;
gtInlineCandidateInfoList->push_back(candidateInfo);
}

gtCallMoreFlags |= GTF_CALL_M_GUARDED_DEVIRT;
gtInlineInfoCount++;
}

//-------------------------------------------------------------------------
// RemoveGDVCandidateInfo: Remove a guarded devirtualization (GDV) candidate info
// by its index. Index must not be greater than gtInlineInfoCount
// the call will be marked as "has no inline candidates" if the last candidate is removed
//
// Arguments:
// comp - Compiler instance
// index - GDV candidate to remove
//
void GenTreeCall::RemoveGDVCandidateInfo(Compiler* comp, uint8_t index)
{
assert(index < gtInlineInfoCount);

if (gtInlineInfoCount == 1)
{
// No longer have any inline candidates
ClearInlineInfo();
assert(gtInlineInfoCount == 0);
return;
}
gtInlineCandidateInfoList->erase(gtInlineCandidateInfoList->begin() + index);
gtInlineInfoCount--;

// Downgrade gtInlineCandidateInfoList to gtInlineCandidateInfo
if (gtInlineInfoCount == 1)
{
gtInlineCandidateInfo = gtInlineCandidateInfoList->at(0);
}
}

//-------------------------------------------------------------------------
// HasSideEffects:
// Returns true if this call has any side effects. All non-helpers are considered to have side-effects. Only helpers
Expand Down
8 changes: 7 additions & 1 deletion src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -5447,6 +5447,8 @@ struct GenTreeCall final : public GenTree

void AddGDVCandidateInfo(Compiler* comp, InlineCandidateInfo* candidateInfo);

void RemoveGDVCandidateInfo(Compiler* comp, uint8_t index);

void ClearInlineInfo()
{
SetSingleInlineCandidateInfo(nullptr);
Expand Down Expand Up @@ -5542,8 +5544,12 @@ struct GenTreeCall final : public GenTree
union {
// only used for CALLI unmanaged calls (CT_INDIRECT)
GenTree* gtCallCookie;

// gtInlineCandidateInfo is only used when inlining methods
InlineCandidateInfo* gtInlineCandidateInfo;
InlineCandidateInfo* gtInlineCandidateInfo;
// gtInlineCandidateInfoList is used when we have more than one GDV candidate
jitstd::vector<InlineCandidateInfo*>* gtInlineCandidateInfoList;

HandleHistogramProfileCandidateInfo* gtHandleHistogramProfileCandidateInfo;
LateDevirtualizationInfo* gtLateDevirtualizationInfo;
CORINFO_GENERIC_HANDLE compileTimeHelperArgumentHandle; // Used to track type handle argument of dynamic helpers
Expand Down
21 changes: 7 additions & 14 deletions src/coreclr/jit/importercalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6212,29 +6212,22 @@ void Compiler::impMarkInlineCandidate(GenTree* callNode,

if (call->IsGuardedDevirtualizationCandidate())
{
const uint8_t candidatesCount = call->GetInlineCandidatesCount();
assert(candidatesCount > 0);
for (uint8_t candidateId = 0; candidateId < candidatesCount; candidateId++)
assert(call->GetInlineCandidatesCount() > 0);
for (uint8_t candidateId = 0; candidateId < call->GetInlineCandidatesCount(); candidateId++)
{
InlineResult inlineResult(this, call, nullptr, "impMarkInlineCandidate", true);

// Do the actual evaluation
impMarkInlineCandidateHelper(call, candidateId, exactContextHnd, exactContextNeedsRuntimeLookup, callInfo,
ilOffset, &inlineResult);

// Ignore non-inlineable candidates
// TODO: Consider keeping them to just devirtualize without inlining, at least for interface
// calls on NativeAOT, but that requires more changes elsewhere too.
if (!inlineResult.IsCandidate())
{
if (candidatesCount > 1)
{
// TODO: we should not give up if one of the candidates fails to inline while others succeed.
//
JITDUMP(
"We had multiple inline candidates but have to give up on them since one of them didn't pass"
"inline checks")
call->ClearInlineInfo();
call->ClearGuardedDevirtualizationCandidate();
}
break;
call->RemoveGDVCandidateInfo(this, candidateId);
candidateId--;
}
}
}
Expand Down

0 comments on commit d58754b

Please sign in to comment.