Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ partial interface IRuntimeTypeSystem : IContract
// define FEATURE_HFA). Mirrors MethodTable::GetHFAType in
// src/coreclr/vm/class.cpp.
public virtual bool TryGetHFAElementSize(ITypeHandle typeHandle, out int elementSize);
// Returns the intrinsic SIMD vector element size derived from type metadata: 16 for
// Vector128<T>, 8 for Vector64<T>, and 8 or 16 for System.Numerics.Vector<T> (based on its
// instance size); 0 for non-vector types and for Vector256<T>/Vector512<T> (never HVA
// elements). Unlike TryGetHFAElementSize this is not gated on FEATURE_HFA, so it is valid on
// wasm, where ArgIterator uses it to 16-byte align v128 args.
public virtual int GetVectorElementSize(ITypeHandle typeHandle);
Comment thread
lewing marked this conversation as resolved.
Outdated
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
public virtual bool RequiresAlign8(ITypeHandle typeHandle);
// Returns the cached SystemV AMD64 eightbyte register-passing classification for a value type
Expand Down Expand Up @@ -806,7 +812,7 @@ static class RuntimeTypeSystem_1_Helpers
// if targetArch is ARM: return (true, th.Flags.RequiresAlign8 ? 8 : 4)
// mt = th
// loop (bounded depth):
// if (elem = GetVectorHFAElementSize(mt)): return (true, elem)
// if (elem = GetVectorElementSize(mt)): return (true, elem)
// field = first non-static field of mt
// if field is null: return false
// switch field.ElementType:
Expand All @@ -815,18 +821,22 @@ static class RuntimeTypeSystem_1_Helpers
// ValueType: mt = GetFieldDescApproxTypeHandle(field); continue
// default: return false
//
// GetVectorHFAElementSize(mt): // detects HVA shapes
// GetVectorElementSize(mt): // detects HVA / SIMD vector shapes
// if !mt.Flags.IsIntrinsicType: return 0
// (ns, name) = typedef name+namespace via EcmaMetadata
// elem = match on (ns, name):
// "System.Numerics", "Vector`1": NumInstanceFieldBytes (8 or 16, else 0)
// "System.Runtime.Intrinsics", "Vector128`1": 16
// "System.Runtime.Intrinsics", "Vector64`1": 8
// _: return 0
// _: return 0 // incl. Vector256/512
// if !CorIsNumericalType(GetInstantiation(mt)[0]): return 0
// return elem
public bool TryGetHFAElementSize(ITypeHandle typeHandle, out int elementSize) { ... }

// Metadata-derived intrinsic vector element size, without FEATURE_HFA gating so it is usable
// on wasm (see GetVectorElementSize pseudocode above).
public int GetVectorElementSize(ITypeHandle typeHandle) { ... }

