@@ -235,6 +235,10 @@ void IRBuilder::dump() {
235235 std::cerr << " (label: " << scope.label << " )" ;
236236 }
237237
238+ if (scope.branchLabel ) {
239+ std::cerr << " (branch label: " << scope.branchLabel << " )" ;
240+ }
241+
238242 if (scope.unreachable ) {
239243 std::cerr << " (unreachable)" ;
240244 }
@@ -703,9 +707,6 @@ Result<> IRBuilder::visitLoopStart(Loop* loop) {
703707
704708Result<> IRBuilder::visitTryStart (Try* tryy, Name label) {
705709 applyDebugLoc (tryy);
706- // The delegate label will be regenerated if we need it. See
707- // `getDelegateLabelName` for details.
708- tryy->name = Name ();
709710 pushScope (ScopeCtx::makeTry (tryy, label));
710711 return Ok{};
711712}
@@ -829,6 +830,7 @@ Result<> IRBuilder::visitCatch(Name tag) {
829830 }
830831 auto originalLabel = scope.getOriginalLabel ();
831832 auto label = scope.label ;
833+ auto branchLabel = scope.branchLabel ;
832834 auto expr = finishScope ();
833835 CHECK_ERR (expr);
834836 if (wasTry) {
@@ -837,7 +839,7 @@ Result<> IRBuilder::visitCatch(Name tag) {
837839 tryy->catchBodies .push_back (*expr);
838840 }
839841 tryy->catchTags .push_back (tag);
840- pushScope (ScopeCtx::makeCatch (tryy, originalLabel, label));
842+ pushScope (ScopeCtx::makeCatch (tryy, originalLabel, label, branchLabel ));
841843 // Push a pop for the exception payload.
842844 auto params = wasm.getTag (tag)->sig .params ;
843845 if (params != Type::none) {
@@ -859,44 +861,18 @@ Result<> IRBuilder::visitCatchAll() {
859861 }
860862 auto originalLabel = scope.getOriginalLabel ();
861863 auto label = scope.label ;
864+ auto branchLabel = scope.branchLabel ;
862865 auto expr = finishScope ();
863866 CHECK_ERR (expr);
864867 if (wasTry) {
865868 tryy->body = *expr;
866869 } else {
867870 tryy->catchBodies .push_back (*expr);
868871 }
869- pushScope (ScopeCtx::makeCatchAll (tryy, originalLabel, label));
872+ pushScope (ScopeCtx::makeCatchAll (tryy, originalLabel, label, branchLabel ));
870873 return Ok{};
871874}
872875
873- Result<Name> IRBuilder::getDelegateLabelName (Index label) {
874- if (label >= scopeStack.size ()) {
875- return Err{" invalid label: " + std::to_string (label)};
876- }
877- auto & scope = scopeStack[scopeStack.size () - label - 1 ];
878- auto * delegateTry = scope.getTry ();
879- if (!delegateTry) {
880- delegateTry = scope.getCatch ();
881- }
882- if (!delegateTry) {
883- delegateTry = scope.getCatchAll ();
884- }
885- if (!delegateTry) {
886- return Err{" expected try scope at label " + std::to_string (label)};
887- }
888- // Only delegate and rethrow can reference the try name in Binaryen IR, so
889- // trys might need two labels: one for delegate/rethrow and one for all
890- // other control flow. These labels must be different to satisfy the
891- // Binaryen validator. To keep this complexity contained within the
892- // handling of trys and delegates, pretend there is just the single normal
893- // label and add a prefix to it to generate the delegate label.
894- auto delegateName =
895- Name (std::string (" __delegate__" ) + getLabelName (label)->toString ());
896- delegateTry->name = delegateName;
897- return delegateName;
898- }
899-
900876Result<> IRBuilder::visitDelegate (Index label) {
901877 auto & scope = getScope ();
902878 auto * tryy = scope.getTry ();
@@ -946,8 +922,10 @@ Result<> IRBuilder::visitEnd() {
946922 // type of the scope expression.
947923 auto originalScopeType = scope.getResultType ();
948924 auto maybeWrapForLabel = [&](Expression* curr) -> Expression* {
949- if (scope.label ) {
950- return builder.makeBlock (scope.label ,
925+ bool isTry = scope.getTry () || scope.getCatch () || scope.getCatchAll ();
926+ auto & label = isTry ? scope.branchLabel : scope.label ;
927+ if (label) {
928+ return builder.makeBlock (label,
951929 {curr},
952930 scope.labelUsed ? originalScopeType
953931 : scope.getResultType ());
@@ -981,11 +959,13 @@ Result<> IRBuilder::visitEnd() {
981959 push (maybeWrapForLabel (iff));
982960 } else if (auto * tryy = scope.getTry ()) {
983961 tryy->body = *expr;
962+ tryy->name = scope.label ;
984963 tryy->finalize (tryy->type );
985964 push (maybeWrapForLabel (tryy));
986965 } else if (Try * tryy;
987966 (tryy = scope.getCatch ()) || (tryy = scope.getCatchAll ())) {
988967 tryy->catchBodies .push_back (*expr);
968+ tryy->name = scope.label ;
989969 tryy->finalize (tryy->type );
990970 push (maybeWrapForLabel (tryy));
991971 } else if (auto * trytable = scope.getTryTable ()) {
@@ -1029,10 +1009,17 @@ Result<Index> IRBuilder::getLabelIndex(Name label, bool inDelegate) {
10291009 return index;
10301010}
10311011
1032- Result<Name> IRBuilder::getLabelName (Index label) {
1012+ Result<Name> IRBuilder::getLabelName (Index label, bool forDelegate ) {
10331013 auto scope = getScope (label);
10341014 CHECK_ERR (scope);
1035- auto & scopeLabel = (*scope)->label ;
1015+
1016+ // For normal branches to try blocks, we need to use the secondary label.
1017+ bool useTryBranchLabel =
1018+ !forDelegate &&
1019+ ((*scope)->getTry () || (*scope)->getCatch () || (*scope)->getCatchAll ());
1020+ auto & scopeLabel =
1021+ useTryBranchLabel ? (*scope)->branchLabel : (*scope)->label ;
1022+
10361023 if (!scopeLabel) {
10371024 // The scope does not already have a name, so we need to create one.
10381025 if ((*scope)->getBlock ()) {
@@ -1041,7 +1028,9 @@ Result<Name> IRBuilder::getLabelName(Index label) {
10411028 scopeLabel = makeFresh (" label" );
10421029 }
10431030 }
1044- (*scope)->labelUsed = true ;
1031+ if (!forDelegate) {
1032+ (*scope)->labelUsed = true ;
1033+ }
10451034 return scopeLabel;
10461035}
10471036
0 commit comments