Skip to content

Unsafe.As breaks callvirt after inlining in .NET 8 RC2 #93650

Closed
@pentp

Description

@pentp

Description

If a call to Unsafe.As<A, B>() and another call that uses the result (e.g., ToString()) are inlined by JIT, it results in bad codegen. If inlined manually, codegen is correct.

Reproduction Steps

Bad codegen sample: https://godbolt.org/z/YEoYM7xY5

Minimal repro:

using System.Runtime.CompilerServices;
using System.Text;

internal static class Program
{
    static void Main()
    {
        var sb = new Holder();
        while (true)
        {
            var s = Bind(ref sb);
            if (s.Length != 0)
            {
                Console.WriteLine("StringBuilder.ToString() returned: " + s);
                return;
            }
        }
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    public static string Bind(ref Holder parameters) => GetString(parameters.GetBuilder());

    public static string GetString(StringBuilder sb) => sb.ToString();
}

internal struct Holder
{
    internal StringBuilder.AppendInterpolatedStringHandler _h;
    public Holder() => _h = new(0, 0, new());

    internal StringBuilder GetBuilder() => Unsafe.As<StringBuilder.AppendInterpolatedStringHandler, StringBuilder>(ref _h);
}

Expected behavior

StringBuilder:ToString() is called (asm listing after manually inlining GetString):

; Assembly listing for method Program:Bind(byref):System.String (Tier1)
; Emitting BLENDED_CODE for X64 with AVX - Windows
; Tier1 code
; optimized code
; rsp based frame
; partially interruptible
; 0 inlinees with PGO data; 1 single block inlinees; 0 inlinees without PGO data

G_M000_IG01:                ;; offset=0x0000
       sub      rsp, 40

G_M000_IG02:                ;; offset=0x0004
       mov      rcx, gword ptr [rcx]
       cmp      dword ptr [rcx], ecx
       call     [System.Text.StringBuilder:ToString():System.String:this]
       nop

G_M000_IG03:                ;; offset=0x0010
       add      rsp, 40
       ret

Actual behavior

Object:ToString() is inlined instead:

; Assembly listing for method Program:Bind(byref):System.String (Tier1)
; Emitting BLENDED_CODE for X64 with AVX - Windows
; Tier1 code
; optimized code
; rsp based frame
; partially interruptible
; No PGO data
; 1 inlinees with PGO data; 3 single block inlinees; 0 inlinees without PGO data

G_M000_IG01:                ;; offset=0x0000
       sub      rsp, 40

G_M000_IG02:                ;; offset=0x0004
       mov      rcx, gword ptr [rcx]
       cmp      byte  ptr [rcx], cl
       call     System.Object:GetType():System.Type:this
       mov      rcx, rax
       mov      edx, 1
       call     [System.RuntimeType:GetCachedName(int):System.String:this]
       nop

G_M000_IG03:                ;; offset=0x001D
       add      rsp, 40
       ret

Regression?

This worked correctly in .NET 7

Known Workarounds

No response

Configuration

.NET 8.0.100-rc.2.23502.2, Windows x64

Other information

No response

Metadata

Metadata

Assignees

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions