summaryrefslogtreecommitdiff
path: root/src/ir
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir')
-rw-r--r--src/ir/ExpressionAnalyzer.cpp20
-rw-r--r--src/ir/branch-utils.h48
-rw-r--r--src/ir/properties.h10
3 files changed, 65 insertions, 13 deletions
diff --git a/src/ir/ExpressionAnalyzer.cpp b/src/ir/ExpressionAnalyzer.cpp
index 04ef52026..0b0adae9e 100644
--- a/src/ir/ExpressionAnalyzer.cpp
+++ b/src/ir/ExpressionAnalyzer.cpp
@@ -17,6 +17,7 @@
#include "ir/iteration.h"
#include "ir/load-utils.h"
#include "ir/utils.h"
+#include "shared-constants.h"
#include "support/hash.h"
#include "support/small_vector.h"
#include "wasm-traversal.h"
@@ -261,6 +262,9 @@ size_t ExpressionAnalyzer::hash(Expression* curr) {
Hasher(Expression* curr) {
stack.push_back(curr);
+ // DELEGATE_CALLER_TARGET is a fake target used to denote delegating to
+ // the caller. Add it here to prevent the unknown name error.
+ noteScopeName(DELEGATE_CALLER_TARGET);
while (stack.size() > 0) {
curr = stack.back();
@@ -327,13 +331,15 @@ size_t ExpressionAnalyzer::hash(Expression* curr) {
}
}
void visitScopeName(Name curr) {
- // Names are relative, we give the same hash for
- // (block $x (br $x))
- // (block $y (br $y))
- static_assert(sizeof(Index) == sizeof(int32_t),
- "wasm64 will need changes here");
- assert(internalNames.find(curr) != internalNames.end());
- rehash(digest, internalNames[curr]);
+ if (curr.is()) { // try's delegate target can be null
+ // Names are relative, we give the same hash for
+ // (block $x (br $x))
+ // (block $y (br $y))
+ static_assert(sizeof(Index) == sizeof(int32_t),
+ "wasm64 will need changes here");
+ assert(internalNames.find(curr) != internalNames.end());
+ rehash(digest, internalNames[curr]);
+ }
}
void visitNonScopeName(Name curr) { rehash(digest, uint64_t(curr.str)); }
void visitType(Type curr) { rehash(digest, curr.getID()); }
diff --git a/src/ir/branch-utils.h b/src/ir/branch-utils.h
index a9561ef07..8a4f02a58 100644
--- a/src/ir/branch-utils.h
+++ b/src/ir/branch-utils.h
@@ -40,9 +40,9 @@ inline bool isBranchReachable(Expression* expr) {
return true;
}
-// 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.
+// Perform a generic operation on uses of scope names (branch + delegate
+// 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
@@ -83,7 +83,7 @@ void operateOnScopeNameUsesAndSentTypes(Expression* expr, T func) {
} else if (auto* br = expr->dynCast<BrOn>()) {
func(name, br->getCastType());
} else {
- WASM_UNREACHABLE("bad br type");
+ assert(expr->is<Try>()); // delegate
}
});
}
@@ -135,6 +135,46 @@ inline bool replacePossibleTarget(Expression* branch, Name from, Name to) {
return worked;
}
+// Replace all delegate targets within the given AST.
+inline void replaceDelegateTargets(Expression* ast, Name from, Name to) {
+ struct Replacer
+ : public PostWalker<Replacer, UnifiedExpressionVisitor<Replacer>> {
+ Name from, to;
+ Replacer(Name from, Name to) : from(from), to(to) {}
+ void visitExpression(Expression* curr) {
+ if (curr->is<Try>()) {
+ operateOnScopeNameUses(curr, [&](Name& name) {
+ if (name == from) {
+ name = to;
+ }
+ });
+ }
+ }
+ };
+ Replacer replacer(from, to);
+ replacer.walk(ast);
+}
+
+// Replace all branch targets within the given AST.
+inline void replaceBranchTargets(Expression* ast, Name from, Name to) {
+ struct Replacer
+ : public PostWalker<Replacer, UnifiedExpressionVisitor<Replacer>> {
+ Name from, to;
+ Replacer(Name from, Name to) : from(from), to(to) {}
+ void visitExpression(Expression* curr) {
+ if (Properties::isBranch(curr)) {
+ operateOnScopeNameUses(curr, [&](Name& name) {
+ if (name == from) {
+ name = to;
+ }
+ });
+ }
+ }
+ };
+ Replacer replacer(from, to);
+ replacer.walk(ast);
+}
+
// Returns the set of targets to which we branch that are
// outside of an expression.
inline NameSet getExitingBranches(Expression* ast) {
diff --git a/src/ir/properties.h b/src/ir/properties.h
index b60c74d98..8ae7befba 100644
--- a/src/ir/properties.h
+++ b/src/ir/properties.h
@@ -69,13 +69,15 @@ inline bool isControlFlowStructure(Expression* curr) {
curr->is<Try>();
}
-// Check if an expression is a control flow construct with a name,
-// which implies it may have breaks to it.
+// Check if an expression is a control flow construct with a name, which implies
+// it may have breaks or delegates to it.
inline bool isNamedControlFlow(Expression* curr) {
if (auto* block = curr->dynCast<Block>()) {
return block->name.is();
} else if (auto* loop = curr->dynCast<Loop>()) {
return loop->name.is();
+ } else if (auto* try_ = curr->dynCast<Try>()) {
+ return try_->name.is();
}
return false;
}
@@ -104,6 +106,10 @@ inline bool isConstantExpression(const Expression* curr) {
return false;
}
+inline bool isBranch(const Expression* curr) {
+ return curr->is<Break>() || curr->is<Switch>() || curr->is<BrOn>();
+}
+
inline Literal getLiteral(const Expression* curr) {
if (auto* c = curr->dynCast<Const>()) {
return c->value;