js/src/builtin/SIMD.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /*
michael@0 8 * JS SIMD pseudo-module.
michael@0 9 * Specification matches polyfill:
michael@0 10 * https://github.com/johnmccutchan/ecmascript_simd/blob/master/src/ecmascript_simd.js
michael@0 11 * The objects float32x4 and int32x4 are installed on the SIMD pseudo-module.
michael@0 12 */
michael@0 13
michael@0 14 #include "builtin/SIMD.h"
michael@0 15
michael@0 16 #include "jsapi.h"
michael@0 17 #include "jsfriendapi.h"
michael@0 18
michael@0 19 #include "builtin/TypedObject.h"
michael@0 20 #include "js/Value.h"
michael@0 21
michael@0 22 #include "jsobjinlines.h"
michael@0 23
michael@0 24 using namespace js;
michael@0 25
michael@0 26 using mozilla::ArrayLength;
michael@0 27 using mozilla::IsFinite;
michael@0 28 using mozilla::IsNaN;
michael@0 29
michael@0 30 namespace js {
michael@0 31 extern const JSFunctionSpec Float32x4Methods[];
michael@0 32 extern const JSFunctionSpec Int32x4Methods[];
michael@0 33 }
michael@0 34
michael@0 35 ///////////////////////////////////////////////////////////////////////////
michael@0 36 // X4
michael@0 37
michael@0 38 static const char *laneNames[] = {"lane 0", "lane 1", "lane 2", "lane3"};
michael@0 39
michael@0 40 template<typename Type32x4, int lane>
michael@0 41 static bool GetX4Lane(JSContext *cx, unsigned argc, Value *vp) {
michael@0 42 typedef typename Type32x4::Elem Elem;
michael@0 43
michael@0 44 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 45 if(!args.thisv().isObject() || !args.thisv().toObject().is<TypedObject>()) {
michael@0 46 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
michael@0 47 X4TypeDescr::class_.name, laneNames[lane],
michael@0 48 InformalValueTypeName(args.thisv()));
michael@0 49 return false;
michael@0 50 }
michael@0 51
michael@0 52 TypedObject &typedObj = args.thisv().toObject().as<TypedObject>();
michael@0 53 TypeDescr &descr = typedObj.typeDescr();
michael@0 54 if (descr.kind() != TypeDescr::X4 || descr.as<X4TypeDescr>().type() != Type32x4::type) {
michael@0 55 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
michael@0 56 X4TypeDescr::class_.name, laneNames[lane],
michael@0 57 InformalValueTypeName(args.thisv()));
michael@0 58 return false;
michael@0 59 }
michael@0 60
michael@0 61 MOZ_ASSERT(!typedObj.owner().isNeutered());
michael@0 62 Elem *data = reinterpret_cast<Elem *>(typedObj.typedMem());
michael@0 63 Type32x4::setReturn(args, data[lane]);
michael@0 64 return true;
michael@0 65 }
michael@0 66
michael@0 67 #define LANE_ACCESSOR(type, lane) \
michael@0 68 static bool type##Lane##lane(JSContext *cx, unsigned argc, Value *vp) { \
michael@0 69 return GetX4Lane<type, lane>(cx, argc, vp);\
michael@0 70 }
michael@0 71
michael@0 72 #define FOUR_LANES_ACCESSOR(type) \
michael@0 73 LANE_ACCESSOR(type, 0); \
michael@0 74 LANE_ACCESSOR(type, 1); \
michael@0 75 LANE_ACCESSOR(type, 2); \
michael@0 76 LANE_ACCESSOR(type, 3);
michael@0 77
michael@0 78 FOUR_LANES_ACCESSOR(Int32x4);
michael@0 79 FOUR_LANES_ACCESSOR(Float32x4);
michael@0 80 #undef FOUR_LANES_ACCESSOR
michael@0 81 #undef LANE_ACCESSOR
michael@0 82
michael@0 83 template<typename Type32x4>
michael@0 84 static bool SignMask(JSContext *cx, unsigned argc, Value *vp) {
michael@0 85 typedef typename Type32x4::Elem Elem;
michael@0 86
michael@0 87 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 88 if(!args.thisv().isObject() || !args.thisv().toObject().is<TypedObject>()) {
michael@0 89 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
michael@0 90 X4TypeDescr::class_.name, "signMask",
michael@0 91 InformalValueTypeName(args.thisv()));
michael@0 92 return false;
michael@0 93 }
michael@0 94
michael@0 95 TypedObject &typedObj = args.thisv().toObject().as<TypedObject>();
michael@0 96 TypeDescr &descr = typedObj.typeDescr();
michael@0 97 if (descr.kind() != TypeDescr::X4 || descr.as<X4TypeDescr>().type() != Type32x4::type) {
michael@0 98 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
michael@0 99 X4TypeDescr::class_.name, "signMask",
michael@0 100 InformalValueTypeName(args.thisv()));
michael@0 101 return false;
michael@0 102 }
michael@0 103
michael@0 104 MOZ_ASSERT(!typedObj.owner().isNeutered());
michael@0 105 Elem *data = reinterpret_cast<Elem *>(typedObj.typedMem());
michael@0 106 int32_t mx = data[0] < 0.0 ? 1 : 0;
michael@0 107 int32_t my = data[1] < 0.0 ? 1 : 0;
michael@0 108 int32_t mz = data[2] < 0.0 ? 1 : 0;
michael@0 109 int32_t mw = data[3] < 0.0 ? 1 : 0;
michael@0 110 int32_t result = mx | my << 1 | mz << 2 | mw << 3;
michael@0 111 args.rval().setInt32(result);
michael@0 112 return true;
michael@0 113 }
michael@0 114
michael@0 115 #define SIGN_MASK(type) \
michael@0 116 static bool type##SignMask(JSContext *cx, unsigned argc, Value *vp) { \
michael@0 117 return SignMask<Int32x4>(cx, argc, vp); \
michael@0 118 }
michael@0 119 SIGN_MASK(Float32x4);
michael@0 120 SIGN_MASK(Int32x4);
michael@0 121 #undef SIGN_MASK
michael@0 122
michael@0 123 const Class X4TypeDescr::class_ = {
michael@0 124 "X4",
michael@0 125 JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
michael@0 126 JS_PropertyStub, /* addProperty */
michael@0 127 JS_DeletePropertyStub, /* delProperty */
michael@0 128 JS_PropertyStub, /* getProperty */
michael@0 129 JS_StrictPropertyStub, /* setProperty */
michael@0 130 JS_EnumerateStub,
michael@0 131 JS_ResolveStub,
michael@0 132 JS_ConvertStub,
michael@0 133 nullptr, /* finalize */
michael@0 134 call, /* call */
michael@0 135 nullptr, /* hasInstance */
michael@0 136 nullptr, /* construct */
michael@0 137 nullptr
michael@0 138 };
michael@0 139
michael@0 140 // These classes just exist to group together various properties and so on.
michael@0 141 namespace js {
michael@0 142 class Int32x4Defn {
michael@0 143 public:
michael@0 144 static const X4TypeDescr::Type type = X4TypeDescr::TYPE_INT32;
michael@0 145 static const JSFunctionSpec TypeDescriptorMethods[];
michael@0 146 static const JSPropertySpec TypedObjectProperties[];
michael@0 147 static const JSFunctionSpec TypedObjectMethods[];
michael@0 148 };
michael@0 149 class Float32x4Defn {
michael@0 150 public:
michael@0 151 static const X4TypeDescr::Type type = X4TypeDescr::TYPE_FLOAT32;
michael@0 152 static const JSFunctionSpec TypeDescriptorMethods[];
michael@0 153 static const JSPropertySpec TypedObjectProperties[];
michael@0 154 static const JSFunctionSpec TypedObjectMethods[];
michael@0 155 };
michael@0 156 } // namespace js
michael@0 157
michael@0 158 const JSFunctionSpec js::Float32x4Defn::TypeDescriptorMethods[] = {
michael@0 159 JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
michael@0 160 JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
michael@0 161 JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
michael@0 162 JS_FS_END
michael@0 163 };
michael@0 164
michael@0 165 const JSPropertySpec js::Float32x4Defn::TypedObjectProperties[] = {
michael@0 166 JS_PSG("x", Float32x4Lane0, JSPROP_PERMANENT),
michael@0 167 JS_PSG("y", Float32x4Lane1, JSPROP_PERMANENT),
michael@0 168 JS_PSG("z", Float32x4Lane2, JSPROP_PERMANENT),
michael@0 169 JS_PSG("w", Float32x4Lane3, JSPROP_PERMANENT),
michael@0 170 JS_PSG("signMask", Float32x4SignMask, JSPROP_PERMANENT),
michael@0 171 JS_PS_END
michael@0 172 };
michael@0 173
michael@0 174 const JSFunctionSpec js::Float32x4Defn::TypedObjectMethods[] = {
michael@0 175 JS_SELF_HOSTED_FN("toSource", "X4ToSource", 0, 0),
michael@0 176 JS_FS_END
michael@0 177 };
michael@0 178
michael@0 179 const JSFunctionSpec js::Int32x4Defn::TypeDescriptorMethods[] = {
michael@0 180 JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
michael@0 181 JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
michael@0 182 JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
michael@0 183 JS_FS_END,
michael@0 184 };
michael@0 185
michael@0 186 const JSPropertySpec js::Int32x4Defn::TypedObjectProperties[] = {
michael@0 187 JS_PSG("x", Int32x4Lane0, JSPROP_PERMANENT),
michael@0 188 JS_PSG("y", Int32x4Lane1, JSPROP_PERMANENT),
michael@0 189 JS_PSG("z", Int32x4Lane2, JSPROP_PERMANENT),
michael@0 190 JS_PSG("w", Int32x4Lane3, JSPROP_PERMANENT),
michael@0 191 JS_PSG("signMask", Int32x4SignMask, JSPROP_PERMANENT),
michael@0 192 JS_PS_END
michael@0 193 };
michael@0 194
michael@0 195 const JSFunctionSpec js::Int32x4Defn::TypedObjectMethods[] = {
michael@0 196 JS_SELF_HOSTED_FN("toSource", "X4ToSource", 0, 0),
michael@0 197 JS_FS_END
michael@0 198 };
michael@0 199
michael@0 200 template<typename T>
michael@0 201 static JSObject *
michael@0 202 CreateX4Class(JSContext *cx,
michael@0 203 Handle<GlobalObject*> global,
michael@0 204 HandlePropertyName stringRepr)
michael@0 205 {
michael@0 206 const X4TypeDescr::Type type = T::type;
michael@0 207
michael@0 208 RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx));
michael@0 209 if (!funcProto)
michael@0 210 return nullptr;
michael@0 211
michael@0 212 // Create type constructor itself and initialize its reserved slots.
michael@0 213
michael@0 214 Rooted<X4TypeDescr*> x4(cx);
michael@0 215 x4 = NewObjectWithProto<X4TypeDescr>(cx, funcProto, global, TenuredObject);
michael@0 216 if (!x4)
michael@0 217 return nullptr;
michael@0 218
michael@0 219 x4->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(TypeDescr::X4));
michael@0 220 x4->initReservedSlot(JS_DESCR_SLOT_STRING_REPR, StringValue(stringRepr));
michael@0 221 x4->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(X4TypeDescr::size(type)));
michael@0 222 x4->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(X4TypeDescr::alignment(type)));
michael@0 223 x4->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(false));
michael@0 224 x4->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(T::type));
michael@0 225
michael@0 226 if (!CreateUserSizeAndAlignmentProperties(cx, x4))
michael@0 227 return nullptr;
michael@0 228
michael@0 229 // Create prototype property, which inherits from Object.prototype.
michael@0 230
michael@0 231 RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
michael@0 232 if (!objProto)
michael@0 233 return nullptr;
michael@0 234 Rooted<TypedProto*> proto(cx);
michael@0 235 proto = NewObjectWithProto<TypedProto>(cx, objProto, nullptr, TenuredObject);
michael@0 236 if (!proto)
michael@0 237 return nullptr;
michael@0 238 proto->initTypeDescrSlot(*x4);
michael@0 239 x4->initReservedSlot(JS_DESCR_SLOT_TYPROTO, ObjectValue(*proto));
michael@0 240
michael@0 241 // Link constructor to prototype and install properties.
michael@0 242
michael@0 243 if (!JS_DefineFunctions(cx, x4, T::TypeDescriptorMethods))
michael@0 244 return nullptr;
michael@0 245
michael@0 246 if (!LinkConstructorAndPrototype(cx, x4, proto) ||
michael@0 247 !DefinePropertiesAndBrand(cx, proto, T::TypedObjectProperties,
michael@0 248 T::TypedObjectMethods))
michael@0 249 {
michael@0 250 return nullptr;
michael@0 251 }
michael@0 252
michael@0 253 return x4;
michael@0 254 }
michael@0 255
michael@0 256 bool
michael@0 257 X4TypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
michael@0 258 {
michael@0 259 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 260 const uint32_t LANES = 4;
michael@0 261
michael@0 262 if (args.length() < LANES) {
michael@0 263 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
michael@0 264 args.callee().getClass()->name, "3", "s");
michael@0 265 return false;
michael@0 266 }
michael@0 267
michael@0 268 double values[LANES];
michael@0 269 for (uint32_t i = 0; i < LANES; i++) {
michael@0 270 if (!ToNumber(cx, args[i], &values[i]))
michael@0 271 return false;
michael@0 272 }
michael@0 273
michael@0 274 Rooted<X4TypeDescr*> descr(cx, &args.callee().as<X4TypeDescr>());
michael@0 275 Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, descr, 0));
michael@0 276 if (!result)
michael@0 277 return false;
michael@0 278
michael@0 279 MOZ_ASSERT(!result->owner().isNeutered());
michael@0 280 switch (descr->type()) {
michael@0 281 #define STORE_LANES(_constant, _type, _name) \
michael@0 282 case _constant: \
michael@0 283 { \
michael@0 284 _type *mem = reinterpret_cast<_type*>(result->typedMem()); \
michael@0 285 for (uint32_t i = 0; i < LANES; i++) { \
michael@0 286 mem[i] = ConvertScalar<_type>(values[i]); \
michael@0 287 } \
michael@0 288 break; \
michael@0 289 }
michael@0 290 JS_FOR_EACH_X4_TYPE_REPR(STORE_LANES)
michael@0 291 #undef STORE_LANES
michael@0 292 }
michael@0 293 args.rval().setObject(*result);
michael@0 294 return true;
michael@0 295 }
michael@0 296
michael@0 297 ///////////////////////////////////////////////////////////////////////////
michael@0 298 // SIMD class
michael@0 299
michael@0 300 const Class SIMDObject::class_ = {
michael@0 301 "SIMD",
michael@0 302 JSCLASS_HAS_CACHED_PROTO(JSProto_SIMD),
michael@0 303 JS_PropertyStub, /* addProperty */
michael@0 304 JS_DeletePropertyStub, /* delProperty */
michael@0 305 JS_PropertyStub, /* getProperty */
michael@0 306 JS_StrictPropertyStub, /* setProperty */
michael@0 307 JS_EnumerateStub,
michael@0 308 JS_ResolveStub,
michael@0 309 JS_ConvertStub,
michael@0 310 nullptr, /* finalize */
michael@0 311 nullptr, /* call */
michael@0 312 nullptr, /* hasInstance */
michael@0 313 nullptr, /* construct */
michael@0 314 nullptr
michael@0 315 };
michael@0 316
michael@0 317 JSObject *
michael@0 318 SIMDObject::initClass(JSContext *cx, Handle<GlobalObject *> global)
michael@0 319 {
michael@0 320 // SIMD relies on having the TypedObject module initialized.
michael@0 321 // In particular, the self-hosted code for array() wants
michael@0 322 // to be able to call GetTypedObjectModule(). It is NOT necessary
michael@0 323 // to install the TypedObjectModule global, but at the moment
michael@0 324 // those two things are not separable.
michael@0 325 if (!global->getOrCreateTypedObjectModule(cx))
michael@0 326 return nullptr;
michael@0 327
michael@0 328 // Create SIMD Object.
michael@0 329 RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
michael@0 330 if(!objProto)
michael@0 331 return nullptr;
michael@0 332 RootedObject SIMD(cx, NewObjectWithGivenProto(cx, &SIMDObject::class_, objProto,
michael@0 333 global, SingletonObject));
michael@0 334 if (!SIMD)
michael@0 335 return nullptr;
michael@0 336
michael@0 337 // float32x4
michael@0 338
michael@0 339 RootedObject float32x4Object(cx);
michael@0 340 float32x4Object = CreateX4Class<Float32x4Defn>(cx, global,
michael@0 341 cx->names().float32x4);
michael@0 342 if (!float32x4Object)
michael@0 343 return nullptr;
michael@0 344
michael@0 345 RootedValue float32x4Value(cx, ObjectValue(*float32x4Object));
michael@0 346 if (!JS_DefineFunctions(cx, float32x4Object, Float32x4Methods) ||
michael@0 347 !JSObject::defineProperty(cx, SIMD, cx->names().float32x4,
michael@0 348 float32x4Value, nullptr, nullptr,
michael@0 349 JSPROP_READONLY | JSPROP_PERMANENT))
michael@0 350 {
michael@0 351 return nullptr;
michael@0 352 }
michael@0 353
michael@0 354 // int32x4
michael@0 355
michael@0 356 RootedObject int32x4Object(cx);
michael@0 357 int32x4Object = CreateX4Class<Int32x4Defn>(cx, global,
michael@0 358 cx->names().int32x4);
michael@0 359 if (!int32x4Object)
michael@0 360 return nullptr;
michael@0 361
michael@0 362 RootedValue int32x4Value(cx, ObjectValue(*int32x4Object));
michael@0 363 if (!JS_DefineFunctions(cx, int32x4Object, Int32x4Methods) ||
michael@0 364 !JSObject::defineProperty(cx, SIMD, cx->names().int32x4,
michael@0 365 int32x4Value, nullptr, nullptr,
michael@0 366 JSPROP_READONLY | JSPROP_PERMANENT))
michael@0 367 {
michael@0 368 return nullptr;
michael@0 369 }
michael@0 370
michael@0 371 RootedValue SIMDValue(cx, ObjectValue(*SIMD));
michael@0 372
michael@0 373 // Everything is set up, install SIMD on the global object.
michael@0 374 if (!JSObject::defineProperty(cx, global, cx->names().SIMD, SIMDValue, nullptr, nullptr, 0))
michael@0 375 return nullptr;
michael@0 376
michael@0 377 global->setConstructor(JSProto_SIMD, SIMDValue);
michael@0 378
michael@0 379 // Define float32x4 functions and install as a property of the SIMD object.
michael@0 380 global->setFloat32x4TypeDescr(*float32x4Object);
michael@0 381
michael@0 382 // Define int32x4 functions and install as a property of the SIMD object.
michael@0 383 global->setInt32x4TypeDescr(*int32x4Object);
michael@0 384
michael@0 385 return SIMD;
michael@0 386 }
michael@0 387
michael@0 388 JSObject *
michael@0 389 js_InitSIMDClass(JSContext *cx, HandleObject obj)
michael@0 390 {
michael@0 391 JS_ASSERT(obj->is<GlobalObject>());
michael@0 392 Rooted<GlobalObject *> global(cx, &obj->as<GlobalObject>());
michael@0 393 return SIMDObject::initClass(cx, global);
michael@0 394 }
michael@0 395
michael@0 396 template<typename V>
michael@0 397 static bool
michael@0 398 IsVectorObject(HandleValue v)
michael@0 399 {
michael@0 400 if (!v.isObject())
michael@0 401 return false;
michael@0 402
michael@0 403 JSObject &obj = v.toObject();
michael@0 404 if (!obj.is<TypedObject>())
michael@0 405 return false;
michael@0 406
michael@0 407 TypeDescr &typeRepr = obj.as<TypedObject>().typeDescr();
michael@0 408 if (typeRepr.kind() != TypeDescr::X4)
michael@0 409 return false;
michael@0 410
michael@0 411 return typeRepr.as<X4TypeDescr>().type() == V::type;
michael@0 412 }
michael@0 413
michael@0 414 template<typename Elem>
michael@0 415 static Elem
michael@0 416 TypedObjectMemory(HandleValue v)
michael@0 417 {
michael@0 418 TypedObject &obj = v.toObject().as<TypedObject>();
michael@0 419 MOZ_ASSERT(!obj.owner().isNeutered());
michael@0 420 return reinterpret_cast<Elem>(obj.typedMem());
michael@0 421 }
michael@0 422
michael@0 423 template<typename V>
michael@0 424 JSObject *
michael@0 425 js::Create(JSContext *cx, typename V::Elem *data)
michael@0 426 {
michael@0 427 typedef typename V::Elem Elem;
michael@0 428 Rooted<TypeDescr*> typeDescr(cx, &V::GetTypeDescr(*cx->global()));
michael@0 429 JS_ASSERT(typeDescr);
michael@0 430
michael@0 431 Rooted<TypedObject *> result(cx, TypedObject::createZeroed(cx, typeDescr, 0));
michael@0 432 if (!result)
michael@0 433 return nullptr;
michael@0 434
michael@0 435 MOZ_ASSERT(!result->owner().isNeutered());
michael@0 436 Elem *resultMem = reinterpret_cast<Elem *>(result->typedMem());
michael@0 437 memcpy(resultMem, data, sizeof(Elem) * V::lanes);
michael@0 438 return result;
michael@0 439 }
michael@0 440
michael@0 441 template JSObject *js::Create<Float32x4>(JSContext *cx, Float32x4::Elem *data);
michael@0 442 template JSObject *js::Create<Int32x4>(JSContext *cx, Int32x4::Elem *data);
michael@0 443
michael@0 444 namespace js {
michael@0 445 template<typename T, typename V>
michael@0 446 struct Abs {
michael@0 447 static inline T apply(T x, T zero) { return V::toType(x < 0 ? -1 * x : x); }
michael@0 448 };
michael@0 449 template<typename T, typename V>
michael@0 450 struct Neg {
michael@0 451 static inline T apply(T x, T zero) { return V::toType(-1 * x); }
michael@0 452 };
michael@0 453 template<typename T, typename V>
michael@0 454 struct Not {
michael@0 455 static inline T apply(T x, T zero) { return V::toType(~x); }
michael@0 456 };
michael@0 457 template<typename T, typename V>
michael@0 458 struct Rec {
michael@0 459 static inline T apply(T x, T zero) { return V::toType(1 / x); }
michael@0 460 };
michael@0 461 template<typename T, typename V>
michael@0 462 struct RecSqrt {
michael@0 463 static inline T apply(T x, T zero) { return V::toType(1 / sqrt(x)); }
michael@0 464 };
michael@0 465 template<typename T, typename V>
michael@0 466 struct Sqrt {
michael@0 467 static inline T apply(T x, T zero) { return V::toType(sqrt(x)); }
michael@0 468 };
michael@0 469 template<typename T, typename V>
michael@0 470 struct Add {
michael@0 471 static inline T apply(T l, T r) { return V::toType(l + r); }
michael@0 472 };
michael@0 473 template<typename T, typename V>
michael@0 474 struct Sub {
michael@0 475 static inline T apply(T l, T r) { return V::toType(l - r); }
michael@0 476 };
michael@0 477 template<typename T, typename V>
michael@0 478 struct Div {
michael@0 479 static inline T apply(T l, T r) { return V::toType(l / r); }
michael@0 480 };
michael@0 481 template<typename T, typename V>
michael@0 482 struct Mul {
michael@0 483 static inline T apply(T l, T r) { return V::toType(l * r); }
michael@0 484 };
michael@0 485 template<typename T, typename V>
michael@0 486 struct Minimum {
michael@0 487 static inline T apply(T l, T r) { return V::toType(l < r ? l : r); }
michael@0 488 };
michael@0 489 template<typename T, typename V>
michael@0 490 struct Maximum {
michael@0 491 static inline T apply(T l, T r) { return V::toType(l > r ? l : r); }
michael@0 492 };
michael@0 493 template<typename T, typename V>
michael@0 494 struct LessThan {
michael@0 495 static inline T apply(T l, T r) { return V::toType(l < r ? 0xFFFFFFFF : 0x0); }
michael@0 496 };
michael@0 497 template<typename T, typename V>
michael@0 498 struct LessThanOrEqual {
michael@0 499 static inline T apply(T l, T r) { return V::toType(l <= r ? 0xFFFFFFFF : 0x0); }
michael@0 500 };
michael@0 501 template<typename T, typename V>
michael@0 502 struct GreaterThan {
michael@0 503 static inline T apply(T l, T r) { return V::toType(l > r ? 0xFFFFFFFF : 0x0); }
michael@0 504 };
michael@0 505 template<typename T, typename V>
michael@0 506 struct GreaterThanOrEqual {
michael@0 507 static inline T apply(T l, T r) { return V::toType(l >= r ? 0xFFFFFFFF : 0x0); }
michael@0 508 };
michael@0 509 template<typename T, typename V>
michael@0 510 struct Equal {
michael@0 511 static inline T apply(T l, T r) { return V::toType(l == r ? 0xFFFFFFFF : 0x0); }
michael@0 512 };
michael@0 513 template<typename T, typename V>
michael@0 514 struct NotEqual {
michael@0 515 static inline T apply(T l, T r) { return V::toType(l != r ? 0xFFFFFFFF : 0x0); }
michael@0 516 };
michael@0 517 template<typename T, typename V>
michael@0 518 struct Xor {
michael@0 519 static inline T apply(T l, T r) { return V::toType(l ^ r); }
michael@0 520 };
michael@0 521 template<typename T, typename V>
michael@0 522 struct And {
michael@0 523 static inline T apply(T l, T r) { return V::toType(l & r); }
michael@0 524 };
michael@0 525 template<typename T, typename V>
michael@0 526 struct Or {
michael@0 527 static inline T apply(T l, T r) { return V::toType(l | r); }
michael@0 528 };
michael@0 529 template<typename T, typename V>
michael@0 530 struct Scale {
michael@0 531 static inline T apply(int32_t lane, T scalar, T x) { return V::toType(scalar * x); }
michael@0 532 };
michael@0 533 template<typename T, typename V>
michael@0 534 struct WithX {
michael@0 535 static inline T apply(int32_t lane, T scalar, T x) { return V::toType(lane == 0 ? scalar : x); }
michael@0 536 };
michael@0 537 template<typename T, typename V>
michael@0 538 struct WithY {
michael@0 539 static inline T apply(int32_t lane, T scalar, T x) { return V::toType(lane == 1 ? scalar : x); }
michael@0 540 };
michael@0 541 template<typename T, typename V>
michael@0 542 struct WithZ {
michael@0 543 static inline T apply(int32_t lane, T scalar, T x) { return V::toType(lane == 2 ? scalar : x); }
michael@0 544 };
michael@0 545 template<typename T, typename V>
michael@0 546 struct WithW {
michael@0 547 static inline T apply(int32_t lane, T scalar, T x) { return V::toType(lane == 3 ? scalar : x); }
michael@0 548 };
michael@0 549 template<typename T, typename V>
michael@0 550 struct WithFlagX {
michael@0 551 static inline T apply(T l, T f, T x) { return V::toType(l == 0 ? (f ? 0xFFFFFFFF : 0x0) : x); }
michael@0 552 };
michael@0 553 template<typename T, typename V>
michael@0 554 struct WithFlagY {
michael@0 555 static inline T apply(T l, T f, T x) { return V::toType(l == 1 ? (f ? 0xFFFFFFFF : 0x0) : x); }
michael@0 556 };
michael@0 557 template<typename T, typename V>
michael@0 558 struct WithFlagZ {
michael@0 559 static inline T apply(T l, T f, T x) { return V::toType(l == 2 ? (f ? 0xFFFFFFFF : 0x0) : x); }
michael@0 560 };
michael@0 561 template<typename T, typename V>
michael@0 562 struct WithFlagW {
michael@0 563 static inline T apply(T l, T f, T x) { return V::toType(l == 3 ? (f ? 0xFFFFFFFF : 0x0) : x); }
michael@0 564 };
michael@0 565 template<typename T, typename V>
michael@0 566 struct Shuffle {
michael@0 567 static inline int32_t apply(int32_t l, int32_t mask) { return V::toType((mask >> l) & 0x3); }
michael@0 568 };
michael@0 569 }
michael@0 570
michael@0 571 template<typename V, typename Op, typename Vret>
michael@0 572 static bool
michael@0 573 Func(JSContext *cx, unsigned argc, Value *vp)
michael@0 574 {
michael@0 575 typedef typename V::Elem Elem;
michael@0 576 typedef typename Vret::Elem RetElem;
michael@0 577
michael@0 578 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 579 if (args.length() != 1 && args.length() != 2) {
michael@0 580 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
michael@0 581 return false;
michael@0 582 }
michael@0 583
michael@0 584 RetElem result[Vret::lanes];
michael@0 585 if (args.length() == 1) {
michael@0 586 if (!IsVectorObject<V>(args[0])) {
michael@0 587 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
michael@0 588 return false;
michael@0 589 }
michael@0 590
michael@0 591 Elem *val = TypedObjectMemory<Elem *>(args[0]);
michael@0 592 for (int32_t i = 0; i < Vret::lanes; i++)
michael@0 593 result[i] = Op::apply(val[i], 0);
michael@0 594 } else {
michael@0 595 JS_ASSERT(args.length() == 2);
michael@0 596 if(!IsVectorObject<V>(args[0]) || !IsVectorObject<V>(args[1]))
michael@0 597 {
michael@0 598 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
michael@0 599 return false;
michael@0 600 }
michael@0 601
michael@0 602 Elem *left = TypedObjectMemory<Elem *>(args[0]);
michael@0 603 Elem *right = TypedObjectMemory<Elem *>(args[1]);
michael@0 604 for (int32_t i = 0; i < Vret::lanes; i++)
michael@0 605 result[i] = Op::apply(left[i], right[i]);
michael@0 606 }
michael@0 607
michael@0 608 RootedObject obj(cx, Create<Vret>(cx, result));
michael@0 609 if (!obj)
michael@0 610 return false;
michael@0 611
michael@0 612 args.rval().setObject(*obj);
michael@0 613 return true;
michael@0 614 }
michael@0 615
michael@0 616 template<typename V, typename OpWith, typename Vret>
michael@0 617 static bool
michael@0 618 FuncWith(JSContext *cx, unsigned argc, Value *vp)
michael@0 619 {
michael@0 620 typedef typename V::Elem Elem;
michael@0 621 typedef typename Vret::Elem RetElem;
michael@0 622
michael@0 623 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 624 if (args.length() != 2 || !IsVectorObject<V>(args[0]) ||
michael@0 625 (!args[1].isNumber() && !args[1].isBoolean()))
michael@0 626 {
michael@0 627 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
michael@0 628 return false;
michael@0 629 }
michael@0 630
michael@0 631 Elem *val = TypedObjectMemory<Elem *>(args[0]);
michael@0 632 RetElem result[Vret::lanes];
michael@0 633
michael@0 634 if (args[1].isNumber()) {
michael@0 635 Elem withAsNumber;
michael@0 636 if (!Vret::toType(cx, args[1], &withAsNumber))
michael@0 637 return false;
michael@0 638 for (int32_t i = 0; i < Vret::lanes; i++)
michael@0 639 result[i] = OpWith::apply(i, withAsNumber, val[i]);
michael@0 640 } else if (args[1].isBoolean()) {
michael@0 641 bool withAsBool = args[1].toBoolean();
michael@0 642 for (int32_t i = 0; i < Vret::lanes; i++)
michael@0 643 result[i] = OpWith::apply(i, withAsBool, val[i]);
michael@0 644 }
michael@0 645
michael@0 646 RootedObject obj(cx, Create<Vret>(cx, result));
michael@0 647 if (!obj)
michael@0 648 return false;
michael@0 649
michael@0 650 args.rval().setObject(*obj);
michael@0 651 return true;
michael@0 652 }
michael@0 653
michael@0 654 template<typename V, typename OpShuffle, typename Vret>
michael@0 655 static bool
michael@0 656 FuncShuffle(JSContext *cx, unsigned argc, Value *vp)
michael@0 657 {
michael@0 658 typedef typename V::Elem Elem;
michael@0 659 typedef typename Vret::Elem RetElem;
michael@0 660
michael@0 661 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 662 if (args.length() != 2 && args.length() != 3) {
michael@0 663 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
michael@0 664 return false;
michael@0 665 }
michael@0 666
michael@0 667 RetElem result[Vret::lanes];
michael@0 668 if (args.length() == 2) {
michael@0 669 if (!IsVectorObject<V>(args[0]) || !args[1].isNumber())
michael@0 670 {
michael@0 671 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
michael@0 672 return false;
michael@0 673 }
michael@0 674
michael@0 675 Elem *val = TypedObjectMemory<Elem *>(args[0]);;
michael@0 676 Elem arg1;
michael@0 677 if (!Vret::toType(cx, args[1], &arg1))
michael@0 678 return false;
michael@0 679
michael@0 680 for (int32_t i = 0; i < Vret::lanes; i++)
michael@0 681 result[i] = val[OpShuffle::apply(i * 2, arg1)];
michael@0 682 } else {
michael@0 683 JS_ASSERT(args.length() == 3);
michael@0 684 if (!IsVectorObject<V>(args[0]) || !IsVectorObject<V>(args[1]) || !args[2].isNumber())
michael@0 685 {
michael@0 686 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
michael@0 687 return false;
michael@0 688 }
michael@0 689
michael@0 690 Elem *val1 = TypedObjectMemory<Elem *>(args[0]);
michael@0 691 Elem *val2 = TypedObjectMemory<Elem *>(args[1]);
michael@0 692 Elem arg2;
michael@0 693 if (!Vret::toType(cx, args[2], &arg2))
michael@0 694 return false;
michael@0 695
michael@0 696 for (int32_t i = 0; i < Vret::lanes; i++) {
michael@0 697 if (i < Vret::lanes / 2)
michael@0 698 result[i] = val1[OpShuffle::apply(i * 2, arg2)];
michael@0 699 else
michael@0 700 result[i] = val2[OpShuffle::apply(i * 2, arg2)];
michael@0 701 }
michael@0 702 }
michael@0 703
michael@0 704 RootedObject obj(cx, Create<Vret>(cx, result));
michael@0 705 if (!obj)
michael@0 706 return false;
michael@0 707
michael@0 708 args.rval().setObject(*obj);
michael@0 709 return true;
michael@0 710 }
michael@0 711
michael@0 712 template<typename V, typename Vret>
michael@0 713 static bool
michael@0 714 FuncConvert(JSContext *cx, unsigned argc, Value *vp)
michael@0 715 {
michael@0 716 typedef typename V::Elem Elem;
michael@0 717 typedef typename Vret::Elem RetElem;
michael@0 718
michael@0 719 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 720 if (args.length() != 1 || !IsVectorObject<V>(args[0]))
michael@0 721 {
michael@0 722 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
michael@0 723 return false;
michael@0 724 }
michael@0 725
michael@0 726 Elem *val = TypedObjectMemory<Elem *>(args[0]);
michael@0 727 RetElem result[Vret::lanes];
michael@0 728 for (int32_t i = 0; i < Vret::lanes; i++)
michael@0 729 result[i] = RetElem(val[i]);
michael@0 730
michael@0 731 RootedObject obj(cx, Create<Vret>(cx, result));
michael@0 732 if (!obj)
michael@0 733 return false;
michael@0 734
michael@0 735 args.rval().setObject(*obj);
michael@0 736 return true;
michael@0 737 }
michael@0 738
michael@0 739 template<typename V, typename Vret>
michael@0 740 static bool
michael@0 741 FuncConvertBits(JSContext *cx, unsigned argc, Value *vp)
michael@0 742 {
michael@0 743 typedef typename Vret::Elem RetElem;
michael@0 744
michael@0 745 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 746 if (args.length() != 1 || !IsVectorObject<V>(args[0]))
michael@0 747 {
michael@0 748 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
michael@0 749 return false;
michael@0 750 }
michael@0 751
michael@0 752 RetElem *val = TypedObjectMemory<RetElem *>(args[0]);
michael@0 753 RootedObject obj(cx, Create<Vret>(cx, val));
michael@0 754 if (!obj)
michael@0 755 return false;
michael@0 756
michael@0 757 args.rval().setObject(*obj);
michael@0 758 return true;
michael@0 759 }
michael@0 760
michael@0 761 template<typename Vret>
michael@0 762 static bool
michael@0 763 FuncZero(JSContext *cx, unsigned argc, Value *vp)
michael@0 764 {
michael@0 765 typedef typename Vret::Elem RetElem;
michael@0 766
michael@0 767 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 768 if (args.length() != 0) {
michael@0 769 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
michael@0 770 return false;
michael@0 771 }
michael@0 772
michael@0 773 RetElem result[Vret::lanes];
michael@0 774 for (int32_t i = 0; i < Vret::lanes; i++)
michael@0 775 result[i] = RetElem(0);
michael@0 776
michael@0 777 RootedObject obj(cx, Create<Vret>(cx, result));
michael@0 778 if (!obj)
michael@0 779 return false;
michael@0 780
michael@0 781 args.rval().setObject(*obj);
michael@0 782 return true;
michael@0 783 }
michael@0 784
michael@0 785 template<typename Vret>
michael@0 786 static bool
michael@0 787 FuncSplat(JSContext *cx, unsigned argc, Value *vp)
michael@0 788 {
michael@0 789 typedef typename Vret::Elem RetElem;
michael@0 790
michael@0 791 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 792 if (args.length() != 1 || !args[0].isNumber()) {
michael@0 793 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
michael@0 794 return false;
michael@0 795 }
michael@0 796
michael@0 797 RetElem arg;
michael@0 798 if (!Vret::toType(cx, args[0], &arg))
michael@0 799 return false;
michael@0 800
michael@0 801 RetElem result[Vret::lanes];
michael@0 802 for (int32_t i = 0; i < Vret::lanes; i++)
michael@0 803 result[i] = arg;
michael@0 804
michael@0 805 RootedObject obj(cx, Create<Vret>(cx, result));
michael@0 806 if (!obj)
michael@0 807 return false;
michael@0 808
michael@0 809 args.rval().setObject(*obj);
michael@0 810 return true;
michael@0 811 }
michael@0 812
michael@0 813 static bool
michael@0 814 Int32x4Bool(JSContext *cx, unsigned argc, Value *vp)
michael@0 815 {
michael@0 816 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 817 if (args.length() != 4 ||
michael@0 818 !args[0].isBoolean() || !args[1].isBoolean() ||
michael@0 819 !args[2].isBoolean() || !args[3].isBoolean())
michael@0 820 {
michael@0 821 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
michael@0 822 return false;
michael@0 823 }
michael@0 824
michael@0 825 int32_t result[Int32x4::lanes];
michael@0 826 for (int32_t i = 0; i < Int32x4::lanes; i++)
michael@0 827 result[i] = args[i].toBoolean() ? 0xFFFFFFFF : 0x0;
michael@0 828
michael@0 829 RootedObject obj(cx, Create<Int32x4>(cx, result));
michael@0 830 if (!obj)
michael@0 831 return false;
michael@0 832
michael@0 833 args.rval().setObject(*obj);
michael@0 834 return true;
michael@0 835 }
michael@0 836
michael@0 837 static bool
michael@0 838 Float32x4Clamp(JSContext *cx, unsigned argc, Value *vp)
michael@0 839 {
michael@0 840 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 841 if (args.length() != 3 || !IsVectorObject<Float32x4>(args[0]) ||
michael@0 842 !IsVectorObject<Float32x4>(args[1]) || !IsVectorObject<Float32x4>(args[2]))
michael@0 843 {
michael@0 844 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
michael@0 845 return false;
michael@0 846 }
michael@0 847
michael@0 848 float *val = TypedObjectMemory<float *>(args[0]);
michael@0 849 float *lowerLimit = TypedObjectMemory<float *>(args[1]);
michael@0 850 float *upperLimit = TypedObjectMemory<float *>(args[2]);
michael@0 851
michael@0 852 float result[Float32x4::lanes];
michael@0 853 for (int32_t i = 0; i < Float32x4::lanes; i++) {
michael@0 854 result[i] = val[i] < lowerLimit[i] ? lowerLimit[i] : val[i];
michael@0 855 result[i] = result[i] > upperLimit[i] ? upperLimit[i] : result[i];
michael@0 856 }
michael@0 857
michael@0 858 RootedObject obj(cx, Create<Float32x4>(cx, result));
michael@0 859 if (!obj)
michael@0 860 return false;
michael@0 861
michael@0 862 args.rval().setObject(*obj);
michael@0 863 return true;
michael@0 864 }
michael@0 865
michael@0 866 static bool
michael@0 867 Int32x4Select(JSContext *cx, unsigned argc, Value *vp)
michael@0 868 {
michael@0 869 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 870 if (args.length() != 3 || !IsVectorObject<Int32x4>(args[0]) ||
michael@0 871 !IsVectorObject<Float32x4>(args[1]) || !IsVectorObject<Float32x4>(args[2]))
michael@0 872 {
michael@0 873 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
michael@0 874 return false;
michael@0 875 }
michael@0 876
michael@0 877 int32_t *val = TypedObjectMemory<int32_t *>(args[0]);
michael@0 878 int32_t *tv = TypedObjectMemory<int32_t *>(args[1]);
michael@0 879 int32_t *fv = TypedObjectMemory<int32_t *>(args[2]);
michael@0 880
michael@0 881 int32_t tr[Int32x4::lanes];
michael@0 882 for (int32_t i = 0; i < Int32x4::lanes; i++)
michael@0 883 tr[i] = And<int32_t, Int32x4>::apply(val[i], tv[i]);
michael@0 884
michael@0 885 int32_t fr[Int32x4::lanes];
michael@0 886 for (int32_t i = 0; i < Int32x4::lanes; i++)
michael@0 887 fr[i] = And<int32_t, Int32x4>::apply(Not<int32_t, Int32x4>::apply(val[i], 0), fv[i]);
michael@0 888
michael@0 889 int32_t orInt[Int32x4::lanes];
michael@0 890 for (int32_t i = 0; i < Int32x4::lanes; i++)
michael@0 891 orInt[i] = Or<int32_t, Int32x4>::apply(tr[i], fr[i]);
michael@0 892
michael@0 893 float *result = reinterpret_cast<float *>(orInt);
michael@0 894 RootedObject obj(cx, Create<Float32x4>(cx, result));
michael@0 895 if (!obj)
michael@0 896 return false;
michael@0 897
michael@0 898 args.rval().setObject(*obj);
michael@0 899 return true;
michael@0 900 }
michael@0 901
michael@0 902 #define DEFINE_SIMD_FLOAT32X4_FUNCTION(Name, Func, Operands, Flags, MIRId) \
michael@0 903 bool \
michael@0 904 js::simd_float32x4_##Name(JSContext *cx, unsigned argc, Value *vp) \
michael@0 905 { \
michael@0 906 return Func(cx, argc, vp); \
michael@0 907 }
michael@0 908 FLOAT32X4_FUNCTION_LIST(DEFINE_SIMD_FLOAT32X4_FUNCTION)
michael@0 909 #undef DEFINE_SIMD_FLOAT32x4_FUNCTION
michael@0 910
michael@0 911 #define DEFINE_SIMD_INT32X4_FUNCTION(Name, Func, Operands, Flags, MIRId) \
michael@0 912 bool \
michael@0 913 js::simd_int32x4_##Name(JSContext *cx, unsigned argc, Value *vp) \
michael@0 914 { \
michael@0 915 return Func(cx, argc, vp); \
michael@0 916 }
michael@0 917 INT32X4_FUNCTION_LIST(DEFINE_SIMD_INT32X4_FUNCTION)
michael@0 918 #undef DEFINE_SIMD_INT32X4_FUNCTION
michael@0 919
michael@0 920 const JSFunctionSpec js::Float32x4Methods[] = {
michael@0 921 #define SIMD_FLOAT32X4_FUNCTION_ITEM(Name, Func, Operands, Flags, MIRId) \
michael@0 922 JS_FN(#Name, js::simd_float32x4_##Name, Operands, Flags),
michael@0 923 FLOAT32X4_FUNCTION_LIST(SIMD_FLOAT32X4_FUNCTION_ITEM)
michael@0 924 #undef SIMD_FLOAT32x4_FUNCTION_ITEM
michael@0 925 JS_FS_END
michael@0 926 };
michael@0 927
michael@0 928 const JSFunctionSpec js::Int32x4Methods[] = {
michael@0 929 #define SIMD_INT32X4_FUNCTION_ITEM(Name, Func, Operands, Flags, MIRId) \
michael@0 930 JS_FN(#Name, js::simd_int32x4_##Name, Operands, Flags),
michael@0 931 INT32X4_FUNCTION_LIST(SIMD_INT32X4_FUNCTION_ITEM)
michael@0 932 #undef SIMD_INT32X4_FUNCTION_ITEM
michael@0 933 JS_FS_END
michael@0 934 };

mercurial