Skip to content

Commit 3be0023

Browse files
Mark the special ABI primitive types as having stable layout (#120802)
This resolves #120367 and was tested using the following program: ```csharp using System.Numerics; using System.Runtime.Intrinsics; TestV(); TestV64(); TestV128(); TestV256(); TestV512(); static ushort[] TestV() { Console.WriteLine(Vector<byte>.Count); ushort[] numbers = new ushort[32]; Vector<ushort>.Zero.CopyTo(numbers); return numbers; } static ushort[] TestV64() { Console.WriteLine(Vector64<byte>.Count); ushort[] numbers = new ushort[4]; Vector64<ushort>.Zero.CopyTo(numbers); return numbers; } static ushort[] TestV128() { Console.WriteLine(Vector128<byte>.Count); ushort[] numbers = new ushort[8]; Vector128<ushort>.Zero.CopyTo(numbers); return numbers; } static ushort[] TestV256() { Console.WriteLine(Vector256<byte>.Count); ushort[] numbers = new ushort[16]; Vector256<ushort>.Zero.CopyTo(numbers); return numbers; } static ushort[] TestV512() { Console.WriteLine(Vector512<byte>.Count); ushort[] numbers = new ushort[32]; Vector512<ushort>.Zero.CopyTo(numbers); return numbers; } ``` ## Results ## Before ``` BEFORE 1: JIT compiled Program:<Main>$(System.String[]) [Tier0, IL size=31, code size=51] 2: JIT compiled Program:<<Main>$>g__TestV|0_0() [Tier0, IL size=34, code size=92] 3: JIT compiled System.Threading.Thread:GetThreadStaticsBase() [Tier0, IL size=18, code size=34] 4: JIT compiled System.Numerics.Vector`1[ushort]:CopyTo(ushort[]) [Tier0, IL size=39, code size=79] 5: JIT compiled Program:<<Main>$>g__TestV64|0_1() [Tier0, IL size=30, code size=85] 6: JIT compiled System.Runtime.Intrinsics.Vector64:CopyTo[ushort](System.Runtime.Intrinsics.Vector64`1[ushort],ushort[]) [Tier0, IL size=34, code size=71] 7: JIT compiled Program:<<Main>$>g__TestV128|0_2() [Tier0, IL size=30, code size=84] 8: JIT compiled Program:<<Main>$>g__TestV256|0_3() [Tier0, IL size=31, code size=84] 9: JIT compiled System.Runtime.Intrinsics.Vector256:CopyTo[ushort](System.Runtime.Intrinsics.Vector256`1[ushort],ushort[]) [Tier0, IL size=34, code size=79] 10: JIT compiled Program:<<Main>$>g__TestV512|0_4() [Tier0, IL size=31, code size=98] 11: JIT compiled System.Runtime.Intrinsics.Vector512:CopyTo[ushort](System.Runtime.Intrinsics.Vector512`1[ushort],ushort[]) [Tier0, IL size=34, code size=83] ``` ## After - .NET 10 ### AVX512 Capable Machine ``` 1: JIT compiled System.Threading.Thread:GetThreadStaticsBase() [Tier0, IL size=18, code size=34] 2: JIT compiled System.Numerics.Vector`1[ushort]:CopyTo(ushort[]) [Tier0, IL size=39, code size=79] 3: JIT compiled System.Runtime.Intrinsics.Vector64:CopyTo[ushort](System.Runtime.Intrinsics.Vector64`1[ushort],ushort[]) [Tier0, IL size=34, code size=71] 4: JIT compiled System.Runtime.Intrinsics.Vector256:CopyTo[ushort](System.Runtime.Intrinsics.Vector256`1[ushort],ushort[]) [Tier0, IL size=34, code size=79] 5: JIT compiled Program:<<Main>$>g__TestV512|0_4() [Tier0, IL size=31, code size=98] 6: JIT compiled System.Runtime.Intrinsics.Vector512:CopyTo[ushort](System.Runtime.Intrinsics.Vector512`1[ushort],ushort[]) [Tier0, IL size=34, code size=83] ``` ### AVX512=0 ``` 1: JIT compiled System.Threading.Thread:GetThreadStaticsBase() [Tier0, IL size=18, code size=34] 2: JIT compiled System.Numerics.Vector`1[ushort]:CopyTo(ushort[]) [Tier0, IL size=39, code size=79] 3: JIT compiled System.Runtime.Intrinsics.Vector64:CopyTo[ushort](System.Runtime.Intrinsics.Vector64`1[ushort],ushort[]) [Tier0, IL size=34, code size=71] 4: JIT compiled System.Runtime.Intrinsics.Vector256:CopyTo[ushort](System.Runtime.Intrinsics.Vector256`1[ushort],ushort[]) [Tier0, IL size=34, code size=79] 5: JIT compiled System.Runtime.Intrinsics.Vector512:CopyTo[ushort](System.Runtime.Intrinsics.Vector512`1[ushort],ushort[]) [Tier0, IL size=34, code size=100] ``` ### AVX2=0 ``` 1: JIT compiled Program:<Main>$(System.String[]) [Tier0, IL size=31, code size=51] 2: JIT compiled Program:<<Main>$>g__TestV|0_0() [Tier0, IL size=34, code size=87] 3: JIT compiled System.Threading.Thread:GetThreadStaticsBase() [Tier0, IL size=18, code size=34] 4: JIT compiled Program:<<Main>$>g__TestV64|0_1() [Tier0, IL size=30, code size=85] 5: JIT compiled System.Runtime.Intrinsics.Vector64:CopyTo[ushort](System.Runtime.Intrinsics.Vector64`1[ushort],ushort[]) [Tier0, IL size=34, code size=71] 6: JIT compiled Program:<<Main>$>g__TestV128|0_2() [Tier0, IL size=30, code size=84] 7: JIT compiled Program:<<Main>$>g__TestV256|0_3() [Tier0, IL size=31, code size=84] 8: JIT compiled System.Runtime.Intrinsics.Vector256:CopyTo[ushort](System.Runtime.Intrinsics.Vector256`1[ushort],ushort[]) [Tier0, IL size=34, code size=79] 9: JIT compiled Program:<<Main>$>g__TestV512|0_4() [Tier0, IL size=31, code size=126] 10: JIT compiled System.Runtime.Intrinsics.Vector512:CopyTo[ushort](System.Runtime.Intrinsics.Vector512`1[ushort],ushort[]) [Tier0, IL size=34, code size=100] ``` ### SSE42=0 ``` 1: JIT compiled System.SpanHelpers:IndexOfNullCharacter(ptr) [Instrumented Tier0, IL size=1148, code size=926] 2: JIT compiled System.SpanHelpers:GetCharVector128SpanLength(nint,nint) [Tier0, IL size=14, code size=26] 3: JIT compiled System.SpanHelpers:NonPackedIndexOfValueType[short,System.SpanHelpers+DontNegate`1[short]](byref,short,int) [Instrumented Tier0, IL size=1204, code size=1761] 4: JIT compiled System.Text.Unicode.Utf16Utility:GetPointerToFirstInvalidChar(ptr,int,byref,byref) [Instrumented Tier0, IL size=946, code size=1280] 5: JIT compiled System.Text.Ascii:GetIndexOfFirstNonAsciiChar_Intrinsified(ptr,nuint) [Instrumented Tier0, IL size=473, code size=1390] 6: JIT compiled System.Text.Ascii:VectorContainsNonAsciiChar(System.Runtime.Intrinsics.Vector128`1[ushort]) [Tier0, IL size=109, code size=63] 7: JIT compiled System.Text.Unicode.Utf8Utility:TranscodeToUtf8(ptr,int,ptr,int,byref,byref) [Instrumented Tier0, IL size=1494, code size=2856] 8: JIT compiled System.Text.Ascii:NarrowUtf16ToAscii(ptr,ptr,nuint) [Instrumented Tier0, IL size=380, code size=755] 9: JIT compiled Program:<Main>$(System.String[]) [Tier0, IL size=31, code size=51] 10: JIT compiled Program:<<Main>$>g__TestV|0_0() [Tier0, IL size=34, code size=87] 11: JIT compiled System.Threading.Thread:GetThreadStaticsBase() [Tier0, IL size=18, code size=34] 12: JIT compiled System.PackedSpanHelpers:IndexOfAnyInRange[System.SpanHelpers+DontNegate`1[short]](byref,short,short,int) [Instrumented Tier0, IL size=861, code size=1316] 13: JIT compiled Program:<<Main>$>g__TestV64|0_1() [Tier0, IL size=30, code size=85] 14: JIT compiled System.Runtime.Intrinsics.Vector64:CopyTo[ushort](System.Runtime.Intrinsics.Vector64`1[ushort],ushort[]) [Tier0, IL size=34, code size=71] 15: JIT compiled Program:<<Main>$>g__TestV128|0_2() [Tier0, IL size=30, code size=82] 16: JIT compiled Program:<<Main>$>g__TestV256|0_3() [Tier0, IL size=31, code size=104] 17: JIT compiled System.Runtime.Intrinsics.Vector256:CopyTo[ushort](System.Runtime.Intrinsics.Vector256`1[ushort],ushort[]) [Tier0, IL size=34, code size=93] 18: JIT compiled Program:<<Main>$>g__TestV512|0_4() [Tier0, IL size=31, code size=135] 19: JIT compiled System.Runtime.Intrinsics.Vector512:CopyTo[ushort](System.Runtime.Intrinsics.Vector512`1[ushort],ushort[]) [Tier0, IL size=34, code size=109] ``` ### HWIntrinsics=0 ``` A LOT - Not actually going to list the several hundred APIs, this is expected since the "baseline" ISA is disabled ``` ## After - .NET 11 ### AVX512 Capable Machine ``` 1: JIT compiled System.Runtime.Intrinsics.Vector64:CopyTo[ushort](System.Runtime.Intrinsics.Vector64`1[ushort],ushort[]) [Tier0, IL size=34, code size=71] 2: JIT compiled System.Runtime.Intrinsics.Vector256:CopyTo[ushort](System.Runtime.Intrinsics.Vector256`1[ushort],ushort[]) [Tier0, IL size=34, code size=79] 3: JIT compiled Program:<<Main>$>g__TestV512|0_4() [Tier0, IL size=31, code size=98] 4: JIT compiled System.Runtime.Intrinsics.Vector512:CopyTo[ushort](System.Runtime.Intrinsics.Vector512`1[ushort],ushort[]) [Tier0, IL size=34, code size=83] ``` ### AVX512=0 ``` 1: JIT compiled System.Runtime.Intrinsics.Vector64:CopyTo[ushort](System.Runtime.Intrinsics.Vector64`1[ushort],ushort[]) [Tier0, IL size=34, code size=71] 2: JIT compiled System.Runtime.Intrinsics.Vector256:CopyTo[ushort](System.Runtime.Intrinsics.Vector256`1[ushort],ushort[]) [Tier0, IL size=34, code size=79] 3: JIT compiled System.Runtime.Intrinsics.Vector512:CopyTo[ushort](System.Runtime.Intrinsics.Vector512`1[ushort],ushort[]) [Tier0, IL size=34, code size=100] ``` ### AVX2=0 ``` A LOT - This is also expected since we bumped the R2R baseline to AVX2 for .NET 11 ```
1 parent 2a63651 commit 3be0023

File tree

4 files changed

+18
-19
lines changed

4 files changed

+18
-19
lines changed

src/coreclr/tools/Common/Compiler/Int128FieldLayoutAlgorithm.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defTyp
3333
// 32bit platforms use standard metadata layout engine
3434
if (defType.Context.Target.Architecture == TargetArchitecture.ARM)
3535
{
36-
layoutFromMetadata.LayoutAbiStable = false; // Int128 parameter passing ABI is unstable at this time
36+
layoutFromMetadata.LayoutAbiStable = true;
3737
layoutFromMetadata.IsInt128OrHasInt128Fields = true;
3838
return layoutFromMetadata;
3939
}
@@ -47,7 +47,7 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defTyp
4747
FieldAlignment = new LayoutInt(16),
4848
FieldSize = layoutFromMetadata.FieldSize,
4949
Offsets = layoutFromMetadata.Offsets,
50-
LayoutAbiStable = false, // Int128 parameter passing ABI is unstable at this time
50+
LayoutAbiStable = true,
5151
IsInt128OrHasInt128Fields = true
5252
};
5353
}

