Skip to content

[ARM64] Incorrect HFA/HVA property calculation #35144

@AntonLapounov

Description

@AntonLapounov

While reviewing changes in dotnet/coreclr#23675, I noticed that the code added to EEClass::CheckForHFA does not handle wrapped Vector64, Vector128, and Vector256 intrinsic types correctly. For instance, it does not distinguish a wrapped Vector64 and a double. Moreover, the elemSize check is skipped for wrapped Vector128 and Vector256 types. As a result, the HFA/HVA property may be calculated incorrectly. For instance (here { } denotes a struct):

  • {{Vector64}, Vector64} is incorrectly treated as non-HVA.
  • {{Vector64}, double} is incorrectly treated as HFA(double).
  • {Vector128, {Vector256}} is incorrectly treated as HVA(simd16).

The code in question:

case ELEMENT_TYPE_VALUETYPE:
{
#ifdef TARGET_ARM64
// hfa/hva types are unique by size, except for Vector64 which we can conveniently
// treat as if it were a double for ABI purposes. However, it only qualifies as
// an HVA if all fields are the same type. This will ensure that we only
// consider it an HVA if all the fields are ELEMENT_TYPE_VALUETYPE (which have been
// determined above to be vectors) of the same size.
MethodTable* pMT;
#if defined(FEATURE_HFA)
pMT = pByValueClassCache[i];
#else
pMT = pFD->LookupApproxFieldTypeHandle().AsMethodTable();
#endif
int thisElemSize = pMT->GetVectorSize();
if (thisElemSize != 0)
{
if (elemSize == 0)
{
elemSize = thisElemSize;
}
else if ((thisElemSize != elemSize) || (hfaType != ELEMENT_TYPE_VALUETYPE))
{
return false;
}
}
else
#endif // TARGET_ARM64
{
#if defined(FEATURE_HFA)
fieldType = pByValueClassCache[i]->GetHFAType();
#else
fieldType = pFD->LookupApproxFieldTypeHandle().AsMethodTable()->GetHFAType();
#endif
}
}
break;

The repro program (set COMPlus_JITDisasm=C::* to see HFA/HVA properties and registers used):

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

#pragma warning disable 0169 // warning CS0169: The field '{0}' is never used
struct WrappedVector64  { Vector64<byte> _; }
struct WrappedVector128 { Vector128<byte> _; }
struct WrappedVector256 { Vector256<byte> _; }

// Incorrectly treated as non-HVA: passed in x0, x1
struct S1 { WrappedVector64 x; Vector64<byte> y; }

// Incorrectly treated as HFA(double): passed in d0, d1
struct S2 { WrappedVector64 x; double y; }

// Incorrectly treated as HVA(simd16): passed in q0, q1, q2
struct S3 { Vector128<byte> x; WrappedVector256 y; }

static class C
{
    [MethodImpl(MethodImplOptions.NoInlining)]
    static void Foo<T>(T x) { }

    static void Main()
    {
        Foo(new S1());
        Foo(new S2());
        Foo(new S3());
    }
}

@CarolEidt @echesakovMSFT @sdmaclea

Metadata

Metadata

Assignees

Labels

arch-arm64area-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