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
1 change: 1 addition & 0 deletions src/coreclr/jit/fgbasic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1359,6 +1359,7 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed
case NI_System_Type_get_IsEnum:
case NI_System_Type_GetEnumUnderlyingType:
case NI_System_Type_get_IsValueType:
case NI_System_Type_get_IsPrimitive:
case NI_System_Type_get_IsByRefLike:
case NI_System_Type_GetTypeFromHandle:
case NI_System_String_get_Length:
Expand Down
21 changes: 21 additions & 0 deletions src/coreclr/jit/importercalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2553,6 +2553,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,

// These may lead to early dead code elimination
case NI_System_Type_get_IsValueType:
case NI_System_Type_get_IsPrimitive:
case NI_System_Type_get_IsEnum:
case NI_System_Type_get_IsByRefLike:
case NI_System_Type_IsAssignableFrom:
Expand Down Expand Up @@ -3143,6 +3144,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,

case NI_System_Type_get_IsEnum:
case NI_System_Type_get_IsValueType:
case NI_System_Type_get_IsPrimitive:
case NI_System_Type_get_IsByRefLike:
{
// Optimize
Expand All @@ -3156,6 +3158,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
CORINFO_CLASS_HANDLE hClass = NO_CLASS_HANDLE;
if (gtIsTypeof(impStackTop().val, &hClass))
{
assert(hClass != NO_CLASS_HANDLE);
switch (ni)
{
case NI_System_Type_get_IsEnum:
Expand All @@ -3176,6 +3179,20 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
retNode = gtNewIconNode(
(info.compCompHnd->getClassAttribs(hClass) & CORINFO_FLG_BYREF_LIKE) ? 1 : 0);
break;
case NI_System_Type_get_IsPrimitive:
// getTypeForPrimitiveValueClass returns underlying type for enums, so we check it first
// because enums are not primitive types.
if ((info.compCompHnd->isEnum(hClass, nullptr) == TypeCompareState::MustNot) &&
info.compCompHnd->getTypeForPrimitiveValueClass(hClass) != CORINFO_TYPE_UNDEF)
{
retNode = gtNewTrue();
}
else
{
retNode = gtNewFalse();
}
break;

default:
NO_WAY("Intrinsic not supported in this path.");
}
Expand Down Expand Up @@ -8807,6 +8824,10 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
{
result = NI_System_Type_get_IsValueType;
}
else if (strcmp(methodName, "get_IsPrimitive") == 0)
{
result = NI_System_Type_get_IsPrimitive;
}
else if (strcmp(methodName, "get_IsByRefLike") == 0)
{
result = NI_System_Type_get_IsByRefLike;
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/namedintrinsiclist.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ enum NamedIntrinsic : unsigned short
NI_System_Type_get_IsEnum,
NI_System_Type_GetEnumUnderlyingType,
NI_System_Type_get_IsValueType,
NI_System_Type_get_IsPrimitive,
NI_System_Type_get_IsByRefLike,
NI_System_Type_get_TypeHandle,
NI_System_Type_IsAssignableFrom,
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/System.Private.CoreLib/src/System/Type.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public virtual Type[] GetGenericParameterConstraints()
public virtual bool IsEnum { [Intrinsic] get => IsSubclassOf(typeof(Enum)); }
public bool IsMarshalByRef => IsMarshalByRefImpl();
protected virtual bool IsMarshalByRefImpl() => false;
public bool IsPrimitive => IsPrimitiveImpl();
public bool IsPrimitive { [Intrinsic] get => IsPrimitiveImpl(); }
protected abstract bool IsPrimitiveImpl();
public bool IsValueType { [Intrinsic] get => IsValueTypeImpl(); }
protected virtual bool IsValueTypeImpl() => IsSubclassOf(typeof(ValueType));
Expand Down
53 changes: 53 additions & 0 deletions src/tests/JIT/Intrinsics/TypeIntrinsics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,60 @@ public static int Main()

GetEnumUnderlyingType.TestGetEnumUnderlyingType();

IsPrimitiveTests();

return 100 + _errors;
}

private static void IsPrimitiveTests()
{
IsTrue(typeof(bool).IsPrimitive);
IsTrue(typeof(char).IsPrimitive);
IsTrue(typeof(sbyte).IsPrimitive);
IsTrue(typeof(byte).IsPrimitive);
IsTrue(typeof(short).IsPrimitive);
IsTrue(typeof(ushort).IsPrimitive);
IsTrue(typeof(int).IsPrimitive);
IsTrue(typeof(uint).IsPrimitive);
IsTrue(typeof(long).IsPrimitive);
IsTrue(typeof(ulong).IsPrimitive);
IsTrue(typeof(float).IsPrimitive);
IsTrue(typeof(double).IsPrimitive);
IsTrue(typeof(nint).IsPrimitive);
IsTrue(typeof(nuint).IsPrimitive);
IsTrue(typeof(IntPtr).IsPrimitive);
IsTrue(typeof(UIntPtr).IsPrimitive);

IsFalse(typeof(Enum).IsPrimitive);
IsFalse(typeof(ValueType).IsPrimitive);
IsFalse(typeof(SimpleEnum).IsPrimitive);
IsFalse(typeof(IntPtrEnum).IsPrimitive);
IsFalse(typeof(FloatEnum).IsPrimitive);
IsFalse(typeof(SimpleEnum?).IsPrimitive);
IsFalse(typeof(int?).IsPrimitive);
IsFalse(typeof(IntPtr?).IsPrimitive);
IsFalse(typeof(decimal).IsPrimitive);
IsFalse(typeof(TimeSpan).IsPrimitive);
IsFalse(typeof(DateTime).IsPrimitive);
IsFalse(typeof(DateTimeOffset).IsPrimitive);
IsFalse(typeof(Guid).IsPrimitive);
IsFalse(typeof(Half).IsPrimitive);
IsFalse(typeof(DateOnly).IsPrimitive);
IsFalse(typeof(TimeOnly).IsPrimitive);
IsFalse(typeof(Int128).IsPrimitive);
IsFalse(typeof(UInt128).IsPrimitive);
IsFalse(typeof(string).IsPrimitive);
IsFalse(typeof(object).IsPrimitive);
IsFalse(typeof(RuntimeArgumentHandle).IsPrimitive);
IsFalse(typeof(int[]).IsPrimitive);
IsFalse(typeof(int[,]).IsPrimitive);
IsFalse(typeof(int*).IsPrimitive);
IsFalse(typeof(void*).IsPrimitive);
IsFalse(typeof(delegate*<int>).IsPrimitive);
IsFalse(typeof(Nullable<>).IsPrimitive);
IsFalse(typeof(Dictionary<,>).IsPrimitive);
}

private static int _varInt = 42;
private static int? _varNullableInt = 42;
private static decimal _varDecimal = 42M;
Expand Down Expand Up @@ -166,6 +217,7 @@ public static int Main()
[MethodImpl(MethodImplOptions.NoInlining)]
private static dynamic CreateDynamic2() => new { Name = "Test" };

[MethodImpl(MethodImplOptions.NoInlining)]
static void IsTrue(bool expression, [CallerLineNumber] int line = 0, [CallerFilePath] string file = "")
{
if (!expression)
Expand All @@ -175,6 +227,7 @@ static void IsTrue(bool expression, [CallerLineNumber] int line = 0, [CallerFile
}
}

[MethodImpl(MethodImplOptions.NoInlining)]
static void IsFalse(bool expression, [CallerLineNumber] int line = 0, [CallerFilePath] string file = "")
{
if (expression)
Expand Down