Skip to content

Commit db27700

Browse files
authored
JIT: Add a gtFindNodeInTree helper (dotnet#115975)
Add a gtFindNodeInTree helper to find a node in a tree matching a predicate, and use it in a couple of places
1 parent 2a47838 commit db27700

File tree

5 files changed

+88
-123
lines changed

5 files changed

+88
-123
lines changed

src/coreclr/jit/compiler.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6161,8 +6161,6 @@ class Compiler
61616161
PhaseStatus fgHeadTailMerge(bool early);
61626162
bool fgHeadMerge(BasicBlock* block, bool early);
61636163
bool fgTryOneHeadMerge(BasicBlock* block, bool early);
6164-
template<typename Predicate>
6165-
bool gtTreeContainsCall(GenTree* tree, Predicate pred);
61666164
bool gtTreeContainsTailCall(GenTree* tree);
61676165
bool gtTreeContainsAsyncCall(GenTree* tree);
61686166
bool fgCanMoveFirstStatementIntoPred(bool early, Statement* firstStmt, BasicBlock* pred);
@@ -6914,6 +6912,9 @@ class Compiler
69146912
bool gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call);
69156913
bool gtIsTypeHandleToRuntimeTypeHandleHelper(GenTreeCall* call, CorInfoHelpFunc* pHelper = nullptr);
69166914

6915+
template<GenTreeFlags RequiredFlagsToDescendIntoTree, typename Predicate>
6916+
GenTree* gtFindNodeInTree(GenTree* tree, Predicate predicate);
6917+
69176918
bool gtTreeContainsOper(GenTree* tree, genTreeOps op);
69186919
ExceptionSetFlags gtCollectExceptions(GenTree* tree);
69196920

src/coreclr/jit/compiler.hpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2199,6 +2199,74 @@ inline bool GenTree::gtOverflowEx() const
21992199
return OperMayOverflow() && gtOverflow();
22002200
}
22012201

