Skip to content

Commit

Permalink
[release/9.0]: ARM64-SVE: Allow SVE ops to re-use the same registers (#…
Browse files Browse the repository at this point in the history
…107818)

* ARM64-SVE: Allow SVE ops to re-use the same registers (#107084)

* ARM64-SVE: Allow SVE ops to re-use the same registers

* Add Sve.IsSupported

* restore an assert

* better asserts

* resolve merge conflicts

---------

Co-authored-by: Alan Hayward <a74nh@users.noreply.github.com>
Co-authored-by: Jeff Schwartz <jeffschw@microsoft.com>
  • Loading branch information
3 people committed Sep 16, 2024
1 parent 46cfb74 commit e256321
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 14 deletions.
21 changes: 7 additions & 14 deletions src/coreclr/jit/hwintrinsiccodegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1141,27 +1141,20 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
{
if (HWIntrinsicInfo::IsExplicitMaskedOperation(intrin.id))
{
if (targetReg != op2Reg)
{
assert(targetReg != op1Reg);
assert(targetReg != op3Reg);
assert((targetReg == op2Reg) || ((targetReg != op1Reg) && (targetReg != op3Reg)));

GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op2Reg,
/* canSkip */ true);
}
GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op2Reg,
/* canSkip */ true);

GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op1Reg, op3Reg, opt);
}
else
{
if (targetReg != op1Reg)
{
assert(targetReg != op2Reg);
assert(targetReg != op3Reg);
assert((targetReg == op1Reg) || ((targetReg != op2Reg) && (targetReg != op3Reg)));

GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg,
/* canSkip */ true);

GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg,
/* canSkip */ true);
}
GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op2Reg, op3Reg, opt);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,15 @@ namespace JIT.HardwareIntrinsics.Arm
// Validates passing a local works, using Unsafe.Read
test.RunLclVarScenario_UnsafeRead();

// Validates using the same local multiple times works, using Unsafe.Read
test.RunSameLclVarScenario_UnsafeRead();

// Validates passing an instance member of a class works
test.RunClassFldScenario();

// Validates using the same instance member of a class multiple times works
test.RunSameClassFldScenario();

// Validates passing the field of a local struct works
test.RunStructLclFldScenario();

Expand Down Expand Up @@ -250,6 +256,19 @@ namespace JIT.HardwareIntrinsics.Arm
ValidateResult(op1, op2, _dataTable.outArrayPtr);
}

public void RunSameLclVarScenario_UnsafeRead()
{
TestLibrary.TestFramework.BeginScenario(nameof(RunSameLclVarScenario_UnsafeRead));

var op = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr);
var op1 = op;
var op2 = op;
var result = {Isa}.{Method}(op1, op2);

Unsafe.Write(_dataTable.outArrayPtr, result);
ValidateResult(op1, op2, _dataTable.outArrayPtr);
}

public void RunClassFldScenario()
{
TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
Expand All @@ -260,6 +279,16 @@ namespace JIT.HardwareIntrinsics.Arm
ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr);
}

public void RunSameClassFldScenario()
{
TestLibrary.TestFramework.BeginScenario(nameof(RunSameClassFldScenario));

var result = {Isa}.{Method}(_fld1, _fld1);

Unsafe.Write(_dataTable.outArrayPtr, result);
ValidateResult(_fld1, _fld1, _dataTable.outArrayPtr);
}

public void RunStructLclFldScenario()
{
TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,15 @@ namespace JIT.HardwareIntrinsics.Arm
// Validates passing a local works, using Unsafe.Read
test.RunLclVarScenario_UnsafeRead();

// Validates using the same local multiple times works, using Unsafe.Read
test.RunSameLclVarScenario_UnsafeRead();

// Validates passing an instance member of a class works
test.RunClassFldScenario();

// Validates using the same instance member of a class multiple times works
test.RunSameClassFldScenario();

// Validates passing the field of a local struct works
test.RunStructLclFldScenario();

Expand Down Expand Up @@ -277,6 +283,20 @@ namespace JIT.HardwareIntrinsics.Arm
ValidateResult(op1, op2, op3, _dataTable.outArrayPtr);
}

public void RunSameLclVarScenario_UnsafeRead()
{
TestLibrary.TestFramework.BeginScenario(nameof(RunSameLclVarScenario_UnsafeRead));

var op = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr);
var op1 = op;
var op2 = op;
var op3 = op;
var result = {Isa}.{Method}(op1, op2, op3);

Unsafe.Write(_dataTable.outArrayPtr, result);
ValidateResult(op1, op2, op3, _dataTable.outArrayPtr);
}

public void RunClassFldScenario()
{
TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
Expand All @@ -287,6 +307,16 @@ namespace JIT.HardwareIntrinsics.Arm
ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr);
}

public void RunSameClassFldScenario()
{
TestLibrary.TestFramework.BeginScenario(nameof(RunSameClassFldScenario));

var result = {Isa}.{Method}(_fld1, _fld1, _fld1);

Unsafe.Write(_dataTable.outArrayPtr, result);
ValidateResult(_fld1, _fld1, _fld1, _dataTable.outArrayPtr);
}

public void RunStructLclFldScenario()
{
TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
Expand Down
50 changes: 50 additions & 0 deletions src/tests/JIT/Regression/JitBlue/Runtime_106866/Runtime_106866.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Xunit;
using System.Runtime.CompilerServices;

// Generated by Fuzzlyn v2.3 on 2024-08-23 10:04:52
// Run on Arm64 Windows
// Seed: 12028719405363964033-vectort,vector64,vector128,armsve
// Reduced from 60.4 KiB to 0.7 KiB in 00:00:33
// Hits JIT assert in Release:
// Assertion failed '(targetReg == op1Reg) || (targetReg != op3Reg)' in 'S0:M3():this' during 'Generate code' (IL size 57; hash 0x4541fc9f; FullOpts)
//
// File: C:\dev\dotnet\runtime2\src\coreclr\jit\hwintrinsiccodegenarm64.cpp Line: 1128
//
using System;
using System.Numerics;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;

public struct S0
{
public bool F0;
public Vector<sbyte> F2;
public void M3()
{
if (Sve.IsSupported)
{
var vr0 = this.F2;
var vr1 = this.F2;
var vr2 = this.F2;
this.F2 = Sve.Splice(vr0, vr1, vr2);
Consume(this.F0);
}
}

[MethodImpl(MethodImplOptions.NoInlining)]
static void Consume<T>(T val)
{
}
}

public class Runtime_106866
{
[Fact]
public static void TestEntryPoint()
{
new S0().M3();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Optimize>True</Optimize>
<NoWarn>$(NoWarn),SYSLIB5003</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
</Project>

0 comments on commit e256321

Please sign in to comment.