Bug 1279248 - Part 1: Preparations in IonMonkey to support i64 on x86, r=jandem
authorHannes Verschore <hv1989@gmail.com>
Fri, 29 Jul 2016 16:51:40 +0200
changeset 332356 f7f0a9f0833e0df30eeaf3c0b9ff5152e16b0fda
parent 332355 e5ae984c685bb798e439fb4ec0bf02b3ab49f8df
child 332357 1a594c9bd29f4a8e05d6dd6e7a390cbd44f9730f
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)
reviewersjandem
bugs1279248
milestone50.0a1
Bug 1279248 - Part 1: Preparations in IonMonkey to support i64 on x86, r=jandem
js/src/jit/LIR.cpp
js/src/jit/LIR.h
js/src/jit/Lowering.cpp
js/src/jit/Registers.h
js/src/jit/arm/Lowering-arm.h
js/src/jit/arm64/Lowering-arm64.h
js/src/jit/mips-shared/Lowering-mips-shared.h
js/src/jit/none/Lowering-none.h
js/src/jit/shared/Assembler-shared.h
js/src/jit/shared/CodeGenerator-shared-inl.h
js/src/jit/shared/Lowering-shared-inl.h
js/src/jit/shared/Lowering-shared.h
js/src/jit/x64/CodeGenerator-x64.cpp
js/src/jit/x64/Lowering-x64.cpp
js/src/jit/x64/Lowering-x64.h
js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
js/src/jit/x86-shared/CodeGenerator-x86-shared.h
js/src/jit/x86/Assembler-x86.cpp
js/src/jit/x86/Assembler-x86.h
js/src/jit/x86/Lowering-x86.cpp
js/src/jit/x86/Lowering-x86.h
--- a/js/src/jit/LIR.cpp
+++ b/js/src/jit/LIR.cpp
@@ -84,33 +84,42 @@ LBlock::LBlock(MBasicBlock* from)
 
 bool
 LBlock::init(TempAllocator& alloc)
 {
     // Count the number of LPhis we'll need.
     size_t numLPhis = 0;
     for (MPhiIterator i(block_->phisBegin()), e(block_->phisEnd()); i != e; ++i) {
         MPhi* phi = *i;
-        numLPhis += (phi->type() == MIRType::Value) ? BOX_PIECES : 1;
+        switch (phi->type()) {
+          case MIRType::Value: numLPhis += BOX_PIECES; break;
+          case MIRType::Int64: numLPhis += INT64_PIECES; break;
+          default: numLPhis += 1; break;
+        }
     }
 
     // Allocate space for the LPhis.
     if (!phis_.init(alloc, numLPhis))
         return false;
 
     // For each MIR phi, set up LIR phis as appropriate. We'll fill in their
     // operands on each incoming edge, and set their definitions at the start of
     // their defining block.
     size_t phiIndex = 0;
     size_t numPreds = block_->numPredecessors();
     for (MPhiIterator i(block_->phisBegin()), e(block_->phisEnd()); i != e; ++i) {
         MPhi* phi = *i;
         MOZ_ASSERT(phi->numOperands() == numPreds);
 
-        int numPhis = (phi->type() == MIRType::Value) ? BOX_PIECES : 1;
+        int numPhis;
+        switch (phi->type()) {
+          case MIRType::Value: numPhis = BOX_PIECES; break;
+          case MIRType::Int64: numPhis = INT64_PIECES; break;
+          default: numPhis = 1; break;
+        }
         for (int i = 0; i < numPhis; i++) {
             LAllocation* inputs = alloc.allocateArray<LAllocation>(numPreds);
             if (!inputs)
                 return false;
 
             void* addr = &phis_[phiIndex++];
             LPhi* lphi = new (addr) LPhi(phi, inputs);
             lphi->setBlock(this);
@@ -338,16 +347,17 @@ LAllocation::aliases(const LAllocation& 
         return toFloatReg()->reg().aliases(other.toFloatReg()->reg());
     return *this == other;
 }
 
 static const char * const TypeChars[] =
 {
     "g",            // GENERAL
     "i",            // INT32
+    "i64",          // INT64
     "o",            // OBJECT
     "s",            // SLOTS
     "f",            // FLOAT32
     "d",            // DOUBLE
     "simd128int",   // SIMD128INT
     "simd128float", // SIMD128FLOAT
     "sincos",       // SINCOS
 #ifdef JS_NUNBOX32
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -39,16 +39,18 @@ static const uint32_t VREG_INCREMENT = 1
 static const uint32_t THIS_FRAME_ARGSLOT = 0;
 
 #if defined(JS_NUNBOX32)
 # define BOX_PIECES         2
 static const uint32_t VREG_TYPE_OFFSET = 0;
 static const uint32_t VREG_DATA_OFFSET = 1;
 static const uint32_t TYPE_INDEX = 0;
 static const uint32_t PAYLOAD_INDEX = 1;
+static const uint32_t INT64LOW_INDEX = 0;
+static const uint32_t INT64HIGH_INDEX = 1;
 #elif defined(JS_PUNBOX64)
 # define BOX_PIECES         1
 #else
 # error "Unknown!"
 #endif
 
 static const uint32_t INT64_PIECES = sizeof(int64_t) / sizeof(uintptr_t);
 
@@ -611,20 +613,21 @@ class LDefinition
             return LDefinition::BOX;
 #endif
           case MIRType::SinCosDouble:
             return LDefinition::SINCOS;
           case MIRType::Slots:
           case MIRType::Elements:
             return LDefinition::SLOTS;
           case MIRType::Pointer:
-#if JS_BITS_PER_WORD == 64
+            return LDefinition::GENERAL;
+#if defined(JS_PUNBOX64)
           case MIRType::Int64:
+            return LDefinition::GENERAL;
 #endif
-            return LDefinition::GENERAL;
           case MIRType::Int8x16:
           case MIRType::Int16x8:
           case MIRType::Int32x4:
           case MIRType::Bool8x16:
           case MIRType::Bool16x8:
           case MIRType::Bool32x4:
             return LDefinition::SIMD128INT;
           case MIRType::Float32x4:
@@ -1120,30 +1123,38 @@ class LInstructionHelper : public detail
     LAllocation* getOperand(size_t index) final override {
         return &operands_[index];
     }
     void setOperand(size_t index, const LAllocation& a) final override {
         operands_[index] = a;
     }
     void setBoxOperand(size_t index, const LBoxAllocation& alloc) {
 #ifdef JS_NUNBOX32
-        operands_[index] = alloc.type();
-        operands_[index + 1] = alloc.payload();
+        operands_[index + TYPE_INDEX] = alloc.type();
+        operands_[index + PAYLOAD_INDEX] = alloc.payload();
 #else
         operands_[index] = alloc.value();
 #endif
     }
     void setInt64Operand(size_t index, const LInt64Allocation& alloc) {
 #if JS_BITS_PER_WORD == 32
-        operands_[index] = alloc.low();
-        operands_[index + 1] = alloc.high();
+        operands_[index + INT64LOW_INDEX] = alloc.low();
+        operands_[index + INT64HIGH_INDEX] = alloc.high();
 #else
         operands_[index] = alloc.value();
 #endif
     }
+    const LInt64Allocation getInt64Operand(size_t offset) {
+#if JS_BITS_PER_WORD == 32
+        return LInt64Allocation(operands_[offset + INT64HIGH_INDEX],
+                                operands_[offset + INT64LOW_INDEX]);
+#else
+        return LInt64Allocation(operands_[offset]);
+#endif
+    }
 };
 
 template<size_t Defs, size_t Temps>
 class LVariadicInstruction : public details::LInstructionFixedDefsTempsHelper<Defs, Temps>
 {
     FixedList<LAllocation> operands_;
 
   public:
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4627,16 +4627,19 @@ void
 LIRGenerator::definePhis()
 {
     size_t lirIndex = 0;
     MBasicBlock* block = current->mir();
     for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
         if (phi->type() == MIRType::Value) {
             defineUntypedPhi(*phi, lirIndex);
             lirIndex += BOX_PIECES;
+        } else if (phi->type() == MIRType::Int64) {
+            defineInt64Phi(*phi, lirIndex);
+            lirIndex += INT64_PIECES;
         } else {
             defineTypedPhi(*phi, lirIndex);
             lirIndex += 1;
         }
     }
 }
 
 void
@@ -4695,16 +4698,19 @@ LIRGenerator::visitBlock(MBasicBlock* bl
             MDefinition* opd = phi->getOperand(position);
             ensureDefined(opd);
 
             MOZ_ASSERT(opd->type() == phi->type());
 
             if (phi->type() == MIRType::Value) {
                 lowerUntypedPhiInput(*phi, position, successor->lir(), lirIndex);
                 lirIndex += BOX_PIECES;
+            } else if (phi->type() == MIRType::Int64) {
+                lowerInt64PhiInput(*phi, position, successor->lir(), lirIndex);
+                lirIndex += INT64_PIECES;
             } else {
                 lowerTypedPhiInput(*phi, position, successor->lir(), lirIndex);
                 lirIndex += 1;
             }
         }
     }
 
     // Now emit the last instruction, which is some form of branch.
--- a/js/src/jit/Registers.h
+++ b/js/src/jit/Registers.h
@@ -94,16 +94,21 @@ struct Register {
     static uint32_t FirstBit(SetType x) {
         return Codes::FirstBit(x);
     }
     static uint32_t LastBit(SetType x) {
         return Codes::LastBit(x);
     }
 };
 
+#if defined(JS_NUNBOX32)
+static const uint32_t INT64LOW_OFFSET = 0 * sizeof(int32_t);
+static const uint32_t INT64HIGH_OFFSET = 1 * sizeof(int32_t);
+#endif
+
 struct Register64
 {
 #ifdef JS_PUNBOX64
     Register reg;
 #else
     Register high;
     Register low;
 #endif
--- a/js/src/jit/arm/Lowering-arm.h
+++ b/js/src/jit/arm/Lowering-arm.h
@@ -33,16 +33,19 @@ class LIRGeneratorARM : public LIRGenera
     inline LDefinition tempToUnbox() {
         return LDefinition::BogusTemp();
     }
 
     bool needTempForPostBarrier() { return false; }
 
     void lowerUntypedPhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex);
     void defineUntypedPhi(MPhi* phi, size_t lirIndex);
+    void lowerInt64PhiInput(MPhi*, uint32_t, LBlock*, size_t) { MOZ_CRASH("NYI"); }
+    void defineInt64Phi(MPhi*, size_t) { MOZ_CRASH("NYI"); }
+
     void lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir, MDefinition* lhs,
                        MDefinition* rhs);
     void lowerUrshD(MUrsh* mir);
 
     void lowerForALU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
                      MDefinition* input);
     void lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
                      MDefinition* lhs, MDefinition* rhs);
