js/src/builtin/SIMD.cpp

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

mercurial