summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binaryen-c.cpp62
-rw-r--r--src/binaryen-c.h16
-rw-r--r--src/gen-s-parser.inc74
-rw-r--r--src/ir/ExpressionAnalyzer.cpp5
-rw-r--r--src/ir/ExpressionManipulator.cpp4
-rw-r--r--src/ir/ReFinalize.cpp1
-rw-r--r--src/ir/effects.h6
-rw-r--r--src/ir/utils.h2
-rw-r--r--src/js/binaryen.js-post.js51
-rw-r--r--src/passes/DeadCodeElimination.cpp2
-rw-r--r--src/passes/Print.cpp31
-rw-r--r--src/tools/fuzzing.h27
-rw-r--r--src/wasm-binary.h6
-rw-r--r--src/wasm-builder.h10
-rw-r--r--src/wasm-interpreter.h34
-rw-r--r--src/wasm-s-parser.h1
-rw-r--r--src/wasm-stack.h12
-rw-r--r--src/wasm-traversal.h17
-rw-r--r--src/wasm.h22
-rw-r--r--src/wasm/wasm-binary.cpp61
-rw-r--r--src/wasm/wasm-s-parser.cpp28
-rw-r--r--src/wasm/wasm-stack.cpp20
-rw-r--r--src/wasm/wasm-validator.cpp15
-rw-r--r--src/wasm/wasm.cpp24
-rw-r--r--src/wasm2js.h4
25 files changed, 479 insertions, 56 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index 0b2ff3b78..5a32737e4 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -349,6 +349,9 @@ BinaryenExpressionId BinaryenSIMDTernaryId(void) {
BinaryenExpressionId BinaryenSIMDShiftId(void) {
return Expression::Id::SIMDShiftId;
}
+BinaryenExpressionId BinaryenSIMDLoadId(void) {
+ return Expression::Id::SIMDLoadId;
+}
BinaryenExpressionId BinaryenMemoryInitId(void) {
return Expression::Id::MemoryInitId;
}
@@ -880,6 +883,10 @@ BinaryenOp BinaryenConvertSVecI64x2ToVecF64x2(void) {
BinaryenOp BinaryenConvertUVecI64x2ToVecF64x2(void) {
return ConvertUVecI64x2ToVecF64x2;
}
+BinaryenOp BinaryenLoadSplatVec8x16(void) { return LoadSplatVec8x16; }
+BinaryenOp BinaryenLoadSplatVec16x8(void) { return LoadSplatVec16x8; }
+BinaryenOp BinaryenLoadSplatVec32x4(void) { return LoadSplatVec32x4; }
+BinaryenOp BinaryenLoadSplatVec64x2(void) { return LoadSplatVec64x2; }
BinaryenOp BinaryenNarrowSVecI16x8ToVecI8x16(void) {
return NarrowSVecI16x8ToVecI8x16;
}
@@ -1599,6 +1606,20 @@ BinaryenExpressionRef BinaryenSIMDShift(BinaryenModuleRef module,
}
return static_cast<Expression*>(ret);
}
+BinaryenExpressionRef BinaryenSIMDLoad(BinaryenModuleRef module,
+ BinaryenOp op,
+ uint32_t offset,
+ uint32_t align,
+ BinaryenExpressionRef ptr) {
+ auto* ret =
+ Builder(*(Module*)module)
+ .makeSIMDLoad(
+ SIMDLoadOp(op), Address(offset), Address(align), (Expression*)ptr);
+ if (tracing) {
+ traceExpression(ret, "BinaryenSIMDLoad", op, offset, align, ptr);
+ }
+ return static_cast<Expression*>(ret);
+}
BinaryenExpressionRef BinaryenMemoryInit(BinaryenModuleRef module,
uint32_t segment,
BinaryenExpressionRef dest,
@@ -2767,6 +2788,47 @@ BinaryenExpressionRef BinaryenSIMDShiftGetShift(BinaryenExpressionRef expr) {
assert(expression->is<SIMDShift>());
return static_cast<SIMDShift*>(expression)->shift;
}
+// SIMDLoad
+BinaryenOp BinaryenSIMDLoadGetOp(BinaryenExpressionRef expr) {
+ if (tracing) {
+ std::cout << " BinaryenSIMDLoadGetOp(expressions[" << expressions[expr]
+ << "])\n";
+ }
+
+ auto* expression = (Expression*)expr;
+ assert(expression->is<SIMDLoad>());
+ return static_cast<SIMDLoad*>(expression)->op;
+}
+uint32_t BinaryenSIMDLoadGetOffset(BinaryenExpressionRef expr) {
+ if (tracing) {
+ std::cout << " BinaryenSIMDLoadGetOffset(expressions[" << expressions[expr]
+ << "])\n";
+ }
+
+ auto* expression = (Expression*)expr;
+ assert(expression->is<SIMDLoad>());
+ return static_cast<SIMDLoad*>(expression)->offset;
+}
+uint32_t BinaryenSIMDLoadGetAlign(BinaryenExpressionRef expr) {
+ if (tracing) {
+ std::cout << " BinaryenSIMDLoadGetAlign(expressions[" << expressions[expr]
+ << "])\n";
+ }
+
+ auto* expression = (Expression*)expr;
+ assert(expression->is<SIMDLoad>());
+ return static_cast<SIMDLoad*>(expression)->align;
+}
+BinaryenExpressionRef BinaryenSIMDLoadGetPtr(BinaryenExpressionRef expr) {
+ if (tracing) {
+ std::cout << " BinaryenSIMDLoadGetPtr(expressions[" << expressions[expr]
+ << "])\n";
+ }
+
+ auto* expression = (Expression*)expr;
+ assert(expression->is<SIMDLoad>());
+ return static_cast<SIMDLoad*>(expression)->ptr;
+}
// MemoryInit
uint32_t BinaryenMemoryInitGetSegment(BinaryenExpressionRef expr) {
if (tracing) {
diff --git a/src/binaryen-c.h b/src/binaryen-c.h
index 8667f7a6d..c4fbb9748 100644
--- a/src/binaryen-c.h
+++ b/src/binaryen-c.h
@@ -131,6 +131,7 @@ BINARYEN_API BinaryenExpressionId BinaryenSIMDReplaceId(void);
BINARYEN_API BinaryenExpressionId BinaryenSIMDShuffleId(void);
BINARYEN_API BinaryenExpressionId BinaryenSIMDTernaryId(void);
BINARYEN_API BinaryenExpressionId BinaryenSIMDShiftId(void);
+BINARYEN_API BinaryenExpressionId BinaryenSIMDLoadId(void);
BINARYEN_API BinaryenExpressionId BinaryenMemoryInitId(void);
BINARYEN_API BinaryenExpressionId BinaryenDataDropId(void);
BINARYEN_API BinaryenExpressionId BinaryenMemoryCopyId(void);
@@ -522,6 +523,10 @@ BINARYEN_API BinaryenOp BinaryenConvertSVecI32x4ToVecF32x4(void);
BINARYEN_API BinaryenOp BinaryenConvertUVecI32x4ToVecF32x4(void);
BINARYEN_API BinaryenOp BinaryenConvertSVecI64x2ToVecF64x2(void);
BINARYEN_API BinaryenOp BinaryenConvertUVecI64x2ToVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenLoadSplatVec8x16(void);
+BINARYEN_API BinaryenOp BinaryenLoadSplatVec16x8(void);
+BINARYEN_API BinaryenOp BinaryenLoadSplatVec32x4(void);
+BINARYEN_API BinaryenOp BinaryenLoadSplatVec64x2(void);
BINARYEN_API BinaryenOp BinaryenNarrowSVecI16x8ToVecI8x16(void);
BINARYEN_API BinaryenOp BinaryenNarrowUVecI16x8ToVecI8x16(void);
BINARYEN_API BinaryenOp BinaryenNarrowSVecI32x4ToVecI16x8(void);
@@ -736,6 +741,11 @@ BinaryenSIMDShift(BinaryenModuleRef module,
BinaryenOp op,
BinaryenExpressionRef vec,
BinaryenExpressionRef shift);
+BINARYEN_API BinaryenExpressionRef BinaryenSIMDLoad(BinaryenModuleRef module,
+ BinaryenOp op,
+ uint32_t offset,
+ uint32_t align,
+ BinaryenExpressionRef ptr);
BINARYEN_API BinaryenExpressionRef
BinaryenMemoryInit(BinaryenModuleRef module,
uint32_t segment,
@@ -962,6 +972,12 @@ BinaryenSIMDShiftGetVec(BinaryenExpressionRef expr);
BINARYEN_API BinaryenExpressionRef
BinaryenSIMDShiftGetShift(BinaryenExpressionRef expr);
+BINARYEN_API BinaryenOp BinaryenSIMDLoadGetOp(BinaryenExpressionRef expr);
+BINARYEN_API uint32_t BinaryenSIMDLoadGetOffset(BinaryenExpressionRef expr);
+BINARYEN_API uint32_t BinaryenSIMDLoadGetAlign(BinaryenExpressionRef expr);
+BINARYEN_API BinaryenExpressionRef
+BinaryenSIMDLoadGetPtr(BinaryenExpressionRef expr);
+
BINARYEN_API uint32_t BinaryenMemoryInitGetSegment(BinaryenExpressionRef expr);
BINARYEN_API BinaryenExpressionRef
BinaryenMemoryInitGetDest(BinaryenExpressionRef expr);
diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc
index adfeb061d..b1bd5c016 100644
--- a/src/gen-s-parser.inc
+++ b/src/gen-s-parser.inc
@@ -2418,40 +2418,62 @@ switch (op[0]) {
case 'v': {
switch (op[1]) {
case '1': {
- switch (op[5]) {
- case 'a':
- if (strcmp(op, "v128.and") == 0) { return makeBinary(s, BinaryOp::AndVec128); }
- goto parse_error;
- case 'b':
- if (strcmp(op, "v128.bitselect") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::Bitselect); }
- goto parse_error;
- case 'c':
- if (strcmp(op, "v128.const") == 0) { return makeConst(s, v128); }
+ switch (op[2]) {
+ case '2': {
+ switch (op[5]) {
+ case 'a':
+ if (strcmp(op, "v128.and") == 0) { return makeBinary(s, BinaryOp::AndVec128); }
+ goto parse_error;
+ case 'b':
+ if (strcmp(op, "v128.bitselect") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::Bitselect); }
+ goto parse_error;
+ case 'c':
+ if (strcmp(op, "v128.const") == 0) { return makeConst(s, v128); }
+ goto parse_error;
+ case 'l':
+ if (strcmp(op, "v128.load") == 0) { return makeLoad(s, v128, /*isAtomic=*/false); }
+ goto parse_error;
+ case 'n':
+ if (strcmp(op, "v128.not") == 0) { return makeUnary(s, UnaryOp::NotVec128); }
+ goto parse_error;
+ case 'o':
+ if (strcmp(op, "v128.or") == 0) { return makeBinary(s, BinaryOp::OrVec128); }
+ goto parse_error;
+ case 'p':
+ if (strcmp(op, "v128.pop") == 0) { return makePop(v128); }
+ goto parse_error;
+ case 's':
+ if (strcmp(op, "v128.store") == 0) { return makeStore(s, v128, /*isAtomic=*/false); }
+ goto parse_error;
+ case 'x':
+ if (strcmp(op, "v128.xor") == 0) { return makeBinary(s, BinaryOp::XorVec128); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ case '6':
+ if (strcmp(op, "v16x8.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec16x8); }
goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ case '3':
+ if (strcmp(op, "v32x4.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec32x4); }
+ goto parse_error;
+ case '6':
+ if (strcmp(op, "v64x2.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec64x2); }
+ goto parse_error;
+ case '8': {
+ switch (op[6]) {
case 'l':
- if (strcmp(op, "v128.load") == 0) { return makeLoad(s, v128, /*isAtomic=*/false); }
- goto parse_error;
- case 'n':
- if (strcmp(op, "v128.not") == 0) { return makeUnary(s, UnaryOp::NotVec128); }
- goto parse_error;
- case 'o':
- if (strcmp(op, "v128.or") == 0) { return makeBinary(s, BinaryOp::OrVec128); }
- goto parse_error;
- case 'p':
- if (strcmp(op, "v128.pop") == 0) { return makePop(v128); }
+ if (strcmp(op, "v8x16.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec8x16); }
goto parse_error;
case 's':
- if (strcmp(op, "v128.store") == 0) { return makeStore(s, v128, /*isAtomic=*/false); }
- goto parse_error;
- case 'x':
- if (strcmp(op, "v128.xor") == 0) { return makeBinary(s, BinaryOp::XorVec128); }
+ if (strcmp(op, "v8x16.shuffle") == 0) { return makeSIMDShuffle(s); }
goto parse_error;
default: goto parse_error;
}
}
- case '8':
- if (strcmp(op, "v8x16.shuffle") == 0) { return makeSIMDShuffle(s); }
- goto parse_error;
default: goto parse_error;
}
}
diff --git a/src/ir/ExpressionAnalyzer.cpp b/src/ir/ExpressionAnalyzer.cpp
index ee3cb0123..f7b7b636e 100644
--- a/src/ir/ExpressionAnalyzer.cpp
+++ b/src/ir/ExpressionAnalyzer.cpp
@@ -196,6 +196,11 @@ template<typename T> void visitImmediates(Expression* curr, T& visitor) {
}
void visitSIMDTernary(SIMDTernary* curr) { visitor.visitInt(curr->op); }
void visitSIMDShift(SIMDShift* curr) { visitor.visitInt(curr->op); }
+ void visitSIMDLoad(SIMDLoad* curr) {
+ visitor.visitInt(curr->op);
+ visitor.visitAddress(curr->offset);
+ visitor.visitAddress(curr->align);
+ }
void visitMemoryInit(MemoryInit* curr) {
visitor.visitIndex(curr->segment);
}
diff --git a/src/ir/ExpressionManipulator.cpp b/src/ir/ExpressionManipulator.cpp
index 7c4de4ceb..fdefbb2e0 100644
--- a/src/ir/ExpressionManipulator.cpp
+++ b/src/ir/ExpressionManipulator.cpp
@@ -179,6 +179,10 @@ flexibleCopy(Expression* original, Module& wasm, CustomCopier custom) {
return builder.makeSIMDShift(
curr->op, copy(curr->vec), copy(curr->shift));
}
+ Expression* visitSIMDLoad(SIMDLoad* curr) {
+ return builder.makeSIMDLoad(
+ curr->op, curr->offset, curr->align, copy(curr->ptr));
+ }
Expression* visitConst(Const* curr) {
return builder.makeConst(curr->value);
}
diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp
index 6c4e7a447..b27b49bd4 100644
--- a/src/ir/ReFinalize.cpp
+++ b/src/ir/ReFinalize.cpp
@@ -147,6 +147,7 @@ void ReFinalize::visitSIMDReplace(SIMDReplace* curr) { curr->finalize(); }
void ReFinalize::visitSIMDShuffle(SIMDShuffle* curr) { curr->finalize(); }
void ReFinalize::visitSIMDTernary(SIMDTernary* curr) { curr->finalize(); }
void ReFinalize::visitSIMDShift(SIMDShift* curr) { curr->finalize(); }
+void ReFinalize::visitSIMDLoad(SIMDLoad* curr) { curr->finalize(); }
void ReFinalize::visitMemoryInit(MemoryInit* curr) { curr->finalize(); }
void ReFinalize::visitDataDrop(DataDrop* curr) { curr->finalize(); }
void ReFinalize::visitMemoryCopy(MemoryCopy* curr) { curr->finalize(); }
diff --git a/src/ir/effects.h b/src/ir/effects.h
index dcee4404b..e93c63017 100644
--- a/src/ir/effects.h
+++ b/src/ir/effects.h
@@ -307,6 +307,12 @@ struct EffectAnalyzer
void visitSIMDShuffle(SIMDShuffle* curr) {}
void visitSIMDTernary(SIMDTernary* curr) {}
void visitSIMDShift(SIMDShift* curr) {}
+ void visitSIMDLoad(SIMDLoad* curr) {
+ readsMemory = true;
+ if (!ignoreImplicitTraps) {
+ implicitTrap = true;
+ }
+ }
void visitMemoryInit(MemoryInit* curr) {
writesMemory = true;
if (!ignoreImplicitTraps) {
diff --git a/src/ir/utils.h b/src/ir/utils.h
index 4ca80caa3..ca8803741 100644
--- a/src/ir/utils.h
+++ b/src/ir/utils.h
@@ -134,6 +134,7 @@ struct ReFinalize
void visitSIMDShuffle(SIMDShuffle* curr);
void visitSIMDTernary(SIMDTernary* curr);
void visitSIMDShift(SIMDShift* curr);
+ void visitSIMDLoad(SIMDLoad* curr);
void visitMemoryInit(MemoryInit* curr);
void visitDataDrop(DataDrop* curr);
void visitMemoryCopy(MemoryCopy* curr);
@@ -198,6 +199,7 @@ struct ReFinalizeNode : public OverriddenVisitor<ReFinalizeNode> {
void visitSIMDShuffle(SIMDShuffle* curr) { curr->finalize(); }
void visitSIMDTernary(SIMDTernary* curr) { curr->finalize(); }
void visitSIMDShift(SIMDShift* curr) { curr->finalize(); }
+ void visitSIMDLoad(SIMDLoad* curr) { curr->finalize(); }
void visitMemoryInit(MemoryInit* curr) { curr->finalize(); }
void visitDataDrop(DataDrop* curr) { curr->finalize(); }
void visitMemoryCopy(MemoryCopy* curr) { curr->finalize(); }
diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js
index 3cf3e1197..c82aaaf6d 100644
--- a/src/js/binaryen.js-post.js
+++ b/src/js/binaryen.js-post.js
@@ -76,6 +76,7 @@ Module['SIMDReplaceId'] = Module['_BinaryenSIMDReplaceId']();
Module['SIMDShuffleId'] = Module['_BinaryenSIMDShuffleId']();
Module['SIMDTernaryId'] = Module['_BinaryenSIMDTernaryId']();
Module['SIMDShiftId'] = Module['_BinaryenSIMDShiftId']();
+Module['SIMDLoadId'] = Module['_BinaryenSIMDLoadId']();
Module['MemoryInitId'] = Module['_BinaryenMemoryInitId']();
Module['DataDropId'] = Module['_BinaryenDataDropId']();
Module['MemoryCopyId'] = Module['_BinaryenMemoryCopyId']();
@@ -394,6 +395,10 @@ Module['ConvertSVecI32x4ToVecF32x4'] = Module['_BinaryenConvertSVecI32x4ToVecF32
Module['ConvertUVecI32x4ToVecF32x4'] = Module['_BinaryenConvertUVecI32x4ToVecF32x4']();
Module['ConvertSVecI64x2ToVecF64x2'] = Module['_BinaryenConvertSVecI64x2ToVecF64x2']();
Module['ConvertUVecI64x2ToVecF64x2'] = Module['_BinaryenConvertUVecI64x2ToVecF64x2']();
+Module['LoadSplatVec8x16'] = Module['_BinaryenLoadSplatVec8x16']();
+Module['LoadSplatVec16x8'] = Module['_BinaryenLoadSplatVec16x8']();
+Module['LoadSplatVec32x4'] = Module['_BinaryenLoadSplatVec32x4']();
+Module['LoadSplatVec64x2'] = Module['_BinaryenLoadSplatVec64x2']();
Module['NarrowSVecI16x8ToVecI8x16'] = Module['_BinaryenNarrowSVecI16x8ToVecI8x16']();
Module['NarrowUVecI16x8ToVecI8x16'] = Module['_BinaryenNarrowUVecI16x8ToVecI8x16']();
Module['NarrowSVecI32x4ToVecI16x8'] = Module['_BinaryenNarrowSVecI32x4ToVecI16x8']();
@@ -1347,14 +1352,6 @@ function wrapModule(module, self) {
}
};
- self['v8x16'] = {
- 'shuffle': function(left, right, mask) {
- return preserveStack(function() {
- return Module['_BinaryenSIMDShuffle'](module, left, right, i8sToStack(mask));
- });
- },
- };
-
self['i8x16'] = {
'splat': function(value) {
return Module['_BinaryenUnary'](module, Module['SplatVecI8x16'], value);
@@ -1814,6 +1811,35 @@ function wrapModule(module, self) {
},
};
+ self['v8x16'] = {
+ 'shuffle': function(left, right, mask) {
+ return preserveStack(function() {
+ return Module['_BinaryenSIMDShuffle'](module, left, right, i8sToStack(mask));
+ });
+ },
+ 'load_splat': function(offset, align, ptr) {
+ return Module['_BinaryenSIMDLoad'](module, Module['LoadSplatVec8x16'], offset, align, ptr);
+ },
+ };
+
+ self['v16x8'] = {
+ 'load_splat': function(offset, align, ptr) {
+ return Module['_BinaryenSIMDLoad'](module, Module['LoadSplatVec16x8'], offset, align, ptr);
+ },
+ };
+
+ self['v32x4'] = {
+ 'load_splat': function(offset, align, ptr) {
+ return Module['_BinaryenSIMDLoad'](module, Module['LoadSplatVec32x4'], offset, align, ptr);
+ },
+ };
+
+ self['v64x2'] = {
+ 'load_splat': function(offset, align, ptr) {
+ return Module['_BinaryenSIMDLoad'](module, Module['LoadSplatVec64x2'], offset, align, ptr);
+ },
+ };
+
self['exnref'] = {
'pop': function() {
return Module['_BinaryenPop'](module, Module['exnref']);
@@ -2452,6 +2478,15 @@ Module['getExpressionInfo'] = function(expr) {
'vec': Module['_BinaryenSIMDShiftGetVec'](expr),
'shift': Module['_BinaryenSIMDShiftGetShift'](expr)
};
+ case Module['SIMDLoadId']:
+ return {
+ 'id': id,
+ 'type': type,
+ 'op': Module['_BinaryenSIMDLoadGetOp'](expr),
+ 'offset': Module['_BinaryenSIMDLoadGetOffset'](expr),
+ 'align': Module['_BinaryenSIMDLoadGetAlign'](expr),
+ 'ptr': Module['_BinaryenSIMDLoadGetPtr'](expr)
+ };
case Module['MemoryInitId']:
return {
'id': id,
diff --git a/src/passes/DeadCodeElimination.cpp b/src/passes/DeadCodeElimination.cpp
index 1d13ed67c..5f562f7ba 100644
--- a/src/passes/DeadCodeElimination.cpp
+++ b/src/passes/DeadCodeElimination.cpp
@@ -310,6 +310,8 @@ struct DeadCodeElimination
DELEGATE(SIMDTernary);
case Expression::Id::SIMDShiftId:
DELEGATE(SIMDShift);
+ case Expression::Id::SIMDLoadId:
+ DELEGATE(SIMDLoad);
case Expression::Id::MemoryInitId:
DELEGATE(MemoryInit);
case Expression::Id::DataDropId:
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index f8f5c1a56..afdb12444 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -391,6 +391,30 @@ struct PrintExpressionContents
break;
}
}
+ void visitSIMDLoad(SIMDLoad* curr) {
+ prepareColor(o);
+ switch (curr->op) {
+ case LoadSplatVec8x16:
+ o << "v8x16.load_splat";
+ break;
+ case LoadSplatVec16x8:
+ o << "v16x8.load_splat";
+ break;
+ case LoadSplatVec32x4:
+ o << "v32x4.load_splat";
+ break;
+ case LoadSplatVec64x2:
+ o << "v64x2.load_splat";
+ break;
+ }
+ restoreNormalColor(o);
+ if (curr->offset) {
+ o << " offset=" << curr->offset;
+ }
+ if (curr->align != curr->getMemBytes()) {
+ o << " align=" << curr->align;
+ }
+ }
void visitMemoryInit(MemoryInit* curr) {
prepareColor(o);
o << "memory.init " << curr->segment;
@@ -1604,6 +1628,13 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> {
printFullLine(curr->shift);
decIndent();
}
+ void visitSIMDLoad(SIMDLoad* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ incIndent();
+ printFullLine(curr->ptr);
+ decIndent();
+ }
void visitMemoryInit(MemoryInit* curr) {
o << '(';
PrintExpressionContents(currFunction, o).visit(curr);
diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h
index bc2f54ecd..2f0c5d315 100644
--- a/src/tools/fuzzing.h
+++ b/src/tools/fuzzing.h
@@ -2338,7 +2338,7 @@ private:
if (type != v128) {
return makeSIMDExtract(type);
}
- switch (upTo(6)) {
+ switch (upTo(7)) {
case 0:
return makeUnary(v128);
case 1:
@@ -2351,6 +2351,8 @@ private:
return makeSIMDTernary();
case 5:
return makeSIMDShift();
+ case 6:
+ return makeSIMDLoad();
}
WASM_UNREACHABLE();
}
@@ -2488,6 +2490,29 @@ private:
return builder.makeSIMDShift(op, vec, shift);
}
+ Expression* makeSIMDLoad() {
+ SIMDLoadOp op = pick(
+ LoadSplatVec8x16, LoadSplatVec16x8, LoadSplatVec32x4, LoadSplatVec64x2);
+ Address offset = logify(get());
+ Address align;
+ switch (op) {
+ case LoadSplatVec8x16:
+ align = 1;
+ break;
+ case LoadSplatVec16x8:
+ align = pick(1, 2);
+ break;
+ case LoadSplatVec32x4:
+ align = pick(1, 2, 4);
+ break;
+ case LoadSplatVec64x2:
+ align = pick(1, 2, 4, 8);
+ break;
+ }
+ Expression* ptr = makePointer();
+ return builder.makeSIMDLoad(op, offset, align, ptr);
+ }
+
Expression* makeBulkMemory(Type type) {
if (!allowMemory) {
return makeTrivial(type);
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 02f21455e..3cbc1cc6b 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -856,6 +856,10 @@ enum ASTNodes {
F32x4ConvertUI32x4 = 0xb0,
F64x2ConvertSI64x2 = 0xb1,
F64x2ConvertUI64x2 = 0xb2,
+ V8x16LoadSplat = 0xc2,
+ V16x8LoadSplat = 0xc3,
+ V32x4LoadSplat = 0xc4,
+ V64x2LoadSplat = 0xc5,
I8x16NarrowSI16x8 = 0xc6,
I8x16NarrowUI16x8 = 0xc7,
I16x8NarrowSI32x4 = 0xc8,
@@ -1257,13 +1261,13 @@ public:
bool maybeVisitSIMDBinary(Expression*& out, uint32_t code);
bool maybeVisitSIMDUnary(Expression*& out, uint32_t code);
bool maybeVisitSIMDConst(Expression*& out, uint32_t code);
- bool maybeVisitSIMDLoad(Expression*& out, uint32_t code);
bool maybeVisitSIMDStore(Expression*& out, uint32_t code);
bool maybeVisitSIMDExtract(Expression*& out, uint32_t code);
bool maybeVisitSIMDReplace(Expression*& out, uint32_t code);
bool maybeVisitSIMDShuffle(Expression*& out, uint32_t code);
bool maybeVisitSIMDTernary(Expression*& out, uint32_t code);
bool maybeVisitSIMDShift(Expression*& out, uint32_t code);
+ bool maybeVisitSIMDLoad(Expression*& out, uint32_t code);
bool maybeVisitMemoryInit(Expression*& out, uint32_t code);
bool maybeVisitDataDrop(Expression*& out, uint32_t code);
bool maybeVisitMemoryCopy(Expression*& out, uint32_t code);
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index c2f1e41b6..d47ec413f 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -420,6 +420,16 @@ public:
ret->finalize();
return ret;
}
+ SIMDLoad*
+ makeSIMDLoad(SIMDLoadOp op, Address offset, Address align, Expression* ptr) {
+ auto* ret = allocator.alloc<SIMDLoad>();
+ ret->op = op;
+ ret->offset = offset;
+ ret->align = align;
+ ret->ptr = ptr;
+ ret->finalize();
+ return ret;
+ }
MemoryInit* makeMemoryInit(uint32_t segment,
Expression* dest,
Expression* offset,
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 95503fb09..a128cf6e5 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -1083,6 +1083,7 @@ public:
Flow visitAtomicCmpxchg(AtomicCmpxchg*) { WASM_UNREACHABLE(); }
Flow visitAtomicWait(AtomicWait*) { WASM_UNREACHABLE(); }
Flow visitAtomicNotify(AtomicNotify*) { WASM_UNREACHABLE(); }
+ Flow visitSIMDLoad(SIMDLoad*) { WASM_UNREACHABLE(); }
Flow visitPush(Push*) { WASM_UNREACHABLE(); }
Flow visitPop(Pop*) { WASM_UNREACHABLE(); }
Flow visitTry(Try*) { WASM_UNREACHABLE(); }
@@ -1697,6 +1698,39 @@ private:
// TODO: add threads support!
return Literal(int32_t(0)); // none woken up
}
+ Flow visitSIMDLoad(SIMDLoad* curr) {
+ NOTE_ENTER("SIMDLoad");
+ Load load;
+ load.type = i32;
+ load.bytes = curr->getMemBytes();
+ load.signed_ = false;
+ load.offset = curr->offset;
+ load.align = curr->align;
+ load.isAtomic = false;
+ load.ptr = curr->ptr;
+ Literal (Literal::*splat)() const = nullptr;
+ switch (curr->op) {
+ case LoadSplatVec8x16:
+ splat = &Literal::splatI8x16;
+ break;
+ case LoadSplatVec16x8:
+ splat = &Literal::splatI16x8;
+ break;
+ case LoadSplatVec32x4:
+ splat = &Literal::splatI32x4;
+ break;
+ case LoadSplatVec64x2:
+ load.type = i64;
+ splat = &Literal::splatI64x2;
+ break;
+ }
+ load.finalize();
+ Flow flow = this->visit(&load);
+ if (flow.breaking()) {
+ return flow;
+ }
+ return (flow.value.*splat)();
+ }
Flow visitHost(Host* curr) {
NOTE_ENTER("Host");
switch (curr->op) {
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index 67035f0ff..c7d43b581 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -200,6 +200,7 @@ private:
Expression* makeSIMDShuffle(Element& s);
Expression* makeSIMDTernary(Element& s, SIMDTernaryOp op);
Expression* makeSIMDShift(Element& s, SIMDShiftOp op);
+ Expression* makeSIMDLoad(Element& s, SIMDLoadOp op);
Expression* makeMemoryInit(Element& s);
Expression* makeDataDrop(Element& s);
Expression* makeMemoryCopy(Element& s);
diff --git a/src/wasm-stack.h b/src/wasm-stack.h
index 4b0ffde40..26105ccdc 100644
--- a/src/wasm-stack.h
+++ b/src/wasm-stack.h
@@ -109,6 +109,7 @@ public:
void visitSIMDShuffle(SIMDShuffle* curr);
void visitSIMDTernary(SIMDTernary* curr);
void visitSIMDShift(SIMDShift* curr);
+ void visitSIMDLoad(SIMDLoad* curr);
void visitMemoryInit(MemoryInit* curr);
void visitDataDrop(DataDrop* curr);
void visitMemoryCopy(MemoryCopy* curr);
@@ -185,6 +186,7 @@ public:
void visitSIMDShuffle(SIMDShuffle* curr);
void visitSIMDTernary(SIMDTernary* curr);
void visitSIMDShift(SIMDShift* curr);
+ void visitSIMDLoad(SIMDLoad* curr);
void visitMemoryInit(MemoryInit* curr);
void visitDataDrop(DataDrop* curr);
void visitMemoryCopy(MemoryCopy* curr);
@@ -588,6 +590,16 @@ void BinaryenIRWriter<SubType>::visitSIMDShift(SIMDShift* curr) {
}
template<typename SubType>
+void BinaryenIRWriter<SubType>::visitSIMDLoad(SIMDLoad* curr) {
+ visit(curr->ptr);
+ if (curr->type == unreachable) {
+ emitUnreachable();
+ return;
+ }
+ emit(curr);
+}
+
+template<typename SubType>
void BinaryenIRWriter<SubType>::visitMemoryInit(MemoryInit* curr) {
visit(curr->dest);
visit(curr->offset);
diff --git a/src/wasm-traversal.h b/src/wasm-traversal.h
index 06ab69615..8f4fb5922 100644
--- a/src/wasm-traversal.h
+++ b/src/wasm-traversal.h
@@ -60,6 +60,7 @@ template<typename SubType, typename ReturnType = void> struct Visitor {
ReturnType visitSIMDShuffle(SIMDShuffle* curr) { return ReturnType(); }
ReturnType visitSIMDTernary(SIMDTernary* curr) { return ReturnType(); }
ReturnType visitSIMDShift(SIMDShift* curr) { return ReturnType(); }
+ ReturnType visitSIMDLoad(SIMDLoad* curr) { return ReturnType(); }
ReturnType visitMemoryInit(MemoryInit* curr) { return ReturnType(); }
ReturnType visitDataDrop(DataDrop* curr) { return ReturnType(); }
ReturnType visitMemoryCopy(MemoryCopy* curr) { return ReturnType(); }
@@ -143,6 +144,8 @@ template<typename SubType, typename ReturnType = void> struct Visitor {
DELEGATE(SIMDTernary);
case Expression::Id::SIMDShiftId:
DELEGATE(SIMDShift);
+ case Expression::Id::SIMDLoadId:
+ DELEGATE(SIMDLoad);
case Expression::Id::MemoryInitId:
DELEGATE(MemoryInit);
case Expression::Id::DataDropId:
@@ -227,6 +230,7 @@ struct OverriddenVisitor {
UNIMPLEMENTED(SIMDShuffle);
UNIMPLEMENTED(SIMDTernary);
UNIMPLEMENTED(SIMDShift);
+ UNIMPLEMENTED(SIMDLoad);
UNIMPLEMENTED(MemoryInit);
UNIMPLEMENTED(DataDrop);
UNIMPLEMENTED(MemoryCopy);
@@ -311,6 +315,8 @@ struct OverriddenVisitor {
DELEGATE(SIMDTernary);
case Expression::Id::SIMDShiftId:
DELEGATE(SIMDShift);
+ case Expression::Id::SIMDLoadId:
+ DELEGATE(SIMDLoad);
case Expression::Id::MemoryInitId:
DELEGATE(MemoryInit);
case Expression::Id::DataDropId:
@@ -436,6 +442,9 @@ struct UnifiedExpressionVisitor : public Visitor<SubType, ReturnType> {
ReturnType visitSIMDShift(SIMDShift* curr) {
return static_cast<SubType*>(this)->visitExpression(curr);
}
+ ReturnType visitSIMDLoad(SIMDLoad* curr) {
+ return static_cast<SubType*>(this)->visitExpression(curr);
+ }
ReturnType visitMemoryInit(MemoryInit* curr) {
return static_cast<SubType*>(this)->visitExpression(curr);
}
@@ -738,6 +747,9 @@ struct Walker : public VisitorType {
static void doVisitSIMDShift(SubType* self, Expression** currp) {
self->visitSIMDShift((*currp)->cast<SIMDShift>());
}
+ static void doVisitSIMDLoad(SubType* self, Expression** currp) {
+ self->visitSIMDLoad((*currp)->cast<SIMDLoad>());
+ }
static void doVisitMemoryInit(SubType* self, Expression** currp) {
self->visitMemoryInit((*currp)->cast<MemoryInit>());
}
@@ -959,6 +971,11 @@ struct PostWalker : public Walker<SubType, VisitorType> {
self->pushTask(SubType::scan, &curr->cast<SIMDShift>()->vec);
break;
}
+ case Expression::Id::SIMDLoadId: {
+ self->pushTask(SubType::doVisitSIMDLoad, currp);
+ self->pushTask(SubType::scan, &curr->cast<SIMDLoad>()->ptr);
+ break;
+ }
case Expression::Id::MemoryInitId: {
self->pushTask(SubType::doVisitMemoryInit, currp);
self->pushTask(SubType::scan, &curr->cast<MemoryInit>()->size);
diff --git a/src/wasm.h b/src/wasm.h
index 2c057b7a4..735b24163 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -433,6 +433,13 @@ enum SIMDShiftOp {
ShrUVecI64x2
};
+enum SIMDLoadOp {
+ LoadSplatVec8x16,
+ LoadSplatVec16x8,
+ LoadSplatVec32x4,
+ LoadSplatVec64x2
+};
+
enum SIMDTernaryOp { Bitselect, QFMAF32x4, QFMSF32x4, QFMAF64x2, QFMSF64x2 };
//
@@ -492,6 +499,7 @@ public:
SIMDShuffleId,
SIMDTernaryId,
SIMDShiftId,
+ SIMDLoadId,
MemoryInitId,
DataDropId,
MemoryCopyId,
@@ -877,6 +885,20 @@ public:
void finalize();
};
+class SIMDLoad : public SpecificExpression<Expression::SIMDLoadId> {
+public:
+ SIMDLoad() = default;
+ SIMDLoad(MixedArena& allocator) {}
+
+ SIMDLoadOp op;
+ Address offset;
+ Address align;
+ Expression* ptr;
+
+ Index getMemBytes();
+ void finalize();
+};
+
class MemoryInit : public SpecificExpression<Expression::MemoryInitId> {
public:
MemoryInit() = default;
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 7b9d9c624..136301500 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -2340,9 +2340,6 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
if (maybeVisitSIMDConst(curr, opcode)) {
break;
}
- if (maybeVisitSIMDLoad(curr, opcode)) {
- break;
- }
if (maybeVisitSIMDStore(curr, opcode)) {
break;
}
@@ -2361,6 +2358,9 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
if (maybeVisitSIMDShift(curr, opcode)) {
break;
}
+ if (maybeVisitSIMDLoad(curr, opcode)) {
+ break;
+ }
throwError("invalid code after SIMD prefix: " + std::to_string(opcode));
break;
}
@@ -4158,21 +4158,6 @@ bool WasmBinaryBuilder::maybeVisitSIMDConst(Expression*& out, uint32_t code) {
return true;
}
-bool WasmBinaryBuilder::maybeVisitSIMDLoad(Expression*& out, uint32_t code) {
- if (code != BinaryConsts::V128Load) {
- return false;
- }
- auto* curr = allocator.alloc<Load>();
- curr->type = v128;
- curr->bytes = 16;
- readMemoryAccess(curr->align, curr->offset);
- curr->isAtomic = false;
- curr->ptr = popNonVoidExpression();
- curr->finalize();
- out = curr;
- return true;
-}
-
bool WasmBinaryBuilder::maybeVisitSIMDStore(Expression*& out, uint32_t code) {
if (code != BinaryConsts::V128Store) {
return false;
@@ -4394,6 +4379,46 @@ bool WasmBinaryBuilder::maybeVisitSIMDShift(Expression*& out, uint32_t code) {
return true;
}
+bool WasmBinaryBuilder::maybeVisitSIMDLoad(Expression*& out, uint32_t code) {
+ if (code == BinaryConsts::V128Load) {
+ auto* curr = allocator.alloc<Load>();
+ curr->type = v128;
+ curr->bytes = 16;
+ readMemoryAccess(curr->align, curr->offset);
+ curr->isAtomic = false;
+ curr->ptr = popNonVoidExpression();
+ curr->finalize();
+ out = curr;
+ return true;
+ }
+ SIMDLoad* curr;
+ switch (code) {
+ case BinaryConsts::V8x16LoadSplat:
+ curr = allocator.alloc<SIMDLoad>();
+ curr->op = LoadSplatVec8x16;
+ break;
+ case BinaryConsts::V16x8LoadSplat:
+ curr = allocator.alloc<SIMDLoad>();
+ curr->op = LoadSplatVec16x8;
+ break;
+ case BinaryConsts::V32x4LoadSplat:
+ curr = allocator.alloc<SIMDLoad>();
+ curr->op = LoadSplatVec32x4;
+ break;
+ case BinaryConsts::V64x2LoadSplat:
+ curr = allocator.alloc<SIMDLoad>();
+ curr->op = LoadSplatVec64x2;
+ break;
+ default:
+ return false;
+ }
+ readMemoryAccess(curr->align, curr->offset);
+ curr->ptr = popNonVoidExpression();
+ curr->finalize();
+ out = curr;
+ return true;
+}
+
void WasmBinaryBuilder::visitSelect(Select* curr) {
if (debug) {
std::cerr << "zz node: Select" << std::endl;
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 322c36c45..9f1fe0044 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -1251,10 +1251,10 @@ static uint8_t parseMemBytes(const char*& s, uint8_t fallback) {
static size_t parseMemAttributes(Element& s,
Address* offset,
Address* align,
- Address fallback) {
+ Address fallbackAlign) {
size_t i = 1;
*offset = 0;
- *align = fallback;
+ *align = fallbackAlign;
while (!s[i]->isList()) {
const char* str = s[i]->c_str();
const char* eq = strchr(str, '=');
@@ -1493,6 +1493,30 @@ Expression* SExpressionWasmBuilder::makeSIMDShift(Element& s, SIMDShiftOp op) {
return ret;
}
+Expression* SExpressionWasmBuilder::makeSIMDLoad(Element& s, SIMDLoadOp op) {
+ auto ret = allocator.alloc<SIMDLoad>();
+ ret->op = op;
+ Address defaultAlign;
+ switch (op) {
+ case LoadSplatVec8x16:
+ defaultAlign = 1;
+ break;
+ case LoadSplatVec16x8:
+ defaultAlign = 2;
+ break;
+ case LoadSplatVec32x4:
+ defaultAlign = 4;
+ break;
+ case LoadSplatVec64x2:
+ defaultAlign = 8;
+ break;
+ }
+ size_t i = parseMemAttributes(s, &ret->offset, &ret->align, defaultAlign);
+ ret->ptr = parseExpression(s[i]);
+ ret->finalize();
+ return ret;
+}
+
Expression* SExpressionWasmBuilder::makeMemoryInit(Element& s) {
auto ret = allocator.alloc<MemoryInit>();
ret->segment = atoi(s[1]->str().c_str());
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index 1da6e9015..c673a3fb0 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -554,6 +554,26 @@ void BinaryInstWriter::visitSIMDShift(SIMDShift* curr) {
}
}
+void BinaryInstWriter::visitSIMDLoad(SIMDLoad* curr) {
+ o << int8_t(BinaryConsts::SIMDPrefix);
+ switch (curr->op) {
+ case LoadSplatVec8x16:
+ o << U32LEB(BinaryConsts::V8x16LoadSplat);
+ break;
+ case LoadSplatVec16x8:
+ o << U32LEB(BinaryConsts::V16x8LoadSplat);
+ break;
+ case LoadSplatVec32x4:
+ o << U32LEB(BinaryConsts::V32x4LoadSplat);
+ break;
+ case LoadSplatVec64x2:
+ o << U32LEB(BinaryConsts::V64x2LoadSplat);
+ break;
+ }
+ assert(curr->align);
+ emitMemoryAccess(curr->align, /*(unused) bytes=*/0, curr->offset);
+}
+
void BinaryInstWriter::visitMemoryInit(MemoryInit* curr) {
o << int8_t(BinaryConsts::MiscPrefix);
o << U32LEB(BinaryConsts::MemoryInit);
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index e64e2ef73..68002e4d2 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -276,6 +276,7 @@ public:
void visitSIMDShuffle(SIMDShuffle* curr);
void visitSIMDTernary(SIMDTernary* curr);
void visitSIMDShift(SIMDShift* curr);
+ void visitSIMDLoad(SIMDLoad* curr);
void visitMemoryInit(MemoryInit* curr);
void visitDataDrop(DataDrop* curr);
void visitMemoryCopy(MemoryCopy* curr);
@@ -1054,6 +1055,20 @@ void FunctionValidator::visitSIMDShift(SIMDShift* curr) {
curr->shift->type, i32, curr, "expected shift amount to have type i32");
}
+void FunctionValidator::visitSIMDLoad(SIMDLoad* curr) {
+ shouldBeTrue(
+ getModule()->memory.exists, curr, "Memory operations require a memory");
+ shouldBeTrue(
+ getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->type, v128, curr, "load_splat must have type v128");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->ptr->type, i32, curr, "load_splat address must have type i32");
+ Type lane_t = curr->op == LoadSplatVec64x2 ? i64 : i32;
+ Index bytes = curr->getMemBytes();
+ validateAlignment(curr->align, lane_t, bytes, /*isAtomic=*/false, curr);
+}
+
void FunctionValidator::visitMemoryInit(MemoryInit* curr) {
shouldBeTrue(getModule()->features.hasBulkMemory(),
curr,
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index f8439ea96..58510cc8f 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -159,6 +159,8 @@ const char* getExpressionName(Expression* curr) {
return "simd_ternary";
case Expression::Id::SIMDShiftId:
return "simd_shift";
+ case Expression::Id::SIMDLoadId:
+ return "simd_load";
case Expression::Id::MemoryInitId:
return "memory_init";
case Expression::Id::DataDropId:
@@ -626,6 +628,28 @@ void SIMDShift::finalize() {
}
}
+void SIMDLoad::finalize() {
+ assert(ptr);
+ type = v128;
+ if (ptr->type == unreachable) {
+ type = unreachable;
+ }
+}
+
+Index SIMDLoad::getMemBytes() {
+ switch (op) {
+ case LoadSplatVec8x16:
+ return 1;
+ case LoadSplatVec16x8:
+ return 2;
+ case LoadSplatVec32x4:
+ return 4;
+ case LoadSplatVec64x2:
+ return 8;
+ }
+ WASM_UNREACHABLE();
+}
+
Const* Const::set(Literal value_) {
value = value_;
type = value.type;
diff --git a/src/wasm2js.h b/src/wasm2js.h
index 86af511fb..337ea3806 100644
--- a/src/wasm2js.h
+++ b/src/wasm2js.h
@@ -1841,6 +1841,10 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m,
unimplemented(curr);
WASM_UNREACHABLE();
}
+ Ref visitSIMDLoad(SIMDLoad* curr) {
+ unimplemented(curr);
+ WASM_UNREACHABLE();
+ }
Ref visitMemoryInit(MemoryInit* curr) {
unimplemented(curr);
WASM_UNREACHABLE();