Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEgor Bogatov <egorbo@gmail.com>2021-07-14 14:01:14 +0300
committerGitHub <noreply@github.com>2021-07-14 14:01:14 +0300
commit21e36e872556c157d4b65a1c997d92dfb31f18c5 (patch)
tree1ff6775dfc6c985aa01945e0cb8e2d86909c1f94 /src
parentafaf666eff08435123eb649ac138419f4c9b9344 (diff)
Inliner: Extend IL limit for profiled call-sites, allow inlining for switches. (#55478)
Diffstat (limited to 'src')
-rw-r--r--src/coreclr/jit/block.cpp3
-rw-r--r--src/coreclr/jit/compiler.cpp3
-rw-r--r--src/coreclr/jit/compiler.h1
-rw-r--r--src/coreclr/jit/fgbasic.cpp64
-rw-r--r--src/coreclr/jit/fgprofile.cpp25
-rw-r--r--src/coreclr/jit/importer.cpp41
-rw-r--r--src/coreclr/jit/inline.def1
-rw-r--r--src/coreclr/jit/inline.h1
-rw-r--r--src/coreclr/jit/inlinepolicy.cpp73
-rw-r--r--src/coreclr/jit/inlinepolicy.h4
-rw-r--r--src/coreclr/jit/jitconfigvalues.h3
-rw-r--r--src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/DebugViewWriter.cs2
12 files changed, 171 insertions, 50 deletions
diff --git a/src/coreclr/jit/block.cpp b/src/coreclr/jit/block.cpp
index 128c4e033d9..5df8c1e4358 100644
--- a/src/coreclr/jit/block.cpp
+++ b/src/coreclr/jit/block.cpp
@@ -1431,6 +1431,7 @@ BasicBlock* Compiler::bbNewBasicBlock(BBjumpKinds jumpKind)
/* Give the block a number, set the ancestor count and weight */
++fgBBcount;
+ ++fgBBNumMax;
if (compIsForInlining())
{
@@ -1438,7 +1439,7 @@ BasicBlock* Compiler::bbNewBasicBlock(BBjumpKinds jumpKind)
}
else
{
- block->bbNum = ++fgBBNumMax;
+ block->bbNum = fgBBNumMax;
}
if (compRationalIRForm)
diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp
index bf49e63ab0c..fe5734213af 100644
--- a/src/coreclr/jit/compiler.cpp
+++ b/src/coreclr/jit/compiler.cpp
@@ -6272,6 +6272,9 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr,
// a potential inline candidate.
InlineResult prejitResult(this, methodHnd, "prejit");
+ // Profile data allows us to avoid early "too many IL bytes" outs.
+ prejitResult.NoteBool(InlineObservation::CALLSITE_HAS_PROFILE, fgHaveSufficientProfileData());
+
// Do the initial inline screen.
impCanInlineIL(methodHnd, methodInfo, forceInline, &prejitResult);
diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h
index b60353d8e84..9027a5d2335 100644
--- a/src/coreclr/jit/compiler.h
+++ b/src/coreclr/jit/compiler.h
@@ -5814,6 +5814,7 @@ public:
void WalkSpanningTree(SpanningTreeVisitor* visitor);
void fgSetProfileWeight(BasicBlock* block, BasicBlock::weight_t weight);
void fgApplyProfileScale();
+ bool fgHaveSufficientProfileData();
// fgIsUsingProfileWeights - returns true if we have real profile data for this method
// or if we have some fake profile data for the stress mode
diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp
index 62a9467da63..6c65586fbca 100644
--- a/src/coreclr/jit/fgbasic.cpp
+++ b/src/coreclr/jit/fgbasic.cpp
@@ -818,8 +818,24 @@ public:
return false;
}
const unsigned argNum = value - SLOT_ARGUMENT;
- assert(argNum < info->argCnt);
- return info->inlArgInfo[argNum].argIsInvariant;
+ if (argNum < info->argCnt)
+ {
+ return info->inlArgInfo[argNum].argIsInvariant;
+ }
+ return false;
+ }
+ static bool IsExactArgument(FgSlot value, InlineInfo* info)
+ {
+ if ((info == nullptr) || !IsArgument(value))
+ {
+ return false;
+ }
+ const unsigned argNum = value - SLOT_ARGUMENT;
+ if (argNum < info->argCnt)
+ {
+ return info->inlArgInfo[argNum].argIsExact;
+ }
+ return false;
}
static unsigned SlotTypeToArgNum(FgSlot value)
{
@@ -876,6 +892,10 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed
if (makeInlineObservations)
{
+ // Set default values for profile (to avoid NoteFailed in CALLEE_IL_CODE_SIZE's handler)
+ // these will be overridden later.
+ compInlineResult->NoteBool(InlineObservation::CALLSITE_HAS_PROFILE, true);
+ compInlineResult->NoteDouble(InlineObservation::CALLSITE_PROFILE_FREQUENCY, 1.0);
// Observe force inline state and code size.
compInlineResult->NoteBool(InlineObservation::CALLEE_IS_FORCE_INLINE, isForceInline);
compInlineResult->NoteInt(InlineObservation::CALLEE_IL_CODE_SIZE, codeSize);
@@ -1031,7 +1051,8 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed
if (makeInlineObservations)
{
FgStack::FgSlot slot = pushedStack.Top();
- if (FgStack::IsConstantOrConstArg(slot, impInlineInfo))
+ if (FgStack::IsConstantOrConstArg(slot, impInlineInfo) ||
+ FgStack::IsExactArgument(slot, impInlineInfo))
{
compInlineResult->Note(InlineObservation::CALLSITE_FOLDABLE_EXPR_UN);
handled = true; // and keep argument in the pushedStack
@@ -1338,44 +1359,59 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed
FgStack::FgSlot arg0 = pushedStack.Top(1);
FgStack::FgSlot arg1 = pushedStack.Top(0);
- if ((FgStack::IsConstant(arg0) && FgStack::IsConstArgument(arg1, impInlineInfo)) ||
- (FgStack::IsConstant(arg1) && FgStack::IsConstArgument(arg0, impInlineInfo)) ||
- (FgStack::IsConstArgument(arg0, impInlineInfo) &&
- FgStack::IsConstArgument(arg1, impInlineInfo)))
+ // Const op ConstArg -> ConstArg
+ if (FgStack::IsConstant(arg0) && FgStack::IsConstArgument(arg1, impInlineInfo))
{
// keep stack unchanged
handled = true;
compInlineResult->Note(InlineObservation::CALLSITE_FOLDABLE_EXPR);
}
- if ((FgStack::IsConstant(arg0) && FgStack::IsConstant(arg1)) ||
- (FgStack::IsConstant(arg1) && FgStack::IsConstant(arg0)))
+ // ConstArg op Const -> ConstArg
+ // ConstArg op ConstArg -> ConstArg
+ else if (FgStack::IsConstArgument(arg0, impInlineInfo) &&
+ FgStack::IsConstantOrConstArg(arg1, impInlineInfo))
+ {
+ if (FgStack::IsConstant(arg1))
+ {
+ pushedStack.Push(arg0);
+ }
+ handled = true;
+ compInlineResult->Note(InlineObservation::CALLSITE_FOLDABLE_EXPR);
+ }
+ // Const op Const -> Const
+ else if (FgStack::IsConstant(arg0) && FgStack::IsConstant(arg1))
{
// both are constants, but we're mostly interested in cases where a const arg leads to
// a foldable expression.
handled = true;
}
+ // Arg op ConstArg
+ // Arg op Const
else if (FgStack::IsArgument(arg0) && FgStack::IsConstantOrConstArg(arg1, impInlineInfo))
{
// "Arg op CNS" --> keep arg0 in the stack for the next ops
+ pushedStack.Push(arg0);
handled = true;
compInlineResult->Note(InlineObservation::CALLEE_BINARY_EXRP_WITH_CNS);
}
+ // ConstArg op Arg
+ // Const op Arg
else if (FgStack::IsArgument(arg1) && FgStack::IsConstantOrConstArg(arg0, impInlineInfo))
{
// "CNS op ARG" --> keep arg1 in the stack for the next ops
- pushedStack.Push(arg1);
handled = true;
compInlineResult->Note(InlineObservation::CALLEE_BINARY_EXRP_WITH_CNS);
}
-
+ // X / ConstArg
+ // X % ConstArg
if (FgStack::IsConstArgument(arg1, impInlineInfo))
{
- // Special case: "X / ConstArg" or "X % ConstArg"
if ((opcode == CEE_DIV) || (opcode == CEE_DIV_UN) || (opcode == CEE_REM) ||
(opcode == CEE_REM_UN))
{
compInlineResult->Note(InlineObservation::CALLSITE_DIV_BY_CNS);
}
+ pushedStack.Push(arg0);
handled = true;
}
}
@@ -1583,6 +1619,10 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed
if (makeInlineObservations)
{
compInlineResult->Note(InlineObservation::CALLEE_HAS_SWITCH);
+ if (FgStack::IsConstantOrConstArg(pushedStack.Top(), impInlineInfo))
+ {
+ compInlineResult->Note(InlineObservation::CALLSITE_FOLDABLE_SWITCH);
+ }
// Fail fast, if we're inlining and can't handle this.
if (isInlining && compInlineResult->IsFailure())
diff --git a/src/coreclr/jit/fgprofile.cpp b/src/coreclr/jit/fgprofile.cpp
index 1659b2d3905..31d7c208eba 100644
--- a/src/coreclr/jit/fgprofile.cpp
+++ b/src/coreclr/jit/fgprofile.cpp
@@ -48,6 +48,31 @@ bool Compiler::fgHaveProfileData()
}
//------------------------------------------------------------------------
+// fgHaveSufficientProfileData: check if profile data is available
+// and is sufficient enough to be trustful.
+//
+// Returns:
+// true if so
+//
+// Note:
+// See notes for fgHaveProfileData.
+//
+bool Compiler::fgHaveSufficientProfileData()
+{
+ if (!fgHaveProfileData())
+ {
+ return false;
+ }
+
+ if ((fgFirstBB != nullptr) && (fgPgoSource == ICorJitInfo::PgoSource::Static))
+ {
+ const BasicBlock::weight_t sufficientSamples = 1000;
+ return fgFirstBB->bbWeight > sufficientSamples;
+ }
+ return true;
+}
+
+//------------------------------------------------------------------------
// fgApplyProfileScale: scale inlinee counts by appropriate scale factor
//
void Compiler::fgApplyProfileScale()
diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index c30e9a17784..b3857cdec58 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -13267,8 +13267,6 @@ void Compiler::impImportBlockCode(BasicBlock* block)
goto COND_JUMP;
case CEE_SWITCH:
- assert(!compIsForInlining());
-
if (tiVerificationNeeded)
{
Verify(impStackTop().seTypeInfo.IsType(TI_INT), "Bad switch val");
@@ -19080,33 +19078,30 @@ void Compiler::impMakeDiscretionaryInlineObservations(InlineInfo* pInlineInfo, I
inlineResult->NoteInt(InlineObservation::CALLSITE_FREQUENCY, static_cast<int>(frequency));
inlineResult->NoteInt(InlineObservation::CALLSITE_WEIGHT, (int)(weight));
+ bool hasProfile = false;
+ double profileFreq = 0.0;
+
// If the call site has profile data, report the relative frequency of the site.
//
- if ((pInlineInfo != nullptr) && rootCompiler->fgHaveProfileData() && pInlineInfo->iciBlock->hasProfileWeight())
+ if ((pInlineInfo != nullptr) && rootCompiler->fgHaveSufficientProfileData())
{
- BasicBlock::weight_t callSiteWeight = pInlineInfo->iciBlock->bbWeight;
- BasicBlock::weight_t entryWeight = rootCompiler->fgFirstBB->bbWeight;
- BasicBlock::weight_t profileFreq = entryWeight == 0.0f ? 0.0f : callSiteWeight / entryWeight;
+ const BasicBlock::weight_t callSiteWeight = pInlineInfo->iciBlock->bbWeight;
+ const BasicBlock::weight_t entryWeight = rootCompiler->fgFirstBB->bbWeight;
+ profileFreq = entryWeight == 0.0f ? 0.0 : callSiteWeight / entryWeight;
+ hasProfile = true;
assert(callSiteWeight >= 0);
assert(entryWeight >= 0);
-
- BasicBlock::weight_t sufficientSamples = 1000.0f;
-
- if (!rootCompiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT) ||
- ((callSiteWeight + entryWeight) > sufficientSamples))
- {
- // Let's not report profiles for methods with insufficient samples during prejitting.
- inlineResult->NoteBool(InlineObservation::CALLSITE_HAS_PROFILE, true);
- inlineResult->NoteDouble(InlineObservation::CALLSITE_PROFILE_FREQUENCY, profileFreq);
- }
}
- else if ((pInlineInfo == nullptr) && rootCompiler->fgHaveProfileData())
+ else if (pInlineInfo == nullptr)
{
// Simulate a hot callsite for PrejitRoot mode.
- inlineResult->NoteBool(InlineObservation::CALLSITE_HAS_PROFILE, true);
- inlineResult->NoteDouble(InlineObservation::CALLSITE_PROFILE_FREQUENCY, 1.0);
+ hasProfile = true;
+ profileFreq = 1.0;
}
+
+ inlineResult->NoteBool(InlineObservation::CALLSITE_HAS_PROFILE, hasProfile);
+ inlineResult->NoteDouble(InlineObservation::CALLSITE_PROFILE_FREQUENCY, profileFreq);
}
/*****************************************************************************
@@ -19252,6 +19247,10 @@ void Compiler::impCheckCanInline(GenTreeCall* call,
goto _exit;
}
+ // Profile data allows us to avoid early "too many IL bytes" outs.
+ pParam->result->NoteBool(InlineObservation::CALLSITE_HAS_PROFILE,
+ pParam->pThis->fgHaveSufficientProfileData());
+
bool forceInline;
forceInline = !!(pParam->methAttr & CORINFO_FLG_FORCEINLINE);
@@ -19474,6 +19473,10 @@ void Compiler::impInlineRecordArgInfo(InlineInfo* pInlineInfo,
}
}
+ bool isExact = false;
+ bool isNonNull = false;
+ inlCurArgInfo->argIsExact = (gtGetClassHandle(curArgVal, &isExact, &isNonNull) != NO_CLASS_HANDLE) && isExact;
+
// If the arg is a local that is address-taken, we can't safely
// directly substitute it into the inlinee.
//
diff --git a/src/coreclr/jit/inline.def b/src/coreclr/jit/inline.def
index a16d82888b6..cbd85ff240d 100644
--- a/src/coreclr/jit/inline.def
+++ b/src/coreclr/jit/inline.def
@@ -182,6 +182,7 @@ INLINE_OBSERVATION(FOLDABLE_INTRINSIC, int, "foldable intrinsic",
INLINE_OBSERVATION(FOLDABLE_EXPR, int, "foldable binary expression", INFORMATION, CALLSITE)
INLINE_OBSERVATION(FOLDABLE_EXPR_UN, int, "foldable unary expression", INFORMATION, CALLSITE)
INLINE_OBSERVATION(FOLDABLE_BRANCH, int, "foldable branch", INFORMATION, CALLSITE)
+INLINE_OBSERVATION(FOLDABLE_SWITCH, int, "foldable switch", INFORMATION, CALLSITE)
INLINE_OBSERVATION(DIV_BY_CNS, int, "dividy by const", INFORMATION, CALLSITE)
INLINE_OBSERVATION(CONSTANT_ARG_FEEDS_TEST, bool, "constant argument feeds test", INFORMATION, CALLSITE)
INLINE_OBSERVATION(DEPTH, int, "depth", INFORMATION, CALLSITE)
diff --git a/src/coreclr/jit/inline.h b/src/coreclr/jit/inline.h
index bc08dd8110d..6a39b2d9cb5 100644
--- a/src/coreclr/jit/inline.h
+++ b/src/coreclr/jit/inline.h
@@ -610,6 +610,7 @@ struct InlArgInfo
unsigned argHasStargOp : 1; // Is there STARG(s) operation on this argument?
unsigned argIsByRefToStructLocal : 1; // Is this arg an address of a struct local or a normed struct local or a
// field in them?
+ unsigned argIsExact : 1; // Is this arg of an exact class?
};
// InlLclVarInfo describes inline candidate argument and local variable properties.
diff --git a/src/coreclr/jit/inlinepolicy.cpp b/src/coreclr/jit/inlinepolicy.cpp
index fdf4ae19341..e84ff2858a0 100644
--- a/src/coreclr/jit/inlinepolicy.cpp
+++ b/src/coreclr/jit/inlinepolicy.cpp
@@ -326,7 +326,6 @@ void DefaultPolicy::NoteBool(InlineObservation obs, bool value)
m_ArgFeedsRangeCheck++;
break;
- case InlineObservation::CALLEE_HAS_SWITCH:
case InlineObservation::CALLEE_UNSUPPORTED_OPCODE:
propagate = true;
break;
@@ -1294,6 +1293,14 @@ void ExtendedDefaultPolicy::NoteBool(InlineObservation obs, bool value)
m_FoldableBranch++;
break;
+ case InlineObservation::CALLSITE_FOLDABLE_SWITCH:
+ m_FoldableSwitch++;
+ break;
+
+ case InlineObservation::CALLEE_HAS_SWITCH:
+ m_Switch++;
+ break;
+
case InlineObservation::CALLSITE_DIV_BY_CNS:
m_DivByCns++;
break;
@@ -1327,7 +1334,14 @@ void ExtendedDefaultPolicy::NoteInt(InlineObservation obs, int value)
{
assert(m_IsForceInlineKnown);
assert(value != 0);
- m_CodeSize = static_cast<unsigned>(value);
+ m_CodeSize = static_cast<unsigned>(value);
+ unsigned maxCodeSize = static_cast<unsigned>(JitConfig.JitExtDefaultPolicyMaxIL());
+
+ // TODO: Enable for PgoSource::Static as well if it's not the generic profile we bundle.
+ if (m_HasProfile && (m_RootCompiler->fgPgoSource == ICorJitInfo::PgoSource::Dynamic))
+ {
+ maxCodeSize = static_cast<unsigned>(JitConfig.JitExtDefaultPolicyMaxILProf());
+ }
if (m_IsForceInline)
{
@@ -1339,7 +1353,7 @@ void ExtendedDefaultPolicy::NoteInt(InlineObservation obs, int value)
// Candidate based on small size
SetCandidate(InlineObservation::CALLEE_BELOW_ALWAYS_INLINE_SIZE);
}
- else if (m_CodeSize <= (unsigned)JitConfig.JitExtDefaultPolicyMaxIL())
+ else if (m_CodeSize <= maxCodeSize)
{
// Candidate, pending profitability evaluation
SetCandidate(InlineObservation::CALLEE_IS_DISCRETIONARY_INLINE);
@@ -1357,16 +1371,16 @@ void ExtendedDefaultPolicy::NoteInt(InlineObservation obs, int value)
{
SetNever(InlineObservation::CALLEE_DOES_NOT_RETURN);
}
- else if (!m_IsForceInline)
+ else if (!m_IsForceInline && !m_HasProfile)
{
unsigned bbLimit = (unsigned)JitConfig.JitExtDefaultPolicyMaxBB();
if (m_IsPrejitRoot)
{
// We're not able to recognize arg-specific foldable branches
// in prejit-root mode.
- bbLimit += 3;
+ bbLimit += 5 + m_Switch * 10;
}
- bbLimit += m_FoldableBranch;
+ bbLimit += m_FoldableBranch + m_FoldableSwitch * 10;
if ((unsigned)value > bbLimit)
{
SetNever(InlineObservation::CALLEE_TOO_MANY_BASIC_BLOCKS);
@@ -1419,13 +1433,13 @@ double ExtendedDefaultPolicy::DetermineMultiplier()
if (m_ReturnsStructByValue)
{
// For structs-passed-by-value we might avoid expensive copy operations if we inline.
- multiplier += 1.5;
+ multiplier += 2.0;
JITDUMP("\nInline candidate returns a struct by value. Multiplier increased to %g.", multiplier);
}
else if (m_ArgIsStructByValue > 0)
{
// Same here
- multiplier += 1.5;
+ multiplier += 2.0;
JITDUMP("\n%d arguments are structs passed by value. Multiplier increased to %g.", m_ArgIsStructByValue,
multiplier);
}
@@ -1451,13 +1465,13 @@ double ExtendedDefaultPolicy::DetermineMultiplier()
if (m_ArgFeedsRangeCheck > 0)
{
- multiplier += 0.5;
+ multiplier += 1.0;
JITDUMP("\nInline candidate has arg that feeds range check. Multiplier increased to %g.", multiplier);
}
if (m_NonGenericCallsGeneric)
{
- multiplier += 1.5;
+ multiplier += 2.0;
JITDUMP("\nInline candidate is generic and caller is not. Multiplier increased to %g.", multiplier);
}
@@ -1507,7 +1521,7 @@ double ExtendedDefaultPolicy::DetermineMultiplier()
if (m_Intrinsic > 0)
{
// In most cases such intrinsics are lowered as single CPU instructions
- multiplier += 1.5;
+ multiplier += 1.0 + m_Intrinsic * 0.3;
JITDUMP("\nInline has %d intrinsics. Multiplier increased to %g.", m_Intrinsic, multiplier);
}
@@ -1636,6 +1650,28 @@ double ExtendedDefaultPolicy::DetermineMultiplier()
break;
}
+ if (m_FoldableSwitch > 0)
+ {
+ multiplier += 6.0;
+ JITDUMP("\nInline candidate has %d foldable switches. Multiplier increased to %g.", m_FoldableSwitch,
+ multiplier);
+ }
+ else if (m_Switch > 0)
+ {
+ if (m_IsPrejitRoot)
+ {
+ // Assume the switches can be foldable in PrejitRoot mode.
+ multiplier += 6.0;
+ JITDUMP("\nPrejit root candidate has %d switches. Multiplier increased to %g.", m_Switch, multiplier);
+ }
+ else
+ {
+ // TODO: Investigate cases where it makes sense to inline non-foldable switches
+ multiplier = 0.0;
+ JITDUMP("\nInline candidate has %d switches. Multiplier limited to %g.", m_Switch, multiplier);
+ }
+ }
+
if (m_HasProfile)
{
// There are cases when Profile Data can be misleading or polluted:
@@ -1657,14 +1693,16 @@ double ExtendedDefaultPolicy::DetermineMultiplier()
{
multiplier *= min(m_ProfileFrequency, 1.0) * profileScale;
}
- JITDUMP("\nCallsite has profile data: %g.", m_ProfileFrequency);
+ JITDUMP("\nCallsite has profile data: %g. Multiplier limited to %g.", m_ProfileFrequency, multiplier);
}
- if (m_RootCompiler->lvaTableCnt > ((unsigned)(JitConfig.JitMaxLocalsToTrack() / 4)))
+ // Slow down if there are already too many locals
+ if (m_RootCompiler->lvaTableCnt > 64)
{
- // Slow down inlining if we already have to many locals in the rootCompiler.
- multiplier /= ((double)m_RootCompiler->lvaTableCnt / ((double)JitConfig.JitMaxLocalsToTrack() / 4.0));
- JITDUMP("\nCaller %d locals. Multiplier decreased to %g.", m_RootCompiler->lvaTableCnt, multiplier);
+ // E.g. MaxLocalsToTrack = 1024 and lvaTableCnt = 512 -> multiplier *= 0.5;
+ const double lclFullness = min(1.0, (double)m_RootCompiler->lvaTableCnt / JitConfig.JitMaxLocalsToTrack());
+ multiplier *= (1.0 - lclFullness);
+ JITDUMP("\nCaller has %d locals. Multiplier decreased to %g.", m_RootCompiler->lvaTableCnt, multiplier);
}
if (m_BackwardJump)
@@ -1738,6 +1776,8 @@ void ExtendedDefaultPolicy::OnDumpXml(FILE* file, unsigned indent) const
XATTR_I4(m_FoldableExpr)
XATTR_I4(m_FoldableExprUn)
XATTR_I4(m_FoldableBranch)
+ XATTR_I4(m_FoldableSwitch)
+ XATTR_I4(m_Switch)
XATTR_I4(m_DivByCns)
XATTR_B(m_ReturnsStructByValue)
XATTR_B(m_IsFromValueClass)
@@ -1927,7 +1967,6 @@ void DiscretionaryPolicy::NoteDouble(InlineObservation obs, double value)
{
assert(obs == InlineObservation::CALLSITE_PROFILE_FREQUENCY);
assert(value >= 0.0);
- assert(m_ProfileFrequency == 0.0);
m_ProfileFrequency = value;
}
diff --git a/src/coreclr/jit/inlinepolicy.h b/src/coreclr/jit/inlinepolicy.h
index 7d0d83bd736..466e17fe0e1 100644
--- a/src/coreclr/jit/inlinepolicy.h
+++ b/src/coreclr/jit/inlinepolicy.h
@@ -204,6 +204,8 @@ public:
, m_FoldableExpr(0)
, m_FoldableExprUn(0)
, m_FoldableBranch(0)
+ , m_FoldableSwitch(0)
+ , m_Switch(0)
, m_DivByCns(0)
, m_ReturnsStructByValue(false)
, m_IsFromValueClass(false)
@@ -252,6 +254,8 @@ protected:
unsigned m_FoldableExpr;
unsigned m_FoldableExprUn;
unsigned m_FoldableBranch;
+ unsigned m_FoldableSwitch;
+ unsigned m_Switch;
unsigned m_DivByCns;
bool m_ReturnsStructByValue : 1;
bool m_IsFromValueClass : 1;
diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h
index 3220193c662..cd685c2cc10 100644
--- a/src/coreclr/jit/jitconfigvalues.h
+++ b/src/coreclr/jit/jitconfigvalues.h
@@ -463,7 +463,8 @@ CONFIG_STRING(JitInlineReplayFile, W("JitInlineReplayFile"))
// Extended version of DefaultPolicy that includes a more precise IL scan,
// relies on PGO if it exists and generally is more aggressive.
CONFIG_INTEGER(JitExtDefaultPolicy, W("JitExtDefaultPolicy"), 1)
-CONFIG_INTEGER(JitExtDefaultPolicyMaxIL, W("JitExtDefaultPolicyMaxIL"), 0x64)
+CONFIG_INTEGER(JitExtDefaultPolicyMaxIL, W("JitExtDefaultPolicyMaxIL"), 0x80)
+CONFIG_INTEGER(JitExtDefaultPolicyMaxILProf, W("JitExtDefaultPolicyMaxILProf"), 0x400)
CONFIG_INTEGER(JitExtDefaultPolicyMaxBB, W("JitExtDefaultPolicyMaxBB"), 7)
// Inliner uses the following formula for PGO-driven decisions:
diff --git a/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/DebugViewWriter.cs b/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/DebugViewWriter.cs
index af967733a5a..2f2ecf4b384 100644
--- a/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/DebugViewWriter.cs
+++ b/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/DebugViewWriter.cs
@@ -7,6 +7,7 @@ using System.Dynamic.Utils;
using System.Globalization;
using System.IO;
using System.Reflection;
+using System.Runtime.CompilerServices;
namespace System.Linq.Expressions
{
@@ -168,6 +169,7 @@ namespace System.Linq.Expressions
Out(Flow.None, s, after);
}
+ [MethodImpl(MethodImplOptions.NoInlining)]
private void Out(Flow before, string s, Flow after)
{
switch (GetFlow(before))