diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 28eb8d1ef430f..217d5f3a20beb 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4631,6 +4631,8 @@ class Compiler GenTreeCall* fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper); + bool fgIsCurrentCallDceCandidate(); + GenTreeCall* fgGetSharedCCtor(CORINFO_CLASS_HANDLE cls); bool backendRequiresLocalVarLifetimes() diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp index 206197a1102f2..320c1e7500854 100644 --- a/src/coreclr/jit/fginline.cpp +++ b/src/coreclr/jit/fginline.cpp @@ -1630,17 +1630,14 @@ Statement* Compiler::fgInlinePrependStatements(InlineInfo* inlineInfo) // For case (1) // - // Look for the following tree shapes - // prejit: (IND (ADD (CONST, CALL(special dce helper...)))) - // jit : (COMMA (CALL(special dce helper...), (FIELD ...))) - if (argNode->gtOper == GT_COMMA) + if (argNode->OperIs(GT_COMMA)) { // Look for (COMMA (CALL(special dce helper...), (FIELD ...))) - GenTree* op1 = argNode->AsOp()->gtOp1; - GenTree* op2 = argNode->AsOp()->gtOp2; + GenTree* op1 = argNode->gtGetOp1(); + GenTree* op2 = argNode->gtGetOp2(); if (op1->IsCall() && ((op1->AsCall()->gtCallMoreFlags & GTF_CALL_M_HELPER_SPECIAL_DCE) != 0) && - (op2->gtOper == GT_FIELD) && ((op2->gtFlags & GTF_EXCEPT) == 0)) + (op2->OperIs(GT_FIELD)) && ((op2->gtFlags & GTF_EXCEPT) == 0)) { JITDUMP("\nPerforming special dce on unused arg [%06u]:" " actual arg [%06u] helper call [%06u]\n", @@ -1649,27 +1646,6 @@ Statement* Compiler::fgInlinePrependStatements(InlineInfo* inlineInfo) append = false; } } - else if (argNode->gtOper == GT_IND) - { - // Look for (IND (ADD (CONST, CALL(special dce helper...)))) - GenTree* addr = argNode->AsOp()->gtOp1; - - if (addr->gtOper == GT_ADD) - { - GenTree* op1 = addr->AsOp()->gtOp1; - GenTree* op2 = addr->AsOp()->gtOp2; - if (op1->IsCall() && - ((op1->AsCall()->gtCallMoreFlags & GTF_CALL_M_HELPER_SPECIAL_DCE) != 0) && - op2->IsCnsIntOrI()) - { - // Drop the whole tree - JITDUMP("\nPerforming special dce on unused arg [%06u]:" - " actual arg [%06u] helper call [%06u]\n", - argNode->gtTreeID, argNode->gtTreeID, op1->gtTreeID); - append = false; - } - } - } } if (!append) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 2613df36930ad..c1244fb557869 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -793,6 +793,31 @@ GenTreeLclVar* Compiler::fgIsIndirOfAddrOfLocal(GenTree* tree) return res; } +//------------------------------------------------------------------------ +// fgIsCurrentCallDceCandidate: Determine whether the currently compiled method +// is a DCE candidate +// +// Returns: +// True if the currently compiled method can be removed if it's not used +// despite potential side-effects +// +bool Compiler::fgIsCurrentCallDceCandidate() +{ + // If we're importing the special EqualityComparer.Default or Comparer.Default + // intrinsics, flag the helper call. Later during inlining, we can + // remove the helper call if the associated field lookup is unused. + if ((info.compFlags & CORINFO_FLG_INTRINSIC) != 0) + { + NamedIntrinsic ni = lookupNamedIntrinsic(info.compMethodHnd); + if ((ni == NI_System_Collections_Generic_EqualityComparer_get_Default) || + (ni == NI_System_Collections_Generic_Comparer_get_Default)) + { + return true; + } + } + return false; +} + GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper) { bool bNeedClassID = true; @@ -891,18 +916,10 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo result->gtFlags |= callFlags; - // If we're importing the special EqualityComparer.Default or Comparer.Default - // intrinsics, flag the helper call. Later during inlining, we can - // remove the helper call if the associated field lookup is unused. - if ((info.compFlags & CORINFO_FLG_INTRINSIC) != 0) + if (fgIsCurrentCallDceCandidate()) { - NamedIntrinsic ni = lookupNamedIntrinsic(info.compMethodHnd); - if ((ni == NI_System_Collections_Generic_EqualityComparer_get_Default) || - (ni == NI_System_Collections_Generic_Comparer_get_Default)) - { - JITDUMP("\nmarking helper call [%06u] as special dce...\n", result->gtTreeID); - result->gtCallMoreFlags |= GTF_CALL_M_HELPER_SPECIAL_DCE; - } + JITDUMP("\nmarking helper call [%06u] as special dce...\n", result->gtTreeID); + result->gtCallMoreFlags |= GTF_CALL_M_HELPER_SPECIAL_DCE; } return result; diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 78336fed4a3e9..f6f77575e3480 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -9035,6 +9035,12 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT op1->gtFlags |= callFlags; op1->AsCall()->setEntryPoint(pFieldInfo->fieldLookup); + + if (fgIsCurrentCallDceCandidate()) + { + JITDUMP("\nmarking helper call [%06u] as special dce...\n", op1->gtTreeID); + op1->AsCall()->gtCallMoreFlags |= GTF_CALL_M_HELPER_SPECIAL_DCE; + } } else #endif @@ -9761,9 +9767,28 @@ var_types Compiler::impImportCall(OPCODE opcode, { // Null check is sometimes needed for ready to run to handle // non-virtual <-> virtual changes between versions + bool addNullcheck = true; if (callInfo->nullInstanceCheck) { - call->gtFlags |= GTF_CALL_NULLCHECK; + GenTree* thisArg = impStackTop(sig->numArgs).val; + if (thisArg->OperIs(GT_RET_EXPR)) + { + GenTreeCall* thisAsCall = thisArg->AsRetExpr()->gtInlineCandidate->AsCall(); + if (thisAsCall->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) + { + NamedIntrinsic ni = lookupNamedIntrinsic(thisAsCall->gtCallMethHnd); + if ((ni == NI_System_Collections_Generic_EqualityComparer_get_Default) || + (ni == NI_System_Collections_Generic_Comparer_get_Default)) + { + addNullcheck = false; + } + } + } + + if (addNullcheck) + { + call->gtFlags |= GTF_CALL_NULLCHECK; + } } } #endif