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 332391 df8f35c1858453850c471339bf3e7687f30cf8b6
parent 332390 48ed814c72c6db5913e0eb5f5724035a652e57cc
child 332392 65981e46881a04d3b36fd9fbd69cb79169d75e83
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)
reviewersnbp
bugs1289054
milestone50.0a1
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");