// This test checks that we are able to optimize float32 inputs. As // GetElementIC (float32 array accesses) output is not specialized with Float32 // output types, we should not force inline caches. if (getJitCompilerOptions()["ion.forceinlineCaches"]) setJitCompilerOption("ion.forceinlineCaches", 0); // Fuzz tests (function(){ // (function(){ var g = {}; x = new Float32Array() Function('g', "g.o = x[1]")(g); })(); // (function() { var g = new Float32Array(16); var h = new Float64Array(16); var farrays = [ g, h ]; for (aridx = 0; aridx < farrays.length; ++aridx) { ar = farrays[aridx]; !(ar[ar.length-2] == (NaN / Infinity)[ar.length-2]) } })(); // (function () { var v = new Float32Array(32); for (var i = 0; i < v.length; ++i) v[i] = i; var t = (false ); for (var i = 0; i < i .length; ++i) t += v[i]; })(); // (function() { x = y = {}; z = new Float32Array(6) for (c in this) { Array.prototype.unshift.call(x, new ArrayBuffer()) } Array.prototype.sort.call(x, (function (j) { y.s = z[2] })) })(); // (function() { // bug 1134298 for (var k = 0; k < 1; k++) { Math.fround(Math.ceil(Math.fround(Math.acos(3.0)))) } })(); })(); // // ION TESTS // // The assertFloat32 function is deactivated in --ion-eager mode, as the first time, the function Math.fround // would be guarded against modifications (typeguard on Math and then on fround). In this case, Math.fround is // not inlined and the compiler will consider the return value to be a double, not a float32, making the // assertions fail. Note that as assertFloat32 is declared unsafe for fuzzing, this can't happen in fuzzed code. // // To be able to test it, we still need ion compilation though. A nice solution // is to manually lower the ion warm-up trigger. setJitCompilerOption("ion.warmup.trigger", 50); function test(f) { f32[0] = .5; for(var n = 110; n; n--) f(); } var f32 = new Float32Array(4); var f64 = new Float64Array(4); function acceptAdd() { var use = f32[0] + 1; assertFloat32(use, true); f32[0] = use; } test(acceptAdd); function acceptAddSeveral() { var sum1 = f32[0] + 0.5; var sum2 = f32[0] + 0.5; f32[0] = sum1; f32[0] = sum2; assertFloat32(sum1, true); assertFloat32(sum2, true); } test(acceptAddSeveral); function acceptAddVar() { var x = f32[0] + 1; f32[0] = x; f32[1] = x; assertFloat32(x, true); } test(acceptAddVar); function refuseAddCst() { var x = f32[0] + 1234567890; // this constant can't be precisely represented as a float32 f32[0] = x; assertFloat32(x, false); } test(refuseAddCst); function refuseAddVar() { var x = f32[0] + 1; f32[0] = x; f32[1] = x; f64[1] = x; // non consumer assertFloat32(x, false); } test(refuseAddVar); function refuseAddStore64() { var x = f32[0] + 1; f64[0] = x; // non consumer f32[0] = f64[0]; assertFloat32(x, false); } test(refuseAddStore64); function refuseAddStoreObj() { var o = {} var x = f32[0] + 1; o.x = x; // non consumer f32[0] = o['x']; assertFloat32(x, false); } test(refuseAddStoreObj); function refuseAddSeveral() { var sum = (f32[0] + 2) - 1; // second addition is not a consumer f32[0] = sum; assertFloat32(sum, false); } test(refuseAddSeveral); function refuseAddFunctionCall() { function plusOne(x) { return Math.cos(x+1)*13.37; } var res = plusOne(f32[0]); // func call is not a consumer f32[0] = res; assertFloat32(res, false); } test(refuseAddFunctionCall); function acceptSqrt() { var res = Math.sqrt(f32[0]); assertFloat32(res, true); f32[0] = res; } test(acceptSqrt); function refuseSqrt() { var res = Math.sqrt(f32[0]); assertFloat32(res, false); f32[0] = res + 1; } test(refuseSqrt); function acceptMin() { var res = Math.min(f32[0], f32[1]); assertFloat32(res, true); f64[0] = res; } test(acceptMin); // In theory, we could do it, as Math.min/max actually behave as a Phi (it's a // float32 producer iff its inputs are producers, it's a consumer iff its uses // are consumers). In practice, this would involve some overhead for big chains // of min/max. function refuseMinAdd() { var res = Math.min(f32[0], f32[1]) + f32[2]; assertFloat32(res, false); f32[3] = res; } test(refuseMinAdd); function acceptSeveralMinMax() { var x = Math.min(f32[0], f32[1]); var y = Math.max(f32[2], f32[3]); var res = Math.min(x, y); assertFloat32(res, true); f64[0] = res; } test(acceptSeveralMinMax); function acceptSeveralMinMax2() { var res = Math.min(f32[0], f32[1], f32[2], f32[3]); assertFloat32(res, true); f64[0] = res; } test(acceptSeveralMinMax2); function partialMinMax() { var x = Math.min(f32[0], f32[1]); var y = Math.min(f64[0], f32[1]); var res = Math.min(x, y); assertFloat32(x, true); assertFloat32(y, false); assertFloat32(res, false); f64[0] = res; } test(partialMinMax); function refuseSeveralMinMax() { var res = Math.min(f32[0], f32[1] + f32[2], f32[2], f32[3]); assertFloat32(res, false); f64[0] = res; } test(refuseSeveralMinMax); function refuseMin() { var res = Math.min(f32[0], 42.13 + f32[1]); assertFloat32(res, false); f64[0] = res; } test(refuseMin); function acceptMax() { var res = Math.max(f32[0], f32[1]); assertFloat32(res, true); f64[0] = res; } test(acceptMax); function refuseMax() { var res = Math.max(f32[0], 42.13 + f32[1]); assertFloat32(res, false); f64[0] = res; } test(refuseMax); function acceptAbs() { var res = Math.abs(f32[0]); assertFloat32(res, true); f32[0] = res; } test(acceptAbs); function refuseAbs() { var res = Math.abs(f32[0]); assertFloat32(res, false); f64[0] = res + 1; } test(refuseAbs); function acceptFilterTypeSet() { var res = f32[0]; if (!res) { } else { f32[0] = res; assertFloat32(res, true); } } test(acceptFilterTypeSet); function acceptFilterTypeSet2() { var res = f32[0]; if (!res) { } else { var res1 = Math.abs(res); f32[0] = res1; assertFloat32(res1, true); } } test(acceptFilterTypeSet2); function refuseFilterTypeSet() { var res = f32[0]; if (!res) { } else { var res1 = Math.abs(res); f64[0] = res1 + 1; assertFloat32(res1, false); } } test(refuseFilterTypeSet); function refuseTrigo() { var res = Math.cos(f32[0]); f32[0] = res; assertFloat32(res, false); var res = Math.sin(f32[0]); f32[0] = res; assertFloat32(res, false); var res = Math.tan(f32[0]); f32[0] = res; assertFloat32(res, false); var res = Math.acos(f32[0]); f32[0] = res; assertFloat32(res, false); var res = Math.asin(f32[0]); f32[0] = res; assertFloat32(res, false); res = Math.atan(f32[0]); f32[0] = res; assertFloat32(res, false); } test(refuseTrigo); function refuseMath() { var res = Math.log10(f32[0]); f32[0] = res; assertFloat32(res, false); res = Math.log2(f32[0]); f32[0] = res; assertFloat32(res, false); res = Math.log1p(f32[0]); f32[0] = res; assertFloat32(res, false); res = Math.expm1(f32[0]); f32[0] = res; assertFloat32(res, false); res = Math.cosh(f32[0]); f32[0] = res; assertFloat32(res, false); res = Math.sinh(f32[0]); f32[0] = res; assertFloat32(res, false); res = Math.tanh(f32[0]); f32[0] = res; assertFloat32(res, false); res = Math.acosh(f32[0]); f32[0] = res; assertFloat32(res, false); res = Math.asinh(f32[0]); f32[0] = res; assertFloat32(res, false); res = Math.atanh(f32[0]); f32[0] = res; assertFloat32(res, false); res = Math.cbrt(f32[0]); f32[0] = res; assertFloat32(res, false); res = Math.sign(f32[0]); f32[0] = res; assertFloat32(res, false); res = Math.trunc(f32[0]); f32[0] = res; assertFloat32(res, false); } test(refuseMath); function refuseLoop() { var res = f32[0], n = 10; while (n--) { res = res + 1; // this loop is equivalent to several additions => second addition is not a consumer assertFloat32(res, false); } assertFloat32(res, false); f32[0] = res; } test(refuseLoop); function acceptLoop() { var res = f32[0], n = 10; while (n--) { var sum = res + 1; res = Math.fround(sum); assertFloat32(sum, true); } assertFloat32(res, true); f32[0] = res; } test(acceptLoop); function alternateCond(n) { var x = f32[0]; if (n > 0) { var s1 = x + 1; f32[0] = s1; assertFloat32(s1, true); } else { var s2 = x + 1; f64[0] = s2; // non consumer assertFloat32(s2, false); } } (function() { f32[0] = 0; for (var n = 110; n; n--) { alternateCond(n % 2); } })(); function phiTest(n) { var x = (f32[0]); var y = n; if (n > 0) { x = x + 2; assertFloat32(x, true); } else { if (n < -10) { x = Math.fround(Math.sqrt(y)); assertFloat32(x, true); } else { x = x - 1; assertFloat32(x, true); } } assertFloat32(x, true); f32[0] = x; } (function() { f32[0] = 0; for (var n = 100; n; n--) { phiTest( ((n % 3) - 1) * 15 ); } })(); function mixedPhiTest(n) { var x = (f32[0]); var y = n; if (n > 0) { x = x + 2; // non consumer because of (1) assertFloat32(x, false); } else { if (n < -10) { x = Math.fround(Math.sqrt(y)); // new producer assertFloat32(x, true); } else { x = x - 1; // non consumer because of (1) assertFloat32(x, false); } } assertFloat32(x, false); x = x + 1; // (1) non consumer f32[0] = x; } (function() { f32[0] = 0; for (var n = 100; n; n--) { mixedPhiTest( ((n % 3) - 1) * 15 ); } })(); function phiTest2(n) { var x = f32[0]; while (n >= 0) { x = Math.fround(Math.fround(x) + 1); assertFloat32(x, true); if (n < 10) { x = f32[0] + 1; assertFloat32(x, true); } n = n - 1; } } (function(){ f32[0] = 0; for (var n = 100; n > 10; n--) { phiTest2(n); } })();