Skip to content

[SharedEverything] Add array.atomic.get/set #7621

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
May 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions scripts/gen-s-parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,11 @@
("array.get", "makeArrayGet()"),
("array.get_s", "makeArrayGet(true)"),
("array.get_u", "makeArrayGet(false)"),
("array.atomic.get", "makeAtomicArrayGet()"),
("array.atomic.get_s", "makeAtomicArrayGet(true)"),
("array.atomic.get_u", "makeAtomicArrayGet(false)"),
("array.set", "makeArraySet()"),
("array.atomic.set", "makeAtomicArraySet()"),
("array.len", "makeArrayLen()"),
("array.copy", "makeArrayCopy()"),
("array.fill", "makeArrayFill()"),
Expand Down
17 changes: 11 additions & 6 deletions src/binaryen-c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1822,17 +1822,22 @@ BinaryenExpressionRef BinaryenArrayGet(BinaryenModuleRef module,
BinaryenExpressionRef index,
BinaryenType type,
bool signed_) {
return static_cast<Expression*>(
Builder(*(Module*)module)
.makeArrayGet((Expression*)ref, (Expression*)index, Type(type), signed_));
return static_cast<Expression*>(Builder(*(Module*)module)
.makeArrayGet((Expression*)ref,
(Expression*)index,
MemoryOrder::Unordered,
Type(type),
signed_));
}
BinaryenExpressionRef BinaryenArraySet(BinaryenModuleRef module,
BinaryenExpressionRef ref,
BinaryenExpressionRef index,
BinaryenExpressionRef value) {
return static_cast<Expression*>(
Builder(*(Module*)module)
.makeArraySet((Expression*)ref, (Expression*)index, (Expression*)value));
return static_cast<Expression*>(Builder(*(Module*)module)
.makeArraySet((Expression*)ref,
(Expression*)index,
(Expression*)value,
MemoryOrder::Unordered));
}
BinaryenExpressionRef BinaryenArrayLen(BinaryenModuleRef module,
BinaryenExpressionRef ref) {
Expand Down
39 changes: 39 additions & 0 deletions src/gen-s-parser.inc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,45 @@ switch (buf[0]) {
goto parse_error;
case 'r': {
switch (buf[6]) {
case 'a': {
switch (buf[13]) {
case 'g': {
switch (buf[16]) {
case '\0':
if (op == "array.atomic.get"sv) {
CHECK_ERR(makeAtomicArrayGet(ctx, pos, annotations));
return Ok{};
}
goto parse_error;
case '_': {
switch (buf[17]) {
case 's':
if (op == "array.atomic.get_s"sv) {
CHECK_ERR(makeAtomicArrayGet(ctx, pos, annotations, true));
return Ok{};
}
goto parse_error;
case 'u':
if (op == "array.atomic.get_u"sv) {
CHECK_ERR(makeAtomicArrayGet(ctx, pos, annotations, false));
return Ok{};
}
goto parse_error;
default: goto parse_error;
}
}
default: goto parse_error;
}
}
case 's':
if (op == "array.atomic.set"sv) {
CHECK_ERR(makeAtomicArraySet(ctx, pos, annotations));
return Ok{};
}
goto parse_error;
default: goto parse_error;
}
}
case 'c':
if (op == "array.copy"sv) {
CHECK_ERR(makeArrayCopy(ctx, pos, annotations));
Expand Down
13 changes: 8 additions & 5 deletions src/ir/possible-contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1059,10 +1059,11 @@ struct InfoCollector
// part of the main IR, which is potentially confusing during debugging,
// however, which is a downside.
Builder builder(*getModule());
auto* get =
builder.makeArrayGet(curr->srcRef, curr->srcIndex, curr->srcRef->type);
auto* get = builder.makeArrayGet(
curr->srcRef, curr->srcIndex, MemoryOrder::Unordered, curr->srcRef->type);
visitArrayGet(get);
auto* set = builder.makeArraySet(curr->destRef, curr->destIndex, get);
auto* set = builder.makeArraySet(
curr->destRef, curr->destIndex, get, MemoryOrder::Unordered);
visitArraySet(set);
}
void visitArrayFill(ArrayFill* curr) {
Expand All @@ -1071,7 +1072,8 @@ struct InfoCollector
}
// See ArrayCopy, above.
Builder builder(*getModule());
auto* set = builder.makeArraySet(curr->ref, curr->index, curr->value);
auto* set = builder.makeArraySet(
curr->ref, curr->index, curr->value, MemoryOrder::Unordered);
visitArraySet(set);
}
template<typename ArrayInit> void visitArrayInit(ArrayInit* curr) {
Expand All @@ -1092,7 +1094,8 @@ struct InfoCollector
Builder builder(*getModule());
auto* get = builder.makeLocalGet(-1, valueType);
addRoot(get);
auto* set = builder.makeArraySet(curr->ref, curr->index, get);
auto* set =
builder.makeArraySet(curr->ref, curr->index, get, MemoryOrder::Unordered);
visitArraySet(set);
}
void visitArrayInitData(ArrayInitData* curr) { visitArrayInit(curr); }
Expand Down
17 changes: 10 additions & 7 deletions src/parser/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -815,12 +815,13 @@ struct NullInstrParserCtx {
return Ok{};
}
template<typename HeapTypeT>
Result<>
makeArrayGet(Index, const std::vector<Annotation>&, HeapTypeT, bool) {
Result<> makeArrayGet(
Index, const std::vector<Annotation>&, HeapTypeT, bool, MemoryOrder) {
return Ok{};
}
template<typename HeapTypeT>
Result<> makeArraySet(Index, const std::vector<Annotation>&, HeapTypeT) {
Result<>
makeArraySet(Index, const std::vector<Annotation>&, HeapTypeT, MemoryOrder) {
return Ok{};
}
Result<> makeArrayLen(Index, const std::vector<Annotation>&) { return Ok{}; }
Expand Down Expand Up @@ -2693,14 +2694,16 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx>, AnnotationParserCtx {
Result<> makeArrayGet(Index pos,
const std::vector<Annotation>& annotations,
HeapType type,
bool signed_) {
return withLoc(pos, irBuilder.makeArrayGet(type, signed_));
bool signed_,
MemoryOrder order) {
return withLoc(pos, irBuilder.makeArrayGet(type, signed_, order));
}

Result<> makeArraySet(Index pos,
const std::vector<Annotation>& annotations,
HeapType type) {
return withLoc(pos, irBuilder.makeArraySet(type));
HeapType type,
MemoryOrder order) {
return withLoc(pos, irBuilder.makeArraySet(type, order));
}

Result<> makeArrayLen(Index pos, const std::vector<Annotation>& annotations) {
Expand Down
35 changes: 33 additions & 2 deletions src/parser/parsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,15 @@ template<typename Ctx>
Result<>
makeArrayGet(Ctx&, Index, const std::vector<Annotation>&, bool signed_ = false);
template<typename Ctx>
Result<> makeAtomicArrayGet(Ctx&,
Index,
const std::vector<Annotation>&,
bool signed_ = false);
template<typename Ctx>
Result<> makeArraySet(Ctx&, Index, const std::vector<Annotation>&);
template<typename Ctx>
Result<> makeAtomicArraySet(Ctx&, Index, const std::vector<Annotation>&);
template<typename Ctx>
Result<> makeArrayLen(Ctx&, Index, const std::vector<Annotation>&);
template<typename Ctx>
Result<> makeArrayCopy(Ctx&, Index, const std::vector<Annotation>&);
Expand Down Expand Up @@ -2411,15 +2418,39 @@ Result<> makeArrayGet(Ctx& ctx,
bool signed_) {
auto type = typeidx(ctx);
CHECK_ERR(type);
return ctx.makeArrayGet(pos, annotations, *type, signed_);
return ctx.makeArrayGet(
pos, annotations, *type, signed_, MemoryOrder::Unordered);
}

template<typename Ctx>
Result<> makeAtomicArrayGet(Ctx& ctx,
Index pos,
const std::vector<Annotation>& annotations,
bool signed_) {
auto order = memorder(ctx);
CHECK_ERR(order);
auto type = typeidx(ctx);
CHECK_ERR(type);
return ctx.makeArrayGet(pos, annotations, *type, signed_, *order);
}

template<typename Ctx>
Result<>
makeArraySet(Ctx& ctx, Index pos, const std::vector<Annotation>& annotations) {
auto type = typeidx(ctx);
CHECK_ERR(type);
return ctx.makeArraySet(pos, annotations, *type);
return ctx.makeArraySet(pos, annotations, *type, MemoryOrder::Unordered);
}

template<typename Ctx>
Result<> makeAtomicArraySet(Ctx& ctx,
Index pos,
const std::vector<Annotation>& annotations) {
auto order = memorder(ctx);
CHECK_ERR(order);
auto type = typeidx(ctx);
CHECK_ERR(type);
return ctx.makeArraySet(pos, annotations, *type, *order);
}

template<typename Ctx>
Expand Down
18 changes: 14 additions & 4 deletions src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2372,19 +2372,29 @@ struct PrintExpressionContents
}
void visitArrayGet(ArrayGet* curr) {
const auto& element = curr->ref->type.getHeapType().getArray().element;
printMedium(o, "array");
if (curr->order != MemoryOrder::Unordered) {
printMedium(o, ".atomic");
}
if (element.type == Type::i32 && element.packedType != Field::not_packed) {
if (curr->signed_) {
printMedium(o, "array.get_s ");
printMedium(o, ".get_s ");
} else {
printMedium(o, "array.get_u ");
printMedium(o, ".get_u ");
}
} else {
printMedium(o, "array.get ");
printMedium(o, ".get ");
}
printMemoryOrder(curr->order);
printHeapTypeName(curr->ref->type.getHeapType());
}
void visitArraySet(ArraySet* curr) {
printMedium(o, "array.set ");
if (curr->order == MemoryOrder::Unordered) {
printMedium(o, "array.set ");
} else {
printMedium(o, "array.atomic.set ");
}
printMemoryOrder(curr->order);
printHeapTypeName(curr->ref->type.getHeapType());
}
void visitArrayLen(ArrayLen* curr) { printMedium(o, "array.len"); }
Expand Down
11 changes: 7 additions & 4 deletions src/tools/fuzzing/fuzzing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5058,14 +5058,16 @@ Expression* TranslateToFuzzReader::makeArrayGet(Type type) {
// Only rarely emit a plain get which might trap. See related logic in
// ::makePointer().
if (allowOOB && oneIn(10)) {
return builder.makeArrayGet(ref, index, type, signed_);
return builder.makeArrayGet(
ref, index, MemoryOrder::Unordered, type, signed_);
}
// To avoid a trap, check the length dynamically using this pattern:
//
// index < array.len ? array[index] : ..some fallback value..
//
auto check = makeArrayBoundsCheck(ref, index, funcContext->func, builder);
auto* get = builder.makeArrayGet(check.getRef, check.getIndex, type, signed_);
auto* get = builder.makeArrayGet(
check.getRef, check.getIndex, MemoryOrder::Unordered, type, signed_);
auto* fallback = makeTrivial(type);
return builder.makeIf(check.condition, get, fallback);
}
Expand All @@ -5083,14 +5085,15 @@ Expression* TranslateToFuzzReader::makeArraySet(Type type) {
// Only rarely emit a plain get which might trap. See related logic in
// ::makePointer().
if (allowOOB && oneIn(10)) {
return builder.makeArraySet(ref, index, value);
return builder.makeArraySet(ref, index, value, MemoryOrder::Unordered);
}
// To avoid a trap, check the length dynamically using this pattern:
//
// if (index < array.len) array[index] = value;
//
auto check = makeArrayBoundsCheck(ref, index, funcContext->func, builder);
auto* set = builder.makeArraySet(check.getRef, check.getIndex, value);
auto* set = builder.makeArraySet(
check.getRef, check.getIndex, value, MemoryOrder::Unordered);
return builder.makeIf(check.condition, set);
}

Expand Down
6 changes: 4 additions & 2 deletions src/tools/wasm-ctor-eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -960,8 +960,10 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
set =
builder.makeStructSet(index, getGlobal, value, MemoryOrder::Unordered);
} else {
set = builder.makeArraySet(
getGlobal, builder.makeConst(int32_t(index)), value);
set = builder.makeArraySet(getGlobal,
builder.makeConst(int32_t(index)),
value,
MemoryOrder::Unordered);
}

(*startBlock)->list.push_back(set);
Expand Down
4 changes: 4 additions & 0 deletions src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -1197,6 +1197,10 @@ enum ASTNodes {
StructAtomicRMWXor = 0x64,
StructAtomicRMWXchg = 0x65,
StructAtomicRMWCmpxchg = 0x66,
ArrayAtomicGet = 0x67,
ArrayAtomicGetS = 0x68,
ArrayAtomicGetU = 0x69,
ArrayAtomicSet = 0x6a,

// stringref opcodes

Expand Down
9 changes: 7 additions & 2 deletions src/wasm-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1034,22 +1034,27 @@ class Builder {
}
ArrayGet* makeArrayGet(Expression* ref,
Expression* index,
MemoryOrder order,
Type type,
bool signed_ = false) {
auto* ret = wasm.allocator.alloc<ArrayGet>();
ret->ref = ref;
ret->index = index;
ret->type = type;
ret->signed_ = signed_;
ret->order = order;
ret->finalize();
return ret;
}
ArraySet*
makeArraySet(Expression* ref, Expression* index, Expression* value) {
ArraySet* makeArraySet(Expression* ref,
Expression* index,
Expression* value,
MemoryOrder order) {
auto* ret = wasm.allocator.alloc<ArraySet>();
ret->ref = ref;
ret->index = index;
ret->value = value;
ret->order = order;
ret->finalize();
return ret;
}
Expand Down
2 changes: 2 additions & 0 deletions src/wasm-delegations-fields.def
Original file line number Diff line number Diff line change
Expand Up @@ -703,12 +703,14 @@ DELEGATE_FIELD_CASE_START(ArrayGet)
DELEGATE_FIELD_CHILD(ArrayGet, index)
DELEGATE_FIELD_IMMEDIATE_TYPED_CHILD(ArrayGet, ref)
DELEGATE_FIELD_INT(ArrayGet, signed_)
DELEGATE_FIELD_INT(ArraySet, order)
DELEGATE_FIELD_CASE_END(ArrayGet)

DELEGATE_FIELD_CASE_START(ArraySet)
DELEGATE_FIELD_CHILD(ArraySet, value)
DELEGATE_FIELD_CHILD(ArraySet, index)
DELEGATE_FIELD_IMMEDIATE_TYPED_CHILD(ArraySet, ref)
DELEGATE_FIELD_INT(ArraySet, order)
DELEGATE_FIELD_CASE_END(ArraySet)

DELEGATE_FIELD_CASE_START(ArrayLen)
Expand Down
4 changes: 2 additions & 2 deletions src/wasm-ir-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
Result<> makeArrayNewData(HeapType type, Name data);
Result<> makeArrayNewElem(HeapType type, Name elem);
Result<> makeArrayNewFixed(HeapType type, uint32_t arity);
Result<> makeArrayGet(HeapType type, bool signed_);
Result<> makeArraySet(HeapType type);
Result<> makeArrayGet(HeapType type, bool signed_, MemoryOrder order);
Result<> makeArraySet(HeapType type, MemoryOrder order);
Result<> makeArrayLen();
Result<> makeArrayCopy(HeapType destType, HeapType srcType);
Result<> makeArrayFill(HeapType type);
Expand Down
2 changes: 2 additions & 0 deletions src/wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -1778,6 +1778,7 @@ class ArrayGet : public SpecificExpression<Expression::ArrayGetId> {
Expression* index;
// Packed fields have a sign.
bool signed_ = false;
MemoryOrder order = MemoryOrder::Unordered;

void finalize();
};
Expand All @@ -1790,6 +1791,7 @@ class ArraySet : public SpecificExpression<Expression::ArraySetId> {
Expression* ref;
Expression* index;
Expression* value;
MemoryOrder order = MemoryOrder::Unordered;

void finalize();
};
Expand Down
Loading
Loading