summaryrefslogtreecommitdiff
path: root/src/ast
diff options
context:
space:
mode:
Diffstat (limited to 'src/ast')
-rw-r--r--src/ast/branch-utils.h14
-rw-r--r--src/ast/type-updating.h43
2 files changed, 20 insertions, 37 deletions
diff --git a/src/ast/branch-utils.h b/src/ast/branch-utils.h
index 77ec70753..05ead8571 100644
--- a/src/ast/branch-utils.h
+++ b/src/ast/branch-utils.h
@@ -103,11 +103,11 @@ inline std::set<Name> getBranchTargets(Expression* ast) {
// Finds if there are branches targeting a name. Note that since names are
// unique in our IR, we just need to look for the name, and do not need
// to analyze scoping.
-// By default we ignore untaken branches. You can set named to
-// note those as well, then any named branch is noted, even if untaken
+// By default we consider untaken branches (so any named use). You can unset named to
+// avoid that (and only note branches that are not obviously unreachable)
struct BranchSeeker : public PostWalker<BranchSeeker> {
Name target;
- bool named = false;
+ bool named = true;
Index found;
WasmType valueType;
@@ -144,16 +144,18 @@ struct BranchSeeker : public PostWalker<BranchSeeker> {
if (curr->default_ == target) noteFound(curr->value);
}
- static bool has(Expression* tree, Name target) {
+ static bool hasTaken(Expression* tree, Name target) {
if (!target.is()) return false;
BranchSeeker seeker(target);
+ seeker.named = false;
seeker.walk(tree);
return seeker.found > 0;
}
- static Index count(Expression* tree, Name target) {
+ static Index countTaken(Expression* tree, Name target) {
if (!target.is()) return 0;
BranchSeeker seeker(target);
+ seeker.named = false;
seeker.walk(tree);
return seeker.found;
}
@@ -161,7 +163,6 @@ struct BranchSeeker : public PostWalker<BranchSeeker> {
static bool hasNamed(Expression* tree, Name target) {
if (!target.is()) return false;
BranchSeeker seeker(target);
- seeker.named = true;
seeker.walk(tree);
return seeker.found > 0;
}
@@ -169,7 +170,6 @@ struct BranchSeeker : public PostWalker<BranchSeeker> {
static Index countNamed(Expression* tree, Name target) {
if (!target.is()) return 0;
BranchSeeker seeker(target);
- seeker.named = true;
seeker.walk(tree);
return seeker.found;
}
diff --git a/src/ast/type-updating.h b/src/ast/type-updating.h
index dc0ae0f36..3cf2f2afe 100644
--- a/src/ast/type-updating.h
+++ b/src/ast/type-updating.h
@@ -132,13 +132,9 @@ struct TypeUpdater : public ExpressionStackWalker<TypeUpdater, UnifiedExpression
// adds (or removes) breaks depending on break/switch contents
void discoverBreaks(Expression* curr, int change) {
if (auto* br = curr->dynCast<Break>()) {
- if (BranchUtils::isBranchTaken(br)) {
- noteBreakChange(br->name, change, br->value);
- }
+ noteBreakChange(br->name, change, br->value);
} else if (auto* sw = curr->dynCast<Switch>()) {
- if (BranchUtils::isBranchTaken(sw)) {
- applySwitchChanges(sw, change);
- }
+ applySwitchChanges(sw, change);
}
}
@@ -200,34 +196,17 @@ struct TypeUpdater : public ExpressionStackWalker<TypeUpdater, UnifiedExpression
auto* child = curr;
curr = parents[child];
if (!curr) return;
- // if a child of a break/switch is now unreachable, the
- // break may no longer be taken. note that if we get here,
- // this is an actually new unreachable child of the
- // node, so if there is just 1 such child, it is us, and
- // we are newly unreachable
- if (auto* br = curr->dynCast<Break>()) {
- int unreachableChildren = 0;
- if (br->value && br->value->type == unreachable) unreachableChildren++;
- if (br->condition && br->condition->type == unreachable) unreachableChildren++;
- if (unreachableChildren == 1) {
- // the break is no longer taken
- noteBreakChange(br->name, -1, br->value);
- }
- } else if (auto* sw = curr->dynCast<Switch>()) {
- int unreachableChildren = 0;
- if (sw->value && sw->value->type == unreachable) unreachableChildren++;
- if (sw->condition->type == unreachable) unreachableChildren++;
- if (unreachableChildren == 1) {
- applySwitchChanges(sw, -1);
- }
- }
// get ready to apply unreachability to this node
if (curr->type == unreachable) {
return; // already unreachable, stop here
}
// most nodes become unreachable if a child is unreachable,
- // but exceptions exists
+ // but exceptions exist
if (auto* block = curr->dynCast<Block>()) {
+ // if the block has a fallthrough, it can keep its type
+ if (isConcreteWasmType(block->list.back()->type)) {
+ return; // did not turn
+ }
// if the block has breaks, it can keep its type
if (!block->name.is() || blockInfos[block->name].numBreaks == 0) {
curr->type = unreachable;
@@ -255,7 +234,7 @@ struct TypeUpdater : public ExpressionStackWalker<TypeUpdater, UnifiedExpression
return; // nothing concrete to change to unreachable
}
if (curr->name.is() && blockInfos[curr->name].numBreaks > 0) {
- return;// has a break, not unreachable
+ return; // has a break, not unreachable
}
// look for a fallthrough
makeBlockUnreachableIfNoFallThrough(curr);
@@ -265,9 +244,13 @@ struct TypeUpdater : public ExpressionStackWalker<TypeUpdater, UnifiedExpression
if (curr->type == unreachable) {
return; // no change possible
}
+ if (!curr->list.empty() &&
+ isConcreteWasmType(curr->list.back()->type)) {
+ return; // should keep type due to fallthrough, even if has an unreachable child
+ }
for (auto* child : curr->list) {
if (child->type == unreachable) {
- // no fallthrough, this block is now unreachable
+ // no fallthrough, and an unreachable, => this block is now unreachable
changeTypeTo(curr, unreachable);
return;
}