/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef builtin_SIMD_h #define builtin_SIMD_h #include "jsapi.h" #include "jsobj.h" #include "builtin/TypedObject.h" #include "js/Conversions.h" #include "vm/GlobalObject.h" /* * JS SIMD functions. * Spec matching polyfill: * https://github.com/johnmccutchan/ecmascript_simd/blob/master/src/ecmascript_simd.js */ #define FLOAT32X4_UNARY_FUNCTION_LIST(V) \ V(abs, (UnaryFunc), 1) \ V(check, (UnaryFunc), 1) \ V(fromFloat64x2, (FuncConvert ), 1) \ V(fromFloat64x2Bits, (FuncConvertBits), 1) \ V(fromInt8x16Bits, (FuncConvertBits), 1) \ V(fromInt16x8Bits, (FuncConvertBits), 1) \ V(fromInt32x4, (FuncConvert ), 1) \ V(fromInt32x4Bits, (FuncConvertBits), 1) \ V(neg, (UnaryFunc), 1) \ V(not, (CoercedUnaryFunc), 1) \ V(reciprocalApproximation, (UnaryFunc), 1) \ V(reciprocalSqrtApproximation, (UnaryFunc), 1) \ V(splat, (FuncSplat), 1) \ V(sqrt, (UnaryFunc), 1) #define FLOAT32X4_BINARY_FUNCTION_LIST(V) \ V(add, (BinaryFunc), 2) \ V(and, (CoercedBinaryFunc), 2) \ V(div, (BinaryFunc), 2) \ V(equal, (CompareFunc), 2) \ V(extractLane, (ExtractLane), 2) \ V(greaterThan, (CompareFunc), 2) \ V(greaterThanOrEqual, (CompareFunc), 2) \ V(lessThan, (CompareFunc), 2) \ V(lessThanOrEqual, (CompareFunc), 2) \ V(load, (Load), 2) \ V(load3, (Load), 2) \ V(load2, (Load), 2) \ V(load1, (Load), 2) \ V(max, (BinaryFunc), 2) \ V(maxNum, (BinaryFunc), 2) \ V(min, (BinaryFunc), 2) \ V(minNum, (BinaryFunc), 2) \ V(mul, (BinaryFunc), 2) \ V(notEqual, (CompareFunc), 2) \ V(or, (CoercedBinaryFunc), 2) \ V(sub, (BinaryFunc), 2) \ V(xor, (CoercedBinaryFunc), 2) #define FLOAT32X4_TERNARY_FUNCTION_LIST(V) \ V(replaceLane, (ReplaceLane), 3) \ V(select, (Select), 3) \ V(store, (Store), 3) \ V(store3, (Store), 3) \ V(store2, (Store), 3) \ V(store1, (Store), 3) #define FLOAT32X4_SHUFFLE_FUNCTION_LIST(V) \ V(swizzle, Swizzle, 5) \ V(shuffle, Shuffle, 6) #define FLOAT32X4_FUNCTION_LIST(V) \ FLOAT32X4_UNARY_FUNCTION_LIST(V) \ FLOAT32X4_BINARY_FUNCTION_LIST(V) \ FLOAT32X4_TERNARY_FUNCTION_LIST(V) \ FLOAT32X4_SHUFFLE_FUNCTION_LIST(V) #define FLOAT64X2_UNARY_FUNCTION_LIST(V) \ V(abs, (UnaryFunc), 1) \ V(check, (UnaryFunc), 1) \ V(fromFloat32x4, (FuncConvert ), 1) \ V(fromFloat32x4Bits, (FuncConvertBits), 1) \ V(fromInt8x16Bits, (FuncConvertBits), 1) \ V(fromInt16x8Bits, (FuncConvertBits), 1) \ V(fromInt32x4, (FuncConvert ), 1) \ V(fromInt32x4Bits, (FuncConvertBits), 1) \ V(neg, (UnaryFunc), 1) \ V(reciprocalApproximation, (UnaryFunc), 1) \ V(reciprocalSqrtApproximation, (UnaryFunc), 1) \ V(splat, (FuncSplat), 1) \ V(sqrt, (UnaryFunc), 1) #define FLOAT64X2_BINARY_FUNCTION_LIST(V) \ V(add, (BinaryFunc), 2) \ V(div, (BinaryFunc), 2) \ V(equal, (CompareFunc), 2) \ V(extractLane, (ExtractLane), 2) \ V(greaterThan, (CompareFunc), 2) \ V(greaterThanOrEqual, (CompareFunc), 2) \ V(lessThan, (CompareFunc), 2) \ V(lessThanOrEqual, (CompareFunc), 2) \ V(load, (Load), 2) \ V(load1, (Load), 2) \ V(max, (BinaryFunc), 2) \ V(maxNum, (BinaryFunc), 2) \ V(min, (BinaryFunc), 2) \ V(minNum, (BinaryFunc), 2) \ V(mul, (BinaryFunc), 2) \ V(notEqual, (CompareFunc), 2) \ V(sub, (BinaryFunc), 2) #define FLOAT64X2_TERNARY_FUNCTION_LIST(V) \ V(replaceLane, (ReplaceLane), 3) \ V(select, (Select), 3) \ V(store, (Store), 3) \ V(store1, (Store), 3) #define FLOAT64X2_SHUFFLE_FUNCTION_LIST(V) \ V(swizzle, Swizzle, 3) \ V(shuffle, Shuffle, 4) #define FLOAT64X2_FUNCTION_LIST(V) \ FLOAT64X2_UNARY_FUNCTION_LIST(V) \ FLOAT64X2_BINARY_FUNCTION_LIST(V) \ FLOAT64X2_TERNARY_FUNCTION_LIST(V) \ FLOAT64X2_SHUFFLE_FUNCTION_LIST(V) #define INT8X16_UNARY_FUNCTION_LIST(V) \ V(check, (UnaryFunc), 1) \ V(fromFloat32x4Bits, (FuncConvertBits), 1) \ V(fromFloat64x2Bits, (FuncConvertBits), 1) \ V(fromInt16x8Bits, (FuncConvertBits), 1) \ V(fromInt32x4Bits, (FuncConvertBits), 1) \ V(neg, (UnaryFunc), 1) \ V(not, (UnaryFunc), 1) \ V(splat, (FuncSplat), 1) #define INT8X16_BINARY_FUNCTION_LIST(V) \ V(add, (BinaryFunc), 2) \ V(and, (BinaryFunc), 2) \ V(equal, (CompareFunc), 2) \ V(extractLane, (ExtractLane), 2) \ V(greaterThan, (CompareFunc), 2) \ V(greaterThanOrEqual, (CompareFunc), 2) \ V(lessThan, (CompareFunc), 2) \ V(lessThanOrEqual, (CompareFunc), 2) \ V(load, (Load), 2) \ V(mul, (BinaryFunc), 2) \ V(notEqual, (CompareFunc), 2) \ V(or, (BinaryFunc), 2) \ V(sub, (BinaryFunc), 2) \ V(shiftLeftByScalar, (BinaryScalar), 2) \ V(shiftRightArithmeticByScalar, (BinaryScalar), 2) \ V(shiftRightLogicalByScalar, (BinaryScalar), 2) \ V(xor, (BinaryFunc), 2) #define INT8X16_TERNARY_FUNCTION_LIST(V) \ V(replaceLane, (ReplaceLane), 3) \ V(select, (Select), 3) \ V(selectBits, (SelectBits), 3) \ V(store, (Store), 3) #define INT8X16_SHUFFLE_FUNCTION_LIST(V) \ V(swizzle, Swizzle, 17) \ V(shuffle, Shuffle, 18) #define INT8X16_FUNCTION_LIST(V) \ INT8X16_UNARY_FUNCTION_LIST(V) \ INT8X16_BINARY_FUNCTION_LIST(V) \ INT8X16_TERNARY_FUNCTION_LIST(V) \ INT8X16_SHUFFLE_FUNCTION_LIST(V) #define INT16X8_UNARY_FUNCTION_LIST(V) \ V(check, (UnaryFunc), 1) \ V(fromFloat32x4Bits, (FuncConvertBits), 1) \ V(fromFloat64x2Bits, (FuncConvertBits), 1) \ V(fromInt8x16Bits, (FuncConvertBits), 1) \ V(fromInt32x4Bits, (FuncConvertBits), 1) \ V(neg, (UnaryFunc), 1) \ V(not, (UnaryFunc), 1) \ V(splat, (FuncSplat), 1) #define INT16X8_BINARY_FUNCTION_LIST(V) \ V(add, (BinaryFunc), 2) \ V(and, (BinaryFunc), 2) \ V(equal, (CompareFunc), 2) \ V(extractLane, (ExtractLane), 2) \ V(greaterThan, (CompareFunc), 2) \ V(greaterThanOrEqual, (CompareFunc), 2) \ V(lessThan, (CompareFunc), 2) \ V(lessThanOrEqual, (CompareFunc), 2) \ V(load, (Load), 2) \ V(mul, (BinaryFunc), 2) \ V(notEqual, (CompareFunc), 2) \ V(or, (BinaryFunc), 2) \ V(sub, (BinaryFunc), 2) \ V(shiftLeftByScalar, (BinaryScalar), 2) \ V(shiftRightArithmeticByScalar, (BinaryScalar), 2) \ V(shiftRightLogicalByScalar, (BinaryScalar), 2) \ V(xor, (BinaryFunc), 2) #define INT16X8_TERNARY_FUNCTION_LIST(V) \ V(replaceLane, (ReplaceLane), 3) \ V(select, (Select), 3) \ V(selectBits, (SelectBits), 3) \ V(store, (Store), 3) #define INT16X8_SHUFFLE_FUNCTION_LIST(V) \ V(swizzle, Swizzle, 9) \ V(shuffle, Shuffle, 10) #define INT16X8_FUNCTION_LIST(V) \ INT16X8_UNARY_FUNCTION_LIST(V) \ INT16X8_BINARY_FUNCTION_LIST(V) \ INT16X8_TERNARY_FUNCTION_LIST(V) \ INT16X8_SHUFFLE_FUNCTION_LIST(V) #define INT32X4_UNARY_FUNCTION_LIST(V) \ V(check, (UnaryFunc), 1) \ V(fromFloat32x4, (FuncConvert), 1) \ V(fromFloat32x4Bits, (FuncConvertBits), 1) \ V(fromFloat64x2, (FuncConvert), 1) \ V(fromFloat64x2Bits, (FuncConvertBits), 1) \ V(fromInt8x16Bits, (FuncConvertBits), 1) \ V(fromInt16x8Bits, (FuncConvertBits), 1) \ V(neg, (UnaryFunc), 1) \ V(not, (UnaryFunc), 1) \ V(splat, (FuncSplat), 0) #define INT32X4_BINARY_FUNCTION_LIST(V) \ V(add, (BinaryFunc), 2) \ V(and, (BinaryFunc), 2) \ V(equal, (CompareFunc), 2) \ V(extractLane, (ExtractLane), 2) \ V(greaterThan, (CompareFunc), 2) \ V(greaterThanOrEqual, (CompareFunc), 2) \ V(lessThan, (CompareFunc), 2) \ V(lessThanOrEqual, (CompareFunc), 2) \ V(load, (Load), 2) \ V(load3, (Load), 2) \ V(load2, (Load), 2) \ V(load1, (Load), 2) \ V(mul, (BinaryFunc), 2) \ V(notEqual, (CompareFunc), 2) \ V(or, (BinaryFunc), 2) \ V(sub, (BinaryFunc), 2) \ V(shiftLeftByScalar, (BinaryScalar), 2) \ V(shiftRightArithmeticByScalar, (BinaryScalar), 2) \ V(shiftRightLogicalByScalar, (BinaryScalar), 2) \ V(xor, (BinaryFunc), 2) #define INT32X4_TERNARY_FUNCTION_LIST(V) \ V(replaceLane, (ReplaceLane), 3) \ V(select, (Select), 3) \ V(selectBits, (SelectBits), 3) \ V(store, (Store), 3) \ V(store3, (Store), 3) \ V(store2, (Store), 3) \ V(store1, (Store), 3) #define INT32X4_SHUFFLE_FUNCTION_LIST(V) \ V(swizzle, Swizzle, 5) \ V(shuffle, Shuffle, 6) #define INT32X4_FUNCTION_LIST(V) \ INT32X4_UNARY_FUNCTION_LIST(V) \ INT32X4_BINARY_FUNCTION_LIST(V) \ INT32X4_TERNARY_FUNCTION_LIST(V) \ INT32X4_SHUFFLE_FUNCTION_LIST(V) #define CONVERSION_INT32X4_SIMD_OP(_) \ _(fromFloat32x4) \ _(fromFloat32x4Bits) #define FOREACH_INT32X4_SIMD_OP(_) \ CONVERSION_INT32X4_SIMD_OP(_) \ _(selectBits) \ _(shiftLeftByScalar) \ _(shiftRightArithmeticByScalar) \ _(shiftRightLogicalByScalar) #define UNARY_ARITH_FLOAT32X4_SIMD_OP(_) \ _(abs) \ _(sqrt) \ _(reciprocalApproximation) \ _(reciprocalSqrtApproximation) #define BINARY_ARITH_FLOAT32X4_SIMD_OP(_) \ _(div) \ _(max) \ _(min) \ _(maxNum) \ _(minNum) #define FOREACH_FLOAT32X4_SIMD_OP(_) \ UNARY_ARITH_FLOAT32X4_SIMD_OP(_) \ BINARY_ARITH_FLOAT32X4_SIMD_OP(_)\ _(fromInt32x4) \ _(fromInt32x4Bits) #define ARITH_COMMONX4_SIMD_OP(_) \ _(add) \ _(sub) \ _(mul) #define BITWISE_COMMONX4_SIMD_OP(_) \ _(and) \ _(or) \ _(xor) #define COMP_COMMONX4_TO_INT32X4_SIMD_OP(_) \ _(lessThan) \ _(lessThanOrEqual) \ _(equal) \ _(notEqual) \ _(greaterThan) \ _(greaterThanOrEqual) // TODO: remove when all SIMD calls are inlined (bug 1112155) #define ION_COMMONX4_SIMD_OP(_) \ ARITH_COMMONX4_SIMD_OP(_) \ BITWISE_COMMONX4_SIMD_OP(_) \ _(extractLane) \ _(replaceLane) \ _(select) \ _(splat) \ _(not) \ _(neg) \ _(swizzle) \ _(shuffle) \ _(load) \ _(load1) \ _(load2) \ _(load3) \ _(store) \ _(store1) \ _(store2) \ _(store3) \ _(check) #define FOREACH_COMMONX4_SIMD_OP(_) \ ION_COMMONX4_SIMD_OP(_) \ COMP_COMMONX4_TO_INT32X4_SIMD_OP(_) #define FORALL_SIMD_OP(_) \ FOREACH_INT32X4_SIMD_OP(_) \ FOREACH_FLOAT32X4_SIMD_OP(_) \ FOREACH_COMMONX4_SIMD_OP(_) namespace js { class SIMDObject : public JSObject { public: static const Class class_; static bool toString(JSContext* cx, unsigned int argc, Value* vp); }; // These classes implement the concept containing the following constraints: // - requires typename Elem: this is the scalar lane type, stored in each lane // of the SIMD vector. // - requires static const unsigned lanes: this is the number of lanes (length) // of the SIMD vector. // - requires static const SimdTypeDescr::Type type: this is the SimdTypeDescr // enum value corresponding to the SIMD type. // - requires static bool Cast(JSContext*, JS::HandleValue, Elem*): casts a // given Value to the current scalar lane type and saves it in the Elem // out-param. // - requires static Value ToValue(Elem): returns a Value of the right type // containing the given value. // // This concept is used in the templates above to define the functions // associated to a given type and in their implementations, to avoid code // redundancy. struct Float32x4 { typedef float Elem; static const unsigned lanes = 4; static const SimdTypeDescr::Type type = SimdTypeDescr::Float32x4; static bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { double d; if (!ToNumber(cx, v, &d)) return false; *out = float(d); return true; } static Value ToValue(Elem value) { return DoubleValue(JS::CanonicalizeNaN(value)); } }; struct Float64x2 { typedef double Elem; static const unsigned lanes = 2; static const SimdTypeDescr::Type type = SimdTypeDescr::Float64x2; static bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { return ToNumber(cx, v, out); } static Value ToValue(Elem value) { return DoubleValue(JS::CanonicalizeNaN(value)); } }; struct Int8x16 { typedef int8_t Elem; static const unsigned lanes = 16; static const SimdTypeDescr::Type type = SimdTypeDescr::Int8x16; static bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { return ToInt8(cx, v, out); } static Value ToValue(Elem value) { return Int32Value(value); } }; struct Int16x8 { typedef int16_t Elem; static const unsigned lanes = 8; static const SimdTypeDescr::Type type = SimdTypeDescr::Int16x8; static bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { return ToInt16(cx, v, out); } static Value ToValue(Elem value) { return Int32Value(value); } }; struct Int32x4 { typedef int32_t Elem; static const unsigned lanes = 4; static const SimdTypeDescr::Type type = SimdTypeDescr::Int32x4; static bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { return ToInt32(cx, v, out); } static Value ToValue(Elem value) { return Int32Value(value); } }; template JSObject* CreateSimd(JSContext* cx, const typename V::Elem* data); template bool IsVectorObject(HandleValue v); template bool ToSimdConstant(JSContext* cx, HandleValue v, jit::SimdConstant* out); #define DECLARE_SIMD_FLOAT32X4_FUNCTION(Name, Func, Operands) \ extern bool \ simd_float32x4_##Name(JSContext* cx, unsigned argc, Value* vp); FLOAT32X4_FUNCTION_LIST(DECLARE_SIMD_FLOAT32X4_FUNCTION) #undef DECLARE_SIMD_FLOAT32X4_FUNCTION #define DECLARE_SIMD_FLOAT64X2_FUNCTION(Name, Func, Operands) \ extern bool \ simd_float64x2_##Name(JSContext* cx, unsigned argc, Value* vp); FLOAT64X2_FUNCTION_LIST(DECLARE_SIMD_FLOAT64X2_FUNCTION) #undef DECLARE_SIMD_FLOAT64X2_FUNCTION #define DECLARE_SIMD_INT8X16_FUNCTION(Name, Func, Operands) \ extern bool \ simd_int8x16_##Name(JSContext* cx, unsigned argc, Value* vp); INT8X16_FUNCTION_LIST(DECLARE_SIMD_INT8X16_FUNCTION) #undef DECLARE_SIMD_INT8X16_FUNCTION #define DECLARE_SIMD_INT16X8_FUNCTION(Name, Func, Operands) \ extern bool \ simd_int16x8_##Name(JSContext* cx, unsigned argc, Value* vp); INT16X8_FUNCTION_LIST(DECLARE_SIMD_INT16X8_FUNCTION) #undef DECLARE_SIMD_INT16X8_FUNCTION #define DECLARE_SIMD_INT32x4_FUNCTION(Name, Func, Operands) \ extern bool \ simd_int32x4_##Name(JSContext* cx, unsigned argc, Value* vp); INT32X4_FUNCTION_LIST(DECLARE_SIMD_INT32x4_FUNCTION) #undef DECLARE_SIMD_INT32x4_FUNCTION JSObject* InitSIMDClass(JSContext* cx, HandleObject obj); } /* namespace js */ #endif /* builtin_SIMD_h */