Skip to content

Loop cloning misses definitions for fields of promoted structs #61040

@SingleAccretion

Description

@SingleAccretion

Reproduction:

using System.Runtime.CompilerServices;

Problem(default);

[MethodImpl(MethodImplOptions.NoInlining)]
static void JitUse<T>(T arg) { }

[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
static void Problem(ArrayWrapper a)
{
    a = GetArrayLong();

    JitUse(a);
    JitUse(a);

    for (int i = 0; i < 10000; i++)
    {
        a = GetArray();
        JitUse(a.Array[i]);
    }
}

[MethodImpl(MethodImplOptions.NoInlining)]
static ArrayWrapper GetArray() => new() { Array = new int[0] };

[MethodImpl(MethodImplOptions.NoInlining)]
static ArrayWrapper GetArrayLong() => new() { Array = new int[10000] };

struct ArrayWrapper
{
    public int[] Array;
}

We expect to get an IndexOutOfRangeException here, but instead get an AV.

The cause is that loop cloning thinks that the promoted struct's field is invariant in the loop and deletes the bounds check. The reason it thinks it is invariant is because this is a special case in block morphing, where we leave an independently promoted struct alone, and it looks like optIsVarAssgCB does not account for this. I thus conjecture this will also reproduce for the multi-reg assignment form.

Found while experimenting with morphing of the "one field" case into ASG(LCL_VAR(promoted field), BITCAST(field type(CALL))).

@dotnet/jit-contrib

Metadata

Metadata

Assignees

Labels

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

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions