Bug 1289054 - Part 8: Implement the 64bit variant of Compare on arm, r=nbp
authorHannes Verschore <hv1989@gmail.com>
Fri, 29 Jul 2016 16:53:49 +0200
changeset 347357 df8f35c1858453850c471339bf3e7687f30cf8b6
parent 347356 48ed814c72c6db5913e0eb5f5724035a652e57cc
child 347358 65981e46881a04d3b36fd9fbd69cb79169d75e83
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)
reviewersnbp
bugs1289054
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 1289054 - Part 8: Implement the 64bit variant of Compare on arm, r=nbp
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/MacroAssembler.h
js/src/jit/arm/CodeGenerator-arm.cpp
js/src/jit/arm/CodeGenerator-arm.h
js/src/jit/arm/MacroAssembler-arm-inl.h
js/src/jit/shared/CodeGenerator-shared.cpp
js/src/jit/shared/CodeGenerator-shared.h
js/src/jit/x64/MacroAssembler-x64-inl.h
js/src/jit/x86/CodeGenerator-x86.cpp
js/src/jit/x86/MacroAssembler-x86-inl.h
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -646,39 +646,16 @@ CodeGenerator::testValueTruthy(const Val
                                Label* ifTruthy, Label* ifFalsy,
                                OutOfLineTestObject* ool,
                                MDefinition* valueMIR)
 {
     testValueTruthyKernel(value, scratch1, scratch2, fr, ifTruthy, ifFalsy, ool, valueMIR);
     masm.jump(ifTruthy);
 }
 
-Label*
-CodeGenerator::getJumpLabelForBranch(MBasicBlock* block)
-{
-    // Skip past trivial blocks.
-    block = skipTrivialBlocks(block);
-
-    if (!labelForBackedgeWithImplicitCheck(block))
-        return block->lir()->label();
-
-    // We need to use a patchable jump for this backedge, but want to treat
-    // this as a normal label target to simplify codegen. Efficiency isn't so
-    // important here as these tests are extremely unlikely to be used in loop
-    // backedges, so emit inline code for the patchable jump. Heap allocating
-    // the label allows it to be used by out of line blocks.
-    Label* res = alloc().lifoAlloc()->newInfallible<Label>();
-    Label after;
-    masm.jump(&after);
-    masm.bind(res);
-    jumpToBlock(block);
-    masm.bind(&after);
-    return res;
-}
-
 void
 CodeGenerator::visitTestOAndBranch(LTestOAndBranch* lir)
 {
     MIRType inputType = lir->mir()->input()->type();
     MOZ_ASSERT(inputType == MIRType::ObjectOrNull || lir->mir()->operandMightEmulateUndefined(),
                "If the object couldn't emulate undefined, this should have been folded.");
 
     Label* truthy = getJumpLabelForBranch(lir->ifTruthy());
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -504,20 +504,16 @@ class CodeGenerator final : public CodeG
                                      Label* ifEmulatesUndefined,
                                      Label* ifDoesntEmulateUndefined,
                                      Register scratch, OutOfLineTestObject* ool);
 
     // Branch to target unless obj has an emptyObjectElements or emptyObjectElementsShared
     // elements pointer.
     void branchIfNotEmptyObjectElements(Register obj, Label* target);
 
-    // Get a label for the start of block which can be used for jumping, in
-    // place of jumpToBlock.
-    Label* getJumpLabelForBranch(MBasicBlock* block);
-
     void emitStoreElementTyped(const LAllocation* value, MIRType valueType, MIRType elementType,
                                Register elements, const LAllocation* index,
                                int32_t offsetAdjustment);
 
     // Bailout if an element about to be written to is a hole.
     void emitStoreHoleCheck(Register elements, const LAllocation* index, int32_t offsetAdjustment,
                             LSnapshot* snapshot);
 
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -946,20 +946,22 @@ class MacroAssembler : public MacroAssem
     inline void branch32(Condition cond, const Operand& lhs, Register rhs, Label* label) DEFINED_ON(x86_shared);
     inline void branch32(Condition cond, const Operand& lhs, Imm32 rhs, Label* label) DEFINED_ON(x86_shared);
 
     inline void branch32(Condition cond, wasm::SymbolicAddress lhs, Imm32 rhs, Label* label)
         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, arm);
