From 3b75072aa7894f8114a31e5021b10d8bfa684ee3 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 27 Jul 2026 10:14:00 -0700 Subject: [PATCH] Make wasm 'V' signature raising deterministic and add a regression test RaiseSignature resolved 'V' to whichever v128 type lowering happened to see first, cached racily from parallel compilation. 'V' is fully determined by the ABI, so resolve a fixed Vector128 instead, and move the 16-byte alignment assert into IsWasmV128Type so it covers every v128 type rather than just the first one cached. The test also covers the Vector alignment fix from #131328; issue #131339 proposed testing Vector128, which was never under-aligned. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../CompilerTypeSystemContext.Wasm.cs | 31 ++- .../tools/Common/JitInterface/WasmLowering.cs | 34 ++- .../ILCompiler.ReadyToRun.Tests.csproj | 3 + .../TestCasesRunner/R2RTestRunner.cs | 16 +- .../TestCasesRunner/TestPaths.cs | 24 ++ .../WasmArgumentLayoutTests.cs | 232 ++++++++++++++++++ .../ILCompiler.ReadyToRun.csproj | 2 + 7 files changed, 291 insertions(+), 51 deletions(-) create mode 100644 src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/WasmArgumentLayoutTests.cs diff --git a/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Wasm.cs b/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Wasm.cs index 3cd7f44f927d69..ef6ff28c2769f6 100644 --- a/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Wasm.cs +++ b/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Wasm.cs @@ -5,8 +5,6 @@ using Internal.TypeSystem; -using Debug = System.Diagnostics.Debug; - namespace ILCompiler { public partial class CompilerTypeSystemContext @@ -14,25 +12,26 @@ public partial class CompilerTypeSystemContext private readonly object _structCacheLock = new object(); private readonly Dictionary _structsBySize = new Dictionary(); private volatile TypeDesc _cachedEmptyStruct; - private volatile TypeDesc _cachedV128Type; - - /// - /// Gets the first SIMD v128 type encountered during lowering, or null if none has been seen. - /// Used by RaiseSignature to produce a roundtrippable type for the 'V' encoding. - /// - public TypeDesc CachedV128Type => _cachedV128Type; + private volatile TypeDesc _wasmV128Type; /// - /// Caches a SIMD v128 type discovered during lowering. Only the first one is retained. + /// Gets the type RaiseSignature produces for the 'V' encoding. All v128 types share the same + /// wasm ABI (16 bytes, 16-byte aligned), so any one of them round-trips 'V' identically; + /// resolving a fixed one keeps raising independent of the order lowering encountered them in. /// - public void CacheV128Type(TypeDesc type) + public TypeDesc WasmV128Type { - // All v128 types share the same wasm ABI (16-byte aligned), so any one round-trips the - // 'V' encoding identically; a smaller alignment would change raised signatures silently. - Debug.Assert(type is DefType defType && defType.InstanceFieldAlignment.AsInt == 16, - $"v128 type {type} must be 16-byte aligned to be interchangeable in raised signatures"); + get + { + TypeDesc type = _wasmV128Type; + if (type is null) + { + var vector128 = (MetadataType)SystemModule.GetType("System.Runtime.Intrinsics"u8, "Vector128`1"u8); + _wasmV128Type = type = vector128.MakeInstantiatedType(GetWellKnownType(WellKnownType.Byte)); + } - _cachedV128Type ??= type; + return type; + } } /// diff --git a/src/coreclr/tools/Common/JitInterface/WasmLowering.cs b/src/coreclr/tools/Common/JitInterface/WasmLowering.cs index 58447a357d4151..ceaaf3289d408a 100644 --- a/src/coreclr/tools/Common/JitInterface/WasmLowering.cs +++ b/src/coreclr/tools/Common/JitInterface/WasmLowering.cs @@ -123,17 +123,21 @@ private static bool IsWasmV128Type(TypeDesc type) } // Vector128 is always a 16-byte v128. - if (Internal.TypeSystem.Interop.InteropTypes.IsSystemRuntimeIntrinsicsVector128T(type.Context, type)) - { - return true; - } - + // // Vector is target-sized, so it is only a v128 when the target's maximum SIMD width is // 128-bit (i.e. it is exactly 16 bytes). This matches the JIT recognizing it as TYP_SIMD16 // via getVectorTByteLength() and keeps the ABI correct should wasm later gain wider vectors. - return type is DefType vectorOfT && - VectorOfTFieldLayoutAlgorithm.IsVectorOfTType(vectorOfT) && - type.GetElementSize().AsInt == 16; + bool isV128 = Internal.TypeSystem.Interop.InteropTypes.IsSystemRuntimeIntrinsicsVector128T(type.Context, type) || + (type is DefType vectorOfT && + VectorOfTFieldLayoutAlgorithm.IsVectorOfTType(vectorOfT) && + type.GetElementSize().AsInt == 16); + + // The wasm ABI gives every v128 a 16-byte aligned argument slot, so a smaller metadata + // alignment would silently misplace it relative to the runtime's own ArgIterator layout. + Debug.Assert(!isV128 || ((DefType)type).InstanceFieldAlignment.AsInt == 16, + $"v128 type {type} must be 16-byte aligned"); + + return isV128; } public static WasmValueType LowerType(TypeDesc type) @@ -219,8 +223,7 @@ public static WasmValueType LowerType(TypeDesc type) 'l' => context.GetWellKnownType(WellKnownType.Int64), 'f' => context.GetWellKnownType(WellKnownType.Single), 'd' => context.GetWellKnownType(WellKnownType.Double), - 'V' => ((CompilerTypeSystemContext)context).CachedV128Type - ?? throw new InvalidOperationException("Encountered 'V' in signature but no v128 type was cached during lowering"), + 'V' => ((CompilerTypeSystemContext)context).WasmV128Type, _ => throw new InvalidOperationException($"Unknown signature char: {c}") }; @@ -402,12 +405,7 @@ public static WasmSignature GetSignature(MethodSignature signature, LoweringFlag } else { - WasmValueType returnWasmType = LowerType(loweredReturnType); - if (returnWasmType == WasmValueType.V128) - { - ((CompilerTypeSystemContext)returnType.Context).CacheV128Type(loweredReturnType); - } - sigBuilder.Append(WasmValueTypeToSigChar(returnWasmType)); + sigBuilder.Append(WasmValueTypeToSigChar(LowerType(loweredReturnType))); } // Reserve space for potential implicit this, stack pointer parameter, portable entrypoint parameter, @@ -484,10 +482,6 @@ public static WasmSignature GetSignature(MethodSignature signature, LoweringFlag else { WasmValueType paramWasmType = LowerType(loweredParamType); - if (paramWasmType == WasmValueType.V128) - { - ((CompilerTypeSystemContext)paramType.Context).CacheV128Type(loweredParamType); - } sigBuilder.Append(WasmValueTypeToSigChar(paramWasmType)); result.Add(paramWasmType); } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/ILCompiler.ReadyToRun.Tests.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/ILCompiler.ReadyToRun.Tests.csproj index e3f0ab6ea0cd15..63688330c5bc2e 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/ILCompiler.ReadyToRun.Tests.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/ILCompiler.ReadyToRun.Tests.csproj @@ -21,6 +21,9 @@ + +