Skip to content

Commit c97df2b

Browse files
Add relaxed atomics support for stores
1 parent ed7bf9e commit c97df2b

18 files changed

+2961
-843
lines changed

src/binaryen-c.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1371,7 +1371,8 @@ BinaryenExpressionRef BinaryenAtomicStore(BinaryenModuleRef module,
13711371
(Expression*)ptr,
13721372
(Expression*)value,
13731373
Type(type),
1374-
getMemoryName(module, memoryName)));
1374+
getMemoryName(module, memoryName),
1375+
MemoryOrder::SeqCst));
13751376
}
13761377
BinaryenExpressionRef BinaryenAtomicRMW(BinaryenModuleRef module,
13771378
BinaryenOp op,

src/parser/contexts.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,8 @@ struct NullInstrParserCtx {
565565
int,
566566
bool,
567567
MemoryIdxT*,
568-
MemargT) {
568+
MemargT,
569+
MemoryOrder) {
569570
return Ok{};
570571
}
571572
Result<> makeAtomicRMW(Index,
@@ -2255,12 +2256,13 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx>, AnnotationParserCtx {
22552256
int bytes,
22562257
bool isAtomic,
22572258
Name* mem,
2258-
Memarg memarg) {
2259+
Memarg memarg,
2260+
MemoryOrder order) {
22592261
auto m = getMemory(pos, mem);
22602262
CHECK_ERR(m);
22612263
if (isAtomic) {
2262-
return withLoc(pos,
2263-
irBuilder.makeAtomicStore(bytes, memarg.offset, type, *m));
2264+
return withLoc(
2265+
pos, irBuilder.makeAtomicStore(bytes, memarg.offset, type, *m, order));
22642266
}
22652267
return withLoc(
22662268
pos, irBuilder.makeStore(bytes, memarg.offset, memarg.align, type, *m));

src/parser/parsers.h

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -850,17 +850,6 @@ Result<typename Ctx::MemTypeT> memtypeContinued(Ctx& ctx, Type addressType) {
850850
return ctx.makeMemType(addressType, *limits, shared);
851851
}
852852

853-
// memorder ::= '' | 'seqcst' | 'acqrel'
854-
template<typename Ctx> Result<MemoryOrder> memorder(Ctx& ctx) {
855-
if (ctx.in.takeKeyword("seqcst"sv)) {
856-
return MemoryOrder::SeqCst;
857-
}
858-
if (ctx.in.takeKeyword("acqrel"sv)) {
859-
return MemoryOrder::AcqRel;
860-
}
861-
return MemoryOrder::SeqCst;
862-
}
863-
864853
// memorder ::= 'seqcst' | 'acqrel'
865854
template<typename Ctx> MaybeResult<MemoryOrder> maybeMemOrder(Ctx& ctx) {
866855
if (ctx.in.takeKeyword("seqcst"sv)) {
@@ -873,6 +862,13 @@ template<typename Ctx> MaybeResult<MemoryOrder> maybeMemOrder(Ctx& ctx) {
873862
return {};
874863
}
875864

865+
// memorder ::= '' | 'seqcst' | 'acqrel'
866+
template<typename Ctx> Result<MemoryOrder> memorder(Ctx& ctx) {
867+
auto order = maybeMemOrder(ctx);
868+
CHECK_ERR(order);
869+
return order ? *order : MemoryOrder::SeqCst;
870+
}
871+
876872
// tabletype ::= (limits32 | 'i32' limits32 | 'i64' limit64) reftype
877873
template<typename Ctx> Result<typename Ctx::TableTypeT> tabletype(Ctx& ctx) {
878874
Type addressType = Type::i32;
@@ -1755,7 +1751,8 @@ Result<> makeLoad(Ctx& ctx,
17551751
CHECK_ERR(mem);
17561752

17571753
// We could only parse this when `isAtomic`, but this way gives a clearer
1758-
// error since `memIdx` can never be mistaken for a `memOrder`.
1754+
// error when a memorder is given for non-atomic operations
1755+
// since the next token can never be mistaken for a `memOrder`.
17591756
auto maybeOrder = maybeMemOrder(ctx);
17601757
CHECK_ERR(maybeOrder);
17611758

@@ -1787,10 +1784,26 @@ Result<> makeStore(Ctx& ctx,
17871784
bool isAtomic) {
17881785
auto mem = maybeMemidx(ctx);
17891786
CHECK_ERR(mem);
1787+
1788+
auto maybeOrder = maybeMemOrder(ctx);
1789+
CHECK_ERR(maybeOrder);
1790+
1791+
if (maybeOrder && !isAtomic) {
1792+
return Err{"Memory ordering can only be provided for atomic stores."};
1793+
}
1794+
17901795
auto arg = memarg(ctx, bytes);
17911796
CHECK_ERR(arg);
1792-
return ctx.makeStore(
1793-
pos, annotations, type, bytes, isAtomic, mem.getPtr(), *arg);
1797+
return ctx.makeStore(pos,
1798+
annotations,
1799+
type,
1800+
bytes,
1801+
isAtomic,
1802+
mem.getPtr(),
1803+
*arg,
1804+
maybeOrder ? *maybeOrder
1805+
: isAtomic ? MemoryOrder::SeqCst
1806+
: MemoryOrder::Unordered);
17941807
}
17951808

17961809
template<typename Ctx>

src/passes/Print.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,7 @@ struct PrintExpressionContents
605605
}
606606
restoreNormalColor(o);
607607
printMemoryName(curr->memory, o, wasm);
608+
printMemoryOrder(curr->order);
608609
if (curr->offset) {
609610
o << " offset=" << curr->offset;
610611
}

src/passes/SafeHeap.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,22 @@ static Name getLoadName(Load* curr) {
6363
}
6464

6565
static Name getStoreName(Store* curr) {
66-
std::string ret = "SAFE_HEAP_STORE_";
67-
ret += curr->valueType.toString();
68-
ret += "_" + std::to_string(curr->bytes) + "_";
69-
if (curr->isAtomic()) {
70-
ret += "A";
71-
} else {
72-
ret += std::to_string(curr->align);
66+
std::vector<std::string> parts{curr->valueType.toString(),
67+
std::to_string(curr->bytes)};
68+
switch (curr->order) {
69+
case MemoryOrder::Unordered: {
70+
parts.push_back(std::to_string(curr->align));
71+
break;
72+
}
73+
case MemoryOrder::SeqCst: {
74+
parts.push_back("SC");
75+
break;
76+
}
77+
case MemoryOrder::AcqRel: {
78+
parts.push_back("AR");
79+
}
7380
}
74-
return ret;
81+
return "SAFE_HEAP_STORE_" + String::join(parts, "_");
7582
}
7683

7784
struct AccessInstrumenter : public WalkerPass<PostWalker<AccessInstrumenter>> {
@@ -287,10 +294,9 @@ struct SafeHeap : public Pass {
287294
if (align > bytes) {
288295
continue;
289296
}
290-
for (auto isAtomic : {true, false}) {
291-
store.order =
292-
isAtomic ? MemoryOrder::SeqCst : MemoryOrder::Unordered;
293-
if (isAtomic &&
297+
for (auto memoryOrder : memoryOrdersToGenerate) {
298+
store.order = memoryOrder;
299+
if (store.isAtomic() &&
294300
!isPossibleAtomicOperation(
295301
align, bytes, module->memories[0]->shared, valueType)) {
296302
continue;

src/tools/wasm-split/instrumenter.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,8 @@ void Instrumenter::instrumentFuncs() {
151151
builder.makeConstPtr(0, Type::i32),
152152
builder.makeConst(uint32_t(1)),
153153
Type::i32,
154-
memoryName),
154+
memoryName,
155+
MemoryOrder::SeqCst),
155156
func->body,
156157
func->body->type);
157158
++funcIdx;

src/wasm-builder.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,9 +451,13 @@ class Builder {
451451
Expression* ptr,
452452
Expression* value,
453453
Type type,
454-
Name memory) {
454+
Name memory,
455+
MemoryOrder order) {
456+
assert(order != MemoryOrder::Unordered &&
457+
"Atomic stores can't be unordered");
458+
455459
Store* store = makeStore(bytes, offset, bytes, ptr, value, type, memory);
456-
store->order = MemoryOrder::SeqCst;
460+
store->order = order;
457461
return store;
458462
}
459463
AtomicRMW* makeAtomicRMW(AtomicRMWOp op,

src/wasm-ir-builder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
158158
unsigned bytes, Address offset, unsigned align, Type type, Name mem);
159159
Result<> makeAtomicLoad(
160160
unsigned bytes, Address offset, Type type, Name mem, MemoryOrder order);
161-
Result<> makeAtomicStore(unsigned bytes, Address offset, Type type, Name mem);
161+
Result<> makeAtomicStore(
162+
unsigned bytes, Address offset, Type type, Name mem, MemoryOrder order);
162163
Result<> makeAtomicRMW(
163164
AtomicRMWOp op, unsigned bytes, Address offset, Type type, Name mem);
164165
Result<>

src/wasm/wasm-binary.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3657,31 +3657,38 @@ Result<> WasmBinaryReader::readInst() {
36573657
}
36583658
case BinaryConsts::I32AtomicStore8: {
36593659
auto [mem, align, offset, memoryOrder] = getAtomicMemarg();
3660-
return builder.makeAtomicStore(1, offset, Type::i32, mem);
3660+
return builder.makeAtomicStore(
3661+
1, offset, Type::i32, mem, memoryOrder);
36613662
}
36623663
case BinaryConsts::I32AtomicStore16: {
36633664
auto [mem, align, offset, memoryOrder] = getAtomicMemarg();
3664-
return builder.makeAtomicStore(2, offset, Type::i32, mem);
3665+
return builder.makeAtomicStore(
3666+
2, offset, Type::i32, mem, memoryOrder);
36653667
}
36663668
case BinaryConsts::I32AtomicStore: {
36673669
auto [mem, align, offset, memoryOrder] = getAtomicMemarg();
3668-
return builder.makeAtomicStore(4, offset, Type::i32, mem);
3670+
return builder.makeAtomicStore(
3671+
4, offset, Type::i32, mem, memoryOrder);
36693672
}
36703673
case BinaryConsts::I64AtomicStore8: {
36713674
auto [mem, align, offset, memoryOrder] = getAtomicMemarg();
3672-
return builder.makeAtomicStore(1, offset, Type::i64, mem);
3675+
return builder.makeAtomicStore(
3676+
1, offset, Type::i64, mem, memoryOrder);
36733677
}
36743678
case BinaryConsts::I64AtomicStore16: {
36753679
auto [mem, align, offset, memoryOrder] = getAtomicMemarg();
3676-
return builder.makeAtomicStore(2, offset, Type::i64, mem);
3680+
return builder.makeAtomicStore(
3681+
2, offset, Type::i64, mem, memoryOrder);
36773682
}
36783683
case BinaryConsts::I64AtomicStore32: {
36793684
auto [mem, align, offset, memoryOrder] = getAtomicMemarg();
3680-
return builder.makeAtomicStore(4, offset, Type::i64, mem);
3685+
return builder.makeAtomicStore(
3686+
4, offset, Type::i64, mem, memoryOrder);
36813687
}
36823688
case BinaryConsts::I64AtomicStore: {
36833689
auto [mem, align, offset, memoryOrder] = getAtomicMemarg();
3684-
return builder.makeAtomicStore(8, offset, Type::i64, mem);
3690+
return builder.makeAtomicStore(
3691+
8, offset, Type::i64, mem, memoryOrder);
36853692
}
36863693

36873694
#define RMW(op) \

src/wasm/wasm-ir-builder.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,15 +1492,14 @@ Result<> IRBuilder::makeAtomicLoad(
14921492
return Ok{};
14931493
}
14941494

1495-
Result<> IRBuilder::makeAtomicStore(unsigned bytes,
1496-
Address offset,
1497-
Type type,
1498-
Name mem) {
1495+
Result<> IRBuilder::makeAtomicStore(
1496+
unsigned bytes, Address offset, Type type, Name mem, MemoryOrder order) {
14991497
Store curr;
15001498
curr.memory = mem;
15011499
curr.valueType = type;
15021500
CHECK_ERR(visitStore(&curr));
1503-
push(builder.makeAtomicStore(bytes, offset, curr.ptr, curr.value, type, mem));
1501+
push(builder.makeAtomicStore(
1502+
bytes, offset, curr.ptr, curr.value, type, mem, order));
15041503
return Ok{};
15051504
}
15061505

0 commit comments

Comments
 (0)