--- a/js/src/jit/arm64/Lowering-arm64.h
+++ b/js/src/jit/arm64/Lowering-arm64.h
@@ -35,16 +35,18 @@ class LIRGeneratorARM64 : public LIRGene
 
     // ARM64 has a scratch register, so no need for another temp for dispatch ICs.
     LDefinition tempForDispatchCache(MIRType outputType = MIRType::None) {
         return LDefinition::BogusTemp();
     }
 
     void lowerUntypedPhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex);
     void defineUntypedPhi(MPhi* phi, size_t lirIndex);
+    void lowerInt64PhiInput(MPhi*, uint32_t, LBlock*, size_t) { MOZ_CRASH("NYI"); }
+    void defineInt64Phi(MPhi*, size_t) { MOZ_CRASH("NYI"); }
     void lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir, MDefinition* lhs,
                        MDefinition* rhs);
     void lowerUrshD(MUrsh* mir);
 
     void lowerForALU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir, MDefinition* input);
     void lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
                      MDefinition* lhs, MDefinition* rhs);
 
--- a/js/src/jit/mips-shared/Lowering-mips-shared.h
+++ b/js/src/jit/mips-shared/Lowering-mips-shared.h
@@ -21,16 +21,19 @@ class LIRGeneratorMIPSShared : public LI
 
   protected:
     // x86 has constraints on what registers can be formatted for 1-byte
     // stores and loads; on MIPS all registers are okay.
     LAllocation useByteOpRegister(MDefinition* mir);
     LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition* mir);
     LDefinition tempByteOpRegister();
 
