Skip to content

Commit 15e96fa

Browse files
authored
JIT: Fix gtNodeHasSideEffects checking call arguments (#106185)
`gtNodeHasSideEffects` is meant to check if a node has side effects when you exclude its children. However, it was checking arguments of calls which is more conservative than expected. The actual reason we were doing that seems to be `gtTreeHasSideEffects` that sometimes wants to ignore `GTF_CALL` on pure helper calls. It was relying on this check in `gtNodeHasSideEffect`; instead move it to `gtTreeHasSideEffects` where it belongs. This is an alternative fix for #106129; there we leave a `COMMA(CORINFO_HELP_RUNTIMELOOKUP_METHOD, ...)` around because extracting side effects from op1 does not end up getting rid of the call. Fix #106129
1 parent c1ab6c5 commit 15e96fa

File tree

3 files changed

+26
-40
lines changed

3 files changed

+26
-40
lines changed

src/coreclr/jit/assertionprop.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6254,13 +6254,7 @@ GenTree* Compiler::optExtractSideEffListFromConst(GenTree* tree)
62546254
// Do a sanity check to ensure persistent side effects aren't discarded and
62556255
// tell gtExtractSideEffList to ignore the root of the tree.
62566256
// We are relying here on an invariant that VN will only fold non-throwing expressions.
6257-
const bool ignoreExceptions = true;
6258-
const bool ignoreCctors = false;
6259-
// We have to check "AsCall()->HasSideEffects()" here separately because "gtNodeHasSideEffects"
6260-
// also checks for side effects that arguments introduce (incosistently so, it otherwise only
6261-
// checks for the side effects the node itself has). TODO-Cleanup: change it to not do that?
6262-
assert(!gtNodeHasSideEffects(tree, GTF_PERSISTENT_SIDE_EFFECTS) ||
6263-
(tree->IsCall() && !tree->AsCall()->HasSideEffects(this, ignoreExceptions, ignoreCctors)));
6257+
assert(!gtNodeHasSideEffects(tree, GTF_PERSISTENT_SIDE_EFFECTS));
62646258

62656259
// Exception side effects may be ignored because the root is known to be a constant
62666260
// (e.g. VN may evaluate a DIV/MOD node to a constant and the node may still

src/coreclr/jit/gentree.cpp

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16828,31 +16828,7 @@ bool Compiler::gtNodeHasSideEffects(GenTree* tree, GenTreeFlags flags, bool igno
1682816828
{
1682916829
GenTreeCall* const call = potentialCall->AsCall();
1683016830
const bool ignoreExceptions = (flags & GTF_EXCEPT) == 0;
16831-
if (!call->HasSideEffects(this, ignoreExceptions, ignoreCctors))
16832-
{
16833-
// If this call is otherwise side effect free, check its arguments.
16834-
for (CallArg& arg : call->gtArgs.Args())
16835-
{
16836-
// I'm a little worried that args that assign to temps that are late args will look like
16837-
// side effects...but better to be conservative for now.
16838-
if ((arg.GetEarlyNode() != nullptr) &&
16839-
gtTreeHasSideEffects(arg.GetEarlyNode(), flags, ignoreCctors))
16840-
{
16841-
return true;
16842-
}
16843-
16844-
if ((arg.GetLateNode() != nullptr) && gtTreeHasSideEffects(arg.GetLateNode(), flags, ignoreCctors))
16845-
{
16846-
return true;
16847-
}
16848-
}
16849-
16850-
// Otherwise:
16851-
return false;
16852-
}
16853-
16854-
// Otherwise the GT_CALL is considered to have side-effects.
16855-
return true;
16831+
return call->HasSideEffects(this, ignoreExceptions, ignoreCctors);
1685616832
}
1685716833
}
1685816834

@@ -16892,19 +16868,30 @@ bool Compiler::gtTreeHasSideEffects(GenTree* tree, GenTreeFlags flags /* = GTF_S
1689216868

1689316869
if (sideEffectFlags == GTF_CALL)
1689416870
{
16895-
if (tree->OperGet() == GT_CALL)
16871+
if (tree->IsHelperCall())
1689616872
{
1689716873
// Generally all trees that contain GT_CALL nodes are considered to have side-effects.
16898-
//
16899-
if (tree->AsCall()->IsHelperCall())
16874+
// However, for some pure helper calls we lie about this.
16875+
if (gtNodeHasSideEffects(tree, flags, ignoreCctors))
1690016876
{
16901-
// If this node is a helper call we may not care about the side-effects.
16902-
// Note that gtNodeHasSideEffects checks the side effects of the helper itself
16903-
// as well as the side effects of its arguments.
16904-
return gtNodeHasSideEffects(tree, flags, ignoreCctors);
16877+
return true;
1690516878
}
16879+
16880+
// The GTF_CALL may be contributed by an operand, so check for
16881+
// that.
16882+
bool hasCallInOperand = false;
16883+
tree->VisitOperands([=, &hasCallInOperand](GenTree* op) {
16884+
if (gtTreeHasSideEffects(op, GTF_CALL, ignoreCctors))
16885+
{
16886+
hasCallInOperand = true;
16887+
return GenTree::VisitResult::Abort;
16888+
}
16889+
return GenTree::VisitResult::Continue;
16890+
});
16891+
16892+
return hasCallInOperand;
1690616893
}
16907-
else if (tree->OperGet() == GT_INTRINSIC)
16894+
else if (tree->OperIs(GT_INTRINSIC))
1690816895
{
1690916896
if (gtNodeHasSideEffects(tree, flags, ignoreCctors))
1691016897
{

src/coreclr/jit/morph.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,13 +1666,16 @@ void CallArgs::EvalArgsToTemps(Compiler* comp, GenTreeCall* call)
16661666
unsigned tmpVarNum = comp->lvaGrabTemp(true DEBUGARG("argument with side effect"));
16671667
GenTree* store = comp->gtNewTempStore(tmpVarNum, use.GetNode());
16681668

1669+
INDEBUG(store->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED);
1670+
16691671
if (setupArg == nullptr)
16701672
{
16711673
setupArg = store;
16721674
}
16731675
else
16741676
{
16751677
setupArg = comp->gtNewOperNode(GT_COMMA, TYP_VOID, setupArg, store);
1678+
INDEBUG(setupArg->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED);
16761679
}
16771680

16781681
use.SetNode(comp->gtNewLclvNode(tmpVarNum, genActualType(use.GetNode())));
@@ -1688,6 +1691,8 @@ void CallArgs::EvalArgsToTemps(Compiler* comp, GenTreeCall* call)
16881691

16891692
setupArg = comp->gtNewTempStore(tmpVarNum, argx);
16901693

1694+
INDEBUG(setupArg->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED);
1695+
16911696
LclVarDsc* varDsc = comp->lvaGetDesc(tmpVarNum);
16921697
var_types lclVarType = genActualType(argx->gtType);
16931698
var_types scalarType = TYP_UNKNOWN;

0 commit comments

Comments
 (0)