-    inline void branch64(Condition cond, Register64 lhs, Register64 rhs, Label* label)
-        DEFINED_ON(x86, x64, arm);
+    // When a fail label is not defined it will fall through to next instruction,
+    // else jump to the fail label.
+    inline void branch64(Condition cond, Register64 lhs, Imm64 val, Label* success,
+                         Label* fail = nullptr) DEFINED_ON(x86, x64, arm);
+    inline void branch64(Condition cond, Register64 lhs, Register64 rhs, Label* success,
+                         Label* fail = nullptr) DEFINED_ON(x86, x64, arm);
     // 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;
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -3184,8 +3184,72 @@ CodeGeneratorARM::visitUDivOrModI64(LUDi
     masm.passABIArg(rhs.low);
 
     MOZ_ASSERT(gen->compilingAsmJS());
     if (lir->mir()->isMod())
         masm.callWithABI(wasm::SymbolicAddress::UModI64);
     else
         masm.callWithABI(wasm::SymbolicAddress::UDivI64);
 }
+
+void
+CodeGeneratorARM::visitCompareI64(LCompareI64* lir)
+{
+    MCompare* mir = lir->mir();
+    MOZ_ASSERT(mir->compareType() == MCompare::Compare_Int64 ||
+               mir->compareType() == MCompare::Compare_UInt64);
+
+    const LInt64Allocation lhs = lir->getInt64Operand(LCompareI64::Lhs);
+    const LInt64Allocation rhs = lir->getInt64Operand(LCompareI64::Rhs);
+    Register64 lhsRegs = ToRegister64(lhs);
+    Register output = ToRegister(lir->output());
+
+    bool isSigned = mir->compareType() == MCompare::Compare_Int64;
+    Assembler::Condition condition = JSOpToCondition(lir->jsop(), isSigned);
+    Label done;
+
+    masm.move32(Imm32(1), output);
+
+    if (IsConstant(rhs)) {
+        Imm64 imm = Imm64(ToInt64(rhs));
+        masm.branch64(condition, lhsRegs, imm, &done);
+    } else {
+        Register64 rhsRegs = ToRegister64(rhs);
+        masm.branch64(condition, lhsRegs, rhsRegs, &done);
+    }
+
+    masm.move32(Imm32(0), output);
+    masm.bind(&done);
+}
+
+void
+CodeGeneratorARM::visitCompareI64AndBranch(LCompareI64AndBranch* lir)
+{
+    MCompare* mir = lir->cmpMir();
+    MOZ_ASSERT(mir->compareType() == MCompare::Compare_Int64 ||
+               mir->compareType() == MCompare::Compare_UInt64);
+
+    const LInt64Allocation lhs = lir->getInt64Operand(LCompareI64::Lhs);
+    const LInt64Allocation rhs = lir->getInt64Operand(LCompareI64::Rhs);
+    Register64 lhsRegs = ToRegister64(lhs);
+
+    bool isSigned = mir->compareType() == MCompare::Compare_Int64;
+    Assembler::Condition condition = JSOpToCondition(lir->jsop(), isSigned);
+
+    Label* trueLabel = getJumpLabelForBranch(lir->ifTrue());
+    Label* falseLabel = getJumpLabelForBranch(lir->ifFalse());
+
+    if (isNextBlock(lir->ifFalse()->lir())) {
+        falseLabel = nullptr;
+    } else if (isNextBlock(lir->ifTrue()->lir())) {
+        condition = Assembler::InvertCondition(condition);
+        trueLabel = falseLabel;
+        falseLabel = nullptr;
+    }
+
+    if (IsConstant(rhs)) {
+        Imm64 imm = Imm64(ToInt64(rhs));
+        masm.branch64(condition, lhsRegs, imm, trueLabel, falseLabel);
+    } else {
+        Register64 rhsRegs = ToRegister64(rhs);
+        masm.branch64(condition, lhsRegs, rhsRegs, trueLabel, falseLabel);
+    }
+}
--- a/js/src/jit/arm/CodeGenerator-arm.h
+++ b/js/src/jit/arm/CodeGenerator-arm.h
@@ -159,16 +159,18 @@ class CodeGeneratorARM : public CodeGene
 
     virtual void visitWrapInt64ToInt32(LWrapInt64ToInt32* lir);
     virtual void visitExtendInt32ToInt64(LExtendInt32ToInt64* lir);
     virtual void visitAddI64(LAddI64* lir);
     virtual void visitSubI64(LSubI64* lir);
     virtual void visitMulI64(LMulI64* lir);
     virtual void visitDivOrModI64(LDivOrModI64* lir);
     virtual void visitUDivOrModI64(LUDivOrModI64* lir);
