summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm/wat-parser.cpp153
-rw-r--r--test/lit/wat-kitchen-sink.wast98
2 files changed, 235 insertions, 16 deletions
diff --git a/src/wasm/wat-parser.cpp b/src/wasm/wat-parser.cpp
index f4057a732..15e193a31 100644
--- a/src/wasm/wat-parser.cpp
+++ b/src/wasm/wat-parser.cpp
@@ -653,6 +653,7 @@ struct NullInstrParserCtx {
using LocalIdxT = Ok;
using GlobalIdxT = Ok;
using MemoryIdxT = Ok;
+ using DataIdxT = Ok;
using MemargT = Ok;
@@ -675,6 +676,8 @@ struct NullInstrParserCtx {
GlobalIdxT getGlobalFromName(Name) { return Ok{}; }
MemoryIdxT getMemoryFromIdx(uint32_t) { return Ok{}; }
MemoryIdxT getMemoryFromName(Name) { return Ok{}; }
+ DataIdxT getDataFromIdx(uint32_t) { return Ok{}; }
+ DataIdxT getDataFromName(Name) { return Ok{}; }
MemargT getMemarg(uint64_t, uint32_t) { return Ok{}; }
@@ -723,6 +726,8 @@ struct NullInstrParserCtx {
Index, SIMDLoadStoreLaneOp, MemoryIdxT*, MemargT, uint8_t) {
return Ok{};
}
+ InstrT makeMemoryInit(Index, MemoryIdxT*, DataIdxT) { return Ok{}; }
+ InstrT makeDataDrop(Index, DataIdxT) { return Ok{}; }
InstrT makeMemoryCopy(Index, MemoryIdxT*, MemoryIdxT*) { return Ok{}; }
InstrT makeMemoryFill(Index, MemoryIdxT*) { return Ok{}; }
@@ -752,6 +757,16 @@ struct NullInstrParserCtx {
InstrT makeStructSet(Index, HeapTypeT, FieldIdxT) {
return Ok{};
}
+ template<typename HeapTypeT> InstrT makeArrayNew(Index, HeapTypeT) {
+ return Ok{};
+ }
+ template<typename HeapTypeT> InstrT makeArrayNewDefault(Index, HeapTypeT) {
+ return Ok{};
+ }
+ template<typename HeapTypeT>
+ InstrT makeArrayNewData(Index, HeapTypeT, DataIdxT) {
+ return Ok{};
+ }
};
// Phase 1: Parse definition spans for top-level module elements and determine
@@ -1226,6 +1241,7 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
using LocalIdxT = Index;
using GlobalIdxT = Name;
using MemoryIdxT = Name;
+ using DataIdxT = uint32_t;
using MemargT = Memarg;
@@ -1450,6 +1466,22 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
return name;
}
+ Result<uint32_t> getDataFromIdx(uint32_t idx) {
+ if (idx >= wasm.dataSegments.size()) {
+ return in.err("data index out of bounds");
+ }
+ return idx;
+ }
+
+ Result<uint32_t> getDataFromName(Name name) {
+ for (uint32_t i = 0; i < wasm.dataSegments.size(); ++i) {
+ if (wasm.dataSegments[i]->name == name) {
+ return i;
+ }
+ }
+ return in.err("data $" + name.toString() + " does not exist");
+ }
+
Result<TypeUseT> makeTypeUse(Index pos,
std::optional<HeapTypeT> type,
ParamsT* params,
@@ -1854,6 +1886,22 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
op, memarg.offset, memarg.align, lane, *ptr, *vec, *m));
}
+ Result<> makeMemoryInit(Index pos, Name* mem, uint32_t data) {
+ auto m = getMemory(pos, mem);
+ CHECK_ERR(m);
+ auto size = pop(pos);
+ CHECK_ERR(size);
+ auto offset = pop(pos);
+ CHECK_ERR(offset);
+ auto dest = pop(pos);
+ CHECK_ERR(dest);
+ return push(pos, builder.makeMemoryInit(data, *dest, *offset, *size, *m));
+ }
+
+ Result<> makeDataDrop(Index pos, uint32_t data) {
+ return push(pos, builder.makeDataDrop(data));
+ }
+
Result<> makeMemoryCopy(Index pos, Name* destMem, Name* srcMem) {
auto destMemory = getMemory(pos, destMem);
CHECK_ERR(destMemory);
@@ -1952,9 +2000,13 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
}
Result<> makeStructGet(Index pos, HeapType type, Index field, bool signed_) {
- assert(type.isStruct());
+ if (!type.isStruct()) {
+ return in.err(pos, "expected struct type annotation");
+ }
const auto& fields = type.getStruct().fields;
- assert(fields.size() > field);
+ if (field >= fields.size()) {
+ return in.err(pos, "struct field index out of bounds");
+ }
auto fieldType = fields[field].type;
auto ref = pop(pos);
CHECK_ERR(ref);
@@ -1963,8 +2015,12 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
}
Result<> makeStructSet(Index pos, HeapType type, Index field) {
- assert(type.isStruct());
- assert(type.getStruct().fields.size() > field);
+ if (!type.isStruct()) {
+ return in.err(pos, "expected struct type annotation");
+ }
+ if (field >= type.getStruct().fields.size()) {
+ return in.err(pos, "struct field index out of bounds");
+ }
auto val = pop(pos);
CHECK_ERR(val);
auto ref = pop(pos);
@@ -1972,6 +2028,38 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
CHECK_ERR(validateTypeAnnotation(pos, type, *ref));
return push(pos, builder.makeStructSet(field, *ref, *val));
}
+
+ Result<> makeArrayNew(Index pos, HeapType type) {
+ if (!type.isArray()) {
+ return in.err(pos, "expected array type annotation");
+ }
+ auto size = pop(pos);
+ CHECK_ERR(size);
+ auto val = pop(pos);
+ CHECK_ERR(val);
+ return push(pos, builder.makeArrayNew(type, *size, *val));
+ }
+
+ Result<> makeArrayNewDefault(Index pos, HeapType type) {
+ if (!type.isArray()) {
+ return in.err(pos, "expected array type annotation");
+ }
+ auto size = pop(pos);
+ CHECK_ERR(size);
+ return push(pos, builder.makeArrayNew(type, *size));
+ }
+
+ Result<> makeArrayNewData(Index pos, HeapType type, uint32_t data) {
+ if (!type.isArray()) {
+ return in.err(pos, "expected array type annotation");
+ }
+ auto size = pop(pos);
+ CHECK_ERR(size);
+ auto offset = pop(pos);
+ CHECK_ERR(offset);
+ return push(pos,
+ builder.makeArrayNewSeg(NewData, type, data, *offset, *size));
+ }
};
// ================
@@ -2881,12 +2969,33 @@ makeSIMDLoadStoreLane(Ctx& ctx, Index pos, SIMDLoadStoreLaneOp op, int bytes) {
template<typename Ctx>
Result<typename Ctx::InstrT> makeMemoryInit(Ctx& ctx, Index pos) {
- return ctx.in.err("unimplemented instruction");
+ auto reset = ctx.in.getPos();
+
+ auto retry = [&]() -> Result<typename Ctx::InstrT> {
+ // We failed to parse. Maybe the data index was accidentally parsed as the
+ // optional memory index. Try again without parsing a memory index.
+ WithPosition with(ctx, reset);
+ auto data = dataidx(ctx);
+ CHECK_ERR(data);
+ return ctx.makeMemoryInit(pos, nullptr, *data);
+ };
+
+ auto mem = maybeMemidx(ctx);
+ if (mem.getErr()) {
+ return retry();
+ }
+ auto data = dataidx(ctx);
+ if (data.getErr()) {
+ return retry();
+ }
+ return ctx.makeMemoryInit(pos, mem.getPtr(), *data);
}
template<typename Ctx>
Result<typename Ctx::InstrT> makeDataDrop(Ctx& ctx, Index pos) {
- return ctx.in.err("unimplemented instruction");
+ auto data = dataidx(ctx);
+ CHECK_ERR(data);
+ return ctx.makeDataDrop(pos, *data);
}
template<typename Ctx>
@@ -3094,13 +3203,29 @@ Result<typename Ctx::InstrT> makeStructSet(Ctx& ctx, Index pos) {
template<typename Ctx>
Result<typename Ctx::InstrT> makeArrayNew(Ctx& ctx, Index pos, bool default_) {
- return ctx.in.err("unimplemented instruction");
+ auto type = typeidx(ctx);
+ CHECK_ERR(type);
+ if (default_) {
+ return ctx.makeArrayNewDefault(pos, *type);
+ }
+ return ctx.makeArrayNew(pos, *type);
}
template<typename Ctx>
Result<typename Ctx::InstrT>
makeArrayNewSeg(Ctx& ctx, Index pos, ArrayNewSegOp op) {
- return ctx.in.err("unimplemented instruction");
+ auto type = typeidx(ctx);
+ CHECK_ERR(type);
+ switch (op) {
+ case NewData: {
+ auto data = dataidx(ctx);
+ CHECK_ERR(data);
+ return ctx.makeArrayNewData(pos, *type, *data);
+ }
+ case NewElem:
+ return ctx.in.err("unimplemented instruction");
+ }
+ WASM_UNREACHABLE("unexpected op");
}
template<typename Ctx>
@@ -3291,6 +3416,18 @@ template<typename Ctx> Result<typename Ctx::GlobalIdxT> globalidx(Ctx& ctx) {
return ctx.in.err("expected global index or identifier");
}
+// dataidx ::= x:u32 => x
+// | v:id => x (if data[x] = v)
+template<typename Ctx> Result<typename Ctx::DataIdxT> dataidx(Ctx& ctx) {
+ if (auto x = ctx.in.takeU32()) {
+ return ctx.getDataFromIdx(*x);
+ }
+ if (auto id = ctx.in.takeID()) {
+ return ctx.getDataFromName(*id);
+ }
+ return ctx.in.err("expected data index or identifier");
+}
+
// localidx ::= x:u32 => x
// | v:id => x (if locals[x] = v)
template<typename Ctx> Result<typename Ctx::LocalIdxT> localidx(Ctx& ctx) {
diff --git a/test/lit/wat-kitchen-sink.wast b/test/lit/wat-kitchen-sink.wast
index 124600e63..976be4401 100644
--- a/test/lit/wat-kitchen-sink.wast
+++ b/test/lit/wat-kitchen-sink.wast
@@ -5,10 +5,10 @@
(module $parse
;; types
- ;; CHECK: (type $pair (struct (field (mut i32)) (field (mut i64))))
-
;; CHECK: (type $void (func))
+ ;; CHECK: (type $pair (struct (field (mut i32)) (field (mut i64))))
+
;; CHECK: (type $none_=>_i32 (func (result i32)))
;; CHECK: (type $ret2 (func (result i32 i32)))
@@ -17,8 +17,12 @@
(rec
;; CHECK: (type $i32_i64_=>_none (func (param i32 i64)))
+ ;; CHECK: (type $a1 (array i64))
+
;; CHECK: (type $i32_=>_none (func (param i32)))
+ ;; CHECK: (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+
;; CHECK: (type $v128_i32_=>_v128 (func (param v128 i32) (result v128)))
;; CHECK: (type $many (func (param i32 i64 f32 f64) (result anyref (ref func))))
@@ -29,8 +33,6 @@
;; CHECK: (type $i64_=>_none (func (param i64)))
- ;; CHECK: (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
-
;; CHECK: (type $v128_=>_i32 (func (param v128) (result i32)))
;; CHECK: (type $v128_v128_=>_v128 (func (param v128 v128) (result v128)))
@@ -71,6 +73,12 @@
;; CHECK: (type $ref|$pair|_i64_=>_none (func (param (ref $pair) i64)))
+ ;; CHECK: (type $i64_i32_=>_ref|$a1| (func (param i64 i32) (result (ref $a1))))
+
+ ;; CHECK: (type $i32_=>_ref|$a1| (func (param i32) (result (ref $a1))))
+
+ ;; CHECK: (type $i32_i32_=>_ref|$a1| (func (param i32 i32) (result (ref $a1))))
+
;; CHECK: (rec
;; CHECK-NEXT: (type $s0 (struct ))
(type $s0 (sub (struct)))
@@ -97,7 +105,6 @@
;; CHECK: (type $a0 (array i32))
(type $a0 (array i32))
- ;; CHECK: (type $a1 (array i64))
(type $a1 (array (field i64)))
;; CHECK: (type $a2 (array (mut f32)))
(type $a2 (array (mut f32)))
@@ -1097,6 +1104,47 @@
v128.store64_lane 3 align=4 0
)
+ ;; CHECK: (func $memory-init (type $i32_i32_i32_=>_none) (param $0 i32) (param $1 i32) (param $2 i32)
+ ;; CHECK-NEXT: (memory.init $mem-i32 2
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (memory.init $mem-i64 1
+ ;; CHECK-NEXT: (i64.const 0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (memory.init $mem 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $memory-init (param i32 i32 i32)
+ local.get 0
+ local.get 1
+ local.get 2
+ memory.init $mem-i32 $passive
+ i64.const 0
+ local.get 1
+ local.get 2
+ memory.init 3 1
+ local.get 0
+ local.get 1
+ local.get 2
+ memory.init 0
+ )
+
+ ;; CHECK: (func $data-drop (type $void)
+ ;; CHECK-NEXT: (data.drop 0)
+ ;; CHECK-NEXT: (data.drop 2)
+ ;; CHECK-NEXT: )
+ (func $data-drop
+ data.drop 0
+ data.drop $passive
+ )
+
;; CHECK: (func $memory-copy (type $i32_i32_i64_i64_=>_none) (param $0 i32) (param $1 i32) (param $2 i64) (param $3 i64)
;; CHECK-NEXT: (memory.copy $mem $mem
;; CHECK-NEXT: (local.get $0)
@@ -1319,7 +1367,7 @@
;; CHECK-NEXT: (struct.new_default $pair)
;; CHECK-NEXT: )
(func $struct-new-default (result (ref $pair))
- struct.new_default $pair
+ struct.new_default 14
)
;; CHECK: (func $struct-get-0 (type $ref|$pair|_=>_i32) (param $0 (ref $pair)) (result i32)
@@ -1329,7 +1377,7 @@
;; CHECK-NEXT: )
(func $struct-get-0 (param (ref $pair)) (result i32)
local.get 0
- struct.get $pair 0
+ struct.get 14 0
)
;; CHECK: (func $struct-get-1 (type $ref|$pair|_=>_i64) (param $0 (ref $pair)) (result i64)
@@ -1363,7 +1411,41 @@
(func $struct-set-1 (param (ref $pair) i64)
local.get 0
local.get 1
- struct.set $pair 1
+ struct.set 14 1
+ )
+
+ ;; CHECK: (func $array-new (type $i64_i32_=>_ref|$a1|) (param $0 i64) (param $1 i32) (result (ref $a1))
+ ;; CHECK-NEXT: (array.new $a1
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-new (param i64 i32) (result (ref 11))
+ local.get 0
+ local.get 1
+ array.new $a1
+ )
+
+ ;; CHECK: (func $array-new-default (type $i32_=>_ref|$a1|) (param $0 i32) (result (ref $a1))
+ ;; CHECK-NEXT: (array.new_default $a1
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-new-default (param i32) (result (ref $a1))
+ local.get 0
+ array.new_default 11
+ )
+
+ ;; CHECK: (func $array-new-data (type $i32_i32_=>_ref|$a1|) (param $0 i32) (param $1 i32) (result (ref $a1))
+ ;; CHECK-NEXT: (array.new_data $a1 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-new-data (param i32 i32) (result (ref $a1))
+ local.get 0
+ local.get 1
+ array.new_data $a1 0
)
;; CHECK: (func $use-types (type $ref|$s0|_ref|$s1|_ref|$s2|_ref|$s3|_ref|$s4|_ref|$s5|_ref|$s6|_ref|$s7|_ref|$s8|_ref|$a0|_ref|$a1|_ref|$a2|_ref|$a3|_ref|$subvoid|_ref|$submany|_=>_none) (param $0 (ref $s0)) (param $1 (ref $s1)) (param $2 (ref $s2)) (param $3 (ref $s3)) (param $4 (ref $s4)) (param $5 (ref $s5)) (param $6 (ref $s6)) (param $7 (ref $s7)) (param $8 (ref $s8)) (param $9 (ref $a0)) (param $10 (ref $a1)) (param $11 (ref $a2)) (param $12 (ref $a3)) (param $13 (ref $subvoid)) (param $14 (ref $submany))