diff options
-rw-r--r-- | src/wasm/wat-parser.cpp | 153 | ||||
-rw-r--r-- | test/lit/wat-kitchen-sink.wast | 98 |
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)) |