+    virtual void visitCompareI64(LCompareI64* lir);
+    virtual void visitCompareI64AndBranch(LCompareI64AndBranch* lir);
 
     // Out of line visitors.
     void visitOutOfLineBailout(OutOfLineBailout* ool);
     void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool);
 
   protected:
     ValueOperand ToValue(LInstruction* ins, size_t pos);
     ValueOperand ToOutValue(LInstruction* ins);
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h
+++ b/js/src/jit/arm/MacroAssembler-arm-inl.h
@@ -815,97 +815,123 @@ MacroAssembler::branch64(Condition cond,
     load32(rhs, scratch);
     branch32(cond, 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);
 }
 
 void
-MacroAssembler::branch64(Condition cond, Register64 lhs, Imm64 val, Label* label)
+MacroAssembler::branch64(Condition cond, Register64 lhs, Imm64 val, Label* success, Label* fail)
 {
-    Label fail;
+    bool fallthrough = false;
+    Label fallthroughLabel;
+
+    if (!fail) {
+        fail = &fallthroughLabel;
+        fallthrough = true;
+    }
 
     switch(cond) {
       case Assembler::Equal:
-        branch32(Assembler::NotEqual, lhs.low, val.low(), &fail);
-        branch32(Assembler::Equal, lhs.high, val.hi(), label);
+        branch32(Assembler::NotEqual, lhs.low, val.low(), fail);
+        branch32(Assembler::Equal, lhs.high, val.hi(), success);
+        if (!fallthrough)
+            jump(fail);
         break;
       case Assembler::NotEqual:
-        branch32(Assembler::NotEqual, lhs.low, val.low(), label);
-        branch32(Assembler::NotEqual, lhs.high, val.hi(), label);
+        branch32(Assembler::NotEqual, lhs.low, val.low(), success);
+        branch32(Assembler::NotEqual, lhs.high, val.hi(), success);
+        if (!fallthrough)
+            jump(fail);
         break;
       case Assembler::LessThan:
       case Assembler::LessThanOrEqual:
       case Assembler::GreaterThan:
       case Assembler::GreaterThanOrEqual:
       case Assembler::Below:
       case Assembler::BelowOrEqual:
       case Assembler::Above:
       case Assembler::AboveOrEqual: {
         Assembler::Condition cond1 = Assembler::ConditionWithoutEqual(cond);
         Assembler::Condition cond2 =
             Assembler::ConditionWithoutEqual(Assembler::InvertCondition(cond));
         Assembler::Condition cond3 = Assembler::UnsignedCondition(cond);
 
         cmp32(lhs.high, val.hi());
-        ma_b(label, cond1);
-        ma_b(&fail, cond2);
+        ma_b(success, cond1);
+        ma_b(fail, cond2);
         cmp32(lhs.low, val.low());
-        ma_b(label, cond3);
+        ma_b(success, cond3);
+        if (!fallthrough)
+            jump(fail);
         break;
       }
       default:
         MOZ_CRASH("Condition code not supported");
         break;
     }
 
-    bind(&fail);
+    if (fallthrough)
+        bind(fail);
 }
 
 void
