summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/parser/contexts.h8
-rw-r--r--src/parser/parsers.h15
-rw-r--r--src/wasm-ir-builder.h8
-rw-r--r--src/wasm/wasm-ir-builder.cpp45
-rw-r--r--test/lit/wat-kitchen-sink.wast145
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
)