Skip to content

JIT does not hoist bound check outside a loop #69194

@hez2010

Description

@hez2010

Repro (needs features/ref-fields branch of roslyn to compile):

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

void Foo(ref Color color, uint index)
{
    for (var i = 0; i < 100; i++)
    {
        color.Raw[index] = 3;
    }
}

var color = new Color { R = 1, G = 2, B = 3, A = 4 };
Foo(ref color, 1);
Console.WriteLine(color.G);

[StructLayout(LayoutKind.Explicit)]
struct Color
{
    [FieldOffset(0)] public byte R;
    [FieldOffset(1)] public byte G;
    [FieldOffset(2)] public byte B;
    [FieldOffset(3)] public byte A;

    [FieldOffset(0)] public int Rgba;

    public ColorView<byte> Raw => new(ref this);
    public ColorView<short> SRaw => new(ref this);
}

ref struct ColorView<T> where T : unmanaged
{
    private ref Color color;
    public ColorView(ref Color color)
    {
        this.color = ref color;
    }
    private static ref T Throw() => throw new IndexOutOfRangeException();
    
    public ref T this[uint index]
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        get
        {
            unsafe
            {
                return ref sizeof(T) * index >= sizeof(Color) ? 
                    ref Throw() : 
                    ref Unsafe.Add(ref Unsafe.AsRef<T>(Unsafe.AsPointer(ref color)), index);
            }
        }
    }
}

Codegen for Foo:

G_M17293_IG01:
       sub      rsp, 40
                                                ;; size=4 bbWeight=0    PerfScore 0.00
G_M17293_IG02:
       xor      eax, eax
                                                ;; size=2 bbWeight=1    PerfScore 0.25
G_M17293_IG03:
       cmp      edx, 4
       jae      SHORT G_M17293_IG05
       mov      r8d, edx
       mov      r9, rcx
       add      r8, r9
       mov      byte  ptr [r8], 3
       inc      eax
       cmp      eax, 100
       jl       SHORT G_M17293_IG03
                                                ;; size=25 bbWeight=4    PerfScore 18.00
G_M17293_IG04:
       add      rsp, 40
       ret
                                                ;; size=5 bbWeight=1    PerfScore 1.25
G_M17293_IG05:
       call     [ColorView`1:Throw():byref]
       int3
                                                ;; size=7 bbWeight=0    PerfScore 0.00

I expect to see the bound check to be hosited outside the loop.

category:cq
theme:bounds-checks
skill-level:expert
cost:medium
impact:medium

Metadata

Metadata

Assignees

No one assigned

    Labels

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

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions