diff --git a/src/cfg/cfg-traversal.h b/src/cfg/cfg-traversal.h index ca5021e9696..10abd9e4f0a 100644 --- a/src/cfg/cfg-traversal.h +++ b/src/cfg/cfg-traversal.h @@ -452,11 +452,13 @@ struct CFGWalker : public PostWalker { } auto handlerBlocks = BranchUtils::getUniqueTargets(*currp); // Add branches to the targets. + auto* last = self->currBasicBlock; for (auto target : handlerBlocks) { if (target) { - self->branches[target].push_back(self->currBasicBlock); + self->branches[target].push_back(last); } } + self->link(last, self->startBasicBlock()); // we might fall through } static bool isReturnCall(Expression* curr) { diff --git a/src/passes/ConstraintAnalysis.cpp b/src/passes/ConstraintAnalysis.cpp index 78d9e71df51..356e6e035b1 100644 --- a/src/passes/ConstraintAnalysis.cpp +++ b/src/passes/ConstraintAnalysis.cpp @@ -57,8 +57,11 @@ struct Info { BasicBlockConstraintMap startConstraints; void dump(Function* func) { - std::cout << "Info{" << actions.size() << ", " << brancher << ", " - << startConstraints << "}\n"; + std::cout << "Info{" << actions.size(); + if (brancher) { + std::cout << ", " << *brancher; + } + std::cout << ", " << startConstraints << "}\n"; } }; diff --git a/test/lit/passes/constraint-analysis-cont.wast b/test/lit/passes/constraint-analysis-cont.wast new file mode 100644 index 00000000000..206597a28df --- /dev/null +++ b/test/lit/passes/constraint-analysis-cont.wast @@ -0,0 +1,76 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. + +;; RUN: wasm-opt %s --constraint-analysis -all -S -o - | filecheck %s + +(module + ;; CHECK: (type $func (func)) + (type $func (func)) + ;; CHECK: (type $cont (cont $func)) + (type $cont (cont $func)) + + ;; CHECK: (tag $tag (type $func)) + (tag $tag (type $func)) + + ;; CHECK: (func $func (type $2) (param $cont (ref $cont)) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (block $out + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block $in (result (ref $cont)) + ;; CHECK-NEXT: (resume $cont (on $tag $in) + ;; CHECK-NEXT: (local.get $cont) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $out) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.eq + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.eq + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $func (param $cont (ref $cont)) + (local $x i32) + + (block $out + (drop + (block $in (result (ref $cont)) + (resume $cont (on $tag $in) + (local.get $cont) + ) + ;; This might or might not be reached, depending on if the resume branches + ;; to $in. + (local.set $x + (i32.const 1) + ) + (br $out) + ) + ) + ) + + ;; We cannot be sure if x is 0 or 1, so nothing is optimized here. + (drop + (i32.eq + (local.get $x) + (i32.const 0) + ) + ) + (drop + (i32.eq + (local.get $x) + (i32.const 1) + ) + ) + ) +) +