Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,33 @@

using Internal.TypeSystem;

using Debug = System.Diagnostics.Debug;

namespace ILCompiler
{
public partial class CompilerTypeSystemContext
{
private readonly object _structCacheLock = new object();
private readonly Dictionary<int, TypeDesc> _structsBySize = new Dictionary<int, TypeDesc>();
private volatile TypeDesc _cachedEmptyStruct;
private volatile TypeDesc _cachedV128Type;

/// <summary>
/// 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.
/// </summary>
public TypeDesc CachedV128Type => _cachedV128Type;
private volatile TypeDesc _wasmV128Type;

/// <summary>
/// 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.
/// </summary>
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;
}
}

/// <summary>
Expand Down
34 changes: 14 additions & 20 deletions src/coreclr/tools/Common/JitInterface/WasmLowering.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,17 +123,21 @@ private static bool IsWasmV128Type(TypeDesc type)
}

// Vector128<T> is always a 16-byte v128.
if (Internal.TypeSystem.Interop.InteropTypes.IsSystemRuntimeIntrinsicsVector128T(type.Context, type))
{
return true;
}

//
// Vector<T> 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)
Expand Down Expand Up @@ -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}")
};

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@

<ItemGroup>
<ProjectReference Include="../ILCompiler.Reflection.ReadyToRun/ILCompiler.Reflection.ReadyToRun.csproj" />
<!-- Aliased because it redefines the ReadyToRun* constant enums that
ILCompiler.Reflection.ReadyToRun already brings into the global namespace. -->
<ProjectReference Include="../ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj" Aliases="crossgen2" />
<ProjectReference Include="../crossgen2/crossgen2_inbuild.csproj" ReferenceOutputAssembly="false">
<!-- crossgen2 is a CoreCLR artifact, so publish it in the CoreCLR configuration. This keeps it
alongside the other CoreCLR artifacts the test consumes (System.Private.CoreLib, the JITs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,21 +341,7 @@ private List<string> BuildReferencePaths()

paths.Add(Path.Combine(_paths.RuntimePackDir, "*.dll"));

// SPCL lives in the runtime pack native/ dir in full builds (placed by
// externals.csproj BinPlace during libs.pretest). In partial CI builds
// that skip libs.pretest, the runtime pack layout may not exist, but the
// CoreCLR artifacts directory always has SPCL after clr.nativecorelib.
string spcl = Path.Combine(_paths.RuntimePackNativeDir, "System.Private.CoreLib.dll");
if (!File.Exists(spcl))
{
string fallback = Path.Combine(_paths.CoreCLRArtifactsDir, "System.Private.CoreLib.dll");
if (File.Exists(fallback))
{
_output.WriteLine($"[R2RTestRunner] SPCL not found at '{spcl}'; using CoreCLR artifacts fallback '{fallback}'");
spcl = fallback;
}
}

string spcl = _paths.SystemPrivateCoreLibPath;
Assert.True(File.Exists(spcl),
$"System.Private.CoreLib.dll not found at '{spcl}'. " +
$"Searched RuntimePackNativeDir='{_paths.RuntimePackNativeDir}' and " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,30 @@ public string RuntimePackNativeDir
}
}

/// <summary>
/// Path to System.Private.CoreLib.dll. It lives in the runtime pack native/ dir in full builds
/// (placed by externals.csproj BinPlace during libs.pretest), but partial builds that skip
/// libs.pretest only have it in the CoreCLR artifacts directory.
/// </summary>
public string SystemPrivateCoreLibPath
{
get
{
string path = Path.Combine(RuntimePackNativeDir, "System.Private.CoreLib.dll");
if (!File.Exists(path))
{
string fallback = Path.Combine(CoreCLRArtifactsDir, "System.Private.CoreLib.dll");
if (File.Exists(fallback))
{
_output.WriteLine($"[TestPaths] '{path}' not found; falling back to '{fallback}'");
return fallback;
}
}

return path;
}
}

/// <summary>
/// Path to the CoreCLR artifacts directory (contains native bits like corerun).
/// e.g. artifacts/bin/coreclr/linux.x64.Checked/
Expand Down
Loading
Loading