pow-base-power-of-two.js (2021B)
1 // |jit-test| skip-variant-if: --ion-eager, getBuildConfiguration("simulator") 2 3 // Slow in simulators with --ion-eager. 4 5 // Lowering provides a specialisation when the base operand is a constant which 6 // is a power of two. 7 8 load(libdir + "math.js"); 9 10 function test(x, y, z) { 11 function pow(x, y) { return `Math.pow(${x}, ${y})` }; 12 function exp(x, y) { return `((${x}) ** ${y})` }; 13 14 function make(fn, x, y, z) { 15 return Function(` 16 // Load from array to prevent constant-folding. 17 // (Ion is currently not smart enough to realise that both array 18 // values are the same.) 19 var ys = [${y}, ${y}]; 20 var zs = [${z}, ${z}]; 21 for (var i = 0; i < 200; ++i) { 22 assertNear(${fn(x, "ys[i & 1]")}, zs[i & 1]); 23 } 24 `); 25 } 26 27 function double(v) { 28 // NB: numberToDouble() always returns a double value. 29 return `numberToDouble(${v})`; 30 } 31 32 function addTests(fn) { 33 tests.push(make(fn, x, y, z)); 34 tests.push(make(fn, x, double(y), z)); 35 tests.push(make(fn, double(x), y, z)); 36 tests.push(make(fn, double(x), double(y), z)); 37 } 38 39 var tests = []; 40 addTests(pow); 41 addTests(exp); 42 43 for (var i = 0; i < tests.length; ++i) { 44 for (var j = 0; j < 2; ++j) { 45 tests[i](); 46 } 47 } 48 } 49 50 function* range(a, b, fn) { 51 for (var i = a; i <= b; ++i) { 52 yield fn(i); 53 } 54 } 55 56 // Only 2^i with |i| ∈ {1..8} currently triggers the optimisation, but also test 57 // the next power-of-two values, 1 and 0, and negative base-of-two values. 58 var values = [ 59 ...range(1, 10, i => 2 ** i), 60 1, 61 0, 62 ...range(1, 4, i => -(2 ** i)), 63 ]; 64 65 for (var x of values) { 66 test(x, 0, 1); 67 test(x, 1, x); 68 test(x, 2, x * x); 69 70 // 0**(negative) is Infinity, 1**(negative) is 1. 71 if (Math.abs(x) > 1) { 72 test(x, -1076, 0); 73 } 74 75 // (negative)**(odd-negative) is -0. 76 if (x > 1) { 77 test(x, -1075, 0); 78 } 79 }