bug1982383.js (3650B)
1 // |jit-test| --ion-check-range-analysis; --disable-main-thread-denormals; skip-if: helperThreadCount() == 0 2 3 let inIon_lege = false; 4 let inIon_legt = false; 5 let inIon_ltge = false; 6 let inIon_ltgt = false; 7 8 function test_lege(negzero) { 9 inIon_lege = inIon(); 10 const a = 3.337610787760802e-308; 11 const b = 2.2250738585072014e-308; 12 if (negzero <= (-a) + b) { 13 if (negzero >= a - b) { 14 // b - a < -0.0 < a - b 15 // 16 // So you thought you understood math, yet this branch is taken! 17 // 18 // Don't worry, you are just enterring a corner case of floating point 19 // arithmetic where numbers are represented as fixed point numbers called 20 // subnormal or denormal. 21 // 22 // Except that these numbers are a hell of a slow down, and any reasonable 23 // person would disable computation with these numbers for the sake of 24 // performance. 25 // 26 // Well, reasonable is debatable given that this performance improvement 27 // comes at the cost of sanity, as we no longer have 2 zeros (+0.0 and 28 // -0.0), but we have 2^53 zeros and the above conditions are basically 29 // checking: 30 // 31 // -0.0 <= -0.0 <= 0.0 32 // 33 // The problem, is that when you have the choice to disable denormals, any 34 // sane person would do it either for everything or for nothing, but not 35 // having one half of the program with denormals enabled and the other 36 // half with denormals disabled. 37 // 38 // What happens here is that Range Analysis, our lovely optimization, 39 // works with denormal enabled, yet this code might or might not run with 40 // denormals disabled :tada:. 41 // 42 // Thus making assumptions about whether zero can enter this branch or not 43 // yield to inconsistencies, and we have to make sure that Range Analysis 44 // is conservative to account for this corner case. 45 // 46 // This test case runs with extra checks for Range Analysis to trip on the 47 // unexpected value of negzero. 48 if (1 / Math.sign(negzero) == -Infinity) { 49 return "What Should Have Been Impossible Happened!"; 50 } 51 } 52 return "The impossible happened!"; 53 } 54 return "the ordinary happened!"; 55 } 56 57 function test_ltge(negzero) { 58 inIon_ltge = inIon(); 59 const a = 3.337610787760802e-308; 60 const b = 2.2250738585072014e-308; 61 if (negzero < (-a) + b) { 62 if (negzero >= a - b) { 63 if (1 / Math.sign(negzero) == -Infinity) { 64 throw 1; 65 } 66 throw 2; 67 } 68 throw 3; 69 } 70 return 0; 71 } 72 73 function test_ltgt(negzero) { 74 inIon_ltgt = inIon(); 75 const a = 3.337610787760802e-308; 76 const b = 2.2250738585072014e-308; 77 if (negzero < (-a) + b) { 78 if (negzero > a - b) { 79 if (1 / Math.sign(negzero) == -Infinity) { 80 throw 1; 81 } 82 throw 2; 83 } 84 throw 3; 85 } 86 return 0; 87 } 88 89 function test_legt(negzero) { 90 inIon_legt = inIon(); 91 const a = 3.337610787760802e-308; 92 const b = 2.2250738585072014e-308; 93 if (negzero <= (-a) + b) { 94 if (negzero > a - b) { 95 if (1 / Math.sign(negzero) == -Infinity) { 96 throw 1; 97 } 98 throw 2; 99 } 100 return 1; 101 } 102 return 0; 103 } 104 105 // Disable the optimizing JIT on the top-level. 106 with({}){}; 107 108 // Assert consistency across execution modes. 109 let expect_lege = test_lege(-0.0); 110 let expect_legt = test_legt(-0.0); 111 let expect_ltgt = test_ltgt(-0.0); 112 let expect_ltge = test_ltge(-0.0); 113 while (!(inIon_lege && inIon_legt && inIon_ltgt && inIon_ltge)) { 114 assertEq(test_lege(-0.0), expect_lege); 115 assertEq(test_legt(-0.0), expect_legt); 116 assertEq(test_ltgt(-0.0), expect_ltgt); 117 assertEq(test_ltge(-0.0), expect_ltge); 118 }