1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/builtin/SIMD.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,934 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * JS SIMD pseudo-module. 1.12 + * Specification matches polyfill: 1.13 + * https://github.com/johnmccutchan/ecmascript_simd/blob/master/src/ecmascript_simd.js 1.14 + * The objects float32x4 and int32x4 are installed on the SIMD pseudo-module. 1.15 + */ 1.16 + 1.17 +#include "builtin/SIMD.h" 1.18 + 1.19 +#include "jsapi.h" 1.20 +#include "jsfriendapi.h" 1.21 + 1.22 +#include "builtin/TypedObject.h" 1.23 +#include "js/Value.h" 1.24 + 1.25 +#include "jsobjinlines.h" 1.26 + 1.27 +using namespace js; 1.28 + 1.29 +using mozilla::ArrayLength; 1.30 +using mozilla::IsFinite; 1.31 +using mozilla::IsNaN; 1.32 + 1.33 +namespace js { 1.34 +extern const JSFunctionSpec Float32x4Methods[]; 1.35 +extern const JSFunctionSpec Int32x4Methods[]; 1.36 +} 1.37 + 1.38 +/////////////////////////////////////////////////////////////////////////// 1.39 +// X4 1.40 + 1.41 +static const char *laneNames[] = {"lane 0", "lane 1", "lane 2", "lane3"}; 1.42 + 1.43 +template<typename Type32x4, int lane> 1.44 +static bool GetX4Lane(JSContext *cx, unsigned argc, Value *vp) { 1.45 + typedef typename Type32x4::Elem Elem; 1.46 + 1.47 + CallArgs args = CallArgsFromVp(argc, vp); 1.48 + if(!args.thisv().isObject() || !args.thisv().toObject().is<TypedObject>()) { 1.49 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, 1.50 + X4TypeDescr::class_.name, laneNames[lane], 1.51 + InformalValueTypeName(args.thisv())); 1.52 + return false; 1.53 + } 1.54 + 1.55 + TypedObject &typedObj = args.thisv().toObject().as<TypedObject>(); 1.56 + TypeDescr &descr = typedObj.typeDescr(); 1.57 + if (descr.kind() != TypeDescr::X4 || descr.as<X4TypeDescr>().type() != Type32x4::type) { 1.58 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, 1.59 + X4TypeDescr::class_.name, laneNames[lane], 1.60 + InformalValueTypeName(args.thisv())); 1.61 + return false; 1.62 + } 1.63 + 1.64 + MOZ_ASSERT(!typedObj.owner().isNeutered()); 1.65 + Elem *data = reinterpret_cast<Elem *>(typedObj.typedMem()); 1.66 + Type32x4::setReturn(args, data[lane]); 1.67 + return true; 1.68 +} 1.69 + 1.70 +#define LANE_ACCESSOR(type, lane) \ 1.71 +static bool type##Lane##lane(JSContext *cx, unsigned argc, Value *vp) { \ 1.72 + return GetX4Lane<type, lane>(cx, argc, vp);\ 1.73 +} 1.74 + 1.75 +#define FOUR_LANES_ACCESSOR(type) \ 1.76 + LANE_ACCESSOR(type, 0); \ 1.77 + LANE_ACCESSOR(type, 1); \ 1.78 + LANE_ACCESSOR(type, 2); \ 1.79 + LANE_ACCESSOR(type, 3); 1.80 + 1.81 + FOUR_LANES_ACCESSOR(Int32x4); 1.82 + FOUR_LANES_ACCESSOR(Float32x4); 1.83 +#undef FOUR_LANES_ACCESSOR 1.84 +#undef LANE_ACCESSOR 1.85 + 1.86 +template<typename Type32x4> 1.87 +static bool SignMask(JSContext *cx, unsigned argc, Value *vp) { 1.88 + typedef typename Type32x4::Elem Elem; 1.89 + 1.90 + CallArgs args = CallArgsFromVp(argc, vp); 1.91 + if(!args.thisv().isObject() || !args.thisv().toObject().is<TypedObject>()) { 1.92 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, 1.93 + X4TypeDescr::class_.name, "signMask", 1.94 + InformalValueTypeName(args.thisv())); 1.95 + return false; 1.96 + } 1.97 + 1.98 + TypedObject &typedObj = args.thisv().toObject().as<TypedObject>(); 1.99 + TypeDescr &descr = typedObj.typeDescr(); 1.100 + if (descr.kind() != TypeDescr::X4 || descr.as<X4TypeDescr>().type() != Type32x4::type) { 1.101 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, 1.102 + X4TypeDescr::class_.name, "signMask", 1.103 + InformalValueTypeName(args.thisv())); 1.104 + return false; 1.105 + } 1.106 + 1.107 + MOZ_ASSERT(!typedObj.owner().isNeutered()); 1.108 + Elem *data = reinterpret_cast<Elem *>(typedObj.typedMem()); 1.109 + int32_t mx = data[0] < 0.0 ? 1 : 0; 1.110 + int32_t my = data[1] < 0.0 ? 1 : 0; 1.111 + int32_t mz = data[2] < 0.0 ? 1 : 0; 1.112 + int32_t mw = data[3] < 0.0 ? 1 : 0; 1.113 + int32_t result = mx | my << 1 | mz << 2 | mw << 3; 1.114 + args.rval().setInt32(result); 1.115 + return true; 1.116 +} 1.117 + 1.118 +#define SIGN_MASK(type) \ 1.119 +static bool type##SignMask(JSContext *cx, unsigned argc, Value *vp) { \ 1.120 + return SignMask<Int32x4>(cx, argc, vp); \ 1.121 +} 1.122 + SIGN_MASK(Float32x4); 1.123 + SIGN_MASK(Int32x4); 1.124 +#undef SIGN_MASK 1.125 + 1.126 +const Class X4TypeDescr::class_ = { 1.127 + "X4", 1.128 + JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS), 1.129 + JS_PropertyStub, /* addProperty */ 1.130 + JS_DeletePropertyStub, /* delProperty */ 1.131 + JS_PropertyStub, /* getProperty */ 1.132 + JS_StrictPropertyStub, /* setProperty */ 1.133 + JS_EnumerateStub, 1.134 + JS_ResolveStub, 1.135 + JS_ConvertStub, 1.136 + nullptr, /* finalize */ 1.137 + call, /* call */ 1.138 + nullptr, /* hasInstance */ 1.139 + nullptr, /* construct */ 1.140 + nullptr 1.141 +}; 1.142 + 1.143 +// These classes just exist to group together various properties and so on. 1.144 +namespace js { 1.145 +class Int32x4Defn { 1.146 + public: 1.147 + static const X4TypeDescr::Type type = X4TypeDescr::TYPE_INT32; 1.148 + static const JSFunctionSpec TypeDescriptorMethods[]; 1.149 + static const JSPropertySpec TypedObjectProperties[]; 1.150 + static const JSFunctionSpec TypedObjectMethods[]; 1.151 +}; 1.152 +class Float32x4Defn { 1.153 + public: 1.154 + static const X4TypeDescr::Type type = X4TypeDescr::TYPE_FLOAT32; 1.155 + static const JSFunctionSpec TypeDescriptorMethods[]; 1.156 + static const JSPropertySpec TypedObjectProperties[]; 1.157 + static const JSFunctionSpec TypedObjectMethods[]; 1.158 +}; 1.159 +} // namespace js 1.160 + 1.161 +const JSFunctionSpec js::Float32x4Defn::TypeDescriptorMethods[] = { 1.162 + JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0), 1.163 + JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0), 1.164 + JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0), 1.165 + JS_FS_END 1.166 +}; 1.167 + 1.168 +const JSPropertySpec js::Float32x4Defn::TypedObjectProperties[] = { 1.169 + JS_PSG("x", Float32x4Lane0, JSPROP_PERMANENT), 1.170 + JS_PSG("y", Float32x4Lane1, JSPROP_PERMANENT), 1.171 + JS_PSG("z", Float32x4Lane2, JSPROP_PERMANENT), 1.172 + JS_PSG("w", Float32x4Lane3, JSPROP_PERMANENT), 1.173 + JS_PSG("signMask", Float32x4SignMask, JSPROP_PERMANENT), 1.174 + JS_PS_END 1.175 +}; 1.176 + 1.177 +const JSFunctionSpec js::Float32x4Defn::TypedObjectMethods[] = { 1.178 + JS_SELF_HOSTED_FN("toSource", "X4ToSource", 0, 0), 1.179 + JS_FS_END 1.180 +}; 1.181 + 1.182 +const JSFunctionSpec js::Int32x4Defn::TypeDescriptorMethods[] = { 1.183 + JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0), 1.184 + JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0), 1.185 + JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0), 1.186 + JS_FS_END, 1.187 +}; 1.188 + 1.189 +const JSPropertySpec js::Int32x4Defn::TypedObjectProperties[] = { 1.190 + JS_PSG("x", Int32x4Lane0, JSPROP_PERMANENT), 1.191 + JS_PSG("y", Int32x4Lane1, JSPROP_PERMANENT), 1.192 + JS_PSG("z", Int32x4Lane2, JSPROP_PERMANENT), 1.193 + JS_PSG("w", Int32x4Lane3, JSPROP_PERMANENT), 1.194 + JS_PSG("signMask", Int32x4SignMask, JSPROP_PERMANENT), 1.195 + JS_PS_END 1.196 +}; 1.197 + 1.198 +const JSFunctionSpec js::Int32x4Defn::TypedObjectMethods[] = { 1.199 + JS_SELF_HOSTED_FN("toSource", "X4ToSource", 0, 0), 1.200 + JS_FS_END 1.201 +}; 1.202 + 1.203 +template<typename T> 1.204 +static JSObject * 1.205 +CreateX4Class(JSContext *cx, 1.206 + Handle<GlobalObject*> global, 1.207 + HandlePropertyName stringRepr) 1.208 +{ 1.209 + const X4TypeDescr::Type type = T::type; 1.210 + 1.211 + RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx)); 1.212 + if (!funcProto) 1.213 + return nullptr; 1.214 + 1.215 + // Create type constructor itself and initialize its reserved slots. 1.216 + 1.217 + Rooted<X4TypeDescr*> x4(cx); 1.218 + x4 = NewObjectWithProto<X4TypeDescr>(cx, funcProto, global, TenuredObject); 1.219 + if (!x4) 1.220 + return nullptr; 1.221 + 1.222 + x4->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(TypeDescr::X4)); 1.223 + x4->initReservedSlot(JS_DESCR_SLOT_STRING_REPR, StringValue(stringRepr)); 1.224 + x4->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(X4TypeDescr::size(type))); 1.225 + x4->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(X4TypeDescr::alignment(type))); 1.226 + x4->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(false)); 1.227 + x4->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(T::type)); 1.228 + 1.229 + if (!CreateUserSizeAndAlignmentProperties(cx, x4)) 1.230 + return nullptr; 1.231 + 1.232 + // Create prototype property, which inherits from Object.prototype. 1.233 + 1.234 + RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); 1.235 + if (!objProto) 1.236 + return nullptr; 1.237 + Rooted<TypedProto*> proto(cx); 1.238 + proto = NewObjectWithProto<TypedProto>(cx, objProto, nullptr, TenuredObject); 1.239 + if (!proto) 1.240 + return nullptr; 1.241 + proto->initTypeDescrSlot(*x4); 1.242 + x4->initReservedSlot(JS_DESCR_SLOT_TYPROTO, ObjectValue(*proto)); 1.243 + 1.244 + // Link constructor to prototype and install properties. 1.245 + 1.246 + if (!JS_DefineFunctions(cx, x4, T::TypeDescriptorMethods)) 1.247 + return nullptr; 1.248 + 1.249 + if (!LinkConstructorAndPrototype(cx, x4, proto) || 1.250 + !DefinePropertiesAndBrand(cx, proto, T::TypedObjectProperties, 1.251 + T::TypedObjectMethods)) 1.252 + { 1.253 + return nullptr; 1.254 + } 1.255 + 1.256 + return x4; 1.257 +} 1.258 + 1.259 +bool 1.260 +X4TypeDescr::call(JSContext *cx, unsigned argc, Value *vp) 1.261 +{ 1.262 + CallArgs args = CallArgsFromVp(argc, vp); 1.263 + const uint32_t LANES = 4; 1.264 + 1.265 + if (args.length() < LANES) { 1.266 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED, 1.267 + args.callee().getClass()->name, "3", "s"); 1.268 + return false; 1.269 + } 1.270 + 1.271 + double values[LANES]; 1.272 + for (uint32_t i = 0; i < LANES; i++) { 1.273 + if (!ToNumber(cx, args[i], &values[i])) 1.274 + return false; 1.275 + } 1.276 + 1.277 + Rooted<X4TypeDescr*> descr(cx, &args.callee().as<X4TypeDescr>()); 1.278 + Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, descr, 0)); 1.279 + if (!result) 1.280 + return false; 1.281 + 1.282 + MOZ_ASSERT(!result->owner().isNeutered()); 1.283 + switch (descr->type()) { 1.284 +#define STORE_LANES(_constant, _type, _name) \ 1.285 + case _constant: \ 1.286 + { \ 1.287 + _type *mem = reinterpret_cast<_type*>(result->typedMem()); \ 1.288 + for (uint32_t i = 0; i < LANES; i++) { \ 1.289 + mem[i] = ConvertScalar<_type>(values[i]); \ 1.290 + } \ 1.291 + break; \ 1.292 + } 1.293 + JS_FOR_EACH_X4_TYPE_REPR(STORE_LANES) 1.294 +#undef STORE_LANES 1.295 + } 1.296 + args.rval().setObject(*result); 1.297 + return true; 1.298 +} 1.299 + 1.300 +/////////////////////////////////////////////////////////////////////////// 1.301 +// SIMD class 1.302 + 1.303 +const Class SIMDObject::class_ = { 1.304 + "SIMD", 1.305 + JSCLASS_HAS_CACHED_PROTO(JSProto_SIMD), 1.306 + JS_PropertyStub, /* addProperty */ 1.307 + JS_DeletePropertyStub, /* delProperty */ 1.308 + JS_PropertyStub, /* getProperty */ 1.309 + JS_StrictPropertyStub, /* setProperty */ 1.310 + JS_EnumerateStub, 1.311 + JS_ResolveStub, 1.312 + JS_ConvertStub, 1.313 + nullptr, /* finalize */ 1.314 + nullptr, /* call */ 1.315 + nullptr, /* hasInstance */ 1.316 + nullptr, /* construct */ 1.317 + nullptr 1.318 +}; 1.319 + 1.320 +JSObject * 1.321 +SIMDObject::initClass(JSContext *cx, Handle<GlobalObject *> global) 1.322 +{ 1.323 + // SIMD relies on having the TypedObject module initialized. 1.324 + // In particular, the self-hosted code for array() wants 1.325 + // to be able to call GetTypedObjectModule(). It is NOT necessary 1.326 + // to install the TypedObjectModule global, but at the moment 1.327 + // those two things are not separable. 1.328 + if (!global->getOrCreateTypedObjectModule(cx)) 1.329 + return nullptr; 1.330 + 1.331 + // Create SIMD Object. 1.332 + RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); 1.333 + if(!objProto) 1.334 + return nullptr; 1.335 + RootedObject SIMD(cx, NewObjectWithGivenProto(cx, &SIMDObject::class_, objProto, 1.336 + global, SingletonObject)); 1.337 + if (!SIMD) 1.338 + return nullptr; 1.339 + 1.340 + // float32x4 1.341 + 1.342 + RootedObject float32x4Object(cx); 1.343 + float32x4Object = CreateX4Class<Float32x4Defn>(cx, global, 1.344 + cx->names().float32x4); 1.345 + if (!float32x4Object) 1.346 + return nullptr; 1.347 + 1.348 + RootedValue float32x4Value(cx, ObjectValue(*float32x4Object)); 1.349 + if (!JS_DefineFunctions(cx, float32x4Object, Float32x4Methods) || 1.350 + !JSObject::defineProperty(cx, SIMD, cx->names().float32x4, 1.351 + float32x4Value, nullptr, nullptr, 1.352 + JSPROP_READONLY | JSPROP_PERMANENT)) 1.353 + { 1.354 + return nullptr; 1.355 + } 1.356 + 1.357 + // int32x4 1.358 + 1.359 + RootedObject int32x4Object(cx); 1.360 + int32x4Object = CreateX4Class<Int32x4Defn>(cx, global, 1.361 + cx->names().int32x4); 1.362 + if (!int32x4Object) 1.363 + return nullptr; 1.364 + 1.365 + RootedValue int32x4Value(cx, ObjectValue(*int32x4Object)); 1.366 + if (!JS_DefineFunctions(cx, int32x4Object, Int32x4Methods) || 1.367 + !JSObject::defineProperty(cx, SIMD, cx->names().int32x4, 1.368 + int32x4Value, nullptr, nullptr, 1.369 + JSPROP_READONLY | JSPROP_PERMANENT)) 1.370 + { 1.371 + return nullptr; 1.372 + } 1.373 + 1.374 + RootedValue SIMDValue(cx, ObjectValue(*SIMD)); 1.375 + 1.376 + // Everything is set up, install SIMD on the global object. 1.377 + if (!JSObject::defineProperty(cx, global, cx->names().SIMD, SIMDValue, nullptr, nullptr, 0)) 1.378 + return nullptr; 1.379 + 1.380 + global->setConstructor(JSProto_SIMD, SIMDValue); 1.381 + 1.382 + // Define float32x4 functions and install as a property of the SIMD object. 1.383 + global->setFloat32x4TypeDescr(*float32x4Object); 1.384 + 1.385 + // Define int32x4 functions and install as a property of the SIMD object. 1.386 + global->setInt32x4TypeDescr(*int32x4Object); 1.387 + 1.388 + return SIMD; 1.389 +} 1.390 + 1.391 +JSObject * 1.392 +js_InitSIMDClass(JSContext *cx, HandleObject obj) 1.393 +{ 1.394 + JS_ASSERT(obj->is<GlobalObject>()); 1.395 + Rooted<GlobalObject *> global(cx, &obj->as<GlobalObject>()); 1.396 + return SIMDObject::initClass(cx, global); 1.397 +} 1.398 + 1.399 +template<typename V> 1.400 +static bool 1.401 +IsVectorObject(HandleValue v) 1.402 +{ 1.403 + if (!v.isObject()) 1.404 + return false; 1.405 + 1.406 + JSObject &obj = v.toObject(); 1.407 + if (!obj.is<TypedObject>()) 1.408 + return false; 1.409 + 1.410 + TypeDescr &typeRepr = obj.as<TypedObject>().typeDescr(); 1.411 + if (typeRepr.kind() != TypeDescr::X4) 1.412 + return false; 1.413 + 1.414 + return typeRepr.as<X4TypeDescr>().type() == V::type; 1.415 +} 1.416 + 1.417 +template<typename Elem> 1.418 +static Elem 1.419 +TypedObjectMemory(HandleValue v) 1.420 +{ 1.421 + TypedObject &obj = v.toObject().as<TypedObject>(); 1.422 + MOZ_ASSERT(!obj.owner().isNeutered()); 1.423 + return reinterpret_cast<Elem>(obj.typedMem()); 1.424 +} 1.425 + 1.426 +template<typename V> 1.427 +JSObject * 1.428 +js::Create(JSContext *cx, typename V::Elem *data) 1.429 +{ 1.430 + typedef typename V::Elem Elem; 1.431 + Rooted<TypeDescr*> typeDescr(cx, &V::GetTypeDescr(*cx->global())); 1.432 + JS_ASSERT(typeDescr); 1.433 + 1.434 + Rooted<TypedObject *> result(cx, TypedObject::createZeroed(cx, typeDescr, 0)); 1.435 + if (!result) 1.436 + return nullptr; 1.437 + 1.438 + MOZ_ASSERT(!result->owner().isNeutered()); 1.439 + Elem *resultMem = reinterpret_cast<Elem *>(result->typedMem()); 1.440 + memcpy(resultMem, data, sizeof(Elem) * V::lanes); 1.441 + return result; 1.442 +} 1.443 + 1.444 +template JSObject *js::Create<Float32x4>(JSContext *cx, Float32x4::Elem *data); 1.445 +template JSObject *js::Create<Int32x4>(JSContext *cx, Int32x4::Elem *data); 1.446 + 1.447 +namespace js { 1.448 +template<typename T, typename V> 1.449 +struct Abs { 1.450 + static inline T apply(T x, T zero) { return V::toType(x < 0 ? -1 * x : x); } 1.451 +}; 1.452 +template<typename T, typename V> 1.453 +struct Neg { 1.454 + static inline T apply(T x, T zero) { return V::toType(-1 * x); } 1.455 +}; 1.456 +template<typename T, typename V> 1.457 +struct Not { 1.458 + static inline T apply(T x, T zero) { return V::toType(~x); } 1.459 +}; 1.460 +template<typename T, typename V> 1.461 +struct Rec { 1.462 + static inline T apply(T x, T zero) { return V::toType(1 / x); } 1.463 +}; 1.464 +template<typename T, typename V> 1.465 +struct RecSqrt { 1.466 + static inline T apply(T x, T zero) { return V::toType(1 / sqrt(x)); } 1.467 +}; 1.468 +template<typename T, typename V> 1.469 +struct Sqrt { 1.470 + static inline T apply(T x, T zero) { return V::toType(sqrt(x)); } 1.471 +}; 1.472 +template<typename T, typename V> 1.473 +struct Add { 1.474 + static inline T apply(T l, T r) { return V::toType(l + r); } 1.475 +}; 1.476 +template<typename T, typename V> 1.477 +struct Sub { 1.478 + static inline T apply(T l, T r) { return V::toType(l - r); } 1.479 +}; 1.480 +template<typename T, typename V> 1.481 +struct Div { 1.482 + static inline T apply(T l, T r) { return V::toType(l / r); } 1.483 +}; 1.484 +template<typename T, typename V> 1.485 +struct Mul { 1.486 + static inline T apply(T l, T r) { return V::toType(l * r); } 1.487 +}; 1.488 +template<typename T, typename V> 1.489 +struct Minimum { 1.490 + static inline T apply(T l, T r) { return V::toType(l < r ? l : r); } 1.491 +}; 1.492 +template<typename T, typename V> 1.493 +struct Maximum { 1.494 + static inline T apply(T l, T r) { return V::toType(l > r ? l : r); } 1.495 +}; 1.496 +template<typename T, typename V> 1.497 +struct LessThan { 1.498 + static inline T apply(T l, T r) { return V::toType(l < r ? 0xFFFFFFFF : 0x0); } 1.499 +}; 1.500 +template<typename T, typename V> 1.501 +struct LessThanOrEqual { 1.502 + static inline T apply(T l, T r) { return V::toType(l <= r ? 0xFFFFFFFF : 0x0); } 1.503 +}; 1.504 +template<typename T, typename V> 1.505 +struct GreaterThan { 1.506 + static inline T apply(T l, T r) { return V::toType(l > r ? 0xFFFFFFFF : 0x0); } 1.507 +}; 1.508 +template<typename T, typename V> 1.509 +struct GreaterThanOrEqual { 1.510 + static inline T apply(T l, T r) { return V::toType(l >= r ? 0xFFFFFFFF : 0x0); } 1.511 +}; 1.512 +template<typename T, typename V> 1.513 +struct Equal { 1.514 + static inline T apply(T l, T r) { return V::toType(l == r ? 0xFFFFFFFF : 0x0); } 1.515 +}; 1.516 +template<typename T, typename V> 1.517 +struct NotEqual { 1.518 + static inline T apply(T l, T r) { return V::toType(l != r ? 0xFFFFFFFF : 0x0); } 1.519 +}; 1.520 +template<typename T, typename V> 1.521 +struct Xor { 1.522 + static inline T apply(T l, T r) { return V::toType(l ^ r); } 1.523 +}; 1.524 +template<typename T, typename V> 1.525 +struct And { 1.526 + static inline T apply(T l, T r) { return V::toType(l & r); } 1.527 +}; 1.528 +template<typename T, typename V> 1.529 +struct Or { 1.530 + static inline T apply(T l, T r) { return V::toType(l | r); } 1.531 +}; 1.532 +template<typename T, typename V> 1.533 +struct Scale { 1.534 + static inline T apply(int32_t lane, T scalar, T x) { return V::toType(scalar * x); } 1.535 +}; 1.536 +template<typename T, typename V> 1.537 +struct WithX { 1.538 + static inline T apply(int32_t lane, T scalar, T x) { return V::toType(lane == 0 ? scalar : x); } 1.539 +}; 1.540 +template<typename T, typename V> 1.541 +struct WithY { 1.542 + static inline T apply(int32_t lane, T scalar, T x) { return V::toType(lane == 1 ? scalar : x); } 1.543 +}; 1.544 +template<typename T, typename V> 1.545 +struct WithZ { 1.546 + static inline T apply(int32_t lane, T scalar, T x) { return V::toType(lane == 2 ? scalar : x); } 1.547 +}; 1.548 +template<typename T, typename V> 1.549 +struct WithW { 1.550 + static inline T apply(int32_t lane, T scalar, T x) { return V::toType(lane == 3 ? scalar : x); } 1.551 +}; 1.552 +template<typename T, typename V> 1.553 +struct WithFlagX { 1.554 + static inline T apply(T l, T f, T x) { return V::toType(l == 0 ? (f ? 0xFFFFFFFF : 0x0) : x); } 1.555 +}; 1.556 +template<typename T, typename V> 1.557 +struct WithFlagY { 1.558 + static inline T apply(T l, T f, T x) { return V::toType(l == 1 ? (f ? 0xFFFFFFFF : 0x0) : x); } 1.559 +}; 1.560 +template<typename T, typename V> 1.561 +struct WithFlagZ { 1.562 + static inline T apply(T l, T f, T x) { return V::toType(l == 2 ? (f ? 0xFFFFFFFF : 0x0) : x); } 1.563 +}; 1.564 +template<typename T, typename V> 1.565 +struct WithFlagW { 1.566 + static inline T apply(T l, T f, T x) { return V::toType(l == 3 ? (f ? 0xFFFFFFFF : 0x0) : x); } 1.567 +}; 1.568 +template<typename T, typename V> 1.569 +struct Shuffle { 1.570 + static inline int32_t apply(int32_t l, int32_t mask) { return V::toType((mask >> l) & 0x3); } 1.571 +}; 1.572 +} 1.573 + 1.574 +template<typename V, typename Op, typename Vret> 1.575 +static bool 1.576 +Func(JSContext *cx, unsigned argc, Value *vp) 1.577 +{ 1.578 + typedef typename V::Elem Elem; 1.579 + typedef typename Vret::Elem RetElem; 1.580 + 1.581 + CallArgs args = CallArgsFromVp(argc, vp); 1.582 + if (args.length() != 1 && args.length() != 2) { 1.583 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS); 1.584 + return false; 1.585 + } 1.586 + 1.587 + RetElem result[Vret::lanes]; 1.588 + if (args.length() == 1) { 1.589 + if (!IsVectorObject<V>(args[0])) { 1.590 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS); 1.591 + return false; 1.592 + } 1.593 + 1.594 + Elem *val = TypedObjectMemory<Elem *>(args[0]); 1.595 + for (int32_t i = 0; i < Vret::lanes; i++) 1.596 + result[i] = Op::apply(val[i], 0); 1.597 + } else { 1.598 + JS_ASSERT(args.length() == 2); 1.599 + if(!IsVectorObject<V>(args[0]) || !IsVectorObject<V>(args[1])) 1.600 + { 1.601 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS); 1.602 + return false; 1.603 + } 1.604 + 1.605 + Elem *left = TypedObjectMemory<Elem *>(args[0]); 1.606 + Elem *right = TypedObjectMemory<Elem *>(args[1]); 1.607 + for (int32_t i = 0; i < Vret::lanes; i++) 1.608 + result[i] = Op::apply(left[i], right[i]); 1.609 + } 1.610 + 1.611 + RootedObject obj(cx, Create<Vret>(cx, result)); 1.612 + if (!obj) 1.613 + return false; 1.614 + 1.615 + args.rval().setObject(*obj); 1.616 + return true; 1.617 +} 1.618 + 1.619 +template<typename V, typename OpWith, typename Vret> 1.620 +static bool 1.621 +FuncWith(JSContext *cx, unsigned argc, Value *vp) 1.622 +{ 1.623 + typedef typename V::Elem Elem; 1.624 + typedef typename Vret::Elem RetElem; 1.625 + 1.626 + CallArgs args = CallArgsFromVp(argc, vp); 1.627 + if (args.length() != 2 || !IsVectorObject<V>(args[0]) || 1.628 + (!args[1].isNumber() && !args[1].isBoolean())) 1.629 + { 1.630 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS); 1.631 + return false; 1.632 + } 1.633 + 1.634 + Elem *val = TypedObjectMemory<Elem *>(args[0]); 1.635 + RetElem result[Vret::lanes]; 1.636 + 1.637 + if (args[1].isNumber()) { 1.638 + Elem withAsNumber; 1.639 + if (!Vret::toType(cx, args[1], &withAsNumber)) 1.640 + return false; 1.641 + for (int32_t i = 0; i < Vret::lanes; i++) 1.642 + result[i] = OpWith::apply(i, withAsNumber, val[i]); 1.643 + } else if (args[1].isBoolean()) { 1.644 + bool withAsBool = args[1].toBoolean(); 1.645 + for (int32_t i = 0; i < Vret::lanes; i++) 1.646 + result[i] = OpWith::apply(i, withAsBool, val[i]); 1.647 + } 1.648 + 1.649 + RootedObject obj(cx, Create<Vret>(cx, result)); 1.650 + if (!obj) 1.651 + return false; 1.652 + 1.653 + args.rval().setObject(*obj); 1.654 + return true; 1.655 +} 1.656 + 1.657 +template<typename V, typename OpShuffle, typename Vret> 1.658 +static bool 1.659 +FuncShuffle(JSContext *cx, unsigned argc, Value *vp) 1.660 +{ 1.661 + typedef typename V::Elem Elem; 1.662 + typedef typename Vret::Elem RetElem; 1.663 + 1.664 + CallArgs args = CallArgsFromVp(argc, vp); 1.665 + if (args.length() != 2 && args.length() != 3) { 1.666 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS); 1.667 + return false; 1.668 + } 1.669 + 1.670 + RetElem result[Vret::lanes]; 1.671 + if (args.length() == 2) { 1.672 + if (!IsVectorObject<V>(args[0]) || !args[1].isNumber()) 1.673 + { 1.674 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS); 1.675 + return false; 1.676 + } 1.677 + 1.678 + Elem *val = TypedObjectMemory<Elem *>(args[0]);; 1.679 + Elem arg1; 1.680 + if (!Vret::toType(cx, args[1], &arg1)) 1.681 + return false; 1.682 + 1.683 + for (int32_t i = 0; i < Vret::lanes; i++) 1.684 + result[i] = val[OpShuffle::apply(i * 2, arg1)]; 1.685 + } else { 1.686 + JS_ASSERT(args.length() == 3); 1.687 + if (!IsVectorObject<V>(args[0]) || !IsVectorObject<V>(args[1]) || !args[2].isNumber()) 1.688 + { 1.689 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS); 1.690 + return false; 1.691 + } 1.692 + 1.693 + Elem *val1 = TypedObjectMemory<Elem *>(args[0]); 1.694 + Elem *val2 = TypedObjectMemory<Elem *>(args[1]); 1.695 + Elem arg2; 1.696 + if (!Vret::toType(cx, args[2], &arg2)) 1.697 + return false; 1.698 + 1.699 + for (int32_t i = 0; i < Vret::lanes; i++) { 1.700 + if (i < Vret::lanes / 2) 1.701 + result[i] = val1[OpShuffle::apply(i * 2, arg2)]; 1.702 + else 1.703 + result[i] = val2[OpShuffle::apply(i * 2, arg2)]; 1.704 + } 1.705 + } 1.706 + 1.707 + RootedObject obj(cx, Create<Vret>(cx, result)); 1.708 + if (!obj) 1.709 + return false; 1.710 + 1.711 + args.rval().setObject(*obj); 1.712 + return true; 1.713 +} 1.714 + 1.715 +template<typename V, typename Vret> 1.716 +static bool 1.717 +FuncConvert(JSContext *cx, unsigned argc, Value *vp) 1.718 +{ 1.719 + typedef typename V::Elem Elem; 1.720 + typedef typename Vret::Elem RetElem; 1.721 + 1.722 + CallArgs args = CallArgsFromVp(argc, vp); 1.723 + if (args.length() != 1 || !IsVectorObject<V>(args[0])) 1.724 + { 1.725 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS); 1.726 + return false; 1.727 + } 1.728 + 1.729 + Elem *val = TypedObjectMemory<Elem *>(args[0]); 1.730 + RetElem result[Vret::lanes]; 1.731 + for (int32_t i = 0; i < Vret::lanes; i++) 1.732 + result[i] = RetElem(val[i]); 1.733 + 1.734 + RootedObject obj(cx, Create<Vret>(cx, result)); 1.735 + if (!obj) 1.736 + return false; 1.737 + 1.738 + args.rval().setObject(*obj); 1.739 + return true; 1.740 +} 1.741 + 1.742 +template<typename V, typename Vret> 1.743 +static bool 1.744 +FuncConvertBits(JSContext *cx, unsigned argc, Value *vp) 1.745 +{ 1.746 + typedef typename Vret::Elem RetElem; 1.747 + 1.748 + CallArgs args = CallArgsFromVp(argc, vp); 1.749 + if (args.length() != 1 || !IsVectorObject<V>(args[0])) 1.750 + { 1.751 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS); 1.752 + return false; 1.753 + } 1.754 + 1.755 + RetElem *val = TypedObjectMemory<RetElem *>(args[0]); 1.756 + RootedObject obj(cx, Create<Vret>(cx, val)); 1.757 + if (!obj) 1.758 + return false; 1.759 + 1.760 + args.rval().setObject(*obj); 1.761 + return true; 1.762 +} 1.763 + 1.764 +template<typename Vret> 1.765 +static bool 1.766 +FuncZero(JSContext *cx, unsigned argc, Value *vp) 1.767 +{ 1.768 + typedef typename Vret::Elem RetElem; 1.769 + 1.770 + CallArgs args = CallArgsFromVp(argc, vp); 1.771 + if (args.length() != 0) { 1.772 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS); 1.773 + return false; 1.774 + } 1.775 + 1.776 + RetElem result[Vret::lanes]; 1.777 + for (int32_t i = 0; i < Vret::lanes; i++) 1.778 + result[i] = RetElem(0); 1.779 + 1.780 + RootedObject obj(cx, Create<Vret>(cx, result)); 1.781 + if (!obj) 1.782 + return false; 1.783 + 1.784 + args.rval().setObject(*obj); 1.785 + return true; 1.786 +} 1.787 + 1.788 +template<typename Vret> 1.789 +static bool 1.790 +FuncSplat(JSContext *cx, unsigned argc, Value *vp) 1.791 +{ 1.792 + typedef typename Vret::Elem RetElem; 1.793 + 1.794 + CallArgs args = CallArgsFromVp(argc, vp); 1.795 + if (args.length() != 1 || !args[0].isNumber()) { 1.796 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS); 1.797 + return false; 1.798 + } 1.799 + 1.800 + RetElem arg; 1.801 + if (!Vret::toType(cx, args[0], &arg)) 1.802 + return false; 1.803 + 1.804 + RetElem result[Vret::lanes]; 1.805 + for (int32_t i = 0; i < Vret::lanes; i++) 1.806 + result[i] = arg; 1.807 + 1.808 + RootedObject obj(cx, Create<Vret>(cx, result)); 1.809 + if (!obj) 1.810 + return false; 1.811 + 1.812 + args.rval().setObject(*obj); 1.813 + return true; 1.814 +} 1.815 + 1.816 +static bool 1.817 +Int32x4Bool(JSContext *cx, unsigned argc, Value *vp) 1.818 +{ 1.819 + CallArgs args = CallArgsFromVp(argc, vp); 1.820 + if (args.length() != 4 || 1.821 + !args[0].isBoolean() || !args[1].isBoolean() || 1.822 + !args[2].isBoolean() || !args[3].isBoolean()) 1.823 + { 1.824 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS); 1.825 + return false; 1.826 + } 1.827 + 1.828 + int32_t result[Int32x4::lanes]; 1.829 + for (int32_t i = 0; i < Int32x4::lanes; i++) 1.830 + result[i] = args[i].toBoolean() ? 0xFFFFFFFF : 0x0; 1.831 + 1.832 + RootedObject obj(cx, Create<Int32x4>(cx, result)); 1.833 + if (!obj) 1.834 + return false; 1.835 + 1.836 + args.rval().setObject(*obj); 1.837 + return true; 1.838 +} 1.839 + 1.840 +static bool 1.841 +Float32x4Clamp(JSContext *cx, unsigned argc, Value *vp) 1.842 +{ 1.843 + CallArgs args = CallArgsFromVp(argc, vp); 1.844 + if (args.length() != 3 || !IsVectorObject<Float32x4>(args[0]) || 1.845 + !IsVectorObject<Float32x4>(args[1]) || !IsVectorObject<Float32x4>(args[2])) 1.846 + { 1.847 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS); 1.848 + return false; 1.849 + } 1.850 + 1.851 + float *val = TypedObjectMemory<float *>(args[0]); 1.852 + float *lowerLimit = TypedObjectMemory<float *>(args[1]); 1.853 + float *upperLimit = TypedObjectMemory<float *>(args[2]); 1.854 + 1.855 + float result[Float32x4::lanes]; 1.856 + for (int32_t i = 0; i < Float32x4::lanes; i++) { 1.857 + result[i] = val[i] < lowerLimit[i] ? lowerLimit[i] : val[i]; 1.858 + result[i] = result[i] > upperLimit[i] ? upperLimit[i] : result[i]; 1.859 + } 1.860 + 1.861 + RootedObject obj(cx, Create<Float32x4>(cx, result)); 1.862 + if (!obj) 1.863 + return false; 1.864 + 1.865 + args.rval().setObject(*obj); 1.866 + return true; 1.867 +} 1.868 + 1.869 +static bool 1.870 +Int32x4Select(JSContext *cx, unsigned argc, Value *vp) 1.871 +{ 1.872 + CallArgs args = CallArgsFromVp(argc, vp); 1.873 + if (args.length() != 3 || !IsVectorObject<Int32x4>(args[0]) || 1.874 + !IsVectorObject<Float32x4>(args[1]) || !IsVectorObject<Float32x4>(args[2])) 1.875 + { 1.876 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS); 1.877 + return false; 1.878 + } 1.879 + 1.880 + int32_t *val = TypedObjectMemory<int32_t *>(args[0]); 1.881 + int32_t *tv = TypedObjectMemory<int32_t *>(args[1]); 1.882 + int32_t *fv = TypedObjectMemory<int32_t *>(args[2]); 1.883 + 1.884 + int32_t tr[Int32x4::lanes]; 1.885 + for (int32_t i = 0; i < Int32x4::lanes; i++) 1.886 + tr[i] = And<int32_t, Int32x4>::apply(val[i], tv[i]); 1.887 + 1.888 + int32_t fr[Int32x4::lanes]; 1.889 + for (int32_t i = 0; i < Int32x4::lanes; i++) 1.890 + fr[i] = And<int32_t, Int32x4>::apply(Not<int32_t, Int32x4>::apply(val[i], 0), fv[i]); 1.891 + 1.892 + int32_t orInt[Int32x4::lanes]; 1.893 + for (int32_t i = 0; i < Int32x4::lanes; i++) 1.894 + orInt[i] = Or<int32_t, Int32x4>::apply(tr[i], fr[i]); 1.895 + 1.896 + float *result = reinterpret_cast<float *>(orInt); 1.897 + RootedObject obj(cx, Create<Float32x4>(cx, result)); 1.898 + if (!obj) 1.899 + return false; 1.900 + 1.901 + args.rval().setObject(*obj); 1.902 + return true; 1.903 +} 1.904 + 1.905 +#define DEFINE_SIMD_FLOAT32X4_FUNCTION(Name, Func, Operands, Flags, MIRId) \ 1.906 +bool \ 1.907 +js::simd_float32x4_##Name(JSContext *cx, unsigned argc, Value *vp) \ 1.908 +{ \ 1.909 + return Func(cx, argc, vp); \ 1.910 +} 1.911 +FLOAT32X4_FUNCTION_LIST(DEFINE_SIMD_FLOAT32X4_FUNCTION) 1.912 +#undef DEFINE_SIMD_FLOAT32x4_FUNCTION 1.913 + 1.914 +#define DEFINE_SIMD_INT32X4_FUNCTION(Name, Func, Operands, Flags, MIRId) \ 1.915 +bool \ 1.916 +js::simd_int32x4_##Name(JSContext *cx, unsigned argc, Value *vp) \ 1.917 +{ \ 1.918 + return Func(cx, argc, vp); \ 1.919 +} 1.920 +INT32X4_FUNCTION_LIST(DEFINE_SIMD_INT32X4_FUNCTION) 1.921 +#undef DEFINE_SIMD_INT32X4_FUNCTION 1.922 + 1.923 +const JSFunctionSpec js::Float32x4Methods[] = { 1.924 +#define SIMD_FLOAT32X4_FUNCTION_ITEM(Name, Func, Operands, Flags, MIRId) \ 1.925 + JS_FN(#Name, js::simd_float32x4_##Name, Operands, Flags), 1.926 + FLOAT32X4_FUNCTION_LIST(SIMD_FLOAT32X4_FUNCTION_ITEM) 1.927 +#undef SIMD_FLOAT32x4_FUNCTION_ITEM 1.928 + JS_FS_END 1.929 +}; 1.930 + 1.931 +const JSFunctionSpec js::Int32x4Methods[] = { 1.932 +#define SIMD_INT32X4_FUNCTION_ITEM(Name, Func, Operands, Flags, MIRId) \ 1.933 + JS_FN(#Name, js::simd_int32x4_##Name, Operands, Flags), 1.934 + INT32X4_FUNCTION_LIST(SIMD_INT32X4_FUNCTION_ITEM) 1.935 +#undef SIMD_INT32X4_FUNCTION_ITEM 1.936 + JS_FS_END 1.937 +};