Bug 1279248 - Part 25: Extra tests, r=lth
authorHannes Verschore <hv1989@gmail.com>
Fri, 29 Jul 2016 16:53:48 +0200
changeset 347346 bb7803606205b1d23590fa05d78c384b833f614d
parent 347345 346f051f5978d60b4e716a5a6d6b9d4d2415892f
child 347347 4dabba8cf9261e11c487fb9aac71bc866f45250a
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslth
bugs1279248
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1279248 - Part 25: Extra tests, r=lth
js/src/jit-test/tests/wasm/basic-conversion.js
js/src/jit-test/tests/wasm/basic-integer.js
js/src/jit/MacroAssembler.h
js/src/jit/arm/MacroAssembler-arm-inl.h
js/src/jit/arm64/MacroAssembler-arm64-inl.h
js/src/jit/mips32/MacroAssembler-mips32-inl.h
js/src/jit/mips64/MacroAssembler-mips64-inl.h
js/src/jit/x64/MacroAssembler-x64-inl.h
js/src/jit/x86/MacroAssembler-x86-inl.h
js/src/jsapi-tests/moz.build
js/src/jsapi-tests/testJitMacroAssembler.cpp
--- a/js/src/jit-test/tests/wasm/basic-conversion.js
+++ b/js/src/jit-test/tests/wasm/basic-conversion.js
@@ -91,23 +91,29 @@ if (hasI64()) {
     testConversion('i64', 'extend_u', 'i32', 0x80000000, "0x0000000080000000");
 
     testConversion('f32', 'convert_s', 'i64', 1, 1.0);
     testConversion('f32', 'convert_s', 'i64', -1, -1.0);
     testConversion('f32', 'convert_s', 'i64', 0, 0.0);
     testConversion('f32', 'convert_s', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
     testConversion('f32', 'convert_s', 'i64', "0x8000000000000000", -9223372036854775808.0);
     testConversion('f32', 'convert_s', 'i64', "0x11db9e76a2483", 314159275180032.0);
+    testConversion('f32', 'convert_s', 'i64', "0x7fffffff", 2147483648.0); // closesth approx.
+    testConversion('f32', 'convert_s', 'i64', "0x80000000", 2147483648.0);
+    testConversion('f32', 'convert_s', 'i64', "0x80000001", 2147483648.0); // closesth approx.
 
     testConversion('f64', 'convert_s', 'i64', 1, 1.0);
     testConversion('f64', 'convert_s', 'i64', -1, -1.0);
     testConversion('f64', 'convert_s', 'i64', 0, 0.0);
     testConversion('f64', 'convert_s', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
     testConversion('f64', 'convert_s', 'i64', "0x8000000000000000", -9223372036854775808.0);
     testConversion('f64', 'convert_s', 'i64', "0x10969d374b968e", 4669201609102990);
+    testConversion('f64', 'convert_s', 'i64', "0x7fffffff", 2147483647.0);
+    testConversion('f64', 'convert_s', 'i64', "0x80000000", 2147483648.0);
+    testConversion('f64', 'convert_s', 'i64', "0x80000001", 2147483649.0);
 
     testConversion('f32', 'convert_u', 'i64', 1, 1.0);
     testConversion('f32', 'convert_u', 'i64', 0, 0.0);
     testConversion('f32', 'convert_u', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
     testConversion('f32', 'convert_u', 'i64', "0x8000000000000000", 9223372036854775808.0);
     testConversion('f32', 'convert_u', 'i64', -1, 18446744073709551616.0);
     testConversion('f32', 'convert_u', 'i64', "0xffff0000ffff0000", 18446462598732840000.0);
 
--- a/js/src/jit-test/tests/wasm/basic-integer.js
+++ b/js/src/jit-test/tests/wasm/basic-integer.js
@@ -153,16 +153,23 @@ if (hasI64()) {
     testBinary64('add', "0x1234567887654321", -1, "0x1234567887654320");
     testBinary64('add', "0xffffffffffffffff", 1, 0);
     testBinary64('sub', 40, 2, 38);
     testBinary64('sub', "0x1234567887654321", "0x123456789", "0x12345677641fdb98");
     testBinary64('sub', 3, 5, -2);
     testBinary64('mul', 40, 2, 80);
     testBinary64('mul', -1, 2, -2);
     testBinary64('mul', 0x123456, "0x9876543210", "0xad77d2c5f941160");
+    testBinary64('mul', 2, -1, -2);
+    testBinary64('mul', "0x80000000", -1, -2147483648);
+    testBinary64('mul', "0x7fffffff", -1, -2147483647);
+    testBinary64('mul', "0x7fffffffffffffff", -1, "0x8000000000000001");
+    testBinary64('mul', 2, 2, 4);
+    testBinary64('mul', "0x80000000", 2, "0x100000000");
+    testBinary64('mul', "0x7fffffff", 2, "0xfffffffe");
     testBinary64('div_s', -40, 2, -20);
     testBinary64('div_s', "0x1234567887654321", 2, "0x91a2b3c43b2a190");
     testBinary64('div_s', "0x1234567887654321", "0x1000000000", "0x1234567");
     testBinary64('div_u', -40, 2, "0x7fffffffffffffec");
     testBinary64('div_u', "0x1234567887654321", 9, "0x205d0b80f0b4059");
     testBinary64('rem_s', 40, -3, 1);
     testBinary64('rem_s', "0x1234567887654321", "0x1000000000", "0x887654321");
     testBinary64('rem_s', "0x7fffffffffffffff", -1, 0);
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -949,17 +949,18 @@ class MacroAssembler : public MacroAssem
         DEFINED_ON(arm, arm64, mips_shared, x86, x64);
 
     // The supported condition are Equal, NotEqual, LessThan(orEqual), GreaterThan(orEqual),
     // Below(orEqual) and Above(orEqual).
     inline void branch64(Condition cond, Register64 lhs, Imm64 val, Label* label)
         DEFINED_ON(x86, x64);
     inline void branch64(Condition cond, Register64 lhs, Register64 rhs, Label* label)
         DEFINED_ON(x86, x64);
-    // Only NotEqual conditions are allowed for the branch64 variants with Address as lhs.
+    // On x86 and x64 NotEqual and Equal conditions are allowed for the branch64 variants
+    // with Address as lhs. On others only the NotEqual condition.
     inline void branch64(Condition cond, const Address& lhs, Imm64 val, Label* label) PER_ARCH;
 
     // Compare the value at |lhs| with the value at |rhs|.  The scratch
     // register *must not* be the base of |lhs| or |rhs|.
     inline void branch64(Condition cond, const Address& lhs, const Address& rhs, Register scratch,
                          Label* label) PER_ARCH;
 
     inline void branchPtr(Condition cond, Register lhs, Register rhs, Label* label) PER_SHARED_ARCH;
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h
+++ b/js/src/jit/arm/MacroAssembler-arm-inl.h
@@ -509,78 +509,86 @@ MacroAssembler::maxDouble(FloatRegister 
 }
 
 // ===============================================================
 // Shift functions
 
 void
 MacroAssembler::lshiftPtr(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     ma_lsl(imm, dest, dest);
 }
 
 void
 MacroAssembler::lshift64(Imm32 imm, Register64 dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     as_mov(dest.high, lsl(dest.high, imm.value));
     as_orr(dest.high, dest.high, lsr(dest.low, 32 - imm.value));
     as_mov(dest.low, lsl(dest.low, imm.value));
 }
 
 void
 MacroAssembler::lshift32(Register src, Register dest)
 {
     ma_lsl(src, dest, dest);
 }
 
 void
 MacroAssembler::lshift32(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     lshiftPtr(imm, dest);
 }
 
 void
 MacroAssembler::rshiftPtr(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     ma_lsr(imm, dest, dest);
 }
 
 void
 MacroAssembler::rshift32(Register src, Register dest)
 {
     ma_lsr(src, dest, dest);
 }
 
 void
 MacroAssembler::rshift32(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     rshiftPtr(imm, dest);
 }
 
 void
 MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     ma_asr(imm, dest, dest);
 }
 
 void
 MacroAssembler::rshift32Arithmetic(Register src, Register dest)
 {
     ma_asr(src, dest, dest);
 }
 
 void
 MacroAssembler::rshift32Arithmetic(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     rshiftPtrArithmetic(imm, dest);
 }
 
 void
 MacroAssembler::rshift64(Imm32 imm, Register64 dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     as_mov(dest.low, lsr(dest.low, imm.value));
     as_orr(dest.low, dest.low, lsl(dest.high, 32 - imm.value));
     as_mov(dest.high, lsr(dest.high, imm.value));
 }
 
 // ===============================================================
 // Rotate functions
 void
--- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h
@@ -536,82 +536,91 @@ MacroAssembler::maxDouble(FloatRegister 
 }
 
 // ===============================================================
 // Shift functions
 
 void
 MacroAssembler::lshiftPtr(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     Lsl(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value);
 }
 
 void
 MacroAssembler::lshift64(Imm32 imm, Register64 dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     lshiftPtr(imm, dest.reg);
 }
 
 void
 MacroAssembler::lshift32(Register shift, Register dest)
 {
     Lsl(ARMRegister(dest, 32), ARMRegister(dest, 32), ARMRegister(shift, 32));
 }
 
 void
 MacroAssembler::lshift32(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     Lsl(ARMRegister(dest, 32), ARMRegister(dest, 32), imm.value);
 }
 
 void
 MacroAssembler::rshiftPtr(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     Lsr(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value);
 }
 
 void
 MacroAssembler::rshiftPtr(Imm32 imm, Register src, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     Lsr(ARMRegister(dest, 64), ARMRegister(src, 64), imm.value);
 }
 
 void
 MacroAssembler::rshift32(Register shift, Register dest)
 {
     Lsr(ARMRegister(dest, 32), ARMRegister(dest, 32), ARMRegister(shift, 32));
 }
 
 void
 MacroAssembler::rshift32(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     Lsr(ARMRegister(dest, 32), ARMRegister(dest, 32), imm.value);
 }
 
 void
 MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     Asr(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value);
 }
 
 void
 MacroAssembler::rshift32Arithmetic(Register shift, Register dest)
 {
     Asr(ARMRegister(dest, 32), ARMRegister(dest, 32), ARMRegister(shift, 32));
 }
 
 void
 MacroAssembler::rshift32Arithmetic(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     Asr(ARMRegister(dest, 32), ARMRegister(dest, 32), imm.value);
 }
 
 void
 MacroAssembler::rshift64(Imm32 imm, Register64 dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     rshiftPtr(imm, dest.reg);
 }
 
 // ===============================================================
 // Rotation functions
 void
 MacroAssembler::rotateLeft(Imm32 count, Register input, Register dest)
 {
--- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h
@@ -225,44 +225,49 @@ MacroAssembler::inc64(AbsoluteAddress de
 }
 
 // ===============================================================
 // Shift functions
 
 void
 MacroAssembler::lshiftPtr(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     ma_sll(dest, dest, imm);
 }
 
 void
 MacroAssembler::lshift64(Imm32 imm, Register64 dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     ScratchRegisterScope scratch(*this);
     as_sll(dest.high, dest.high, imm.value);
     as_srl(scratch, dest.low, 32 - imm.value);
     as_or(dest.high, dest.high, scratch);
     as_sll(dest.low, dest.low, imm.value);
 }
 
 void
 MacroAssembler::rshiftPtr(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     ma_srl(dest, dest, imm);
 }
 
 void
 MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     ma_sra(dest, dest, imm);
 }
 
 void
 MacroAssembler::rshift64(Imm32 imm, Register64 dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     ScratchRegisterScope scratch(*this);
     as_srl(dest.low, dest.low, imm.value);
     as_sll(scratch, dest.high, 32 - imm.value);
     as_or(dest.low, dest.low, scratch);
     as_srl(dest.high, dest.high, imm.value);
 }
 
 // ===============================================================
--- a/js/src/jit/mips64/MacroAssembler-mips64-inl.h
+++ b/js/src/jit/mips64/MacroAssembler-mips64-inl.h
@@ -172,40 +172,45 @@ MacroAssembler::inc64(AbsoluteAddress de
 }
 
 // ===============================================================
 // Shift functions
 
 void
 MacroAssembler::lshiftPtr(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     ma_dsll(dest, dest, imm);
 }
 
 void
 MacroAssembler::lshift64(Imm32 imm, Register64 dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     ma_dsll(dest.reg, dest.reg, imm);
 }
 
 void
 MacroAssembler::rshiftPtr(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     ma_dsrl(dest, dest, imm);
 }
 
 void
 MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     ma_dsra(dest, dest, imm);
 }
 
 void
 MacroAssembler::rshift64(Imm32 imm, Register64 dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     ma_dsrl(dest.reg, dest.reg, imm);
 }
 
 // ===============================================================
 // Branch functions
 
 void
 MacroAssembler::branch64(Condition cond, const Address& lhs, Imm64 val, Label* label)
--- a/js/src/jit/x64/MacroAssembler-x64-inl.h
+++ b/js/src/jit/x64/MacroAssembler-x64-inl.h
@@ -322,35 +322,38 @@ MacroAssembler::neg64(Register64 reg)
 }
 
 // ===============================================================
 // Shift functions
 
 void
 MacroAssembler::lshiftPtr(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     shlq(imm, dest);
 }
 
 void
 MacroAssembler::lshift64(Imm32 imm, Register64 dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     lshiftPtr(imm, dest.reg);
 }
 
 void
 MacroAssembler::lshift64(Register shift, Register64 srcDest)
 {
     MOZ_ASSERT(shift == rcx);
     shlq_cl(srcDest.reg);
 }
 
 void
 MacroAssembler::rshiftPtr(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     shrq(imm, dest);
 }
 
 void
 MacroAssembler::rshift64(Imm32 imm, Register64 dest)
 {
     rshiftPtr(imm, dest.reg);
 }
@@ -360,22 +363,24 @@ MacroAssembler::rshift64(Register shift,
 {
     MOZ_ASSERT(shift == rcx);
     shrq_cl(srcDest.reg);
 }
 
 void
 MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     sarq(imm, dest);
 }
 
 void
 MacroAssembler::rshift64Arithmetic(Imm32 imm, Register64 dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     rshiftPtrArithmetic(imm, dest.reg);
 }
 
 void
 MacroAssembler::rshift64Arithmetic(Register shift, Register64 srcDest)
 {
     MOZ_ASSERT(shift == rcx);
     sarq_cl(srcDest.reg);
@@ -577,27 +582,27 @@ MacroAssembler::branch64(Condition cond,
                "other condition codes not supported");
 
     branchPtr(cond, lhs.reg, rhs.reg, label);
 }
 
 void
 MacroAssembler::branch64(Condition cond, const Address& lhs, Imm64 val, Label* label)
 {
-    MOZ_ASSERT(cond == Assembler::NotEqual,
+    MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal,
                "other condition codes not supported");
 
     branchPtr(cond, lhs, ImmWord(val.value), label);
 }
 
 void
 MacroAssembler::branch64(Condition cond, const Address& lhs, const Address& rhs, Register scratch,
                          Label* label)
 {
-    MOZ_ASSERT(cond == Assembler::NotEqual,
+    MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal,
                "other condition codes not supported");
     MOZ_ASSERT(lhs.base != scratch);
     MOZ_ASSERT(rhs.base != scratch);
 
     loadPtr(rhs, scratch);
     branchPtr(cond, lhs, scratch, label);
 }
 
@@ -741,17 +746,17 @@ MacroAssembler::truncateFloat32ToUInt64(
     Label done;
 
     loadFloat32(src, floatTemp);
 
     truncateFloat32ToInt64(src, dest, temp);
 
     // For unsigned conversion the case of [INT64, UINT64] needs to get handle seperately.
     loadPtr(dest, temp);
-    branch32(Assembler::Condition::NotSigned, temp, Imm32(0), &done);
+    branchPtr(Assembler::Condition::NotSigned, temp, Imm32(0), &done);
 
     // Move the value inside INT64 range.
     storeFloat32(floatTemp, dest);
     loadConstantFloat32(double(int64_t(0x8000000000000000)), floatTemp);
     vaddss(Operand(dest), floatTemp, floatTemp);
     storeFloat32(floatTemp, dest);
     truncateFloat32ToInt64(dest, dest, temp);
 
@@ -769,17 +774,17 @@ MacroAssembler::truncateDoubleToUInt64(A
     Label done;
 
     loadDouble(src, floatTemp);
 
     truncateDoubleToInt64(src, dest, temp);
 
     // For unsigned conversion the case of [INT64, UINT64] needs to get handle seperately.
     loadPtr(dest, temp);
-    branch32(Assembler::Condition::NotSigned, temp, Imm32(0), &done);
+    branchPtr(Assembler::Condition::NotSigned, temp, Imm32(0), &done);
 
     // Move the value inside INT64 range.
     storeDouble(floatTemp, dest);
     loadConstantDouble(double(int64_t(0x8000000000000000)), floatTemp);
     vaddsd(Operand(dest), floatTemp, floatTemp);
     storeDouble(floatTemp, dest);
     truncateDoubleToInt64(dest, dest, temp);
 
--- a/js/src/jit/x86/MacroAssembler-x86-inl.h
+++ b/js/src/jit/x86/MacroAssembler-x86-inl.h
@@ -346,23 +346,25 @@ MacroAssembler::neg64(Register64 reg)
 }
 
 // ===============================================================
 // Shift functions
 
 void
 MacroAssembler::lshiftPtr(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     shll(imm, dest);
 }
 
 void
 MacroAssembler::lshift64(Imm32 imm, Register64 dest)
 {
-    if ((imm.value & INT32_MAX) < 32) {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
+    if (imm.value < 32) {
         shldl(imm, dest.low, dest.high);
         shll(imm, dest.low);
         return;
     }
 
     mov(dest.low, dest.high);
     shll(Imm32(imm.value & 0x1f), dest.high);
     xorl(dest.low, dest.low);
@@ -387,23 +389,25 @@ MacroAssembler::lshift64(Register shift,
     xorl(srcDest.low, srcDest.low);
 
     bind(&done);
 }
 
 void
 MacroAssembler::rshiftPtr(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     shrl(imm, dest);
 }
 
 void
 MacroAssembler::rshift64(Imm32 imm, Register64 dest)
 {
-    if ((imm.value & INT32_MAX) < 32) {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
+    if (imm.value < 32) {
         shrdl(imm, dest.high, dest.low);
         shrl(imm, dest.high);
         return;
     }
 
     movl(dest.high, dest.low);
     shrl(Imm32(imm.value & 0x1f), dest.low);
     xorl(dest.high, dest.high);
@@ -428,23 +432,25 @@ MacroAssembler::rshift64(Register shift,
     xorl(srcDest.high, srcDest.high);
 
     bind(&done);
 }
 
 void
 MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest)
 {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     sarl(imm, dest);
 }
 
 void
 MacroAssembler::rshift64Arithmetic(Imm32 imm, Register64 dest)
 {
-    if ((imm.value & INT32_MAX) < 32) {
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
+    if (imm.value < 32) {
         shrdl(imm, dest.high, dest.low);
         sarl(imm, dest.high);
         return;
     }
 
     movl(dest.high, dest.low);
     sarl(Imm32(imm.value & 0x1f), dest.low);
     sarl(Imm32(0x1f), dest.high);
@@ -710,37 +716,51 @@ MacroAssembler::branch64(Condition cond,
     }
 
     bind(&fail);
 }
 
 void
 MacroAssembler::branch64(Condition cond, const Address& lhs, Imm64 val, Label* label)
 {
-    MOZ_ASSERT(cond == Assembler::NotEqual,
+    MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal,
                "other condition codes not supported");
 
-    branch32(cond, lhs, val.firstHalf(), label);
+    Label done;
+
+    if (cond == Assembler::Equal)
+        branch32(Assembler::NotEqual, lhs, val.firstHalf(), &done);
+    else
+        branch32(Assembler::NotEqual, lhs, val.firstHalf(), label);
     branch32(cond, Address(lhs.base, lhs.offset + sizeof(uint32_t)), val.secondHalf(), label);
+
+    bind(&done);
 }
 
 void
 MacroAssembler::branch64(Condition cond, const Address& lhs, const Address& rhs, Register scratch,
                          Label* label)
 {
-    MOZ_ASSERT(cond == Assembler::NotEqual,
+    MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal,
                "other condition codes not supported");
     MOZ_ASSERT(lhs.base != scratch);
     MOZ_ASSERT(rhs.base != scratch);
 
+    Label done;
+
     load32(rhs, scratch);
-    branch32(cond, lhs, scratch, label);
+    if (cond == Assembler::Equal)
+        branch32(Assembler::NotEqual, lhs, scratch, &done);
+    else
+        branch32(Assembler::NotEqual, lhs, scratch, label);
 
     load32(Address(rhs.base, rhs.offset + sizeof(uint32_t)), scratch);
     branch32(cond, Address(lhs.base, lhs.offset + sizeof(uint32_t)), scratch, label);
+
+    bind(&done);
 }
 
 void
 MacroAssembler::branchPtr(Condition cond, const AbsoluteAddress& lhs, Register rhs, Label* label)
 {
     branchPtrImpl(cond, lhs, rhs, label);
 }
 
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -109,16 +109,17 @@ SOURCES += [
     'testAssemblerBuffer.cpp',
 ]
 
 if CONFIG['ENABLE_ION']:
     UNIFIED_SOURCES += [
         'testJitDCEinGVN.cpp',
         'testJitFoldsTo.cpp',
         'testJitGVN.cpp',
+        'testJitMacroAssembler.cpp',
         'testJitMoveEmitterCycles-mips32.cpp',
         'testJitMoveEmitterCycles.cpp',
         'testJitRangeAnalysis.cpp',
         'testJitRegisterSet.cpp',
         'testJitRValueAlloc.cpp',
     ]
 
 if CONFIG['SPIDERMONKEY_PROMISE']:
new file mode 100644
--- /dev/null
+++ b/js/src/jsapi-tests/testJitMacroAssembler.cpp
@@ -0,0 +1,476 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "jit/IonAnalysis.h"
+#include "jit/Linker.h"
+#include "jit/MacroAssembler.h"
+#include "jit/MIRGenerator.h"
+#include "jit/MIRGraph.h"
+#include "jit/ValueNumbering.h"
+#include "js/Value.h"
+
+#include "jsapi-tests/tests.h"
+
+#include "jit/MacroAssembler-inl.h"
+
+using namespace js;
+using namespace js::jit;
+
+using mozilla::PositiveInfinity;
+using mozilla::NegativeInfinity;
+
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+
+typedef void (*EnterTest)();
+
+static bool Prepare(MacroAssembler& masm)
+{
+    AllocatableRegisterSet regs(RegisterSet::Volatile());
+    LiveRegisterSet save(regs.asLiveSet());
+    masm.PushRegsInMask(save);
+    return true;
+}
+
+static bool Execute(JSContext* cx, MacroAssembler& masm)
+{
+    AllocatableRegisterSet regs(RegisterSet::Volatile());
+    LiveRegisterSet save(regs.asLiveSet());
+    masm.PopRegsInMask(save);
+    masm.ret(); // Add return statement to be sure.
+
+    if (masm.oom())
+        return false;
+
+    Linker linker(masm);
+    JitCode* code = linker.newCode<CanGC>(cx, OTHER_CODE);
+    if (!code)
+        return false;
+    if (!ExecutableAllocator::makeExecutable(code->raw(), code->bufferSize()))
+        return false;
+
+    EnterTest test = code->as<EnterTest>();
+    test();
+    return true;
+}
+
+BEGIN_TEST(testJitMacroAssembler_truncateDoubleToInt64)
+{
+    MacroAssembler masm(cx);
+
+    if (!Prepare(masm))
+        return false;
+
+    AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
+    AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
+    FloatRegister input = allFloatRegs.takeAny();
+#ifdef JS_NUNBOX32
+    Register64 output(allRegs.takeAny(), allRegs.takeAny());
+#else
+    Register64 output(allRegs.takeAny());
+#endif
+    Register temp = allRegs.takeAny();
+
+    masm.reserveStack(sizeof(int32_t));
+
+#define TEST(INPUT, OUTPUT)                                                     \
+    {                                                                           \
+        Label next;                                                             \
+        masm.loadConstantDouble(double(INPUT), input);                          \
+        masm.storeDouble(input, Operand(esp, 0));                               \
+        masm.truncateDoubleToInt64(Address(esp, 0), Address(esp, 0), temp);     \
+        masm.branch64(Assembler::Equal, Address(esp, 0), Imm64(OUTPUT), &next); \
+        masm.printf("truncateDoubleToInt64("#INPUT") failed\n");                \
+        masm.breakpoint();                                                      \
+        masm.bind(&next);                                                       \
+    }
+
+    TEST(0, 0);
+    TEST(-0, 0);
+    TEST(1, 1);
+    TEST(9223372036854774784.0, 9223372036854774784);
+    TEST(-9223372036854775808.0, 0x8000000000000000);
+    TEST(9223372036854775808.0, 0x8000000000000000);
+    TEST(JS::GenericNaN(), 0x8000000000000000);
+    TEST(PositiveInfinity<double>(), 0x8000000000000000);
+    TEST(NegativeInfinity<double>(), 0x8000000000000000);
+#undef TEST
+
+    masm.freeStack(sizeof(int32_t));
+
+    return Execute(cx, masm);
+}
+END_TEST(testJitMacroAssembler_truncateDoubleToInt64)
+
+BEGIN_TEST(testJitMacroAssembler_truncateDoubleToUInt64)
+{
+    MacroAssembler masm(cx);
+
+    if (!Prepare(masm))
+        return false;
+
+    AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
+    AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
+    FloatRegister input = allFloatRegs.takeAny();
+    FloatRegister floatTemp = allFloatRegs.takeAny();
+#ifdef JS_NUNBOX32
+    Register64 output(allRegs.takeAny(), allRegs.takeAny());
+#else
+    Register64 output(allRegs.takeAny());
+#endif
+    Register temp = allRegs.takeAny();
+
+    masm.reserveStack(sizeof(int32_t));
+
+#define TEST(INPUT, OUTPUT)                                                                \
+    {                                                                                      \
+        Label next;                                                                        \
+        masm.loadConstantDouble(double(INPUT), input);                                     \
+        masm.storeDouble(input, Operand(esp, 0));                                          \
+        masm.truncateDoubleToUInt64(Address(esp, 0), Address(esp, 0), temp, floatTemp);    \
+        masm.branch64(Assembler::Equal, Address(esp, 0), Imm64(OUTPUT), &next);            \
+        masm.printf("truncateDoubleToUInt64("#INPUT") failed\n");                          \
+        masm.breakpoint();                                                                 \
+        masm.bind(&next);                                                                  \
+    }
+
+    TEST(0, 0);
+    TEST(1, 1);
+    TEST(9223372036854774784.0, 9223372036854774784);
+    TEST((uint64_t)0x8000000000000000, 0x8000000000000000);
+    TEST((uint64_t)0x8000000000000001, 0x8000000000000000);
+    TEST((uint64_t)0x8006004000000001, 0x8006004000000000);
+    TEST(-0.0, 0);
+    TEST(-0.5, 0);
+    TEST(-0.99, 0);
+    TEST(JS::GenericNaN(), 0x8000000000000000);
+    TEST(PositiveInfinity<double>(), 0x8000000000000000);
+    TEST(NegativeInfinity<double>(), 0x8000000000000000);
+#undef TEST
+
+    masm.freeStack(sizeof(int32_t));
+
+    return Execute(cx, masm);
+}
+END_TEST(testJitMacroAssembler_truncateDoubleToUInt64)
+
+BEGIN_TEST(testJitMacroAssembler_branchDoubleNotInInt64Range)
+{
+    MacroAssembler masm(cx);
+
+    if (!Prepare(masm))
+        return false;
+
+    AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
+    AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
+    FloatRegister input = allFloatRegs.takeAny();
+#ifdef JS_NUNBOX32
+    Register64 output(allRegs.takeAny(), allRegs.takeAny());
+#else
+    Register64 output(allRegs.takeAny());
+#endif
+    Register temp = allRegs.takeAny();
+
+    masm.reserveStack(sizeof(int32_t));
+
+#define TEST(INPUT, OUTPUT)                                                                 \
+    {                                                                                       \
+        Label next;                                                                         \
+        masm.loadConstantDouble(double(INPUT), input);                                      \
+        masm.storeDouble(input, Operand(esp, 0));                                           \
+        if (OUTPUT) {                                                                       \
+            masm.branchDoubleNotInInt64Range(Address(esp, 0), temp, &next);                 \
+        } else {                                                                            \
+            Label fail;                                                                     \
+            masm.branchDoubleNotInInt64Range(Address(esp, 0), temp, &fail);                 \
+            masm.jump(&next);                                                               \
+            masm.bind(&fail);                                                               \
+        }                                                                                   \
+        masm.printf("branchDoubleNotInInt64Range("#INPUT") failed\n");                      \
+        masm.breakpoint();                                                                  \
+        masm.bind(&next);                                                                   \
+    }
+
+    TEST(0, false);
+    TEST(-0, false);
+    TEST(1, false);
+    TEST(9223372036854774784.0, false);
+    TEST(-9223372036854775808.0, true);
+    TEST(9223372036854775808.0, true);
+    TEST(JS::GenericNaN(), true);
+    TEST(PositiveInfinity<double>(), true);
+    TEST(NegativeInfinity<double>(), true);
+#undef TEST
+
+    masm.freeStack(sizeof(int32_t));
+
+    return Execute(cx, masm);
+}
+END_TEST(testJitMacroAssembler_branchDoubleNotInInt64Range)
+
+BEGIN_TEST(testJitMacroAssembler_branchDoubleNotInUInt64Range)
+{
+    MacroAssembler masm(cx);
+
+    if (!Prepare(masm))
+        return false;
+
+    AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
+    AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
+    FloatRegister input = allFloatRegs.takeAny();
+#ifdef JS_NUNBOX32
+    Register64 output(allRegs.takeAny(), allRegs.takeAny());
+#else
+    Register64 output(allRegs.takeAny());
+#endif
+    Register temp = allRegs.takeAny();
+
+    masm.reserveStack(sizeof(int32_t));
+
+#define TEST(INPUT, OUTPUT)                                                                 \
+    {                                                                                       \
+        Label next;                                                                         \
+        masm.loadConstantDouble(double(INPUT), input);                                      \
+        masm.storeDouble(input, Operand(esp, 0));                                           \
+        if (OUTPUT) {                                                                       \
+            masm.branchDoubleNotInUInt64Range(Address(esp, 0), temp, &next);                \
+        } else {                                                                            \
+            Label fail;                                                                     \
+            masm.branchDoubleNotInUInt64Range(Address(esp, 0), temp, &fail);                \
+            masm.jump(&next);                                                               \
+            masm.bind(&fail);                                                               \
+        }                                                                                   \
+        masm.printf("branchDoubleNotInUInt64Range("#INPUT") failed\n");                     \
+        masm.breakpoint();                                                                  \
+        masm.bind(&next);                                                                   \
+    }
+
+    TEST(0, false);
+    TEST(1, false);
+    TEST(9223372036854774784.0, false);
+    TEST((uint64_t)0x8000000000000000, false);
+    TEST((uint64_t)0x8000000000000001, false);
+    TEST((uint64_t)0x8006004000000001, false);
+    TEST(-0.0, true);
+    TEST(-0.5, true);
+    TEST(-0.99, true);
+    TEST(JS::GenericNaN(), true);
+    TEST(PositiveInfinity<double>(), true);
+    TEST(NegativeInfinity<double>(), true);
+#undef TEST
+
+    masm.freeStack(sizeof(int32_t));
+
+    return Execute(cx, masm);
+}
+END_TEST(testJitMacroAssembler_branchDoubleNotInUInt64Range)
+
+BEGIN_TEST(testJitMacroAssembler_lshift64)
+{
+    MacroAssembler masm(cx);
+
+    if (!Prepare(masm))
+        return false;
+
+    AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
+    AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
+#if defined(JS_CODEGEN_X86)
+    Register shift = ecx;
+    allRegs.take(shift);
+#elif defined(JS_CODEGEN_X64)
+    Register shift = rcx;
+    allRegs.take(shift);
+#else
+    Register shift = allRegs.takeAny();
+#endif
+
+#ifdef JS_NUNBOX32
+    Register64 input(allRegs.takeAny(), allRegs.takeAny());
+#else
+    Register64 input(allRegs.takeAny());
+#endif
+
+    masm.reserveStack(sizeof(int32_t));
+
+#define TEST(SHIFT, INPUT, OUTPUT)                                                          \
+    {                                                                                       \
+        Label next;                                                                         \
+        masm.move64(Imm64(INPUT), input);                                                   \
+        masm.move32(Imm32(SHIFT), shift);                                                   \
+        masm.lshift64(shift, input);                                                        \
+        masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next);                       \
+        masm.printf("lshift64("#SHIFT", "#INPUT") failed\n");                               \
+        masm.breakpoint();                                                                  \
+        masm.bind(&next);                                                                   \
+    }                                                                                       \
+    {                                                                                       \
+        Label next;                                                                         \
+        masm.move64(Imm64(INPUT), input);                                                   \
+        masm.lshift64(Imm32(SHIFT & 0x3f), input);                                          \
+        masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next);                       \
+        masm.printf("lshift64(Imm32("#SHIFT"&0x3f), "#INPUT") failed\n");                   \
+        masm.breakpoint();                                                                  \
+        masm.bind(&next);                                                                   \
+    }
+
+    TEST(0, 1, 1);
+    TEST(1, 1, 2);
+    TEST(2, 1, 4);
+    TEST(32, 1, 0x0000000100000000);
+    TEST(33, 1, 0x0000000200000000);
+    TEST(0, -1, 0xffffffffffffffff);
+    TEST(1, -1, 0xfffffffffffffffe);
+    TEST(2, -1, 0xfffffffffffffffc);
+    TEST(32, -1, 0xffffffff00000000);
+    TEST(0xffffffff, 1, 0x8000000000000000);
+    TEST(0xfffffffe, 1, 0x4000000000000000);
+    TEST(0xfffffffd, 1, 0x2000000000000000);
+    TEST(0x80000001, 1, 2);
+#undef TEST
+
+    masm.freeStack(sizeof(int32_t));
+
+    return Execute(cx, masm);
+}
+END_TEST(testJitMacroAssembler_lshift64)
+
+BEGIN_TEST(testJitMacroAssembler_rshift64Arithmetic)
+{
+    MacroAssembler masm(cx);
+
+    if (!Prepare(masm))
+        return false;
+
+    AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
+    AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
+#if defined(JS_CODEGEN_X86)
+    Register shift = ecx;
+    allRegs.take(shift);
+#elif defined(JS_CODEGEN_X64)
+    Register shift = rcx;
+    allRegs.take(shift);
+#else
+    Register shift = allRegs.takeAny();
+#endif
+
+#ifdef JS_NUNBOX32
+    Register64 input(allRegs.takeAny(), allRegs.takeAny());
+#else
+    Register64 input(allRegs.takeAny());
+#endif
+
+    masm.reserveStack(sizeof(int32_t));
+
+#define TEST(SHIFT, INPUT, OUTPUT)                                                          \
+    {                                                                                       \
+        Label next;                                                                         \
+        masm.move64(Imm64(INPUT), input);                                                   \
+        masm.move32(Imm32(SHIFT), shift);                                                   \
+        masm.rshift64Arithmetic(shift, input);                                              \
+        masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next);                       \
+        masm.printf("rshift64Arithmetic("#SHIFT", "#INPUT") failed\n");                     \
+        masm.breakpoint();                                                                  \
+        masm.bind(&next);                                                                   \
+    }                                                                                       \
+    {                                                                                       \
+        Label next;                                                                         \
+        masm.move64(Imm64(INPUT), input);                                                   \
+        masm.rshift64Arithmetic(Imm32(SHIFT & 0x3f), input);                                \
+        masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next);                       \
+        masm.printf("rshift64Arithmetic(Imm32("#SHIFT"&0x3f), "#INPUT") failed\n");         \
+        masm.breakpoint();                                                                  \
+        masm.bind(&next);                                                                   \
+    }
+
+    TEST(0, 0x4000000000000000, 0x4000000000000000);
+    TEST(1, 0x4000000000000000, 0x2000000000000000);
+    TEST(2, 0x4000000000000000, 0x1000000000000000);
+    TEST(32, 0x4000000000000000, 0x0000000040000000);
+    TEST(0, 0x8000000000000000, 0x8000000000000000);
+    TEST(1, 0x8000000000000000, 0xc000000000000000);
+    TEST(2, 0x8000000000000000, 0xe000000000000000);
+    TEST(32, 0x8000000000000000, 0xffffffff80000000);
+    TEST(0xffffffff, 0x8000000000000000, 0xffffffffffffffff);
+    TEST(0xfffffffe, 0x8000000000000000, 0xfffffffffffffffe);
+    TEST(0xfffffffd, 0x8000000000000000, 0xfffffffffffffffc);
+    TEST(0x80000001, 0x8000000000000000, 0xc000000000000000);
+#undef TEST
+
+    masm.freeStack(sizeof(int32_t));
+
+    return Execute(cx, masm);
+}
+END_TEST(testJitMacroAssembler_rshift64Arithmetic)
+
+BEGIN_TEST(testJitMacroAssembler_rshift64)
+{
+    MacroAssembler masm(cx);
+
+    if (!Prepare(masm))
+        return false;
+
+    AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
+    AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
+#if defined(JS_CODEGEN_X86)
+    Register shift = ecx;
+    allRegs.take(shift);
+#elif defined(JS_CODEGEN_X64)
+    Register shift = rcx;
+    allRegs.take(shift);
+#else
+    Register shift = allRegs.takeAny();
+#endif
+
+#ifdef JS_NUNBOX32
+    Register64 input(allRegs.takeAny(), allRegs.takeAny());
+#else
+    Register64 input(allRegs.takeAny());
+#endif
+
+    masm.reserveStack(sizeof(int32_t));
+
+#define TEST(SHIFT, INPUT, OUTPUT)                                                          \
+    {                                                                                       \
+        Label next;                                                                         \
+        masm.move64(Imm64(INPUT), input);                                                   \
+        masm.move32(Imm32(SHIFT), shift);                                                   \
+        masm.rshift64(shift, input);                                                        \
+        masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next);                       \
+        masm.printf("rshift64("#SHIFT", "#INPUT") failed\n");                               \
+        masm.breakpoint();                                                                  \
+        masm.bind(&next);                                                                   \
+    }                                                                                       \
+    {                                                                                       \
+        Label next;                                                                         \
+        masm.move64(Imm64(INPUT), input);                                                   \
+        masm.rshift64(Imm32(SHIFT & 0x3f), input);                                          \
+        masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next);                       \
+        masm.printf("rshift64(Imm32("#SHIFT"&0x3f), "#INPUT") failed\n");                   \
+        masm.breakpoint();                                                                  \
+        masm.bind(&next);                                                                   \
+    }
+
+    TEST(0, 0x4000000000000000, 0x4000000000000000);
+    TEST(1, 0x4000000000000000, 0x2000000000000000);
+    TEST(2, 0x4000000000000000, 0x1000000000000000);
+    TEST(32, 0x4000000000000000, 0x0000000040000000);
+    TEST(0, 0x8000000000000000, 0x8000000000000000);
+    TEST(1, 0x8000000000000000, 0x4000000000000000);
+    TEST(2, 0x8000000000000000, 0x2000000000000000);
+    TEST(32, 0x8000000000000000, 0x0000000080000000);
+    TEST(0xffffffff, 0x8000000000000000, 0x0000000000000001);
+    TEST(0xfffffffe, 0x8000000000000000, 0x0000000000000002);
+    TEST(0xfffffffd, 0x8000000000000000, 0x0000000000000004);
+    TEST(0x80000001, 0x8000000000000000, 0x4000000000000000);
+#undef TEST
+
+    masm.freeStack(sizeof(int32_t));
+
+    return Execute(cx, masm);
+}
+END_TEST(testJitMacroAssembler_rshift64)
+
+#endif