2202+
//------------------------------------------------------------------------
2203+
// gtFindNodeInTree:
2204+
// Check if a tree contains a node matching the specified predicate. Descend
2205+
// only into subtrees with the specified flags set on them (can be GTF_EMPTY
2206+
// to descend into all nodes).
2207+
//
2208+
// Type parameters:
2209+
// RequiredFlagsToDescendIntoNode - Flags that must be set on the node to
2210+
// descend into it (GTF_EMPTY to descend into all nodes)
2211+
// Predicate - Type of the predicate (GenTree* -> bool)
2212+
//
2213+
// Parameters:
2214+
// tree - The tree
2215+
// pred - Predicate that the call must match
2216+
//
2217+
// Returns:
2218+
// Node matching the predicate, or nullptr if no such node was found.
2219+
//
2220+
template <GenTreeFlags RequiredFlagsToDescendIntoNode, typename Predicate>
2221+
GenTree* Compiler::gtFindNodeInTree(GenTree* tree, Predicate pred)
2222+
{
2223+
struct FindNodeVisitor : GenTreeVisitor<FindNodeVisitor>
2224+
{
2225+
private:
2226+
Predicate& m_pred;
2227+
2228+
public:
2229+
GenTree* Result = nullptr;
2230+
2231+
enum
2232+
{
2233+
DoPreOrder = true
2234+
};
2235+
2236+
FindNodeVisitor(Compiler* comp, Predicate& pred)
2237+
: GenTreeVisitor<FindNodeVisitor>(comp)
2238+
, m_pred(pred)
2239+
{
2240+
}
2241+
2242+
fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
2243+
{
2244+
GenTree* node = *use;
2245+
if ((node->gtFlags & RequiredFlagsToDescendIntoNode) != RequiredFlagsToDescendIntoNode)
2246+
{
2247+
return WALK_SKIP_SUBTREES;
2248+
}
2249+
2250+
if (m_pred(node))
2251+
{
2252+
Result = node;
2253+
return WALK_ABORT;
2254+
}
2255+
2256+
return WALK_CONTINUE;
2257+
}
2258+
};
2259+
2260+
if ((tree->gtFlags & RequiredFlagsToDescendIntoNode) != RequiredFlagsToDescendIntoNode)
2261+
{
2262+
return nullptr;
2263+
}
2264+
2265+
FindNodeVisitor findNode(this, pred);
2266+
findNode.WalkTree(&tree, nullptr);
2267+
return findNode.Result;
2268+
}
2269+
22022270
/*
22032271
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
22042272
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

src/coreclr/jit/fgopt.cpp

Lines changed: 10 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -5604,63 +5604,6 @@ bool Compiler::fgHeadMerge(BasicBlock* block, bool early)
56045604
return madeChanges;
56055605
}
56065606

5607-
//------------------------------------------------------------------------
5608-
// gtTreeContainsCall:
5609-
// Check if a tree contains a call node matching the given predicate.
5610-
//
5611-
// Parameters:
5612-
// tree - The tree
5613-
// pred - Predicate that the call must match
5614-
//
5615-
// Returns:
5616-
// True if a call node matching the predicate was found, false otherwise.
5617-
//
5618-
template <typename Predicate>
5619-
bool Compiler::gtTreeContainsCall(GenTree* tree, Predicate pred)
5620-
{
5621-
struct HasCallVisitor : GenTreeVisitor<HasCallVisitor>
5622-
{
5623-
private:
5624-
Predicate& m_pred;
5625-
5626-
public:
5627-
enum
5628-
{
5629-
DoPreOrder = true
5630-
};
5631-
5632-
HasCallVisitor(Compiler* comp, Predicate& pred)
5633-
: GenTreeVisitor<HasCallVisitor>(comp)
5634-
, m_pred(pred)
5635-
{
5636-
}
5637-
5638-
fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
5639-
{
5640-
GenTree* node = *use;
5641-
if ((node->gtFlags & GTF_CALL) == 0)
5642-
{
5643-
return WALK_SKIP_SUBTREES;
5644-
}
5645-
5646-
if (node->IsCall() && m_pred(node->AsCall()))
5647-
{
5648-
return WALK_ABORT;
5649-
}
5650-
5651-
return WALK_CONTINUE;
5652-
}
5653-
};
5654-
5655-
if ((tree->gtFlags & GTF_CALL) == 0)
5656-
{
5657-
return false;
5658-
}
5659-
5660-
HasCallVisitor hasCall(this, pred);
5661-
return hasCall.WalkTree(&tree, nullptr) == WALK_ABORT;
5662-
}
5663-
56645607
//------------------------------------------------------------------------
56655608
// gtTreeContainsTailCall: Check if a tree contains any tail call or tail call
56665609
// candidate.
@@ -5676,9 +5619,11 @@ bool Compiler::gtTreeContainsCall(GenTree* tree, Predicate pred)
56765619
//
56775620
bool Compiler::gtTreeContainsTailCall(GenTree* tree)
56785621
{
5679-
return gtTreeContainsCall(tree, [](GenTreeCall* call) {
5680-
return call->CanTailCall() || call->IsTailCall();
5681-
});
5622+
auto isTailCall = [](GenTree* tree) {
5623+
return tree->IsCall() && (tree->AsCall()->CanTailCall() || tree->AsCall()->IsTailCall());
5624+
};
5625+
5626+
return gtFindNodeInTree<GTF_CALL>(tree, isTailCall) != nullptr;
56825627
}
56835628

56845629
//------------------------------------------------------------------------
@@ -5697,9 +5642,11 @@ bool Compiler::gtTreeContainsAsyncCall(GenTree* tree)
56975642
return false;
56985643
}
56995644

5700-
return gtTreeContainsCall(tree, [](GenTreeCall* call) {
5701-
return call->IsAsync();
5702-
});
5645+
auto isAsyncCall = [](GenTree* tree) {
5646+
return tree->IsCall() && tree->AsCall()->IsAsync();
5647+
};
5648+
5649+
return gtFindNodeInTree<GTF_CALL>(tree, isAsyncCall) != nullptr;
57035650
}
57045651

57055652
//------------------------------------------------------------------------

src/coreclr/jit/gentree.cpp

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17716,35 +17716,10 @@ bool Compiler::gtIsTypeHandleToRuntimeTypeHandleHelper(GenTreeCall* call, CorInf
1771617716
//
1771717717
bool Compiler::gtTreeContainsOper(GenTree* tree, genTreeOps oper)
1771817718
{
17719-
class Visitor final : public GenTreeVisitor<Visitor>
17720-
{
17721-
genTreeOps m_oper;
17722-
17723-
public:
17724-
Visitor(Compiler* comp, genTreeOps oper)
17725-
: GenTreeVisitor(comp)
17726-
, m_oper(oper)
17727-
{
17728-
}
17729-
17730-
enum
17731-
{
17732-
DoPreOrder = true,
17733-
};
17734-
17735-
fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
17736-
{
17737-
if ((*use)->OperIs(m_oper))
17738-
{
17739-
return WALK_ABORT;
17740-
}
17741-
17742-
return WALK_CONTINUE;
17743-
}
17719+
auto hasOper = [oper](GenTree* tree) {
17720+
return tree->OperGet() == oper;
1774417721
};
17745-
17746-
Visitor visitor(this, oper);
17747-
return visitor.WalkTree(&tree, nullptr) == WALK_ABORT;
17722+
return gtFindNodeInTree<GTF_EMPTY>(tree, hasOper) != nullptr;
1774817723
}
1774917724

1775017725
//------------------------------------------------------------------------

src/coreclr/jit/gschecks.cpp

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -537,45 +537,19 @@ void Compiler::gsParamsToShadows()
537537
// inserting reverse pinvoke transitions way too early in the
538538
// JIT.
539539

540-
struct HasReversePInvokeEnterVisitor : GenTreeVisitor<HasReversePInvokeEnterVisitor>
541-
{
542-
enum
543-
{
544-
DoPreOrder = true,
545-
};
546-
547-
HasReversePInvokeEnterVisitor(Compiler* comp)
548-
: GenTreeVisitor(comp)
549-
{
550-
}
551-
552-
fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
553-
{
554-
if (((*use)->gtFlags & GTF_CALL) == 0)
555-
{
556-
return fgWalkResult::WALK_SKIP_SUBTREES;
557-
}
558-
559-
if ((*use)->IsHelperCall(m_compiler, CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER) ||
560-
(*use)->IsHelperCall(m_compiler, CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER_TRACK_TRANSITIONS))
561-
{
562-
return fgWalkResult::WALK_ABORT;
563-
}
564-
565-
return fgWalkResult::WALK_CONTINUE;
566-
}
540+
auto isReversePInvoke = [=](GenTree* tree) {
541+
return tree->IsHelperCall(this, CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER) ||
542+
tree->IsHelperCall(this, CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER_TRACK_TRANSITIONS);
567543
};
568544

569-
HasReversePInvokeEnterVisitor checker(this);
570-
571545
Statement* reversePInvokeStmt = nullptr;
572546
for (Statement* const stmt : fgFirstBB->Statements())
573547
{
574548
// assert that we don't have any uses of the local variable
575549
// at the point before we insert the shadow copy statement.
576550
assert(!gtHasRef(stmt->GetRootNode(), lclNum));
577551

578-
if (checker.WalkTree(stmt->GetRootNodePointer(), nullptr) == fgWalkResult::WALK_ABORT)
552+
if (gtFindNodeInTree<GTF_CALL>(stmt->GetRootNode(), isReversePInvoke) != nullptr)
579553
{
580554
reversePInvokeStmt = stmt;
581555
break;

0 commit comments

Comments
 (0)