udivormod-fallible.js (3430B)
1 // Test case for fallible unsigned division and modulus instructions. 2 // 3 // Doesn't include test that bailouts are correctly implemented. 4 5 // |MBinaryInstruction::unsignedOperands()| calls MustBeUInt32, which only 6 // treats MUrsh as unsigned when bailouts are disabled. 7 // 8 // |MUrsh::collectRangeInfoPreTrunc()| sets |MUrsh::bailoutsDisabled_| if 9 // the lower bound of the lhs operand is >= 0 and the lower bound of the rhs 10 // operand is >= 1. 11 // 12 // Use |Math.max(v, 0)| below to ensure the operand is non-negative, so that 13 // the |MUrsh| is marked as bailouts disabled. 14 15 // MMod::computeRange sets |MMod::unsigned_| flag. 16 // 17 // Range Analysis uses IsUint32Type to check for Uint32 types. IsUint32Type 18 // doesn't require that |Ursh| is marked as bailouts disabled. 19 // 20 // These don't need an explicit bit-or operation to mark as truncated. 21 function umod_by_constant(x) { 22 return (x >>> 0) % 3; 23 } 24 function umod_by_constant_pow_two(x) { 25 return (x >>> 0) % 4; 26 } 27 function umod(dividend, divisor) { 28 // Ensure range of |divisor| doesn't include zero. 29 divisor = Math.min(Math.max(divisor, 1), 10); 30 31 // Make sure |IsUint32Type| returns true for both operands. 32 return (dividend >>> 0) % (divisor >>> 0); 33 } 34 35 // |MMod::computeRange| also marks the operation as unsigned when the lower 36 // bound of the dividend is >= 0 (and the divisor's range doesn't include zero.) 37 function umod_by_constant_no_ursh(dividend, divisor) { 38 // Ensure lower bound of |dividend| range is >= 0. 39 dividend = Math.max(dividend, 0); 40 41 return dividend % 5; 42 } 43 function umod_no_ursh(dividend, divisor) { 44 // Ensure lower bound of |dividend| range is >= 0. 45 dividend = Math.max(dividend, 0); 46 47 // Ensure range of |divisor| doesn't include zero. 48 divisor = Math.min(Math.max(divisor, 1), 10); 49 50 return dividend % divisor; 51 } 52 53 // MMod::truncate sets |MMod::unsigned_| flag. Bit-or is needed to mark as truncated. 54 function umod_truncate(dividend, divisor) { 55 dividend = Math.max(dividend, 0); 56 divisor = Math.max(divisor, 0); 57 return ((dividend >>> 0) % (divisor >>> 0))|0; 58 } 59 60 // MDiv::truncate sets |MDiv::unsigned_| flag. Bit-or is needed to mark as truncated. 61 // 62 // Note: MDiv::computeRange never sets |MDiv::unsigned_|. 63 function udiv_by_constant(dividend) { 64 dividend = Math.max(dividend, 0); 65 return ((dividend >>> 0) / 3)|0; 66 } 67 function udiv_by_constant_pow_two(dividend) { 68 dividend = Math.max(dividend, 0); 69 return ((dividend >>> 0) / 8)|0; 70 } 71 function udiv(dividend, divisor) { 72 dividend = Math.max(dividend, 0); 73 divisor = Math.max(divisor, 0); 74 return ((dividend >>> 0) / (divisor >>> 0))|0; 75 } 76 77 // Don't Ion compile the top-level script. 78 with ({}); 79 80 for (let i = 0; i < 100; ++i) { 81 assertEq(umod_by_constant(i), i % 3); 82 assertEq(umod_by_constant_pow_two(i), i % 4); 83 84 assertEq(umod(i, 1), i % 1); 85 assertEq(umod(i, 3), i % 3); 86 assertEq(umod(i, 5), i % 5); 87 88 assertEq(umod_by_constant_no_ursh(i), i % 5); 89 90 assertEq(umod_no_ursh(i, 1), i % 1); 91 assertEq(umod_no_ursh(i, 7), i % 7); 92 assertEq(umod_no_ursh(i, 9), i % 9); 93 94 assertEq(umod_truncate(i, 1), i % 1); 95 assertEq(umod_truncate(i, 6), i % 6); 96 assertEq(umod_truncate(i, 11), i % 11); 97 98 // Use multiples of the divisor to ensure CacheIR doesn't emit a Double division. (bug 1554721) 99 assertEq(udiv_by_constant(i * 3), i); 100 assertEq(udiv_by_constant_pow_two(i * 8), i); 101 102 assertEq(udiv(i * 1, 1), i); 103 assertEq(udiv(i * 3, 3), i); 104 assertEq(udiv(i * 5, 5), i); 105 }