summaryrefslogtreecommitdiff
path: root/src/ir/branch-utils.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir/branch-utils.h')
-rw-r--r--src/ir/branch-utils.h212
1 files changed, 98 insertions, 114 deletions
diff --git a/src/ir/branch-utils.h b/src/ir/branch-utils.h
index 9b439be89..e6a3486ca 100644
--- a/src/ir/branch-utils.h
+++ b/src/ir/branch-utils.h
@@ -28,111 +28,106 @@ namespace BranchUtils {
// Some branches are obviously not actually reachable (e.g. (br $out
// (unreachable)))
-inline bool isBranchReachable(Break* br) {
- return !(br->value && br->value->type == Type::unreachable) &&
- !(br->condition && br->condition->type == Type::unreachable);
+inline bool isBranchReachable(Expression* expr) {
+ // If any child is unreachable, the branch is not taken. Note that expr itself
+ // may be unreachable regardless (as in the case of a simple Break with no
+ // condition, which is still taken).
+ for (auto child : ChildIterator(expr)) {
+ if (child->type == Type::unreachable) {
+ return false;
+ }
+ }
+ return true;
}
-inline bool isBranchReachable(Switch* sw) {
- return !(sw->value && sw->value->type == Type::unreachable) &&
- sw->condition->type != Type::unreachable;
-}
+// Perform a generic operation on uses of scope names (branch targets) in an
+// expression. The provided function receives a Name& which it can modify if it
+// needs to.
+template<typename T> void operateOnScopeNameUses(Expression* expr, T func) {
+#define DELEGATE_ID expr->_id
+
+#define DELEGATE_START(id) \
+ auto* cast = expr->cast<id>(); \
+ WASM_UNUSED(cast);
-inline bool isBranchReachable(BrOnExn* br) {
- return br->exnref->type != Type::unreachable;
+#define DELEGATE_GET_FIELD(id, name) cast->name
+
+#define DELEGATE_FIELD_SCOPE_NAME_USE(id, name) func(cast->name);
+
+#define DELEGATE_FIELD_CHILD(id, name)
+#define DELEGATE_FIELD_INT(id, name)
+#define DELEGATE_FIELD_LITERAL(id, name)
+#define DELEGATE_FIELD_NAME(id, name)
+#define DELEGATE_FIELD_SCOPE_NAME_DEF(id, name)
+#define DELEGATE_FIELD_SIGNATURE(id, name)
+#define DELEGATE_FIELD_TYPE(id, name)
+#define DELEGATE_FIELD_ADDRESS(id, name)
+#define DELEGATE_FIELD_CHILD_VECTOR(id, name)
+#define DELEGATE_FIELD_INT_ARRAY(id, name)
+
+#include "wasm-delegations-fields.h"
}
-inline bool isBranchReachable(Expression* expr) {
- if (auto* br = expr->dynCast<Break>()) {
- return isBranchReachable(br);
- } else if (auto* sw = expr->dynCast<Switch>()) {
- return isBranchReachable(sw);
- } else if (auto* br = expr->dynCast<BrOnExn>()) {
- return isBranchReachable(br);
- }
- WASM_UNREACHABLE("unexpected expression type");
+// Perform a generic operation on definitions of scope names in an expression.
+// The provided function receives a Name& which it can modify if it needs to.
+template<typename T> void operateOnScopeNameDefs(Expression* expr, T func) {
+#define DELEGATE_ID expr->_id
+
+#define DELEGATE_START(id) \
+ auto* cast = expr->cast<id>(); \
+ WASM_UNUSED(cast);
+
+#define DELEGATE_FIELD_SCOPE_NAME_DEF(id, name) func(cast->name)
+
+#define DELEGATE_FIELD_CHILD(id, name)
+#define DELEGATE_FIELD_INT(id, name)
+#define DELEGATE_FIELD_LITERAL(id, name)
+#define DELEGATE_FIELD_NAME(id, name)
+#define DELEGATE_FIELD_SIGNATURE(id, name)
+#define DELEGATE_FIELD_TYPE(id, name)
+#define DELEGATE_FIELD_ADDRESS(id, name)
+#define DELEGATE_FIELD_CHILD_VECTOR(id, name)
+#define DELEGATE_FIELD_INT_ARRAY(id, name)
+#define DELEGATE_FIELD_SCOPE_NAME_USE(id, name)
+#define DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(id, name)
+
+#include "wasm-delegations-fields.h"
}
using NameSet = std::set<Name>;
-inline NameSet getUniqueTargets(Break* br) { return {br->name}; }
-
-inline NameSet getUniqueTargets(Switch* sw) {
+inline NameSet getUniqueTargets(Expression* expr) {
NameSet ret;
- for (auto target : sw->targets) {
- ret.insert(target);
- }
- ret.insert(sw->default_);
+ operateOnScopeNameUses(expr, [&](Name& name) { ret.insert(name); });
return ret;
}
-inline NameSet getUniqueTargets(BrOnExn* br) { return {br->name}; }
-
-inline NameSet getUniqueTargets(Expression* expr) {
- if (auto* br = expr->dynCast<Break>()) {
- return getUniqueTargets(br);
- }
- if (auto* br = expr->dynCast<Switch>()) {
- return getUniqueTargets(br);
- }
- if (auto* br = expr->dynCast<BrOnExn>()) {
- return getUniqueTargets(br);
- }
- return {};
-}
// If we branch to 'from', change that to 'to' instead.
inline bool replacePossibleTarget(Expression* branch, Name from, Name to) {
bool worked = false;
- if (auto* br = branch->dynCast<Break>()) {
- if (br->name == from) {
- br->name = to;
- worked = true;
- }
- } else if (auto* sw = branch->dynCast<Switch>()) {
- for (auto& target : sw->targets) {
- if (target == from) {
- target = to;
- worked = true;
- }
- }
- if (sw->default_ == from) {
- sw->default_ = to;
- worked = true;
- }
- } else if (auto* br = branch->dynCast<BrOnExn>()) {
- if (br->name == from) {
- br->name = to;
+ operateOnScopeNameUses(branch, [&](Name& name) {
+ if (name == from) {
+ name = to;
worked = true;
}
- } else {
- WASM_UNREACHABLE("unexpected expression type");
- }
+ });
return worked;
}
-// returns the set of targets to which we branch that are
-// outside of a node
+// Returns the set of targets to which we branch that are
+// outside of an expression.
inline NameSet getExitingBranches(Expression* ast) {
- struct Scanner : public PostWalker<Scanner> {
+ struct Scanner
+ : public PostWalker<Scanner, UnifiedExpressionVisitor<Scanner>> {
NameSet targets;
- void visitBreak(Break* curr) { targets.insert(curr->name); }
- void visitSwitch(Switch* curr) {
- for (auto target : curr->targets) {
- targets.insert(target);
- }
- targets.insert(curr->default_);
- }
- void visitBrOnExn(BrOnExn* curr) { targets.insert(curr->name); }
- void visitBlock(Block* curr) {
- if (curr->name.is()) {
- targets.erase(curr->name);
- }
- }
- void visitLoop(Loop* curr) {
- if (curr->name.is()) {
- targets.erase(curr->name);
- }
+ void visitExpression(Expression* curr) {
+ operateOnScopeNameDefs(curr, [&](Name& name) {
+ if (name.is()) {
+ targets.erase(name);
+ }
+ });
+ operateOnScopeNameUses(curr, [&](Name& name) { targets.insert(name); });
}
};
Scanner scanner;
@@ -144,18 +139,16 @@ inline NameSet getExitingBranches(Expression* ast) {
// returns the list of all branch targets in a node
inline NameSet getBranchTargets(Expression* ast) {
- struct Scanner : public PostWalker<Scanner> {
+ struct Scanner
+ : public PostWalker<Scanner, UnifiedExpressionVisitor<Scanner>> {
NameSet targets;
- void visitBlock(Block* curr) {
- if (curr->name.is()) {
- targets.insert(curr->name);
- }
- }
- void visitLoop(Loop* curr) {
- if (curr->name.is()) {
- targets.insert(curr->name);
- }
+ void visitExpression(Expression* curr) {
+ operateOnScopeNameDefs(curr, [&](Name& name) {
+ if (name.is()) {
+ targets.insert(name);
+ }
+ });
}
};
Scanner scanner;
@@ -166,7 +159,8 @@ inline NameSet 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.
-struct BranchSeeker : public PostWalker<BranchSeeker> {
+struct BranchSeeker
+ : public PostWalker<BranchSeeker, UnifiedExpressionVisitor<BranchSeeker>> {
Name target;
Index found = 0;
@@ -188,30 +182,20 @@ struct BranchSeeker : public PostWalker<BranchSeeker> {
}
}
- void visitBreak(Break* curr) {
- // check the break
- if (curr->name == target) {
- noteFound(curr->value);
- }
- }
-
- void visitSwitch(Switch* curr) {
- // check the switch
- for (auto name : curr->targets) {
+ void visitExpression(Expression* curr) {
+ operateOnScopeNameUses(curr, [&](Name& name) {
if (name == target) {
- noteFound(curr->value);
+ if (auto* br = curr->dynCast<Break>()) {
+ noteFound(br->value);
+ } else if (auto* sw = curr->dynCast<Switch>()) {
+ noteFound(sw->value);
+ } else if (auto* br = curr->dynCast<BrOnExn>()) {
+ noteFound(br->sent);
+ } else {
+ WASM_UNREACHABLE("bad br type");
+ }
}
- }
- if (curr->default_ == target) {
- noteFound(curr->value);
- }
- }
-
- void visitBrOnExn(BrOnExn* curr) {
- // check the br_on_exn
- if (curr->name == target) {
- noteFound(curr->sent);
- }
+ });
}
static bool has(Expression* tree, Name target) {