Skip to content

AggressiveOptimization makes wrong Vector256 optimization in .NET8 RC1 #92328

Closed
@emaame

Description

@emaame

Description

In .NET8 RC1, some Vector256 code ill function with AggressiveOptimization flags in Release build.
I tried some repro condition to work fine (the below numbers refer in repro code).
Please see minimal repro code.

  1. ✅ .NET7 or .NET8 RC1 Debug build ❌ .NET8 RC1 Release build
  2. ✅ remove AggressiveOptimization ❌ enable AggressiveOptimization
  3. ✅ create Vector256 from literal to vecTmp ❌ create Vector256 with runtime value
  4. ✅ use Vector256<int>.Zero ❌ (3-a) vecTmp ^ vecTmp or (3-b) vec0 in this case
  5. ✅ refer vecTmp anywhere ❌ just use vecTmp to create 0 vector

This problem seems to related with using vec ^ vec.
Use Vector256<int>.Zero to 0 vector, other functions look to work fine in my env.

Reproduction Steps

Run this code with .NET8 RC1.

this code simply compare <0,0,0,0,0,0,0,0> and <0,0,0,0,0,0,0,0>, so result should be <-1,-1,-1,-1,-1,-1,-1,-1>

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

// (1) works fine if `MethodImplOptions.AggressiveOptimization` is disabled
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
void Main()
{
    var data = new int[] { 0, 0, 0, 0, 0, 0, 0, 0 };
    var span = data.AsSpan();

    // (2) works fine if replace Random.Shared.Next() to literal
    // var vecTmp = Vector256.Create(0x1234);
    var vecTmp = Vector256.Create(Random.Shared.Next());

    // xor generates 0, however, `vec0` has wrong values after loop.
    // (3-a) works fine if use `Vector256<int>.Zero`
    // var vec0 = Vector256<int>.Zero;
    var vec0 = vecTmp ^ vecTmp;

    for (var elementOffset = 0; elementOffset < span.Length; elementOffset += Vector256<int>.Count)
    {
        var vec = Vector256.LoadUnsafe(ref MemoryMarshal.GetReference(span), (nuint)elementOffset);

        // (3-b) data will be OK if use`Vector256<int>.Zero` directly here
        var vecIsZero = Vector256.Equals<int>(vec, vec0);
        // var vecIsZero = Vector256.Equals<int>(vec, Vector256<int>.Zero);
        vecIsZero.StoreUnsafe(ref MemoryMarshal.GetReference(span), (nuint)elementOffset);
    }

    // (4) works fine if vecTmp is refered
    // Console.WriteLine($"{vecTmp}");

    // expected: True
    // actual  : False
    Console.WriteLine(vec0.Equals(Vector256<int>.Zero));

    // expected: <0, 0, 0, 0, 0, 0, 0, 0>
    // actual: <same random value> ... has random values it might be `vecTmp`
    Console.WriteLine(vec0);

    // expected: <-1, -1, -1, -1, -1, -1, -1, -1>
    // actual  : <0, 0, 0, 0, 0, 0, 0, 0>
    Console.WriteLine(Vector256.Create(data));
}

Main();

Expected behavior

  • vec0 becomes <0, 0, 0, 0, 0, 0, 0, 0>
  • data becomes <-1, -1, -1, -1, -1, -1, -1, -1>

Actual behavior

  • vec0 becomes <same random value>
  • data becomes <0, 0, 0, 0, 0, 0, 0, 0>

vec0 seems to be the same to vecTmp, however if observe vecTmp, result becomes expected values

Regression?

yes.

in .NET 7.0.401 or Debug build, it works fine.
(in .csproj <TargetFramework>net7.0</TargetFramework> or <TargetFramework>net8.0</TargetFramework> changes result)

Known Workarounds

No response

Configuration

dotnet  --info
.NET SDK:
 Version:   8.0.100-rc.1.23455.8
 Commit:    e14caf947f

 OS Name:     Windows
 OS Version:  10.0.19045
 OS Platform: Windows
 RID:         win-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

Relationships

None yet

Development

No branches or pull requests

Issue actions