public bool RequiresAlign8(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.RequiresAlign8;

public bool IsCanonicalMethodTable(ITypeHandle typeHandle)
Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/tools/Common/CallingConvention/ITypeHandle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ internal interface ITypeHandle
// x86 - trivial pointer-sized struct check for register passing
bool IsTrivialPointerSizedStruct();

// LoongArch64/Wasm alignment
// LoongArch64/Wasm alignment. On wasm this also reports 16 for Vector128<T> / 128-bit
// Vector<T> (whose InstanceFieldAlignment under-reports as 8) so the Wasm32 ArgIterator
// 16-aligns v128 arguments to match the runtime and interpreter.
int GetFieldAlignment();

private static readonly int[] s_elemSizes = new int[]
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/tools/Common/JitInterface/WasmLowering.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public static TypeDesc LowerToAbiType(TypeDesc type)
/// and non-primitive instantiations (e.g. the shared <c>__Canon</c> form) are not ABI
/// primitives and continue to use the generic struct ABI.
/// </summary>
private static bool IsWasmV128Type(TypeDesc type)
internal static bool IsWasmV128Type(TypeDesc type)
{
if (!type.IsIntrinsic ||
type.Instantiation.Length != 1 ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,15 @@ public bool IsTrivialPointerSizedStruct()

public int GetFieldAlignment()
{
// Vector128<T> / 128-bit Vector<T> arguments must be 16-byte aligned on wasm to match the
Comment thread
lewing marked this conversation as resolved.
Outdated
// interpreter and runtime ArgIterator (getClassAlignmentRequirement). The crossgen type
// system reports their InstanceFieldAlignment as 8 (pointer-sized), so pin the wasm v128
// SIMD types to 16 here; the ArgIterator wasm case is the sole caller of this method.
if (WasmLowering.IsWasmV128Type(_type))
{
return 16;
}

return ((DefType)_type).InstanceFieldAlignment.AsInt;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,13 @@ public interface IRuntimeTypeSystem : IContract
// define FEATURE_HFA). Mirrors MethodTable::GetHFAType in
// src/coreclr/vm/class.cpp.
bool TryGetHFAElementSize(ITypeHandle typeHandle, out int elementSize) => throw new NotImplementedException();
// Returns the intrinsic SIMD vector element size derived from type metadata: 16 for
// Vector128<T>, 8 for Vector64<T>, and 8 or 16 for System.Numerics.Vector<T> (based on its
// instance size). Returns 0 for non-vector types, and also for Vector256<T>/Vector512<T>
// (never HVA elements; no caller needs their size). Unlike TryGetHFAElementSize this is not
// gated on FEATURE_HFA, so it is valid on wasm, where ArgIterator uses it to give v128
// (16-byte) arguments the stack alignment the runtime and interpreter require.
int GetVectorElementSize(ITypeHandle typeHandle) => throw new NotImplementedException();
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
bool RequiresAlign8(ITypeHandle typeHandle) => throw new NotImplementedException();
// Returns the cached SystemV AMD64 eightbyte register-passing classification for a value type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,17 @@ public bool IsTrivialPointerSizedStruct()
}
}

// Only used by ArgIterator on WASM32 for stack alignment of value types.
// Only used by ArgIterator on WASM32 for stack alignment of value types. Vector128<T> /
// 128-bit Vector<T> must be 16-byte aligned to match the runtime and interpreter ArgIterator;
// the crossgen type system under-reports their field alignment as 8, so report 16 for the wasm
// v128 SIMD types here. Non-v128 value types are not yet reconstructed by the cDAC reader.
public int GetFieldAlignment()
{
if (_typeHandle is not null && Rts.GetVectorElementSize(_typeHandle) == 16)
{
return 16;
}

throw new NotImplementedException("Field alignment is not yet implemented.");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,7 @@ public bool TryGetHFAElementSize(ITypeHandle typeHandle, out int elementSize)
ITypeHandle current = typeHandle;
for (int depth = 0; depth < 16; depth++)
{
int vectorElem = GetVectorHFAElementSize(current);
int vectorElem = GetVectorElementSize(current);
if (vectorElem != 0)
{
elementSize = vectorElem;
Expand Down Expand Up @@ -735,9 +735,13 @@ public bool TryGetHFAElementSize(ITypeHandle typeHandle, out int elementSize)
return false;
}

// Mirrors MethodTable::GetVectorHFA in src/coreclr/vm/class.cpp. Any
// metadata decode failure returns 0 (treated as "not an HVA").
private int GetVectorHFAElementSize(ITypeHandle typeHandle)
// Metadata-derived intrinsic vector element size, independent of FEATURE_HFA gating so it is
// usable on wasm (where ArgIterator uses it to 16-byte align v128 arguments) as well as by the
// HFA/HVA classification below. Returns 8 for Vector64<T> and 8-byte Vector<T>, 16 for
// Vector128<T> and 16-byte Vector<T>, and 0 for anything else. Vector256<T>/Vector512<T> return
// 0: they are never HVA elements and no caller needs their size. Mirrors
// MethodTable::GetVectorHFA in src/coreclr/vm/class.cpp. Any metadata decode failure returns 0.
public int GetVectorElementSize(ITypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable() || !_methodTables[typeHandle.Address].Flags.IsIntrinsicType)
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ private struct NestedDouble4 { public Double2 First; public Double2 Second; }

// --- HVA shapes (intrinsic Vector types). On non-FEATURE_HFA targets
// these go through the regular struct path; on ARM64 they hit the
// GetVectorHFAElementSize TypeDef-name match (Vector64/128 in
// GetVectorElementSize TypeDef-name match (Vector64/128 in
// System.Runtime.Intrinsics, Vector<T> in System.Numerics). ---
[MethodImpl(MethodImplOptions.NoInlining)] private static void Vec64FloatArg(Vector64<float> v) { AllocBurst(); GC.KeepAlive((object)v.GetElement(0)); }
[MethodImpl(MethodImplOptions.NoInlining)] private static void Vec128FloatArg(Vector128<float> v) { AllocBurst(); GC.KeepAlive((object)v.GetElement(0)); }
Expand Down
Loading