Skip to content

Commit daf0782

Browse files
authored
Implement v128.{load,store}{8,16,32,64}_lane instructions (#3278)
These instructions are proposed in WebAssembly/simd#350. This PR implements them throughout Binaryen except in the C/JS APIs and in the fuzzer, where it leaves TODOs instead. Right now these instructions are just being implemented for prototyping so adding them to the APIs isn't critical and they aren't generally available to be fuzzed in Wasm engines.
1 parent a2fa37e commit daf0782

31 files changed

Lines changed: 1083 additions & 177 deletions

scripts/gen-s-parser.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,14 @@
350350
("v128.xor", "makeBinary(s, BinaryOp::XorVec128)"),
351351
("v128.andnot", "makeBinary(s, BinaryOp::AndNotVec128)"),
352352
("v128.bitselect", "makeSIMDTernary(s, SIMDTernaryOp::Bitselect)"),
353+
("v128.load8_lane", "makeSIMDLoadStoreLane(s, LoadLaneVec8x16)"),
354+
("v128.load16_lane", "makeSIMDLoadStoreLane(s, LoadLaneVec16x8)"),
355+
("v128.load32_lane", "makeSIMDLoadStoreLane(s, LoadLaneVec32x4)"),
356+
("v128.load64_lane", "makeSIMDLoadStoreLane(s, LoadLaneVec64x2)"),
357+
("v128.store8_lane", "makeSIMDLoadStoreLane(s, StoreLaneVec8x16)"),
358+
("v128.store16_lane", "makeSIMDLoadStoreLane(s, StoreLaneVec16x8)"),
359+
("v128.store32_lane", "makeSIMDLoadStoreLane(s, StoreLaneVec32x4)"),
360+
("v128.store64_lane", "makeSIMDLoadStoreLane(s, StoreLaneVec64x2)"),
353361
("i8x16.abs", "makeUnary(s, UnaryOp::AbsVecI8x16)"),
354362
("i8x16.neg", "makeUnary(s, UnaryOp::NegVecI8x16)"),
355363
("i8x16.any_true", "makeUnary(s, UnaryOp::AnyTrueVecI8x16)"),

src/binaryen-c.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ BINARYEN_API BinaryenExpressionId BinaryenSIMDShuffleId(void);
159159
BINARYEN_API BinaryenExpressionId BinaryenSIMDTernaryId(void);
160160
BINARYEN_API BinaryenExpressionId BinaryenSIMDShiftId(void);
161161
BINARYEN_API BinaryenExpressionId BinaryenSIMDLoadId(void);
162+
// TODO: Expose SIMDLoadStoreLane in C and JS APIs
162163
BINARYEN_API BinaryenExpressionId BinaryenMemoryInitId(void);
163164
BINARYEN_API BinaryenExpressionId BinaryenDataDropId(void);
164165
BINARYEN_API BinaryenExpressionId BinaryenMemoryCopyId(void);

src/gen-s-parser.inc

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2776,11 +2776,33 @@ switch (op[0]) {
27762776
case '\0':
27772777
if (strcmp(op, "v128.load") == 0) { return makeLoad(s, Type::v128, /*isAtomic=*/false); }
27782778
goto parse_error;
2779-
case '3':
2780-
if (strcmp(op, "v128.load32_zero") == 0) { return makeSIMDLoad(s, SIMDLoadOp::Load32Zero); }
2779+
case '1':
2780+
if (strcmp(op, "v128.load16_lane") == 0) { return makeSIMDLoadStoreLane(s, LoadLaneVec16x8); }
27812781
goto parse_error;
2782-
case '6':
2783-
if (strcmp(op, "v128.load64_zero") == 0) { return makeSIMDLoad(s, SIMDLoadOp::Load64Zero); }
2782+
case '3': {
2783+
switch (op[12]) {
2784+
case 'l':
2785+
if (strcmp(op, "v128.load32_lane") == 0) { return makeSIMDLoadStoreLane(s, LoadLaneVec32x4); }
2786+
goto parse_error;
2787+
case 'z':
2788+
if (strcmp(op, "v128.load32_zero") == 0) { return makeSIMDLoad(s, SIMDLoadOp::Load32Zero); }
2789+
goto parse_error;
2790+
default: goto parse_error;
2791+
}
2792+
}
2793+
case '6': {
2794+
switch (op[12]) {
2795+
case 'l':
2796+
if (strcmp(op, "v128.load64_lane") == 0) { return makeSIMDLoadStoreLane(s, LoadLaneVec64x2); }
2797+
goto parse_error;
2798+
case 'z':
2799+
if (strcmp(op, "v128.load64_zero") == 0) { return makeSIMDLoad(s, SIMDLoadOp::Load64Zero); }
2800+
goto parse_error;
2801+
default: goto parse_error;
2802+
}
2803+
}
2804+
case '8':
2805+
if (strcmp(op, "v128.load8_lane") == 0) { return makeSIMDLoadStoreLane(s, LoadLaneVec8x16); }
27842806
goto parse_error;
27852807
default: goto parse_error;
27862808
}
@@ -2791,9 +2813,26 @@ switch (op[0]) {
27912813
case 'o':
27922814
if (strcmp(op, "v128.or") == 0) { return makeBinary(s, BinaryOp::OrVec128); }
27932815
goto parse_error;
2794-
case 's':
2795-
if (strcmp(op, "v128.store") == 0) { return makeStore(s, Type::v128, /*isAtomic=*/false); }
2796-
goto parse_error;
2816+
case 's': {
2817+
switch (op[10]) {
2818+
case '\0':
2819+
if (strcmp(op, "v128.store") == 0) { return makeStore(s, Type::v128, /*isAtomic=*/false); }
2820+
goto parse_error;
2821+
case '1':
2822+
if (strcmp(op, "v128.store16_lane") == 0) { return makeSIMDLoadStoreLane(s, StoreLaneVec16x8); }
2823+
goto parse_error;
2824+
case '3':
2825+
if (strcmp(op, "v128.store32_lane") == 0) { return makeSIMDLoadStoreLane(s, StoreLaneVec32x4); }
2826+
goto parse_error;
2827+
case '6':
2828+
if (strcmp(op, "v128.store64_lane") == 0) { return makeSIMDLoadStoreLane(s, StoreLaneVec64x2); }
2829+
goto parse_error;
2830+
case '8':
2831+
if (strcmp(op, "v128.store8_lane") == 0) { return makeSIMDLoadStoreLane(s, StoreLaneVec8x16); }
2832+
goto parse_error;
2833+
default: goto parse_error;
2834+
}
2835+
}
27972836
case 'x':
27982837
if (strcmp(op, "v128.xor") == 0) { return makeBinary(s, BinaryOp::XorVec128); }
27992838
goto parse_error;

src/ir/ExpressionAnalyzer.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,12 @@ template<typename T> void visitImmediates(Expression* curr, T& visitor) {
203203
visitor.visitAddress(curr->offset);
204204
visitor.visitAddress(curr->align);
205205
}
206+
void visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
207+
visitor.visitInt(curr->op);
208+
visitor.visitAddress(curr->offset);
209+
visitor.visitAddress(curr->align);
210+
visitor.visitInt(curr->index);
211+
}
206212
void visitMemoryInit(MemoryInit* curr) {
207213
visitor.visitIndex(curr->segment);
208214
}

src/ir/ExpressionManipulator.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,14 @@ flexibleCopy(Expression* original, Module& wasm, CustomCopier custom) {
182182
return builder.makeSIMDLoad(
183183
curr->op, curr->offset, curr->align, copy(curr->ptr));
184184
}
185+
Expression* visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
186+
return builder.makeSIMDLoadStoreLane(curr->op,
187+
curr->offset,
188+
curr->align,
189+
curr->index,
190+
copy(curr->ptr),
191+
copy(curr->vec));
192+
}
185193
Expression* visitConst(Const* curr) {
186194
return builder.makeConst(curr->value);
187195
}

src/ir/ReFinalize.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ void ReFinalize::visitSIMDShuffle(SIMDShuffle* curr) { curr->finalize(); }
109109
void ReFinalize::visitSIMDTernary(SIMDTernary* curr) { curr->finalize(); }
110110
void ReFinalize::visitSIMDShift(SIMDShift* curr) { curr->finalize(); }
111111
void ReFinalize::visitSIMDLoad(SIMDLoad* curr) { curr->finalize(); }
112+
void ReFinalize::visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
113+
curr->finalize();
114+
}
112115
void ReFinalize::visitMemoryInit(MemoryInit* curr) { curr->finalize(); }
113116
void ReFinalize::visitDataDrop(DataDrop* curr) { curr->finalize(); }
114117
void ReFinalize::visitMemoryCopy(MemoryCopy* curr) { curr->finalize(); }

src/ir/effects.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,16 @@ struct EffectAnalyzer
385385
implicitTrap = true;
386386
}
387387
}
388+
void visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
389+
if (curr->isLoad()) {
390+
readsMemory = true;
391+
} else {
392+
writesMemory = true;
393+
}
394+
if (!ignoreImplicitTraps) {
395+
implicitTrap = true;
396+
}
397+
}
388398
void visitMemoryInit(MemoryInit* curr) {
389399
writesMemory = true;
390400
if (!ignoreImplicitTraps) {

src/ir/utils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ struct ReFinalize
135135
void visitSIMDTernary(SIMDTernary* curr);
136136
void visitSIMDShift(SIMDShift* curr);
137137
void visitSIMDLoad(SIMDLoad* curr);
138+
void visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr);
138139
void visitMemoryInit(MemoryInit* curr);
139140
void visitDataDrop(DataDrop* curr);
140141
void visitMemoryCopy(MemoryCopy* curr);
@@ -219,6 +220,7 @@ struct ReFinalizeNode : public OverriddenVisitor<ReFinalizeNode> {
219220
void visitSIMDTernary(SIMDTernary* curr) { curr->finalize(); }
220221
void visitSIMDShift(SIMDShift* curr) { curr->finalize(); }
221222
void visitSIMDLoad(SIMDLoad* curr) { curr->finalize(); }
223+
void visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) { curr->finalize(); }
222224
void visitMemoryInit(MemoryInit* curr) { curr->finalize(); }
223225
void visitDataDrop(DataDrop* curr) { curr->finalize(); }
224226
void visitMemoryCopy(MemoryCopy* curr) { curr->finalize(); }

src/passes/DeadCodeElimination.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,8 @@ struct DeadCodeElimination
345345
DELEGATE(SIMDShift);
346346
case Expression::Id::SIMDLoadId:
347347
DELEGATE(SIMDLoad);
348+
case Expression::Id::SIMDLoadStoreLaneId:
349+
DELEGATE(SIMDLoadStoreLane);
348350
case Expression::Id::MemoryInitId:
349351
DELEGATE(MemoryInit);
350352
case Expression::Id::DataDropId:

src/passes/Print.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,43 @@ struct PrintExpressionContents
499499
o << " align=" << curr->align;
500500
}
501501
}
502+
void visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
503+
prepareColor(o);
504+
switch (curr->op) {
505+
case LoadLaneVec8x16:
506+
o << "v128.load8_lane";
507+
break;
508+
case LoadLaneVec16x8:
509+
o << "v128.load16_lane";
510+
break;
511+
case LoadLaneVec32x4:
512+
o << "v128.load32_lane";
513+
break;
514+
case LoadLaneVec64x2:
515+
o << "v128.load64_lane";
516+
break;
517+
case StoreLaneVec8x16:
518+
o << "v128.store8_lane";
519+
break;
520+
case StoreLaneVec16x8:
521+
o << "v128.store16_lane";
522+
break;
523+
case StoreLaneVec32x4:
524+
o << "v128.store32_lane";
525+
break;
526+
case StoreLaneVec64x2:
527+
o << "v128.store64_lane";
528+
break;
529+
}
530+
restoreNormalColor(o);
531+
if (curr->offset) {
532+
o << " offset=" << curr->offset;
533+
}
534+
if (curr->align != curr->getMemBytes()) {
535+
o << " align=" << curr->align;
536+
}
537+
o << " " << int(curr->index);
538+
}
502539
void visitMemoryInit(MemoryInit* curr) {
503540
prepareColor(o);
504541
o << "memory.init " << curr->segment;
@@ -1908,6 +1945,14 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> {
19081945
printFullLine(curr->ptr);
19091946
decIndent();
19101947
}
1948+
void visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
1949+
o << '(';
1950+
PrintExpressionContents(currFunction, o).visit(curr);
1951+
incIndent();
1952+
printFullLine(curr->ptr);
1953+
printFullLine(curr->vec);
1954+
decIndent();
1955+
}
19111956
void visitMemoryInit(MemoryInit* curr) {
19121957
o << '(';
19131958
PrintExpressionContents(currFunction, o).visit(curr);

0 commit comments

Comments
 (0)