Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Multiple GDV: ignore non-inlineable candidates #86835

Merged
merged 2 commits into from
May 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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