Skip to content

Commit a7b3e65

Browse files
committed
Implement multibyte array store instructions
Add support for multibyte array store instructions as proposed in the WebAssembly multibyte proposal. These instructions allow storing values of various byte widths directly into i8 arrays, avoiding the need for manual bit manipulation and masking. Link: https://github.com/WebAssembly/multibyte
1 parent ca32e92 commit a7b3e65

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1149
-198
lines changed

scripts/clusterfuzz/run.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
'--disable-strings',
9595
'--disable-stack-switching',
9696
'--disable-relaxed-atomics',
97+
'--disable-multibyte',
9798
]
9899

99100

src/interpreter/interpreter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ struct ExpressionInterpreter : OverriddenVisitor<ExpressionInterpreter, Flow> {
260260
Flow visitArrayNewFixed(ArrayNewFixed* curr) { WASM_UNREACHABLE("TODO"); }
261261
Flow visitArrayGet(ArrayGet* curr) { WASM_UNREACHABLE("TODO"); }
262262
Flow visitArraySet(ArraySet* curr) { WASM_UNREACHABLE("TODO"); }
263+
Flow visitArrayStore(ArrayStore* curr) { WASM_UNREACHABLE("TODO"); }
263264
Flow visitArrayLen(ArrayLen* curr) { WASM_UNREACHABLE("TODO"); }
264265
Flow visitArrayCopy(ArrayCopy* curr) { WASM_UNREACHABLE("TODO"); }
265266
Flow visitArrayFill(ArrayFill* curr) { WASM_UNREACHABLE("TODO"); }

src/ir/ReFinalize.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ void ReFinalize::visitArrayNewElem(ArrayNewElem* curr) { curr->finalize(); }
169169
void ReFinalize::visitArrayNewFixed(ArrayNewFixed* curr) { curr->finalize(); }
170170
void ReFinalize::visitArrayGet(ArrayGet* curr) { curr->finalize(); }
171171
void ReFinalize::visitArraySet(ArraySet* curr) { curr->finalize(); }
172+
void ReFinalize::visitArrayStore(ArrayStore* curr) { curr->finalize(); }
172173
void ReFinalize::visitArrayLen(ArrayLen* curr) { curr->finalize(); }
173174
void ReFinalize::visitArrayCopy(ArrayCopy* curr) { curr->finalize(); }
174175
void ReFinalize::visitArrayFill(ArrayFill* curr) { curr->finalize(); }

src/ir/child-typer.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,20 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
10671067
note(&curr->value, type);
10681068
}
10691069

1070+
void visitArrayStore(ArrayStore* curr,
1071+
std::optional<HeapType> ht = std::nullopt) {
1072+
if (!ht) {
1073+
if (!curr->ref->type.isRef()) {
1074+
self().noteUnknown();
1075+
return;
1076+
}
1077+
ht = curr->ref->type.getHeapType();
1078+
}
1079+
note(&curr->ref, Type(*ht, Nullable));
1080+
note(&curr->index, Type::i32);
1081+
note(&curr->value, curr->valueType);
1082+
}
1083+
10701084
void visitArrayLen(ArrayLen* curr) {
10711085
note(&curr->ref, Type(HeapType::array, Nullable));
10721086
}

src/ir/cost.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,10 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
745745
return 2 + nullCheckCost(curr->ref) + visit(curr->ref) +
746746
visit(curr->index) + visit(curr->value);
747747
}
748+
CostType visitArrayStore(ArrayStore* curr) {
749+
return 2 + nullCheckCost(curr->ref) + visit(curr->ref) +
750+
visit(curr->index) + visit(curr->value);
751+
}
748752
CostType visitArrayLen(ArrayLen* curr) {
749753
return 1 + nullCheckCost(curr->ref) + visit(curr->ref);
750754
}