+    void lowerInt64PhiInput(MPhi*, uint32_t, LBlock*, size_t) { MOZ_CRASH("NYI"); }
+    void defineInt64Phi(MPhi*, size_t) { MOZ_CRASH("NYI"); }
+
     bool needTempForPostBarrier() { return false; }
 
     void lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir, MDefinition* lhs,
                        MDefinition* rhs);
     void lowerUrshD(MUrsh* mir);
 
     void lowerForALU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
                      MDefinition* input);
--- a/js/src/jit/none/Lowering-none.h
+++ b/js/src/jit/none/Lowering-none.h
@@ -24,17 +24,19 @@ class LIRGeneratorNone : public LIRGener
     LBoxAllocation useBoxFixed(MDefinition*, Register, Register, bool useAtStart = false) { MOZ_CRASH(); }
 
     LAllocation useByteOpRegister(MDefinition*) { MOZ_CRASH(); }
     LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition*) { MOZ_CRASH(); }
     LDefinition tempByteOpRegister() { MOZ_CRASH(); }
     LDefinition tempToUnbox() { MOZ_CRASH(); }
     bool needTempForPostBarrier() { MOZ_CRASH(); }
     void lowerUntypedPhiInput(MPhi*, uint32_t, LBlock*, size_t) { MOZ_CRASH(); }
+    void lowerInt64PhiInput(MPhi*, uint32_t, LBlock*, size_t) { MOZ_CRASH(); }
     void defineUntypedPhi(MPhi*, size_t) { MOZ_CRASH(); }
+    void defineInt64Phi(MPhi*, size_t) { MOZ_CRASH(); }
     void lowerForShift(LInstructionHelper<1, 2, 0>*, MDefinition*, MDefinition*, MDefinition*) {
         MOZ_CRASH();
     }
     void lowerUrshD(MUrsh*) { MOZ_CRASH(); }
     template <typename T>
     void lowerForALU(T, MDefinition*, MDefinition*, MDefinition* v = nullptr) { MOZ_CRASH(); }
     template <typename T>
     void lowerForFPU(T, MDefinition*, MDefinition*, MDefinition* v = nullptr) { MOZ_CRASH(); }
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -126,17 +126,17 @@ struct ImmWord
     { }
 };
 
 // Used for 64-bit immediates which do not require relocation.
 struct Imm64
 {
     uint64_t value;
 
-    explicit Imm64(uint64_t value) : value(value)
+    explicit Imm64(int64_t value) : value(value)
     { }
 
     Imm32 low() const {
         return Imm32(int32_t(value));
     }
 
     Imm32 hi() const {
         return Imm32(int32_t(value >> 32));
--- a/js/src/jit/shared/CodeGenerator-shared-inl.h
+++ b/js/src/jit/shared/CodeGenerator-shared-inl.h
@@ -10,16 +10,33 @@
 #include "jit/shared/CodeGenerator-shared.h"
 #include "jit/Disassembler.h"
 
 #include "jit/MacroAssembler-inl.h"
 
 namespace js {
 namespace jit {
 
+static inline bool
+IsConstant(const LInt64Allocation& a)
+{
+#if JS_BITS_PER_WORD == 32
+    if (a.high().isConstantValue())
+        return true;
+    if (a.high().isConstantIndex())
+        return true;
+#else
+    if (a.value().isConstantValue())
+        return true;
+    if (a.value().isConstantIndex())
+        return true;
+#endif
+    return false;
+}
+
 static inline int32_t
 ToInt32(const LAllocation* a)
 {
     if (a->isConstantValue())
         return a->toConstant()->toInt32();
     if (a->isConstantIndex())
         return a->toConstantIndex()->index();
     MOZ_CRASH("this is not a constant!");
@@ -30,16 +47,33 @@ ToInt64(const LAllocation* a)
 {
     if (a->isConstantValue())
         return a->toConstant()->toInt64();
     if (a->isConstantIndex())
         return a->toConstantIndex()->index();
     MOZ_CRASH("this is not a constant!");
 }
 
+static inline int64_t
+ToInt64(const LInt64Allocation& a)
+{
+#if JS_BITS_PER_WORD == 32
+    if (a.high().isConstantValue())
+        return a.high().toConstant()->toInt64();
+    if (a.high().isConstantIndex())
+        return a.high().toConstantIndex()->index();
+#else
+    if (a.value().isConstantValue())
+        return a.value().toConstant()->toInt64();
+    if (a.value().isConstantIndex())
+        return a.value().toConstantIndex()->index();
+#endif
+    MOZ_CRASH("this is not a constant!");
+}
+
 static inline double
 ToDouble(const LAllocation* a)
 {
     return a->toConstant()->numberToDouble();
 }
 
 static inline Register
 ToRegister(const LAllocation& a)
@@ -59,24 +93,34 @@ ToRegister(const LDefinition* def)
 {
     return ToRegister(*def->output());
 }
 
 static inline Register64
 ToOutRegister64(LInstruction* ins)
 {
 #if JS_BITS_PER_WORD == 32
-    Register loReg = ToRegister(ins->getDef(0));
-    Register hiReg = ToRegister(ins->getDef(1));
+    Register loReg = ToRegister(ins->getDef(INT64LOW_INDEX));
+    Register hiReg = ToRegister(ins->getDef(INT64HIGH_INDEX));
     return Register64(hiReg, loReg);
 #else
     return Register64(ToRegister(ins->getDef(0)));
 #endif
 }
 
+static inline Register64
+ToRegister64(const LInt64Allocation& a)
+{
+#if JS_BITS_PER_WORD == 32
+    return Register64(ToRegister(a.high()), ToRegister(a.low()));
+#else
+    return Register64(ToRegister(a.value()));
+#endif
+}
+
 static inline Register
 ToTempRegisterOrInvalid(const LDefinition* def)
 {
     if (def->isBogusTemp())
         return InvalidReg;
     return ToRegister(def);
 }
 
--- a/js/src/jit/shared/Lowering-shared-inl.h
+++ b/js/src/jit/shared/Lowering-shared-inl.h
@@ -24,16 +24,18 @@ LIRGeneratorShared::emitAtUses(MInstruct
 }
 
 LUse
 LIRGeneratorShared::use(MDefinition* mir, LUse policy)
 {
     // It is illegal to call use() on an instruction with two defs.
 #if BOX_PIECES > 1
     MOZ_ASSERT(mir->type() != MIRType::Value);
+#endif
+#if INT64_PIECES > 1
     MOZ_ASSERT(mir->type() != MIRType::Int64);
 #endif
     ensureDefined(mir);
     policy.setVirtualRegister(mir->virtualRegister());
     return policy;
 }
 
 template <size_t X> void
@@ -174,18 +176,18 @@ LIRGeneratorShared::defineInt64(LInstruc
 {
     // Call instructions should use defineReturn.
     MOZ_ASSERT(!lir->isCall());
     MOZ_ASSERT(mir->type() == MIRType::Int64);
 
     uint32_t vreg = getVirtualRegister();
 
 #if JS_BITS_PER_WORD == 32
-    lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL, policy));
-    lir->setDef(1, LDefinition(vreg + 1, LDefinition::GENERAL, policy));
+    lir->setDef(0, LDefinition(vreg + INT64LOW_INDEX, LDefinition::GENERAL, policy));
+    lir->setDef(1, LDefinition(vreg + INT64HIGH_INDEX, LDefinition::GENERAL, policy));
     getVirtualRegister();
 #else
     lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL, policy));
 #endif
     lir->setMir(mir);
 
     mir->setVirtualRegister(vreg);
     add(lir);
@@ -231,16 +233,27 @@ LIRGeneratorShared::defineReturn(LInstru
                                             LGeneralReg(JSReturnReg_Type)));
         lir->setDef(PAYLOAD_INDEX, LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD,
                                                LGeneralReg(JSReturnReg_Data)));
         getVirtualRegister();
 #elif defined(JS_PUNBOX64)
         lir->setDef(0, LDefinition(vreg, LDefinition::BOX, LGeneralReg(JSReturnReg)));
 #endif
         break;
+      case MIRType::Int64:
+#if defined(JS_NUNBOX32)
+        lir->setDef(INT64LOW_INDEX, LDefinition(vreg + INT64LOW_INDEX, LDefinition::GENERAL,
+                                                LGeneralReg(ReturnReg64.low)));
+        lir->setDef(INT64HIGH_INDEX, LDefinition(vreg + INT64HIGH_INDEX, LDefinition::GENERAL,
+                                                 LGeneralReg(ReturnReg64.high)));
+        getVirtualRegister();
+#elif defined(JS_PUNBOX64)
+        lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL, LGeneralReg(ReturnReg)));
+#endif
+        break;
       case MIRType::Float32:
         lir->setDef(0, LDefinition(vreg, LDefinition::FLOAT32, LFloatReg(ReturnFloat32Reg)));
         break;
       case MIRType::Double:
         lir->setDef(0, LDefinition(vreg, LDefinition::DOUBLE, LFloatReg(ReturnDoubleReg)));
         break;
       case MIRType::Int8x16:
       case MIRType::Int16x8:
@@ -745,24 +758,40 @@ LInt64Allocation
 LIRGeneratorShared::useInt64(MDefinition* mir, LUse::Policy policy, bool useAtStart)
 {
     MOZ_ASSERT(mir->type() == MIRType::Int64);
 
     ensureDefined(mir);
 
     uint32_t vreg = mir->virtualRegister();
 #if JS_BITS_PER_WORD == 32
-    return LInt64Allocation(LUse(vreg + 1, policy, useAtStart),
-                            LUse(vreg, policy, useAtStart));
+    return LInt64Allocation(LUse(vreg + INT64HIGH_INDEX, policy, useAtStart),
+                            LUse(vreg + INT64LOW_INDEX, policy, useAtStart));
 #else
     return LInt64Allocation(LUse(vreg, policy, useAtStart));
 #endif
 }
 
 LInt64Allocation
+LIRGeneratorShared::useInt64Fixed(MDefinition* mir, Register64 regs, bool useAtStart)
+{
+    MOZ_ASSERT(mir->type() == MIRType::Int64);
+
+    ensureDefined(mir);
+
+    uint32_t vreg = mir->virtualRegister();
+#if JS_BITS_PER_WORD == 32
+    return LInt64Allocation(LUse(regs.high, vreg + INT64HIGH_INDEX, useAtStart),
+                            LUse(regs.low, vreg + INT64LOW_INDEX, useAtStart));
+#else
+    return LInt64Allocation(LUse(regs.reg, vreg, useAtStart));
+#endif
+}
+
+LInt64Allocation
 LIRGeneratorShared::useInt64(MDefinition* mir, bool useAtStart)
 {
     // On 32-bit platforms, always load the value in registers.
 #if JS_BITS_PER_WORD == 32
     return useInt64(mir, LUse::REGISTER, useAtStart);
 #else
     return useInt64(mir, LUse::ANY, useAtStart);
 #endif
--- a/js/src/jit/shared/Lowering-shared.h
+++ b/js/src/jit/shared/Lowering-shared.h
@@ -182,16 +182,17 @@ class LIRGeneratorShared : public MDefin
     inline LBoxAllocation useBoxOrTypedOrConstant(MDefinition* mir, bool useConstant);
 
     // Returns an int64 allocation for an Int64-typed instruction.
     inline LInt64Allocation useInt64(MDefinition* mir, LUse::Policy policy, bool useAtStart);
     inline LInt64Allocation useInt64(MDefinition* mir, bool useAtStart = false);
     inline LInt64Allocation useInt64AtStart(MDefinition* mir);
     inline LInt64Allocation useInt64OrConstant(MDefinition* mir, bool useAtStart = false);
     inline LInt64Allocation useInt64Register(MDefinition* mir, bool useAtStart = false);
+    inline LInt64Allocation useInt64Fixed(MDefinition* mir, Register64 regs, bool useAtStart = false);
 
     LInt64Allocation useInt64RegisterAtStart(MDefinition* mir) {
         return useInt64Register(mir, /* useAtStart = */ true);
     }
     LInt64Allocation useInt64OrConstantAtStart(MDefinition* mir) {
         return useInt64OrConstant(mir, /* useAtStart = */ true);
     }
 
--- a/js/src/jit/x64/CodeGenerator-x64.cpp
+++ b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -16,28 +16,16 @@
 #include "jit/MacroAssembler-inl.h"
 #include "jit/shared/CodeGenerator-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::DebugOnly;
 
-static inline Register64
-ToRegister64(const LAllocation* a)
-{
-    return Register64(ToRegister(a));
-}
-
-static inline Register64
-ToRegister64(const LDefinition* a)
-{
-    return Register64(ToRegister(a));
-}
-
 CodeGeneratorX64::CodeGeneratorX64(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm)
   : CodeGeneratorX86Shared(gen, graph, masm)
 {
 }
 
 ValueOperand
 CodeGeneratorX64::ToValue(LInstruction* ins, size_t pos)
 {
--- a/js/src/jit/x64/Lowering-x64.cpp
+++ b/js/src/jit/x64/Lowering-x64.cpp
@@ -115,16 +115,28 @@ LIRGeneratorX64::defineUntypedPhi(MPhi* 
     defineTypedPhi(phi, lirIndex);
 }
 
 void
 LIRGeneratorX64::lowerUntypedPhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex)
 {
     lowerTypedPhiInput(phi, inputPosition, block, lirIndex);
 }
+ 
+void
+LIRGeneratorX64::defineInt64Phi(MPhi* phi, size_t lirIndex)
+{
+    defineTypedPhi(phi, lirIndex);
+}
+
+void
+LIRGeneratorX64::lowerInt64PhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex)
+{
+    lowerTypedPhiInput(phi, inputPosition, block, lirIndex);
+}
 
 void
 LIRGeneratorX64::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins)
 {
     lowerCompareExchangeTypedArrayElement(ins, /* useI386ByteRegisters = */ false);
 }
 
 void
