summaryrefslogtreecommitdiff
path: root/src/jit/gentree.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/gentree.cpp')
-rw-r--r--src/jit/gentree.cpp100
1 files changed, 95 insertions, 5 deletions
diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp
index 6c13285a77..cf1de878ca 100644
--- a/src/jit/gentree.cpp
+++ b/src/jit/gentree.cpp
@@ -1301,6 +1301,7 @@ AGAIN:
// For the ones below no extra argument matters for comparison.
case GT_BOX:
+ case GT_RUNTIMELOOKUP:
break;
default:
@@ -11813,6 +11814,48 @@ GenTree* Compiler::gtFoldExprCompare(GenTree* tree)
}
//------------------------------------------------------------------------
+// gtCreateHandleCompare: generate a type handle comparison
+//
+// Arguments:
+// oper -- comparison operation (equal/not equal)
+// op1 -- first operand
+// op2 -- second operand
+// typeCheckInliningResult -- indicates how the comparison should happen
+//
+// Returns:
+// Type comparison tree
+//
+
+GenTree* Compiler::gtCreateHandleCompare(genTreeOps oper,
+ GenTree* op1,
+ GenTree* op2,
+ CorInfoInlineTypeCheck typeCheckInliningResult)
+{
+ // If we can compare pointers directly, just emit the binary operation
+ if (typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_PASS)
+ {
+ return gtNewOperNode(oper, TYP_INT, op1, op2);
+ }
+
+ assert(typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_USE_HELPER);
+
+ // Emit a call to a runtime helper
+ GenTreeArgList* helperArgs = gtNewArgList(op1, op2);
+ GenTree* ret = gtNewHelperCallNode(CORINFO_HELP_ARE_TYPES_EQUIVALENT, TYP_INT, helperArgs);
+ if (oper == GT_EQ)
+ {
+ ret = gtNewOperNode(GT_NE, TYP_INT, ret, gtNewIconNode(0, TYP_INT));
+ }
+ else
+ {
+ assert(oper == GT_NE);
+ ret = gtNewOperNode(GT_EQ, TYP_INT, ret, gtNewIconNode(0, TYP_INT));
+ }
+
+ return ret;
+}
+
+//------------------------------------------------------------------------
// gtFoldTypeCompare: see if a type comparison can be further simplified
//
// Arguments:
@@ -11926,16 +11969,29 @@ GenTree* Compiler::gtFoldTypeCompare(GenTree* tree)
// We can't answer the equality comparison definitively at jit
// time, but can still simplfy the comparison.
//
+ // Find out how we can compare the two handles.
+ // NOTE: We're potentially passing NO_CLASS_HANDLE, but the runtime knows what to do with it here.
+ CorInfoInlineTypeCheck inliningKind =
+ info.compCompHnd->canInlineTypeCheck(cls1Hnd, CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN);
+
+ // If the first type needs helper, check the other type: it might be okay with a simple compare.
+ if (inliningKind == CORINFO_INLINE_TYPECHECK_USE_HELPER)
+ {
+ inliningKind = info.compCompHnd->canInlineTypeCheck(cls2Hnd, CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN);
+ }
+
+ assert(inliningKind == CORINFO_INLINE_TYPECHECK_PASS || inliningKind == CORINFO_INLINE_TYPECHECK_USE_HELPER);
+
// If we successfully tunneled through both operands, compare
// the tunneled values, otherwise compare the original values.
- GenTree* compare = nullptr;
+ GenTree* compare;
if ((op1TunneledHandle != nullptr) && (op2TunneledHandle != nullptr))
{
- compare = gtNewOperNode(oper, TYP_INT, op1TunneledHandle, op2TunneledHandle);
+ compare = gtCreateHandleCompare(oper, op1TunneledHandle, op2TunneledHandle, inliningKind);
}
else
{
- compare = gtNewOperNode(oper, TYP_INT, op1ClassFromHandle, op2ClassFromHandle);
+ compare = gtCreateHandleCompare(oper, op1ClassFromHandle, op2ClassFromHandle, inliningKind);
}
// Drop any now-irrelvant flags
@@ -11971,7 +12027,9 @@ GenTree* Compiler::gtFoldTypeCompare(GenTree* tree)
// Ask the VM if this type can be equality tested by a simple method
// table comparison.
- if (!info.compCompHnd->canInlineTypeCheckWithObjectVTable(clsHnd))
+ CorInfoInlineTypeCheck typeCheckInliningResult =
+ info.compCompHnd->canInlineTypeCheck(clsHnd, CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE);
+ if (typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_NONE)
{
return tree;
}
@@ -12005,7 +12063,7 @@ GenTree* Compiler::gtFoldTypeCompare(GenTree* tree)
optMethodFlags |= OMF_HAS_VTABLEREF;
// Compare the two method tables
- GenTree* const compare = gtNewOperNode(oper, TYP_INT, objMT, knownMT);
+ GenTree* const compare = gtCreateHandleCompare(oper, objMT, knownMT, typeCheckInliningResult);
// Drop any any now irrelevant flags
compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
@@ -15128,6 +15186,38 @@ bool Compiler::gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call)
call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL);
}
+//------------------------------------------------------------------------
+// gtIsTypeHandleToRuntimeTypeHandleHelperCall -- see if tree is constructing
+// a RuntimeTypeHandle from a handle
+//
+// Arguments:
+// tree - tree to examine
+// pHelper - optional pointer to a variable that receives the type of the helper
+//
+// Return Value:
+// True if so
+
+bool Compiler::gtIsTypeHandleToRuntimeTypeHandleHelper(GenTreeCall* call, CorInfoHelpFunc* pHelper)
+{
+ CorInfoHelpFunc helper = CORINFO_HELP_UNDEF;
+
+ if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE))
+ {
+ helper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE;
+ }
+ else if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL))
+ {
+ helper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL;
+ }
+
+ if (pHelper != nullptr)
+ {
+ *pHelper = helper;
+ }
+
+ return helper != CORINFO_HELP_UNDEF;
+}
+
bool Compiler::gtIsActiveCSE_Candidate(GenTree* tree)
{
return (optValnumCSE_phase && IS_CSE_INDEX(tree->gtCSEnum));