Skip to content

Commit a86987c

Browse files
authored
JIT: Remove GTF_IS_IN_CSE (#104855)
This flag is just a convoluted way to pass an argument through to a bunch of methods from inside CSE. That's because CSE tries to reuse `gtExtractSideEffList` even though it needs something more capable that considers CSE defs and CSE uses as well. Remove the flag in favor of an `ignoreCctors` flag in the side effect checking functions; then, additionally add a CSE-specific version of `gtExtractSideEffList` called `optExtractSideEffectsForCSE` which handles side effects and also CSE defs/uses. This does result in a slight amount of duplication, but I think that's beneficial over the convoluted logic before.
1 parent 5354e0f commit a86987c

File tree

4 files changed

+161
-124
lines changed

4 files changed

+161
-124
lines changed

src/coreclr/jit/compiler.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3648,10 +3648,10 @@ class Compiler
36483648
void gtSetStmtInfo(Statement* stmt);
36493649

36503650
// Returns "true" iff "node" has any of the side effects in "flags".
3651-
bool gtNodeHasSideEffects(GenTree* node, GenTreeFlags flags);
3651+
bool gtNodeHasSideEffects(GenTree* node, GenTreeFlags flags, bool ignoreCctors = false);
36523652

36533653
// Returns "true" iff "tree" or its (transitive) children have any of the side effects in "flags".
3654-
bool gtTreeHasSideEffects(GenTree* tree, GenTreeFlags flags);
3654+
bool gtTreeHasSideEffects(GenTree* tree, GenTreeFlags flags, bool ignoreCctors = false);
36553655

36563656
void gtExtractSideEffList(GenTree* expr,
36573657
GenTree** pList,
@@ -7251,6 +7251,7 @@ class Compiler
72517251
void optValnumCSE_DataFlow();
72527252
void optValnumCSE_Availability();
72537253
void optValnumCSE_Heuristic(CSE_HeuristicCommon* heuristic);
7254+
GenTree* optExtractSideEffectsForCSE(GenTree* tree);
72547255

72557256
bool optDoCSE; // True when we have found a duplicate CSE tree
72567257
bool optValnumCSE_phase; // True when we are executing the optOptimizeValnumCSEs() phase

src/coreclr/jit/gentree.cpp

Lines changed: 49 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -16609,7 +16609,7 @@ GenTree* Compiler::gtNewRefCOMfield(GenTree* objPtr,
1660916609
* It may return false even if the node has GTF_SIDE_EFFECT (because of its children).
1661016610
*/
1661116611

16612-
bool Compiler::gtNodeHasSideEffects(GenTree* tree, GenTreeFlags flags)
16612+
bool Compiler::gtNodeHasSideEffects(GenTree* tree, GenTreeFlags flags, bool ignoreCctors)
1661316613
{
1661416614
if (flags & GTF_ASG)
1661516615
{
@@ -16636,20 +16636,20 @@ bool Compiler::gtNodeHasSideEffects(GenTree* tree, GenTreeFlags flags)
1663616636
{
1663716637
GenTreeCall* const call = potentialCall->AsCall();
1663816638
const bool ignoreExceptions = (flags & GTF_EXCEPT) == 0;
16639-
const bool ignoreCctors = (flags & GTF_IS_IN_CSE) != 0; // We can CSE helpers that run cctors.
1664016639
if (!call->HasSideEffects(this, ignoreExceptions, ignoreCctors))
1664116640
{
1664216641
// If this call is otherwise side effect free, check its arguments.
1664316642
for (CallArg& arg : call->gtArgs.Args())
1664416643
{
1664516644
// I'm a little worried that args that assign to temps that are late args will look like
1664616645
// side effects...but better to be conservative for now.
16647-
if ((arg.GetEarlyNode() != nullptr) && gtTreeHasSideEffects(arg.GetEarlyNode(), flags))
16646+
if ((arg.GetEarlyNode() != nullptr) &&
16647+
gtTreeHasSideEffects(arg.GetEarlyNode(), flags, ignoreCctors))
1664816648
{
1664916649
return true;
1665016650
}
1665116651

16652-
if ((arg.GetLateNode() != nullptr) && gtTreeHasSideEffects(arg.GetLateNode(), flags))
16652+
if ((arg.GetLateNode() != nullptr) && gtTreeHasSideEffects(arg.GetLateNode(), flags, ignoreCctors))
1665316653
{
1665416654
return true;
1665516655
}
@@ -16686,7 +16686,7 @@ bool Compiler::gtNodeHasSideEffects(GenTree* tree, GenTreeFlags flags)
1668616686
* Returns true if the expr tree has any side effects.
1668716687
*/
1668816688

16689-
bool Compiler::gtTreeHasSideEffects(GenTree* tree, GenTreeFlags flags /* = GTF_SIDE_EFFECT*/)
16689+
bool Compiler::gtTreeHasSideEffects(GenTree* tree, GenTreeFlags flags /* = GTF_SIDE_EFFECT*/, bool ignoreCctors)
1669016690
{
1669116691
// These are the side effect flags that we care about for this tree
1669216692
GenTreeFlags sideEffectFlags = tree->gtFlags & flags;
@@ -16709,22 +16709,22 @@ bool Compiler::gtTreeHasSideEffects(GenTree* tree, GenTreeFlags flags /* = GTF_S
1670916709
// If this node is a helper call we may not care about the side-effects.
1671016710
// Note that gtNodeHasSideEffects checks the side effects of the helper itself
1671116711
// as well as the side effects of its arguments.
16712-
return gtNodeHasSideEffects(tree, flags);
16712+
return gtNodeHasSideEffects(tree, flags, ignoreCctors);
1671316713
}
1671416714
}
1671516715
else if (tree->OperGet() == GT_INTRINSIC)
1671616716
{
16717-
if (gtNodeHasSideEffects(tree, flags))
16717+
if (gtNodeHasSideEffects(tree, flags, ignoreCctors))
1671816718
{
1671916719
return true;
1672016720
}
1672116721

16722-
if (gtNodeHasSideEffects(tree->AsOp()->gtOp1, flags))
16722+
if (gtNodeHasSideEffects(tree->AsOp()->gtOp1, flags, ignoreCctors))
1672316723
{
1672416724
return true;
1672516725
}
1672616726

16727-
if ((tree->AsOp()->gtOp2 != nullptr) && gtNodeHasSideEffects(tree->AsOp()->gtOp2, flags))
16727+
if ((tree->AsOp()->gtOp2 != nullptr) && gtNodeHasSideEffects(tree->AsOp()->gtOp2, flags, ignoreCctors))
1672816728
{
1672916729
return true;
1673016730
}
@@ -17110,81 +17110,61 @@ void Compiler::gtExtractSideEffList(GenTree* expr,
1711017110
{
1711117111
GenTree* node = *use;
1711217112

17113-
bool treeHasSideEffects = m_compiler->gtTreeHasSideEffects(node, m_flags);
17113+
if (!m_compiler->gtTreeHasSideEffects(node, m_flags))
17114+
{
17115+
return Compiler::WALK_SKIP_SUBTREES;
17116+
}
1711417117

17115-
if (treeHasSideEffects)
17118+
if (m_compiler->gtNodeHasSideEffects(node, m_flags))
1711617119
{
17117-
if (m_compiler->gtNodeHasSideEffects(node, m_flags))
17120+
if (node->OperIsBlk() && !node->OperIsStoreBlk())
1711817121
{
17119-
if (node->OperIsBlk() && !node->OperIsStoreBlk())
17120-
{
17121-
JITDUMP("Replace an unused BLK node [%06d] with a NULLCHECK\n", dspTreeID(node));
17122-
m_compiler->gtChangeOperToNullCheck(node, m_compiler->compCurBB);
17123-
}
17124-
17125-
Append(node);
17126-
return Compiler::WALK_SKIP_SUBTREES;
17122+
JITDUMP("Replace an unused BLK node [%06d] with a NULLCHECK\n", dspTreeID(node));
17123+
m_compiler->gtChangeOperToNullCheck(node, m_compiler->compCurBB);
1712717124
}
1712817125

17129-
if (node->OperIs(GT_QMARK))
17130-
{
17131-
GenTree* prevSideEffects = m_result;
17132-
// Visit children out of order so we know if we can
17133-
// completely remove the qmark. We cannot modify the
17134-
// condition if we cannot completely remove the qmark, so
17135-
// we cannot visit it first.
17126+
Append(node);
17127+
return Compiler::WALK_SKIP_SUBTREES;
17128+
}
1713617129

17137-
GenTreeQmark* qmark = node->AsQmark();
17138-
GenTreeColon* colon = qmark->gtGetOp2()->AsColon();
17130+
if (node->OperIs(GT_QMARK))
17131+
{
17132+
GenTree* prevSideEffects = m_result;
17133+
// Visit children out of order so we know if we can
17134+
// completely remove the qmark. We cannot modify the
17135+
// condition if we cannot completely remove the qmark, so
17136+
// we cannot visit it first.
1713917137

17140-
m_result = nullptr;
17141-
WalkTree(&colon->gtOp1, colon);
17142-
GenTree* thenSideEffects = m_result;
17138+
GenTreeQmark* qmark = node->AsQmark();
17139+
GenTreeColon* colon = qmark->gtGetOp2()->AsColon();
1714317140

17144-
m_result = nullptr;
17145-
WalkTree(&colon->gtOp2, colon);
17146-
GenTree* elseSideEffects = m_result;
17141+
m_result = nullptr;
17142+
WalkTree(&colon->gtOp1, colon);
17143+
GenTree* thenSideEffects = m_result;
1714717144

17148-
m_result = prevSideEffects;
17145+
m_result = nullptr;
17146+
WalkTree(&colon->gtOp2, colon);
17147+
GenTree* elseSideEffects = m_result;
1714917148

17150-
if ((thenSideEffects == nullptr) && (elseSideEffects == nullptr))
17151-
{
17152-
WalkTree(&qmark->gtOp1, qmark);
17153-
}
17154-
else
17155-
{
17156-
colon->gtOp1 = (thenSideEffects != nullptr) ? thenSideEffects : m_compiler->gtNewNothingNode();
17157-
colon->gtOp2 = (elseSideEffects != nullptr) ? elseSideEffects : m_compiler->gtNewNothingNode();
17158-
qmark->gtType = TYP_VOID;
17159-
colon->gtType = TYP_VOID;
17160-
Append(qmark);
17161-
}
17149+
m_result = prevSideEffects;
1716217150

17163-
return Compiler::WALK_SKIP_SUBTREES;
17151+
if ((thenSideEffects == nullptr) && (elseSideEffects == nullptr))
17152+
{
17153+
WalkTree(&qmark->gtOp1, qmark);
1716417154
}
17165-
17166-
// Generally all GT_CALL nodes are considered to have side-effects.
17167-
// So if we get here it must be a helper call that we decided it does
17168-
// not have side effects that we needed to keep.
17169-
assert(!node->OperIs(GT_CALL) || node->AsCall()->IsHelperCall());
17170-
}
17171-
17172-
if ((m_flags & GTF_IS_IN_CSE) != 0)
17173-
{
17174-
// If we're doing CSE then we also need to unmark CSE nodes. This will fail for CSE defs,
17175-
// those need to be extracted as if they're side effects.
17176-
if (!UnmarkCSE(node))
17155+
else
1717717156
{
17178-
Append(node);
17179-
return Compiler::WALK_SKIP_SUBTREES;
17157+
colon->gtOp1 = (thenSideEffects != nullptr) ? thenSideEffects : m_compiler->gtNewNothingNode();
17158+
colon->gtOp2 = (elseSideEffects != nullptr) ? elseSideEffects : m_compiler->gtNewNothingNode();
17159+
qmark->gtType = TYP_VOID;
17160+
colon->gtType = TYP_VOID;
17161+
Append(qmark);
1718017162
}
1718117163

17182-
// The existence of CSE defs and uses is not propagated up the tree like side
17183-
// effects are. We need to continue visiting the tree as if it has side effects.
17184-
treeHasSideEffects = true;
17164+
return Compiler::WALK_SKIP_SUBTREES;
1718517165
}
1718617166

17187-
return treeHasSideEffects ? Compiler::WALK_CONTINUE : Compiler::WALK_SKIP_SUBTREES;
17167+
return Compiler::WALK_CONTINUE;
1718817168
}
1718917169

1719017170
void Append(GenTree* node)
@@ -17196,7 +17176,6 @@ void Compiler::gtExtractSideEffList(GenTree* expr,
1719617176
}
1719717177

1719817178
GenTree* comma = m_compiler->gtNewOperNode(GT_COMMA, TYP_VOID, m_result, node);
17199-
comma->gtFlags |= (m_result->gtFlags | node->gtFlags) & GTF_ALL_EFFECT;
1720017179

1720117180
#ifdef DEBUG
1720217181
if (m_compiler->fgGlobalMorph)
@@ -17218,52 +17197,12 @@ void Compiler::gtExtractSideEffList(GenTree* expr,
1721817197
//
1721917198
if ((m_compiler->vnStore != nullptr) && m_result->gtVNPair.BothDefined() && node->gtVNPair.BothDefined())
1722017199
{
17221-
// The result of a GT_COMMA node is op2, the normal value number is op2vnp
17222-
// But we also need to include the union of side effects from op1 and op2.
17223-
// we compute this value into exceptions_vnp.
17224-
ValueNumPair op1vnp;
17225-
ValueNumPair op1Xvnp = ValueNumStore::VNPForEmptyExcSet();
17226-
ValueNumPair op2vnp;
17227-
ValueNumPair op2Xvnp = ValueNumStore::VNPForEmptyExcSet();
17228-
17229-
m_compiler->vnStore->VNPUnpackExc(node->gtVNPair, &op1vnp, &op1Xvnp);
17230-
m_compiler->vnStore->VNPUnpackExc(m_result->gtVNPair, &op2vnp, &op2Xvnp);
17231-
17232-
ValueNumPair exceptions_vnp = ValueNumStore::VNPForEmptyExcSet();
17233-
17234-
exceptions_vnp = m_compiler->vnStore->VNPExcSetUnion(exceptions_vnp, op1Xvnp);
17235-
exceptions_vnp = m_compiler->vnStore->VNPExcSetUnion(exceptions_vnp, op2Xvnp);
17236-
17237-
comma->gtVNPair = m_compiler->vnStore->VNPWithExc(op2vnp, exceptions_vnp);
17200+
ValueNumPair op1Exceptions = m_compiler->vnStore->VNPExceptionSet(m_result->gtVNPair);
17201+
comma->gtVNPair = m_compiler->vnStore->VNPWithExc(node->gtVNPair, op1Exceptions);
1723817202
}
1723917203

1724017204
m_result = comma;
1724117205
}
17242-
17243-
private:
17244-
bool UnmarkCSE(GenTree* node)
17245-
{
17246-
assert(m_compiler->optValnumCSE_phase);
17247-
17248-
if (m_compiler->optUnmarkCSE(node))
17249-
{
17250-
// The call to optUnmarkCSE(node) should have cleared any CSE info.
17251-
assert(!IS_CSE_INDEX(node->gtCSEnum));
17252-
return true;
17253-
}
17254-
else
17255-
{
17256-
assert(IS_CSE_DEF(node->gtCSEnum));
17257-
#ifdef DEBUG
17258-
if (m_compiler->verbose)
17259-
{
17260-
printf("Preserving the CSE def #%02d at ", GET_CSE_INDEX(node->gtCSEnum));
17261-
m_compiler->printTreeID(node);
17262-
}
17263-
#endif
17264-
return false;
17265-
}
17266-
}
1726717206
};
1726817207

1726917208
SideEffectExtractor extractor(this, flags);

src/coreclr/jit/gentree.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -404,15 +404,6 @@ enum GenTreeFlags : unsigned int
404404
// With operators: the specified node is an unsigned operator
405405
GTF_SPILL = 0x00020000, // Needs to be spilled here
406406

407-
// The extra flag GTF_IS_IN_CSE is used to tell the consumer of the side effect flags
408-
// that we are calling in the context of performing a CSE, thus we
409-
// should allow the run-once side effects of running a class constructor.
410-
//
411-
// The only requirement of this flag is that it not overlap any of the
412-
// side-effect flags. The actual bit used is otherwise arbitrary.
413-
414-
GTF_IS_IN_CSE = 0x00004000,
415-
416407
GTF_COMMON_MASK = 0x0003FFFF, // mask of all the flags above
417408

418409
GTF_REUSE_REG_VAL = 0x00800000, // This is set by the register allocator on nodes whose value already exists in the

0 commit comments

Comments
 (0)