summaryrefslogtreecommitdiff
path: root/src/wasm/wasm-ir-builder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm/wasm-ir-builder.cpp')
-rw-r--r--src/wasm/wasm-ir-builder.cpp63
1 files changed, 26 insertions, 37 deletions
diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp
index 78ce07f8d..ccd2ee77a 100644
--- a/src/wasm/wasm-ir-builder.cpp
+++ b/src/wasm/wasm-ir-builder.cpp
@@ -235,6 +235,10 @@ void IRBuilder::dump() {
std::cerr << " (label: " << scope.label << ")";
}
+ if (scope.branchLabel) {
+ std::cerr << " (branch label: " << scope.branchLabel << ")";
+ }
+
if (scope.unreachable) {
std::cerr << " (unreachable)";
}
@@ -703,9 +707,6 @@ Result<> IRBuilder::visitLoopStart(Loop* loop) {
Result<> IRBuilder::visitTryStart(Try* tryy, Name label) {
applyDebugLoc(tryy);
- // The delegate label will be regenerated if we need it. See
- // `getDelegateLabelName` for details.
- tryy->name = Name();
pushScope(ScopeCtx::makeTry(tryy, label));
return Ok{};
}
@@ -829,6 +830,7 @@ Result<> IRBuilder::visitCatch(Name tag) {
}
auto originalLabel = scope.getOriginalLabel();
auto label = scope.label;
+ auto branchLabel = scope.branchLabel;
auto expr = finishScope();
CHECK_ERR(expr);
if (wasTry) {
@@ -837,7 +839,7 @@ Result<> IRBuilder::visitCatch(Name tag) {
tryy->catchBodies.push_back(*expr);
}
tryy->catchTags.push_back(tag);
- pushScope(ScopeCtx::makeCatch(tryy, originalLabel, label));
+ pushScope(ScopeCtx::makeCatch(tryy, originalLabel, label, branchLabel));
// Push a pop for the exception payload.
auto params = wasm.getTag(tag)->sig.params;
if (params != Type::none) {
@@ -859,6 +861,7 @@ Result<> IRBuilder::visitCatchAll() {
}
auto originalLabel = scope.getOriginalLabel();
auto label = scope.label;
+ auto branchLabel = scope.branchLabel;
auto expr = finishScope();
CHECK_ERR(expr);
if (wasTry) {
@@ -866,37 +869,10 @@ Result<> IRBuilder::visitCatchAll() {
} else {
tryy->catchBodies.push_back(*expr);
}
- pushScope(ScopeCtx::makeCatchAll(tryy, originalLabel, label));
+ pushScope(ScopeCtx::makeCatchAll(tryy, originalLabel, label, branchLabel));
return Ok{};
}
-Result<Name> IRBuilder::getDelegateLabelName(Index label) {
- if (label >= scopeStack.size()) {
- return Err{"invalid label: " + std::to_string(label)};
- }
- auto& scope = scopeStack[scopeStack.size() - label - 1];
- auto* delegateTry = scope.getTry();
- if (!delegateTry) {
- delegateTry = scope.getCatch();
- }
- if (!delegateTry) {
- delegateTry = scope.getCatchAll();
- }
- if (!delegateTry) {
- return Err{"expected try scope at label " + std::to_string(label)};
- }
- // Only delegate and rethrow can reference the try name in Binaryen IR, so
- // trys might need two labels: one for delegate/rethrow and one for all
- // other control flow. These labels must be different to satisfy the
- // Binaryen validator. To keep this complexity contained within the
- // handling of trys and delegates, pretend there is just the single normal
- // label and add a prefix to it to generate the delegate label.
- auto delegateName =
- Name(std::string("__delegate__") + getLabelName(label)->toString());
- delegateTry->name = delegateName;
- return delegateName;
-}
-
Result<> IRBuilder::visitDelegate(Index label) {
auto& scope = getScope();
auto* tryy = scope.getTry();
@@ -946,8 +922,10 @@ Result<> IRBuilder::visitEnd() {
// type of the scope expression.
auto originalScopeType = scope.getResultType();
auto maybeWrapForLabel = [&](Expression* curr) -> Expression* {
- if (scope.label) {
- return builder.makeBlock(scope.label,
+ bool isTry = scope.getTry() || scope.getCatch() || scope.getCatchAll();
+ auto& label = isTry ? scope.branchLabel : scope.label;
+ if (label) {
+ return builder.makeBlock(label,
{curr},
scope.labelUsed ? originalScopeType
: scope.getResultType());
@@ -981,11 +959,13 @@ Result<> IRBuilder::visitEnd() {
push(maybeWrapForLabel(iff));
} else if (auto* tryy = scope.getTry()) {
tryy->body = *expr;
+ tryy->name = scope.label;
tryy->finalize(tryy->type);
push(maybeWrapForLabel(tryy));
} else if (Try * tryy;
(tryy = scope.getCatch()) || (tryy = scope.getCatchAll())) {
tryy->catchBodies.push_back(*expr);
+ tryy->name = scope.label;
tryy->finalize(tryy->type);
push(maybeWrapForLabel(tryy));
} else if (auto* trytable = scope.getTryTable()) {
@@ -1029,10 +1009,17 @@ Result<Index> IRBuilder::getLabelIndex(Name label, bool inDelegate) {
return index;
}
-Result<Name> IRBuilder::getLabelName(Index label) {
+Result<Name> IRBuilder::getLabelName(Index label, bool forDelegate) {
auto scope = getScope(label);
CHECK_ERR(scope);
- auto& scopeLabel = (*scope)->label;
+
+ // For normal branches to try blocks, we need to use the secondary label.
+ bool useTryBranchLabel =
+ !forDelegate &&
+ ((*scope)->getTry() || (*scope)->getCatch() || (*scope)->getCatchAll());
+ auto& scopeLabel =
+ useTryBranchLabel ? (*scope)->branchLabel : (*scope)->label;
+
if (!scopeLabel) {
// The scope does not already have a name, so we need to create one.
if ((*scope)->getBlock()) {
@@ -1041,7 +1028,9 @@ Result<Name> IRBuilder::getLabelName(Index label) {
scopeLabel = makeFresh("label");
}
}
- (*scope)->labelUsed = true;
+ if (!forDelegate) {
+ (*scope)->labelUsed = true;
+ }
return scopeLabel;
}