Skip to content

Commit 006ad21

Browse files
authored
JIT: boost inlining for methods that may return small arrays (#114806)
Look for inlinees that may be allocating and returning small fixed sized arrays. When inlined, these array allocations may end up non-escaping and be stack allocated. This analysis is approximate; we can't tell for sure in the IL scan what the array size is, and we can't easily tell if the allocated array is actually returned. Contributes to #113236
1 parent 45a4cc2 commit 006ad21

File tree

4 files changed

+52
-6
lines changed

4 files changed

+52
-6
lines changed

src/coreclr/jit/fgbasic.cpp

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -915,12 +915,14 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed
915915
var_types varType = DUMMY_INIT(TYP_UNDEF); // TYP_ type
916916
bool typeIsNormed = false;
917917
FgStack pushedStack;
918-
const bool isForceInline = (info.compFlags & CORINFO_FLG_FORCEINLINE) != 0;
919-
const bool isInlining = compIsForInlining();
920-
unsigned retBlocks = 0;
921-
int prefixFlags = 0;
922-
bool preciseScan = makeInlineObservations && compInlineResult->GetPolicy()->RequiresPreciseScan();
923-
const bool resolveTokens = preciseScan;
918+
const bool isForceInline = (info.compFlags & CORINFO_FLG_FORCEINLINE) != 0;
919+
const bool isInlining = compIsForInlining();
920+
unsigned retBlocks = 0;
921+
int prefixFlags = 0;
922+
bool preciseScan = makeInlineObservations && compInlineResult->GetPolicy()->RequiresPreciseScan();
923+
const bool resolveTokens = preciseScan;
924+
bool isReturnsArrayKnown = false;
925+
bool returnsArray = false;
924926

925927
// Track offsets where IL instructions begin in DEBUG builds. Used to
926928
// validate debug info generated by the JIT.
@@ -2441,6 +2443,36 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed
24412443
retBlocks++;
24422444
break;
24432445

2446+
case CEE_NEWARR:
2447+
2448+
if (makeInlineObservations)
2449+
{
2450+
if (!isReturnsArrayKnown)
2451+
{
2452+
if (info.compRetType == TYP_REF)
2453+
{
2454+
CORINFO_CLASS_HANDLE retClass = info.compMethodInfo->args.retTypeClass;
2455+
if (retClass != NO_CLASS_HANDLE)
2456+
{
2457+
uint32_t retClassAttribs = info.compCompHnd->getClassAttribs(retClass);
2458+
returnsArray = (retClassAttribs & CORINFO_FLG_ARRAY) != 0;
2459+
}
2460+
}
2461+
isReturnsArrayKnown = true;
2462+
}
2463+
2464+
if (returnsArray && pushedStack.IsStackAtLeastOneDeep())
2465+
{
2466+
FgStack::FgSlot slot0 = pushedStack.GetSlot0();
2467+
2468+
if (FgStack::IsConstantOrConstArg(slot0, impInlineInfo))
2469+
{
2470+
compInlineResult->Note(InlineObservation::CALLEE_MAY_RETURN_SMALL_ARRAY);
2471+
}
2472+
}
2473+
}
2474+
break;
2475+
24442476
default:
24452477
break;
24462478
}

src/coreclr/jit/inline.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ INLINE_OBSERVATION(IS_SIZE_DECREASING_INLINE, bool, "size decreasing inline",
101101
INLINE_OBSERVATION(LOG_REPLAY_ACCEPT, bool, "accepted by log replay", INFORMATION, CALLEE)
102102
INLINE_OBSERVATION(LOOKS_LIKE_WRAPPER, bool, "thin wrapper around a call", INFORMATION, CALLEE)
103103
INLINE_OBSERVATION(MAXSTACK, int, "maxstack", INFORMATION, CALLEE)
104+
INLINE_OBSERVATION(MAY_RETURN_SMALL_ARRAY, bool, "may return a small new array", INFORMATION, CALLEE)
104105
INLINE_OBSERVATION(OPCODE, int, "next opcode in IL stream", INFORMATION, CALLEE)
105106
INLINE_OBSERVATION(OPCODE_NORMED, int, "next opcode in IL stream", INFORMATION, CALLEE)
106107
INLINE_OBSERVATION(NUMBER_OF_ARGUMENTS, int, "number of arguments", INFORMATION, CALLEE)

src/coreclr/jit/inlinepolicy.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,6 +1341,10 @@ void ExtendedDefaultPolicy::NoteBool(InlineObservation obs, bool value)
13411341
m_ArgUnboxExact++;
13421342
break;
13431343

1344+
case InlineObservation::CALLEE_MAY_RETURN_SMALL_ARRAY:
1345+
m_MayReturnSmallArray = true;
1346+
break;
1347+
13441348
default:
13451349
DefaultPolicy::NoteBool(obs, value);
13461350
break;
@@ -1776,6 +1780,12 @@ double ExtendedDefaultPolicy::DetermineMultiplier()
17761780
}
17771781
}
17781782

1783+
if (m_MayReturnSmallArray)
1784+
{
1785+
multiplier += 4.0;
1786+
JITDUMP("\nInline candidate may return small known-size array. Multiplier increased to %g.", multiplier);
1787+
}
1788+
17791789
if (m_HasProfileWeights)
17801790
{
17811791
// There are cases when Profile Data can be misleading or polluted:
@@ -1889,6 +1899,7 @@ void ExtendedDefaultPolicy::OnDumpXml(FILE* file, unsigned indent) const
18891899
XATTR_B(m_IsCallsiteInNoReturnRegion)
18901900
XATTR_B(m_HasProfileWeights)
18911901
XATTR_B(m_InsideThrowBlock)
1902+
XATTR_B(m_MayReturnSmallArray)
18921903
}
18931904
#endif
18941905

src/coreclr/jit/inlinepolicy.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ class ExtendedDefaultPolicy : public DefaultPolicy
226226
, m_NonGenericCallsGeneric(false)
227227
, m_IsCallsiteInNoReturnRegion(false)
228228
, m_HasProfileWeights(false)
229+
, m_MayReturnSmallArray(false)
229230
{
230231
// Empty
231232
}
@@ -281,6 +282,7 @@ class ExtendedDefaultPolicy : public DefaultPolicy
281282
bool m_NonGenericCallsGeneric : 1;
282283
bool m_IsCallsiteInNoReturnRegion : 1;
283284
bool m_HasProfileWeights : 1;
285+
bool m_MayReturnSmallArray : 1;
284286
};
285287

286288
// DiscretionaryPolicy is a variant of the default policy. It

0 commit comments

Comments
 (0)