diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gen-s-parser.inc | 42 | ||||
-rw-r--r-- | src/passes/Print.cpp | 16 | ||||
-rw-r--r-- | src/wasm-binary.h | 12 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 37 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 65 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 30 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 5 |
7 files changed, 166 insertions, 41 deletions
diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 98f5b7831..c54a0de54 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -454,12 +454,23 @@ switch (buf[0]) { return Ok{}; } goto parse_error; - case 'o': - if (op == "f32.load"sv) { - CHECK_ERR(makeLoad(ctx, pos, annotations, Type::f32, /*signed=*/false, 4, /*isAtomic=*/false)); - return Ok{}; + case 'o': { + switch (buf[8]) { + case '\0': + if (op == "f32.load"sv) { + CHECK_ERR(makeLoad(ctx, pos, annotations, Type::f32, /*signed=*/false, 4, /*isAtomic=*/false)); + return Ok{}; + } + goto parse_error; + case '_': + if (op == "f32.load_f16"sv) { + CHECK_ERR(makeLoad(ctx, pos, annotations, Type::f32, /*signed=*/false, 2, /*isAtomic=*/false)); + return Ok{}; + } + goto parse_error; + default: goto parse_error; } - goto parse_error; + } case 't': if (op == "f32.lt"sv) { CHECK_ERR(makeBinary(ctx, pos, annotations, BinaryOp::LtFloat32)); @@ -529,12 +540,23 @@ switch (buf[0]) { return Ok{}; } goto parse_error; - case 't': - if (op == "f32.store"sv) { - CHECK_ERR(makeStore(ctx, pos, annotations, Type::f32, 4, /*isAtomic=*/false)); - return Ok{}; + case 't': { + switch (buf[9]) { + case '\0': + if (op == "f32.store"sv) { + CHECK_ERR(makeStore(ctx, pos, annotations, Type::f32, 4, /*isAtomic=*/false)); + return Ok{}; + } + goto parse_error; + case '_': + if (op == "f32.store_f16"sv) { + CHECK_ERR(makeStore(ctx, pos, annotations, Type::f32, 2, /*isAtomic=*/false)); + return Ok{}; + } + goto parse_error; + default: goto parse_error; } - goto parse_error; + } case 'u': if (op == "f32.sub"sv) { CHECK_ERR(makeBinary(ctx, pos, annotations, BinaryOp::SubFloat32)); diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index ede49ab38..aca43924d 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -548,13 +548,19 @@ struct PrintExpressionContents if (curr->bytes == 1) { o << '8'; } else if (curr->bytes == 2) { - o << "16"; + if (curr->type == Type::f32) { + o << "_f16"; + } else { + o << "16"; + } } else if (curr->bytes == 4) { o << "32"; } else { abort(); } - o << (curr->signed_ ? "_s" : "_u"); + if (curr->type != Type::f32) { + o << (curr->signed_ ? "_s" : "_u"); + } } restoreNormalColor(o); printMemoryName(curr->memory, o, wasm); @@ -575,7 +581,11 @@ struct PrintExpressionContents if (curr->bytes == 1) { o << '8'; } else if (curr->bytes == 2) { - o << "16"; + if (curr->valueType == Type::f32) { + o << "_f16"; + } else { + o << "16"; + } } else if (curr->bytes == 4) { o << "32"; } else { diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 8a6f825ff..5fae1b64d 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1051,6 +1051,10 @@ enum ASTNodes { I16x8DotI8x16I7x16S = 0x112, I32x4DotI8x16I7x16AddS = 0x113, + // half precision opcodes + F32_F16LoadMem = 0x30, + F32_F16StoreMem = 0x31, + // bulk memory opcodes MemoryInit = 0x08, @@ -1703,8 +1707,12 @@ public: void visitLocalSet(LocalSet* curr, uint8_t code); void visitGlobalGet(GlobalGet* curr); void visitGlobalSet(GlobalSet* curr); - bool maybeVisitLoad(Expression*& out, uint8_t code, bool isAtomic); - bool maybeVisitStore(Expression*& out, uint8_t code, bool isAtomic); + bool maybeVisitLoad(Expression*& out, + uint8_t code, + std::optional<BinaryConsts::ASTNodes> prefix); + bool maybeVisitStore(Expression*& out, + uint8_t code, + std::optional<BinaryConsts::ASTNodes> prefix); bool maybeVisitNontrappingTrunc(Expression*& out, uint32_t code); bool maybeVisitAtomicRMW(Expression*& out, uint8_t code); bool maybeVisitAtomicCmpxchg(Expression*& out, uint8_t code); diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 9bdf0e72c..3e62d5335 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -28,6 +28,7 @@ #include <sstream> #include <variant> +#include "fp16.h" #include "ir/intrinsics.h" #include "ir/module-utils.h" #include "support/bits.h" @@ -2540,8 +2541,22 @@ public: } break; } - case Type::f32: - return Literal(load32u(addr, memory)).castToF32(); + case Type::f32: { + switch (load->bytes) { + case 2: { + // Convert the float16 to float32 and store the binary + // representation. + return Literal(bit_cast<int32_t>( + fp16_ieee_to_fp32_value(load16u(addr, memory)))) + .castToF32(); + } + case 4: + return Literal(load32u(addr, memory)).castToF32(); + default: + WASM_UNREACHABLE("invalid size"); + } + break; + } case Type::f64: return Literal(load64u(addr, memory)).castToF64(); case Type::v128: @@ -2590,9 +2605,23 @@ public: break; } // write floats carefully, ensuring all bits reach memory - case Type::f32: - store32(addr, value.reinterpreti32(), memory); + case Type::f32: { + switch (store->bytes) { + case 2: { + float f32 = bit_cast<float>(value.reinterpreti32()); + // Convert the float32 to float16 and store the binary + // representation. + store16(addr, fp16_ieee_from_fp32_value(f32), memory); + break; + } + case 4: + store32(addr, value.reinterpreti32(), memory); + break; + default: + WASM_UNREACHABLE("invalid store size"); + } break; + } case Type::f64: store64(addr, value.reinterpreti64(), memory); break; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 574e13aa2..b9645ab8f 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -4145,10 +4145,10 @@ BinaryConsts::ASTNodes WasmBinaryReader::readExpression(Expression*& curr) { } case BinaryConsts::AtomicPrefix: { code = static_cast<uint8_t>(getU32LEB()); - if (maybeVisitLoad(curr, code, /*isAtomic=*/true)) { + if (maybeVisitLoad(curr, code, BinaryConsts::AtomicPrefix)) { break; } - if (maybeVisitStore(curr, code, /*isAtomic=*/true)) { + if (maybeVisitStore(curr, code, BinaryConsts::AtomicPrefix)) { break; } if (maybeVisitAtomicRMW(curr, code)) { @@ -4198,6 +4198,12 @@ BinaryConsts::ASTNodes WasmBinaryReader::readExpression(Expression*& curr) { if (maybeVisitTableCopy(curr, opcode)) { break; } + if (maybeVisitLoad(curr, opcode, BinaryConsts::MiscPrefix)) { + break; + } + if (maybeVisitStore(curr, opcode, BinaryConsts::MiscPrefix)) { + break; + } throwError("invalid code after misc prefix: " + std::to_string(opcode)); break; } @@ -4338,10 +4344,10 @@ BinaryConsts::ASTNodes WasmBinaryReader::readExpression(Expression*& curr) { if (maybeVisitConst(curr, code)) { break; } - if (maybeVisitLoad(curr, code, /*isAtomic=*/false)) { + if (maybeVisitLoad(curr, code, /*prefix=*/std::nullopt)) { break; } - if (maybeVisitStore(curr, code, /*isAtomic=*/false)) { + if (maybeVisitStore(curr, code, /*prefix=*/std::nullopt)) { break; } throwError("bad node code " + std::to_string(code)); @@ -4717,14 +4723,15 @@ Index WasmBinaryReader::readMemoryAccess(Address& alignment, Address& offset) { return memIdx; } -bool WasmBinaryReader::maybeVisitLoad(Expression*& out, - uint8_t code, - bool isAtomic) { +bool WasmBinaryReader::maybeVisitLoad( + Expression*& out, + uint8_t code, + std::optional<BinaryConsts::ASTNodes> prefix) { Load* curr; auto allocate = [&]() { curr = allocator.alloc<Load>(); }; - if (!isAtomic) { + if (!prefix) { switch (code) { case BinaryConsts::I32LoadMem8S: allocate(); @@ -4805,7 +4812,7 @@ bool WasmBinaryReader::maybeVisitLoad(Expression*& out, return false; } BYN_TRACE("zz node: Load\n"); - } else { + } else if (prefix == BinaryConsts::AtomicPrefix) { switch (code) { case BinaryConsts::I32AtomicLoad8U: allocate(); @@ -4846,9 +4853,22 @@ bool WasmBinaryReader::maybeVisitLoad(Expression*& out, return false; } BYN_TRACE("zz node: AtomicLoad\n"); + } else if (prefix == BinaryConsts::MiscPrefix) { + switch (code) { + case BinaryConsts::F32_F16LoadMem: + allocate(); + curr->bytes = 2; + curr->type = Type::f32; + break; + default: + return false; + } + BYN_TRACE("zz node: Load\n"); + } else { + return false; } - curr->isAtomic = isAtomic; + curr->isAtomic = prefix == BinaryConsts::AtomicPrefix; Index memIdx = readMemoryAccess(curr->align, curr->offset); memoryRefs[memIdx].push_back(&curr->memory); curr->ptr = popNonVoidExpression(); @@ -4857,11 +4877,12 @@ bool WasmBinaryReader::maybeVisitLoad(Expression*& out, return true; } -bool WasmBinaryReader::maybeVisitStore(Expression*& out, - uint8_t code, - bool isAtomic) { +bool WasmBinaryReader::maybeVisitStore( + Expression*& out, + uint8_t code, + std::optional<BinaryConsts::ASTNodes> prefix) { Store* curr; - if (!isAtomic) { + if (!prefix) { switch (code) { case BinaryConsts::I32StoreMem8: curr = allocator.alloc<Store>(); @@ -4911,7 +4932,7 @@ bool WasmBinaryReader::maybeVisitStore(Expression*& out, default: return false; } - } else { + } else if (prefix == BinaryConsts::AtomicPrefix) { switch (code) { case BinaryConsts::I32AtomicStore8: curr = allocator.alloc<Store>(); @@ -4951,9 +4972,21 @@ bool WasmBinaryReader::maybeVisitStore(Expression*& out, default: return false; } + } else if (prefix == BinaryConsts::MiscPrefix) { + switch (code) { + case BinaryConsts::F32_F16StoreMem: + curr = allocator.alloc<Store>(); + curr->bytes = 2; + curr->valueType = Type::f32; + break; + default: + return false; + } + } else { + return false; } - curr->isAtomic = isAtomic; + curr->isAtomic = prefix == BinaryConsts::AtomicPrefix; BYN_TRACE("zz node: Store\n"); Index memIdx = readMemoryAccess(curr->align, curr->offset); memoryRefs[memIdx].push_back(&curr->memory); diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index cd0a9928e..35db3b322 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -258,9 +258,20 @@ void BinaryInstWriter::visitLoad(Load* curr) { } break; } - case Type::f32: - o << int8_t(BinaryConsts::F32LoadMem); + case Type::f32: { + switch (curr->bytes) { + case 2: + o << int8_t(BinaryConsts::MiscPrefix) + << U32LEB(BinaryConsts::F32_F16LoadMem); + break; + case 4: + o << int8_t(BinaryConsts::F32LoadMem); + break; + default: + WASM_UNREACHABLE("invalid load size"); + } break; + } case Type::f64: o << int8_t(BinaryConsts::F64LoadMem); break; @@ -359,9 +370,20 @@ void BinaryInstWriter::visitStore(Store* curr) { } break; } - case Type::f32: - o << int8_t(BinaryConsts::F32StoreMem); + case Type::f32: { + switch (curr->bytes) { + case 2: + o << int8_t(BinaryConsts::MiscPrefix) + << U32LEB(BinaryConsts::F32_F16StoreMem); + break; + case 4: + o << int8_t(BinaryConsts::F32StoreMem); + break; + default: + WASM_UNREACHABLE("invalid store size"); + } break; + } case Type::f64: o << int8_t(BinaryConsts::F64StoreMem); break; diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index ce7d0df3c..b32917432 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -1579,8 +1579,9 @@ void FunctionValidator::validateMemBytes(uint8_t bytes, "expected i64 operation to touch 1, 2, 4, or 8 bytes"); break; case Type::f32: - shouldBeEqual( - bytes, uint8_t(4), curr, "expected f32 operation to touch 4 bytes"); + shouldBeTrue(bytes == 2 || bytes == 4, + curr, + "expected f32 operation to touch 2 or 4 bytes"); break; case Type::f64: shouldBeEqual( |