diff options
-rw-r--r-- | src/ir/ExpressionManipulator.cpp | 15 | ||||
-rw-r--r-- | src/ir/cost.h | 154 | ||||
-rw-r--r-- | src/literal.h | 2 | ||||
-rw-r--r-- | src/tools/execution-results.h | 1 | ||||
-rw-r--r-- | src/tools/feature-options.h | 4 | ||||
-rw-r--r-- | src/tools/fuzzing.h | 358 | ||||
-rw-r--r-- | src/tools/spec-wrapper.h | 2 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 2 | ||||
-rw-r--r-- | src/wasm-traversal.h | 10 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 2 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 10 | ||||
-rw-r--r-- | test/passes/translate-to-fuzz.txt | 1083 |
12 files changed, 748 insertions, 895 deletions
diff --git a/src/ir/ExpressionManipulator.cpp b/src/ir/ExpressionManipulator.cpp index d65509c52..3f53bccdd 100644 --- a/src/ir/ExpressionManipulator.cpp +++ b/src/ir/ExpressionManipulator.cpp @@ -114,6 +114,21 @@ Expression* flexibleCopy(Expression* original, Module& wasm, CustomCopier custom Expression* visitAtomicWake(AtomicWake* curr) { return builder.makeAtomicWake(copy(curr->ptr), copy(curr->wakeCount), curr->offset); } + Expression* visitSIMDExtract(SIMDExtract* curr) { + return builder.makeSIMDExtract(curr->op, copy(curr->vec), curr->idx); + } + Expression* visitSIMDReplace(SIMDReplace* curr) { + return builder.makeSIMDReplace(curr->op, copy(curr->vec), curr->idx, copy(curr->value)); + } + Expression* visitSIMDShuffle(SIMDShuffle* curr) { + return builder.makeSIMDShuffle(copy(curr->left), copy(curr->right), curr->mask); + } + Expression* visitSIMDBitselect(SIMDBitselect* curr) { + return builder.makeSIMDBitselect(copy(curr->left), copy(curr->right), copy(curr->cond)); + } + Expression* visitSIMDShift(SIMDShift* curr) { + return builder.makeSIMDShift(curr->op, copy(curr->vec), copy(curr->shift)); + } Expression* visitConst(Const *curr) { return builder.makeConst(curr->value); } diff --git a/src/ir/cost.h b/src/ir/cost.h index 354f663e1..defd9413e 100644 --- a/src/ir/cost.h +++ b/src/ir/cost.h @@ -184,7 +184,7 @@ struct CostAnalyzer : public Visitor<CostAnalyzer, Index> { case ConvertSVecI32x4ToVecF32x4: case ConvertUVecI32x4ToVecF32x4: case ConvertSVecI64x2ToVecF64x2: - case ConvertUVecI64x2ToVecF64x2: assert(false && "v128 not implemented yet"); + case ConvertUVecI64x2ToVecF64x2: return 1; case InvalidUnary: WASM_UNREACHABLE(); } return ret + visit(curr->value); @@ -268,82 +268,82 @@ struct CostAnalyzer : public Visitor<CostAnalyzer, Index> { case NeFloat32: ret = 1; break; case EqFloat64: ret = 1; break; case NeFloat64: ret = 1; break; - case EqVecI8x16: - case NeVecI8x16: - case LtSVecI8x16: - case LtUVecI8x16: - case LeSVecI8x16: - case LeUVecI8x16: - case GtSVecI8x16: - case GtUVecI8x16: - case GeSVecI8x16: - case GeUVecI8x16: - case EqVecI16x8: - case NeVecI16x8: - case LtSVecI16x8: - case LtUVecI16x8: - case LeSVecI16x8: - case LeUVecI16x8: - case GtSVecI16x8: - case GtUVecI16x8: - case GeSVecI16x8: - case GeUVecI16x8: - case EqVecI32x4: - case NeVecI32x4: - case LtSVecI32x4: - case LtUVecI32x4: - case LeSVecI32x4: - case LeUVecI32x4: - case GtSVecI32x4: - case GtUVecI32x4: - case GeSVecI32x4: - case GeUVecI32x4: - case EqVecF32x4: - case NeVecF32x4: - case LtVecF32x4: - case LeVecF32x4: - case GtVecF32x4: - case GeVecF32x4: - case EqVecF64x2: - case NeVecF64x2: - case LtVecF64x2: - case LeVecF64x2: - case GtVecF64x2: - case GeVecF64x2: - case AndVec128: - case OrVec128: - case XorVec128: - case AddVecI8x16: - case AddSatSVecI8x16: - case AddSatUVecI8x16: - case SubVecI8x16: - case SubSatSVecI8x16: - case SubSatUVecI8x16: - case MulVecI8x16: - case AddVecI16x8: - case AddSatSVecI16x8: - case AddSatUVecI16x8: - case SubVecI16x8: - case SubSatSVecI16x8: - case SubSatUVecI16x8: - case MulVecI16x8: - case AddVecI32x4: - case SubVecI32x4: - case MulVecI32x4: - case AddVecI64x2: - case SubVecI64x2: - case AddVecF32x4: - case SubVecF32x4: - case MulVecF32x4: - case DivVecF32x4: - case MinVecF32x4: - case MaxVecF32x4: - case AddVecF64x2: - case SubVecF64x2: - case MulVecF64x2: - case DivVecF64x2: - case MinVecF64x2: - case MaxVecF64x2: assert(false && "v128 not implemented yet"); + case EqVecI8x16: ret = 1; break; + case NeVecI8x16: ret = 1; break; + case LtSVecI8x16: ret = 1; break; + case LtUVecI8x16: ret = 1; break; + case LeSVecI8x16: ret = 1; break; + case LeUVecI8x16: ret = 1; break; + case GtSVecI8x16: ret = 1; break; + case GtUVecI8x16: ret = 1; break; + case GeSVecI8x16: ret = 1; break; + case GeUVecI8x16: ret = 1; break; + case EqVecI16x8: ret = 1; break; + case NeVecI16x8: ret = 1; break; + case LtSVecI16x8: ret = 1; break; + case LtUVecI16x8: ret = 1; break; + case LeSVecI16x8: ret = 1; break; + case LeUVecI16x8: ret = 1; break; + case GtSVecI16x8: ret = 1; break; + case GtUVecI16x8: ret = 1; break; + case GeSVecI16x8: ret = 1; break; + case GeUVecI16x8: ret = 1; break; + case EqVecI32x4: ret = 1; break; + case NeVecI32x4: ret = 1; break; + case LtSVecI32x4: ret = 1; break; + case LtUVecI32x4: ret = 1; break; + case LeSVecI32x4: ret = 1; break; + case LeUVecI32x4: ret = 1; break; + case GtSVecI32x4: ret = 1; break; + case GtUVecI32x4: ret = 1; break; + case GeSVecI32x4: ret = 1; break; + case GeUVecI32x4: ret = 1; break; + case EqVecF32x4: ret = 1; break; + case NeVecF32x4: ret = 1; break; + case LtVecF32x4: ret = 1; break; + case LeVecF32x4: ret = 1; break; + case GtVecF32x4: ret = 1; break; + case GeVecF32x4: ret = 1; break; + case EqVecF64x2: ret = 1; break; + case NeVecF64x2: ret = 1; break; + case LtVecF64x2: ret = 1; break; + case LeVecF64x2: ret = 1; break; + case GtVecF64x2: ret = 1; break; + case GeVecF64x2: ret = 1; break; + case AndVec128: ret = 1; break; + case OrVec128: ret = 1; break; + case XorVec128: ret = 1; break; + case AddVecI8x16: ret = 1; break; + case AddSatSVecI8x16: ret = 1; break; + case AddSatUVecI8x16: ret = 1; break; + case SubVecI8x16: ret = 1; break; + case SubSatSVecI8x16: ret = 1; break; + case SubSatUVecI8x16: ret = 1; break; + case MulVecI8x16: ret = 2; break; + case AddVecI16x8: ret = 1; break; + case AddSatSVecI16x8: ret = 1; break; + case AddSatUVecI16x8: ret = 1; break; + case SubVecI16x8: ret = 1; break; + case SubSatSVecI16x8: ret = 1; break; + case SubSatUVecI16x8: ret = 1; break; + case MulVecI16x8: ret = 2; break; + case AddVecI32x4: ret = 1; break; + case SubVecI32x4: ret = 1; break; + case MulVecI32x4: ret = 2; break; + case AddVecI64x2: ret = 1; break; + case SubVecI64x2: ret = 1; break; + case AddVecF32x4: ret = 1; break; + case SubVecF32x4: ret = 1; break; + case MulVecF32x4: ret = 2; break; + case DivVecF32x4: ret = 3; break; + case MinVecF32x4: ret = 1; break; + case MaxVecF32x4: ret = 1; break; + case AddVecF64x2: ret = 1; break; + case SubVecF64x2: ret = 1; break; + case MulVecF64x2: ret = 2; break; + case DivVecF64x2: ret = 3; break; + case MinVecF64x2: ret = 1; break; + case MaxVecF64x2: ret = 1; break; case InvalidBinary: WASM_UNREACHABLE(); } return ret + visit(curr->left) + visit(curr->right); diff --git a/src/literal.h b/src/literal.h index dd5688263..6cd148b23 100644 --- a/src/literal.h +++ b/src/literal.h @@ -42,7 +42,7 @@ private: public: Literal() : type(Type::none), v128() {} - explicit Literal(Type type) : type(type), i64(0) {} + explicit Literal(Type type) : type(type), v128() {} explicit Literal(int32_t init) : type(Type::i32), i32(init) {} explicit Literal(uint32_t init) : type(Type::i32), i32(init) {} explicit Literal(int64_t init) : type(Type::i64), i64(init) {} diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 935aff4cc..89e0440bb 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -143,4 +143,3 @@ struct ExecutionResults { }; } // namespace wasm - diff --git a/src/tools/feature-options.h b/src/tools/feature-options.h index 1bd78d9b9..282aa4d4b 100644 --- a/src/tools/feature-options.h +++ b/src/tools/feature-options.h @@ -29,12 +29,12 @@ struct FeatureOptions : public Options { FeatureOptions(const std::string& command, const std::string& description) : Options(command, description) { (*this) - .add("--mvp-features", "-mvp", "Disable all non-MVP features (default)", + .add("--mvp-features", "-mvp", "Disable all non-MVP features", Options::Arguments::Zero, [this](Options *o, const std::string& arguments) { passOptions.features = FeatureSet::MVP; }) - .add("--all-features", "-all", "Enable all features", + .add("--all-features", "-all", "Enable all features (default)", Options::Arguments::Zero, [this](Options *o, const std::string& arguments) { passOptions.features = FeatureSet::All; diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 999325baa..5aec51c88 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -177,6 +177,7 @@ private: // Optionally remove NaNs, which are a source of nondeterminism (which makes // cross-VM comparisons harder) + // TODO: de-NaN SIMD values static const bool DE_NAN = true; // Features allowed to be emitted @@ -688,8 +689,8 @@ private: case i32: case i64: case f32: - case f64: ret = _makeConcrete(type); break; - case v128: assert(false && "v128 not implemented yet"); + case f64: + case v128: ret = _makeConcrete(type); break; case none: ret = _makenone(); break; case unreachable: ret = _makeunreachable(); break; } @@ -707,24 +708,28 @@ private: if (choice < 70) return makeIf(type); if (choice < 80) return makeLoop(type); if (choice < 90) return makeBreak(type); - switch (upTo(15)) { - case 0: return makeBlock(type); - case 1: return makeIf(type); - case 2: return makeLoop(type); - case 3: return makeBreak(type); - case 4: return makeCall(type); - case 5: return makeCallIndirect(type); - case 6: return makeGetLocal(type); - case 7: return makeSetLocal(type); - case 8: return makeLoad(type); - case 9: return makeConst(type); - case 10: return makeUnary(type); - case 11: return makeBinary(type); - case 12: return makeSelect(type); - case 13: return makeGetGlobal(type); - case 14: return makeAtomic(type); - } - WASM_UNREACHABLE(); + using Self = TranslateToFuzzReader; + auto options = FeatureOptions<Expression* (Self::*)(Type)>() + .add(FeatureSet::MVP, + &Self::makeBlock, + &Self::makeIf, + &Self::makeLoop, + &Self::makeBreak, + &Self::makeCall, + &Self::makeCallIndirect, + &Self::makeGetLocal, + &Self::makeSetLocal, + &Self::makeLoad, + &Self::makeConst, + &Self::makeUnary, + &Self::makeBinary, + &Self::makeSelect, + &Self::makeGetGlobal) + .add(FeatureSet::SIMD, &Self::makeSIMD); + if (type == i32 || type == i64) { + options.add(FeatureSet::Atomics, &Self::makeAtomic); + } + return (this->*pick(options))(type); } Expression* _makenone() { @@ -881,18 +886,18 @@ private: } } + Expression* buildIf(const struct ThreeArgs& args) { + return builder.makeIf(args.a, args.b, args.c); + } + Expression* makeIf(Type type) { auto* condition = makeCondition(); hangStack.push_back(nullptr); - auto* ret = makeIf({ condition, makeMaybeBlock(type), makeMaybeBlock(type) }); + auto* ret = buildIf({ condition, makeMaybeBlock(type), makeMaybeBlock(type) }); hangStack.pop_back(); return ret; } - Expression* makeIf(const struct ThreeArgs& args) { - return builder.makeIf(args.a, args.b, args.c); - } - Expression* makeBreak(Type type) { if (breakableStack.empty()) return makeTrivial(type); Expression* condition = nullptr; @@ -1108,7 +1113,9 @@ private: case f64: { return builder.makeLoad(8, false, offset, pick(1, 2, 4, 8), ptr, type); } - case v128: assert(false && "v128 not implemented yet"); + case v128: { + return builder.makeLoad(16, false, offset, pick(1, 2, 4, 8, 16), ptr, type); + } case none: case unreachable: WASM_UNREACHABLE(); } @@ -1171,7 +1178,9 @@ private: case f64: { return builder.makeStore(8, offset, pick(1, 2, 4, 8), ptr, value, type); } - case v128: assert(false && "v128 not implemented yet"); + case v128: { + return builder.makeStore(16, offset, pick(1, 2, 4, 8, 16), ptr, value, type); + } case none: case unreachable: WASM_UNREACHABLE(); } @@ -1189,17 +1198,41 @@ private: return ret; } - Expression* makeConst(Type type) { - Literal value; + Literal makeLiteral(Type type) { + if (type == v128) { + // generate each lane individually for random lane interpretation + switch (upTo(6)) { + case 0: return Literal( + std::array<Literal, 16>{{ + makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), + makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), + makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), + makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32) + }} + ); + case 1: return Literal( + std::array<Literal, 8>{{ + makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), + makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32) + }} + ); + case 2: return Literal(std::array<Literal, 4>{{makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32)}}); + case 3: return Literal(std::array<Literal, 2>{{makeLiteral(i64), makeLiteral(i64)}}); + case 4: return Literal(std::array<Literal, 4>{{makeLiteral(f32), makeLiteral(f32), makeLiteral(f32), makeLiteral(f32)}}); + case 5: return Literal(std::array<Literal, 2>{{makeLiteral(f64), makeLiteral(f64)}}); + default: WASM_UNREACHABLE(); + } + } + switch (upTo(4)) { case 0: { // totally random, entire range switch (type) { - case i32: value = Literal(get32()); break; - case i64: value = Literal(get64()); break; - case f32: value = Literal(getFloat()); break; - case f64: value = Literal(getDouble()); break; - case v128: assert(false && "v128 not implemented yet"); + case i32: return Literal(get32()); + case i64: return Literal(get64()); + case f32: return Literal(getFloat()); + case f64: return Literal(getDouble()); + case v128: case none: case unreachable: WASM_UNREACHABLE(); } @@ -1218,11 +1251,11 @@ private: default: WASM_UNREACHABLE(); } switch (type) { - case i32: value = Literal(int32_t(small)); break; - case i64: value = Literal(int64_t(small)); break; - case f32: value = Literal(float(small)); break; - case f64: value = Literal(double(small)); break; - case v128: assert(false && "v128 not implemented yet"); + case i32: return Literal(int32_t(small)); + case i64: return Literal(int64_t(small)); + case f32: return Literal(float(small)); + case f64: return Literal(double(small)); + case v128: case none: case unreachable: WASM_UNREACHABLE(); } @@ -1230,6 +1263,7 @@ private: } case 2: { // special values + Literal value; switch (type) { case i32: value = Literal(pick<int32_t>(0, std::numeric_limits<int8_t>::min(), std::numeric_limits<int8_t>::max(), @@ -1260,11 +1294,9 @@ private: std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::max(), std::numeric_limits<uint32_t>::max(), std::numeric_limits<uint64_t>::max())); break; - case v128: assert(false && "v128 not implemented yet"); + case v128: case none: - case unreachable: { - WASM_UNREACHABLE(); - } + case unreachable: WASM_UNREACHABLE(); } // tweak around special values if (oneIn(3)) { // +- 1 @@ -1273,16 +1305,17 @@ private: if (oneIn(2)) { // flip sign value = value.mul(Literal::makeFromInt32(-1, type)); } - break; + return value; } case 3: { // powers of 2 + Literal value; switch (type) { case i32: value = Literal(int32_t(1) << upTo(32)); break; case i64: value = Literal(int64_t(1) << upTo(64)); break; case f32: value = Literal(float(int64_t(1) << upTo(64))); break; case f64: value = Literal(double(int64_t(1) << upTo(64))); break; - case v128: assert(false && "v128 not implemented yet"); + case v128: case none: case unreachable: WASM_UNREACHABLE(); } @@ -1290,15 +1323,20 @@ private: if (oneIn(2)) { value = value.mul(Literal::makeFromInt32(-1, type)); } + return value; } } + WASM_UNREACHABLE(); + } + + Expression* makeConst(Type type) { auto* ret = wasm.allocator.alloc<Const>(); - ret->value = value; - ret->type = value.type; + ret->value = makeLiteral(type); + ret->type = type; return ret; } - Expression* makeUnary(const UnaryArgs& args) { + Expression* buildUnary(const UnaryArgs& args) { return builder.makeUnary(args.a, args.b); } @@ -1312,32 +1350,40 @@ private: } switch (type) { case i32: { - switch (upTo(4)) { - case 0: { + switch (getConcreteType()) { + case i32: { auto op = pick( FeatureOptions<UnaryOp>() .add(FeatureSet::MVP, EqZInt32, ClzInt32, CtzInt32, PopcntInt32) .add(FeatureSet::Atomics, ExtendS8Int32, ExtendS16Int32) ); - return makeUnary({ op, make(i32) }); + return buildUnary({ op, make(i32) }); } - case 1: return makeUnary({ pick(EqZInt64, WrapInt64), make(i64) }); - case 2: { + case i64: return buildUnary({ pick(EqZInt64, WrapInt64), make(i64) }); + case f32: { auto op = pick( FeatureOptions<UnaryOp>() .add(FeatureSet::MVP, TruncSFloat32ToInt32, TruncUFloat32ToInt32, ReinterpretFloat32) .add(FeatureSet::TruncSat, TruncSatSFloat32ToInt32, TruncSatUFloat32ToInt32) ); - return makeUnary({ op, make(f32) }); + return buildUnary({ op, make(f32) }); } - case 3: { + case f64: { auto op = pick( FeatureOptions<UnaryOp>() .add(FeatureSet::MVP, TruncSFloat64ToInt32, TruncUFloat64ToInt32) .add(FeatureSet::TruncSat, TruncSatSFloat64ToInt32, TruncSatUFloat64ToInt32) ); - return makeUnary({ op, make(f64) }); + return buildUnary({ op, make(f64) }); } + case v128: { + assert(features.hasSIMD()); + return buildUnary({ pick(AnyTrueVecI8x16, AllTrueVecI8x16, AnyTrueVecI16x8, AllTrueVecI16x8, + AnyTrueVecI32x4, AllTrueVecI32x4, AnyTrueVecI64x2, AllTrueVecI64x2), + make(v128) }); + } + case none: + case unreachable: WASM_UNREACHABLE(); } WASM_UNREACHABLE(); } @@ -1349,16 +1395,16 @@ private: .add(FeatureSet::MVP, ClzInt64, CtzInt64, PopcntInt64) .add(FeatureSet::Atomics, ExtendS8Int64, ExtendS16Int64, ExtendS32Int64) ); - return makeUnary({ op, make(i64) }); + return buildUnary({ op, make(i64) }); } - case 1: return makeUnary({ pick(ExtendSInt32, ExtendUInt32), make(i32) }); + case 1: return buildUnary({ pick(ExtendSInt32, ExtendUInt32), make(i32) }); case 2: { auto op = pick( FeatureOptions<UnaryOp>() .add(FeatureSet::MVP, TruncSFloat32ToInt64, TruncUFloat32ToInt64) .add(FeatureSet::TruncSat, TruncSatSFloat32ToInt64, TruncSatUFloat32ToInt64) ); - return makeUnary({ op, make(f32) }); + return buildUnary({ op, make(f32) }); } case 3: { auto op = pick( @@ -1366,46 +1412,59 @@ private: .add(FeatureSet::MVP, TruncSFloat64ToInt64, TruncUFloat64ToInt64, ReinterpretFloat64) .add(FeatureSet::TruncSat, TruncSatSFloat64ToInt64, TruncSatUFloat64ToInt64) ); - return makeUnary({ op, make(f64) }); + return buildUnary({ op, make(f64) }); } } WASM_UNREACHABLE(); } case f32: { switch (upTo(4)) { - case 0: return makeDeNanOp(makeUnary({ pick(NegFloat32, AbsFloat32, CeilFloat32, FloorFloat32, TruncFloat32, NearestFloat32, SqrtFloat32), make(f32) })); - case 1: return makeDeNanOp(makeUnary({ pick(ConvertUInt32ToFloat32, ConvertSInt32ToFloat32, ReinterpretInt32), make(i32) })); - case 2: return makeDeNanOp(makeUnary({ pick(ConvertUInt64ToFloat32, ConvertSInt64ToFloat32), make(i64) })); - case 3: return makeDeNanOp(makeUnary({ DemoteFloat64, make(f64) })); + case 0: return makeDeNanOp(buildUnary({ pick(NegFloat32, AbsFloat32, CeilFloat32, FloorFloat32, TruncFloat32, NearestFloat32, SqrtFloat32), make(f32) })); + case 1: return makeDeNanOp(buildUnary({ pick(ConvertUInt32ToFloat32, ConvertSInt32ToFloat32, ReinterpretInt32), make(i32) })); + case 2: return makeDeNanOp(buildUnary({ pick(ConvertUInt64ToFloat32, ConvertSInt64ToFloat32), make(i64) })); + case 3: return makeDeNanOp(buildUnary({ DemoteFloat64, make(f64) })); } WASM_UNREACHABLE(); } case f64: { switch (upTo(4)) { - case 0: return makeDeNanOp(makeUnary({ pick(NegFloat64, AbsFloat64, CeilFloat64, FloorFloat64, TruncFloat64, NearestFloat64, SqrtFloat64), make(f64) })); - case 1: return makeDeNanOp(makeUnary({ pick(ConvertUInt32ToFloat64, ConvertSInt32ToFloat64), make(i32) })); - case 2: return makeDeNanOp(makeUnary({ pick(ConvertUInt64ToFloat64, ConvertSInt64ToFloat64, ReinterpretInt64), make(i64) })); - case 3: return makeDeNanOp(makeUnary({ PromoteFloat32, make(f32) })); + case 0: return makeDeNanOp(buildUnary({ pick(NegFloat64, AbsFloat64, CeilFloat64, FloorFloat64, TruncFloat64, NearestFloat64, SqrtFloat64), make(f64) })); + case 1: return makeDeNanOp(buildUnary({ pick(ConvertUInt32ToFloat64, ConvertSInt32ToFloat64), make(i32) })); + case 2: return makeDeNanOp(buildUnary({ pick(ConvertUInt64ToFloat64, ConvertSInt64ToFloat64, ReinterpretInt64), make(i64) })); + case 3: return makeDeNanOp(buildUnary({ PromoteFloat32, make(f32) })); } WASM_UNREACHABLE(); } - case v128: assert(false && "v128 not implemented yet"); - case none: - case unreachable: { + case v128: { + assert(features.hasSIMD()); + switch (upTo(5)) { + case 0: return buildUnary({ pick(SplatVecI8x16, SplatVecI16x8, SplatVecI32x4), make(i32) }); + case 1: return buildUnary({ SplatVecI64x2, make(i64) }); + case 2: return buildUnary({ SplatVecF32x4, make(f32) }); + case 3: return buildUnary({ SplatVecF64x2, make(f64) }); + case 4: return buildUnary({ + pick(NotVec128, NegVecI8x16, NegVecI16x8, NegVecI32x4, NegVecI64x2, + AbsVecF32x4, NegVecF32x4, SqrtVecF32x4, AbsVecF64x2, NegVecF64x2, SqrtVecF64x2, + TruncSatSVecF32x4ToVecI32x4, TruncSatUVecF32x4ToVecI32x4, TruncSatSVecF64x2ToVecI64x2, TruncSatUVecF64x2ToVecI64x2, + ConvertSVecI32x4ToVecF32x4, ConvertUVecI32x4ToVecF32x4, ConvertSVecI64x2ToVecF64x2, ConvertUVecI64x2ToVecF64x2), + make(v128) }); + } WASM_UNREACHABLE(); } + case none: + case unreachable: WASM_UNREACHABLE(); } WASM_UNREACHABLE(); } - Expression* makeBinary(const BinaryArgs& args) { + Expression* buildBinary(const BinaryArgs& args) { return builder.makeBinary(args.a, args.b, args.c); } Expression* makeBinary(Type type) { if (type == unreachable) { if (auto* binary = makeBinary(getConcreteType())->dynCast<Binary>()) { - return makeDeNanOp(makeBinary({ binary->op, make(unreachable), make(unreachable) })); + return makeDeNanOp(buildBinary({ binary->op, make(unreachable), make(unreachable) })); } // give up return makeTrivial(type); @@ -1413,35 +1472,47 @@ private: switch (type) { case i32: { switch (upTo(4)) { - case 0: return makeBinary({ pick(AddInt32, SubInt32, MulInt32, DivSInt32, DivUInt32, RemSInt32, RemUInt32, AndInt32, OrInt32, XorInt32, ShlInt32, ShrUInt32, ShrSInt32, RotLInt32, RotRInt32, EqInt32, NeInt32, LtSInt32, LtUInt32, LeSInt32, LeUInt32, GtSInt32, GtUInt32, GeSInt32, GeUInt32), make(i32), make(i32) }); - case 1: return makeBinary({ pick(EqInt64, NeInt64, LtSInt64, LtUInt64, LeSInt64, LeUInt64, GtSInt64, GtUInt64, GeSInt64, GeUInt64), make(i64), make(i64) }); - case 2: return makeBinary({ pick(EqFloat32, NeFloat32, LtFloat32, LeFloat32, GtFloat32, GeFloat32), make(f32), make(f32) }); - case 3: return makeBinary({ pick(EqFloat64, NeFloat64, LtFloat64, LeFloat64, GtFloat64, GeFloat64), make(f64), make(f64) }); + case 0: return buildBinary({ pick(AddInt32, SubInt32, MulInt32, DivSInt32, DivUInt32, RemSInt32, RemUInt32, AndInt32, OrInt32, XorInt32, ShlInt32, ShrUInt32, ShrSInt32, RotLInt32, RotRInt32, EqInt32, NeInt32, LtSInt32, LtUInt32, LeSInt32, LeUInt32, GtSInt32, GtUInt32, GeSInt32, GeUInt32), make(i32), make(i32) }); + case 1: return buildBinary({ pick(EqInt64, NeInt64, LtSInt64, LtUInt64, LeSInt64, LeUInt64, GtSInt64, GtUInt64, GeSInt64, GeUInt64), make(i64), make(i64) }); + case 2: return buildBinary({ pick(EqFloat32, NeFloat32, LtFloat32, LeFloat32, GtFloat32, GeFloat32), make(f32), make(f32) }); + case 3: return buildBinary({ pick(EqFloat64, NeFloat64, LtFloat64, LeFloat64, GtFloat64, GeFloat64), make(f64), make(f64) }); } WASM_UNREACHABLE(); } case i64: { - return makeBinary({ pick(AddInt64, SubInt64, MulInt64, DivSInt64, DivUInt64, RemSInt64, RemUInt64, AndInt64, OrInt64, XorInt64, ShlInt64, ShrUInt64, ShrSInt64, RotLInt64, RotRInt64), make(i64), make(i64) }); + return buildBinary({ pick(AddInt64, SubInt64, MulInt64, DivSInt64, DivUInt64, RemSInt64, RemUInt64, AndInt64, OrInt64, XorInt64, ShlInt64, ShrUInt64, ShrSInt64, RotLInt64, RotRInt64), make(i64), make(i64) }); } case f32: { - return makeDeNanOp(makeBinary({ pick(AddFloat32, SubFloat32, MulFloat32, DivFloat32, CopySignFloat32, MinFloat32, MaxFloat32), make(f32), make(f32) })); + return makeDeNanOp(buildBinary({ pick(AddFloat32, SubFloat32, MulFloat32, DivFloat32, CopySignFloat32, MinFloat32, MaxFloat32), make(f32), make(f32) })); } case f64: { - return makeDeNanOp(makeBinary({ pick(AddFloat64, SubFloat64, MulFloat64, DivFloat64, CopySignFloat64, MinFloat64, MaxFloat64), make(f64), make(f64) })); + return makeDeNanOp(buildBinary({ pick(AddFloat64, SubFloat64, MulFloat64, DivFloat64, CopySignFloat64, MinFloat64, MaxFloat64), make(f64), make(f64) })); + } + case v128: { + assert(features.hasSIMD()); + return buildBinary({ + pick(EqVecI8x16, NeVecI8x16, LtSVecI8x16, LtUVecI8x16, GtSVecI8x16, GtUVecI8x16, LeSVecI8x16, LeUVecI8x16, GeSVecI8x16, GeUVecI8x16, + EqVecI16x8, NeVecI16x8, LtSVecI16x8, LtUVecI16x8, GtSVecI16x8, GtUVecI16x8, LeSVecI16x8, LeUVecI16x8, GeSVecI16x8, GeUVecI16x8, + EqVecI32x4, NeVecI32x4, LtSVecI32x4, LtUVecI32x4, GtSVecI32x4, GtUVecI32x4, LeSVecI32x4, LeUVecI32x4, GeSVecI32x4, GeUVecI32x4, + EqVecF32x4, NeVecF32x4, LtVecF32x4, GtVecF32x4, LeVecF32x4, GeVecF32x4, EqVecF64x2, NeVecF64x2, LtVecF64x2, GtVecF64x2, LeVecF64x2, GeVecF64x2, + AndVec128, OrVec128, XorVec128, AddVecI8x16, AddSatSVecI8x16, AddSatUVecI8x16, SubVecI8x16, SubSatSVecI8x16, SubSatUVecI8x16, MulVecI8x16, + AddVecI16x8, AddSatSVecI16x8, AddSatUVecI16x8, SubVecI16x8, SubSatSVecI16x8, SubSatUVecI16x8, MulVecI16x8, AddVecI32x4, SubVecI32x4, MulVecI32x4, + AddVecI64x2, SubVecI64x2, AddVecF32x4, SubVecF32x4, MulVecF32x4, DivVecF32x4, MinVecF32x4, MaxVecF32x4, + AddVecF64x2, SubVecF64x2, MulVecF64x2, DivVecF64x2, MinVecF64x2, MaxVecF64x2), + make(v128), make(v128) }); } - case v128: assert(false && "v128 not implemented yet"); case none: case unreachable: WASM_UNREACHABLE(); } WASM_UNREACHABLE(); } - Expression* makeSelect(const ThreeArgs& args) { + Expression* buildSelect(const ThreeArgs& args) { return builder.makeSelect(args.a, args.b, args.c); } Expression* makeSelect(Type type) { - return makeDeNanOp(makeSelect({ make(i32), make(type), make(type) })); + return makeDeNanOp(buildSelect({ make(i32), make(type), make(type) })); } Expression* makeSwitch(Type type) { @@ -1493,7 +1564,7 @@ private: } Expression* makeAtomic(Type type) { - if (!features.hasAtomics() || (type != i32 && type != i64)) return makeTrivial(type); + assert(features.hasAtomics()); wasm.memory.shared = true; if (type == i32 && oneIn(2)) { if (ATOMIC_WAITS && oneIn(2)) { @@ -1544,6 +1615,92 @@ private: } } + Expression* makeSIMD(Type type) { + assert(features.hasSIMD()); + if (type != v128) { + return makeSIMDExtract(type); + } + switch (upTo(6)) { + case 0: return makeUnary(v128); + case 1: return makeBinary(v128); + case 2: return makeSIMDReplace(); + case 3: return makeSIMDShuffle(); + case 4: return makeSIMDBitselect(); + case 5: return makeSIMDShift(); + } + WASM_UNREACHABLE(); + } + + Expression* makeSIMDExtract(Type type) { + auto op = static_cast<SIMDExtractOp>(0); + switch (type) { + case i32: op = pick(ExtractLaneSVecI8x16, ExtractLaneUVecI8x16, ExtractLaneSVecI16x8, ExtractLaneUVecI16x8, ExtractLaneVecI32x4); break; + case i64: op = ExtractLaneVecI64x2; break; + case f32: op = ExtractLaneVecF32x4; break; + case f64: op = ExtractLaneVecF64x2; break; + case v128: + case none: + case unreachable: WASM_UNREACHABLE(); + } + Expression* vec = make(v128); + uint8_t idx = 0; + switch (op) { + case ExtractLaneSVecI8x16: + case ExtractLaneUVecI8x16: idx = upTo(16); break; + case ExtractLaneSVecI16x8: + case ExtractLaneUVecI16x8: idx = upTo(8); break; + case ExtractLaneVecI32x4: + case ExtractLaneVecF32x4: idx = upTo(4); break; + case ExtractLaneVecI64x2: + case ExtractLaneVecF64x2: idx = upTo(2); break; + } + return builder.makeSIMDExtract(op, vec, idx); + } + + Expression* makeSIMDReplace() { + SIMDReplaceOp op = pick(ReplaceLaneVecI8x16, ReplaceLaneVecI16x8, ReplaceLaneVecI32x4, + ReplaceLaneVecI64x2, ReplaceLaneVecF32x4, ReplaceLaneVecF64x2); + Expression* vec = make(v128); + uint8_t idx; + Type lane_t; + switch (op) { + case ReplaceLaneVecI8x16: idx = upTo(16); lane_t = i32; break; + case ReplaceLaneVecI16x8: idx = upTo(8); lane_t = i32; break; + case ReplaceLaneVecI32x4: idx = upTo(4); lane_t = i32; break; + case ReplaceLaneVecI64x2: idx = upTo(2); lane_t = i64; break; + case ReplaceLaneVecF32x4: idx = upTo(4); lane_t = f32; break; + case ReplaceLaneVecF64x2: idx = upTo(2); lane_t = f64; break; + default: WASM_UNREACHABLE(); + } + Expression* value = make(lane_t); + return builder.makeSIMDReplace(op, vec, idx, value); + } + + Expression* makeSIMDShuffle() { + Expression* left = make(v128); + Expression* right = make(v128); + std::array<uint8_t, 16> mask; + for (size_t i = 0; i < 16; ++i) { + mask[i] = upTo(32); + } + return builder.makeSIMDShuffle(left, right, mask); + } + + Expression* makeSIMDBitselect() { + Expression* left = make(v128); + Expression* right = make(v128); + Expression* cond = make(v128); + return builder.makeSIMDBitselect(left, right, cond); + } + + Expression* makeSIMDShift() { + SIMDShiftOp op = pick(ShlVecI8x16, ShrSVecI8x16, ShrUVecI8x16, ShlVecI16x8, ShrSVecI16x8, ShrUVecI16x8, + ShlVecI32x4, ShrSVecI32x4, ShrUVecI32x4, ShlVecI64x2, ShrSVecI64x2, ShrUVecI64x2); + Expression* vec = make(v128); + Expression* shift = make(i32); + return builder.makeSIMDShift(op, vec, shift); + } + // special makers Expression* makeLogging() { @@ -1554,36 +1711,21 @@ private: // special getters Type getType() { - switch (upTo(6)) { - case 0: return i32; - case 1: return i64; - case 2: return f32; - case 3: return f64; - case 4: return none; - case 5: return unreachable; - } - WASM_UNREACHABLE(); + return pick(FeatureOptions<Type>() + .add(FeatureSet::MVP, i32, i64, f32, f64, none, unreachable) + .add(FeatureSet::SIMD, v128)); } Type getReachableType() { - switch (upTo(5)) { - case 0: return i32; - case 1: return i64; - case 2: return f32; - case 3: return f64; - case 4: return none; - } - WASM_UNREACHABLE(); + return pick(FeatureOptions<Type>() + .add(FeatureSet::MVP, i32, i64, f32, f64, none) + .add(FeatureSet::SIMD, v128)); } Type getConcreteType() { - switch (upTo(4)) { - case 0: return i32; - case 1: return i64; - case 2: return f32; - case 3: return f64; - } - WASM_UNREACHABLE(); + return pick(FeatureOptions<Type>() + .add(FeatureSet::MVP, i32, i64, f32, f64) + .add(FeatureSet::SIMD, v128)); } // statistical distributions diff --git a/src/tools/spec-wrapper.h b/src/tools/spec-wrapper.h index d6aa0d87e..a42230fc1 100644 --- a/src/tools/spec-wrapper.h +++ b/src/tools/spec-wrapper.h @@ -34,7 +34,7 @@ static std::string generateSpecWrapper(Module& wasm) { case i64: ret += "(i64.const 0)"; break; case f32: ret += "(f32.const 0)"; break; case f64: ret += "(f64.const 0)"; break; - case v128: assert(false && "v128 not implemented yet"); + case v128: ret += "(v128.const i32 0 0 0 0)"; break; case none: case unreachable: WASM_UNREACHABLE(); } diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index e970a4f83..cec5dd983 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -589,7 +589,7 @@ public: return left.shuffleV8x16(right, curr->mask); } Flow visitSIMDBitselect(SIMDBitselect *curr) { - NOTE_ENTER("SIMDShuffle"); + NOTE_ENTER("SIMDBitselect"); Flow flow = this->visit(curr->left); if (flow.breaking()) return flow; Literal left = flow.value; diff --git a/src/wasm-traversal.h b/src/wasm-traversal.h index 200a67cb6..c79be1c10 100644 --- a/src/wasm-traversal.h +++ b/src/wasm-traversal.h @@ -591,27 +591,27 @@ struct PostWalker : public Walker<SubType, VisitorType> { } case Expression::Id::SIMDReplaceId: { self->pushTask(SubType::doVisitSIMDReplace, currp); - self->pushTask(SubType::scan, &curr->cast<SIMDReplace>()->vec); self->pushTask(SubType::scan, &curr->cast<SIMDReplace>()->value); + self->pushTask(SubType::scan, &curr->cast<SIMDReplace>()->vec); break; } case Expression::Id::SIMDShuffleId: { self->pushTask(SubType::doVisitSIMDShuffle, currp); - self->pushTask(SubType::scan, &curr->cast<SIMDShuffle>()->left); self->pushTask(SubType::scan, &curr->cast<SIMDShuffle>()->right); + self->pushTask(SubType::scan, &curr->cast<SIMDShuffle>()->left); break; } case Expression::Id::SIMDBitselectId: { self->pushTask(SubType::doVisitSIMDBitselect, currp); - self->pushTask(SubType::scan, &curr->cast<SIMDBitselect>()->left); - self->pushTask(SubType::scan, &curr->cast<SIMDBitselect>()->right); self->pushTask(SubType::scan, &curr->cast<SIMDBitselect>()->cond); + self->pushTask(SubType::scan, &curr->cast<SIMDBitselect>()->right); + self->pushTask(SubType::scan, &curr->cast<SIMDBitselect>()->left); break; } case Expression::Id::SIMDShiftId: { self->pushTask(SubType::doVisitSIMDShift, currp); - self->pushTask(SubType::scan, &curr->cast<SIMDShift>()->vec); self->pushTask(SubType::scan, &curr->cast<SIMDShift>()->shift); + self->pushTask(SubType::scan, &curr->cast<SIMDShift>()->vec); break; } case Expression::Id::ConstId: { diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index a373a5ec6..bdd8f327e 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -2544,6 +2544,7 @@ bool WasmBinaryBuilder::maybeVisitSIMDLoad(Expression*& out, uint32_t code) { curr->type = v128; curr->bytes = 16; readMemoryAccess(curr->align, curr->offset); + curr->isAtomic = false; curr->ptr = popNonVoidExpression(); curr->finalize(); out = curr; @@ -2558,6 +2559,7 @@ bool WasmBinaryBuilder::maybeVisitSIMDStore(Expression*& out, uint32_t code) { curr->bytes = 16; curr->valueType = v128; readMemoryAccess(curr->align, curr->offset); + curr->isAtomic = false; curr->value = popNonVoidExpression(); curr->ptr = popNonVoidExpression(); curr->finalize(); diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index e1838bb71..7137e0860 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -502,7 +502,10 @@ void FunctionValidator::visitSetGlobal(SetGlobal* curr) { } void FunctionValidator::visitLoad(Load* curr) { - if (curr->isAtomic) shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); + if (curr->isAtomic) { + shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); + shouldBeTrue(curr->type == i32 || curr->type == i64 || curr->type == unreachable, curr, "Atomic load should be i32 or i64"); + } if (curr->type == v128) shouldBeTrue(info.features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)"); shouldBeFalse(curr->isAtomic && !getModule()->memory.shared, curr, "Atomic operation with non-shared memory"); validateMemBytes(curr->bytes, curr->type, curr); @@ -515,7 +518,10 @@ void FunctionValidator::visitLoad(Load* curr) { } void FunctionValidator::visitStore(Store* curr) { - if (curr->isAtomic) shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); + if (curr->isAtomic) { + shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); + shouldBeTrue(curr->valueType == i32 || curr->valueType == i64 || curr->valueType == unreachable, curr, "Atomic store should be i32 or i64"); + } if (curr->valueType == v128) shouldBeTrue(info.features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)"); shouldBeFalse(curr->isAtomic && !getModule()->memory.shared, curr, "Atomic operation with non-shared memory"); validateMemBytes(curr->bytes, curr->valueType, curr); diff --git a/test/passes/translate-to-fuzz.txt b/test/passes/translate-to-fuzz.txt index 50f5486cf..c175193cd 100644 --- a/test/passes/translate-to-fuzz.txt +++ b/test/passes/translate-to-fuzz.txt @@ -1,31 +1,47 @@ (module (type $FUNCSIG$v (func)) + (type $FUNCSIG$jddfiV (func (param f64 f64 f32 i32 v128) (result i64))) + (type $FUNCSIG$viViVjV (func (param i32 v128 i32 v128 i64 v128))) + (type $FUNCSIG$vd (func (param f64))) + (type $FUNCSIG$VVVVVii (func (param v128 v128 v128 v128 i32 i32) (result v128))) + (type $FUNCSIG$fddffj (func (param f64 f64 f32 f32 i64) (result f32))) + (type $FUNCSIG$j (func (result i64))) + (type $FUNCSIG$i (func (result i32))) + (type $FUNCSIG$f (func (result f32))) (import "fuzzing-support" "log-i32" (func $log-i32 (param i32))) (import "fuzzing-support" "log-i64" (func $log-i64 (param i64))) (import "fuzzing-support" "log-f32" (func $log-f32 (param f32))) (import "fuzzing-support" "log-f64" (func $log-f64 (param f64))) (memory $0 (shared 1 1)) (data (i32.const 0) "n\00\05E\00\00\00\00") - (table $0 2 2 anyfunc) - (elem (i32.const 0) $func_7 $func_11) + (table $0 6 6 anyfunc) + (elem (i32.const 0) $func_6 $func_12 $func_12 $func_12 $func_15 $func_16) (global $global$0 (mut f32) (f32.const 536870912)) (global $global$1 (mut f32) (f32.const 2147483648)) (global $global$2 (mut f64) (f64.const -1048576)) (global $global$3 (mut f64) (f64.const 23643)) (global $hangLimit (mut i32) (i32.const 10)) - (export "func_5_invoker" (func $func_5_invoker)) - (export "func_9_invoker" (func $func_9_invoker)) + (export "func_4" (func $func_4)) + (export "func_5" (func $func_5)) + (export "func_6_invoker" (func $func_6_invoker)) + (export "func_8" (func $func_8)) + (export "func_8_invoker" (func $func_8_invoker)) + (export "func_10" (func $func_10)) + (export "func_10_invoker" (func $func_10_invoker)) + (export "func_12" (func $func_12)) + (export "func_13" (func $func_13)) + (export "func_14" (func $func_14)) + (export "func_16" (func $func_16)) + (export "func_17" (func $func_17)) (export "hangLimitInitializer" (func $hangLimitInitializer)) - (func $func_4 (; 4 ;) (param $0 f32) (param $1 i64) (param $2 i32) (param $3 f32) (param $4 f64) (result f32) - (local $5 f32) + (func $func_4 (; 4 ;) (type $FUNCSIG$v) + (local $0 f64) (block (if (i32.eqz (get_global $hangLimit) ) - (return - (get_local $0) - ) + (return) ) (set_global $hangLimit (i32.sub @@ -35,56 +51,49 @@ ) ) (block $label$0 - (set_local $0 - (f32.const -32) - ) - (return - (get_local $5) - ) - ) - ) - (func $func_5 (; 5 ;) (result f64) - (local $0 i32) - (local $1 i32) - (local $2 i64) - (local $3 i32) - (block - (if - (i32.eqz - (get_global $hangLimit) - ) - (return - (f64.const 2.2250738585072014e-308) + (call $log-i32 + (loop $label$22 (result i32) + (block + (if + (i32.eqz + (get_global $hangLimit) + ) + (return) + ) + (set_global $hangLimit + (i32.sub + (get_global $hangLimit) + (i32.const 1) + ) + ) + ) + (block (result i32) + (call $log-i32 + (i32.const -16777216) + ) + (br_if $label$22 + (i32.const 520883468) + ) + (i32.const 925912624) + ) ) ) - (set_global $hangLimit - (i32.sub - (get_global $hangLimit) - (i32.const 1) + (set_local $0 + (tee_local $0 + (get_local $0) ) ) ) - (f64.const 1) - ) - (func $func_5_invoker (; 6 ;) (type $FUNCSIG$v) - (drop - (call $func_5) - ) - (drop - (call $func_5) - ) - (drop - (call $func_5) - ) ) - (func $func_7 (; 7 ;) (param $0 i32) (param $1 i32) (result i64) + (func $func_5 (; 5 ;) (type $FUNCSIG$jddfiV) (param $0 f64) (param $1 f64) (param $2 f32) (param $3 i32) (param $4 v128) (result i64) + (local $5 i32) (block (if (i32.eqz (get_global $hangLimit) ) (return - (i64.const -125) + (i64.const 1) ) ) (set_global $hangLimit @@ -94,38 +103,37 @@ ) ) ) - (i64.const -9223372036854775807) - ) - (func $func_8 (; 8 ;) (param $0 f32) (param $1 i32) (result i64) - (block - (if - (i32.eqz - (get_global $hangLimit) - ) - (return - (i64.const 1872) - ) - ) - (set_global $hangLimit - (i32.sub - (get_global $hangLimit) - (i32.const 1) - ) + (block $label$0 + (nop) + (return + (i64.const -16777216) ) ) - (i64.const 1) ) - (func $func_9 (; 9 ;) (param $0 i64) (result i32) - (local $1 i64) - (local $2 f32) - (local $3 i64) + (func $func_6 (; 6 ;) (param $0 i32) (result i64) + (local $1 v128) + (local $2 f64) + (local $3 i32) + (local $4 v128) + (local $5 f64) + (local $6 f32) + (local $7 i64) + (local $8 i64) + (local $9 f64) + (local $10 i64) + (local $11 i64) + (local $12 v128) + (local $13 f32) + (local $14 i32) + (local $15 f64) + (local $16 f32) (block (if (i32.eqz (get_global $hangLimit) ) (return - (i32.const 20313) + (get_local $7) ) ) (set_global $hangLimit @@ -135,35 +143,22 @@ ) ) ) - (i32.const -8192) + (i64.const 18014398509481984) ) - (func $func_9_invoker (; 10 ;) (type $FUNCSIG$v) + (func $func_6_invoker (; 7 ;) (type $FUNCSIG$v) (drop - (call $func_9 - (i64.const 6780181376769203038) - ) - ) - (drop - (call $func_9 - (i64.const 939691058929557011) + (call $func_6 + (i32.const 225118223) ) ) ) - (func $func_11 (; 11 ;) (param $0 i64) (param $1 f64) (param $2 f32) (param $3 f64) (result i32) - (local $4 f32) - (local $5 i64) - (local $6 f32) - (local $7 i64) - (local $8 i32) - (local $9 i32) + (func $func_8 (; 8 ;) (type $FUNCSIG$viViVjV) (param $0 i32) (param $1 v128) (param $2 i32) (param $3 v128) (param $4 i64) (param $5 v128) (block (if (i32.eqz (get_global $hangLimit) ) - (return - (i32.const -72) - ) + (return) ) (set_global $hangLimit (i32.sub @@ -172,34 +167,16 @@ ) ) ) - (loop $label$0 (result i32) - (block - (if - (i32.eqz - (get_global $hangLimit) - ) - (return - (get_local $9) - ) - ) - (set_global $hangLimit - (i32.sub - (get_global $hangLimit) - (i32.const 1) - ) - ) - ) - (block $label$1 (result i32) - (if - (loop $label$2 (result i32) + (block $label$0 + (set_local $5 + (tee_local $5 + (loop $label$1 (result v128) (block (if (i32.eqz (get_global $hangLimit) ) - (return - (i32.const 1499158319) - ) + (return) ) (set_global $hangLimit (i32.sub @@ -208,19 +185,17 @@ ) ) ) - (block (result i32) - (block $label$3 - (set_local $6 - (if (result f32) - (loop $label$4 (result i32) + (block (result v128) + (drop + (if (result i32) + (i32.eqz + (loop $label$25 (block (if (i32.eqz (get_global $hangLimit) ) - (return - (get_local $9) - ) + (return) ) (set_global $hangLimit (i32.sub @@ -229,232 +204,57 @@ ) ) ) - (block (result i32) - (block $label$5 - (set_local $3 - (get_local $1) - ) - (set_local $6 - (get_local $2) - ) - ) - (br_if $label$4 - (tee_local $8 - (tee_local $9 - (tee_local $8 - (tee_local $8 - (tee_local $9 - (get_local $9) - ) - ) - ) + (block + (block $label$26 + (if + (get_local $0) + (nop) + (block $label$27 + (nop) + (nop) ) ) - ) - (loop $label$9 (result i32) - (block - (if - (i32.eqz - (get_global $hangLimit) - ) - (return - (i32.const -42) - ) - ) - (set_global $hangLimit - (i32.sub - (get_global $hangLimit) - (i32.const 1) - ) - ) + (block $label$28 + (nop) ) - (i32.trunc_u:sat/f64 - (loop $label$10 (result f64) - (block - (if - (i32.eqz - (get_global $hangLimit) - ) - (return - (i32.const -127) - ) - ) - (set_global $hangLimit - (i32.sub - (get_global $hangLimit) - (i32.const 1) - ) - ) + (set_local $4 + (block $label$29 (result i64) + (call $log-f64 + (f64.const 72) ) - (loop $label$11 (result f64) - (block - (if - (i32.eqz - (get_global $hangLimit) - ) - (return - (get_local $8) - ) - ) - (set_global $hangLimit - (i32.sub - (get_global $hangLimit) - (i32.const 1) - ) - ) - ) - (block (result f64) - (set_local $5 - (tee_local $0 - (i64.const 281474976710656) - ) - ) - (br_if $label$11 - (i32.const 16) - ) - (loop $label$12 (result f64) - (block - (if - (i32.eqz - (get_global $hangLimit) - ) - (return - (i32.const -65536) + (tee_local $4 + (tee_local $4 + (tee_local $4 + (br_if $label$29 + (block $label$30 (result i64) + (br_if $label$25 + (get_local $2) ) + (i64.const 4294967229) ) - (set_global $hangLimit - (i32.sub - (get_global $hangLimit) - (i32.const 1) - ) + (i32.eqz + (i32.const 0) ) ) - (get_local $1) ) ) ) ) ) ) - ) - ) - (tee_local $2 - (if (result f32) - (i32.eqz - (loop $label$13 (result i32) - (block - (if - (i32.eqz - (get_global $hangLimit) - ) - (return - (i32.const -65536) - ) - ) - (set_global $hangLimit - (i32.sub - (get_global $hangLimit) - (i32.const 1) - ) - ) - ) - (block (result i32) - (block $label$14 - (if - (i32.const 0) - (block $label$15 - (call $log-f64 - (f64.const -2) - ) - (set_local $4 - (get_local $2) - ) - ) - (set_local $0 - (i64.const 65510) - ) - ) - (call $log-i32 - (loop $label$16 (result i32) - (block - (if - (i32.eqz - (get_global $hangLimit) - ) - (return - (get_local $9) - ) - ) - (set_global $hangLimit - (i32.sub - (get_global $hangLimit) - (i32.const 1) - ) - ) - ) - (block (result i32) - (nop) - (br_if $label$16 - (i32.eqz - (get_local $8) - ) - ) - (i32.const -71) - ) - ) - ) - ) - (br_if $label$13 - (get_local $9) - ) - (br_if $label$1 - (if (result i32) - (i32.eqz - (tee_local $8 - (i32.const -65536) - ) - ) - (block $label$24 (result i32) - (set_local $0 - (i64.const -127) - ) - (call $func_11 - (get_local $7) - (f64.const 3402823466385288598117041e14) - (f32.const 2305843009213693952) - (get_local $3) - ) - ) - (tee_local $9 - (i32.const 1162292275) - ) - ) - (i32.eqz - (if (result i32) - (get_local $8) - (i32.const 1024) - (block $label$22 (result i32) - (set_local $0 - (i64.const 36028797018963968) - ) - (loop $label$23 (result i32) - (block - (if - (i32.eqz - (get_global $hangLimit) - ) - (return - (i32.const -65536) - ) - ) - (set_global $hangLimit - (i32.sub - (get_global $hangLimit) - (i32.const 1) - ) + (br_if $label$25 + (i32.eqz + (tee_local $0 + (tee_local $2 + (tee_local $0 + (tee_local $0 + (tee_local $0 + (tee_local $0 + (tee_local $2 + (tee_local $0 + (i32.const 1215581264) ) ) - (get_local $8) ) ) ) @@ -463,54 +263,14 @@ ) ) ) - (get_local $4) - (get_local $2) - ) - ) - (block $label$25 (result f32) - (loop $label$26 - (block - (if - (i32.eqz - (get_global $hangLimit) - ) - (return - (i32.const 1465597219) - ) - ) - (set_global $hangLimit - (i32.sub - (get_global $hangLimit) - (i32.const 1) - ) - ) - ) - (block - (set_local $5 - (i64.const 1877285765241048336) - ) - (br_if $label$26 - (i32.const -127) - ) - (set_local $6 - (get_local $2) - ) - ) - ) - (br_if $label$25 - (br_if $label$25 - (tee_local $4 - (f32.const 4294967296) - ) - (loop $label$29 (result i32) + (tee_local $0 + (loop $label$31 (block (if (i32.eqz (get_global $hangLimit) ) - (return - (i32.const -88) - ) + (return) ) (set_global $hangLimit (i32.sub @@ -519,353 +279,282 @@ ) ) ) - (block (result i32) - (block $label$30 - (set_local $3 - (if (result f64) - (i32.const 32767) - (block $label$31 - (set_local $9 - (get_local $8) - ) - (br $label$29) - ) - (f64.const 4) - ) - ) - (set_local $3 - (get_local $1) - ) - ) - (br_if $label$29 - (tee_local $9 - (tee_local $9 - (tee_local $8 - (get_local $8) - ) - ) - ) - ) - (if (result i32) - (block $label$32 (result i32) - (call $log-f32 - (get_local $2) - ) - (i32.const -32768) - ) - (block $label$33 (result i32) - (loop $label$34 - (block - (if - (i32.eqz - (get_global $hangLimit) - ) - (return - (get_local $8) - ) - ) - (set_global $hangLimit - (i32.sub - (get_global $hangLimit) - (i32.const 1) - ) - ) - ) - (block - (block $label$35 - (nop) - (if - (tee_local $9 - (i32.const -32768) - ) - (nop) - (set_local $9 - (get_local $8) - ) - ) - ) - (br_if $label$34 - (i32.eqz - (i32.const -69) - ) - ) - (call $log-i32 - (i32.const 5) - ) - ) - ) - (tee_local $8 - (tee_local $9 - (i32.const -128) - ) - ) - ) - (get_local $9) + (block $label$32 + (set_local $2 + (i32.const -127) ) + (br $label$25) ) ) ) - (i32.eqz - (get_local $8) - ) ) ) ) - ) - (nop) - ) - (br_if $label$2 - (tee_local $9 - (tee_local $9 - (tee_local $9 - (tee_local $9 - (get_local $9) - ) - ) + (i32.const 9282) + (block $label$33 (result i32) + (get_local $0) ) ) ) - (i32.const 7) + (br_if $label$1 + (i32.const -1) + ) + (v128.const i32 0xb2 0xc0 0x0 0xb 0x0 0x2 0x1 0x1f 0x1 0xff 0x0 0xff 0x0 0xed 0xf 0xff) ) ) - (block $label$45 - (set_local $5 - (get_local $5) - ) + ) + ) + (set_local $5 + (v128.const i32 0x0 0x0 0x19 0x80 0x1b 0x2 0x0 0xeb 0x4a 0x1a 0x0 0x7f 0x80 0x12 0x5d 0x0) + ) + ) + ) + (func $func_8_invoker (; 9 ;) (type $FUNCSIG$v) + (call $func_8 + (i32.const 68) + (v128.const i32 0x70 0x38 0x37 0x25 0x3d 0x79 0x3c 0x31 0x2 0x9 0xc 0x15 0xa 0x3 0x4c 0x1f) + (i32.const 420088586) + (v128.const i32 0x9 0x1b 0xfe 0xff 0x0 0x0 0xfe 0xff 0x15 0x16 0xb 0x5f 0xe6 0xff 0x3d 0x46) + (i64.const 2055) + (v128.const i32 0x0 0x0 0x0 0x0 0x0 0x0 0xe0 0x43 0x0 0x0 0x0 0x0 0x0 0x60 0x6c 0x40) + ) + ) + (func $func_10 (; 10 ;) (type $FUNCSIG$vd) (param $0 f64) + (local $1 i32) + (local $2 i64) + (local $3 f64) + (local $4 f64) + (block + (if + (i32.eqz + (get_global $hangLimit) + ) + (return) + ) + (set_global $hangLimit + (i32.sub + (get_global $hangLimit) + (i32.const 1) + ) + ) + ) + (block $label$0 + (nop) + (br_if $label$0 + (get_local $1) + ) + ) + ) + (func $func_10_invoker (; 11 ;) (type $FUNCSIG$v) + (call $func_10 + (f64.const -nan:0xfffffffffffac) + ) + (call $func_10 + (f64.const -81) + ) + (call $func_10 + (f64.const -91) + ) + ) + (func $func_12 (; 12 ;) (type $FUNCSIG$VVVVVii) (param $0 v128) (param $1 v128) (param $2 v128) (param $3 v128) (param $4 i32) (param $5 i32) (result v128) + (block + (if + (i32.eqz + (get_global $hangLimit) + ) + (return + (v128.const i32 0x0 0x0 0x4 0xff 0x46 0x1d 0x37 0xff 0x2 0x0 0x0 0x6f 0x18 0x43 0x0 0x0) + ) + ) + (set_global $hangLimit + (i32.sub + (get_global $hangLimit) + (i32.const 1) + ) + ) + ) + (block $label$0 + (call $log-i64 + (i64.const -17179869184) + ) + (return + (get_local $0) + ) + ) + ) + (func $func_13 (; 13 ;) (type $FUNCSIG$fddffj) (param $0 f64) (param $1 f64) (param $2 f32) (param $3 f32) (param $4 i64) (result f32) + (local $5 f32) + (block + (if + (i32.eqz + (get_global $hangLimit) + ) + (return + (get_local $3) + ) + ) + (set_global $hangLimit + (i32.sub + (get_global $hangLimit) + (i32.const 1) + ) + ) + ) + (block $label$0 + (nop) + (return + (f32.const -562949953421312) + ) + ) + ) + (func $func_14 (; 14 ;) (type $FUNCSIG$j) (result i64) + (local $0 v128) + (block + (if + (i32.eqz + (get_global $hangLimit) + ) + (return + (i64.const -4294967295) + ) + ) + (set_global $hangLimit + (i32.sub + (get_global $hangLimit) + (i32.const 1) + ) + ) + ) + (block $label$0 + (call $log-f64 + (f64.const 3.0085765013203267e-46) + ) + (return + (i64.const 117901063) + ) + ) + ) + (func $func_15 (; 15 ;) + (local $0 v128) + (local $1 i64) + (local $2 i32) + (local $3 f64) + (local $4 f64) + (local $5 v128) + (local $6 i64) + (block + (if + (i32.eqz + (get_global $hangLimit) + ) + (return) + ) + (set_global $hangLimit + (i32.sub + (get_global $hangLimit) + (i32.const 1) + ) + ) + ) + (block $label$0 + (set_local $5 + (v128.const i32 0x4e 0x5d 0x1b 0x5d 0x54 0x1b 0x48 0x48 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xf8) + ) + (nop) + ) + ) + (func $func_16 (; 16 ;) (type $FUNCSIG$i) (result i32) + (block + (if + (i32.eqz + (get_global $hangLimit) + ) + (return + (i32.const 0) + ) + ) + (set_global $hangLimit + (i32.sub + (get_global $hangLimit) + (i32.const 1) + ) + ) + ) + (loop $label$0 (result i32) + (block + (if + (i32.eqz + (get_global $hangLimit) ) - (block $label$46 - (nop) - (if - (loop $label$47 (result i32) - (block - (if - (i32.eqz - (get_global $hangLimit) - ) - (return - (i32.const -32768) - ) - ) - (set_global $hangLimit - (i32.sub - (get_global $hangLimit) - (i32.const 1) - ) - ) - ) - (block (result i32) - (block $label$48 - (set_local $8 - (tee_local $8 - (tee_local $8 - (tee_local $8 - (tee_local $9 - (tee_local $9 - (tee_local $8 - (get_local $9) - ) - ) - ) - ) - ) - ) - ) - (if - (get_local $8) - (block $label$49 - (set_global $global$3 - (get_local $3) - ) - (set_local $3 - (f64.const 274877906944) - ) - ) - (block $label$64 - (set_local $5 - (i64.const -32) - ) - (set_local $1 - (get_local $1) - ) - ) - ) - ) - (br_if $label$47 - (get_local $9) - ) - (block $label$66 (result i32) - (set_local $6 - (get_local $4) - ) - (if (result i32) - (i32.eqz - (get_local $8) - ) - (block $label$67 (result i32) - (br_if $label$46 - (i32.eqz - (get_local $8) - ) - ) - (tee_local $8 - (loop $label$68 (result i32) - (block - (if - (i32.eqz - (get_global $hangLimit) - ) - (return - (get_local $8) - ) - ) - (set_global $hangLimit - (i32.sub - (get_global $hangLimit) - (i32.const 1) - ) - ) - ) - (block (result i32) - (set_local $8 - (tee_local $9 - (tee_local $9 - (i32.const 32767) - ) - ) - ) - (br_if $label$68 - (i32.eqz - (call $func_11 - (i64.const 8245) - (get_local $3) - (block $label$69 (result f32) - (if - (i32.const 1001235) - (set_local $7 - (if (result i64) - (get_local $9) - (get_local $0) - (i64.const 32768) - ) - ) - (set_local $7 - (get_local $0) - ) - ) - (f32.const 23316) - ) - (loop $label$70 (result f64) - (block - (if - (i32.eqz - (get_global $hangLimit) - ) - (return - (i32.const -8388608) - ) - ) - (set_global $hangLimit - (i32.sub - (get_global $hangLimit) - (i32.const 1) - ) - ) - ) - (block (result f64) - (nop) - (br_if $label$70 - (tee_local $9 - (i32.const 134217728) - ) - ) - (get_local $3) - ) - ) - ) - ) - ) - (tee_local $8 - (tee_local $8 - (tee_local $8 - (i32.const 167) - ) - ) - ) - ) - ) - ) - ) - (block $label$72 - (set_local $6 - (get_local $2) - ) - (br $label$46) - ) - ) - ) - ) - ) - (block $label$73 - (set_local $1 - (block $label$74 (result f64) - (call $log-i64 - (i64.const 108) - ) - (tee_local $3 - (f64.const 9223372036854775808) - ) - ) - ) - (call $log-i64 - (tee_local $0 - (loop $label$75 - (block - (if - (i32.eqz - (get_global $hangLimit) - ) - (return - (get_local $8) - ) - ) - (set_global $hangLimit - (i32.sub - (get_global $hangLimit) - (i32.const 1) - ) - ) - ) - (block $label$76 - (set_local $9 - (tee_local $8 - (i32.const 80) - ) - ) - (br $label$46) - ) - ) - ) - ) - ) - (set_local $9 - (i32.const -1024) - ) + (return + (i32.const 32767) + ) + ) + (set_global $hangLimit + (i32.sub + (get_global $hangLimit) + (i32.const 1) + ) + ) + ) + (block (result i32) + (block $label$1 + (block $label$2 + (block $label$3 + (nop) + (nop) ) + (nop) ) + (nop) + (nop) + ) + (br_if $label$0 + (i32.const 1147035403) + ) + (i32.const 1024) + ) + ) + ) + (func $func_17 (; 17 ;) (type $FUNCSIG$f) (result f32) + (block + (if + (i32.eqz + (get_global $hangLimit) ) - (br_if $label$1 - (get_local $9) - (get_local $9) + (return + (f32.const 865309568) ) ) + (set_global $hangLimit + (i32.sub + (get_global $hangLimit) + (i32.const 1) + ) + ) + ) + (if (result f32) + (i32.eqz + (if (result i32) + (i32.const 709182789) + (i32.const -4) + (i32.const 873467920) + ) + ) + (block $label$5 (result f32) + (f32.const 59953536565248) + ) + (block $label$6 (result f32) + (f32.const 1) + ) ) ) - (func $hangLimitInitializer (; 12 ;) + (func $hangLimitInitializer (; 18 ;) (set_global $hangLimit (i32.const 10) ) ) - (func $deNan32 (; 13 ;) (param $0 f32) (result f32) + (func $deNan32 (; 19 ;) (param $0 f32) (result f32) (if (result f32) (f32.eq (get_local $0) @@ -875,7 +564,7 @@ (f32.const 0) ) ) - (func $deNan64 (; 14 ;) (param $0 f64) (result f64) + (func $deNan64 (; 20 ;) (param $0 f64) (result f64) (if (result f64) (f64.eq (get_local $0) |