@@ -411,27 +411,57 @@ struct IRBuilder::ChildPopper
411411 Result<> popConstrainedChildren (std::vector<Child>& children) {
412412 auto & scope = builder.getScope ();
413413
414- // Two-part indices into the stack of available expressions and the vector
415- // of requirements, allowing them to move independently with the granularity
416- // of a single tuple element.
417- size_t stackIndex = scope.exprStack .size ();
418- size_t stackTupleIndex = 0 ;
419- size_t childIndex = children.size ();
420- size_t childTupleIndex = 0 ;
421-
422- // The index of the shallowest unreachable instruction on the stack.
414+ // The index of the shallowest unreachable instruction on the stack, found
415+ // by checkNeedsUnreachableFallback.
423416 std::optional<size_t > unreachableIndex;
424417
425418 // Whether popping the children past the unreachable would produce a type
426419 // mismatch or try to pop from an empty stack.
427420 bool needUnreachableFallback = false ;
428421
429- if (!scope.unreachable ) {
430- // We only need to check requirements if there is an unreachable.
431- // Otherwise the validator will catch any problems.
432- goto pop;
422+ // We only need to check requirements if there is an unreachable.
423+ // Otherwise the validator will catch any problems.
424+ if (scope.unreachable ) {
425+ needUnreachableFallback =
426+ checkNeedsUnreachableFallback (children, unreachableIndex);
433427 }
434428
429+ // We have checked all the constraints, so we are ready to pop children.
430+ for (int i = children.size () - 1 ; i >= 0 ; --i) {
431+ if (needUnreachableFallback &&
432+ scope.exprStack .size () == *unreachableIndex + 1 && i > 0 ) {
433+ // The next item on the stack is the unreachable instruction we must
434+ // not pop past. We cannot insert unreachables in front of it because
435+ // it might be a branch we actually have to execute, so this next item
436+ // must be child 0. But we are not ready to pop child 0 yet, so
437+ // synthesize an unreachable instead of popping. The deeper
438+ // instructions that would otherwise have been popped will remain on
439+ // the stack to become prior children of future expressions or to be
440+ // implicitly dropped at the end of the scope.
441+ *children[i].childp = builder.builder .makeUnreachable ();
442+ continue ;
443+ }
444+
445+ // Pop a child normally.
446+ auto val = pop (children[i].constraint .size ());
447+ CHECK_ERR (val);
448+ *children[i].childp = *val;
449+ }
450+ return Ok{};
451+ }
452+
453+ bool checkNeedsUnreachableFallback (const std::vector<Child>& children,
454+ std::optional<size_t >& unreachableIndex) {
455+ auto & scope = builder.getScope ();
456+
457+ // Two-part indices into the stack of available expressions and the vector
458+ // of requirements, allowing them to move independently with the granularity
459+ // of a single tuple element.
460+ size_t stackIndex = scope.exprStack .size ();
461+ size_t stackTupleIndex = 0 ;
462+ size_t childIndex = children.size ();
463+ size_t childTupleIndex = 0 ;
464+
435465 // Check whether the values on the stack will be able to meet the given
436466 // requirements.
437467 while (true ) {
@@ -458,8 +488,7 @@ struct IRBuilder::ChildPopper
458488 // the input unreachable instruction is executed first. If we are
459489 // not reaching past an unreachable, the error will be caught when
460490 // we pop.
461- needUnreachableFallback = true ;
462- goto pop;
491+ return true ;
463492 }
464493 --stackIndex;
465494 stackTupleIndex = scope.exprStack [stackIndex]->type .size () - 1 ;
@@ -483,13 +512,11 @@ struct IRBuilder::ChildPopper
483512 // Always succeeds.
484513 } else if (constraint.isAnyReference ()) {
485514 if (!type.isRef () && type != Type::unreachable) {
486- needUnreachableFallback = true ;
487- break ;
515+ return true ;
488516 }
489517 } else if (auto bound = constraint.getSubtype ()) {
490518 if (!Type::isSubType (type, *bound)) {
491- needUnreachableFallback = true ;
492- break ;
519+ return true ;
493520 }
494521 } else if (constraint.isAnyI8ArrayReference ()) {
495522 bool isI8Array =
@@ -498,8 +525,7 @@ struct IRBuilder::ChildPopper
498525 bool isNone =
499526 type.isRef () && type.getHeapType ().isMaybeShared (HeapType::none);
500527 if (!isI8Array && !isNone && type != Type::unreachable) {
501- needUnreachableFallback = true ;
502- break ;
528+ return true ;
503529 }
504530 } else if (constraint.isAnyI16ArrayReference ()) {
505531 bool isI16Array =
@@ -508,8 +534,7 @@ struct IRBuilder::ChildPopper
508534 bool isNone =
509535 type.isRef () && type.getHeapType ().isMaybeShared (HeapType::none);
510536 if (!isI16Array && !isNone && type != Type::unreachable) {
511- needUnreachableFallback = true ;
512- break ;
537+ return true ;
513538 }
514539 } else {
515540 WASM_UNREACHABLE (" unexpected constraint" );
@@ -518,34 +543,10 @@ struct IRBuilder::ChildPopper
518543
519544 // No problems for children after this unreachable.
520545 if (type == Type::unreachable) {
521- assert (!needUnreachableFallback);
522546 unreachableIndex = stackIndex;
523547 }
524548 }
525-
526- pop:
527- // We have checked all the constraints, so we are ready to pop children.
528- for (int i = children.size () - 1 ; i >= 0 ; --i) {
529- if (needUnreachableFallback &&
530- scope.exprStack .size () == *unreachableIndex + 1 && i > 0 ) {
531- // The next item on the stack is the unreachable instruction we must
532- // not pop past. We cannot insert unreachables in front of it because
533- // it might be a branch we actually have to execute, so this next item
534- // must be child 0. But we are not ready to pop child 0 yet, so
535- // synthesize an unreachable instead of popping. The deeper
536- // instructions that would otherwise have been popped will remain on
537- // the stack to become prior children of future expressions or to be
538- // implicitly dropped at the end of the scope.
539- *children[i].childp = builder.builder .makeUnreachable ();
540- continue ;
541- }
542-
543- // Pop a child normally.
544- auto val = pop (children[i].constraint .size ());
545- CHECK_ERR (val);
546- *children[i].childp = *val;
547- }
548- return Ok{};
549+ return false ;
549550 }
550551
551552 Result<Expression*> pop (size_t size) {
0 commit comments