Optimize ToString() for byte, ushort, uint and ulong by EgorBo · Pull Request #27056 · dotnet/coreclr (original) (raw)

I do not understand what you mean. FormatUInt32 does not just forward to another method.

I wasn't referring to FormatUInt32. I was referring to byte.ToString() which itself just forwards to FormatUInt32.

Based on the code from the original post:

static string Test(byte b) => b.ToString();

Compiles down to:

G_M64984_IG01: sub rsp, 56 xor rax, rax mov qword ptr [rsp+28H], rax mov dword ptr [rsp+40H], ecx G_M64984_IG02: movzx rcx, byte ptr [rsp+40H] xor rdx, rdx xor r8d, r8d lea rax, bword ptr [rsp+28H] mov bword ptr [rax], rdx mov dword ptr [rax+8], r8d lea rdx, bword ptr [rsp+28H] xor r8, r8 call System.Number:FormatUInt32(int,struct,ref):ref nop
G_M64984_IG03: add rsp, 56 ret
; Total bytes of code: 56

So, the JIT is seeing that byte.ToString() is small and therefore just inlines that (which is the forward to FormatUInt32).

However, it may be beneficial to keep the call to byte.ToString() and have its call to FormatUInt32 be inlined instead. Having FormatUInt32 inlined here would, worst case, produce similar code to what we already produced for FormatUInt32; but would likely give some opportunities for dead code elimination and other optimizations due to the additional constant args that are used in the call to FormatUInt32.

This is going based on the premise that the byte.ToString() => Number.FormatUInt32(m_value, null, null) pattern is common throughout the framework and methods like Number.FormatUInt32 are generally the thing that has all the logic and the checks for "fast path" vs "slow path". So, I believe this would allow code targeting the "fast path" (due to the constants being passed in) to just avoid those fast vs slow path checks entirely.