Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4496,6 +4496,7 @@ class Compiler
IL_OFFSET ilOffset = BAD_IL_OFFSET);

bool impConsiderCallProbe(GenTreeCall* call, IL_OFFSET ilOffset);
GenTree* impFoldEnumEquals(GenTreeCall* call);

enum class GDVProbeType
{
Expand Down
73 changes: 71 additions & 2 deletions src/coreclr/jit/importercalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,16 @@ var_types Compiler::impImportCall(OPCODE opcode,
if ((callInfo->methodFlags & CORINFO_FLG_INTRINSIC) != 0)
{
call->AsCall()->gtCallMoreFlags |= GTF_CALL_M_SPECIAL_INTRINSIC;

if (call->AsCall()->IsSpecialIntrinsic(this, NI_System_Enum_Equals))
{
GenTree* folded = impFoldEnumEquals(call->AsCall());
if (folded)
{
impPushOnStack(folded, typeInfo(folded->TypeGet()));
return folded->TypeGet();
}
}
}
}
}
Expand Down Expand Up @@ -1571,7 +1581,62 @@ var_types Compiler::impImportCall(OPCODE opcode,
}

//------------------------------------------------------------------------
// impThrowIfNull: Remove redundandant boxing from ArgumentNullException_ThrowIfNull
// impFoldEnumEquals: Optimize Enum.Equals calls by unboxing and comparing underlying values
//
// Arguments:
// call -- call representing Enum.Equals
//
// Return Value:
// Optimized tree (or nullptr if we can't optimize it).
//
GenTree* Compiler::impFoldEnumEquals(GenTreeCall* call)
{
assert(call->IsSpecialIntrinsic(this, NI_System_Enum_Equals));
assert(call->AsCall()->gtArgs.CountUserArgs() == 2);

GenTree* arg0 = call->AsCall()->gtArgs.GetArgByIndex(0)->GetNode();
GenTree* arg1 = call->AsCall()->gtArgs.GetArgByIndex(1)->GetNode();

bool isArg0Exact;
bool isArg1Exact;
bool isNonNull; // we don't care about this property for both args here

CORINFO_CLASS_HANDLE cls0 = gtGetClassHandle(arg0, &isArg0Exact, &isNonNull);
CORINFO_CLASS_HANDLE cls1 = gtGetClassHandle(arg1, &isArg1Exact, &isNonNull);

if ((cls0 != cls1) || (cls0 == NO_CLASS_HANDLE) || !isArg0Exact || !isArg1Exact)
{
return nullptr;
}

CORINFO_CLASS_HANDLE underlyingEnumCls;
if (info.compCompHnd->isEnum(cls1, &underlyingEnumCls) != TypeCompareState::Must)
{
return nullptr;
}

var_types typ = JITtype2varType(info.compCompHnd->getTypeForPrimitiveNumericClass(underlyingEnumCls));
if (!varTypeIsIntegral(typ))
{
// Ignore non-integral enums e.g. enums based on float/double
return nullptr;
}

// Unbox both integral arguments and compare their underlying values
GenTree* offset = gtNewIconNode(TARGET_POINTER_SIZE, TYP_I_IMPL);
GenTree* addr0 = gtNewOperNode(GT_ADD, TYP_BYREF, arg0, offset);
GenTree* addr1 = gtNewOperNode(GT_ADD, TYP_BYREF, arg1, gtCloneExpr(offset));
GenTree* cmpNode = gtNewOperNode(GT_EQ, TYP_INT, gtNewIndir(typ, addr0), gtNewIndir(typ, addr1));

JITDUMP("Optimized Enum.Equals call to comparison of underlying values:\n");
DISPTREE(cmpNode);
JITDUMP("\n");

return cmpNode;
}

//------------------------------------------------------------------------
// impThrowIfNull: Remove redundant boxing from ArgumentNullException_ThrowIfNull
// it is done for Tier0 where we can't remove it without inlining otherwise.
//
// Arguments:
Expand Down Expand Up @@ -10344,7 +10409,11 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
{
if (strcmp(className, "Enum") == 0)
{
if (strcmp(methodName, "HasFlag") == 0)
if (strcmp(methodName, "Equals") == 0)
{
result = NI_System_Enum_Equals;
}
else if (strcmp(methodName, "HasFlag") == 0)
{
result = NI_System_Enum_HasFlag;
}
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 @@ -15,6 +15,7 @@ enum NamedIntrinsic : unsigned short

NI_System_ArgumentNullException_ThrowIfNull,

NI_System_Enum_Equals,
NI_System_Enum_HasFlag,

NI_System_BitConverter_DoubleToInt64Bits,
Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.Private.CoreLib/src/System/Enum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1187,6 +1187,7 @@ internal object GetValue()
}

/// <inheritdoc/>
[Intrinsic]
public override bool Equals([NotNullWhen(true)] object? obj)
{
if (obj is null)
Expand Down
Loading