diff options
Diffstat (limited to 'src/jit/gentree.cpp')
-rw-r--r-- | src/jit/gentree.cpp | 100 |
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)); |