diff options
-rw-r--r-- | src/parser/contexts.h | 8 | ||||
-rw-r--r-- | src/parser/parsers.h | 15 | ||||
-rw-r--r-- | src/wasm-ir-builder.h | 8 | ||||
-rw-r--r-- | src/wasm/wasm-ir-builder.cpp | 45 | ||||
-rw-r--r-- | test/lit/wat-kitchen-sink.wast | 145 |
5 files changed, 195 insertions, 26 deletions
diff --git a/src/parser/contexts.h b/src/parser/contexts.h index 6a3ab9614..485c596e7 100644 --- a/src/parser/contexts.h +++ b/src/parser/contexts.h @@ -383,6 +383,9 @@ struct NullInstrParserCtx { Result<> makeMemoryFill(Index, MemoryIdxT*) { return Ok{}; } Result<> makeCall(Index, FuncIdxT, bool) { return Ok{}; } Result<> makeBreak(Index, LabelIdxT) { return Ok{}; } + Result<> makeSwitch(Index, const std::vector<LabelIdxT>&, LabelIdxT) { + return Ok{}; + } Result<> makeReturn(Index) { return Ok{}; } template<typename HeapTypeT> Result<> makeRefNull(Index, HeapTypeT) { return Ok{}; @@ -1246,6 +1249,11 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { return withLoc(pos, irBuilder.makeBreak(label)); } + Result<> + makeSwitch(Index pos, const std::vector<Index> labels, Index defaultLabel) { + return withLoc(pos, irBuilder.makeSwitch(labels, defaultLabel)); + } + Result<> makeReturn(Index pos) { return withLoc(pos, irBuilder.makeReturn()); } diff --git a/src/parser/parsers.h b/src/parser/parsers.h index eb93fa717..0641e941c 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -1200,7 +1200,20 @@ template<typename Ctx> Result<> makeBreak(Ctx& ctx, Index pos) { } template<typename Ctx> Result<> makeBreakTable(Ctx& ctx, Index pos) { - return ctx.in.err("unimplemented instruction"); + std::vector<typename Ctx::LabelIdxT> labels; + while (true) { + // Parse at least one label; return an error only if we parse none. + auto label = labelidx(ctx); + if (labels.empty()) { + CHECK_ERR(label); + } else if (label.getErr()) { + break; + } + labels.push_back(*label); + } + auto defaultLabel = labels.back(); + labels.pop_back(); + return ctx.makeSwitch(pos, labels, defaultLabel); } template<typename Ctx> Result<> makeReturn(Ctx& ctx, Index pos) { diff --git a/src/wasm-ir-builder.h b/src/wasm-ir-builder.h index 2fc03326b..6d4fca3c3 100644 --- a/src/wasm-ir-builder.h +++ b/src/wasm-ir-builder.h @@ -76,7 +76,8 @@ public: [[nodiscard]] Result<> makeIf(Name label, Type type); [[nodiscard]] Result<> makeLoop(Name label, Type type); [[nodiscard]] Result<> makeBreak(Index label); - // [[nodiscard]] Result<> makeSwitch(); + [[nodiscard]] Result<> makeSwitch(const std::vector<Index>& labels, + Index defaultLabel); // Unlike Builder::makeCall, this assumes the function already exists. [[nodiscard]] Result<> makeCall(Name func, bool isReturn); // [[nodiscard]] Result<> makeCallIndirect(); @@ -191,6 +192,8 @@ public: [[nodiscard]] Result<> visitArrayNew(ArrayNew*); [[nodiscard]] Result<> visitBreak(Break*, std::optional<Index> label = std::nullopt); + [[nodiscard]] Result<> + visitSwitch(Switch*, std::optional<Index> defaultLabel = std::nullopt); [[nodiscard]] Result<> visitCall(Call*); private: @@ -392,6 +395,9 @@ private: // the value, if they are different. May only be called directly after // hoistLastValue(). [[nodiscard]] Result<> packageHoistedValue(const HoistedVal&); + + [[nodiscard]] Result<Expression*> getBranchValue(Name labelName, + std::optional<Index> label); }; } // namespace wasm diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index 0c5f0830e..cbb16ff68 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -290,9 +290,10 @@ Result<> IRBuilder::visitArrayNew(ArrayNew* curr) { return Ok{}; } -Result<> IRBuilder::visitBreak(Break* curr, std::optional<Index> label) { +Result<Expression*> IRBuilder::getBranchValue(Name labelName, + std::optional<Index> label) { if (!label) { - auto index = getLabelIndex(curr->name); + auto index = getLabelIndex(labelName); CHECK_ERR(index); label = *index; } @@ -305,12 +306,29 @@ Result<> IRBuilder::visitBreak(Break* curr, std::optional<Index> label) { values[size - 1 - i] = *val; } if (values.size() == 0) { - curr->value = nullptr; + return nullptr; } else if (values.size() == 1) { - curr->value = values[0]; + return values[0]; } else { - curr->value = builder.makeTupleMake(values); + return builder.makeTupleMake(values); } +} + +Result<> IRBuilder::visitBreak(Break* curr, std::optional<Index> label) { + auto value = getBranchValue(curr->name, label); + CHECK_ERR(value); + curr->value = *value; + return Ok{}; +} + +Result<> IRBuilder::visitSwitch(Switch* curr, + std::optional<Index> defaultLabel) { + auto cond = pop(); + CHECK_ERR(cond); + curr->condition = *cond; + auto value = getBranchValue(curr->default_, defaultLabel); + CHECK_ERR(value); + curr->value = *value; return Ok{}; } @@ -556,7 +574,22 @@ Result<> IRBuilder::makeBreak(Index label) { return Ok{}; } -// Result<> IRBuilder::makeSwitch() {} +Result<> IRBuilder::makeSwitch(const std::vector<Index>& labels, + Index defaultLabel) { + std::vector<Name> names; + names.reserve(labels.size()); + for (auto label : labels) { + auto name = getLabelName(label); + CHECK_ERR(name); + names.push_back(*name); + } + auto defaultName = getLabelName(defaultLabel); + CHECK_ERR(defaultName); + Switch curr(wasm.allocator); + CHECK_ERR(visitSwitch(&curr, defaultLabel)); + push(builder.makeSwitch(names, *defaultName, curr.condition, curr.value)); + return Ok{}; +} Result<> IRBuilder::makeCall(Name func, bool isReturn) { Call curr(wasm.allocator); diff --git a/test/lit/wat-kitchen-sink.wast b/test/lit/wat-kitchen-sink.wast index 5f2742591..f57541e90 100644 --- a/test/lit/wat-kitchen-sink.wast +++ b/test/lit/wat-kitchen-sink.wast @@ -15,14 +15,14 @@ (rec ;; CHECK: (type $pair (struct (field (mut i32)) (field (mut i64)))) - ;; CHECK: (type $4 (func (param i32 i64))) + ;; CHECK: (type $4 (func (result i32 i64))) + + ;; CHECK: (type $5 (func (param i32 i64))) ;; CHECK: (type $a1 (array i64)) ;; CHECK: (type $a2 (array (mut f32))) - ;; CHECK: (type $7 (func (result i32 i64))) - ;; CHECK: (type $8 (func (param i32))) ;; CHECK: (type $9 (func (param i32 i32 i32))) @@ -1569,8 +1569,8 @@ br 0 ) - ;; CHECK: (func $br-multivalue (type $7) (result i32 i64) - ;; CHECK-NEXT: (block $label (type $7) (result i32 i64) + ;; CHECK: (func $br-multivalue (type $4) (result i32 i64) + ;; CHECK-NEXT: (block $label (type $4) (result i32 i64) ;; CHECK-NEXT: (br $label ;; CHECK-NEXT: (tuple.make ;; CHECK-NEXT: (i32.const 0) @@ -1585,9 +1585,9 @@ br 0 ) - ;; CHECK: (func $br-multivalue-drop (type $7) (result i32 i64) - ;; CHECK-NEXT: (block $label (type $7) (result i32 i64) - ;; CHECK-NEXT: (block (type $7) (result i32 i64) + ;; 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-NEXT: (drop ;; CHECK-NEXT: (f32.const 0) ;; CHECK-NEXT: ) @@ -1607,6 +1607,115 @@ br 0 ) + ;; CHECK: (func $br-table (type $void) + ;; CHECK-NEXT: (block $a + ;; CHECK-NEXT: (block $b + ;; CHECK-NEXT: (block $c + ;; CHECK-NEXT: (block $d + ;; CHECK-NEXT: (br_table $a $b $d $c + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $br-table + block $a + block $b + block $c + block $d + i32.const 0 + br_table $a $b $d $c + end + end + end + end + ) + + ;; CHECK: (func $br-table-index (type $void) + ;; CHECK-NEXT: (block $label + ;; CHECK-NEXT: (block $l + ;; CHECK-NEXT: (block $label_1 + ;; CHECK-NEXT: (block $label_0 + ;; CHECK-NEXT: (br_table $label $l $label_0 $label_1 + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $br-table-index + block + block $l + block + block + i32.const 0 + br_table 3 2 0 1 + end + end + end + end + ) + + ;; CHECK: (func $br-table-return (type $void) + ;; CHECK-NEXT: (block $label + ;; CHECK-NEXT: (br_table $label $label $label $label $label $label $label $label + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $br-table-return + i32.const 0 + br_table 0 0 0 0 0 0 0 0 + ) + + ;; CHECK: (func $br-table-value (type $1) (result i32) + ;; CHECK-NEXT: (block $a (result i32) + ;; CHECK-NEXT: (block $b (result i32) + ;; CHECK-NEXT: (br_table $a $b + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $br-table-value (result i32) + block $a (result i32) + block $b (result i32) + i32.const 42 + i32.const 0 + br_table $a $b + end + 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-NEXT: (br_table $a $b + ;; CHECK-NEXT: (tuple.make + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (i64.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $br-table-multivalue (result i32 i64) + block $a (result i32 i64) + block $b (result i32 i64) + i32.const 42 + i64.const 42 + i32.const 0 + br_table $a $b + end + end + ) + + ;; CHECK: (func $binary (type $16) (param $0 i32) (param $1 i32) (param $2 f64) (param $3 f64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.add @@ -1718,7 +1827,7 @@ drop ) - ;; CHECK: (func $memory-grow (type $4) (param $0 i32) (param $1 i64) + ;; CHECK: (func $memory-grow (type $5) (param $0 i32) (param $1 i64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (memory.grow $mem ;; CHECK-NEXT: (local.get $0) @@ -1757,7 +1866,7 @@ global.set 4 ) - ;; CHECK: (func $load (type $4) (param $0 i32) (param $1 i64) + ;; CHECK: (func $load (type $5) (param $0 i32) (param $1 i64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.load $mem offset=42 ;; CHECK-NEXT: (local.get $0) @@ -1786,7 +1895,7 @@ drop ) - ;; CHECK: (func $store (type $4) (param $0 i32) (param $1 i64) + ;; CHECK: (func $store (type $5) (param $0 i32) (param $1 i64) ;; CHECK-NEXT: (i32.store $mem offset=42 align=1 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (i32.const 0) @@ -1812,7 +1921,7 @@ f32.store $mem-i64 ) - ;; CHECK: (func $atomic-rmw (type $4) (param $0 i32) (param $1 i64) + ;; CHECK: (func $atomic-rmw (type $5) (param $0 i32) (param $1 i64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.atomic.rmw16.add_u $mem ;; CHECK-NEXT: (local.get $0) @@ -1837,7 +1946,7 @@ drop ) - ;; CHECK: (func $atomic-cmpxchg (type $4) (param $0 i32) (param $1 i64) + ;; CHECK: (func $atomic-cmpxchg (type $5) (param $0 i32) (param $1 i64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.atomic.rmw8.cmpxchg_u $mem ;; CHECK-NEXT: (local.get $0) @@ -1866,7 +1975,7 @@ drop ) - ;; CHECK: (func $atomic-wait (type $4) (param $0 i32) (param $1 i64) + ;; CHECK: (func $atomic-wait (type $5) (param $0 i32) (param $1 i64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (memory.atomic.wait32 $mem ;; CHECK-NEXT: (local.get $0) @@ -1895,7 +2004,7 @@ drop ) - ;; CHECK: (func $atomic-notify (type $4) (param $0 i32) (param $1 i64) + ;; CHECK: (func $atomic-notify (type $5) (param $0 i32) (param $1 i64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (memory.atomic.notify $mem offset=8 ;; CHECK-NEXT: (local.get $0) @@ -1987,7 +2096,7 @@ i8x16.shl ) - ;; CHECK: (func $simd-load (type $4) (param $0 i32) (param $1 i64) + ;; CHECK: (func $simd-load (type $5) (param $0 i32) (param $1 i64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (v128.load8x8_s $mem offset=8 ;; CHECK-NEXT: (local.get $0) @@ -2103,7 +2212,7 @@ memory.copy $mem-i64 3 ) - ;; CHECK: (func $memory-fill (type $4) (param $0 i32) (param $1 i64) + ;; CHECK: (func $memory-fill (type $5) (param $0 i32) (param $1 i64) ;; CHECK-NEXT: (memory.fill $mem ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (i32.const 1) @@ -2218,7 +2327,7 @@ (func $ref-func ref.func $ref-func drop - ref.func 102 + ref.func 107 drop ) |