diff --git a/scripts/gen-s-parser.py b/scripts/gen-s-parser.py index af29f402001..c65e5ddc45a 100755 --- a/scripts/gen-s-parser.py +++ b/scripts/gen-s-parser.py @@ -522,6 +522,8 @@ ("i32x4.trunc_sat_f64x2_zero_u", "makeUnary(s, UnaryOp::TruncSatZeroUVecF64x2ToVecI32x4)"), ("f32x4.demote_f64x2_zero", "makeUnary(s, UnaryOp::DemoteZeroVecF64x2ToVecF32x4)"), ("f64x2.promote_low_f32x4", "makeUnary(s, UnaryOp::PromoteLowVecF32x4ToVecF64x2)"), + ("i32x4.widen_i8x16_s", "makeSIMDWiden(s, SIMDWidenOp::WidenSVecI8x16ToVecI32x4)"), + ("i32x4.widen_i8x16_u", "makeSIMDWiden(s, SIMDWidenOp::WidenUVecI8x16ToVecI32x4)"), # prefetch instructions ("prefetch.t", "makePrefetch(s, PrefetchOp::PrefetchTemporal)"), diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 281a2cfcae5..4e5a61d9277 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -1832,6 +1832,17 @@ switch (op[0]) { default: goto parse_error; } } + case 'i': { + switch (op[18]) { + case 's': + if (strcmp(op, "i32x4.widen_i8x16_s") == 0) { return makeSIMDWiden(s, SIMDWidenOp::WidenSVecI8x16ToVecI32x4); } + goto parse_error; + case 'u': + if (strcmp(op, "i32x4.widen_i8x16_u") == 0) { return makeSIMDWiden(s, SIMDWidenOp::WidenUVecI8x16ToVecI32x4); } + goto parse_error; + default: goto parse_error; + } + } case 'l': { switch (op[22]) { case 's': diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp index 808b9d41ba3..de418459610 100644 --- a/src/ir/ReFinalize.cpp +++ b/src/ir/ReFinalize.cpp @@ -112,6 +112,7 @@ void ReFinalize::visitSIMDLoad(SIMDLoad* curr) { curr->finalize(); } void ReFinalize::visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) { curr->finalize(); } +void ReFinalize::visitSIMDWiden(SIMDWiden* curr) { curr->finalize(); } void ReFinalize::visitPrefetch(Prefetch* curr) { curr->finalize(); } void ReFinalize::visitMemoryInit(MemoryInit* curr) { curr->finalize(); } void ReFinalize::visitDataDrop(DataDrop* curr) { curr->finalize(); } diff --git a/src/ir/cost.h b/src/ir/cost.h index 212933ffbef..50941bdd3c5 100644 --- a/src/ir/cost.h +++ b/src/ir/cost.h @@ -540,6 +540,7 @@ struct CostAnalyzer : public OverriddenVisitor { Index visitSIMDShift(SIMDShift* curr) { return 1 + visit(curr->vec) + visit(curr->shift); } + Index visitSIMDWiden(SIMDWiden* curr) { return 1 + visit(curr->vec); } Index visitSIMDShuffle(SIMDShuffle* curr) { return 1 + visit(curr->left) + visit(curr->right); } diff --git a/src/ir/effects.h b/src/ir/effects.h index c7142dc3421..d52fcfb1578 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -430,6 +430,7 @@ class EffectAnalyzer { } parent.implicitTrap = true; } + void visitSIMDWiden(SIMDWiden* curr) {} void visitPrefetch(Prefetch* curr) { // Do not reorder with respect to other memory ops parent.writesMemory = true; diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 39c66cc57fe..74bd5598f9a 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -671,6 +671,19 @@ struct PrintExpressionContents } o << " " << int(curr->index); } + void visitSIMDWiden(SIMDWiden* curr) { + prepareColor(o); + switch (curr->op) { + case WidenSVecI8x16ToVecI32x4: + o << "i32x4.widen_i8x16_s "; + break; + case WidenUVecI8x16ToVecI32x4: + o << "i32x4.widen_i8x16_u "; + break; + } + restoreNormalColor(o); + o << int(curr->index); + } void visitPrefetch(Prefetch* curr) { prepareColor(o); switch (curr->op) { @@ -2303,6 +2316,13 @@ struct PrintSExpression : public OverriddenVisitor { printFullLine(curr->vec); decIndent(); } + void visitSIMDWiden(SIMDWiden* curr) { + o << '('; + PrintExpressionContents(currFunction, o).visit(curr); + incIndent(); + printFullLine(curr->vec); + decIndent(); + } void visitPrefetch(Prefetch* curr) { o << '('; PrintExpressionContents(currFunction, o).visit(curr); diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 0213baffeca..6a409f7db46 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -979,6 +979,9 @@ enum ASTNodes { F32x4DemoteZeroF64x2 = 0x57, F64x2PromoteLowF32x4 = 0x69, + I32x4WidenSI8x16 = 0x67, + I32x4WidenUI8x16 = 0x68, + // prefetch opcodes PrefetchT = 0xc5, @@ -1521,6 +1524,7 @@ class WasmBinaryBuilder { bool maybeVisitSIMDShift(Expression*& out, uint32_t code); bool maybeVisitSIMDLoad(Expression*& out, uint32_t code); bool maybeVisitSIMDLoadStoreLane(Expression*& out, uint32_t code); + bool maybeVisitSIMDWiden(Expression*& out, uint32_t code); bool maybeVisitPrefetch(Expression*& out, uint32_t code); bool maybeVisitMemoryInit(Expression*& out, uint32_t code); bool maybeVisitDataDrop(Expression*& out, uint32_t code); diff --git a/src/wasm-delegations-fields.h b/src/wasm-delegations-fields.h index d4ea25b3d14..b99ebef40d9 100644 --- a/src/wasm-delegations-fields.h +++ b/src/wasm-delegations-fields.h @@ -386,6 +386,14 @@ switch (DELEGATE_ID) { DELEGATE_END(SIMDLoadStoreLane); break; } + case Expression::Id::SIMDWidenId: { + DELEGATE_START(SIMDWiden); + DELEGATE_FIELD_CHILD(SIMDWiden, vec); + DELEGATE_FIELD_INT(SIMDWiden, op); + DELEGATE_FIELD_INT(SIMDWiden, index); + DELEGATE_END(SIMDWiden); + break; + } case Expression::Id::PrefetchId: { DELEGATE_START(Prefetch); DELEGATE_FIELD_CHILD(Prefetch, ptr); diff --git a/src/wasm-delegations.h b/src/wasm-delegations.h index fd419f508b1..5a05a731fb1 100644 --- a/src/wasm-delegations.h +++ b/src/wasm-delegations.h @@ -40,6 +40,7 @@ DELEGATE(SIMDTernary); DELEGATE(SIMDShift); DELEGATE(SIMDLoad); DELEGATE(SIMDLoadStoreLane); +DELEGATE(SIMDWiden); DELEGATE(Prefetch); DELEGATE(MemoryInit); DELEGATE(DataDrop); diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index ac64a30c0b3..6cd6f4b500b 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1132,6 +1132,7 @@ class ExpressionRunner : public OverriddenVisitor { } WASM_UNREACHABLE("invalid op"); } + Flow visitSIMDWiden(SIMDWiden* curr) { WASM_UNREACHABLE("unimp"); } Flow visitSelect(Select* curr) { NOTE_ENTER("Select"); Flow ifTrue = visit(curr->ifTrue); diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index 921ef6b4a9b..031589894df 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -220,6 +220,7 @@ class SExpressionWasmBuilder { Expression* makeSIMDShift(Element& s, SIMDShiftOp op); Expression* makeSIMDLoad(Element& s, SIMDLoadOp op); Expression* makeSIMDLoadStoreLane(Element& s, SIMDLoadStoreLaneOp op); + Expression* makeSIMDWiden(Element& s, SIMDWidenOp op); Expression* makePrefetch(Element& s, PrefetchOp op); Expression* makeMemoryInit(Element& s); Expression* makeDataDrop(Element& s); diff --git a/src/wasm.h b/src/wasm.h index bd2e3181439..0050fcc281c 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -481,7 +481,7 @@ enum SIMDReplaceOp { ReplaceLaneVecI32x4, ReplaceLaneVecI64x2, ReplaceLaneVecF32x4, - ReplaceLaneVecF64x2 + ReplaceLaneVecF64x2, }; enum SIMDShiftOp { @@ -537,6 +537,11 @@ enum SIMDTernaryOp { SignSelectVec64x2 }; +enum SIMDWidenOp { + WidenSVecI8x16ToVecI32x4, + WidenUVecI8x16ToVecI32x4, +}; + enum PrefetchOp { PrefetchTemporal, PrefetchNontemporal, @@ -625,6 +630,7 @@ class Expression { SIMDShiftId, SIMDLoadId, SIMDLoadStoreLaneId, + SIMDWidenId, MemoryInitId, DataDropId, MemoryCopyId, @@ -1072,6 +1078,18 @@ class SIMDLoadStoreLane void finalize(); }; +class SIMDWiden : public SpecificExpression { +public: + SIMDWiden() = default; + SIMDWiden(MixedArena& allocator) {} + + SIMDWidenOp op; + uint8_t index; + Expression* vec; + + void finalize(); +}; + class Prefetch : public SpecificExpression { public: Prefetch() = default; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index b7ffcd8d772..2c473a254eb 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -3005,6 +3005,9 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { if (maybeVisitSIMDLoadStoreLane(curr, opcode)) { break; } + if (maybeVisitSIMDWiden(curr, opcode)) { + break; + } if (maybeVisitPrefetch(curr, opcode)) { break; } @@ -5466,6 +5469,27 @@ bool WasmBinaryBuilder::maybeVisitSIMDLoadStoreLane(Expression*& out, return true; } +bool WasmBinaryBuilder::maybeVisitSIMDWiden(Expression*& out, uint32_t code) { + SIMDWidenOp op; + switch (code) { + case BinaryConsts::I32x4WidenSI8x16: + op = WidenSVecI8x16ToVecI32x4; + break; + case BinaryConsts::I32x4WidenUI8x16: + op = WidenUVecI8x16ToVecI32x4; + break; + default: + return false; + } + auto* curr = allocator.alloc(); + curr->op = op; + curr->index = getLaneIndex(4); + curr->vec = popNonVoidExpression(); + curr->finalize(); + out = curr; + return true; +} + bool WasmBinaryBuilder::maybeVisitPrefetch(Expression*& out, uint32_t code) { PrefetchOp op; switch (code) { diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 3075f70d7a6..0dc121f2c90 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -1666,6 +1666,15 @@ SExpressionWasmBuilder::makeSIMDLoadStoreLane(Element& s, return ret; } +Expression* SExpressionWasmBuilder::makeSIMDWiden(Element& s, SIMDWidenOp op) { + auto* ret = allocator.alloc(); + ret->op = op; + ret->index = parseLaneIndex(s[1], 4); + ret->vec = parseExpression(s[2]); + ret->finalize(); + return ret; +} + Expression* SExpressionWasmBuilder::makePrefetch(Element& s, PrefetchOp op) { Address offset, align; size_t i = parseMemAttributes(s, offset, align, /*defaultAlign*/ 1); diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index d42080bac7f..cb8702d0c0d 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -691,6 +691,19 @@ void BinaryInstWriter::visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) { o << curr->index; } +void BinaryInstWriter::visitSIMDWiden(SIMDWiden* curr) { + o << int8_t(BinaryConsts::SIMDPrefix); + switch (curr->op) { + case WidenSVecI8x16ToVecI32x4: + o << U32LEB(BinaryConsts::I32x4WidenSI8x16); + break; + case WidenUVecI8x16ToVecI32x4: + o << U32LEB(BinaryConsts::I32x4WidenUI8x16); + break; + } + o << uint8_t(curr->index); +} + void BinaryInstWriter::visitPrefetch(Prefetch* curr) { o << int8_t(BinaryConsts::SIMDPrefix); switch (curr->op) { diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index f8d8890ec94..e9d2bf1161d 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -496,6 +496,11 @@ void SIMDLoadStoreLane::finalize() { } } +void SIMDWiden::finalize() { + assert(vec); + type = vec->type == Type::unreachable ? Type::unreachable : Type::v128; +} + Index SIMDLoadStoreLane::getMemBytes() { switch (op) { case LoadLaneVec8x16: diff --git a/src/wasm2js.h b/src/wasm2js.h index 43c5f4cbdd5..db25fd47205 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -2119,6 +2119,10 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, unimplemented(curr); WASM_UNREACHABLE("unimp"); } + Ref visitSIMDWiden(SIMDWiden* curr) { + unimplemented(curr); + WASM_UNREACHABLE("unimp"); + } Ref visitMemoryInit(MemoryInit* curr) { ABI::wasm2js::ensureHelpers(module, ABI::wasm2js::MEMORY_INIT); return ValueBuilder::makeCall(ABI::wasm2js::MEMORY_INIT, diff --git a/test/binaryen.js/exception-handling.js.txt b/test/binaryen.js/exception-handling.js.txt index e7c72e6a76f..69b619564e6 100644 --- a/test/binaryen.js/exception-handling.js.txt +++ b/test/binaryen.js/exception-handling.js.txt @@ -19,6 +19,6 @@ ) ) -getExpressionInfo(throw) = {"id":47,"type":1,"event":"e"} -getExpressionInfo(rethrow) = {"id":48,"type":1,"depth":0} -getExpressionInfo(try) = {"id":46,"type":1,"hasCatchAll":0} +getExpressionInfo(throw) = {"id":48,"type":1,"event":"e"} +getExpressionInfo(rethrow) = {"id":49,"type":1,"depth":0} +getExpressionInfo(try) = {"id":47,"type":1,"hasCatchAll":0} diff --git a/test/binaryen.js/kitchen-sink.js.txt b/test/binaryen.js/kitchen-sink.js.txt index 5ad60b286bf..9b45d9a0197 100644 --- a/test/binaryen.js/kitchen-sink.js.txt +++ b/test/binaryen.js/kitchen-sink.js.txt @@ -76,35 +76,35 @@ SIMDShuffleId: 32 SIMDTernaryId: 33 SIMDShiftId: 34 SIMDLoadId: 35 -MemoryInitId: 37 -DataDropId: 38 -MemoryCopyId: 39 -MemoryFillId: 40 -PopId: 41 -RefNullId: 42 -RefIsId: 43 -RefFuncId: 44 -RefEqId: 45 -TryId: 46 -ThrowId: 47 -RethrowId: 48 -TupleMakeId: 49 -TupleExtractId: 50 -I31NewId: 51 -I31GetId: 52 -CallRefId: 53 -RefTestId: 54 -RefCastId: 55 -BrOnId: 56 -RttCanonId: 57 -RttSubId: 58 -StructNewId: 59 -StructGetId: 60 -StructSetId: 61 -ArrayNewId: 62 -ArrayGetId: 63 -ArraySetId: 64 -ArrayLenId: 65 +MemoryInitId: 38 +DataDropId: 39 +MemoryCopyId: 40 +MemoryFillId: 41 +PopId: 42 +RefNullId: 43 +RefIsId: 44 +RefFuncId: 45 +RefEqId: 46 +TryId: 47 +ThrowId: 48 +RethrowId: 49 +TupleMakeId: 50 +TupleExtractId: 51 +I31NewId: 52 +I31GetId: 53 +CallRefId: 54 +RefTestId: 55 +RefCastId: 56 +BrOnId: 57 +RttCanonId: 58 +RttSubId: 59 +StructNewId: 60 +StructGetId: 61 +StructSetId: 62 +ArrayNewId: 63 +ArrayGetId: 64 +ArraySetId: 65 +ArrayLenId: 66 getExpressionInfo={"id":15,"type":4,"op":6} (f32.neg (f32.const -33.61199951171875) diff --git a/test/simd.wast b/test/simd.wast index a171c53983d..8d12ea0ac0a 100644 --- a/test/simd.wast +++ b/test/simd.wast @@ -1436,4 +1436,14 @@ (local.get $0) ) ) + (func $i32x4.widen_i8x16_s (param $0 v128) (result v128) + (i32x4.widen_i8x16_s 0 + (local.get $0) + ) + ) + (func $i32x4.widen_i8x16_u (param $0 v128) (result v128) + (i32x4.widen_i8x16_u 0 + (local.get $0) + ) + ) ) diff --git a/test/simd.wast.from-wast b/test/simd.wast.from-wast index 223191c18da..6fbacea1155 100644 --- a/test/simd.wast.from-wast +++ b/test/simd.wast.from-wast @@ -1454,4 +1454,14 @@ (local.get $0) ) ) + (func $i32x4.widen_i8x16_s (param $0 v128) (result v128) + (i32x4.widen_i8x16_s 0 + (local.get $0) + ) + ) + (func $i32x4.widen_i8x16_u (param $0 v128) (result v128) + (i32x4.widen_i8x16_u 0 + (local.get $0) + ) + ) ) diff --git a/test/simd.wast.fromBinary b/test/simd.wast.fromBinary index 1c0b12493f0..4c84b5b2542 100644 --- a/test/simd.wast.fromBinary +++ b/test/simd.wast.fromBinary @@ -1454,5 +1454,15 @@ (local.get $0) ) ) + (func $i32x4.widen_i8x16_s (param $0 v128) (result v128) + (i32x4.widen_i8x16_s 0 + (local.get $0) + ) + ) + (func $i32x4.widen_i8x16_u (param $0 v128) (result v128) + (i32x4.widen_i8x16_u 0 + (local.get $0) + ) + ) ) diff --git a/test/simd.wast.fromBinary.noDebugInfo b/test/simd.wast.fromBinary.noDebugInfo index 3feb5a7b41f..bb5cdd5e056 100644 --- a/test/simd.wast.fromBinary.noDebugInfo +++ b/test/simd.wast.fromBinary.noDebugInfo @@ -1454,5 +1454,15 @@ (local.get $0) ) ) + (func $256 (param $0 v128) (result v128) + (i32x4.widen_i8x16_s 0 + (local.get $0) + ) + ) + (func $257 (param $0 v128) (result v128) + (i32x4.widen_i8x16_u 0 + (local.get $0) + ) + ) )