Skip to content

Commit e2c08d4

Browse files
authored
Add atomic loads and stores (#1077)
Add IR, wast and binary support for atomic loads and stores. Currently all IR generated by means other than parsing wast and binary files always generates non-atomic accesses, and optimizations have not yet been made aware of atomics, so they are certainly not ready to be used yet.
1 parent 14bcc44 commit e2c08d4

15 files changed

Lines changed: 514 additions & 86 deletions

src/asm2wasm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,6 +1772,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
17721772
assert(views.find(heap) != views.end());
17731773
View& view = views[heap];
17741774
auto ret = allocator.alloc<Store>();
1775+
ret->isAtomic = false;
17751776
ret->bytes = view.bytes;
17761777
ret->offset = 0;
17771778
ret->align = view.bytes;
@@ -1843,6 +1844,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
18431844
assert(views.find(heap) != views.end());
18441845
View& view = views[heap];
18451846
auto ret = allocator.alloc<Load>();
1847+
ret->isAtomic = false;
18461848
ret->bytes = view.bytes;
18471849
ret->signed_ = view.signed_;
18481850
ret->offset = 0;

src/binaryen-c.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ BinaryenExpressionRef BinaryenLoad(BinaryenModuleRef module, uint32_t bytes, int
549549
auto id = noteExpression(ret);
550550
std::cout << " expressions[" << id << "] = BinaryenLoad(the_module, " << bytes << ", " << int(signed_) << ", " << offset << ", " << align << ", " << type << ", expressions[" << expressions[ptr] << "]);\n";
551551
}
552-
552+
ret->isAtomic = false;
553553
ret->bytes = bytes;
554554
ret->signed_ = !!signed_;
555555
ret->offset = offset;
@@ -566,7 +566,7 @@ BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module, uint32_t bytes, ui
566566
auto id = noteExpression(ret);
567567
std::cout << " expressions[" << id << "] = BinaryenStore(the_module, " << bytes << ", " << offset << ", " << align << ", expressions[" << expressions[ptr] << "], expressions[" << expressions[value] << "], " << type << ");\n";
568568
}
569-
569+
ret->isAtomic = false;
570570
ret->bytes = bytes;
571571
ret->offset = offset;
572572
ret->align = align ? align : bytes;

src/compiler-support.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
// If control flow reaches the point of the WASM_UNREACHABLE(), the program is
2929
// undefined.
30-
#if __has_builtin(__builtin_unreachable)
30+
#if __has_builtin(__builtin_unreachable) && defined(NDEBUG)
3131
# define WASM_UNREACHABLE() __builtin_unreachable()
3232
#elif defined(_MSC_VER)
3333
# define WASM_UNREACHABLE() __assume(false)