--- a/js/src/jit/x64/Lowering-x64.h
+++ b/js/src/jit/x64/Lowering-x64.h
@@ -17,16 +17,19 @@ class LIRGeneratorX64 : public LIRGenera
   public:
     LIRGeneratorX64(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
       : LIRGeneratorX86Shared(gen, graph, lirGraph)
     { }
 
   protected:
     void lowerUntypedPhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex);
     void defineUntypedPhi(MPhi* phi, size_t lirIndex);
+    void lowerInt64PhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex);
+    void defineInt64Phi(MPhi* phi, size_t lirIndex);
+
 
     // Returns a box allocation. reg2 is ignored on 64-bit platforms.
     LBoxAllocation useBoxFixed(MDefinition* mir, Register reg1, Register, bool useAtStart = false);
 
     // x86 has constraints on what registers can be formatted for 1-byte
     // stores and loads; on x64 all registers are okay.
     LAllocation useByteOpRegister(MDefinition* mir);
     LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition* mir);
--- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
@@ -36,16 +36,30 @@ using JS::GenericNaN;
 namespace js {
 namespace jit {
 
 CodeGeneratorX86Shared::CodeGeneratorX86Shared(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm)
   : CodeGeneratorShared(gen, graph, masm)
 {
 }
 
+#ifdef JS_PUNBOX64
+Operand
+CodeGeneratorX86Shared::ToOperandOrRegister64(const LInt64Allocation input)
+{
+    return ToOperand(input.value());
+}
+#else
+Register64
+CodeGeneratorX86Shared::ToOperandOrRegister64(const LInt64Allocation input)
+{
+    return ToRegister64(input);
+}
+#endif
+
 void
 OutOfLineBailout::accept(CodeGeneratorX86Shared* codegen)
 {
     codegen->visitOutOfLineBailout(this);
 }
 
 void
 CodeGeneratorX86Shared::emitBranch(Assembler::Condition cond, MBasicBlock* mirTrue,
@@ -270,17 +284,17 @@ CodeGeneratorX86Shared::visitCompareFAnd
 
 void
 CodeGeneratorX86Shared::visitAsmJSPassStackArg(LAsmJSPassStackArg* ins)
 {
     const MAsmJSPassStackArg* mir = ins->mir();
     Address dst(StackPointer, mir->spOffset());
     if (ins->arg()->isConstant()) {
         if (mir->input()->type() == MIRType::Int64)
-            masm.storePtr(ImmWord(ToInt64(ins->arg())), dst);
+            masm.storePtr(ImmWord(ins->arg()->toConstant()->toInt64()), dst); // tmp
         else
             masm.storePtr(ImmWord(ToInt32(ins->arg())), dst);
     } else {
         if (ins->arg()->isGeneralReg()) {
             masm.storePtr(ToRegister(ins->arg()), dst);
         } else {
             switch (mir->input()->type()) {
               case MIRType::Double:
--- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.h
+++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.h
@@ -117,16 +117,22 @@ class CodeGeneratorX86Shared : public Co
     void cleanupAfterAsmJSBoundsCheckBranch(const MWasmMemoryAccess* mir, Register ptr);
 
     NonAssertingLabel deoptLabel_;
 
     Operand ToOperand(const LAllocation& a);
     Operand ToOperand(const LAllocation* a);
     Operand ToOperand(const LDefinition* def);
 
+#ifdef JS_PUNBOX64
+    Operand ToOperandOrRegister64(const LInt64Allocation input);
+#else
+    Register64 ToOperandOrRegister64(const LInt64Allocation input);
+#endif
+
     MoveOperand toMoveOperand(LAllocation a) const;
 
     void bailoutIf(Assembler::Condition condition, LSnapshot* snapshot);
     void bailoutIf(Assembler::DoubleCondition condition, LSnapshot* snapshot);
     void bailoutFrom(Label* label, LSnapshot* snapshot);
     void bailout(LSnapshot* snapshot);
 
     template <typename T1, typename T2>
--- a/js/src/jit/x86/Assembler-x86.cpp
+++ b/js/src/jit/x86/Assembler-x86.cpp
@@ -25,16 +25,20 @@ ABIArgGenerator::next(MIRType type)
         current_ = ABIArg(stackOffset_);
         stackOffset_ += sizeof(uint32_t);
         break;
       case MIRType::Float32: // Float32 moves are actually double moves
       case MIRType::Double:
         current_ = ABIArg(stackOffset_);
         stackOffset_ += sizeof(uint64_t);
         break;
+      case MIRType::Int64:
+        current_ = ABIArg(stackOffset_);
+        stackOffset_ += sizeof(uint64_t);
+        break;
       case MIRType::Int8x16:
       case MIRType::Int16x8:
       case MIRType::Int32x4:
       case MIRType::Float32x4:
       case MIRType::Bool8x16:
       case MIRType::Bool16x8:
       case MIRType::Bool32x4:
         // SIMD values aren't passed in or out of C++, so we can make up
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -39,17 +39,17 @@ static constexpr FloatRegister xmm7 = Fl
 static constexpr Register InvalidReg = { X86Encoding::invalid_reg };
 static constexpr FloatRegister InvalidFloatReg = FloatRegister();
 
 static constexpr Register JSReturnReg_Type = ecx;
 static constexpr Register JSReturnReg_Data = edx;
 static constexpr Register StackPointer = esp;
 static constexpr Register FramePointer = ebp;
 static constexpr Register ReturnReg = eax;
-static constexpr Register64 ReturnReg64(InvalidReg, InvalidReg);
+static constexpr Register64 ReturnReg64(edi, eax);
 static constexpr FloatRegister ReturnFloat32Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Single);
 static constexpr FloatRegister ReturnDoubleReg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Double);
 static constexpr FloatRegister ReturnSimd128Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Simd128);
 static constexpr FloatRegister ScratchFloat32Reg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Single);
 static constexpr FloatRegister ScratchDoubleReg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Double);
 static constexpr FloatRegister ScratchSimd128Reg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Simd128);
 
 // TLS pointer argument register for WebAssembly functions. This must not alias
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -165,16 +165,45 @@ LIRGeneratorX86::lowerUntypedPhiInput(MP
     MDefinition* operand = phi->getOperand(inputPosition);
     LPhi* type = block->getPhi(lirIndex + VREG_TYPE_OFFSET);
     LPhi* payload = block->getPhi(lirIndex + VREG_DATA_OFFSET);
     type->setOperand(inputPosition, LUse(operand->virtualRegister() + VREG_TYPE_OFFSET, LUse::ANY));
     payload->setOperand(inputPosition, LUse(VirtualRegisterOfPayload(operand), LUse::ANY));
 }
 
 void
+LIRGeneratorX86::defineInt64Phi(MPhi* phi, size_t lirIndex)
+{
+    LPhi* low = current->getPhi(lirIndex + INT64LOW_INDEX);
+    LPhi* high = current->getPhi(lirIndex + INT64HIGH_INDEX);
+
+    uint32_t lowVreg = getVirtualRegister();
+
+    phi->setVirtualRegister(lowVreg);
+
+    uint32_t highVreg = getVirtualRegister();
+    MOZ_ASSERT(lowVreg + INT64HIGH_INDEX == highVreg + INT64LOW_INDEX);
+
+    low->setDef(0, LDefinition(lowVreg, LDefinition::INT32));
+    high->setDef(0, LDefinition(highVreg, LDefinition::INT32));
+    annotate(high);
+    annotate(low);
+}
+
+void
+LIRGeneratorX86::lowerInt64PhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex)
+{
+    MDefinition* operand = phi->getOperand(inputPosition);
+    LPhi* low = block->getPhi(lirIndex + INT64LOW_INDEX);
+    LPhi* high = block->getPhi(lirIndex + INT64HIGH_INDEX);
+    low->setOperand(inputPosition, LUse(operand->virtualRegister() + INT64LOW_INDEX, LUse::ANY));
+    high->setOperand(inputPosition, LUse(operand->virtualRegister() + INT64HIGH_INDEX, LUse::ANY));
+}
+
+void
 LIRGeneratorX86::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins)
 {
     lowerCompareExchangeTypedArrayElement(ins, /* useI386ByteRegisters = */ true);
 }
 
 void
 LIRGeneratorX86::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins)
 {
--- a/js/src/jit/x86/Lowering-x86.h
+++ b/js/src/jit/x86/Lowering-x86.h
@@ -37,16 +37,19 @@ class LIRGeneratorX86 : public LIRGenera
         return LDefinition::BogusTemp();
     }
 
     bool needTempForPostBarrier() { return true; }
 
     void lowerUntypedPhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex);
     void defineUntypedPhi(MPhi* phi, size_t lirIndex);
 
+    void lowerInt64PhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex);
+    void defineInt64Phi(MPhi* phi, size_t lirIndex);
+
     void lowerDivI64(MDiv* div);
     void lowerModI64(MMod* mod);
 
   public:
     void visitBox(MBox* box);
     void visitUnbox(MUnbox* unbox);
     void visitReturn(MReturn* ret);
     void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);