Skip to content

Commit c2470c3

Browse files
Fix
1 parent 3bb2c60 commit c2470c3

1 file changed

Lines changed: 43 additions & 41 deletions

File tree

src/passes/CodeFolding.cpp

Lines changed: 43 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,6 @@ struct CodeFolding
301301
unoptimizables.clear();
302302
modifieds.clear();
303303
exitingBranchCache.clear();
304-
bodyCachePopulated = false;
305304
if (needEHFixups) {
306305
EHUtils::handleBlockNestedPops(func, *getModule());
307306
}
@@ -400,41 +399,6 @@ struct CodeFolding
400399
// inside that item
401400
bool canMove(const std::vector<Expression*>& items, Expression* outOf) {
402401
auto allTargets = BranchUtils::getBranchTargets(outOf);
403-
bool hasTry = false;
404-
bool hasTryTable = false;
405-
if (getModule()->features.hasExceptionHandling()) {
406-
hasTry = FindAll<Try>(outOf).has();
407-
hasTryTable = FindAll<TryTable>(outOf).has();
408-
}
409-
return canMoveImpl(items, allTargets, hasTry, hasTryTable);
410-
}
411-
412-
// Cached data for the function body, computed on demand to avoid repeated
413-
// O(N) tree walks in optimizeTerminatingTails.
414-
BranchUtils::NameSet bodyBranchTargets;
415-
bool bodyHasTry = false;
416-
bool bodyHasTryTable = false;
417-
bool bodyCachePopulated = false;
418-
419-
// Like canMove, but uses precomputed branch targets and Try/TryTable
420-
// presence. This avoids repeated O(N) tree walks when outOf is the
421-
// function body and canMove is called multiple times.
422-
bool canMoveWithCachedBodyInfo(const std::vector<Expression*>& items) {
423-
if (!bodyCachePopulated) {
424-
bodyBranchTargets = BranchUtils::getBranchTargets(getFunction()->body);
425-
if (getModule()->features.hasExceptionHandling()) {
426-
bodyHasTry = FindAll<Try>(getFunction()->body).has();
427-
bodyHasTryTable = FindAll<TryTable>(getFunction()->body).has();
428-
}
429-
bodyCachePopulated = true;
430-
}
431-
return canMoveImpl(items, bodyBranchTargets, bodyHasTry, bodyHasTryTable);
432-
}
433-
434-
bool canMoveImpl(const std::vector<Expression*>& items,
435-
const BranchUtils::NameSet& allTargets,
436-
bool hasTry,
437-
bool hasTryTable) {
438402
for (auto* item : items) {
439403
auto exiting = BranchUtils::getExitingBranches(item);
440404
std::vector<Name> intersection;
@@ -465,7 +429,8 @@ struct CodeFolding
465429
// conservative approximation because there can be cases that
466430
// 'try'/'try_table' is within the expression that may throw so it is
467431
// safe to take the expression out.
468-
if (effects.throws() && (hasTry || hasTryTable)) {
432+
if (effects.throws() &&
433+
(FindAll<Try>(outOf).has() || FindAll<TryTable>(outOf).has())) {
469434
return false;
470435
}
471436
}
@@ -667,10 +632,19 @@ struct CodeFolding
667632
// equal in the last num items, so we can merge there, but we look for
668633
// deeper merges first.
669634
// returns whether we optimized something.
670-
bool optimizeTerminatingTails(std::vector<Tail>& tails, Index num = 0) {
635+
bool optimizeTerminatingTails(std::vector<Tail>& tails,
636+
Index num = 0,
637+
BranchUtils::NameSet* bodyTargets = nullptr) {
671638
if (tails.size() < 2) {
672639
return false;
673640
}
641+
// Compute body branch targets once and share across recursive calls to
642+
// avoid repeated O(N) tree walks.
643+
BranchUtils::NameSet localBodyTargets;
644+
if (!bodyTargets) {
645+
localBodyTargets = BranchUtils::getBranchTargets(getFunction()->body);
646+
bodyTargets = &localBodyTargets;
647+
}
674648
// remove things that are untoward and cannot be optimized
675649
tails.erase(
676650
std::remove_if(tails.begin(),
@@ -731,8 +705,36 @@ struct CodeFolding
731705
// can be removed, though
732706
cost += WORTH_ADDING_BLOCK_TO_REMOVE_THIS_MUCH;
733707
// if we cannot merge to the end, then we definitely need 2 blocks,
734-
// and a branch
735-
if (!canMoveWithCachedBodyInfo(items)) {
708+
// and a branch. Use the pre-computed bodyTargets to avoid repeated
709+
// O(N) getBranchTargets calls.
710+
auto* body = getFunction()->body;
711+
bool canMoveItems = [&]() {
712+
for (auto* item : items) {
713+
auto exiting = BranchUtils::getExitingBranches(item);
714+
std::vector<Name> intersection;
715+
std::set_intersection(bodyTargets->begin(),
716+
bodyTargets->end(),
717+
exiting.begin(),
718+
exiting.end(),
719+
std::back_inserter(intersection));
720+
if (intersection.size() > 0) {
721+
return false;
722+
}
723+
if (getModule()->features.hasExceptionHandling()) {
724+
EffectAnalyzer effects(getPassOptions(), *getModule(), item);
725+
if (effects.danglingPop) {
726+
return false;
727+
}
728+
if (effects.throws() &&
729+
(FindAll<Try>(body).has() ||
730+
FindAll<TryTable>(body).has())) {
731+
return false;
732+
}
733+
}
734+
}
735+
return true;
736+
}();
737+
if (!canMoveItems) {
736738
cost += 1 + WORTH_ADDING_BLOCK_TO_REMOVE_THIS_MUCH;
737739
// TODO: to do this, we need to maintain a map of element=>parent,
738740
// so that we can insert the new blocks in the right place
@@ -828,7 +830,7 @@ struct CodeFolding
828830
// as the changes may influence us. we leave further opts to further
829831
// passes (as this is rare in practice, it's generally not a perf
830832
// issue, but TODO optimize)
831-
if (optimizeTerminatingTails(explore, num + 1)) {
833+
if (optimizeTerminatingTails(explore, num + 1, bodyTargets)) {
832834
return true;
833835
}
834836
}

0 commit comments

Comments
 (0)