Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/parser/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -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{};
Expand Down Expand Up @@ -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());
}
Expand Down
15 changes: 14 additions & 1 deletion src/parser/parsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add a comment here explaining the logic and the intended outcome of parsing at least one label.

// 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) {
Expand Down
8 changes: 7 additions & 1 deletion src/wasm-ir-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
[[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();
Expand Down Expand Up @@ -191,6 +192,8 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
[[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:
Expand Down Expand Up @@ -392,6 +395,9 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
// 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
Expand Down
45 changes: 39 additions & 6 deletions src/wasm/wasm-ir-builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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{};
}

Expand Down Expand Up @@ -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);
Expand Down
145 changes: 127 additions & 18 deletions test/lit/wat-kitchen-sink.wast
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
Expand Down Expand Up @@ -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)
Expand All @@ -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: )
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -2218,7 +2327,7 @@
(func $ref-func
ref.func $ref-func
drop
ref.func 102
ref.func 107
drop
)

Expand Down