-MacroAssembler::branch64(Condition cond, Register64 lhs, Register64 rhs, Label* label)
+MacroAssembler::branch64(Condition cond, Register64 lhs, Register64 rhs, Label* success, Label* fail)
 {
-    Label fail;
+    bool fallthrough = false;
+    Label fallthroughLabel;
+
+    if (!fail) {
+        fail = &fallthroughLabel;
+        fallthrough = true;
+    }
 
     switch(cond) {
       case Assembler::Equal:
-        branch32(Assembler::NotEqual, lhs.low, rhs.low, &fail);
-        branch32(Assembler::Equal, lhs.high, rhs.high, label);
+        branch32(Assembler::NotEqual, lhs.low, rhs.low, fail);
+        branch32(Assembler::Equal, lhs.high, rhs.high, success);
+        if (!fallthrough)
+            jump(fail);
         break;
       case Assembler::NotEqual:
-        branch32(Assembler::NotEqual, lhs.low, rhs.low, label);
-        branch32(Assembler::NotEqual, lhs.high, rhs.high, label);
+        branch32(Assembler::NotEqual, lhs.low, rhs.low, success);
+        branch32(Assembler::NotEqual, lhs.high, rhs.high, success);
+        if (!fallthrough)
+            jump(fail);
         break;
       case Assembler::LessThan:
       case Assembler::LessThanOrEqual:
       case Assembler::GreaterThan:
       case Assembler::GreaterThanOrEqual:
       case Assembler::Below:
       case Assembler::BelowOrEqual:
       case Assembler::Above:
       case Assembler::AboveOrEqual: {
         Assembler::Condition cond1 = Assembler::ConditionWithoutEqual(cond);
         Assembler::Condition cond2 =
             Assembler::ConditionWithoutEqual(Assembler::InvertCondition(cond));
         Assembler::Condition cond3 = Assembler::UnsignedCondition(cond);
 
         cmp32(lhs.high, rhs.high);
-        ma_b(label, cond1);
-        ma_b(&fail, cond2);
+        ma_b(success, cond1);
+        ma_b(fail, cond2);
         cmp32(lhs.low, rhs.low);
-        ma_b(label, cond3);
+        ma_b(success, cond3);
+        if (!fallthrough)
+            jump(fail);
         break;
       }
       default:
         MOZ_CRASH("Condition code not supported");
         break;
     }
 
-    bind(&fail);
+    if (fallthrough)
+        bind(fail);
 }
 
 void
 MacroAssembler::branchPtr(Condition cond, Register lhs, Register rhs, Label* label)
 {
     branch32(cond, lhs, rhs, label);
 }
 
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -1602,16 +1602,39 @@ CodeGeneratorShared::jumpToBlock(MBasicB
         masm.bind(&rejoin);
 
         masm.propagateOOM(patchableBackedges_.append(PatchableBackedgeInfo(backedge, mir->lir()->label(), oolEntry)));
     } else {
         masm.jump(mir->lir()->label());
     }
 }
 
+Label*
+CodeGeneratorShared::getJumpLabelForBranch(MBasicBlock* block)
+{
+    // Skip past trivial blocks.
+    block = skipTrivialBlocks(block);
+
+    if (!labelForBackedgeWithImplicitCheck(block))
+        return block->lir()->label();
+
+    // We need to use a patchable jump for this backedge, but want to treat
+    // this as a normal label target to simplify codegen. Efficiency isn't so
+    // important here as these tests are extremely unlikely to be used in loop
+    // backedges, so emit inline code for the patchable jump. Heap allocating
+    // the label allows it to be used by out of line blocks.
+    Label* res = alloc().lifoAlloc()->newInfallible<Label>();
+    Label after;
+    masm.jump(&after);
+    masm.bind(res);
+    jumpToBlock(block);
+    masm.bind(&after);
+    return res;
+}
+
 // This function is not used for MIPS/MIPS64. MIPS has branchToBlock.
 #if !defined(JS_CODEGEN_MIPS32) && !defined(JS_CODEGEN_MIPS64)
 void
 CodeGeneratorShared::jumpToBlock(MBasicBlock* mir, Assembler::Condition cond)
 {
     // Skip past trivial blocks.
     mir = skipTrivialBlocks(mir);
 
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -463,24 +463,28 @@ class CodeGeneratorShared : public LElem
   protected:
     bool generatePrologue();
     bool generateEpilogue();
 
     void addOutOfLineCode(OutOfLineCode* code, const MInstruction* mir);
     void addOutOfLineCode(OutOfLineCode* code, const BytecodeSite* site);
     bool generateOutOfLineCode();
 
-    Label* labelForBackedgeWithImplicitCheck(MBasicBlock* mir);
+    Label* getJumpLabelForBranch(MBasicBlock* block);
 
     // Generate a jump to the start of the specified block, adding information
     // if this is a loop backedge. Use this in place of jumping directly to
     // mir->lir()->label(), or use getJumpLabelForBranch() if a label to use
     // directly is needed.
     void jumpToBlock(MBasicBlock* mir);
 
+    // Get a label for the start of block which can be used for jumping, in
+    // place of jumpToBlock.
+    Label* labelForBackedgeWithImplicitCheck(MBasicBlock* mir);
+
 // This function is not used for MIPS. MIPS has branchToBlock.
 #if !defined(JS_CODEGEN_MIPS32) && !defined(JS_CODEGEN_MIPS64)
     void jumpToBlock(MBasicBlock* mir, Assembler::Condition cond);
 #endif
 
   private:
     void generateInvalidateEpilogue();
 
--- a/js/src/jit/x64/MacroAssembler-x64-inl.h
+++ b/js/src/jit/x64/MacroAssembler-x64-inl.h
@@ -554,39 +554,43 @@ void
 MacroAssembler::branch32(Condition cond, wasm::SymbolicAddress lhs, Imm32 rhs, Label* label)
 {
     ScratchRegisterScope scratch(*this);
     mov(lhs, scratch);
     branch32(cond, Address(scratch, 0), rhs, label);
 }
 
 void
-MacroAssembler::branch64(Condition cond, Register64 lhs, Imm64 val, Label* label)
+MacroAssembler::branch64(Condition cond, Register64 lhs, Imm64 val, Label* success, Label* fail)
 {
     MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal ||
                cond == Assembler::LessThan || cond == Assembler::LessThanOrEqual ||
                cond == Assembler::GreaterThan || cond == Assembler::GreaterThanOrEqual ||
                cond == Assembler::Below || cond == Assembler::BelowOrEqual ||
                cond == Assembler::Above || cond == Assembler::AboveOrEqual,
                "other condition codes not supported");
 
-    branchPtr(cond, lhs.reg, ImmWord(val.value), label);
+    branchPtr(cond, lhs.reg, ImmWord(val.value), success);
+    if (fail)
+        jump(fail);
 }
 
 void
