diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm-ir-builder.h | 23 | ||||
-rw-r--r-- | src/wasm/wasm-ir-builder.cpp | 63 |
2 files changed, 43 insertions, 43 deletions
diff --git a/src/wasm-ir-builder.h b/src/wasm-ir-builder.h index 5803f0c61..addbd1a30 100644 --- a/src/wasm-ir-builder.h +++ b/src/wasm-ir-builder.h @@ -298,6 +298,10 @@ private: // The branch label name for this scope. Always fresh, never shadowed. Name label; + // For Try/Catch/CatchAll scopes, we need to separately track a label used + // for branches, since the normal label is only used for delegates. + Name branchLabel; + bool labelUsed = false; std::vector<Expression*> exprStack; @@ -308,6 +312,8 @@ private: ScopeCtx() : scope(NoScope{}) {} ScopeCtx(Scope scope) : scope(scope) {} ScopeCtx(Scope scope, Name label) : scope(scope), label(label) {} + ScopeCtx(Scope scope, Name label, Name branchLabel) + : scope(scope), label(label), branchLabel(branchLabel) {} static ScopeCtx makeFunc(Function* func) { return ScopeCtx(FuncScope{func}); @@ -325,11 +331,13 @@ private: static ScopeCtx makeTry(Try* tryy, Name originalLabel = {}) { return ScopeCtx(TryScope{tryy, originalLabel}); } - static ScopeCtx makeCatch(Try* tryy, Name originalLabel, Name label) { - return ScopeCtx(CatchScope{tryy, originalLabel}, label); + static ScopeCtx + makeCatch(Try* tryy, Name originalLabel, Name label, Name branchLabel) { + return ScopeCtx(CatchScope{tryy, originalLabel}, label, branchLabel); } - static ScopeCtx makeCatchAll(Try* tryy, Name originalLabel, Name label) { - return ScopeCtx(CatchAllScope{tryy, originalLabel}, label); + static ScopeCtx + makeCatchAll(Try* tryy, Name originalLabel, Name label, Name branchLabel) { + return ScopeCtx(CatchAllScope{tryy, originalLabel}, label, branchLabel); } static ScopeCtx makeTryTable(TryTable* trytable, Name originalLabel = {}) { return ScopeCtx(TryTableScope{trytable, originalLabel}); @@ -507,8 +515,11 @@ private: // `block`, but otherwise we will have to allocate a new block. Result<Expression*> finishScope(Block* block = nullptr); - [[nodiscard]] Result<Name> getLabelName(Index label); - [[nodiscard]] Result<Name> getDelegateLabelName(Index label); + [[nodiscard]] Result<Name> getLabelName(Index label, + bool forDelegate = false); + [[nodiscard]] Result<Name> getDelegateLabelName(Index label) { + return getLabelName(label, true); + } [[nodiscard]] Result<Index> addScratchLocal(Type); struct HoistedVal { 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; } |