src/ir/effects.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,15 @@ class EffectAnalyzer {
979979
// traps when the arg is null or the index out of bounds
980980
parent.implicitTrap = true;
981981
}
982+
void visitArrayStore(ArrayStore* curr) {
983+
if (curr->ref->type.isNull()) {
984+
parent.trap = true;
985+
return;
986+
}
987+
parent.writesArray = true;
988+
// traps when the arg is null or the index out of bounds
989+
parent.implicitTrap = true;
990+
}
982991
void visitArrayLen(ArrayLen* curr) {
983992
if (curr->ref->type.isNull()) {
984993
parent.trap = true;

src/ir/possible-contents.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,13 @@ struct InfoCollector
10951095
addChildParentLink(curr->ref, curr);
10961096
addChildParentLink(curr->value, curr);
10971097
}
1098+
void visitArrayStore(ArrayStore* curr) {
1099+
if (curr->ref->type == Type::unreachable) {
1100+
return;
1101+
}
1102+
addChildParentLink(curr->ref, curr);
1103+
addChildParentLink(curr->value, curr);
1104+
}
10981105

10991106
void visitArrayLen(ArrayLen* curr) {
11001107
// TODO: optimize when possible (perhaps we can infer a Literal for the
@@ -1732,6 +1739,7 @@ void TNHOracle::scan(Function* func,
17321739
}
17331740
void visitArrayGet(ArrayGet* curr) { notePossibleTrap(curr->ref); }
17341741
void visitArraySet(ArraySet* curr) { notePossibleTrap(curr->ref); }
1742+
void visitArrayStore(ArrayStore* curr) { notePossibleTrap(curr->ref); }
17351743
void visitArrayLen(ArrayLen* curr) { notePossibleTrap(curr->ref); }
17361744
void visitArrayCopy(ArrayCopy* curr) {
17371745
notePossibleTrap(curr->srcRef);

src/ir/subtype-exprs.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,13 @@ struct SubtypingDiscoverer : public OverriddenVisitor<SubType> {
406406
auto array = curr->ref->type.getHeapType().getArray();
407407
self()->noteSubtype(curr->value, array.element.type);
408408
}
409+
void visitArrayStore(ArrayStore* curr) {
410+
if (!curr->ref->type.isArray()) {
411+
return;
412+
}
413+
auto array = curr->ref->type.getHeapType().getArray();
414+
self()->noteSubtype(curr->value, array.element.type);
415+
}
409416
void visitArrayLen(ArrayLen* curr) {}
410417
void visitArrayCopy(ArrayCopy* curr) {
411418
if (!curr->srcRef->type.isArray() || !curr->destRef->type.isArray()) {

src/parser/contexts.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,14 @@ struct NullInstrParserCtx {
571571
MemoryOrder) {
572572
return Ok{};
573573
}
574+
template<typename HeapTypeT>
575+
Result<> makeArrayStore(Index,
576+
const std::vector<Annotation>&,
577+
Type,
578+
int,
579+
HeapTypeT) {
580+
return Ok{};
581+
}
574582
Result<> makeAtomicRMW(Index,
575583
const std::vector<Annotation>&,
576584
AtomicRMWOp,
@@ -2302,6 +2310,14 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx>, AnnotationParserCtx {
23022310
pos, irBuilder.makeStore(bytes, memarg.offset, memarg.align, type, *m));
23032311
}
23042312

2313+
Result<> makeArrayStore(Index pos,
2314+
const std::vector<Annotation>& annotations,
2315+
Type type,
2316+
int bytes,
2317+
HeapTypeT arrayType) {
2318+
return withLoc(pos, irBuilder.makeArrayStore(arrayType, bytes, type));
2319+
}
2320+
23052321
Result<> makeAtomicRMW(Index pos,
23062322
const std::vector<Annotation>& annotations,
23072323
AtomicRMWOp op,

src/parser/parsers.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1786,6 +1786,18 @@ Result<> makeStore(Ctx& ctx,
17861786
Type type,
17871787
int bytes,
17881788
bool isAtomic) {
1789+
if (ctx.in.takeSExprStart("type"sv)) {
1790+
std::optional<typename Ctx::HeapTypeT> arrayType;
1791+
auto x = typeidx(ctx);
1792+
CHECK_ERR(x);
1793+
1794+
if (!ctx.in.takeRParen()) {
1795+
return ctx.in.err("expected end of type use");
1796+
}
1797+
1798+
arrayType = *x;
1799+
return ctx.makeArrayStore(pos, annotations, type, bytes, *arrayType);
1800+
}
17891801
auto mem = maybeMemidx(ctx);
17901802
CHECK_ERR(mem);
17911803

0 commit comments

Comments
 (0)