-MacroAssembler::branch64(Condition cond, Register64 lhs, Register64 rhs, Label* label)
+MacroAssembler::branch64(Condition cond, Register64 lhs, Register64 rhs, Label* success, Label* fail)
 {
     MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal ||
                cond == Assembler::LessThan || cond == Assembler::LessThanOrEqual ||
                cond == Assembler::GreaterThan || cond == Assembler::GreaterThanOrEqual ||
                cond == Assembler::Below || cond == Assembler::BelowOrEqual ||
                cond == Assembler::Above || cond == Assembler::AboveOrEqual,
                "other condition codes not supported");
 
-    branchPtr(cond, lhs.reg, rhs.reg, label);
+    branchPtr(cond, lhs.reg, rhs.reg, success);
+    if (fail)
+        jump(fail);
 }
 
 void
 MacroAssembler::branch64(Condition cond, const Address& lhs, Imm64 val, Label* label)
 {
     MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal,
                "other condition codes not supported");
 
--- a/js/src/jit/x86/CodeGenerator-x86.cpp
+++ b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -1388,89 +1388,33 @@ CodeGeneratorX86::visitCompareI64AndBran
 
     const LInt64Allocation lhs = lir->getInt64Operand(LCompareI64::Lhs);
     const LInt64Allocation rhs = lir->getInt64Operand(LCompareI64::Rhs);
     Register64 lhsRegs = ToRegister64(lhs);
 
     bool isSigned = mir->compareType() == MCompare::Compare_Int64;
     Assembler::Condition condition = JSOpToCondition(lir->jsop(), isSigned);
 