src/coreclr/tools/Common/Compiler/VectorFieldLayoutAlgorithm.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,9 @@ namespace ILCompiler
1515
public class VectorFieldLayoutAlgorithm : FieldLayoutAlgorithm
1616
{
1717
private readonly FieldLayoutAlgorithm _fallbackAlgorithm;
18-
private readonly bool _vectorAbiIsStable;
1918

20-
public VectorFieldLayoutAlgorithm(FieldLayoutAlgorithm fallbackAlgorithm, bool vectorAbiIsStable = true)
19+
public VectorFieldLayoutAlgorithm(FieldLayoutAlgorithm fallbackAlgorithm)
2120
{
22-
_vectorAbiIsStable = vectorAbiIsStable;
2321
_fallbackAlgorithm = fallbackAlgorithm;
2422
}
2523

@@ -119,7 +117,7 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defTyp
119117
FieldAlignment = alignment,
120118
FieldSize = layoutFromMetadata.FieldSize,
121119
Offsets = layoutFromMetadata.Offsets,
122-
LayoutAbiStable = _vectorAbiIsStable
120+
LayoutAbiStable = true
123121
};
124122
}
125123

src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilerContext.cs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,14 @@ public ReadyToRunCompilerContext(
6464
_r2rFieldLayoutAlgorithm = new ReadyToRunMetadataFieldLayoutAlgorithm();
6565
_systemObjectFieldLayoutAlgorithm = new SystemObjectFieldLayoutAlgorithm(_r2rFieldLayoutAlgorithm);
6666

67-
// Only the Arm64 JIT respects the OS rules for vector type abi currently
68-
_vectorFieldLayoutAlgorithm = new VectorFieldLayoutAlgorithm(_r2rFieldLayoutAlgorithm, (details.Architecture == TargetArchitecture.ARM64) ? true : bubbleIncludesCorelib);
67+
// There are a few types which require special layout algorithms and which could change based on hardware
68+
// or to better match the underlying native ABI in the future. However, these are also fairly core types
69+
// which are used in many perf critical functions that exist on startup and which are often tied to an ISA.
70+
//
71+
// Given that, we treat them as ABI stable today to ensure that R2R works well. If we end up modifying the
72+
// ABI handling in the future, we would need to take a major version bump to R2R, which is deemed worthwhile.
73+
74+
_vectorFieldLayoutAlgorithm = new VectorFieldLayoutAlgorithm(_r2rFieldLayoutAlgorithm);
6975

7076
ReadOnlySpan<byte> matchingVectorType = "Unknown"u8;
7177
if (details.MaximumSimdVectorLength == SimdVectorLength.Vector128Bit)
@@ -75,10 +81,7 @@ public ReadyToRunCompilerContext(
7581
else if (details.MaximumSimdVectorLength == SimdVectorLength.Vector512Bit)
7682
matchingVectorType = "Vector512`1"u8;
7783

78-
// No architecture has completely stable handling of Vector<T> in the abi (Arm64 may change to SVE)
79-
_vectorOfTFieldLayoutAlgorithm = new VectorOfTFieldLayoutAlgorithm(_r2rFieldLayoutAlgorithm, _vectorFieldLayoutAlgorithm, matchingVectorType, bubbleIncludesCorelib);
80-
81-
// Int128 and UInt128 should be ABI stable on all currently supported platforms
84+
_vectorOfTFieldLayoutAlgorithm = new VectorOfTFieldLayoutAlgorithm(_r2rFieldLayoutAlgorithm, _vectorFieldLayoutAlgorithm, matchingVectorType);
8285
_int128FieldLayoutAlgorithm = new Int128FieldLayoutAlgorithm(_r2rFieldLayoutAlgorithm);
8386

8487
_typeWithRepeatedFieldsFieldLayoutAlgorithm = new TypeWithRepeatedFieldsFieldLayoutAlgorithm(_r2rFieldLayoutAlgorithm);
@@ -198,14 +201,12 @@ internal class VectorOfTFieldLayoutAlgorithm : FieldLayoutAlgorithm
198201
private FieldLayoutAlgorithm _vectorFallbackAlgorithm;
199202
private byte[] _similarVectorName;
200203
private DefType _similarVectorOpenType;
201-
private bool _vectorAbiIsStable;
202204

203-
public VectorOfTFieldLayoutAlgorithm(FieldLayoutAlgorithm fallbackAlgorithm, FieldLayoutAlgorithm vectorFallbackAlgorithm, ReadOnlySpan<byte> similarVector, bool vectorAbiIsStable = true)
205+
public VectorOfTFieldLayoutAlgorithm(FieldLayoutAlgorithm fallbackAlgorithm, FieldLayoutAlgorithm vectorFallbackAlgorithm, ReadOnlySpan<byte> similarVector)
204206
{
205207
_fallbackAlgorithm = fallbackAlgorithm;
206208
_vectorFallbackAlgorithm = vectorFallbackAlgorithm;
207209
_similarVectorName = similarVector.ToArray();
208-
_vectorAbiIsStable = vectorAbiIsStable;
209210
}
210211

211212
private DefType GetSimilarVector(DefType vectorOfTType)
@@ -256,7 +257,7 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type,
256257
ByteCountUnaligned = LayoutInt.Indeterminate,
257258
ByteCountAlignment = LayoutInt.Indeterminate,
258259
Offsets = fieldsAndOffsets.ToArray(),
259-
LayoutAbiStable = false,
260+
LayoutAbiStable = true,
260261
IsVectorTOrHasVectorTFields = true,
261262
};
262263
return instanceLayout;
@@ -275,7 +276,7 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type,
275276
FieldAlignment = layoutFromSimilarIntrinsicVector.FieldAlignment,
276277
FieldSize = layoutFromSimilarIntrinsicVector.FieldSize,
277278
Offsets = layoutFromMetadata.Offsets,
278-
LayoutAbiStable = _vectorAbiIsStable,
279+
LayoutAbiStable = true,
279280
IsVectorTOrHasVectorTFields = true,
280281
};
281282
#else
@@ -286,7 +287,7 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type,
286287
FieldAlignment = layoutFromMetadata.FieldAlignment,
287288
FieldSize = layoutFromSimilarIntrinsicVector.FieldSize,
288289
Offsets = layoutFromMetadata.Offsets,
289-
LayoutAbiStable = _vectorAbiIsStable,
290+
LayoutAbiStable = true,
290291
IsVectorTOrHasVectorTFields = true,
291292
};
292293
#endif

src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TestTypeSystemContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ internal class TestTypeSystemContext : MetadataTypeSystemContext
3737
public TestTypeSystemContext(TargetArchitecture arch, TargetOS targetOS = TargetOS.Unknown)
3838
: base(new TargetDetails(arch, targetOS, TargetAbi.Unknown))
3939
{
40-
_vectorFieldLayoutAlgorithm = new VectorFieldLayoutAlgorithm(_metadataFieldLayout, true);
40+
_vectorFieldLayoutAlgorithm = new VectorFieldLayoutAlgorithm(_metadataFieldLayout);
4141
_int128FieldLayoutAlgorithm = new Int128FieldLayoutAlgorithm(_metadataFieldLayout);
4242
}
4343

0 commit comments

Comments
 (0)