Bug 1279248 - Part 25: Extra tests, r=lth
authorHannes Verschore <hv1989@gmail.com>
Fri, 29 Jul 2016 16:53:48 +0200
changeset 332380 bb7803606205b1d23590fa05d78c384b833f614d
parent 332379 346f051f5978d60b4e716a5a6d6b9d4d2415892f
child 332381 4dabba8cf9261e11c487fb9aac71bc866f45250a
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslth
bugs1279248
milestone50.0a1
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