+    Label* trueLabel = getJumpLabelForBranch(lir->ifTrue());
+    Label* falseLabel = getJumpLabelForBranch(lir->ifFalse());
+
+    if (isNextBlock(lir->ifFalse()->lir())) {
+        falseLabel = nullptr;
+    } else if (isNextBlock(lir->ifTrue()->lir())) {
+        condition = Assembler::InvertCondition(condition);
+        trueLabel = falseLabel;
+        falseLabel = nullptr;
+    }
+
     if (IsConstant(rhs)) {
         Imm64 imm = Imm64(ToInt64(rhs));
-        switch(lir->jsop()) {
-          case JSOP_EQ:
-          case JSOP_STRICTEQ:
-            masm.cmp32(lhsRegs.high, imm.hi());
-            jumpToBlock(lir->ifFalse(), Assembler::NotEqual);
-            masm.cmp32(lhsRegs.low, imm.low());
-            emitBranch(condition, lir->ifTrue(), lir->ifFalse());
-            break;
-          case JSOP_NE:
-          case JSOP_STRICTNE:
-            masm.cmp32(lhsRegs.high, imm.hi());
-            jumpToBlock(lir->ifTrue(), Assembler::NotEqual);
-            masm.cmp32(lhsRegs.low, imm.low());
-            emitBranch(condition, lir->ifTrue(), lir->ifFalse());
-            break;
-          case JSOP_LT:
-          case JSOP_LE:
-          case JSOP_GT:
-          case JSOP_GE: {
-            Assembler::Condition cond1 = Assembler::ConditionWithoutEqual(condition);
-            Assembler::Condition cond2 = Assembler::ConditionWithoutEqual(Assembler::InvertCondition(condition));
-            Assembler::Condition cond3 = Assembler::UnsignedCondition(condition);
-
-            masm.cmp32(lhsRegs.high, imm.hi());
-            jumpToBlock(lir->ifTrue(), cond1);
-            jumpToBlock(lir->ifFalse(), cond2);
-            masm.cmp32(lhsRegs.low, imm.low());
-            jumpToBlock(lir->ifTrue(), cond3);
-            jumpToBlock(lir->ifFalse());
-            break;
-          }
-          default:
-            MOZ_CRASH("unexpected op");
-        }
-        return;
-    }
-
-    Register64 rhsRegs = ToRegister64(rhs);
-    switch(lir->jsop()) {
-      case JSOP_EQ:
-      case JSOP_STRICTEQ:
-        masm.cmp32(lhsRegs.high, rhsRegs.high);
-        jumpToBlock(lir->ifFalse(), Assembler::NotEqual);
-        masm.cmp32(lhsRegs.low, rhsRegs.low);
-        emitBranch(condition, lir->ifTrue(), lir->ifFalse());
-        break;
-      case JSOP_NE:
-      case JSOP_STRICTNE:
-        masm.cmp32(lhsRegs.high, rhsRegs.high);
-        jumpToBlock(lir->ifTrue(), Assembler::NotEqual);
-        masm.cmp32(lhsRegs.low, rhsRegs.low);
-        emitBranch(condition, lir->ifTrue(), lir->ifFalse());
-        break;
-      case JSOP_LT:
-      case JSOP_LE:
-      case JSOP_GT:
-      case JSOP_GE: {
-        Assembler::Condition cond1 = Assembler::ConditionWithoutEqual(condition);
-        Assembler::Condition cond2 = Assembler::ConditionWithoutEqual(Assembler::InvertCondition(condition));
-        Assembler::Condition cond3 = Assembler::UnsignedCondition(condition);
-
-        masm.cmp32(lhsRegs.high, rhsRegs.high);
-        jumpToBlock(lir->ifTrue(), cond1);
-        jumpToBlock(lir->ifFalse(), cond2);
-        masm.cmp32(lhsRegs.low, rhsRegs.low);
-        jumpToBlock(lir->ifTrue(), cond3);
-        jumpToBlock(lir->ifFalse());
-        break;
-      }
-      default:
-        MOZ_CRASH("unexpected op");
+        masm.branch64(condition, lhsRegs, imm, trueLabel, falseLabel);
+    } else {
+        Register64 rhsRegs = ToRegister64(rhs);
+        masm.branch64(condition, lhsRegs, rhsRegs, trueLabel, falseLabel);
     }
 }
 
 void
 CodeGeneratorX86::visitDivOrModI64(LDivOrModI64* lir)
 {
     Register64 lhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Lhs));
     Register64 rhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Rhs));
