summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gen-s-parser.inc42
-rw-r--r--src/passes/Print.cpp16
-rw-r--r--src/wasm-binary.h12
-rw-r--r--src/wasm-interpreter.h37
-rw-r--r--src/wasm/wasm-binary.cpp65
-rw-r--r--src/wasm/wasm-stack.cpp30
-rw-r--r--src/wasm/wasm-validator.cpp5
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(