diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 948e8d239dd..ecdfe16eb06 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -3550,7 +3550,8 @@ static std::ostream& printStackIR(StackIR* ir, PrintSExpression& printer) { [[fallthrough]]; case StackInst::BlockBegin: case StackInst::IfBegin: - case StackInst::LoopBegin: { + case StackInst::LoopBegin: + case StackInst::TryTableBegin: { controlFlowDepth++; doIndent(); PrintExpressionContents(printer).visit(inst->origin); @@ -3562,7 +3563,8 @@ static std::ostream& printStackIR(StackIR* ir, PrintSExpression& printer) { [[fallthrough]]; case StackInst::BlockEnd: case StackInst::IfEnd: - case StackInst::LoopEnd: { + case StackInst::LoopEnd: + case StackInst::TryTableEnd: { controlFlowDepth--; indent--; doIndent(); diff --git a/src/passes/StackIR.cpp b/src/passes/StackIR.cpp index c57bea83f71..24b4fcbe844 100644 --- a/src/passes/StackIR.cpp +++ b/src/passes/StackIR.cpp @@ -292,7 +292,8 @@ class StackIROptimizer { case StackInst::Catch: case StackInst::CatchAll: case StackInst::Delegate: - case StackInst::TryEnd: { + case StackInst::TryEnd: + case StackInst::TryTableEnd: { return true; } default: { return false; } @@ -305,7 +306,8 @@ class StackIROptimizer { case StackInst::BlockBegin: case StackInst::IfBegin: case StackInst::LoopBegin: - case StackInst::TryBegin: { + case StackInst::TryBegin: + case StackInst::TryTableBegin: { return true; } default: { return false; } @@ -319,7 +321,8 @@ class StackIROptimizer { case StackInst::IfEnd: case StackInst::LoopEnd: case StackInst::TryEnd: - case StackInst::Delegate: { + case StackInst::Delegate: + case StackInst::TryTableEnd: { return true; } default: { return false; } diff --git a/src/wasm-stack.h b/src/wasm-stack.h index a195f1a84bd..de8fd8b03d0 100644 --- a/src/wasm-stack.h +++ b/src/wasm-stack.h @@ -60,20 +60,22 @@ class StackInst { StackInst(MixedArena&) {} enum Op { - Basic, // an instruction directly corresponding to a non-control-flow - // Binaryen IR node - BlockBegin, // the beginning of a block - BlockEnd, // the ending of a block - IfBegin, // the beginning of a if - IfElse, // the else of a if - IfEnd, // the ending of a if - LoopBegin, // the beginning of a loop - LoopEnd, // the ending of a loop - TryBegin, // the beginning of a try - Catch, // the catch within a try - CatchAll, // the catch_all within a try - Delegate, // the delegate within a try - TryEnd // the ending of a try + Basic, // an instruction directly corresponding to a + // non-control-flow Binaryen IR node + BlockBegin, // the beginning of a block + BlockEnd, // the ending of a block + IfBegin, // the beginning of a if + IfElse, // the else of a if + IfEnd, // the ending of a if + LoopBegin, // the beginning of a loop + LoopEnd, // the ending of a loop + TryBegin, // the beginning of a try + Catch, // the catch within a try + CatchAll, // the catch_all within a try + Delegate, // the delegate within a try + TryEnd, // the ending of a try + TryTableBegin, // the beginning of a try_table + TryTableEnd // the ending of a try_table } op; Expression* origin; // the expression this originates from diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 6a2fd8468c5..12ce68324cf 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -16,6 +16,7 @@ #include "wasm-stack.h" #include "ir/find_all.h" +#include "ir/properties.h" #include "wasm-binary.h" #include "wasm-debug.h" @@ -2680,6 +2681,8 @@ void StackIRGenerator::emit(Expression* curr) { stackInst = makeStackInst(StackInst::LoopBegin, curr); } else if (curr->is()) { stackInst = makeStackInst(StackInst::TryBegin, curr); + } else if (curr->is()) { + stackInst = makeStackInst(StackInst::TryTableBegin, curr); } else { stackInst = makeStackInst(curr); } @@ -2696,6 +2699,8 @@ void StackIRGenerator::emitScopeEnd(Expression* curr) { stackInst = makeStackInst(StackInst::LoopEnd, curr); } else if (curr->is()) { stackInst = makeStackInst(StackInst::TryEnd, curr); + } else if (curr->is()) { + stackInst = makeStackInst(StackInst::TryTableEnd, curr); } else { WASM_UNREACHABLE("unexpected expr type"); } @@ -2708,15 +2713,15 @@ StackInst* StackIRGenerator::makeStackInst(StackInst::Op op, ret->op = op; ret->origin = origin; auto stackType = origin->type; - if (origin->is() || origin->is() || origin->is() || - origin->is()) { + if (Properties::isControlFlowStructure(origin)) { if (stackType == Type::unreachable) { - // There are no unreachable blocks, loops, or ifs. we emit extra - // unreachables to fix that up, so that they are valid as having none - // type. + // There are no unreachable blocks, loops, ifs, trys, or try_tables. we + // emit extra unreachables to fix that up, so that they are valid as + // having none type. stackType = Type::none; } else if (op != StackInst::BlockEnd && op != StackInst::IfEnd && - op != StackInst::LoopEnd && op != StackInst::TryEnd) { + op != StackInst::LoopEnd && op != StackInst::TryEnd && + op != StackInst::TryTableEnd) { // If a concrete type is returned, we mark the end of the construct has // having that type (as it is pushed to the value stack at that point), // other parts are marked as none). @@ -2742,7 +2747,8 @@ void StackIRToBinaryWriter::write() { case StackInst::Basic: case StackInst::BlockBegin: case StackInst::IfBegin: - case StackInst::LoopBegin: { + case StackInst::LoopBegin: + case StackInst::TryTableBegin: { writer.visit(inst->origin); break; } @@ -2751,7 +2757,8 @@ void StackIRToBinaryWriter::write() { [[fallthrough]]; case StackInst::BlockEnd: case StackInst::IfEnd: - case StackInst::LoopEnd: { + case StackInst::LoopEnd: + case StackInst::TryTableEnd: { writer.emitScopeEnd(inst->origin); break; } diff --git a/test/lit/passes/stack-ir-eh.wast b/test/lit/passes/stack-ir-eh.wast new file mode 100644 index 00000000000..e06e5e5172d --- /dev/null +++ b/test/lit/passes/stack-ir-eh.wast @@ -0,0 +1,61 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --generate-stack-ir --optimize-stack-ir \ +;; RUN: -all --print-stack-ir | filecheck %s + +(module + ;; CHECK: (tag $e-i32 (param i32)) + (tag $e-i32 (param i32)) + + ;; CHECK: (func $foo (type $0) + ;; CHECK-NEXT: ) + (func $foo) + + ;; CHECK: (func $test (type $0) + ;; CHECK-NEXT: block $outer + ;; CHECK-NEXT: block $l-catch (result i32) + ;; CHECK-NEXT: block $l-catch-ref (type $1) (result i32 exnref) + ;; CHECK-NEXT: block $l-catch-all + ;; CHECK-NEXT: block $l-catch-all-ref (result exnref) + ;; CHECK-NEXT: try_table (catch $e-i32 $l-catch) (catch_ref $e-i32 $l-catch-ref) (catch_all $l-catch-all) (catch_all_ref $l-catch-all-ref) + ;; CHECK-NEXT: call $foo + ;; CHECK-NEXT: end + ;; CHECK-NEXT: br $outer + ;; CHECK-NEXT: end + ;; CHECK-NEXT: throw_ref + ;; CHECK-NEXT: end + ;; CHECK-NEXT: br $outer + ;; CHECK-NEXT: end + ;; CHECK-NEXT: tuple.drop 2 + ;; CHECK-NEXT: br $outer + ;; CHECK-NEXT: end + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: end + ;; CHECK-NEXT: ) + (func $test + (block $outer + (drop + (block $l-catch (result i32) + (tuple.drop 2 + (block $l-catch-ref (result i32 exnref) + (block $l-catch-all + (throw_ref + (block $l-catch-all-ref (result exnref) + (try_table (catch $e-i32 $l-catch) + (catch_ref $e-i32 $l-catch-ref) + (catch_all $l-catch-all) + (catch_all_ref $l-catch-all-ref) + (call $foo) + ) + (br $outer) + ) + ) + ) + (br $outer) + ) + ) + (br $outer) + ) + ) + ) + ) +)