--- a/js/src/jit/x86/MacroAssembler-x86-inl.h
+++ b/js/src/jit/x86/MacroAssembler-x86-inl.h
@@ -630,97 +630,123 @@ MacroAssembler::branch32(Condition cond,
 void
 MacroAssembler::branch32(Condition cond, wasm::SymbolicAddress lhs, Imm32 rhs, Label* label)
 {
     cmpl(rhs, lhs);
     j(cond, label);
 }
 
 void
-MacroAssembler::branch64(Condition cond, Register64 lhs, Imm64 val, Label* label)
+MacroAssembler::branch64(Condition cond, Register64 lhs, Imm64 val, Label* success, Label* fail)
 {
-    Label fail;
+    bool fallthrough = false;
+    Label fallthroughLabel;
+
+    if (!fail) {
+        fail = &fallthroughLabel;
+        fallthrough = true;
+    }
 
     switch(cond) {
       case Assembler::Equal:
-        branch32(Assembler::NotEqual, lhs.low, val.low(), &fail);
-        branch32(Assembler::Equal, lhs.high, val.hi(), label);
+        branch32(Assembler::NotEqual, lhs.low, val.low(), fail);
+        branch32(Assembler::Equal, lhs.high, val.hi(), success);
+        if (!fallthrough)
+            jump(fail);
         break;
       case Assembler::NotEqual:
-        branch32(Assembler::NotEqual, lhs.low, val.low(), label);
-        branch32(Assembler::NotEqual, lhs.high, val.hi(), label);
+        branch32(Assembler::NotEqual, lhs.low, val.low(), success);
+        branch32(Assembler::NotEqual, lhs.high, val.hi(), success);
+        if (!fallthrough)
+            jump(fail);
         break;
       case Assembler::LessThan:
       case Assembler::LessThanOrEqual:
       case Assembler::GreaterThan:
       case Assembler::GreaterThanOrEqual:
       case Assembler::Below:
       case Assembler::BelowOrEqual:
       case Assembler::Above:
       case Assembler::AboveOrEqual: {
         Assembler::Condition cond1 = Assembler::ConditionWithoutEqual(cond);
         Assembler::Condition cond2 =
             Assembler::ConditionWithoutEqual(Assembler::InvertCondition(cond));
         Assembler::Condition cond3 = Assembler::UnsignedCondition(cond);
 
         cmp32(lhs.high, val.hi());
-        j(cond1, label);
-        j(cond2, &fail);
+        j(cond1, success);
+        j(cond2, fail);
         cmp32(lhs.low, val.low());
-        j(cond3, label);
+        j(cond3, success);
+        if (!fallthrough)
+            jump(fail);
         break;
       }
       default:
         MOZ_CRASH("Condition code not supported");
         break;
     }
 
-    bind(&fail);
+    if (fallthrough)
+        bind(fail);
 }
 
 void
-MacroAssembler::branch64(Condition cond, Register64 lhs, Register64 rhs, Label* label)
+MacroAssembler::branch64(Condition cond, Register64 lhs, Register64 rhs, Label* success, Label* fail)
 {
-    Label fail;
+    bool fallthrough = false;
+    Label fallthroughLabel;
+
+    if (!fail) {
+        fail = &fallthroughLabel;
+        fallthrough = true;
+    }
 
     switch(cond) {
       case Assembler::Equal:
-        branch32(Assembler::NotEqual, lhs.low, rhs.low, &fail);
-        branch32(Assembler::Equal, lhs.high, rhs.high, label);
+        branch32(Assembler::NotEqual, lhs.low, rhs.low, fail);
+        branch32(Assembler::Equal, lhs.high, rhs.high, success);
+        if (!fallthrough)
+            jump(fail);
         break;
       case Assembler::NotEqual:
-        branch32(Assembler::NotEqual, lhs.low, rhs.low, label);
-        branch32(Assembler::NotEqual, lhs.high, rhs.high, label);
+        branch32(Assembler::NotEqual, lhs.low, rhs.low, success);
+        branch32(Assembler::NotEqual, lhs.high, rhs.high, success);
+        if (!fallthrough)
+            jump(fail);
         break;
       case Assembler::LessThan:
       case Assembler::LessThanOrEqual:
       case Assembler::GreaterThan:
       case Assembler::GreaterThanOrEqual:
       case Assembler::Below:
       case Assembler::BelowOrEqual:
       case Assembler::Above:
       case Assembler::AboveOrEqual: {
         Assembler::Condition cond1 = Assembler::ConditionWithoutEqual(cond);
         Assembler::Condition cond2 =
             Assembler::ConditionWithoutEqual(Assembler::InvertCondition(cond));
         Assembler::Condition cond3 = Assembler::UnsignedCondition(cond);
 
         cmp32(lhs.high, rhs.high);
-        j(cond1, label);
-        j(cond2, &fail);
+        j(cond1, success);
+        j(cond2, fail);
         cmp32(lhs.low, rhs.low);
-        j(cond3, label);
+        j(cond3, success);
+        if (!fallthrough)
+            jump(fail);
         break;
       }
       default:
         MOZ_CRASH("Condition code not supported");
         break;
     }
 
-    bind(&fail);
+    if (fallthrough)
+        bind(fail);
 }
 
 void
 MacroAssembler::branch64(Condition cond, const Address& lhs, Imm64 val, Label* label)
 {
     MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal,
                "other condition codes not supported");