Skip to content

Commit 4f9374c

Browse files
authored
[Shared-Everything] ArrayRMW and ArrayCmpxchg (#7632)
1 parent efd572c commit 4f9374c

31 files changed

+964
-86
lines changed

scripts/gen-s-parser.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,13 @@
653653
("array.fill", "makeArrayFill()"),
654654
("array.init_data", "makeArrayInitData()"),
655655
("array.init_elem", "makeArrayInitElem()"),
656+
("array.atomic.rmw.add", "makeArrayRMW(RMWAdd)"),
657+
("array.atomic.rmw.sub", "makeArrayRMW(RMWSub)"),
658+
("array.atomic.rmw.and", "makeArrayRMW(RMWAnd)"),
659+
("array.atomic.rmw.or", "makeArrayRMW(RMWOr)"),
660+
("array.atomic.rmw.xor", "makeArrayRMW(RMWXor)"),
661+
("array.atomic.rmw.xchg", "makeArrayRMW(RMWXchg)"),
662+
("array.atomic.rmw.cmpxchg", "makeArrayCmpxchg()"),
656663
("ref.as_non_null", "makeRefAs(RefAsNonNull)"),
657664
("extern.internalize", "makeRefAs(AnyConvertExtern)"), # Deprecated
658665
("extern.externalize", "makeRefAs(ExternConvertAny)"), # Deprecated

src/gen-s-parser.inc

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,63 @@ switch (buf[0]) {
5252
default: goto parse_error;
5353
}
5454
}
55+
case 'r': {
56+
switch (buf[17]) {
57+
case 'a': {
58+
switch (buf[18]) {
59+
case 'd':
60+
if (op == "array.atomic.rmw.add"sv) {
61+
CHECK_ERR(makeArrayRMW(ctx, pos, annotations, RMWAdd));
62+
return Ok{};
63+
}
64+
goto parse_error;
65+
case 'n':
66+
if (op == "array.atomic.rmw.and"sv) {
67+
CHECK_ERR(makeArrayRMW(ctx, pos, annotations, RMWAnd));
68+
return Ok{};
69+
}
70+
goto parse_error;
71+
default: goto parse_error;
72+
}
73+
}
74+
case 'c':
75+
if (op == "array.atomic.rmw.cmpxchg"sv) {
76+
CHECK_ERR(makeArrayCmpxchg(ctx, pos, annotations));
77+
return Ok{};
78+
}
79+
goto parse_error;
80+
case 'o':
81+
if (op == "array.atomic.rmw.or"sv) {
82+
CHECK_ERR(makeArrayRMW(ctx, pos, annotations, RMWOr));
83+
return Ok{};
84+
}
85+
goto parse_error;
86+
case 's':
87+
if (op == "array.atomic.rmw.sub"sv) {
88+
CHECK_ERR(makeArrayRMW(ctx, pos, annotations, RMWSub));
89+
return Ok{};
90+
}
91+
goto parse_error;
92+
case 'x': {
93+
switch (buf[18]) {
94+
case 'c':
95+
if (op == "array.atomic.rmw.xchg"sv) {
96+
CHECK_ERR(makeArrayRMW(ctx, pos, annotations, RMWXchg));
97+
return Ok{};
98+
}
99+
goto parse_error;
100+
case 'o':
101+
if (op == "array.atomic.rmw.xor"sv) {
102+
CHECK_ERR(makeArrayRMW(ctx, pos, annotations, RMWXor));
103+
return Ok{};
104+
}
105+
goto parse_error;
106+
default: goto parse_error;
107+
}
108+
}
109+
default: goto parse_error;
110+
}
111+
}
55112
case 's':
56113
if (op == "array.atomic.set"sv) {
57114
CHECK_ERR(makeAtomicArraySet(ctx, pos, annotations));

src/interpreter/interpreter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ struct ExpressionInterpreter : OverriddenVisitor<ExpressionInterpreter, Flow> {
263263
Flow visitArrayFill(ArrayFill* curr) { WASM_UNREACHABLE("TODO"); }
264264
Flow visitArrayInitData(ArrayInitData* curr) { WASM_UNREACHABLE("TODO"); }
265265
Flow visitArrayInitElem(ArrayInitElem* curr) { WASM_UNREACHABLE("TODO"); }
266+
Flow visitArrayRMW(ArrayRMW* curr) { WASM_UNREACHABLE("TODO"); }
267+
Flow visitArrayCmpxchg(ArrayCmpxchg* curr) { WASM_UNREACHABLE("TODO"); }
266268
Flow visitRefAs(RefAs* curr) { WASM_UNREACHABLE("TODO"); }
267269
Flow visitStringNew(StringNew* curr) { WASM_UNREACHABLE("TODO"); }
268270
Flow visitStringConst(StringConst* curr) { WASM_UNREACHABLE("TODO"); }

src/ir/ReFinalize.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ void ReFinalize::visitArrayCopy(ArrayCopy* curr) { curr->finalize(); }
172172
void ReFinalize::visitArrayFill(ArrayFill* curr) { curr->finalize(); }
173173
void ReFinalize::visitArrayInitData(ArrayInitData* curr) { curr->finalize(); }
174174
void ReFinalize::visitArrayInitElem(ArrayInitElem* curr) { curr->finalize(); }
175+
void ReFinalize::visitArrayRMW(ArrayRMW* curr) { curr->finalize(); }
176+
void ReFinalize::visitArrayCmpxchg(ArrayCmpxchg* curr) { curr->finalize(); }
175177
void ReFinalize::visitRefAs(RefAs* curr) { curr->finalize(); }
176178
void ReFinalize::visitStringNew(StringNew* curr) { curr->finalize(); }
177179
void ReFinalize::visitStringConst(StringConst* curr) { curr->finalize(); }

src/ir/child-typer.h

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -997,8 +997,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
997997
const auto& fields = ht->getStruct().fields;
998998
assert(curr->index < fields.size());
999999
note(&curr->ref, Type(*ht, Nullable));
1000-
note(&curr->expected, fields[curr->index].type);
1001-
note(&curr->replacement, fields[curr->index].type);
1000+
auto type = fields[curr->index].type;
1001+
note(&curr->expected, type.isRef() ? Type(HeapType::eq, Nullable) : type);
1002+
note(&curr->replacement, type);
10021003
}
10031004

10041005
void visitArrayNew(ArrayNew* curr) {
@@ -1126,6 +1127,35 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
11261127
note(&curr->size, Type::i32);
11271128
}
11281129

1130+
void visitArrayRMW(ArrayRMW* curr,
1131+
std::optional<HeapType> ht = std::nullopt) {
1132+
if (!ht) {
1133+
if (self().skipUnreachable() && !curr->ref->type.isRef()) {
1134+
return;
1135+
}
1136+
ht = curr->ref->type.getHeapType();
1137+
}
1138+
auto type = ht->getArray().element.type;
1139+
note(&curr->ref, Type(*ht, Nullable));
1140+
note(&curr->index, Type::i32);
1141+
note(&curr->value, type);
1142+
}
1143+
1144+
void visitArrayCmpxchg(ArrayCmpxchg* curr,
1145+
std::optional<HeapType> ht = std::nullopt) {
1146+
if (!ht) {
1147+
if (self().skipUnreachable() && !curr->ref->type.isRef()) {
1148+
return;
1149+
}
1150+
ht = curr->ref->type.getHeapType();
1151+
}
1152+
auto type = ht->getArray().element.type;
1153+
note(&curr->ref, Type(*ht, Nullable));
1154+
note(&curr->index, Type::i32);
1155+
note(&curr->expected, type.isRef() ? Type(HeapType::eq, Nullable) : type);
1156+
note(&curr->replacement, type);
1157+
}
1158+
11291159
void visitRefAs(RefAs* curr) {
11301160
switch (curr->op) {
11311161
case RefAsNonNull:

src/ir/cost.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,15 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
752752
return 6 + visit(curr->ref) + visit(curr->index) + visit(curr->offset) +
753753
visit(curr->size);
754754
}
755+
CostType visitArrayRMW(ArrayRMW* curr) {
756+
return AtomicCost + nullCheckCost(curr->ref) + visit(curr->ref) +
757+
visit(curr->index) + visit(curr->value);
758+
}
759+
CostType visitArrayCmpxchg(ArrayCmpxchg* curr) {
760+
return AtomicCost + nullCheckCost(curr->ref) + visit(curr->ref) +
761+
visit(curr->index) + visit(curr->expected) +
762+
visit(curr->replacement);
763+
}
755764
CostType visitRefAs(RefAs* curr) { return 1 + visit(curr->value); }
756765
CostType visitStringNew(StringNew* curr) {
757766
return 8 + visit(curr->ref) + maybeVisit(curr->start) +

src/ir/effects.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,32 @@ class EffectAnalyzer {
10001000
}
10011001
void visitArrayInitData(ArrayInitData* curr) { visitArrayInit(curr); }
10021002
void visitArrayInitElem(ArrayInitElem* curr) { visitArrayInit(curr); }
1003+
void visitArrayRMW(ArrayRMW* curr) {
1004+
if (curr->ref->type.isNull()) {
1005+
parent.trap = true;
1006+
return;
1007+
}
1008+
parent.readsArray = true;
1009+
parent.writesArray = true;
1010+
if (curr->ref->type.isNullable()) {
1011+
parent.implicitTrap = true;
1012+
}
1013+
assert(curr->order != MemoryOrder::Unordered);
1014+
parent.isAtomic = true;
1015+
}
1016+
void visitArrayCmpxchg(ArrayCmpxchg* curr) {
1017+
if (curr->ref->type.isNull()) {
1018+
parent.trap = true;
1019+
return;
1020+
}
1021+
parent.readsArray = true;
1022+
parent.writesArray = true;
1023+
if (curr->ref->type.isNullable()) {
1024+
parent.implicitTrap = true;
1025+
}
1026+
assert(curr->order != MemoryOrder::Unordered);
1027+
parent.isAtomic = true;
1028+
}
10031029
void visitRefAs(RefAs* curr) {
10041030
if (curr->op == AnyConvertExtern || curr->op == ExternConvertAny) {
10051031
// These conversions are infallible.

src/ir/possible-contents.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,6 +1100,22 @@ struct InfoCollector
11001100
}
11011101
void visitArrayInitData(ArrayInitData* curr) { visitArrayInit(curr); }
11021102
void visitArrayInitElem(ArrayInitElem* curr) { visitArrayInit(curr); }
1103+
void visitArrayRMW(ArrayRMW* curr) {
1104+
if (curr->ref->type == Type::unreachable) {
1105+
return;
1106+
}
1107+
// TODO: Model the modification part of the RMW in addition to the read and
1108+
// the write.
1109+
addRoot(curr);
1110+
}
1111+
void visitArrayCmpxchg(ArrayCmpxchg* curr) {
1112+
if (curr->ref->type == Type::unreachable) {
1113+
return;
1114+
}
1115+
// TODO: Model the modification part of the RMW in addition to the read and
1116+
// the write.
1117+
addRoot(curr);
1118+
}
11031119
void visitStringNew(StringNew* curr) {
11041120
if (curr->type == Type::unreachable) {
11051121
return;
@@ -1618,6 +1634,8 @@ void TNHOracle::scan(Function* func,
16181634
void visitArrayInitElem(ArrayInitElem* curr) {
16191635
notePossibleTrap(curr->ref);
16201636
}
1637+
void visitArrayRMW(ArrayRMW* curr) { notePossibleTrap(curr->ref); }
1638+
void visitArrayCmpxchg(ArrayCmpxchg* curr) { notePossibleTrap(curr->ref); }
16211639

16221640
void visitFunction(Function* curr) {
16231641
// In optimized TNH code, a function that always traps will be turned

src/ir/subtype-exprs.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,8 +337,10 @@ struct SubtypingDiscoverer : public OverriddenVisitor<SubType> {
337337
return;
338338
}
339339
const auto& fields = curr->ref->type.getHeapType().getStruct().fields;
340-
self()->noteSubtype(curr->expected, fields[curr->index].type);
341-
self()->noteSubtype(curr->replacement, fields[curr->index].type);
340+
auto type = fields[curr->index].type;
341+
self()->noteSubtype(curr->expected,
342+
type.isRef() ? Type(HeapType::eq, Nullable) : type);
343+
self()->noteSubtype(curr->replacement, type);
342344
}
343345
void visitArrayNew(ArrayNew* curr) {
344346
if (!curr->type.isArray() || curr->isWithDefault()) {
@@ -399,6 +401,22 @@ struct SubtypingDiscoverer : public OverriddenVisitor<SubType> {
399401
auto* seg = self()->getModule()->getElementSegment(curr->segment);
400402
self()->noteSubtype(seg->type, array.element.type);
401403
}
404+
void visitArrayRMW(ArrayRMW* curr) {
405+
if (!curr->ref->type.isArray()) {
406+
return;
407+
}
408+
auto array = curr->ref->type.getHeapType().getArray();
409+
self()->noteSubtype(curr->value, array.element.type);
410+
}
411+
void visitArrayCmpxchg(ArrayCmpxchg* curr) {
412+
if (!curr->ref->type.isArray()) {
413+
return;
414+
}
415+
auto type = curr->ref->type.getHeapType().getArray().element.type;
416+
self()->noteSubtype(curr->expected,
417+
type.isRef() ? Type(HeapType::eq, Nullable) : type);
418+
self()->noteSubtype(curr->replacement, type);
419+
}
402420
void visitRefAs(RefAs* curr) {
403421
if (curr->op == RefAsNonNull) {
404422
self()->noteCast(curr->value, curr);

src/parser/contexts.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,21 @@ struct NullInstrParserCtx {
848848
ElemIdxT) {
849849
return Ok{};
850850
}
851+
template<typename HeapTypeT>
852+
Result<> makeArrayRMW(Index,
853+
const std::vector<Annotation>&,
854+
AtomicRMWOp,
855+
HeapTypeT,
856+
MemoryOrder) {
857+
return Ok{};
858+
}
859+
template<typename HeapTypeT>
860+
Result<> makeArrayCmpxchg(Index,
861+
const std::vector<Annotation>&,
862+
HeapTypeT,
863+
MemoryOrder) {
864+
return Ok{};
865+
}
851866
Result<> makeRefAs(Index, const std::vector<Annotation>&, RefAsOp) {
852867
return Ok{};
853868
}
@@ -2738,6 +2753,21 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx>, AnnotationParserCtx {
27382753
return withLoc(pos, irBuilder.makeArrayInitElem(type, elem));
27392754
}
27402755

2756+
Result<> makeArrayRMW(Index pos,
2757+
const std::vector<Annotation>& annotations,
2758+
AtomicRMWOp op,
2759+
HeapType type,
2760+
MemoryOrder order) {
2761+
return withLoc(pos, irBuilder.makeArrayRMW(op, type, order));
2762+
}
2763+
2764+
Result<> makeArrayCmpxchg(Index pos,
2765+
const std::vector<Annotation>& annotations,
2766+
HeapType type,
2767+
MemoryOrder order) {
2768+
return withLoc(pos, irBuilder.makeArrayCmpxchg(type, order));
2769+
}
2770+
27412771
Result<>
27422772
makeRefAs(Index pos, const std::vector<Annotation>& annotations, RefAsOp op) {
27432773
return withLoc(pos, irBuilder.makeRefAs(op));

0 commit comments

Comments
 (0)