summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asm2wasm.h2
-rw-r--r--src/binaryen-c.cpp4
-rw-r--r--src/compiler-support.h2
-rw-r--r--src/passes/Print.cpp8
-rw-r--r--src/s2wasm.h2
-rw-r--r--src/wasm-binary.h25
-rw-r--r--src/wasm-builder.h2
-rw-r--r--src/wasm-s-parser.h4
-rw-r--r--src/wasm.h10
-rw-r--r--src/wasm/wasm-binary.cpp233
-rw-r--r--src/wasm/wasm-s-parser.cpp18
11 files changed, 224 insertions, 86 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h
index 90e258c54..4395054f6 100644
--- a/src/asm2wasm.h
+++ b/src/asm2wasm.h
@@ -1772,6 +1772,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
assert(views.find(heap) != views.end());
View& view = views[heap];
auto ret = allocator.alloc<Store>();
+ ret->isAtomic = false;
ret->bytes = view.bytes;
ret->offset = 0;
ret->align = view.bytes;
@@ -1843,6 +1844,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
assert(views.find(heap) != views.end());
View& view = views[heap];
auto ret = allocator.alloc<Load>();
+ ret->isAtomic = false;
ret->bytes = view.bytes;
ret->signed_ = view.signed_;
ret->offset = 0;
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index 36b2abbe7..83d0e155f 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -549,7 +549,7 @@ BinaryenExpressionRef BinaryenLoad(BinaryenModuleRef module, uint32_t bytes, int
auto id = noteExpression(ret);
std::cout << " expressions[" << id << "] = BinaryenLoad(the_module, " << bytes << ", " << int(signed_) << ", " << offset << ", " << align << ", " << type << ", expressions[" << expressions[ptr] << "]);\n";
}
-
+ ret->isAtomic = false;
ret->bytes = bytes;
ret->signed_ = !!signed_;
ret->offset = offset;
@@ -566,7 +566,7 @@ BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module, uint32_t bytes, ui
auto id = noteExpression(ret);
std::cout << " expressions[" << id << "] = BinaryenStore(the_module, " << bytes << ", " << offset << ", " << align << ", expressions[" << expressions[ptr] << "], expressions[" << expressions[value] << "], " << type << ");\n";
}
-
+ ret->isAtomic = false;
ret->bytes = bytes;
ret->offset = offset;
ret->align = align ? align : bytes;
diff --git a/src/compiler-support.h b/src/compiler-support.h
index 3dd873383..f2e58ff5e 100644
--- a/src/compiler-support.h
+++ b/src/compiler-support.h
@@ -27,7 +27,7 @@
// If control flow reaches the point of the WASM_UNREACHABLE(), the program is
// undefined.
-#if __has_builtin(__builtin_unreachable)
+#if __has_builtin(__builtin_unreachable) && defined(NDEBUG)
# define WASM_UNREACHABLE() __builtin_unreachable()
#elif defined(_MSC_VER)
# define WASM_UNREACHABLE() __assume(false)
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 0494e7d78..7ec3e98a3 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -296,7 +296,9 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
void visitLoad(Load *curr) {
o << '(';
- prepareColor(o) << printWasmType(curr->type) << ".load";
+ prepareColor(o) << printWasmType(curr->type);
+ if (curr->isAtomic) o << ".atomic";
+ o << ".load";
if (curr->bytes < 4 || (curr->type == i64 && curr->bytes < 8)) {
if (curr->bytes == 1) {
o << '8';
@@ -322,7 +324,9 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
void visitStore(Store *curr) {
o << '(';
- prepareColor(o) << printWasmType(curr->valueType) << ".store";
+ prepareColor(o) << printWasmType(curr->valueType);
+ if (curr->isAtomic) o << ".atomic";
+ o << ".store";
if (curr->bytes < 4 || (curr->valueType == i64 && curr->bytes < 8)) {
if (curr->bytes == 1) {
o << '8';
diff --git a/src/s2wasm.h b/src/s2wasm.h
index efa4ad601..0fc0201cd 100644
--- a/src/s2wasm.h
+++ b/src/s2wasm.h
@@ -920,6 +920,7 @@ class S2WasmBuilder {
auto makeLoad = [&](WasmType type) {
skipComma();
auto curr = allocator->alloc<Load>();
+ curr->isAtomic = false;
curr->type = type;
int32_t bytes = getInt() / CHAR_BIT;
curr->bytes = bytes > 0 ? bytes : getWasmTypeSize(type);
@@ -939,6 +940,7 @@ class S2WasmBuilder {
};
auto makeStore = [&](WasmType type) {
auto curr = allocator->alloc<Store>();
+ curr->isAtomic = false;
curr->valueType = type;
s += strlen("store");
if(!isspace(*s)) {
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 9e75d6501..f1396cbb2 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -506,7 +506,26 @@ enum ASTNodes {
I32ReinterpretF32 = 0xbc,
I64ReinterpretF64 = 0xbd,
F32ReinterpretI32 = 0xbe,
- F64ReinterpretI64 = 0xbf
+ F64ReinterpretI64 = 0xbf,
+
+ AtomicPrefix = 0xfe
+};
+
+enum AtomicOpcodes {
+ I32AtomicLoad = 0x10,
+ I64AtomicLoad = 0x11,
+ I32AtomicLoad8U = 0x12,
+ I32AtomicLoad16U = 0x13,
+ I64AtomicLoad8U = 0x14,
+ I64AtomicLoad16U = 0x15,
+ I64AtomicLoad32U = 0x16,
+ I32AtomicStore = 0x17,
+ I64AtomicStore = 0x18,
+ I32AtomicStore8 = 0x19,
+ I32AtomicStore16 = 0x1a,
+ I64AtomicStore8 = 0x1b,
+ I64AtomicStore16 = 0x1c,
+ I64AtomicStore32 = 0x1d
};
enum MemoryAccess {
@@ -812,8 +831,8 @@ public:
void visitGetGlobal(GetGlobal *curr);
void visitSetGlobal(SetGlobal *curr);
void readMemoryAccess(Address& alignment, size_t bytes, Address& offset);
- bool maybeVisitLoad(Expression*& out, uint8_t code);
- bool maybeVisitStore(Expression*& out, uint8_t code);
+ bool maybeVisitLoad(Expression*& out, uint8_t code, bool isAtomic);
+ bool maybeVisitStore(Expression*& out, uint8_t code, bool isAtomic);
bool maybeVisitConst(Expression*& out, uint8_t code);
bool maybeVisitUnary(Expression*& out, uint8_t code);
bool maybeVisitBinary(Expression*& out, uint8_t code);
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index 42d3dfe47..41aaf6766 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -188,12 +188,14 @@ public:
}
Load* makeLoad(unsigned bytes, bool signed_, uint32_t offset, unsigned align, Expression *ptr, WasmType type) {
auto* ret = allocator.alloc<Load>();
+ ret->isAtomic = false;
ret->bytes = bytes; ret->signed_ = signed_; ret->offset = offset; ret->align = align; ret->ptr = ptr;
ret->type = type;
return ret;
}
Store* makeStore(unsigned bytes, uint32_t offset, unsigned align, Expression *ptr, Expression *value, WasmType type) {
auto* ret = allocator.alloc<Store>();
+ ret->isAtomic = false;
ret->bytes = bytes; ret->offset = offset; ret->align = align; ret->ptr = ptr; ret->value = value; ret->valueType = type;
ret->finalize();
assert(isConcreteWasmType(ret->value->type) ? ret->value->type == type : true);
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index c79e0a458..90e797615 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -175,8 +175,8 @@ private:
Expression* makeBlock(Element& s);
Expression* makeThenOrElse(Element& s);
Expression* makeConst(Element& s, WasmType type);
- Expression* makeLoad(Element& s, WasmType type);
- Expression* makeStore(Element& s, WasmType type);
+ Expression* makeLoad(Element& s, WasmType type, bool isAtomic);
+ Expression* makeStore(Element& s, WasmType type, bool isAtomic);
Expression* makeIf(Element& s);
Expression* makeMaybeBlock(Element& s, size_t i, WasmType type);
Expression* makeLoop(Element& s);
diff --git a/src/wasm.h b/src/wasm.h
index 56432faf9..286604848 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -177,6 +177,7 @@ public:
HostId,
NopId,
UnreachableId,
+ AtomicRMWId,
NumExpressionIds
};
Id _id;
@@ -398,6 +399,7 @@ public:
bool signed_;
Address offset;
Address align;
+ bool isAtomic;
Expression* ptr;
// type must be set during creation, cannot be inferred
@@ -413,6 +415,7 @@ public:
uint8_t bytes;
Address offset;
Address align;
+ bool isAtomic;
Expression* ptr;
Expression* value;
WasmType valueType; // the store never returns a value
@@ -511,6 +514,13 @@ public:
Unreachable(MixedArena& allocator) : Unreachable() {}
};
+class AtomicRMW : public SpecificExpression<Expression::AtomicRMWId> {
+ public:
+ AtomicRMW() {}
+ AtomicRMW(MixedArena& allocator) : AtomicRMW() {}
+ bool finalize();
+};
+
// Globals
class Function {
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 359d9d8f8..e44f9fb83 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -720,30 +720,57 @@ void WasmBinaryWriter::emitMemoryAccess(size_t alignment, size_t bytes, uint32_t
void WasmBinaryWriter::visitLoad(Load *curr) {
if (debug) std::cerr << "zz node: Load" << std::endl;
recurse(curr->ptr);
- switch (curr->type) {
- case i32: {
- switch (curr->bytes) {
- case 1: o << int8_t(curr->signed_ ? BinaryConsts::I32LoadMem8S : BinaryConsts::I32LoadMem8U); break;
- case 2: o << int8_t(curr->signed_ ? BinaryConsts::I32LoadMem16S : BinaryConsts::I32LoadMem16U); break;
- case 4: o << int8_t(BinaryConsts::I32LoadMem); break;
- default: abort();
+ if (!curr->isAtomic) {
+ switch (curr->type) {
+ case i32: {
+ switch (curr->bytes) {
+ case 1: o << int8_t(curr->signed_ ? BinaryConsts::I32LoadMem8S : BinaryConsts::I32LoadMem8U); break;
+ case 2: o << int8_t(curr->signed_ ? BinaryConsts::I32LoadMem16S : BinaryConsts::I32LoadMem16U); break;
+ case 4: o << int8_t(BinaryConsts::I32LoadMem); break;
+ default: abort();
+ }
+ break;
}
- break;
+ case i64: {
+ switch (curr->bytes) {
+ case 1: o << int8_t(curr->signed_ ? BinaryConsts::I64LoadMem8S : BinaryConsts::I64LoadMem8U); break;
+ case 2: o << int8_t(curr->signed_ ? BinaryConsts::I64LoadMem16S : BinaryConsts::I64LoadMem16U); break;
+ case 4: o << int8_t(curr->signed_ ? BinaryConsts::I64LoadMem32S : BinaryConsts::I64LoadMem32U); break;
+ case 8: o << int8_t(BinaryConsts::I64LoadMem); break;
+ default: abort();
+ }
+ break;
+ }
+ case f32: o << int8_t(BinaryConsts::F32LoadMem); break;
+ case f64: o << int8_t(BinaryConsts::F64LoadMem); break;
+ case unreachable: return; // the pointer is unreachable, so we are never reached; just don't emit a load
+ default: WASM_UNREACHABLE();
}
- case i64: {
- switch (curr->bytes) {
- case 1: o << int8_t(curr->signed_ ? BinaryConsts::I64LoadMem8S : BinaryConsts::I64LoadMem8U); break;
- case 2: o << int8_t(curr->signed_ ? BinaryConsts::I64LoadMem16S : BinaryConsts::I64LoadMem16U); break;
- case 4: o << int8_t(curr->signed_ ? BinaryConsts::I64LoadMem32S : BinaryConsts::I64LoadMem32U); break;
- case 8: o << int8_t(BinaryConsts::I64LoadMem); break;
- default: abort();
+ } else {
+ o << int8_t(BinaryConsts::AtomicPrefix);
+ switch (curr->type) {
+ case i32: {
+ switch (curr->bytes) {
+ case 1: o << int8_t(BinaryConsts::I32AtomicLoad8U); break;
+ case 2: o << int8_t(BinaryConsts::I32AtomicLoad16U); break;
+ case 4: o << int8_t(BinaryConsts::I32AtomicLoad); break;
+ default: WASM_UNREACHABLE();
+ }
+ break;
}
- break;
+ case i64: {
+ switch (curr->bytes) {
+ case 1: o << int8_t(BinaryConsts::I64AtomicLoad8U); break;
+ case 2: o << int8_t(BinaryConsts::I64AtomicLoad16U); break;
+ case 4: o << int8_t(BinaryConsts::I64AtomicLoad32U); break;
+ case 8: o << int8_t(BinaryConsts::I64AtomicLoad); break;
+ default: WASM_UNREACHABLE();
+ }
+ break;
+ }
+ case unreachable: return;
+ default: WASM_UNREACHABLE();
}
- case f32: o << int8_t(BinaryConsts::F32LoadMem); break;
- case f64: o << int8_t(BinaryConsts::F64LoadMem); break;
- case unreachable: return; // the pointer is unreachable, so we are never reached; just don't emit a load
- default: WASM_UNREACHABLE();
}
emitMemoryAccess(curr->align, curr->bytes, curr->offset);
}
@@ -752,29 +779,55 @@ void WasmBinaryWriter::visitStore(Store *curr) {
if (debug) std::cerr << "zz node: Store" << std::endl;
recurse(curr->ptr);
recurse(curr->value);
- switch (curr->valueType) {
- case i32: {
- switch (curr->bytes) {
- case 1: o << int8_t(BinaryConsts::I32StoreMem8); break;
- case 2: o << int8_t(BinaryConsts::I32StoreMem16); break;
- case 4: o << int8_t(BinaryConsts::I32StoreMem); break;
- default: abort();
+ if (!curr->isAtomic) {
+ switch (curr->valueType) {
+ case i32: {
+ switch (curr->bytes) {
+ case 1: o << int8_t(BinaryConsts::I32StoreMem8); break;
+ case 2: o << int8_t(BinaryConsts::I32StoreMem16); break;
+ case 4: o << int8_t(BinaryConsts::I32StoreMem); break;
+ default: abort();
+ }
+ break;
}
- break;
+ case i64: {
+ switch (curr->bytes) {
+ case 1: o << int8_t(BinaryConsts::I64StoreMem8); break;
+ case 2: o << int8_t(BinaryConsts::I64StoreMem16); break;
+ case 4: o << int8_t(BinaryConsts::I64StoreMem32); break;
+ case 8: o << int8_t(BinaryConsts::I64StoreMem); break;
+ default: abort();
+ }
+ break;
+ }
+ case f32: o << int8_t(BinaryConsts::F32StoreMem); break;
+ case f64: o << int8_t(BinaryConsts::F64StoreMem); break;
+ default: abort();
}
- case i64: {
- switch (curr->bytes) {
- case 1: o << int8_t(BinaryConsts::I64StoreMem8); break;
- case 2: o << int8_t(BinaryConsts::I64StoreMem16); break;
- case 4: o << int8_t(BinaryConsts::I64StoreMem32); break;
- case 8: o << int8_t(BinaryConsts::I64StoreMem); break;
- default: abort();
+ } else {
+ o << int8_t(BinaryConsts::AtomicPrefix);
+ switch (curr->valueType) {
+ case i32: {
+ switch (curr->bytes) {
+ case 1: o << int8_t(BinaryConsts::I32AtomicStore8); break;
+ case 2: o << int8_t(BinaryConsts::I32AtomicStore16); break;
+ case 4: o << int8_t(BinaryConsts::I32AtomicStore); break;
+ default: WASM_UNREACHABLE();
+ }
+ break;
}
- break;
+ case i64: {
+ switch (curr->bytes) {
+ case 1: o << int8_t(BinaryConsts::I64AtomicStore8); break;
+ case 2: o << int8_t(BinaryConsts::I64AtomicStore16); break;
+ case 4: o << int8_t(BinaryConsts::I64AtomicStore32); break;
+ case 8: o << int8_t(BinaryConsts::I64AtomicStore); break;
+ default: WASM_UNREACHABLE();
+ }
+ break;
+ }
+ default: WASM_UNREACHABLE();
}
- case f32: o << int8_t(BinaryConsts::F32StoreMem); break;
- case f64: o << int8_t(BinaryConsts::F64StoreMem); break;
- default: abort();
}
emitMemoryAccess(curr->align, curr->bytes, curr->offset);
}
@@ -1873,13 +1926,19 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
case BinaryConsts::Drop: visitDrop((curr = allocator.alloc<Drop>())->cast<Drop>()); break;
case BinaryConsts::End:
case BinaryConsts::Else: curr = nullptr; break;
+ case BinaryConsts::AtomicPrefix: {
+ code = getInt8();
+ if (maybeVisitLoad(curr, code, /*isAtomic=*/true)) break;
+ if (maybeVisitStore(curr, code, /*isAtomic=*/true)) break;
+ throw ParseException("invalid code after atomic prefix: " + std::to_string(code));
+ }
default: {
// otherwise, the code is a subcode TODO: optimize
if (maybeVisitBinary(curr, code)) break;
if (maybeVisitUnary(curr, code)) break;
if (maybeVisitConst(curr, code)) break;
- if (maybeVisitLoad(curr, code)) break;
- if (maybeVisitStore(curr, code)) break;
+ if (maybeVisitLoad(curr, code, /*isAtomic=*/false)) break;
+ if (maybeVisitStore(curr, code, /*isAtomic=*/false)) break;
if (maybeVisitHost(curr, code)) break;
throw ParseException("bad node code " + std::to_string(code));
}
@@ -2137,26 +2196,43 @@ void WasmBinaryBuilder::readMemoryAccess(Address& alignment, size_t bytes, Addre
offset = getU32LEB();
}
-bool WasmBinaryBuilder::maybeVisitLoad(Expression*& out, uint8_t code) {
+bool WasmBinaryBuilder::maybeVisitLoad(Expression*& out, uint8_t code, bool isAtomic) {
Load* curr;
- switch (code) {
- case BinaryConsts::I32LoadMem8S: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i32; curr->signed_ = true; break;
- case BinaryConsts::I32LoadMem8U: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i32; curr->signed_ = false; break;
- case BinaryConsts::I32LoadMem16S: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i32; curr->signed_ = true; break;
- case BinaryConsts::I32LoadMem16U: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i32; curr->signed_ = false; break;
- case BinaryConsts::I32LoadMem: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = i32; break;
- case BinaryConsts::I64LoadMem8S: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i64; curr->signed_ = true; break;
- case BinaryConsts::I64LoadMem8U: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i64; curr->signed_ = false; break;
- case BinaryConsts::I64LoadMem16S: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i64; curr->signed_ = true; break;
- case BinaryConsts::I64LoadMem16U: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i64; curr->signed_ = false; break;
- case BinaryConsts::I64LoadMem32S: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = i64; curr->signed_ = true; break;
- case BinaryConsts::I64LoadMem32U: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = i64; curr->signed_ = false; break;
- case BinaryConsts::I64LoadMem: curr = allocator.alloc<Load>(); curr->bytes = 8; curr->type = i64; break;
- case BinaryConsts::F32LoadMem: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = f32; break;
- case BinaryConsts::F64LoadMem: curr = allocator.alloc<Load>(); curr->bytes = 8; curr->type = f64; break;
- default: return false;
+ if (!isAtomic) {
+ switch (code) {
+ case BinaryConsts::I32LoadMem8S: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i32; curr->signed_ = true; break;
+ case BinaryConsts::I32LoadMem8U: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i32; curr->signed_ = false; break;
+ case BinaryConsts::I32LoadMem16S: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i32; curr->signed_ = true; break;
+ case BinaryConsts::I32LoadMem16U: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i32; curr->signed_ = false; break;
+ case BinaryConsts::I32LoadMem: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = i32; break;
+ case BinaryConsts::I64LoadMem8S: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i64; curr->signed_ = true; break;
+ case BinaryConsts::I64LoadMem8U: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i64; curr->signed_ = false; break;
+ case BinaryConsts::I64LoadMem16S: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i64; curr->signed_ = true; break;
+ case BinaryConsts::I64LoadMem16U: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i64; curr->signed_ = false; break;
+ case BinaryConsts::I64LoadMem32S: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = i64; curr->signed_ = true; break;
+ case BinaryConsts::I64LoadMem32U: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = i64; curr->signed_ = false; break;
+ case BinaryConsts::I64LoadMem: curr = allocator.alloc<Load>(); curr->bytes = 8; curr->type = i64; break;
+ case BinaryConsts::F32LoadMem: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = f32; break;
+ case BinaryConsts::F64LoadMem: curr = allocator.alloc<Load>(); curr->bytes = 8; curr->type = f64; break;
+ default: return false;
+ }
+ if (debug) std::cerr << "zz node: Load" << std::endl;
+ } else {
+ switch (code) {
+ case BinaryConsts::I32AtomicLoad8U: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i32; break;
+ case BinaryConsts::I32AtomicLoad16U: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i32; break;
+ case BinaryConsts::I32AtomicLoad: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = i32; break;
+ case BinaryConsts::I64AtomicLoad8U: curr = allocator.alloc<Load>(); curr->bytes = 1; curr->type = i64; break;
+ case BinaryConsts::I64AtomicLoad16U: curr = allocator.alloc<Load>(); curr->bytes = 2; curr->type = i64; break;
+ case BinaryConsts::I64AtomicLoad32U: curr = allocator.alloc<Load>(); curr->bytes = 4; curr->type = i64; break;
+ case BinaryConsts::I64AtomicLoad: curr = allocator.alloc<Load>(); curr->bytes = 8; curr->type = i64; break;
+ default: return false;
+ }
+ curr->signed_ = false;
+ if (debug) std::cerr << "zz node: AtomicLoad" << std::endl;
}
- if (debug) std::cerr << "zz node: Load" << std::endl;
+
+ curr->isAtomic = isAtomic;
readMemoryAccess(curr->align, curr->bytes, curr->offset);
curr->ptr = popNonVoidExpression();
curr->finalize();
@@ -2164,20 +2240,35 @@ bool WasmBinaryBuilder::maybeVisitLoad(Expression*& out, uint8_t code) {
return true;
}
-bool WasmBinaryBuilder::maybeVisitStore(Expression*& out, uint8_t code) {
+bool WasmBinaryBuilder::maybeVisitStore(Expression*& out, uint8_t code, bool isAtomic) {
Store* curr;
- switch (code) {
- case BinaryConsts::I32StoreMem8: curr = allocator.alloc<Store>(); curr->bytes = 1; curr->valueType = i32; break;
- case BinaryConsts::I32StoreMem16: curr = allocator.alloc<Store>(); curr->bytes = 2; curr->valueType = i32; break;
- case BinaryConsts::I32StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->valueType = i32; break;
- case BinaryConsts::I64StoreMem8: curr = allocator.alloc<Store>(); curr->bytes = 1; curr->valueType = i64; break;
- case BinaryConsts::I64StoreMem16: curr = allocator.alloc<Store>(); curr->bytes = 2; curr->valueType = i64; break;
- case BinaryConsts::I64StoreMem32: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->valueType = i64; break;
- case BinaryConsts::I64StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 8; curr->valueType = i64; break;
- case BinaryConsts::F32StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->valueType = f32; break;
- case BinaryConsts::F64StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 8; curr->valueType = f64; break;
- default: return false;
+ if (!isAtomic) {
+ switch (code) {
+ case BinaryConsts::I32StoreMem8: curr = allocator.alloc<Store>(); curr->bytes = 1; curr->valueType = i32; break;
+ case BinaryConsts::I32StoreMem16: curr = allocator.alloc<Store>(); curr->bytes = 2; curr->valueType = i32; break;
+ case BinaryConsts::I32StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->valueType = i32; break;
+ case BinaryConsts::I64StoreMem8: curr = allocator.alloc<Store>(); curr->bytes = 1; curr->valueType = i64; break;
+ case BinaryConsts::I64StoreMem16: curr = allocator.alloc<Store>(); curr->bytes = 2; curr->valueType = i64; break;
+ case BinaryConsts::I64StoreMem32: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->valueType = i64; break;
+ case BinaryConsts::I64StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 8; curr->valueType = i64; break;
+ case BinaryConsts::F32StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->valueType = f32; break;
+ case BinaryConsts::F64StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 8; curr->valueType = f64; break;
+ default: return false;
+ }
+ } else {
+ switch (code) {
+ case BinaryConsts::I32AtomicStore8: curr = allocator.alloc<Store>(); curr->bytes = 1; curr->valueType = i32; break;
+ case BinaryConsts::I32AtomicStore16: curr = allocator.alloc<Store>(); curr->bytes = 2; curr->valueType = i32; break;
+ case BinaryConsts::I32AtomicStore: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->valueType = i32; break;
+ case BinaryConsts::I64AtomicStore8: curr = allocator.alloc<Store>(); curr->bytes = 1; curr->valueType = i64; break;
+ case BinaryConsts::I64AtomicStore16: curr = allocator.alloc<Store>(); curr->bytes = 2; curr->valueType = i64; break;
+ case BinaryConsts::I64AtomicStore32: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->valueType = i64; break;
+ case BinaryConsts::I64AtomicStore: curr = allocator.alloc<Store>(); curr->bytes = 8; curr->valueType = i64; break;
+ default: return false;
+ }
}
+
+ curr->isAtomic = isAtomic;
if (debug) std::cerr << "zz node: Store" << std::endl;
readMemoryAccess(curr->align, curr->bytes, curr->offset);
curr->value = popNonVoidExpression();
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 6bf030302..38954af1f 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -663,6 +663,10 @@ Expression* SExpressionWasmBuilder::makeExpression(Element& s) {
if (op[1] == 'b') return makeUnary(s, type == f32 ? UnaryOp::AbsFloat32 : UnaryOp::AbsFloat64, type);
if (op[1] == 'd') return makeBinary(s, BINARY_INT_OR_FLOAT(Add), type);
if (op[1] == 'n') return makeBinary(s, BINARY_INT(And), type);
+ if (op[1] == 't' && !strncmp(op, "atomic.", strlen("atomic."))) {
+ if (op[7] == 'l') return makeLoad(s, type, /*isAtomic=*/true);
+ if (op[7] == 's') return makeStore(s, type, /*isAtomic=*/true);
+ }
abort_on(op);
}
case 'c': {
@@ -721,7 +725,7 @@ Expression* SExpressionWasmBuilder::makeExpression(Element& s) {
if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BINARY_INT(LeU) : BINARY_INT(LeS), type);
if (op[2] == 0) return makeBinary(s, BINARY_FLOAT(Le), type);
}
- if (op[1] == 'o') return makeLoad(s, type);
+ if (op[1] == 'o') return makeLoad(s, type, /*isAtomic=*/false);
abort_on(op);
}
case 'm': {
@@ -764,7 +768,7 @@ Expression* SExpressionWasmBuilder::makeExpression(Element& s) {
}
if (op[1] == 'u') return makeBinary(s, BINARY_INT_OR_FLOAT(Sub), type);
if (op[1] == 'q') return makeUnary(s, type == f32 ? UnaryOp::SqrtFloat32 : UnaryOp::SqrtFloat64, type);
- if (op[1] == 't') return makeStore(s, type);
+ if (op[1] == 't') return makeStore(s, type, /*isAtomic=*/false);
abort_on(op);
}
case 't': {
@@ -1122,9 +1126,11 @@ Expression* SExpressionWasmBuilder::makeConst(Element& s, WasmType type) {
}
-Expression* SExpressionWasmBuilder::makeLoad(Element& s, WasmType type) {
+Expression* SExpressionWasmBuilder::makeLoad(Element& s, WasmType type, bool isAtomic) {
const char *extra = strchr(s[0]->c_str(), '.') + 5; // after "type.load"
- auto ret = allocator.alloc<Load>();
+ if (isAtomic) extra += 7; // after "type.atomic.load"
+ auto* ret = allocator.alloc<Load>();
+ ret->isAtomic = isAtomic;
ret->type = type;
ret->bytes = getWasmTypeSize(type);
if (extra[0] == '8') {
@@ -1164,9 +1170,11 @@ Expression* SExpressionWasmBuilder::makeLoad(Element& s, WasmType type) {
return ret;
}
-Expression* SExpressionWasmBuilder::makeStore(Element& s, WasmType type) {
+Expression* SExpressionWasmBuilder::makeStore(Element& s, WasmType type, bool isAtomic) {
const char *extra = strchr(s[0]->c_str(), '.') + 6; // after "type.store"
+ if (isAtomic) extra += 7; // after "type.atomic.store"
auto ret = allocator.alloc<Store>();
+ ret->isAtomic = isAtomic;
ret->valueType = type;
ret->bytes = getWasmTypeSize(type);
if (extra[0] == '8') {