Skip to content

Commit 7f9ed8f

Browse files
Adding Int128 and UInt128 with a base software implementation (#69204)
* Adding barebones Int128 and UInt128 structs * Special case Int128 and UInt128 alignment on x64 Unix and Arm64 * Implementing Int128 and UInt128 * Adding tests for Int128 and UInt128 * Updating Int128/UInt128 to respect the System V ABI ordering * Fixing an issue with UInt128->BigInteger setting the wrong sign * Don't use Unsafe.As in the Int128/UInt128 hex parsing logic * Adding Int128 P/Invoke tests and ensure R2R correctly sets the packing * Fixing some issues with the Int128 interop test for non-Windows * Ensure that floating-point conversions exist for Int128 and UInt128 * Fixing the casing of a couple fields * Revert "Don't use Unsafe.As in the Int128/UInt128 hex parsing logic" This reverts commit 09e8bfc. * Adjusting the Int128/UInt128 generic math tests to have consistent ordering * Responding to PR feedback * Ensure that pNativeLayoutInfo alignment is initialized for Int128/UInt128 * Don't use Unsafe.As in the Int128/UInt128 hex parsing logic * Skip the Interop/PInvoke/Int128 tests on Mono
1 parent d8fe9cd commit 7f9ed8f

54 files changed

Lines changed: 11141 additions & 239 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

THIRD-PARTY-NOTICES.TXT

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1072,4 +1072,30 @@ Copyright (c) Microsoft Corporation.
10721072
Licensed under the MIT License.
10731073

10741074
Available at
1075-
https://github.com/microsoft/msquic/blob/main/LICENSE
1075+
https://github.com/microsoft/msquic/blob/main/LICENSE
1076+
1077+
License notice for m-ou-se/floatconv
1078+
-------------------------------
1079+
1080+
Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se>
1081+
All rights reserved.
1082+
1083+
Redistribution and use in source and binary forms, with or without
1084+
modification, are permitted provided that the following conditions are met:
1085+
1086+
1. Redistributions of source code must retain the above copyright notice, this
1087+
list of conditions and the following disclaimer.
1088+
2. Redistributions in binary form must reproduce the above copyright notice,
1089+
this list of conditions and the following disclaimer in the documentation
1090+
and/or other materials provided with the distribution.
1091+
1092+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
1093+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1094+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1095+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
1096+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1097+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1098+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1099+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1100+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1101+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Internal.TypeSystem;
5+
6+
using Debug = System.Diagnostics.Debug;
7+
8+
namespace ILCompiler
9+
{
10+
/// <summary>
11+
/// Represents an algorithm that computes field layout for intrinsic integer types (Int128/UInt128).
12+
/// </summary>
13+
public class Int128FieldLayoutAlgorithm : FieldLayoutAlgorithm
14+
{
15+
private readonly FieldLayoutAlgorithm _fallbackAlgorithm;
16+
17+
public Int128FieldLayoutAlgorithm(FieldLayoutAlgorithm fallbackAlgorithm)
18+
{
19+
_fallbackAlgorithm = fallbackAlgorithm;
20+
}
21+
22+
public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defType, InstanceLayoutKind layoutKind)
23+
{
24+
Debug.Assert(IsIntegerType(defType));
25+
26+
string name = defType.Name;
27+
Debug.Assert((name == "Int128") || (name == "UInt128"));
28+
29+
ComputedInstanceFieldLayout layoutFromMetadata = _fallbackAlgorithm.ComputeInstanceLayout(defType, layoutKind);
30+
31+
if (defType.Context.Target.IsWindows || (defType.Context.Target.PointerSize == 4))
32+
{
33+
return layoutFromMetadata;
34+
}
35+
36+
// 64-bit Unix systems follow the System V ABI and have a 16-byte packing requirement for Int128/UInt128
37+
38+
return new ComputedInstanceFieldLayout
39+
{
40+
ByteCountUnaligned = layoutFromMetadata.ByteCountUnaligned,
41+
ByteCountAlignment = layoutFromMetadata.ByteCountAlignment,
42+
FieldAlignment = new LayoutInt(16),
43+
FieldSize = layoutFromMetadata.FieldSize,
44+
Offsets = layoutFromMetadata.Offsets,
45+
LayoutAbiStable = true
46+
};
47+
}
48+
49+
public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType defType, StaticLayoutKind layoutKind)
50+
{
51+
return _fallbackAlgorithm.ComputeStaticFieldLayout(defType, layoutKind);
52+
}
53+
54+
public override bool ComputeContainsGCPointers(DefType type)
55+
{
56+
Debug.Assert(!_fallbackAlgorithm.ComputeContainsGCPointers(type));
57+
return false;
58+
}
59+
60+
public override bool ComputeIsUnsafeValueType(DefType type)
61+
{
62+
Debug.Assert(!_fallbackAlgorithm.ComputeIsUnsafeValueType(type));
63+
return false;
64+
}
65+
66+
public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type)
67+
{
68+
Debug.Assert(_fallbackAlgorithm.ComputeValueTypeShapeCharacteristics(type) == ValueTypeShapeCharacteristics.None);
69+
return ValueTypeShapeCharacteristics.None;
70+
}
71+
72+
public static bool IsIntegerType(DefType type)
73+
{
74+
return type.IsIntrinsic
75+
&& type.Namespace == "System."
76+
&& ((type.Name == "Int128") || (type.Name == "UInt128"));
77+
}
78+
}
79+
}

