Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Unroll StringBuilder.Append for const string #85894

Merged
merged 5 commits into from
May 9, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
14 changes: 14 additions & 0 deletions src/coreclr/jit/fgbasic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,20 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed
break;
}

case NI_System_SpanHelpers_SequenceEqual:
case NI_System_Buffer_Memmove:
{
if (FgStack::IsConstArgument(pushedStack.Top(), impInlineInfo))
{
// Constant (at its call-site) argument feeds the Memmove/Memcmp length argument.
// We most likely will be able to unroll it.
// It is important to only raise this hint for constant arguments, if it's just a
// constant in the inlinee itself then we don't need to inline it for unrolling.
compInlineResult->Note(InlineObservation::CALLSITE_UNROLLABLE_MEMOP);
}
break;
}

case NI_System_Span_get_Item:
case NI_System_ReadOnlySpan_get_Item:
{
Expand Down
8 changes: 6 additions & 2 deletions src/coreclr/jit/importercalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3795,8 +3795,12 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
case NI_System_SpanHelpers_SequenceEqual:
case NI_System_Buffer_Memmove:
{
// We'll try to unroll this in lower for constant input.
isSpecial = true;
if (sig->sigInst.methInstCount == 0)
{
// We'll try to unroll this in lower for constant input.
isSpecial = true;
}
// The generic version is also marked as [Intrinsic] just as a hint for the inliner
break;
}

Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/inline.def
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ INLINE_OBSERVATION(FOLDABLE_EXPR, int, "foldable binary expressio
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(UNROLLABLE_MEMOP, int, "unrollable memmove/memcmp", 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)
Expand Down
14 changes: 13 additions & 1 deletion src/coreclr/jit/inlinepolicy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1317,6 +1317,10 @@ void ExtendedDefaultPolicy::NoteBool(InlineObservation obs, bool value)
m_FoldableSwitch++;
break;

case InlineObservation::CALLSITE_UNROLLABLE_MEMOP:
m_UnrollableMemop++;
break;

case InlineObservation::CALLEE_HAS_SWITCH:
m_Switch++;
break;
Expand Down Expand Up @@ -1409,7 +1413,7 @@ void ExtendedDefaultPolicy::NoteInt(InlineObservation obs, int value)
// in prejit-root mode.
bbLimit += 5 + m_Switch * 10;
}
bbLimit += m_FoldableBranch + m_FoldableSwitch * 10;
bbLimit += m_FoldableBranch + m_FoldableSwitch * 10 + m_UnrollableMemop * 2;

if ((unsigned)value > bbLimit)
{
Expand Down Expand Up @@ -1715,6 +1719,13 @@ double ExtendedDefaultPolicy::DetermineMultiplier()
break;
}

if (m_UnrollableMemop > 0)
{
multiplier += m_UnrollableMemop;
JITDUMP("\nInline candidate has %d unrollable memory operations. Multiplier increased to %g.",
m_UnrollableMemop, multiplier);
}

if (m_FoldableSwitch > 0)
{
multiplier += 6.0;
Expand Down Expand Up @@ -1841,6 +1852,7 @@ void ExtendedDefaultPolicy::OnDumpXml(FILE* file, unsigned indent) const
XATTR_I4(m_FoldableExprUn)
XATTR_I4(m_FoldableBranch)
XATTR_I4(m_FoldableSwitch)
XATTR_I4(m_UnrollableMemop)
XATTR_I4(m_Switch)
XATTR_I4(m_DivByCns)
XATTR_B(m_ReturnsStructByValue)
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/jit/inlinepolicy.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ class ExtendedDefaultPolicy : public DefaultPolicy
, m_FoldableExprUn(0)
, m_FoldableBranch(0)
, m_FoldableSwitch(0)
, m_UnrollableMemop(0)
, m_Switch(0)
, m_DivByCns(0)
, m_ReturnsStructByValue(false)
Expand Down Expand Up @@ -268,6 +269,7 @@ class ExtendedDefaultPolicy : public DefaultPolicy
unsigned m_FoldableExprUn;
unsigned m_FoldableBranch;
unsigned m_FoldableSwitch;
unsigned m_UnrollableMemop;
unsigned m_Switch;
unsigned m_DivByCns;
bool m_ReturnsStructByValue : 1;
Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.Private.CoreLib/src/System/Buffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ internal static unsafe void _ZeroMemory(ref byte b, nuint byteLength)

#if !MONO // Mono BulkMoveWithWriteBarrier is in terms of elements (not bytes) and takes a type handle.

[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe void Memmove<T>(ref T destination, ref T source, nuint elementCount)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -728,9 +728,9 @@ public StringBuilder Append(char[]? value, int startIndex, int charCount)
/// <param name="value">The string to append.</param>
public StringBuilder Append(string? value)
{
if (value is not null)
if (value != null)
yesmey marked this conversation as resolved.
Show resolved Hide resolved
{
Append(valueCount: value.Length, value: ref value.GetRawStringData());
Append(ref value.GetRawStringData(), value.Length);
}

return this;
Expand Down Expand Up @@ -2107,7 +2107,7 @@ public unsafe StringBuilder Append(char* value, int valueCount)
/// <summary>Appends a specified number of chars starting from the specified reference.</summary>
private void Append(ref char value, int valueCount)
{
Debug.Assert(valueCount >= 0, $"Invalid length; should have been validated by caller.");
Debug.Assert(valueCount >= 0, "Invalid length; should have been validated by caller.");
if (valueCount != 0)
{
char[] chunkChars = m_ChunkChars;
Expand Down