src/passes/Print.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,9 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
296296
}
297297
void visitLoad(Load *curr) {
298298
o << '(';
299-
prepareColor(o) << printWasmType(curr->type) << ".load";
299+
prepareColor(o) << printWasmType(curr->type);
300+
if (curr->isAtomic) o << ".atomic";
301+
o << ".load";
300302
if (curr->bytes < 4 || (curr->type == i64 && curr->bytes < 8)) {
301303
if (curr->bytes == 1) {
302304
o << '8';
@@ -322,7 +324,9 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
322324
}
323325
void visitStore(Store *curr) {
324326
o << '(';
325-
prepareColor(o) << printWasmType(curr->valueType) << ".store";
327+
prepareColor(o) << printWasmType(curr->valueType);
328+
if (curr->isAtomic) o << ".atomic";
329+
o << ".store";
326330
if (curr->bytes < 4 || (curr->valueType == i64 && curr->bytes < 8)) {
327331
if (curr->bytes == 1) {
328332
o << '8';

src/s2wasm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,7 @@ class S2WasmBuilder {
920920
auto makeLoad = [&](WasmType type) {
921921
skipComma();
922922
auto curr = allocator->alloc<Load>();
923+
curr->isAtomic = false;
923924
curr->type = type;
924925
int32_t bytes = getInt() / CHAR_BIT;
925926
curr->bytes = bytes > 0 ? bytes : getWasmTypeSize(type);
@@ -939,6 +940,7 @@ class S2WasmBuilder {
939940
};
940941
auto makeStore = [&](WasmType type) {
941942
auto curr = allocator->alloc<Store>();
943+
curr->isAtomic = false;
942944
curr->valueType = type;
943945
s += strlen("store");
944946
if(!isspace(*s)) {

src/wasm-binary.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,26 @@ enum ASTNodes {
506506
I32ReinterpretF32 = 0xbc,
507507
I64ReinterpretF64 = 0xbd,
508508
F32ReinterpretI32 = 0xbe,
509-
F64ReinterpretI64 = 0xbf
509+
F64ReinterpretI64 = 0xbf,
510+
511+
AtomicPrefix = 0xfe
512+
};
513+
514+
enum AtomicOpcodes {
515+
I32AtomicLoad = 0x10,
516+
I64AtomicLoad = 0x11,
517+
I32AtomicLoad8U = 0x12,
518+
I32AtomicLoad16U = 0x13,
519+
I64AtomicLoad8U = 0x14,
520+
I64AtomicLoad16U = 0x15,
521+
I64AtomicLoad32U = 0x16,
522+
I32AtomicStore = 0x17,
523+
I64AtomicStore = 0x18,
524+
I32AtomicStore8 = 0x19,
525+
I32AtomicStore16 = 0x1a,
526+
I64AtomicStore8 = 0x1b,
527+
I64AtomicStore16 = 0x1c,
528+
I64AtomicStore32 = 0x1d
510529
};
511530

512531
enum MemoryAccess {
@@ -812,8 +831,8 @@ class WasmBinaryBuilder {
812831
void visitGetGlobal(GetGlobal *curr);
813832
void visitSetGlobal(SetGlobal *curr);
814833
void readMemoryAccess(Address& alignment, size_t bytes, Address& offset);
815-
bool maybeVisitLoad(Expression*& out, uint8_t code);
816-
bool maybeVisitStore(Expression*& out, uint8_t code);
834+
bool maybeVisitLoad(Expression*& out, uint8_t code, bool isAtomic);
835+
bool maybeVisitStore(Expression*& out, uint8_t code, bool isAtomic);
817836
bool maybeVisitConst(Expression*& out, uint8_t code);
818837
bool maybeVisitUnary(Expression*& out, uint8_t code);
819838
bool maybeVisitBinary(Expression*& out, uint8_t code);

src/wasm-builder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,14 @@ class Builder {
188188
}
189189
Load* makeLoad(unsigned bytes, bool signed_, uint32_t offset, unsigned align, Expression *ptr, WasmType type) {
190190
auto* ret = allocator.alloc<Load>();
191+
ret->isAtomic = false;
191192
ret->bytes = bytes; ret->signed_ = signed_; ret->offset = offset; ret->align = align; ret->ptr = ptr;
192193
ret->type = type;
193194
return ret;
194195
}
195196
Store* makeStore(unsigned bytes, uint32_t offset, unsigned align, Expression *ptr, Expression *value, WasmType type) {
196197
auto* ret = allocator.alloc<Store>();
198+
ret->isAtomic = false;
197199
ret->bytes = bytes; ret->offset = offset; ret->align = align; ret->ptr = ptr; ret->value = value; ret->valueType = type;
198200
ret->finalize();
199201
assert(isConcreteWasmType(ret->value->type) ? ret->value->type == type : true);

src/wasm-s-parser.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ class SExpressionWasmBuilder {
175175
Expression* makeBlock(Element& s);
176176
Expression* makeThenOrElse(Element& s);
177177
Expression* makeConst(Element& s, WasmType type);
178-
Expression* makeLoad(Element& s, WasmType type);
179-
Expression* makeStore(Element& s, WasmType type);
178+
Expression* makeLoad(Element& s, WasmType type, bool isAtomic);
179+
Expression* makeStore(Element& s, WasmType type, bool isAtomic);
180180
Expression* makeIf(Element& s);
181181
Expression* makeMaybeBlock(Element& s, size_t i, WasmType type);
182182
Expression* makeLoop(Element& s);

src/wasm.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ class Expression {
177177
HostId,
178178
NopId,
179179
UnreachableId,
180+
AtomicRMWId,
180181
NumExpressionIds
181182
};
182183
Id _id;
@@ -398,6 +399,7 @@ class Load : public SpecificExpression<Expression::LoadId> {
398399
bool signed_;
399400
Address offset;
400401
Address align;
402+
bool isAtomic;
401403
Expression* ptr;
402404

403405
// type must be set during creation, cannot be inferred
@@ -413,6 +415,7 @@ class Store : public SpecificExpression<Expression::StoreId> {
413415
uint8_t bytes;
414416
Address offset;
415417
Address align;
418+
bool isAtomic;
416419
Expression* ptr;
417420
Expression* value;
418421
WasmType valueType; // the store never returns a value
@@ -511,6 +514,13 @@ class Unreachable : public SpecificExpression<Expression::UnreachableId> {
511514
Unreachable(MixedArena& allocator) : Unreachable() {}
512515
};
513516

517+
class AtomicRMW : public SpecificExpression<Expression::AtomicRMWId> {
518+
public:
519+
AtomicRMW() {}
520+
AtomicRMW(MixedArena& allocator) : AtomicRMW() {}
521+
bool finalize();
522+
};
523+
514524
// Globals
515525

516526
class Function {

0 commit comments

Comments
 (0)