src/coreclr/tools/Common/JitInterface/SystemVStructClassificator.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ internal SystemVStructRegisterPassingHelper(int totalStructSize)
3030
FieldClassifications = new SystemVClassificationType[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
3131
FieldSizes = new int[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
3232
FieldOffsets = new int[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
33-
33+
3434
for (int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++)
3535
{
3636
EightByteClassifications[i] = SystemVClassificationTypeNoClass;
@@ -94,7 +94,7 @@ public static void GetSystemVAmd64PassStructInRegisterDescriptor(TypeDesc typeDe
9494
{
9595
structPassInRegDescPtr = default;
9696
structPassInRegDescPtr.passedInRegisters = false;
97-
97+
9898
int typeSize = typeDesc.GetElementSize().AsInt;
9999
if (typeDesc.IsValueType && (typeSize <= CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS))
100100
{
@@ -114,7 +114,7 @@ public static void GetSystemVAmd64PassStructInRegisterDescriptor(TypeDesc typeDe
114114
structPassInRegDescPtr.eightByteClassifications0 = helper.EightByteClassifications[0];
115115
structPassInRegDescPtr.eightByteSizes0 = (byte)helper.EightByteSizes[0];
116116
structPassInRegDescPtr.eightByteOffsets0 = (byte)helper.EightByteOffsets[0];
117-
117+
118118
structPassInRegDescPtr.eightByteClassifications1 = helper.EightByteClassifications[1];
119119
structPassInRegDescPtr.eightByteSizes1 = (byte)helper.EightByteSizes[1];
120120
structPassInRegDescPtr.eightByteOffsets1 = (byte)helper.EightByteOffsets[1];
@@ -216,7 +216,7 @@ static SystemVClassificationType ReClassifyField(SystemVClassificationType origi
216216
/// <summary>
217217
/// Returns 'true' if the struct is passed in registers, 'false' otherwise.
218218
/// </summary>
219-
private static bool ClassifyEightBytes(TypeDesc typeDesc,
219+
private static bool ClassifyEightBytes(TypeDesc typeDesc,
220220
ref SystemVStructRegisterPassingHelper helper,
221221
int startOffsetOfStruct)
222222
{
@@ -239,14 +239,15 @@ private static bool ClassifyEightBytes(TypeDesc typeDesc,
239239
return false;
240240
}
241241

242-
// The SIMD Intrinsic types are meant to be handled specially and should not be passed as struct registers
242+
// The SIMD and Int128 Intrinsic types are meant to be handled specially and should not be passed as struct registers
243243
if (typeDesc.IsIntrinsic)
244244
{
245245
InstantiatedType instantiatedType = typeDesc as InstantiatedType;
246246
if (instantiatedType != null)
247247
{
248248
if (VectorFieldLayoutAlgorithm.IsVectorType(instantiatedType) ||
249-
VectorOfTFieldLayoutAlgorithm.IsVectorOfTType(instantiatedType))
249+
VectorOfTFieldLayoutAlgorithm.IsVectorOfTType(instantiatedType) ||
250+
Int128FieldLayoutAlgorithm.IsIntegerType(instantiatedType))
250251
{
251252
return false;
252253
}
@@ -316,7 +317,7 @@ private static bool ClassifyEightBytes(TypeDesc typeDesc,
316317

317318
bool structRet = false;
318319
structRet = ClassifyEightBytes(field.FieldType, ref helper, normalizedFieldOffset);
319-
320+
320321
helper.InEmbeddedStruct = inEmbeddedStructPrev;
321322

322323
if (!structRet)
@@ -482,7 +483,7 @@ private static void AssignClassifiedEightByteTypes(ref SystemVStructRegisterPass
482483
else if ((helper.EightByteClassifications[currentFieldEightByte] == SystemVClassificationTypeInteger) ||
483484
(fieldClassificationType == SystemVClassificationTypeInteger))
484485
{
485-
Debug.Assert((fieldClassificationType != SystemVClassificationTypeIntegerReference) &&
486+
Debug.Assert((fieldClassificationType != SystemVClassificationTypeIntegerReference) &&
486487
(fieldClassificationType != SystemVClassificationTypeIntegerByRef));
487488

488489
helper.EightByteClassifications[currentFieldEightByte] = SystemVClassificationTypeInteger;

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/CompilerTypeSystemContext.Aot.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public SharedGenericsConfiguration GenericsConfig
3333
private readonly RuntimeDeterminedFieldLayoutAlgorithm _runtimeDeterminedFieldLayoutAlgorithm = new RuntimeDeterminedFieldLayoutAlgorithm();
3434
private readonly VectorOfTFieldLayoutAlgorithm _vectorOfTFieldLayoutAlgorithm;
3535
private readonly VectorFieldLayoutAlgorithm _vectorFieldLayoutAlgorithm;
36+
private readonly Int128FieldLayoutAlgorithm _int128FieldLayoutAlgorithm;
3637

3738
private TypeDesc[] _arrayOfTInterfaces;
3839
private ArrayOfTRuntimeInterfacesAlgorithm _arrayOfTRuntimeInterfacesAlgorithm;
@@ -45,6 +46,7 @@ public CompilerTypeSystemContext(TargetDetails details, SharedGenericsMode gener
4546

4647
_vectorOfTFieldLayoutAlgorithm = new VectorOfTFieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm);
4748
_vectorFieldLayoutAlgorithm = new VectorFieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm);
49+
_int128FieldLayoutAlgorithm = new Int128FieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm);
4850

4951
_delegateInfoHashtable = new DelegateInfoHashtable(delegateFeatures);
5052

@@ -72,6 +74,8 @@ public override FieldLayoutAlgorithm GetLayoutAlgorithmForType(DefType type)
7274
return _vectorOfTFieldLayoutAlgorithm;
7375
else if (VectorFieldLayoutAlgorithm.IsVectorType(type))
7476
return _vectorFieldLayoutAlgorithm;
77+
else if (Int128FieldLayoutAlgorithm.IsIntegerType(type))
78+
return _int128FieldLayoutAlgorithm;
7579
else
7680
return _metadataFieldLayoutAlgorithm;
7781
}
@@ -220,8 +224,8 @@ public class SharedGenericsConfiguration
220224
// method table.
221225
public long UniversalCanonReflectionMethodRootHeuristic_InstantiationCount { get; }
222226

223-
// To avoid infinite generic recursion issues during debug type record generation, attempt to
224-
// use canonical form for types with high generic complexity.
227+
// To avoid infinite generic recursion issues during debug type record generation, attempt to
228+
// use canonical form for types with high generic complexity.
225229
public long MaxGenericDepthOfDebugRecord { get; }
226230

227231
public SharedGenericsConfiguration()

src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@
303303
<Compile Include="..\..\Common\Compiler\HardwareIntrinsicHelpers.cs" Link="Compiler\HardwareIntrinsicHelpers.cs" />
304304
<Compile Include="..\..\Common\Compiler\ICompilationRootProvider.cs" Link="Compiler\ICompilationRootProvider.cs" />
305305
<Compile Include="..\..\Common\Compiler\InstructionSetSupport.cs" Link="Compiler\InstructionSetSupport.cs" />
306+
<Compile Include="..\..\Common\Compiler\Int128FieldLayoutAlgorithm.cs" Link="Compiler\Int128FieldLayoutAlgorithm.cs" />
306307
<Compile Include="..\..\Common\Compiler\InternalCompilerErrorException.cs" Link="Compiler\InternalCompilerErrorException.cs" />
307308
<Compile Include="..\..\Common\Compiler\NameMangler.cs" Link="Compiler\NameMangler.cs" />
308309
<Compile Include="..\..\Common\Compiler\SingleMethodRootProvider.cs" Link="Compiler\SingleMethodRootProvider.cs" />

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public partial class ReadyToRunCompilerContext : CompilerTypeSystemContext
3636
private SystemObjectFieldLayoutAlgorithm _systemObjectFieldLayoutAlgorithm;
3737
private VectorOfTFieldLayoutAlgorithm _vectorOfTFieldLayoutAlgorithm;
3838
private VectorFieldLayoutAlgorithm _vectorFieldLayoutAlgorithm;
39+
private Int128FieldLayoutAlgorithm _int128FieldLayoutAlgorithm;
3940

4041
public ReadyToRunCompilerContext(TargetDetails details, SharedGenericsMode genericsMode, bool bubbleIncludesCorelib, CompilerTypeSystemContext oldTypeSystemContext = null)
4142
: base(details, genericsMode)
@@ -55,6 +56,9 @@ public ReadyToRunCompilerContext(TargetDetails details, SharedGenericsMode gener
5556
// No architecture has completely stable handling of Vector<T> in the abi (Arm64 may change to SVE)
5657
_vectorOfTFieldLayoutAlgorithm = new VectorOfTFieldLayoutAlgorithm(_r2rFieldLayoutAlgorithm, _vectorFieldLayoutAlgorithm, matchingVectorType, bubbleIncludesCorelib);
5758

59+
// Int128 and UInt128 should be ABI stable on all currently supported platforms
60+
_int128FieldLayoutAlgorithm = new Int128FieldLayoutAlgorithm(_r2rFieldLayoutAlgorithm);
61+
5862
if (oldTypeSystemContext != null)
5963
{
6064
InheritOpenModules(oldTypeSystemContext);
@@ -77,6 +81,10 @@ public override FieldLayoutAlgorithm GetLayoutAlgorithmForType(DefType type)
7781
{
7882
return _vectorFieldLayoutAlgorithm;
7983
}
84+
else if (Int128FieldLayoutAlgorithm.IsIntegerType(type))
85+
{
86+
return _int128FieldLayoutAlgorithm;
87+
}
8088
else
8189
{
8290
Debug.Assert(_r2rFieldLayoutAlgorithm != null);

src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
<Compile Include="..\..\Common\Compiler\HardwareIntrinsicHelpers.cs" Link="Compiler\HardwareIntrinsicHelpers.cs" />
9292
<Compile Include="..\..\Common\Compiler\ICompilationRootProvider.cs" Link="Compiler\ICompilationRootProvider.cs" />
9393
<Compile Include="..\..\Common\Compiler\InstructionSetSupport.cs" Link="Compiler\InstructionSetSupport.cs" />
94+
<Compile Include="..\..\Common\Compiler\Int128FieldLayoutAlgorithm.cs" Link="Compiler\Int128FieldLayoutAlgorithm.cs" />
9495
<Compile Include="..\..\Common\Compiler\InternalCompilerErrorException.cs" Link="Compiler\InternalCompilerErrorException.cs" />
9596
<Compile Include="..\..\Common\Compiler\NameMangler.cs" Link="Compiler\NameMangler.cs" />
9697
<Compile Include="..\..\Common\Compiler\SingleMethodRootProvider.cs" Link="Compiler\SingleMethodRootProvider.cs" />

src/coreclr/vm/classlayoutinfo.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,9 @@ EEClassNativeLayoutInfo* EEClassNativeLayoutInfo::CollectNativeLayoutFieldMetada
955955
pNativeLayoutInfo->m_alignmentRequirement = pEEClassLayoutInfo->m_ManagedLargestAlignmentRequirementOfAllMembers;
956956
}
957957
else
958-
if (pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__VECTOR64T)) ||
958+
if (pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__INT128)) ||
959+
pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__UINT128)) ||
960+
pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__VECTOR64T)) ||
959961
pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__VECTOR128T)) ||
960962
pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__VECTOR256T)))
961963
{

src/coreclr/vm/classnames.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@
3838
#define g_DateTimeOffsetClassName "System.DateTimeOffset"
3939
#define g_DecimalClassName "System.Decimal"
4040

41+
#define g_Int128ClassName "System.Int128"
42+
#define g_Int128Name "Int128"
43+
44+
#define g_UInt128ClassName "System.UInt128"
45+
#define g_UInt128Name "UInt128"
46+
4147
#define g_Vector64ClassName "System.Runtime.Intrinsics.Vector64`1"
4248
#define g_Vector64Name "Vector64`1"
4349

src/coreclr/vm/corelib.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,9 @@ DEFINE_FIELD(DELEGATE, METHOD_PTR_AUX, _methodPtrAux)
282282
DEFINE_METHOD(DELEGATE, CONSTRUCT_DELEGATE, DelegateConstruct, IM_Obj_IntPtr_RetVoid)
283283
DEFINE_METHOD(DELEGATE, GET_INVOKE_METHOD, GetInvokeMethod, IM_RetIntPtr)
284284

285+
DEFINE_CLASS(INT128, System, Int128)
286+
DEFINE_CLASS(UINT128, System, UInt128)
287+
285288
DEFINE_CLASS(DYNAMICMETHOD, ReflectionEmit, DynamicMethod)
286289

287290
DEFINE_CLASS(DYNAMICRESOLVER, ReflectionEmit, DynamicResolver)

0 commit comments

Comments
 (0)