Skip to content

Commit f263f08

Browse files
Fix review
1 parent 66dff99 commit f263f08

File tree

1 file changed

+20
-13
lines changed

1 file changed

+20
-13
lines changed

src/passes/CodeFolding.cpp

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,10 @@ struct CodeFolding
136136
modifieds; // modified code should not be processed
137137
// again, wait for next pass
138138

139-
// Cache for hasExitingBranches results. Populated by a single bottom-up
140-
// walk to avoid O(N^2) repeated tree traversals on nested blocks.
141-
std::unordered_map<Expression*, bool> exitingBranchCache_;
139+
// Cache of expressions that have branches exiting to targets defined
140+
// outside them. Populated lazily on first access via PostWalker.
141+
std::unordered_set<Expression*> exitingBranchCache_;
142+
bool exitingBranchCachePopulated_ = false;
142143

143144
// walking
144145

@@ -305,28 +306,39 @@ struct CodeFolding
305306
unoptimizables.clear();
306307
modifieds.clear();
307308
exitingBranchCache_.clear();
309+
exitingBranchCachePopulated_ = false;
308310
if (needEHFixups) {
309311
EHUtils::handleBlockNestedPops(func, *getModule());
310312
}
311313
}
312314
}
313315

314316
private:
317+
// Check if an expression has branches that exit to targets defined outside
318+
// it. The cache is populated lazily on first call using a PostWalker for
319+
// efficient bottom-up traversal.
320+
bool hasExitingBranches(Expression* expr) {
321+
if (!exitingBranchCachePopulated_) {
322+
populateExitingBranchCache(getFunction()->body);
323+
exitingBranchCachePopulated_ = true;
324+
}
325+
return exitingBranchCache_.count(expr);
326+
}
327+
315328
// Pre-populate the exiting branch cache for all sub-expressions of root
316329
// in a single O(N) bottom-up walk. After this, exitingBranchCache_
317330
// lookups are O(1).
318331
void populateExitingBranchCache(Expression* root) {
319332
struct CachePopulator
320333
: public PostWalker<CachePopulator,
321334
UnifiedExpressionVisitor<CachePopulator>> {
322-
std::unordered_map<Expression*, bool>& cache;
335+
std::unordered_set<Expression*>& cache;
323336
// Track unresolved branch targets at each node. We propagate children's
324337
// targets upward: add uses, remove defs. If any remain, the expression
325338
// has exiting branches.
326339
std::unordered_map<Expression*, std::unordered_set<Name>> targetSets;
327340

328-
CachePopulator(std::unordered_map<Expression*, bool>& cache)
329-
: cache(cache) {}
341+
CachePopulator(std::unordered_set<Expression*>& cache) : cache(cache) {}
330342

331343
void visitExpression(Expression* curr) {
332344
std::unordered_set<Name> targets;
@@ -353,8 +365,8 @@ struct CodeFolding
353365
}
354366
});
355367
bool hasExiting = !targets.empty();
356-
cache[curr] = hasExiting;
357368
if (hasExiting) {
369+
cache.insert(curr);
358370
targetSets[curr] = std::move(targets);
359371
}
360372
}
@@ -606,11 +618,6 @@ struct CodeFolding
606618
if (tails.size() < 2) {
607619
return false;
608620
}
609-
// Pre-populate the cache once at the top level so all subsequent
610-
// exitingBranchCache_ lookups are O(1).
611-
if (num == 0) {
612-
populateExitingBranchCache(getFunction()->body);
613-
}
614621
// remove things that are untoward and cannot be optimized
615622
tails.erase(
616623
std::remove_if(tails.begin(),
@@ -699,7 +706,7 @@ struct CodeFolding
699706
// TODO: this should not be a problem in
700707
// *non*-terminating tails, but
701708
// double-verify that
702-
if (exitingBranchCache_[newItem]) {
709+
if (hasExitingBranches(newItem)) {
703710
return true;
704711
}
705712
return false;

0 commit comments

Comments
 (0)