diff options
author | Frank Emrich <git@emrich.io> | 2024-03-19 17:53:08 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-19 10:53:08 -0700 |
commit | 84cc9fa123e58c5ff236145a24157c098daede64 (patch) | |
tree | 9ed80b7ba904073e8b80e47e5e1105ef9b6966b0 | |
parent | 63db13bf0f0f5dcc76c45a22ff43c424fa54a011 (diff) | |
download | binaryen-84cc9fa123e58c5ff236145a24157c098daede64.tar.gz binaryen-84cc9fa123e58c5ff236145a24157c098daede64.tar.bz2 binaryen-84cc9fa123e58c5ff236145a24157c098daede64.zip |
Typed continuations: suspend instructions (#6393)
This PR is part of a series that adds basic support for the [typed
continuations/wasmfx proposal](https://github.com/wasmfx/specfx).
This particular PR adds support for the `suspend` instruction for suspending
with a given tag, documented
[here](https://github.com/wasmfx/specfx/blob/main/proposals/continuations/Overview.md#instructions).
These instructions are of the form `(suspend $tag)`. Assuming that `$tag` is
defined with _n_ `param` types `t_1` to `t_n`, the instruction consumes _n_
arguments of types `t_1` to `t_n`. Its result type is the same as the `result`
type of the tag. Thus, the folded textual representation looks like
`(suspend $tag arg1 ... argn)`.
Support for the instruction is implemented in both the old and the new wat
parser.
Note that this PR does not implement validation of the new instruction.
This PR also fixes finalization of `cont.new`, `cont.bind` and `resume` nodes in
those cases where any of their children are unreachable.
29 files changed, 281 insertions, 22 deletions
diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index 8bef4e98c..3cf711e7b 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -328,6 +328,7 @@ INITIAL_CONTENTS_IGNORE = [ 'typed_continuations_resume.wast', 'typed_continuations_contnew.wast', 'typed_continuations_contbind.wast', + 'typed_continuations_suspend.wast', # New EH implementation is in progress 'exception-handling.wast', 'translate-eh-old-to-new.wast', diff --git a/scripts/gen-s-parser.py b/scripts/gen-s-parser.py index b2cac2b89..3f632c004 100755 --- a/scripts/gen-s-parser.py +++ b/scripts/gen-s-parser.py @@ -570,6 +570,7 @@ instructions = [ ("cont.new", "makeContNew(s)"), ("cont.bind", "makeContBind(s)"), ("resume", "makeResume(s)"), + ("suspend", "makeSuspend(s)"), # GC ("i31.new", "makeRefI31(s)"), # deprecated ("ref.i31", "makeRefI31(s)"), diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 8f13750d4..939031020 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -3369,6 +3369,9 @@ switch (buf[0]) { default: goto parse_error; } } + case 'u': + if (op == "suspend"sv) { return makeSuspend(s); } + goto parse_error; default: goto parse_error; } } @@ -8653,6 +8656,12 @@ switch (buf[0]) { default: goto parse_error; } } + case 'u': + if (op == "suspend"sv) { + CHECK_ERR(makeSuspend(ctx, pos, annotations)); + return Ok{}; + } + goto parse_error; default: goto parse_error; } } diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp index 6d872056a..c8f83f1ba 100644 --- a/src/ir/ReFinalize.cpp +++ b/src/ir/ReFinalize.cpp @@ -185,6 +185,7 @@ void ReFinalize::visitStringSliceIter(StringSliceIter* curr) { void ReFinalize::visitContNew(ContNew* curr) { curr->finalize(); } void ReFinalize::visitContBind(ContBind* curr) { curr->finalize(); } void ReFinalize::visitResume(Resume* curr) { curr->finalize(); } +void ReFinalize::visitSuspend(Suspend* curr) { curr->finalize(getModule()); } void ReFinalize::visitExport(Export* curr) { WASM_UNREACHABLE("unimp"); } void ReFinalize::visitGlobal(Global* curr) { WASM_UNREACHABLE("unimp"); } diff --git a/src/ir/cost.h b/src/ir/cost.h index d66c97282..edb39546d 100644 --- a/src/ir/cost.h +++ b/src/ir/cost.h @@ -742,7 +742,18 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> { } CostType visitResume(Resume* curr) { // Inspired by indirect calls, but twice the cost. - return 12 + visit(curr->cont); + CostType ret = 12 + visit(curr->cont); + for (auto* arg : curr->operands) { + ret += visit(arg); + } + return ret; + } + CostType visitSuspend(Suspend* curr) { + CostType ret = 12; + for (auto* arg : curr->operands) { + ret += visit(arg); + } + return ret; } private: diff --git a/src/ir/effects.h b/src/ir/effects.h index 0b3d2a4af..6901f99de 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -994,6 +994,14 @@ private: parent.throws_ = true; } } + void visitSuspend(Suspend* curr) { + // Similar to resume/call: Suspending means that we execute arbitrary + // other code before we may resume here. + parent.calls = true; + if (parent.features.hasExceptionHandling() && parent.tryDepth == 0) { + parent.throws_ = true; + } + } }; public: diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index 44015c113..c80ada95c 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -1212,6 +1212,10 @@ struct InfoCollector // TODO: optimize when possible addRoot(curr); } + void visitSuspend(Suspend* curr) { + // TODO: optimize when possible + addRoot(curr); + } void visitFunction(Function* func) { // Functions with a result can flow a value out from their body. diff --git a/src/ir/subtype-exprs.h b/src/ir/subtype-exprs.h index 553c1497b..1457e1ef5 100644 --- a/src/ir/subtype-exprs.h +++ b/src/ir/subtype-exprs.h @@ -394,6 +394,7 @@ struct SubtypingDiscoverer : public OverriddenVisitor<SubType> { void visitContBind(ContBind* curr) { WASM_UNREACHABLE("not implemented"); } void visitContNew(ContNew* curr) { WASM_UNREACHABLE("not implemented"); } void visitResume(Resume* curr) { WASM_UNREACHABLE("not implemented"); } + void visitSuspend(Suspend* curr) { WASM_UNREACHABLE("not implemented"); } }; } // namespace wasm diff --git a/src/parser/contexts.h b/src/parser/contexts.h index e79330871..8b59ab40b 100644 --- a/src/parser/contexts.h +++ b/src/parser/contexts.h @@ -824,6 +824,9 @@ struct NullInstrParserCtx { const TagLabelListT&) { return Ok{}; } + Result<> makeSuspend(Index, const std::vector<Annotation>&, TagIdxT) { + return Ok{}; + } }; struct NullCtx : NullTypeParserCtx, NullInstrParserCtx { @@ -2594,6 +2597,11 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { } return withLoc(pos, irBuilder.makeResume(type, tags, labels)); } + + Result<> + makeSuspend(Index pos, const std::vector<Annotation>& annotations, Name tag) { + return withLoc(pos, irBuilder.makeSuspend(tag)); + } }; } // namespace wasm::WATParser diff --git a/src/parser/parsers.h b/src/parser/parsers.h index 0150af811..51b5d8f9e 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -309,6 +309,8 @@ template<typename Ctx> Result<> makeContNew(Ctx*, Index, const std::vector<Annotation>&); template<typename Ctx> Result<> makeResume(Ctx&, Index, const std::vector<Annotation>&); +template<typename Ctx> +Result<> makeSuspend(Ctx&, Index, const std::vector<Annotation>&); // Modules template<typename Ctx> MaybeResult<Index> maybeTypeidx(Ctx& ctx); @@ -2498,6 +2500,15 @@ makeResume(Ctx& ctx, Index pos, const std::vector<Annotation>& annotations) { return ctx.makeResume(pos, annotations, *type, tagLabels); } +template<typename Ctx> +Result<> +makeSuspend(Ctx& ctx, Index pos, const std::vector<Annotation>& annotations) { + auto tag = tagidx(ctx); + CHECK_ERR(tag); + + return ctx.makeSuspend(pos, annotations, *tag); +} + // ======= // Modules // ======= diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index a9354defa..643f1cc3f 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -2382,6 +2382,11 @@ struct PrintExpressionContents o << ')'; } } + + void visitSuspend(Suspend* curr) { + printMedium(o, "suspend "); + curr->tag.print(o); + } }; void PrintSExpression::setModule(Module* module) { diff --git a/src/passes/TypeGeneralizing.cpp b/src/passes/TypeGeneralizing.cpp index 10dfe8737..26a0f1eab 100644 --- a/src/passes/TypeGeneralizing.cpp +++ b/src/passes/TypeGeneralizing.cpp @@ -878,6 +878,7 @@ struct TransferFn : OverriddenVisitor<TransferFn> { void visitContBind(ContBind* curr) { WASM_UNREACHABLE("TODO"); } void visitContNew(ContNew* curr) { WASM_UNREACHABLE("TODO"); } void visitResume(Resume* curr) { WASM_UNREACHABLE("TODO"); } + void visitSuspend(Suspend* curr) { WASM_UNREACHABLE("TODO"); } }; struct TypeGeneralizing : WalkerPass<PostWalker<TypeGeneralizing>> { diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 16e7945c5..f8463f3b1 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1179,6 +1179,7 @@ enum ASTNodes { // typed continuation opcodes ContNew = 0xe0, ContBind = 0xe1, + Suspend = 0xe2, Resume = 0xe3, }; @@ -1810,6 +1811,7 @@ public: void visitContNew(ContNew* curr); void visitContBind(ContBind* curr); void visitResume(Resume* curr); + void visitSuspend(Suspend* curr); [[noreturn]] void throwError(std::string text); diff --git a/src/wasm-builder.h b/src/wasm-builder.h index eb1874c3b..7d4991d9a 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -1231,6 +1231,13 @@ public: ret->finalize(&wasm); return ret; } + Suspend* makeSuspend(Name tag, const std::vector<Expression*>& args) { + auto* ret = wasm.allocator.alloc<Suspend>(); + ret->tag = tag; + ret->operands.set(args); + ret->finalize(&wasm); + return ret; + } // Additional helpers diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def index ac0256cf2..02674e8b2 100644 --- a/src/wasm-delegations-fields.def +++ b/src/wasm-delegations-fields.def @@ -973,6 +973,13 @@ switch (DELEGATE_ID) { DELEGATE_END(Resume); break; } + case Expression::Id::SuspendId: { + DELEGATE_START(Suspend); + DELEGATE_FIELD_CHILD_VECTOR(Suspend, operands); + DELEGATE_FIELD_NAME_KIND(Suspend, tag, ModuleItemKind::Tag); + DELEGATE_END(Suspend); + break; + } } #undef DELEGATE_ID diff --git a/src/wasm-delegations.def b/src/wasm-delegations.def index c07a78f8b..ca07356b9 100644 --- a/src/wasm-delegations.def +++ b/src/wasm-delegations.def @@ -108,5 +108,6 @@ DELEGATE(StringSliceIter); DELEGATE(ContBind); DELEGATE(ContNew); DELEGATE(Resume); +DELEGATE(Suspend); #undef DELEGATE diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 5179d6ad0..b9b12bc35 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -2488,6 +2488,7 @@ public: Flow visitContBind(ContBind* curr) { WASM_UNREACHABLE("unimplemented"); } Flow visitContNew(ContNew* curr) { WASM_UNREACHABLE("unimplemented"); } Flow visitResume(Resume* curr) { WASM_UNREACHABLE("unimplemented"); } + Flow visitSuspend(Suspend* curr) { WASM_UNREACHABLE("unimplemented"); } void trap(const char* why) override { throw NonconstantException(); } @@ -4064,6 +4065,7 @@ public: Flow visitContBind(ContBind* curr) { return Flow(NONCONSTANT_FLOW); } Flow visitContNew(ContNew* curr) { return Flow(NONCONSTANT_FLOW); } Flow visitResume(Resume* curr) { return Flow(NONCONSTANT_FLOW); } + Flow visitSuspend(Suspend* curr) { return Flow(NONCONSTANT_FLOW); } void trap(const char* why) override { externalInterface->trap(why); } diff --git a/src/wasm-ir-builder.h b/src/wasm-ir-builder.h index 917080fc4..7c4c4a36d 100644 --- a/src/wasm-ir-builder.h +++ b/src/wasm-ir-builder.h @@ -216,6 +216,7 @@ public: [[nodiscard]] Result<> makeResume(HeapType ct, const std::vector<Name>& tags, const std::vector<Index>& labels); + [[nodiscard]] Result<> makeSuspend(Name tag); // Private functions that must be public for technical reasons. [[nodiscard]] Result<> visitExpression(Expression*); @@ -256,6 +257,7 @@ public: [[nodiscard]] Result<> visitStringEncode(StringEncode*); [[nodiscard]] Result<> visitContBind(ContBind*); [[nodiscard]] Result<> visitResume(Resume*); + [[nodiscard]] Result<> visitSuspend(Suspend*); [[nodiscard]] Result<> visitTupleMake(TupleMake*); [[nodiscard]] Result<> visitTupleExtract(TupleExtract*, diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index e1d9dab47..7b8faa16b 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -331,6 +331,7 @@ private: Expression* makeContBind(Element& s); Expression* makeContNew(Element& s); Expression* makeResume(Element& s); + Expression* makeSuspend(Element& s); // Helper functions Type parseBlockType(Element& s, Index& i); diff --git a/src/wasm.h b/src/wasm.h index ad7ccb3ad..d852950e8 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -746,6 +746,7 @@ public: ContBindId, ContNewId, ResumeId, + SuspendId, NumExpressionIds }; Id _id; @@ -2048,6 +2049,19 @@ public: ArenaVector<Type> sentTypes; }; +class Suspend : public SpecificExpression<Expression::SuspendId> { +public: + Suspend(MixedArena& allocator) : operands(allocator) {} + + Name tag; + ExpressionList operands; + + // We need access to the module to obtain the signature of the tag, + // which determines this node's type. + // If no module is given, then the type must have been set already. + void finalize(Module* wasm = nullptr); +}; + // Globals struct Named { diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index efb65bb50..55cdd726c 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -4060,6 +4060,10 @@ BinaryConsts::ASTNodes WasmBinaryReader::readExpression(Expression*& curr) { visitResume((curr = allocator.alloc<Resume>())->cast<Resume>()); break; } + case BinaryConsts::Suspend: { + visitSuspend((curr = allocator.alloc<Suspend>())->cast<Suspend>()); + break; + } case BinaryConsts::AtomicPrefix: { code = static_cast<uint8_t>(getU32LEB()); if (maybeVisitLoad(curr, code, /*isAtomic=*/true)) { @@ -7869,6 +7873,26 @@ void WasmBinaryReader::visitResume(Resume* curr) { curr->finalize(&wasm); } +void WasmBinaryReader::visitSuspend(Suspend* curr) { + BYN_TRACE("zz node: Suspend\n"); + + auto tagIndex = getU32LEB(); + if (tagIndex >= wasm.tags.size()) { + throwError("bad tag index"); + } + auto* tag = wasm.tags[tagIndex].get(); + curr->tag = tag->name; + tagRefs[tagIndex].push_back(&curr->tag); + + auto numArgs = tag->sig.params.size(); + curr->operands.resize(numArgs); + for (size_t i = 0; i < numArgs; i++) { + curr->operands[numArgs - i - 1] = popNonVoidExpression(); + } + + curr->finalize(&wasm); +} + void WasmBinaryReader::throwError(std::string text) { throw ParseException(text, 0, pos); } diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index 4bc80d25c..99462e9a8 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -658,6 +658,19 @@ Result<> IRBuilder::visitResume(Resume* curr) { return Ok{}; } +Result<> IRBuilder::visitSuspend(Suspend* curr) { + auto tag = wasm.getTag(curr->tag); + auto sig = tag->sig; + auto size = sig.params.size(); + curr->operands.resize(size); + for (size_t i = 0; i < size; ++i) { + auto val = pop(); + CHECK_ERR(val); + curr->operands[size - i - 1] = *val; + } + return Ok{}; +} + Result<> IRBuilder::visitTupleMake(TupleMake* curr) { assert(curr->operands.size() >= 2); for (size_t i = 0, size = curr->operands.size(); i < size; ++i) { @@ -1930,4 +1943,14 @@ Result<> IRBuilder::makeResume(HeapType ct, return Ok{}; } +Result<> IRBuilder::makeSuspend(Name tag) { + Suspend curr(wasm.allocator); + curr.tag = tag; + CHECK_ERR(visitSuspend(&curr)); + + std::vector<Expression*> operands(curr.operands.begin(), curr.operands.end()); + push(builder.makeSuspend(tag, operands)); + return Ok{}; +} + } // namespace wasm diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 44ba84351..2d4f3fffe 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -3059,6 +3059,20 @@ Expression* SExpressionWasmBuilder::makeResume(Element& s) { return ret; } +Expression* SExpressionWasmBuilder::makeSuspend(Element& s) { + auto ret = allocator.alloc<Suspend>(); + + ret->tag = getTagName(*s[1]); + + Index i = 2; + while (i < s.size()) { + ret->operands.push_back(parseExpression(s[i++])); + } + + ret->finalize(&wasm); + return ret; +} + Expression* SExpressionWasmBuilder::makeRefI31(Element& s) { auto ret = allocator.alloc<RefI31>(); ret->value = parseExpression(s[1]); diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 90d5a3768..31742681d 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2512,6 +2512,10 @@ void BinaryInstWriter::visitResume(Resume* curr) { } } +void BinaryInstWriter::visitSuspend(Suspend* curr) { + o << int8_t(BinaryConsts::Suspend) << U32LEB(parent.getTagIndex(curr->tag)); +} + void BinaryInstWriter::emitScopeEnd(Expression* curr) { assert(!breakStack.empty()); breakStack.pop_back(); diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 4bb556160..0b60aed5c 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -490,6 +490,7 @@ public: void visitContBind(ContBind* curr); void visitContNew(ContNew* curr); void visitResume(Resume* curr); + void visitSuspend(Suspend* curr); void visitFunction(Function* curr); @@ -3345,6 +3346,14 @@ void FunctionValidator::visitResume(Resume* curr) { "invalid type in Resume expression"); } +void FunctionValidator::visitSuspend(Suspend* curr) { + // TODO implement actual type-checking + shouldBeTrue( + !getModule() || getModule()->features.hasTypedContinuations(), + curr, + "suspend requires typed-continuations [--enable-typed-continuations]"); +} + void FunctionValidator::visitFunction(Function* curr) { FeatureSet features; // Check for things like having a rec group with GC enabled. The type we're diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 7147f2c3d..bc707890c 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -1360,9 +1360,21 @@ void StringSliceIter::finalize() { } } -void ContBind::finalize() { type = Type(contTypeAfter, NonNullable); } +void ContBind::finalize() { + if (cont->type == Type::unreachable) { + type = Type::unreachable; + } else if (!handleUnreachableOperands(this)) { + type = Type(contTypeAfter, NonNullable); + } +} -void ContNew::finalize() { type = Type(contType, NonNullable); } +void ContNew::finalize() { + if (func->type == Type::unreachable) { + type = Type::unreachable; + } else { + type = Type(contType, NonNullable); + } +} static void populateResumeSentTypes(Resume* curr, Module* wasm) { if (!wasm) { @@ -1406,13 +1418,24 @@ static void populateResumeSentTypes(Resume* curr, Module* wasm) { } void Resume::finalize(Module* wasm) { - const Signature& contSig = - this->contType.getContinuation().type.getSignature(); - type = contSig.results; + if (cont->type == Type::unreachable) { + type = Type::unreachable; + } else if (!handleUnreachableOperands(this)) { + const Signature& contSig = + this->contType.getContinuation().type.getSignature(); + type = contSig.results; + } populateResumeSentTypes(this, wasm); } +void Suspend::finalize(Module* wasm) { + if (!handleUnreachableOperands(this) && wasm) { + auto tag = wasm->getTag(this->tag); + type = tag->sig.results; + } +} + size_t Function::getNumParams() { return getParams().size(); } size_t Function::getNumVars() { return vars.size(); } diff --git a/src/wasm2js.h b/src/wasm2js.h index 5f0305877..3ac4d2b4d 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -2440,6 +2440,10 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, unimplemented(curr); WASM_UNREACHABLE("unimp"); } + Ref visitSuspend(Suspend* curr) { + unimplemented(curr); + WASM_UNREACHABLE("unimp"); + } private: Ref makePointer(Expression* ptr, Address offset) { diff --git a/test/lit/basic/typed_continuations_suspend.wast b/test/lit/basic/typed_continuations_suspend.wast new file mode 100644 index 000000000..62a09c213 --- /dev/null +++ b/test/lit/basic/typed_continuations_suspend.wast @@ -0,0 +1,49 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. + +;; RUN: wasm-opt %s -all -o %t.text.wast -g -S +;; RUN: wasm-as %s -all -g -o %t.wasm +;; RUN: wasm-dis %t.wasm -all -o %t.bin.wast +;; RUN: wasm-as %s -all -o %t.nodebug.wasm +;; RUN: wasm-dis %t.nodebug.wasm -all -o %t.bin.nodebug.wast +;; RUN: cat %t.text.wast | filecheck %s --check-prefix=CHECK-TEXT +;; RUN: cat %t.bin.wast | filecheck %s --check-prefix=CHECK-BIN +;; RUN: cat %t.bin.nodebug.wast | filecheck %s --check-prefix=CHECK-BIN-NODEBUG + +(module + ;; CHECK-TEXT: (type $0 (func (param i32) (result i64))) + + ;; CHECK-TEXT: (type $1 (func (result i64))) + + ;; CHECK-TEXT: (tag $t (param i32) (result i64)) + ;; CHECK-BIN: (type $0 (func (param i32) (result i64))) + + ;; CHECK-BIN: (type $1 (func (result i64))) + + ;; CHECK-BIN: (tag $t (param i32) (result i64)) + (tag $t (param i32) (result i64)) + + ;; CHECK-TEXT: (func $f (type $1) (result i64) + ;; CHECK-TEXT-NEXT: (suspend $t + ;; CHECK-TEXT-NEXT: (i32.const 123) + ;; CHECK-TEXT-NEXT: ) + ;; CHECK-TEXT-NEXT: ) + ;; CHECK-BIN: (func $f (type $1) (result i64) + ;; CHECK-BIN-NEXT: (suspend $t + ;; CHECK-BIN-NEXT: (i32.const 123) + ;; CHECK-BIN-NEXT: ) + ;; CHECK-BIN-NEXT: ) + (func $f (result i64) + (suspend $t (i32.const 123)) + ) +) +;; CHECK-BIN-NODEBUG: (type $0 (func (param i32) (result i64))) + +;; CHECK-BIN-NODEBUG: (type $1 (func (result i64))) + +;; CHECK-BIN-NODEBUG: (tag $tag$0 (param i32) (result i64)) + +;; CHECK-BIN-NODEBUG: (func $0 (type $1) (result i64) +;; CHECK-BIN-NODEBUG-NEXT: (suspend $tag$0 +;; CHECK-BIN-NODEBUG-NEXT: (i32.const 123) +;; CHECK-BIN-NODEBUG-NEXT: ) +;; CHECK-BIN-NODEBUG-NEXT: ) diff --git a/test/lit/wat-kitchen-sink.wast b/test/lit/wat-kitchen-sink.wast index af9ce7ff0..c56523af1 100644 --- a/test/lit/wat-kitchen-sink.wast +++ b/test/lit/wat-kitchen-sink.wast @@ -13,9 +13,9 @@ (type $ret2 (func (result i32 i32))) (rec - ;; CHECK: (type $pair (struct (field $first (mut i32)) (field $second (mut i64)))) + ;; CHECK: (type $3 (func (result i32 i64))) - ;; CHECK: (type $4 (func (result i32 i64))) + ;; CHECK: (type $pair (struct (field $first (mut i32)) (field $second (mut i64)))) ;; CHECK: (type $5 (func (param i32 i64))) @@ -315,7 +315,7 @@ ;; CHECK: (import "mod" "f5" (func $fimport$0 (type $void))) - ;; CHECK: (import "mod" "imported-f" (func $fimport$1 (type $4) (result i32 i64))) + ;; CHECK: (import "mod" "imported-f" (func $fimport$1 (type $3) (result i32 i64))) ;; CHECK: (import "mod" "t0" (tag $imported (param i32 i64))) @@ -1874,8 +1874,8 @@ end ) - ;; CHECK: (func $try-catch-params (type $4) (result i32 i64) - ;; CHECK-NEXT: (try (type $4) (result i32 i64) + ;; CHECK: (func $try-catch-params (type $3) (result i32 i64) + ;; CHECK-NEXT: (try (type $3) (result i32 i64) ;; CHECK-NEXT: (do ;; CHECK-NEXT: (tuple.make 2 ;; CHECK-NEXT: (i32.const 0) @@ -1895,8 +1895,8 @@ end ) - ;; CHECK: (func $try-catch-pop (type $4) (result i32 i64) - ;; CHECK-NEXT: (try (type $4) (result i32 i64) + ;; CHECK: (func $try-catch-pop (type $3) (result i32 i64) + ;; CHECK-NEXT: (try (type $3) (result i32 i64) ;; CHECK-NEXT: (do ;; CHECK-NEXT: (tuple.make 2 ;; CHECK-NEXT: (i32.const 0) @@ -2754,8 +2754,8 @@ br 0 ) - ;; CHECK: (func $br-multivalue (type $4) (result i32 i64) - ;; CHECK-NEXT: (block $label (type $4) (result i32 i64) + ;; CHECK: (func $br-multivalue (type $3) (result i32 i64) + ;; CHECK-NEXT: (block $label (type $3) (result i32 i64) ;; CHECK-NEXT: (br $label ;; CHECK-NEXT: (tuple.make 2 ;; CHECK-NEXT: (i32.const 0) @@ -2770,9 +2770,9 @@ br 0 ) - ;; CHECK: (func $br-multivalue-drop (type $4) (result i32 i64) - ;; CHECK-NEXT: (block $label (type $4) (result i32 i64) - ;; CHECK-NEXT: (block (type $4) (result i32 i64) + ;; CHECK: (func $br-multivalue-drop (type $3) (result i32 i64) + ;; CHECK-NEXT: (block $label (type $3) (result i32 i64) + ;; CHECK-NEXT: (block (type $3) (result i32 i64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (f32.const 0) ;; CHECK-NEXT: ) @@ -2972,9 +2972,9 @@ end ) - ;; CHECK: (func $br-table-multivalue (type $4) (result i32 i64) - ;; CHECK-NEXT: (block $a (type $4) (result i32 i64) - ;; CHECK-NEXT: (block $b (type $4) (result i32 i64) + ;; CHECK: (func $br-table-multivalue (type $3) (result i32 i64) + ;; CHECK-NEXT: (block $a (type $3) (result i32 i64) + ;; CHECK-NEXT: (block $b (type $3) (result i32 i64) ;; CHECK-NEXT: (br_table $a $b ;; CHECK-NEXT: (tuple.make 2 ;; CHECK-NEXT: (i32.const 42) @@ -3662,7 +3662,7 @@ return ) - ;; CHECK: (func $return-multivalue (type $4) (result i32 i64) + ;; CHECK: (func $return-multivalue (type $3) (result i32 i64) ;; CHECK-NEXT: (return ;; CHECK-NEXT: (call $return-multivalue) ;; CHECK-NEXT: ) @@ -5141,6 +5141,18 @@ cont.bind $cont-bind-before $simple-cont ) + ;; CHECK: (func $suspend (type $3) (result i32 i64) + ;; CHECK-NEXT: (suspend $tag-pair-to-pair + ;; CHECK-NEXT: (i32.const 123) + ;; CHECK-NEXT: (i64.const 456) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $suspend (result i32 i64) + i32.const 123 + i64.const 456 + suspend $tag-pair-to-pair + ) + ;; CHECK: (func $source-maps (type $void) ;; CHECK-NEXT: ;;@ src.cpp:40:1 ;; CHECK-NEXT: (drop |