@@ -7273,82 +7273,14 @@ GenTree* Compiler::gtCloneExpr(
72737273
72747274 case GT_CALL:
72757275
7276- copy = new (this, GT_CALL) GenTreeCall(tree->TypeGet());
7277-
7278- copy->gtCall.gtCallObjp = tree->gtCall.gtCallObjp
7279- ? gtCloneExpr(tree->gtCall.gtCallObjp, addFlags, deepVarNum, deepVarVal)
7280- : nullptr;
7281- copy->gtCall.gtCallArgs =
7282- tree->gtCall.gtCallArgs
7283- ? gtCloneExpr(tree->gtCall.gtCallArgs, addFlags, deepVarNum, deepVarVal)->AsArgList()
7284- : nullptr;
7285- copy->gtCall.gtCallMoreFlags = tree->gtCall.gtCallMoreFlags;
7286- copy->gtCall.gtCallLateArgs =
7287- tree->gtCall.gtCallLateArgs
7288- ? gtCloneExpr(tree->gtCall.gtCallLateArgs, addFlags, deepVarNum, deepVarVal)->AsArgList()
7289- : nullptr;
7290-
7291- #if !FEATURE_FIXED_OUT_ARGS
7292- copy->gtCall.regArgList = tree->gtCall.regArgList;
7293- copy->gtCall.regArgListCount = tree->gtCall.regArgListCount;
7294- #endif
7295-
7296- // The call sig comes from the EE and doesn't change throughout the compilation process, meaning
7297- // we only really need one physical copy of it. Therefore a shallow pointer copy will suffice.
7298- // (Note that this still holds even if the tree we are cloning was created by an inlinee compiler,
7299- // because the inlinee still uses the inliner's memory allocator anyway.)
7300- copy->gtCall.callSig = tree->gtCall.callSig;
7301-
7302- copy->gtCall.gtCallType = tree->gtCall.gtCallType;
7303- copy->gtCall.gtReturnType = tree->gtCall.gtReturnType;
7304- copy->gtCall.gtControlExpr = tree->gtCall.gtControlExpr;
7305-
7306- /* Copy the union */
7307- if (tree->gtCall.gtCallType == CT_INDIRECT)
7308- {
7309- copy->gtCall.gtCallCookie =
7310- tree->gtCall.gtCallCookie ? gtCloneExpr(tree->gtCall.gtCallCookie, addFlags, deepVarNum, deepVarVal)
7311- : nullptr;
7312- copy->gtCall.gtCallAddr = tree->gtCall.gtCallAddr
7313- ? gtCloneExpr(tree->gtCall.gtCallAddr, addFlags, deepVarNum, deepVarVal)
7314- : nullptr;
7315- }
7316- else if (tree->gtCall.IsVirtualStub())
7317- {
7318- copy->gtCall.gtCallMethHnd = tree->gtCall.gtCallMethHnd;
7319- copy->gtCall.gtStubCallStubAddr = tree->gtCall.gtStubCallStubAddr;
7320- }
7321- else
7276+ // We can't safely clone calls that have GT_RET_EXPRs via gtCloneExpr.
7277+ // You must use gtCloneCandidateCall for these calls (and then do appropriate other fixup)
7278+ if (tree->gtCall.IsInlineCandidate() || tree->gtCall.IsGuardedDevirtualizationCandidate())
73227279 {
7323- copy->gtCall.gtCallMethHnd = tree->gtCall.gtCallMethHnd;
7324- copy->gtCall.gtInlineCandidateInfo = tree->gtCall.gtInlineCandidateInfo;
7280+ NO_WAY("Cloning of calls with associated GT_RET_EXPR nodes is not supported");
73257281 }
73267282
7327- if (tree->gtCall.fgArgInfo)
7328- {
7329- // Create and initialize the fgArgInfo for our copy of the call tree
7330- copy->gtCall.fgArgInfo = new (this, CMK_Unknown) fgArgInfo(copy->AsCall(), tree->AsCall());
7331- }
7332- else
7333- {
7334- copy->gtCall.fgArgInfo = nullptr;
7335- }
7336- copy->gtCall.gtRetClsHnd = tree->gtCall.gtRetClsHnd;
7337-
7338- #if FEATURE_MULTIREG_RET
7339- copy->gtCall.gtReturnTypeDesc = tree->gtCall.gtReturnTypeDesc;
7340- #endif
7341-
7342- #ifdef FEATURE_READYTORUN_COMPILER
7343- copy->gtCall.setEntryPoint(tree->gtCall.gtEntryPoint);
7344- #endif
7345-
7346- #if defined(DEBUG) || defined(INLINE_DATA)
7347- copy->gtCall.gtInlineObservation = tree->gtCall.gtInlineObservation;
7348- copy->gtCall.gtRawILOffset = tree->gtCall.gtRawILOffset;
7349- #endif
7350-
7351- copy->AsCall()->CopyOtherRegFlags(tree->AsCall());
7283+ copy = gtCloneExprCallHelper(tree->AsCall(), addFlags, deepVarNum, deepVarVal);
73527284 break;
73537285
73547286 case GT_FIELD:
@@ -7486,6 +7418,131 @@ GenTree* Compiler::gtCloneExpr(
74867418 return copy;
74877419}
74887420
7421+ //------------------------------------------------------------------------
7422+ // gtCloneExprCallHelper: clone a call tree
7423+ //
7424+ // Notes:
7425+ // Do not invoke this method directly, instead call either gtCloneExpr
7426+ // or gtCloneCandidateCall, as appropriate.
7427+ //
7428+ // Arguments:
7429+ // tree - the call to clone
7430+ // addFlags - GTF_* flags to add to the copied tree nodes
7431+ // deepVarNum - lclNum to replace uses of beyond the root, or BAD_VAR_NUM for no replacement
7432+ // deepVarVal - If replacing beyond root, replace `deepVarNum` with IntCns `deepVarVal`
7433+ //
7434+ // Returns:
7435+ // Cloned copy of call and all subtrees.
7436+
7437+ GenTreeCall* Compiler::gtCloneExprCallHelper(GenTreeCall* tree, unsigned addFlags, unsigned deepVarNum, int deepVarVal)
7438+ {
7439+ GenTreeCall* copy = new (this, GT_CALL) GenTreeCall(tree->TypeGet());
7440+
7441+ copy->gtCallObjp = tree->gtCallObjp ? gtCloneExpr(tree->gtCallObjp, addFlags, deepVarNum, deepVarVal) : nullptr;
7442+ copy->gtCallArgs =
7443+ tree->gtCallArgs ? gtCloneExpr(tree->gtCallArgs, addFlags, deepVarNum, deepVarVal)->AsArgList() : nullptr;
7444+ copy->gtCallMoreFlags = tree->gtCallMoreFlags;
7445+ copy->gtCallLateArgs = tree->gtCallLateArgs
7446+ ? gtCloneExpr(tree->gtCallLateArgs, addFlags, deepVarNum, deepVarVal)->AsArgList()
7447+ : nullptr;
7448+
7449+ #if !FEATURE_FIXED_OUT_ARGS
7450+ copy->regArgList = tree->regArgList;
7451+ copy->regArgListCount = tree->regArgListCount;
7452+ #endif
7453+
7454+ // The call sig comes from the EE and doesn't change throughout the compilation process, meaning
7455+ // we only really need one physical copy of it. Therefore a shallow pointer copy will suffice.
7456+ // (Note that this still holds even if the tree we are cloning was created by an inlinee compiler,
7457+ // because the inlinee still uses the inliner's memory allocator anyway.)
7458+ copy->callSig = tree->callSig;
7459+
7460+ copy->gtCallType = tree->gtCallType;
7461+ copy->gtReturnType = tree->gtReturnType;
7462+ copy->gtControlExpr = tree->gtControlExpr;
7463+
7464+ /* Copy the union */
7465+ if (tree->gtCallType == CT_INDIRECT)
7466+ {
7467+ copy->gtCallCookie =
7468+ tree->gtCallCookie ? gtCloneExpr(tree->gtCallCookie, addFlags, deepVarNum, deepVarVal) : nullptr;
7469+ copy->gtCallAddr = tree->gtCallAddr ? gtCloneExpr(tree->gtCallAddr, addFlags, deepVarNum, deepVarVal) : nullptr;
7470+ }
7471+ else if (tree->IsVirtualStub())
7472+ {
7473+ copy->gtCallMethHnd = tree->gtCallMethHnd;
7474+ copy->gtStubCallStubAddr = tree->gtStubCallStubAddr;
7475+ }
7476+ else
7477+ {
7478+ copy->gtCallMethHnd = tree->gtCallMethHnd;
7479+ copy->gtInlineCandidateInfo = nullptr;
7480+ }
7481+
7482+ if (tree->fgArgInfo)
7483+ {
7484+ // Create and initialize the fgArgInfo for our copy of the call tree
7485+ copy->fgArgInfo = new (this, CMK_Unknown) fgArgInfo(copy, tree);
7486+ }
7487+ else
7488+ {
7489+ copy->fgArgInfo = nullptr;
7490+ }
7491+
7492+ copy->gtRetClsHnd = tree->gtRetClsHnd;
7493+
7494+ #if FEATURE_MULTIREG_RET
7495+ copy->gtReturnTypeDesc = tree->gtReturnTypeDesc;
7496+ #endif
7497+
7498+ #ifdef FEATURE_READYTORUN_COMPILER
7499+ copy->setEntryPoint(tree->gtEntryPoint);
7500+ #endif
7501+
7502+ #if defined(DEBUG) || defined(INLINE_DATA)
7503+ copy->gtInlineObservation = tree->gtInlineObservation;
7504+ copy->gtRawILOffset = tree->gtCall.gtRawILOffset;
7505+ #endif
7506+
7507+ copy->CopyOtherRegFlags(tree);
7508+
7509+ return copy;
7510+ }
7511+
7512+ //------------------------------------------------------------------------
7513+ // gtCloneCandidateCall: clone a call that is an inline or guarded
7514+ // devirtualization candidate (~ any call that can have a GT_RET_EXPR)
7515+ //
7516+ // Notes:
7517+ // If the call really is a candidate, the caller must take additional steps
7518+ // after cloning to re-establish candidate info and the relationship between
7519+ // the candidate and any associated GT_RET_EXPR.
7520+ //
7521+ // Arguments:
7522+ // call - the call to clone
7523+ //
7524+ // Returns:
7525+ // Cloned copy of call and all subtrees.
7526+
7527+ GenTreeCall* Compiler::gtCloneCandidateCall(GenTreeCall* call)
7528+ {
7529+ assert(call->IsInlineCandidate() || call->IsGuardedDevirtualizationCandidate());
7530+
7531+ GenTreeCall* result = gtCloneExprCallHelper(call);
7532+
7533+ // There is some common post-processing in gtCloneExpr that we reproduce
7534+ // here, for the fields that make sense for candidate calls.
7535+ result->gtFlags |= call->gtFlags;
7536+
7537+ #if defined(DEBUG)
7538+ result->gtDebugFlags |= (call->gtDebugFlags & ~GTF_DEBUG_NODE_MASK);
7539+ #endif
7540+
7541+ result->CopyReg(call);
7542+
7543+ return result;
7544+ }
7545+
74897546//------------------------------------------------------------------------
74907547// gtReplaceTree: Replace a tree with a new tree.
74917548//
@@ -12079,7 +12136,7 @@ GenTree* Compiler::gtFoldTypeCompare(GenTree* tree)
1207912136 // Compare the two method tables
1208012137 GenTree* const compare = gtCreateHandleCompare(oper, objMT, knownMT, typeCheckInliningResult);
1208112138
12082- // Drop any any now irrelevant flags
12139+ // Drop any now irrelevant flags
1208312140 compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
1208412141
1208512142 // And we're done
0 commit comments