diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binaryen-c.cpp | 62 | ||||
-rw-r--r-- | src/binaryen-c.h | 16 | ||||
-rw-r--r-- | src/gen-s-parser.inc | 74 | ||||
-rw-r--r-- | src/ir/ExpressionAnalyzer.cpp | 5 | ||||
-rw-r--r-- | src/ir/ExpressionManipulator.cpp | 4 | ||||
-rw-r--r-- | src/ir/ReFinalize.cpp | 1 | ||||
-rw-r--r-- | src/ir/effects.h | 6 | ||||
-rw-r--r-- | src/ir/utils.h | 2 | ||||
-rw-r--r-- | src/js/binaryen.js-post.js | 51 | ||||
-rw-r--r-- | src/passes/DeadCodeElimination.cpp | 2 | ||||
-rw-r--r-- | src/passes/Print.cpp | 31 | ||||
-rw-r--r-- | src/tools/fuzzing.h | 27 | ||||
-rw-r--r-- | src/wasm-binary.h | 6 | ||||
-rw-r--r-- | src/wasm-builder.h | 10 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 34 | ||||
-rw-r--r-- | src/wasm-s-parser.h | 1 | ||||
-rw-r--r-- | src/wasm-stack.h | 12 | ||||
-rw-r--r-- | src/wasm-traversal.h | 17 | ||||
-rw-r--r-- | src/wasm.h | 22 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 61 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 28 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 20 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 15 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 24 | ||||
-rw-r--r-- | src/wasm2js.h | 4 |
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(); |