blob: a3d46159c1173eb3b03323de510b35dfc3caf722 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Murdochda12d292016-06-02 14:46:10 +01005// Flags: --harmony-simd
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006// Flags: --allow-natives-syntax --expose-natives-as natives --noalways-opt
7
8function lanesForType(typeName) {
9 // The lane count follows the first 'x' in the type name, which begins with
10 // 'float', 'int', or 'bool'.
11 return Number.parseInt(typeName.substr(typeName.indexOf('x') + 1));
12}
13
14
15// Creates an instance that has been zeroed, so it can be used for equality
16// testing.
17function createInstance(type) {
18 // Provide enough parameters for the longest type (currently 16). It's
19 // important that instances be consistent to better test that different SIMD
20 // types can't be compared and are never equal or the same in any sense.
21 return SIMD[type](0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
22}
23
24
25function isValidSimdString(string, value, type, lanes) {
26 var simdFn = SIMD[type],
27 parseFn =
28 type.indexOf('Float') === 0 ? Number.parseFloat : Number.parseInt,
29 indexOfOpenParen = string.indexOf('(');
30 // Check prefix (e.g. SIMD.Float32x4.)
31 if (string.substr(0, indexOfOpenParen) !== 'SIMD.' + type)
32 return false;
33 // Remove type name (e.g. SIMD.Float32x4) and open parenthesis.
34 string = string.substr(indexOfOpenParen + 1);
35 var laneStrings = string.split(',');
36 if (laneStrings.length !== lanes)
37 return false;
38 for (var i = 0; i < lanes; i++) {
39 var fromString = parseFn(laneStrings[i]),
40 fromValue = simdFn.extractLane(value, i);
41 if (Math.abs(fromString - fromValue) > Number.EPSILON)
42 return false;
43 }
44 return true;
45}
46
47
48var simdTypeNames = ['Float32x4', 'Int32x4', 'Uint32x4', 'Bool32x4',
49 'Int16x8', 'Uint16x8', 'Bool16x8',
50 'Int8x16', 'Uint8x16', 'Bool8x16'];
51
52var nonSimdValues = [347, 1.275, NaN, "string", null, undefined, {},
53 function() {}];
54
55function checkTypeMatrix(type, fn) {
56 // Check against non-SIMD types.
57 nonSimdValues.forEach(fn);
58 // Check against SIMD values of a different type.
59 for (var i = 0; i < simdTypeNames.length; i++) {
60 var otherType = simdTypeNames[i];
61 if (type != otherType) fn(createInstance(otherType));
62 }
63}
64
65
66// Test different forms of constructor calls.
67function TestConstructor(type, lanes) {
68 var simdFn = SIMD[type];
69 var instance = createInstance(type);
70
71 assertFalse(Object === simdFn.prototype.constructor)
72 assertFalse(simdFn === Object.prototype.constructor)
73 assertSame(simdFn, simdFn.prototype.constructor)
74
75 assertSame(simdFn, instance.__proto__.constructor)
76 assertSame(simdFn, Object(instance).__proto__.constructor)
77 assertSame(simdFn.prototype, instance.__proto__)
78 assertSame(simdFn.prototype, Object(instance).__proto__)
79}
80
81
82function TestType(type, lanes) {
83 var simdFn = SIMD[type];
84 var instance = createInstance(type);
85 var typeofString = type.charAt(0).toLowerCase() + type.slice(1);
86
87 assertEquals(typeofString, typeof instance)
88 assertTrue(typeof instance === typeofString)
89 assertTrue(typeof Object(instance) === 'object')
90 assertEquals(null, %_ClassOf(instance))
91 assertEquals(type, %_ClassOf(Object(instance)))
92}
93
94
95function TestPrototype(type, lanes) {
96 var simdFn = SIMD[type];
97 var instance = createInstance(type);
98
99 assertSame(Object.prototype, simdFn.prototype.__proto__)
100 assertSame(simdFn.prototype, instance.__proto__)
101 assertSame(simdFn.prototype, Object(instance).__proto__)
102}
103
104
105function TestValueOf(type, lanes) {
106 var simdFn = SIMD[type];
107 var instance = createInstance(type);
108
109 assertTrue(instance === Object(instance).valueOf())
110 assertTrue(instance === instance.valueOf())
111 assertTrue(simdFn.prototype.valueOf.call(Object(instance)) === instance)
112 assertTrue(simdFn.prototype.valueOf.call(instance) === instance)
113}
114
115
116function TestGet(type, lanes) {
117 var simdFn = SIMD[type];
118 var instance = createInstance(type);
119
120 assertEquals(undefined, instance.a)
121 assertEquals(undefined, instance["a" + "b"])
122 assertEquals(undefined, instance["" + "1"])
123 assertEquals(undefined, instance[42])
124}
125
126
127function TestToBoolean(type, lanes) {
128 var simdFn = SIMD[type];
129 var instance = createInstance(type);
130
131 assertTrue(Boolean(Object(instance)))
132 assertFalse(!Object(instance))
133 assertTrue(Boolean(instance).valueOf())
134 assertFalse(!instance)
135 assertTrue(!!instance)
136 assertTrue(instance && true)
137 assertFalse(!instance && false)
138 assertTrue(!instance || true)
139 assertEquals(1, instance ? 1 : 2)
140 assertEquals(2, !instance ? 1 : 2)
141 if (!instance) assertUnreachable();
142 if (instance) {} else assertUnreachable();
143}
144
145
146function TestToString(type, lanes) {
147 var simdFn = SIMD[type];
148 var instance = createInstance(type);
149
150 assertEquals(instance.toString(), String(instance))
151 assertTrue(isValidSimdString(instance.toString(), instance, type, lanes))
152 assertTrue(
153 isValidSimdString(Object(instance).toString(), instance, type, lanes))
154 assertTrue(isValidSimdString(
155 simdFn.prototype.toString.call(instance), instance, type, lanes))
156}
157
158
159function TestToNumber(type, lanes) {
160 var simdFn = SIMD[type];
161 var instance = createInstance(type);
162
163 assertThrows(function() { Number(Object(instance)) }, TypeError)
164 assertThrows(function() { +Object(instance) }, TypeError)
165 assertThrows(function() { Number(instance) }, TypeError)
166 assertThrows(function() { instance + 0 }, TypeError)
167}
168
169
170function TestCoercions(type, lanes) {
171 var simdFn = SIMD[type];
172 var instance = createInstance(type);
173 // Test that setting a lane to value 'a' results in a lane with value 'b'.
174 function test(a, b) {
175 for (var i = 0; i < lanes; i++) {
176 var ainstance = simdFn.replaceLane(instance, i, a);
177 var lane_value = simdFn.extractLane(ainstance, i);
178 assertSame(b, lane_value);
179 }
180 }
181
182 switch (type) {
183 case 'Float32x4':
184 test(0, 0);
185 test(-0, -0);
186 test(NaN, NaN);
187 test(null, 0);
188 test(undefined, NaN);
189 test("5.25", 5.25);
190 test(Number.MAX_VALUE, Infinity);
191 test(-Number.MAX_VALUE, -Infinity);
192 test(Number.MIN_VALUE, 0);
193 break;
194 case 'Int32x4':
195 test(Infinity, 0);
196 test(-Infinity, 0);
197 test(NaN, 0);
198 test(0, 0);
199 test(-0, 0);
200 test(Number.MIN_VALUE, 0);
201 test(-Number.MIN_VALUE, 0);
202 test(0.1, 0);
203 test(-0.1, 0);
204 test(1, 1);
205 test(1.1, 1);
206 test(-1, -1);
207 test(-1.6, -1);
208 test(2147483647, 2147483647);
209 test(2147483648, -2147483648);
210 test(2147483649, -2147483647);
211 test(4294967295, -1);
212 test(4294967296, 0);
213 test(4294967297, 1);
214 break;
215 case 'Uint32x4':
216 test(Infinity, 0);
217 test(-Infinity, 0);
218 test(NaN, 0);
219 test(0, 0);
220 test(-0, 0);
221 test(Number.MIN_VALUE, 0);
222 test(-Number.MIN_VALUE, 0);
223 test(0.1, 0);
224 test(-0.1, 0);
225 test(1, 1);
226 test(1.1, 1);
227 test(-1, 4294967295);
228 test(-1.6, 4294967295);
229 test(4294967295, 4294967295);
230 test(4294967296, 0);
231 test(4294967297, 1);
232 break;
233 case 'Int16x8':
234 test(Infinity, 0);
235 test(-Infinity, 0);
236 test(NaN, 0);
237 test(0, 0);
238 test(-0, 0);
239 test(Number.MIN_VALUE, 0);
240 test(-Number.MIN_VALUE, 0);
241 test(0.1, 0);
242 test(-0.1, 0);
243 test(1, 1);
244 test(1.1, 1);
245 test(-1, -1);
246 test(-1.6, -1);
247 test(32767, 32767);
248 test(32768, -32768);
249 test(32769, -32767);
250 test(65535, -1);
251 test(65536, 0);
252 test(65537, 1);
253 break;
254 case 'Uint16x8':
255 test(Infinity, 0);
256 test(-Infinity, 0);
257 test(NaN, 0);
258 test(0, 0);
259 test(-0, 0);
260 test(Number.MIN_VALUE, 0);
261 test(-Number.MIN_VALUE, 0);
262 test(0.1, 0);
263 test(-0.1, 0);
264 test(1, 1);
265 test(1.1, 1);
266 test(-1, 65535);
267 test(-1.6, 65535);
268 test(65535, 65535);
269 test(65536, 0);
270 test(65537, 1);
271 break;
272 case 'Int8x16':
273 test(Infinity, 0);
274 test(-Infinity, 0);
275 test(NaN, 0);
276 test(0, 0);
277 test(-0, 0);
278 test(Number.MIN_VALUE, 0);
279 test(-Number.MIN_VALUE, 0);
280 test(0.1, 0);
281 test(-0.1, 0);
282 test(1, 1);
283 test(1.1, 1);
284 test(-1, -1);
285 test(-1.6, -1);
286 test(127, 127);
287 test(128, -128);
288 test(129, -127);
289 test(255, -1);
290 test(256, 0);
291 test(257, 1);
292 break;
293 case 'Uint8x16':
294 test(Infinity, 0);
295 test(-Infinity, 0);
296 test(NaN, 0);
297 test(0, 0);
298 test(-0, 0);
299 test(Number.MIN_VALUE, 0);
300 test(-Number.MIN_VALUE, 0);
301 test(0.1, 0);
302 test(-0.1, 0);
303 test(1, 1);
304 test(1.1, 1);
305 test(-1, 255);
306 test(-1.6, 255);
307 test(255, 255);
308 test(256, 0);
309 test(257, 1);
310 break;
311 case 'Bool32x4':
312 case 'Bool16x8':
313 case 'Bool8x16':
314 test(true, true);
315 test(false, false);
316 test(0, false);
317 test(1, true);
318 test(0.1, true);
319 test(NaN, false);
320 test(null, false);
321 test("", false);
322 test("false", true);
323 break;
324 }
325}
326
327
328function TestEquality(type, lanes) {
329 var simdFn = SIMD[type];
330 var instance = createInstance(type);
331
332 // Every SIMD value should equal itself, and non-strictly equal its wrapper.
333 assertSame(instance, instance)
334 assertEquals(instance, instance)
335 assertTrue(Object.is(instance, instance))
336 assertTrue(instance === instance)
337 assertTrue(instance == instance)
338 assertFalse(instance === Object(instance))
339 assertFalse(Object(instance) === instance)
340 assertTrue(instance == Object(instance))
341 assertTrue(Object(instance) == instance)
342 assertTrue(instance === instance.valueOf())
343 assertTrue(instance.valueOf() === instance)
344 assertTrue(instance == instance.valueOf())
345 assertTrue(instance.valueOf() == instance)
346 assertFalse(Object(instance) === Object(instance))
347 assertEquals(Object(instance).valueOf(), Object(instance).valueOf())
348
349 function notEqual(other) {
350 assertFalse(instance === other)
351 assertFalse(other === instance)
352 assertFalse(instance == other)
353 assertFalse(other == instance)
354 }
355
356 // SIMD values should not be equal to instances of different types.
357 checkTypeMatrix(type, function(other) {
358 assertFalse(instance === other)
359 assertFalse(other === instance)
360 assertFalse(instance == other)
361 assertFalse(other == instance)
362 });
363
364 // Test that f(a, b) is the same as f(SIMD(a), SIMD(b)) for equality and
365 // strict equality, at every lane.
366 function test(a, b) {
367 for (var i = 0; i < lanes; i++) {
368 var aval = simdFn.replaceLane(instance, i, a);
369 var bval = simdFn.replaceLane(instance, i, b);
370 assertSame(a == b, aval == bval);
371 assertSame(a === b, aval === bval);
372 }
373 }
374
375 switch (type) {
376 case 'Float32x4':
377 test(1, 2.5);
378 test(1, 1);
379 test(0, 0);
380 test(-0, +0);
381 test(+0, -0);
382 test(-0, -0);
383 test(0, NaN);
384 test(NaN, NaN);
385 break;
386 case 'Int32x4':
387 case 'Uint32x4':
388 case 'Int16x8':
389 case 'Uint16x8':
390 case 'Int8x16':
391 case 'Uint8x16':
392 test(1, 2);
393 test(1, 1);
394 test(1, -1);
395 break;
396 case 'Bool32x4':
397 case 'Bool16x8':
398 case 'Bool8x16':
399 test(true, false);
400 test(false, true);
401 break;
402 }
403}
404
405
406function TestSameValue(type, lanes) {
407 var simdFn = SIMD[type];
408 var instance = createInstance(type);
409 var sameValue = Object.is
Ben Murdoch097c5b22016-05-18 11:27:45 +0100410 var sameValueZero = function(x, y) { return %SameValueZero(x, y); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000411
412 // SIMD values should not be the same as instances of different types.
413 checkTypeMatrix(type, function(other) {
414 assertFalse(sameValue(instance, other));
415 assertFalse(sameValueZero(instance, other));
416 });
417
418 // Test that f(a, b) is the same as f(SIMD(a), SIMD(b)) for sameValue and
419 // sameValueZero, at every lane.
420 function test(a, b) {
421 for (var i = 0; i < lanes; i++) {
422 var aval = simdFn.replaceLane(instance, i, a);
423 var bval = simdFn.replaceLane(instance, i, b);
424 assertSame(sameValue(a, b), sameValue(aval, bval));
425 assertSame(sameValueZero(a, b), sameValueZero(aval, bval));
426 }
427 }
428
429 switch (type) {
430 case 'Float32x4':
431 test(1, 2.5);
432 test(1, 1);
433 test(0, 0);
434 test(-0, +0);
435 test(+0, -0);
436 test(-0, -0);
437 test(0, NaN);
438 test(NaN, NaN);
439 break;
440 case 'Int32x4':
441 case 'Uint32x4':
442 case 'Int16x8':
443 case 'Uint16x8':
444 case 'Int8x16':
445 case 'Uint8x16':
446 test(1, 2);
447 test(1, 1);
448 test(1, -1);
449 break;
450 case 'Bool32x4':
451 case 'Bool16x8':
452 case 'Bool8x16':
453 test(true, false);
454 test(false, true);
455 break;
456 }
457}
458
459
460function TestComparison(type, lanes) {
461 var simdFn = SIMD[type];
462 var a = createInstance(type), b = createInstance(type);
463
464 function compare(other) {
465 var throwFuncs = [
466 function lt() { a < b; },
467 function gt() { a > b; },
468 function le() { a <= b; },
469 function ge() { a >= b; },
470 function lt_same() { a < a; },
471 function gt_same() { a > a; },
472 function le_same() { a <= a; },
473 function ge_same() { a >= a; },
474 ];
475
476 for (var f of throwFuncs) {
477 assertThrows(f, TypeError);
478 %OptimizeFunctionOnNextCall(f);
479 assertThrows(f, TypeError);
480 assertThrows(f, TypeError);
481 }
482 }
483
484 // Test comparison against the same SIMD type.
485 compare(b);
486 // Test comparison against other types.
487 checkTypeMatrix(type, compare);
488}
489
490
491// Test SIMD value wrapping/boxing over non-builtins.
492function TestCall(type, lanes) {
493 var simdFn = SIMD[type];
494 var instance = createInstance(type);
495 simdFn.prototype.getThisProto = function () {
496 return Object.getPrototypeOf(this);
497 }
498 assertTrue(instance.getThisProto() === simdFn.prototype)
499}
500
501
502function TestAsSetKey(type, lanes, set) {
503 var simdFn = SIMD[type];
504 var instance = createInstance(type);
505
506 function test(set, key) {
507 assertFalse(set.has(key));
508 assertFalse(set.delete(key));
509 if (!(set instanceof WeakSet)) {
510 assertSame(set, set.add(key));
511 assertTrue(set.has(key));
512 assertTrue(set.delete(key));
513 } else {
514 // SIMD values can't be used as keys in WeakSets.
515 assertThrows(function() { set.add(key) });
516 }
517 assertFalse(set.has(key));
518 assertFalse(set.delete(key));
519 assertFalse(set.has(key));
520 }
521
522 test(set, instance);
523}
524
525
526function TestAsMapKey(type, lanes, map) {
527 var simdFn = SIMD[type];
528 var instance = createInstance(type);
529
530 function test(map, key, value) {
531 assertFalse(map.has(key));
532 assertSame(undefined, map.get(key));
533 assertFalse(map.delete(key));
534 if (!(map instanceof WeakMap)) {
535 assertSame(map, map.set(key, value));
536 assertSame(value, map.get(key));
537 assertTrue(map.has(key));
538 assertTrue(map.delete(key));
539 } else {
540 // SIMD values can't be used as keys in WeakMaps.
541 assertThrows(function() { map.set(key, value) });
542 }
543 assertFalse(map.has(key));
544 assertSame(undefined, map.get(key));
545 assertFalse(map.delete(key));
546 assertFalse(map.has(key));
547 assertSame(undefined, map.get(key));
548 }
549
550 test(map, instance, {});
551}
552
553
554// Test SIMD type with Harmony reflect-apply.
555function TestReflectApply(type) {
556 var simdFn = SIMD[type];
557 var instance = createInstance(type);
558
559 function returnThis() { return this; }
560 function returnThisStrict() { 'use strict'; return this; }
561 function noop() {}
562 function noopStrict() { 'use strict'; }
563 var R = void 0;
564
565 assertSame(SIMD[type].prototype,
566 Object.getPrototypeOf(
567 Reflect.apply(returnThis, instance, [])));
568 assertSame(instance, Reflect.apply(returnThisStrict, instance, []));
569
570 assertThrows(
571 function() { 'use strict'; Reflect.apply(instance); }, TypeError);
572 assertThrows(
573 function() { Reflect.apply(instance); }, TypeError);
574 assertThrows(
575 function() { Reflect.apply(noopStrict, R, instance); }, TypeError);
576 assertThrows(
577 function() { Reflect.apply(noop, R, instance); }, TypeError);
578}
579
580
581function TestSIMDTypes() {
582 for (var i = 0; i < simdTypeNames.length; ++i) {
583 var type = simdTypeNames[i],
584 lanes = lanesForType(type);
585 TestConstructor(type, lanes);
586 TestType(type, lanes);
587 TestPrototype(type, lanes);
588 TestValueOf(type, lanes);
589 TestGet(type, lanes);
590 TestToBoolean(type, lanes);
591 TestToString(type, lanes);
592 TestToNumber(type, lanes);
593 TestCoercions(type, lanes);
594 TestEquality(type, lanes);
595 TestSameValue(type, lanes);
596 TestComparison(type, lanes);
597 TestCall(type, lanes);
598 TestAsSetKey(type, lanes, new Set);
599 TestAsSetKey(type, lanes, new WeakSet);
600 TestAsMapKey(type, lanes, new Map);
601 TestAsMapKey(type, lanes, new WeakMap);
602 TestReflectApply(type);
603 }
604}
605TestSIMDTypes();
606
607// Tests for the global SIMD object.
608function TestSIMDObject() {
609 assertSame(typeof SIMD, 'object');
610 assertSame(SIMD.constructor, Object);
611 assertSame(Object.getPrototypeOf(SIMD), Object.prototype);
612 assertSame(SIMD + "", "[object SIMD]");
613 // The SIMD object is mutable.
614 SIMD.foo = "foo";
615 assertSame(SIMD.foo, "foo");
616 delete SIMD.foo;
617 delete SIMD.Bool8x16;
618 assertSame(SIMD.Bool8x16, undefined);
619}
620TestSIMDObject()
621
622
623function TestStringify(expected, input) {
624 assertEquals(expected, JSON.stringify(input));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100625 assertEquals(expected, JSON.stringify(input, (key, value) => value));
626 assertEquals(JSON.stringify(input, null, "="),
627 JSON.stringify(input, (key, value) => value, "="));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000628}
629
630TestStringify(undefined, SIMD.Float32x4(1, 2, 3, 4));
631TestStringify('[null]', [SIMD.Float32x4(1, 2, 3, 4)]);
632TestStringify('[{}]', [Object(SIMD.Float32x4(1, 2, 3, 4))]);
633var simd_wrapper = Object(SIMD.Float32x4(1, 2, 3, 4));
634TestStringify('{}', simd_wrapper);
635simd_wrapper.a = 1;
636TestStringify('{"a":1}', simd_wrapper);