Bug 1007156 - Port changes from bug 991153 to MIPS. Support for all float32 regs, part 1. r=mjrosenb
authorBranislav Rankov <branislav.rankov@imgtec.com>
Fri, 22 Aug 2014 11:37:06 +0200
changeset 201644 c18c3ad45bef0fb312f1d25fa97ac985921ad931
parent 201643 cdfad45b2ed038d018a0434920e87599bbc8070d
child 201645 b5f83ef103598d381aec80b6ff3e27efa3b51a80
push id27375
push userryanvm@gmail.com
push dateTue, 26 Aug 2014 19:56:59 +0000
treeherdermozilla-central@f9bfe115fee5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmjrosenb
bugs1007156, 991153
milestone34.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 1007156 - Port changes from bug 991153 to MIPS. Support for all float32 regs, part 1. r=mjrosenb
js/src/jit/mips/Architecture-mips.cpp
js/src/jit/mips/Architecture-mips.h
js/src/jit/mips/Assembler-mips.cpp
js/src/jit/mips/Assembler-mips.h
js/src/jit/mips/Bailouts-mips.h
js/src/jit/mips/CodeGenerator-mips.cpp
js/src/jit/mips/Lowering-mips.cpp
js/src/jit/mips/MacroAssembler-mips.cpp
js/src/jit/mips/MoveEmitter-mips.cpp
js/src/jit/mips/MoveEmitter-mips.h
js/src/jit/mips/Simulator-mips.cpp
js/src/jit/mips/Trampoline-mips.cpp
--- a/js/src/jit/mips/Architecture-mips.cpp
+++ b/js/src/jit/mips/Architecture-mips.cpp
@@ -71,13 +71,77 @@ FloatRegisters::FromName(const char *nam
     for (size_t i = 0; i < Total; i++) {
         if (strcmp(GetName(i), name) == 0)
             return Code(i);
     }
 
     return Invalid;
 }
 
+FloatRegister
+FloatRegister::doubleOverlay(unsigned int which) const
+{
+    MOZ_ASSERT(!isInvalid());
+    if (kind_ != Double)
+        return FloatRegister(code_ & ~1, Double);
+    return *this;
+}
 
+FloatRegister
+FloatRegister::singleOverlay(unsigned int which) const
+{
+    MOZ_ASSERT(!isInvalid());
+    if (kind_ == Double) {
+        // Only even registers are double
+        MOZ_ASSERT(code_ % 2 == 0);
+        MOZ_ASSERT(which < 2);
+        return FloatRegister(code_ + which, Single);
+    }
+    MOZ_ASSERT(which == 0);
+    return FloatRegister(code_, Single);
+}
+
+FloatRegisterSet
+FloatRegister::ReduceSetForPush(const FloatRegisterSet &s)
+{
+    FloatRegisterSet mod;
+    for (TypedRegisterIterator<FloatRegister> iter(s); iter.more(); iter++) {
+        if ((*iter).isSingle()) {
+            // Even for single size registers save complete double register.
+            mod.addUnchecked((*iter).doubleOverlay());
+        } else {
+            mod.addUnchecked(*iter);
+        }
+    }
+    return mod;
+}
+
+uint32_t
+FloatRegister::GetSizeInBytes(const FloatRegisterSet &s)
+{
+    uint64_t bits = s.bits();
+    uint32_t ret = mozilla::CountPopulation32(bits & 0xffffffff) * sizeof(float);
+    ret +=  mozilla::CountPopulation32(bits >> 32) * sizeof(double);
+    return ret;
+}
+uint32_t
+FloatRegister::GetPushSizeInBytes(const FloatRegisterSet &s)
+{
+    FloatRegisterSet ss = s.reduceSetForPush();
+    uint64_t bits = ss.bits();
+    // We are only pushing double registers.
+    MOZ_ASSERT((bits & 0xffffffff) == 0);
+    uint32_t ret =  mozilla::CountPopulation32(bits >> 32) * sizeof(double);
+    return ret;
+}
+uint32_t
+FloatRegister::getRegisterDumpOffsetInBytes()
+{
+    if (isSingle())
+        return id() * sizeof(float);
+    if (isDouble())
+        return id() * sizeof(double);
+    MOZ_CRASH();
+}
 
 } // namespace ion
 } // namespace js
 
--- a/js/src/jit/mips/Architecture-mips.h
+++ b/js/src/jit/mips/Architecture-mips.h
@@ -192,16 +192,28 @@ class Registers
         (1 << Registers::a3);
 
     // Registers returned from a JS -> C call.
     static const uint32_t CallMask =
         (1 << Registers::v0) |
         (1 << Registers::v1);  // used for double-size returns
 
     static const uint32_t AllocatableMask = AllMask & ~NonAllocatableMask;
+
+    typedef uint32_t SetType;
+    static uint32_t SetSize(SetType x) {
+        static_assert(sizeof(SetType) == 4, "SetType must be 32 bits");
+        return mozilla::CountPopulation32(x);
+    }
+    static uint32_t FirstBit(SetType x) {
+        return mozilla::CountTrailingZeroes32(x);
+    }
+    static uint32_t LastBit(SetType x) {
+        return 31 - mozilla::CountLeadingZeroes32(x);
+    }
 };
 
 // Smallest integer type that can hold a register bitmask.
 typedef uint32_t PackedRegisterMask;
 
 
 // MIPS32 can have two types of floating-point coprocessors:
 // - 32 bit floating-point coprocessor - In this case, there are 32 single
@@ -265,72 +277,231 @@ class FloatRegisters
         MOZ_ASSERT(i < Total);
         return GetName(Code(i));
     }
 
     static Code FromName(const char *name);
 
     static const Code Invalid = invalid_freg;
 
-    static const uint32_t Total = 32;
-    // :TODO: (Bug 972836) // Fix this once odd regs can be used as float32
-    // only. For now we don't allocate odd regs for O32 ABI.
-    static const uint32_t Allocatable = 14;
+    static const uint32_t Total = 64;
+    static const uint32_t TotalDouble = 16;
+    static const uint32_t TotalSingle = 32;
+    static const uint32_t Allocatable = 42;
+    // When saving all registers we only need to do is save double registers.
+    static const uint32_t TotalPhys = 16;
+    static const uint64_t AllDoubleMask = 0x55555555ULL << 32;
+    static const uint64_t AllMask = AllDoubleMask | ((1ULL << 32) - 1);
 
-    static const uint32_t AllMask = 0xffffffff;
+    static const uint64_t NonVolatileDoubleMask =
+        ((1ULL << FloatRegisters::f20) |
+         (1ULL << FloatRegisters::f22) |
+         (1ULL << FloatRegisters::f24) |
+         (1ULL << FloatRegisters::f26) |
+         (1ULL << FloatRegisters::f28) |
+         (1ULL << FloatRegisters::f30)) << 32;
 
-    static const uint32_t VolatileMask =
-        (1 << FloatRegisters::f0) |
-        (1 << FloatRegisters::f2) |
-        (1 << FloatRegisters::f4) |
-        (1 << FloatRegisters::f6) |
-        (1 << FloatRegisters::f8) |
-        (1 << FloatRegisters::f10) |
-        (1 << FloatRegisters::f12) |
-        (1 << FloatRegisters::f14) |
-        (1 << FloatRegisters::f16) |
-        (1 << FloatRegisters::f18);
-    static const uint32_t NonVolatileMask =
-        (1 << FloatRegisters::f20) |
-        (1 << FloatRegisters::f22) |
-        (1 << FloatRegisters::f24) |
-        (1 << FloatRegisters::f26) |
-        (1 << FloatRegisters::f28) |
-        (1 << FloatRegisters::f30);
-
-    static const uint32_t WrapperMask = VolatileMask;
+    // f20-single and f21-single alias f20-double ...
+    static const uint64_t NonVolatileMask =
+        NonVolatileDoubleMask |
+        (1ULL << FloatRegisters::f20) |
+        (1ULL << FloatRegisters::f21) |
+        (1ULL << FloatRegisters::f22) |
+        (1ULL << FloatRegisters::f23) |
+        (1ULL << FloatRegisters::f24) |
+        (1ULL << FloatRegisters::f25) |
+        (1ULL << FloatRegisters::f26) |
+        (1ULL << FloatRegisters::f27) |
+        (1ULL << FloatRegisters::f28) |
+        (1ULL << FloatRegisters::f29) |
+        (1ULL << FloatRegisters::f30) |
+        (1ULL << FloatRegisters::f31);
 
-    // :TODO: (Bug 972836) // Fix this once odd regs can be used as float32
-    // only. For now we don't allocate odd regs for O32 ABI.
-    static const uint32_t NonAllocatableMask =
-        (1 << FloatRegisters::f1) |
-        (1 << FloatRegisters::f3) |
-        (1 << FloatRegisters::f5) |
-        (1 << FloatRegisters::f7) |
-        (1 << FloatRegisters::f9) |
-        (1 << FloatRegisters::f11) |
-        (1 << FloatRegisters::f13) |
-        (1 << FloatRegisters::f15) |
-        (1 << FloatRegisters::f17) |
-        (1 << FloatRegisters::f19) |
-        (1 << FloatRegisters::f21) |
-        (1 << FloatRegisters::f23) |
-        (1 << FloatRegisters::f25) |
-        (1 << FloatRegisters::f27) |
-        (1 << FloatRegisters::f29) |
-        (1 << FloatRegisters::f31) |
-        // f18 and f16 are MIPS scratch float registers.
-        (1 << FloatRegisters::f16) |
-        (1 << FloatRegisters::f18);
+    static const uint64_t VolatileMask = AllMask & ~NonVolatileMask;
+    static const uint64_t VolatileDoubleMask = AllDoubleMask & ~NonVolatileDoubleMask;
+
+    static const uint64_t WrapperMask = VolatileMask;
+
+    static const uint64_t NonAllocatableDoubleMask =
+        ((1ULL << FloatRegisters::f16) |
+         (1ULL << FloatRegisters::f18)) << 32;
+    // f16-single and f17-single alias f16-double ...
+    static const uint64_t NonAllocatableMask =
+        NonAllocatableDoubleMask |
+        (1ULL << FloatRegisters::f16) |
+        (1ULL << FloatRegisters::f17) |
+        (1ULL << FloatRegisters::f18) |
+        (1ULL << FloatRegisters::f19);
 
     // Registers that can be allocated without being saved, generally.
-    static const uint32_t TempMask = VolatileMask & ~NonAllocatableMask;
+    static const uint64_t TempMask = VolatileMask & ~NonAllocatableMask;
+
+    static const uint64_t AllocatableMask = AllMask & ~NonAllocatableMask;
+
+    typedef uint64_t SetType;
+};
+
+template <typename T>
+class TypedRegisterSet;
+
+class FloatRegister
+{
+  public:
+    enum RegType {
+        Single = 0x0,
+        Double = 0x1,
+    };
+
+    typedef FloatRegisters Codes;
+    typedef Codes::Code Code;
+
+    uint32_t code_ : 6;
+  protected:
+    RegType kind_ : 1;
+
+  public:
+    MOZ_CONSTEXPR FloatRegister(uint32_t code, RegType kind = Double)
+      : code_ (Code(code)), kind_(kind)
+    { }
+    MOZ_CONSTEXPR FloatRegister()
+      : code_(Code(FloatRegisters::invalid_freg)), kind_(Double)
+    { }
+
+    bool operator==(const FloatRegister &other) const {
+        JS_ASSERT(!isInvalid());
+        JS_ASSERT(!other.isInvalid());
+        return kind_ == other.kind_ && code_ == other.code_;
+    }
+    bool isDouble() const { return kind_ == Double; }
+    bool isSingle() const { return kind_ == Single; }
+    bool equiv(const FloatRegister &other) const { return other.kind_ == kind_; }
+    size_t size() const { return (kind_ == Double) ? 8 : 4; }
+    bool isInvalid() const {
+        return code_ == FloatRegisters::invalid_freg;
+    }
+
+    FloatRegister doubleOverlay(unsigned int which = 0) const;
+    FloatRegister singleOverlay(unsigned int which = 0) const;
+    FloatRegister sintOverlay(unsigned int which = 0) const;
+    FloatRegister uintOverlay(unsigned int which = 0) const;
+
+    Code code() const {
+        JS_ASSERT(!isInvalid());
+        return Code(code_  | (kind_ << 5));
+    }
+    uint32_t id() const {
+        return code_;
+    }
+    static FloatRegister FromCode(uint32_t i) {
+        uint32_t code = i & 31;
+        uint32_t kind = i >> 5;
+        return FloatRegister(code, RegType(kind));
+    }
+    // This is similar to FromCode except for double registers on O32.
+    static FloatRegister FromIndex(uint32_t index, RegType kind) {
+#if defined(USES_O32_ABI)
+        if (kind == Double)
+            return FloatRegister(index * 2, RegType(kind));
+#endif
+        return FloatRegister(index, RegType(kind));
+    }
 
-    static const uint32_t AllocatableMask = AllMask & ~NonAllocatableMask;
+    bool volatile_() const {
+        if (isDouble())
+            return !!((1ULL << code_) & FloatRegisters::VolatileMask);
+        return !!((1ULL << (code_ & ~1)) & FloatRegisters::VolatileMask);
+    }
+    const char *name() const {
+        return FloatRegisters::GetName(code_);
+    }
+    bool operator != (const FloatRegister &other) const {
+        return other.kind_ != kind_ || code_ != other.code_;
+    }
+    bool aliases(const FloatRegister &other) {
+        if (kind_ == other.kind_)
+            return code_ == other.code_;
+        return doubleOverlay() == other.doubleOverlay();
+    }
+    uint32_t numAliased() const {
+        if (isDouble()) {
+            MOZ_ASSERT((code_ & 1) == 0);
+            return 3;
+        }
+        return 2;
+    }
+    void aliased(uint32_t aliasIdx, FloatRegister *ret) {
+        if (aliasIdx == 0) {
+            *ret = *this;
+            return;
+        }
+        if (isDouble()) {
+            MOZ_ASSERT((code_ & 1) == 0);
+            MOZ_ASSERT(aliasIdx <= 2);
+            *ret = singleOverlay(aliasIdx - 1);
+            return;
+        }
+        MOZ_ASSERT(aliasIdx == 1);
+        *ret = doubleOverlay(aliasIdx - 1);
+    }
+    uint32_t numAlignedAliased() const {
+        if (isDouble()) {
+            MOZ_ASSERT((code_ & 1) == 0);
+            return 2;
+        }
+        // f1-float32 has 0 other aligned aliases, 1 total.
+        // f0-float32 has 1 other aligned alias, 2 total.
+        return 2 - (code_ & 1);
+    }
+    // |        f0-double        |
+    // | f0-float32 | f1-float32 |
+    // We only push double registers on MIPS. So, if we've stored f0-double
+    // we also want to f0-float32 is stored there.
+    void alignedAliased(uint32_t aliasIdx, FloatRegister *ret) {
+        MOZ_ASSERT(isDouble());
+        MOZ_ASSERT((code_ & 1) == 0);
+        if (aliasIdx == 0) {
+            *ret = *this;
+            return;
+        }
+        MOZ_ASSERT(aliasIdx == 1);
+        *ret = singleOverlay(aliasIdx - 1);
+    }
+    typedef FloatRegisters::SetType SetType;
+    static uint32_t SetSize(SetType x) {
+        static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
+        return mozilla::CountPopulation32(x);
+    }
+    static Code FromName(const char *name) {
+        return FloatRegisters::FromName(name);
+    }
+    static TypedRegisterSet<FloatRegister> ReduceSetForPush(const TypedRegisterSet<FloatRegister> &s);
+    static uint32_t GetSizeInBytes(const TypedRegisterSet<FloatRegister> &s);
+    static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister> &s);
+    uint32_t getRegisterDumpOffsetInBytes();
+    static uint32_t FirstBit(SetType x) {
+        return mozilla::CountTrailingZeroes64(x);
+    }
+    static uint32_t LastBit(SetType x) {
+        return 63 - mozilla::CountLeadingZeroes64(x);
+    }
 };
 
 uint32_t GetMIPSFlags();
 bool hasFPU();
 
+// MIPS doesn't have double registers that can NOT be treated as float32.
+inline bool
+hasUnaliasedDouble() {
+    return false;
+}
+
+// On MIPS, fn-double aliases both fn-float32 and fn+1-float32, so if you need
+// to convert a float32 to a double as a temporary, you need a temporary
+// double register.
+inline bool
+hasMultiAlias() {
+    return true;
+}
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_mips_Architecture_mips_h */
--- a/js/src/jit/mips/Assembler-mips.cpp
+++ b/js/src/jit/mips/Assembler-mips.cpp
@@ -25,37 +25,39 @@ ABIArgGenerator::ABIArgGenerator()
   : usedArgSlots_(0),
     firstArgFloat(false),
     current_()
 {}
 
 ABIArg
 ABIArgGenerator::next(MIRType type)
 {
+    FloatRegister::RegType regType;
     switch (type) {
       case MIRType_Int32:
       case MIRType_Pointer:
         Register destReg;
         if (GetIntArgReg(usedArgSlots_, &destReg))
             current_ = ABIArg(destReg);
         else
             current_ = ABIArg(usedArgSlots_ * sizeof(intptr_t));
         usedArgSlots_++;
         break;
       case MIRType_Float32:
       case MIRType_Double:
+        regType = (type == MIRType_Double ? FloatRegister::Double : FloatRegister::Single);
         if (!usedArgSlots_) {
-            current_ = ABIArg(f12);
+            current_ = ABIArg(FloatRegister(FloatRegisters::f12, regType));
             usedArgSlots_ += 2;
             firstArgFloat = true;
         } else if (usedArgSlots_ <= 2) {
             // NOTE: We will use f14 always. This is not compatible with
             // system ABI. We will have to introduce some infrastructure
             // changes if we have to use system ABI here.
-            current_ = ABIArg(f14);
+            current_ = ABIArg(FloatRegister(FloatRegisters::f14, regType));
             usedArgSlots_ = 4;
         } else {
             usedArgSlots_ += usedArgSlots_ % 2;
             current_ = ABIArg(usedArgSlots_ * sizeof(intptr_t));
             usedArgSlots_ += 2;
         }
         break;
       default:
@@ -84,46 +86,46 @@ js::jit::RT(Register r)
 {
     MOZ_ASSERT((r.code() & ~RegMask) == 0);
     return r.code() << RTShift;
 }
 
 uint32_t
 js::jit::RT(FloatRegister r)
 {
-    MOZ_ASSERT(r.code() < FloatRegisters::Total);
-    return r.code() << RTShift;
+    MOZ_ASSERT(r.id() < FloatRegisters::TotalSingle);
+    return r.id() << RTShift;
 }
 
 uint32_t
 js::jit::RD(Register r)
 {
     MOZ_ASSERT((r.code() & ~RegMask) == 0);
     return r.code() << RDShift;
 }
 
 uint32_t
 js::jit::RD(FloatRegister r)
 {
-    MOZ_ASSERT(r.code() < FloatRegisters::Total);
-    return r.code() << RDShift;
+    MOZ_ASSERT(r.id() < FloatRegisters::TotalSingle);
+    return r.id() << RDShift;
 }
 
 uint32_t
 js::jit::SA(uint32_t value)
 {
     MOZ_ASSERT(value < 32);
     return value << SAShift;
 }
 
 uint32_t
 js::jit::SA(FloatRegister r)
 {
-    MOZ_ASSERT(r.code() < FloatRegisters::Total);
-    return r.code() << SAShift;
+    MOZ_ASSERT(r.id() < FloatRegisters::TotalSingle);
+    return r.id() << SAShift;
 }
 
 Register
 js::jit::toRS(Instruction &i)
 {
     return Register::FromCode((i.encode() & RSMask ) >> RSShift);
 }
 
--- a/js/src/jit/mips/Assembler-mips.h
+++ b/js/src/jit/mips/Assembler-mips.h
@@ -100,58 +100,61 @@ class ABIArgGenerator
     static const Register NonArg_VolatileReg;
     static const Register NonReturn_VolatileReg0;
     static const Register NonReturn_VolatileReg1;
 };
 
 static MOZ_CONSTEXPR_VAR Register PreBarrierReg = a1;
 
 static MOZ_CONSTEXPR_VAR Register InvalidReg = { Registers::invalid_reg };
-static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg = { FloatRegisters::invalid_freg };
+static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg;
 
 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = a3;
 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = a2;
 static MOZ_CONSTEXPR_VAR Register StackPointer = sp;
 static MOZ_CONSTEXPR_VAR Register FramePointer = InvalidReg;
 static MOZ_CONSTEXPR_VAR Register ReturnReg = v0;
-static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloatReg = { FloatRegisters::f0 };
-static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloatReg = { FloatRegisters::f18 };
-static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchFloatReg = { FloatRegisters::f16 };
+static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = { FloatRegisters::f0, FloatRegister::Single };
+static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = { FloatRegisters::f0, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = { FloatRegisters::f18, FloatRegister::Single };
+static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = { FloatRegisters::f18, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchFloat32Reg = { FloatRegisters::f16, FloatRegister::Single };
+static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchDoubleReg = { FloatRegisters::f16, FloatRegister::Double };
 
 // Registers used in the GenerateFFIIonExit Enable Activation block.
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = t0;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = a0;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE1 = a1;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE2 = a2;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE3 = a3;
 
 // Registers used in the GenerateFFIIonExit Disable Activation block.
 // None of these may be the second scratch register (t8).
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnData = JSReturnReg_Data;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnType = JSReturnReg_Type;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = a0;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = a1;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = t0;
 
-static MOZ_CONSTEXPR_VAR FloatRegister f0  = {FloatRegisters::f0};
-static MOZ_CONSTEXPR_VAR FloatRegister f2  = {FloatRegisters::f2};
-static MOZ_CONSTEXPR_VAR FloatRegister f4  = {FloatRegisters::f4};
-static MOZ_CONSTEXPR_VAR FloatRegister f6  = {FloatRegisters::f6};
-static MOZ_CONSTEXPR_VAR FloatRegister f8  = {FloatRegisters::f8};
-static MOZ_CONSTEXPR_VAR FloatRegister f10 = {FloatRegisters::f10};
-static MOZ_CONSTEXPR_VAR FloatRegister f12 = {FloatRegisters::f12};
-static MOZ_CONSTEXPR_VAR FloatRegister f14 = {FloatRegisters::f14};
-static MOZ_CONSTEXPR_VAR FloatRegister f16 = {FloatRegisters::f16};
-static MOZ_CONSTEXPR_VAR FloatRegister f18 = {FloatRegisters::f18};
-static MOZ_CONSTEXPR_VAR FloatRegister f20 = {FloatRegisters::f20};
-static MOZ_CONSTEXPR_VAR FloatRegister f22 = {FloatRegisters::f22};
-static MOZ_CONSTEXPR_VAR FloatRegister f24 = {FloatRegisters::f24};
-static MOZ_CONSTEXPR_VAR FloatRegister f26 = {FloatRegisters::f26};
-static MOZ_CONSTEXPR_VAR FloatRegister f28 = {FloatRegisters::f28};
-static MOZ_CONSTEXPR_VAR FloatRegister f30 = {FloatRegisters::f30};
+static MOZ_CONSTEXPR_VAR FloatRegister f0  = { FloatRegisters::f0, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister f2  = { FloatRegisters::f2, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister f4  = { FloatRegisters::f4, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister f6  = { FloatRegisters::f6, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister f8  = { FloatRegisters::f8, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister f10 = { FloatRegisters::f10, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister f12 = { FloatRegisters::f12, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister f14 = { FloatRegisters::f14, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister f16 = { FloatRegisters::f16, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister f18 = { FloatRegisters::f18, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister f20 = { FloatRegisters::f20, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister f22 = { FloatRegisters::f22, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister f24 = { FloatRegisters::f24, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister f26 = { FloatRegisters::f26, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister f28 = { FloatRegisters::f28, FloatRegister::Double };
+static MOZ_CONSTEXPR_VAR FloatRegister f30 = { FloatRegisters::f30, FloatRegister::Double };
 
 // MIPS CPUs can only load multibyte data that is "naturally"
 // four-byte-aligned, sp register should be eight-byte-aligned.
 static const uint32_t StackAlignment = 8;
 static const uint32_t CodeAlignment = 4;
 static const bool StackKeptAligned = true;
 
 // This boolean indicates whether we support SIMD instructions flavoured for
@@ -906,21 +909,21 @@ class Assembler : public AssemblerShared
 
     BufferOffset as_movs(FloatRegister fd, FloatRegister fs);
     BufferOffset as_movd(FloatRegister fd, FloatRegister fs);
 
     BufferOffset as_mtc1(Register rt, FloatRegister fs);
     BufferOffset as_mfc1(Register rt, FloatRegister fs);
 
   protected:
-    // This is used to access the odd regiter form the pair of single
+    // This is used to access the odd register form the pair of single
     // precision registers that make one double register.
     FloatRegister getOddPair(FloatRegister reg) {
-        MOZ_ASSERT(reg.code() % 2 == 0);
-        return FloatRegister::FromCode(reg.code() + 1);
+        MOZ_ASSERT(reg.isDouble());
+        return reg.singleOverlay(1);
     }
 
   public:
     // FP convert instructions
     BufferOffset as_ceilws(FloatRegister fd, FloatRegister fs);
     BufferOffset as_floorws(FloatRegister fd, FloatRegister fs);
     BufferOffset as_roundws(FloatRegister fd, FloatRegister fs);
     BufferOffset as_truncws(FloatRegister fd, FloatRegister fs);
--- a/js/src/jit/mips/Bailouts-mips.h
+++ b/js/src/jit/mips/Bailouts-mips.h
@@ -21,17 +21,17 @@ class BailoutStack
     // stack along with frameClassId_ above.  This should be migrated to ip.
   public:
     union {
         uintptr_t frameSize_;
         uintptr_t tableOffset_;
     };
 
   protected:
-    mozilla::Array<double, FloatRegisters::Total> fpregs_;
+    mozilla::Array<double, FloatRegisters::TotalPhys> fpregs_;
     mozilla::Array<uintptr_t, Registers::Total> regs_;
 
     uintptr_t snapshotOffset_;
     uintptr_t padding_;
 
   public:
     FrameSizeClass frameClass() const {
         return FrameSizeClass::FromClass(frameClassId_);
--- a/js/src/jit/mips/CodeGenerator-mips.cpp
+++ b/js/src/jit/mips/CodeGenerator-mips.cpp
@@ -245,19 +245,19 @@ CodeGeneratorMIPS::visitMinMaxD(LMinMaxD
     masm.ma_bc1d(first, second, &nan, Assembler::DoubleUnordered, ShortJump);
     // Make sure we handle -0 and 0 right.
     masm.ma_bc1d(first, second, &equal, Assembler::DoubleEqual, ShortJump);
     masm.ma_bc1d(first, second, &returnSecond, cond, ShortJump);
     masm.ma_b(&done, ShortJump);
 
     // Check for zero.
     masm.bind(&equal);
-    masm.loadConstantDouble(0.0, ScratchFloatReg);
+    masm.loadConstantDouble(0.0, ScratchDoubleReg);
     // First wasn't 0 or -0, so just return it.
-    masm.ma_bc1d(first, ScratchFloatReg, &done, Assembler::DoubleNotEqualOrUnordered, ShortJump);
+    masm.ma_bc1d(first, ScratchDoubleReg, &done, Assembler::DoubleNotEqualOrUnordered, ShortJump);
 
     // So now both operands are either -0 or 0.
     if (ins->mir()->isMax()) {
         // -0 + -0 = -0 and -0 + 0 = 0.
         masm.addDouble(second, first);
     } else {
         masm.negateDouble(first);
         masm.subDouble(second, first);
@@ -915,26 +915,26 @@ bool
 CodeGeneratorMIPS::visitPowHalfD(LPowHalfD *ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     FloatRegister output = ToFloatRegister(ins->output());
 
     Label done, skip;
 
     // Masm.pow(-Infinity, 0.5) == Infinity.
-    masm.loadConstantDouble(NegativeInfinity<double>(), ScratchFloatReg);
-    masm.ma_bc1d(input, ScratchFloatReg, &skip, Assembler::DoubleNotEqualOrUnordered, ShortJump);
-    masm.as_negd(output, ScratchFloatReg);
+    masm.loadConstantDouble(NegativeInfinity<double>(), ScratchDoubleReg);
+    masm.ma_bc1d(input, ScratchDoubleReg, &skip, Assembler::DoubleNotEqualOrUnordered, ShortJump);
+    masm.as_negd(output, ScratchDoubleReg);
     masm.ma_b(&done, ShortJump);
 
     masm.bind(&skip);
     // Math.pow(-0, 0.5) == 0 == Math.pow(0, 0.5).
     // Adding 0 converts any -0 to 0.
-    masm.loadConstantDouble(0.0, ScratchFloatReg);
-    masm.as_addd(output, input, ScratchFloatReg);
+    masm.loadConstantDouble(0.0, ScratchDoubleReg);
+    masm.as_addd(output, input, ScratchDoubleReg);
     masm.as_sqrtd(output, output);
 
     masm.bind(&done);
     return true;
 }
 
 MoveOperand
 CodeGeneratorMIPS::toMoveOperand(const LAllocation *a) const
@@ -1082,17 +1082,17 @@ CodeGeneratorMIPS::visitMathF(LMathF *ma
     }
     return true;
 }
 
 bool
 CodeGeneratorMIPS::visitFloor(LFloor *lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
-    FloatRegister scratch = ScratchFloatReg;
+    FloatRegister scratch = ScratchDoubleReg;
     Register output = ToRegister(lir->output());
 
     Label skipCheck, done;
 
     // If Nan, 0 or -0 check for bailout
     masm.loadConstantDouble(0.0, scratch);
     masm.ma_bc1d(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump);
 
@@ -1119,17 +1119,17 @@ CodeGeneratorMIPS::visitFloor(LFloor *li
 
     return true;
 }
 
 bool
 CodeGeneratorMIPS::visitFloorF(LFloorF *lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
-    FloatRegister scratch = ScratchFloatReg;
+    FloatRegister scratch = ScratchFloat32Reg;
     Register output = ToRegister(lir->output());
 
     Label skipCheck, done;
 
     // If Nan, 0 or -0 check for bailout
     masm.loadConstantFloat32(0.0, scratch);
     masm.ma_bc1s(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump);
 
@@ -1156,17 +1156,17 @@ CodeGeneratorMIPS::visitFloorF(LFloorF *
 
     return true;
 }
 
 bool
 CodeGeneratorMIPS::visitCeil(LCeil *lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
-    FloatRegister scratch = ScratchFloatReg;
+    FloatRegister scratch = ScratchDoubleReg;
     Register output = ToRegister(lir->output());
 
     Label performCeil, done;
 
     // If x < -1 or x > 0 then perform ceil.
     masm.loadConstantDouble(0, scratch);
     masm.branchDouble(Assembler::DoubleGreaterThan, input, scratch, &performCeil);
     masm.loadConstantDouble(-1, scratch);
@@ -1193,17 +1193,17 @@ CodeGeneratorMIPS::visitCeil(LCeil *lir)
     masm.bind(&done);
     return true;
 }
 
 bool
 CodeGeneratorMIPS::visitCeilF(LCeilF *lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
-    FloatRegister scratch = ScratchFloatReg;
+    FloatRegister scratch = ScratchFloat32Reg;
     Register output = ToRegister(lir->output());
 
     Label performCeil, done;
 
     // If x < -1 or x > 0 then perform ceil.
     masm.loadConstantFloat32(0, scratch);
     masm.branchFloat(Assembler::DoubleGreaterThan, input, scratch, &performCeil);
     masm.loadConstantFloat32(-1, scratch);
@@ -1231,17 +1231,17 @@ CodeGeneratorMIPS::visitCeilF(LCeilF *li
     return true;
 }
 
 bool
 CodeGeneratorMIPS::visitRound(LRound *lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
     FloatRegister temp = ToFloatRegister(lir->temp());
-    FloatRegister scratch = ScratchFloatReg;
+    FloatRegister scratch = ScratchDoubleReg;
     Register output = ToRegister(lir->output());
 
     Label bail, negative, end, skipCheck;
 
     // Load 0.5 in the temp register.
     masm.loadConstantDouble(0.5, temp);
 
     // Branch to a slow path for negative inputs. Doesn't catch NaN or -0.
@@ -1297,17 +1297,17 @@ CodeGeneratorMIPS::visitRound(LRound *li
     return true;
 }
 
 bool
 CodeGeneratorMIPS::visitRoundF(LRoundF *lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
     FloatRegister temp = ToFloatRegister(lir->temp());
-    FloatRegister scratch = ScratchFloatReg;
+    FloatRegister scratch = ScratchFloat32Reg;
     Register output = ToRegister(lir->output());
 
     Label bail, negative, end, skipCheck;
 
     // Load 0.5 in the temp register.
     masm.loadConstantFloat32(0.5, temp);
 
     // Branch to a slow path for negative inputs. Doesn't catch NaN or -0.
@@ -1456,18 +1456,18 @@ bool
 CodeGeneratorMIPS::visitBoxFloatingPoint(LBoxFloatingPoint *box)
 {
     const LDefinition *payload = box->getDef(PAYLOAD_INDEX);
     const LDefinition *type = box->getDef(TYPE_INDEX);
     const LAllocation *in = box->getOperand(0);
 
     FloatRegister reg = ToFloatRegister(in);
     if (box->type() == MIRType_Float32) {
-        masm.convertFloat32ToDouble(reg, ScratchFloatReg);
-        reg = ScratchFloatReg;
+        masm.convertFloat32ToDouble(reg, ScratchDoubleReg);
+        reg = ScratchDoubleReg;
     }
     masm.ma_mv(reg, ValueOperand(ToRegister(type), ToRegister(payload)));
     return true;
 }
 
 bool
 CodeGeneratorMIPS::visitUnbox(LUnbox *unbox)
 {
@@ -1510,47 +1510,47 @@ CodeGeneratorMIPS::splitTagForTest(const
 bool
 CodeGeneratorMIPS::visitTestDAndBranch(LTestDAndBranch *test)
 {
     FloatRegister input = ToFloatRegister(test->input());
 
     MBasicBlock *ifTrue = test->ifTrue();
     MBasicBlock *ifFalse = test->ifFalse();
 
-    masm.loadConstantDouble(0.0, ScratchFloatReg);
+    masm.loadConstantDouble(0.0, ScratchDoubleReg);
     // If 0, or NaN, the result is false.
 
     if (isNextBlock(ifFalse->lir())) {
-        branchToBlock(Assembler::DoubleFloat, input, ScratchFloatReg, ifTrue,
+        branchToBlock(Assembler::DoubleFloat, input, ScratchDoubleReg, ifTrue,
                       Assembler::DoubleNotEqual);
     } else {
-        branchToBlock(Assembler::DoubleFloat, input, ScratchFloatReg, ifFalse,
+        branchToBlock(Assembler::DoubleFloat, input, ScratchDoubleReg, ifFalse,
                       Assembler::DoubleEqualOrUnordered);
         jumpToBlock(ifTrue);
     }
 
     return true;
 }
 
 bool
 CodeGeneratorMIPS::visitTestFAndBranch(LTestFAndBranch *test)
 {
     FloatRegister input = ToFloatRegister(test->input());
 
     MBasicBlock *ifTrue = test->ifTrue();
     MBasicBlock *ifFalse = test->ifFalse();
 
-    masm.loadConstantFloat32(0.0, ScratchFloatReg);
+    masm.loadConstantFloat32(0.0, ScratchFloat32Reg);
     // If 0, or NaN, the result is false.
 
     if (isNextBlock(ifFalse->lir())) {
-        branchToBlock(Assembler::SingleFloat, input, ScratchFloatReg, ifTrue,
+        branchToBlock(Assembler::SingleFloat, input, ScratchFloat32Reg, ifTrue,
                       Assembler::DoubleNotEqual);
     } else {
-        branchToBlock(Assembler::SingleFloat, input, ScratchFloatReg, ifFalse,
+        branchToBlock(Assembler::SingleFloat, input, ScratchFloat32Reg, ifFalse,
                       Assembler::DoubleEqualOrUnordered);
         jumpToBlock(ifTrue);
     }
 
     return true;
 }
 
 bool
@@ -1756,18 +1756,18 @@ bool
 CodeGeneratorMIPS::visitNotD(LNotD *ins)
 {
     // Since this operation is not, we want to set a bit if
     // the double is falsey, which means 0.0, -0.0 or NaN.
     FloatRegister in = ToFloatRegister(ins->input());
     Register dest = ToRegister(ins->output());
 
     Label falsey, done;
-    masm.loadConstantDouble(0.0, ScratchFloatReg);
-    masm.ma_bc1d(in, ScratchFloatReg, &falsey, Assembler::DoubleEqualOrUnordered, ShortJump);
+    masm.loadConstantDouble(0.0, ScratchDoubleReg);
+    masm.ma_bc1d(in, ScratchDoubleReg, &falsey, Assembler::DoubleEqualOrUnordered, ShortJump);
 
     masm.move32(Imm32(0), dest);
     masm.ma_b(&done, ShortJump);
 
     masm.bind(&falsey);
     masm.move32(Imm32(1), dest);
 
     masm.bind(&done);
@@ -1778,18 +1778,18 @@ bool
 CodeGeneratorMIPS::visitNotF(LNotF *ins)
 {
     // Since this operation is not, we want to set a bit if
     // the float32 is falsey, which means 0.0, -0.0 or NaN.
     FloatRegister in = ToFloatRegister(ins->input());
     Register dest = ToRegister(ins->output());
 
     Label falsey, done;
-    masm.loadConstantFloat32(0.0, ScratchFloatReg);
-    masm.ma_bc1s(in, ScratchFloatReg, &falsey, Assembler::DoubleEqualOrUnordered, ShortJump);
+    masm.loadConstantFloat32(0.0, ScratchFloat32Reg);
+    masm.ma_bc1s(in, ScratchFloat32Reg, &falsey, Assembler::DoubleEqualOrUnordered, ShortJump);
 
     masm.move32(Imm32(0), dest);
     masm.ma_b(&done, ShortJump);
 
     masm.bind(&falsey);
     masm.move32(Imm32(1), dest);
 
     masm.bind(&done);
@@ -1885,24 +1885,24 @@ CodeGeneratorMIPS::visitAsmJSLoadHeap(LA
     const MAsmJSLoadHeap *mir = ins->mir();
     const LAllocation *ptr = ins->ptr();
     const LDefinition *out = ins->output();
 
     bool isSigned;
     int size;
     bool isFloat = false;
     switch (mir->viewType()) {
-      case ArrayBufferView::TYPE_INT8:    isSigned = true;  size =  8; break;
-      case ArrayBufferView::TYPE_UINT8:   isSigned = false; size =  8; break;
-      case ArrayBufferView::TYPE_INT16:   isSigned = true;  size = 16; break;
-      case ArrayBufferView::TYPE_UINT16:  isSigned = false; size = 16; break;
-      case ArrayBufferView::TYPE_INT32:   isSigned = true;  size = 32; break;
-      case ArrayBufferView::TYPE_UINT32:  isSigned = false; size = 32; break;
-      case ArrayBufferView::TYPE_FLOAT64: isFloat  = true;  size = 64; break;
-      case ArrayBufferView::TYPE_FLOAT32: isFloat  = true;  size = 32; break;
+      case Scalar::Int8:    isSigned = true;  size =  8; break;
+      case Scalar::Uint8:   isSigned = false; size =  8; break;
+      case Scalar::Int16:   isSigned = true;  size = 16; break;
+      case Scalar::Uint16:  isSigned = false; size = 16; break;
+      case Scalar::Int32:   isSigned = true;  size = 32; break;
+      case Scalar::Uint32:  isSigned = false; size = 32; break;
+      case Scalar::Float64: isFloat  = true;  size = 64; break;
+      case Scalar::Float32: isFloat  = true;  size = 32; break;
       default: MOZ_CRASH("unexpected array type");
     }
 
     if (ptr->isConstant()) {
         MOZ_ASSERT(mir->skipBoundsCheck());
         int32_t ptrImm = ptr->toConstant()->toInt32();
         MOZ_ASSERT(ptrImm >= 0);
         if (isFloat) {
@@ -1972,24 +1972,24 @@ CodeGeneratorMIPS::visitAsmJSStoreHeap(L
     const MAsmJSStoreHeap *mir = ins->mir();
     const LAllocation *value = ins->value();
     const LAllocation *ptr = ins->ptr();
 
     bool isSigned;
     int size;
     bool isFloat = false;
     switch (mir->viewType()) {
-      case ArrayBufferView::TYPE_INT8:    isSigned = true;  size = 8;  break;
-      case ArrayBufferView::TYPE_UINT8:   isSigned = false; size = 8;  break;
-      case ArrayBufferView::TYPE_INT16:   isSigned = true;  size = 16; break;
-      case ArrayBufferView::TYPE_UINT16:  isSigned = false; size = 16; break;
-      case ArrayBufferView::TYPE_INT32:   isSigned = true;  size = 32; break;
-      case ArrayBufferView::TYPE_UINT32:  isSigned = false; size = 32; break;
-      case ArrayBufferView::TYPE_FLOAT64: isFloat  = true;  size = 64; break;
-      case ArrayBufferView::TYPE_FLOAT32: isFloat  = true;  size = 32; break;
+      case Scalar::Int8:    isSigned = true;  size =  8; break;
+      case Scalar::Uint8:   isSigned = false; size =  8; break;
+      case Scalar::Int16:   isSigned = true;  size = 16; break;
+      case Scalar::Uint16:  isSigned = false; size = 16; break;
+      case Scalar::Int32:   isSigned = true;  size = 32; break;
+      case Scalar::Uint32:  isSigned = false; size = 32; break;
+      case Scalar::Float64: isFloat  = true;  size = 64; break;
+      case Scalar::Float32: isFloat  = true;  size = 32; break;
       default: MOZ_CRASH("unexpected array type");
     }
 
     if (ptr->isConstant()) {
         MOZ_ASSERT(mir->skipBoundsCheck());
         int32_t ptrImm = ptr->toConstant()->toInt32();
         MOZ_ASSERT(ptrImm >= 0);
 
@@ -2048,17 +2048,18 @@ CodeGeneratorMIPS::visitAsmJSPassStackAr
 {
     const MAsmJSPassStackArg *mir = ins->mir();
     if (ins->arg()->isConstant()) {
         masm.storePtr(ImmWord(ToInt32(ins->arg())), Address(StackPointer, mir->spOffset()));
     } else {
         if (ins->arg()->isGeneralReg()) {
             masm.storePtr(ToRegister(ins->arg()), Address(StackPointer, mir->spOffset()));
         } else {
-            masm.storeDouble(ToFloatRegister(ins->arg()), Address(StackPointer, mir->spOffset()));
+            masm.storeDouble(ToFloatRegister(ins->arg()).doubleOverlay(0),
+                             Address(StackPointer, mir->spOffset()));
         }
     }
 
     return true;
 }
 
 bool
 CodeGeneratorMIPS::visitUDiv(LUDiv *ins)
--- a/js/src/jit/mips/Lowering-mips.cpp
+++ b/js/src/jit/mips/Lowering-mips.cpp
@@ -351,17 +351,17 @@ LIRGeneratorMIPS::newLTableSwitch(const 
                                   MTableSwitch *tableswitch)
 {
     return new(alloc()) LTableSwitch(in, inputCopy, temp(), tableswitch);
 }
 
 LTableSwitchV *
 LIRGeneratorMIPS::newLTableSwitchV(MTableSwitch *tableswitch)
 {
-    return new(alloc()) LTableSwitchV(temp(), tempFloat32(), temp(), tableswitch);
+    return new(alloc()) LTableSwitchV(temp(), tempDouble(), temp(), tableswitch);
 }
 
 bool
 LIRGeneratorMIPS::visitGuardShape(MGuardShape *ins)
 {
     MOZ_ASSERT(ins->obj()->type() == MIRType_Object);
 
     LDefinition tempObj = temp(LDefinition::OBJECT);
--- a/js/src/jit/mips/MacroAssembler-mips.cpp
+++ b/js/src/jit/mips/MacroAssembler-mips.cpp
@@ -47,30 +47,30 @@ MacroAssemblerMIPS::convertInt32ToDouble
     ma_lw(ScratchRegister, src);
     as_mtc1(ScratchRegister, dest);
     as_cvtdw(dest, dest);
 }
 
 void
 MacroAssemblerMIPS::convertUInt32ToDouble(Register src, FloatRegister dest)
 {
-    // We use SecondScratchFloatReg because MacroAssembler::loadFromTypedArray
-    // calls with ScratchFloatReg as dest.
-    MOZ_ASSERT(dest != SecondScratchFloatReg);
+    // We use SecondScratchDoubleReg because MacroAssembler::loadFromTypedArray
+    // calls with ScratchDoubleReg as dest.
+    MOZ_ASSERT(dest != SecondScratchDoubleReg);
 
     // Subtract INT32_MIN to get a positive number
     ma_subu(ScratchRegister, src, Imm32(INT32_MIN));
 
     // Convert value
     as_mtc1(ScratchRegister, dest);
     as_cvtdw(dest, dest);
 
     // Add unsigned value of INT32_MIN
-    ma_lid(SecondScratchFloatReg, 2147483648.0);
-    as_addd(dest, dest, SecondScratchFloatReg);
+    ma_lid(SecondScratchDoubleReg, 2147483648.0);
+    as_addd(dest, dest, SecondScratchDoubleReg);
 }
 
 void
 MacroAssemblerMIPS::convertUInt32ToFloat32(Register src, FloatRegister dest)
 {
     Label positive, done;
     ma_b(src, src, &positive, NotSigned, ShortJump);
 
@@ -96,36 +96,36 @@ MacroAssemblerMIPS::convertDoubleToFloat
 // was clamped to INT32_MIN/INT32_MAX, and we can test it.
 // NOTE: if the value really was supposed to be INT32_MAX / INT32_MIN then it
 // will be wrong.
 void
 MacroAssemblerMIPS::branchTruncateDouble(FloatRegister src, Register dest,
                                          Label *fail)
 {
     Label test, success;
-    as_truncwd(ScratchFloatReg, src);
-    as_mfc1(dest, ScratchFloatReg);
+    as_truncwd(ScratchDoubleReg, src);
+    as_mfc1(dest, ScratchDoubleReg);
 
     ma_b(dest, Imm32(INT32_MAX), fail, Assembler::Equal);
     ma_b(dest, Imm32(INT32_MIN), fail, Assembler::Equal);
 }
 
 // Checks whether a double is representable as a 32-bit integer. If so, the
 // integer is written to the output register. Otherwise, a bailout is taken to
 // the given snapshot. This function overwrites the scratch float register.
 void
 MacroAssemblerMIPS::convertDoubleToInt32(FloatRegister src, Register dest,
                                          Label *fail, bool negativeZeroCheck)
 {
     // Convert double to int, then convert back and check if we have the
     // same number.
-    as_cvtwd(ScratchFloatReg, src);
-    as_mfc1(dest, ScratchFloatReg);
-    as_cvtdw(ScratchFloatReg, ScratchFloatReg);
-    ma_bc1d(src, ScratchFloatReg, fail, Assembler::DoubleNotEqualOrUnordered);
+    as_cvtwd(ScratchDoubleReg, src);
+    as_mfc1(dest, ScratchDoubleReg);
+    as_cvtdw(ScratchDoubleReg, ScratchDoubleReg);
+    ma_bc1d(src, ScratchDoubleReg, fail, Assembler::DoubleNotEqualOrUnordered);
 
     if (negativeZeroCheck) {
         Label notZero;
         ma_b(dest, Imm32(0), &notZero, Assembler::NotEqual, ShortJump);
         // Test and bail for -0.0, when integer result is 0
         // Move the top word of the double into the output reg, if it is
         // non-zero, then the original value was -0.0
         moveFromDoubleHi(src, dest);
@@ -139,20 +139,20 @@ MacroAssemblerMIPS::convertDoubleToInt32
 // the given snapshot. This function overwrites the scratch float register.
 void
 MacroAssemblerMIPS::convertFloat32ToInt32(FloatRegister src, Register dest,
                                           Label *fail, bool negativeZeroCheck)
 {
     // convert the floating point value to an integer, if it did not fit, then
     // when we convert it *back* to  a float, it will have a different value,
     // which we can test.
-    as_cvtws(ScratchFloatReg, src);
-    as_mfc1(dest, ScratchFloatReg);
-    as_cvtsw(ScratchFloatReg, ScratchFloatReg);
-    ma_bc1s(src, ScratchFloatReg, fail, Assembler::DoubleNotEqualOrUnordered);
+    as_cvtws(ScratchFloat32Reg, src);
+    as_mfc1(dest, ScratchFloat32Reg);
+    as_cvtsw(ScratchFloat32Reg, ScratchFloat32Reg);
+    ma_bc1s(src, ScratchFloat32Reg, fail, Assembler::DoubleNotEqualOrUnordered);
 
     if (negativeZeroCheck) {
         Label notZero;
         ma_b(dest, Imm32(0), &notZero, Assembler::NotEqual, ShortJump);
         // Test and bail for -0.0, when integer result is 0
         // Move the top word of the double into the output reg,
         // if it is non-zero, then the original value was -0.0
         moveFromDoubleHi(src, dest);
@@ -167,18 +167,18 @@ MacroAssemblerMIPS::convertFloat32ToDoub
     as_cvtds(dest, src);
 }
 
 void
 MacroAssemblerMIPS::branchTruncateFloat32(FloatRegister src, Register dest,
                                           Label *fail)
 {
     Label test, success;
-    as_truncws(ScratchFloatReg, src);
-    as_mfc1(dest, ScratchFloatReg);
+    as_truncws(ScratchFloat32Reg, src);
+    as_mfc1(dest, ScratchFloat32Reg);
 
     ma_b(dest, Imm32(INT32_MAX), fail, Assembler::Equal);
 }
 
 void
 MacroAssemblerMIPS::convertInt32ToFloat32(Register src, FloatRegister dest)
 {
     as_mtc1(src, dest);
@@ -1425,25 +1425,25 @@ MacroAssemblerMIPS::ma_ss(FloatRegister 
 {
     computeScaledAddress(address, SecondScratchReg);
     ma_ss(ft, Address(SecondScratchReg, address.offset));
 }
 
 void
 MacroAssemblerMIPS::ma_pop(FloatRegister fs)
 {
-    ma_ld(fs, Address(StackPointer, 0));
+    ma_ld(fs.doubleOverlay(0), Address(StackPointer, 0));
     as_addiu(StackPointer, StackPointer, sizeof(double));
 }
 
 void
 MacroAssemblerMIPS::ma_push(FloatRegister fs)
 {
     as_addiu(StackPointer, StackPointer, -sizeof(double));
-    ma_sd(fs, Address(StackPointer, 0));
+    ma_sd(fs.doubleOverlay(0), Address(StackPointer, 0));
 }
 
 void
 MacroAssemblerMIPS::ma_bc1s(FloatRegister lhs, FloatRegister rhs, Label *label,
                             DoubleCondition c, JumpKind jumpKind, FPConditionBit fcc)
 {
     FloatTestKind testKind;
     compareFloatingPoint(SingleFloat, lhs, rhs, c, &testKind, fcc);
@@ -1556,63 +1556,54 @@ MacroAssemblerMIPSCompat::freeStack(Regi
 {
     as_addu(StackPointer, StackPointer, amount);
 }
 
 void
 MacroAssembler::PushRegsInMask(RegisterSet set, FloatRegisterSet simdSet)
 {
     JS_ASSERT(!SupportsSimd && simdSet.size() == 0);
-    int32_t diffF = set.fpus().size() * sizeof(double);
+    int32_t diffF = set.fpus().getPushSizeInBytes();
     int32_t diffG = set.gprs().size() * sizeof(intptr_t);
 
     reserveStack(diffG);
     for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
         diffG -= sizeof(intptr_t);
         storePtr(*iter, Address(StackPointer, diffG));
     }
     MOZ_ASSERT(diffG == 0);
 
     // Double values have to be aligned. We reserve extra space so that we can
     // start writing from the first aligned location.
     // We reserve a whole extra double so that the buffer has even size.
     ma_and(SecondScratchReg, sp, Imm32(~(StackAlignment - 1)));
     reserveStack(diffF + sizeof(double));
 
-    for (FloatRegisterForwardIterator iter(set.fpus()); iter.more(); iter++) {
-        // Use assembly s.d because we have alligned the stack.
-        // :TODO: (Bug 972836) Fix this once odd regs can be used as
-        // float32 only. For now we skip saving odd regs for O32 ABI.
-
-        // :TODO: (Bug 985881) Make a switch for N32 ABI.
+    for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); iter++) {
         if ((*iter).code() % 2 == 0)
             as_sd(*iter, SecondScratchReg, -diffF);
         diffF -= sizeof(double);
     }
     MOZ_ASSERT(diffF == 0);
 }
 
 void
 MacroAssembler::PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore, FloatRegisterSet simdSet)
 {
     JS_ASSERT(!SupportsSimd && simdSet.size() == 0);
     int32_t diffG = set.gprs().size() * sizeof(intptr_t);
-    int32_t diffF = set.fpus().size() * sizeof(double);
+    int32_t diffF = set.fpus().getPushSizeInBytes();
     const int32_t reservedG = diffG;
     const int32_t reservedF = diffF;
 
     // Read the buffer form the first aligned location.
     ma_addu(SecondScratchReg, sp, Imm32(reservedF + sizeof(double)));
     ma_and(SecondScratchReg, SecondScratchReg, Imm32(~(StackAlignment - 1)));
 
-    for (FloatRegisterForwardIterator iter(set.fpus()); iter.more(); iter++) {
-        // :TODO: (Bug 972836) Fix this once odd regs can be used as
-        // float32 only. For now we skip loading odd regs for O32 ABI.
-
-        // :TODO: (Bug 985881) Make a switch for N32 ABI.
+    for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); iter++) {
         if (!ignore.has(*iter) && ((*iter).code() % 2 == 0))
             // Use assembly l.d because we have alligned the stack.
             as_ld(*iter, SecondScratchReg, -diffF);
         diffF -= sizeof(double);
     }
     freeStack(reservedF + sizeof(double));
     MOZ_ASSERT(diffF == 0);
 
@@ -2065,41 +2056,41 @@ MacroAssemblerMIPSCompat::storePtr(Regis
     ma_li(ScratchRegister, Imm32((uint32_t)dest.addr));
     as_sw(src, ScratchRegister, 0);
 }
 
 // Note: this function clobbers the input register.
 void
 MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output)
 {
-    JS_ASSERT(input != ScratchFloatReg);
+    JS_ASSERT(input != ScratchDoubleReg);
     Label positive, done;
 
     // <= 0 or NaN --> 0
-    zeroDouble(ScratchFloatReg);
-    branchDouble(DoubleGreaterThan, input, ScratchFloatReg, &positive);
+    zeroDouble(ScratchDoubleReg);
+    branchDouble(DoubleGreaterThan, input, ScratchDoubleReg, &positive);
     {
         move32(Imm32(0), output);
         jump(&done);
     }
 
     bind(&positive);
 
     // Add 0.5 and truncate.
-    loadConstantDouble(0.5, ScratchFloatReg);
-    addDouble(ScratchFloatReg, input);
+    loadConstantDouble(0.5, ScratchDoubleReg);
+    addDouble(ScratchDoubleReg, input);
 
     Label outOfRange;
 
     branchTruncateDouble(input, output, &outOfRange);
     branch32(Assembler::Above, output, Imm32(255), &outOfRange);
     {
         // Check if we had a tie.
-        convertInt32ToDouble(output, ScratchFloatReg);
-        branchDouble(DoubleNotEqual, input, ScratchFloatReg, &done);
+        convertInt32ToDouble(output, ScratchDoubleReg);
+        branchDouble(DoubleNotEqual, input, ScratchDoubleReg, &done);
 
         // It was a tie. Mask out the ones bit to get an even value.
         // See also js_TypedArray_uint8_clamp_double.
         and32(Imm32(~1), output);
         jump(&done);
     }
 
     // > 255 --> 255
@@ -2529,17 +2520,16 @@ void
 MacroAssemblerMIPSCompat::unboxBoolean(const Address &src, Register dest)
 {
     ma_lw(dest, Address(src.base, src.offset + PAYLOAD_OFFSET));
 }
 
 void
 MacroAssemblerMIPSCompat::unboxDouble(const ValueOperand &operand, FloatRegister dest)
 {
-    MOZ_ASSERT(dest != ScratchFloatReg);
     moveToDoubleLo(operand.payloadReg(), dest);
     moveToDoubleHi(operand.typeReg(), dest);
 }
 
 void
 MacroAssemblerMIPSCompat::unboxDouble(const Address &src, FloatRegister dest)
 {
     ma_lw(ScratchRegister, Address(src.base, src.offset + PAYLOAD_OFFSET));
@@ -2709,19 +2699,19 @@ MacroAssemblerMIPSCompat::branchTestStri
     Register string = value.payloadReg();
     ma_lw(SecondScratchReg, Address(string, JSString::offsetOfLength()));
     ma_b(SecondScratchReg, Imm32(0), label, b ? NotEqual : Equal);
 }
 
 void
 MacroAssemblerMIPSCompat::branchTestDoubleTruthy(bool b, FloatRegister value, Label *label)
 {
-    ma_lid(ScratchFloatReg, 0.0);
+    ma_lid(ScratchDoubleReg, 0.0);
     DoubleCondition cond = b ? DoubleNotEqual : DoubleEqualOrUnordered;
-    ma_bc1d(value, ScratchFloatReg, label, cond);
+    ma_bc1d(value, ScratchDoubleReg, label, cond);
 }
 
 void
 MacroAssemblerMIPSCompat::branchTestBooleanTruthy(bool b, const ValueOperand &operand,
                                                   Label *label)
 {
     ma_b(operand.payloadReg(), operand.payloadReg(), label, b ? NonZero : Zero);
 }
--- a/js/src/jit/mips/MoveEmitter-mips.cpp
+++ b/js/src/jit/mips/MoveEmitter-mips.cpp
@@ -5,50 +5,50 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/mips/MoveEmitter-mips.h"
 
 using namespace js;
 using namespace js::jit;
 
 MoveEmitterMIPS::MoveEmitterMIPS(MacroAssemblerMIPSCompat &masm)
-  : inCycle_(false),
+  : inCycle_(0),
     masm(masm),
     pushedAtCycle_(-1),
     pushedAtSpill_(-1),
     spilledReg_(InvalidReg),
     spilledFloatReg_(InvalidFloatReg)
 {
     pushedAtStart_ = masm.framePushed();
 }
 
 void
 MoveEmitterMIPS::emit(const MoveResolver &moves)
 {
-    if (moves.hasCycles()) {
+    if (moves.numCycles()) {
         // Reserve stack for cycle resolution
-        masm.reserveStack(sizeof(double));
+        masm.reserveStack(moves.numCycles() * sizeof(double));
         pushedAtCycle_ = masm.framePushed();
     }
 
     for (size_t i = 0; i < moves.numMoves(); i++)
         emit(moves.getMove(i));
 }
 
 MoveEmitterMIPS::~MoveEmitterMIPS()
 {
     assertDone();
 }
 
 Address
-MoveEmitterMIPS::cycleSlot() const
+MoveEmitterMIPS::cycleSlot(uint32_t slot, uint32_t subslot) const
 {
-    int offset = masm.framePushed() - pushedAtCycle_;
+    int32_t offset = masm.framePushed() - pushedAtCycle_;
     MOZ_ASSERT(Imm16::IsInSignedRange(offset));
-    return Address(StackPointer, offset);
+    return Address(StackPointer, offset + slot * sizeof(double) + subslot);
 }
 
 int32_t
 MoveEmitterMIPS::getAdjustedOffset(const MoveOperand &operand)
 {
     MOZ_ASSERT(operand.isMemoryOrEffectiveAddress());
     if (operand.base() != StackPointer)
         return operand.disp();
@@ -67,100 +67,109 @@ MoveEmitterMIPS::getAdjustedAddress(cons
 Register
 MoveEmitterMIPS::tempReg()
 {
     spilledReg_ = SecondScratchReg;
     return SecondScratchReg;
 }
 
 void
-MoveEmitterMIPS::breakCycle(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type)
+MoveEmitterMIPS::breakCycle(const MoveOperand &from, const MoveOperand &to,
+                            MoveOp::Type type, uint32_t slotId)
 {
     // There is some pattern:
     //   (A -> B)
     //   (B -> A)
     //
     // This case handles (A -> B), which we reach first. We save B, then allow
     // the original move to continue.
     switch (type) {
       case MoveOp::FLOAT32:
         if (to.isMemory()) {
-            FloatRegister temp = ScratchFloatReg;
+            FloatRegister temp = ScratchFloat32Reg;
             masm.loadFloat32(getAdjustedAddress(to), temp);
-            masm.storeFloat32(temp, cycleSlot());
+            // Since it is uncertain if the load will be aligned or not
+            // just fill both of them with the same value.
+            masm.storeFloat32(temp, cycleSlot(slotId, 0));
+            masm.storeFloat32(temp, cycleSlot(slotId, 4));
         } else {
-            masm.storeFloat32(to.floatReg(), cycleSlot());
+            masm.storeFloat32(to.floatReg(), cycleSlot(slotId, 0));
         }
         break;
       case MoveOp::DOUBLE:
         if (to.isMemory()) {
-            FloatRegister temp = ScratchFloatReg;
+            FloatRegister temp = ScratchDoubleReg;
             masm.loadDouble(getAdjustedAddress(to), temp);
-            masm.storeDouble(temp, cycleSlot());
+            masm.storeDouble(temp, cycleSlot(slotId, 0));
         } else {
-            masm.storeDouble(to.floatReg(), cycleSlot());
+            masm.storeDouble(to.floatReg(), cycleSlot(slotId, 0));
         }
         break;
       case MoveOp::INT32:
         MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t));
       case MoveOp::GENERAL:
         if (to.isMemory()) {
             Register temp = tempReg();
             masm.loadPtr(getAdjustedAddress(to), temp);
-            masm.storePtr(temp, cycleSlot());
+            masm.storePtr(temp, cycleSlot(0, 0));
         } else {
             // Second scratch register should not be moved by MoveEmitter.
             MOZ_ASSERT(to.reg() != spilledReg_);
-            masm.storePtr(to.reg(), cycleSlot());
+            masm.storePtr(to.reg(), cycleSlot(0, 0));
         }
         break;
       default:
         MOZ_CRASH("Unexpected move type");
     }
 }
 
 void
-MoveEmitterMIPS::completeCycle(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type)
+MoveEmitterMIPS::completeCycle(const MoveOperand &from, const MoveOperand &to,
+                               MoveOp::Type type, uint32_t slotId)
 {
     // There is some pattern:
     //   (A -> B)
     //   (B -> A)
     //
     // This case handles (B -> A), which we reach last. We emit a move from the
     // saved value of B, to A.
     switch (type) {
       case MoveOp::FLOAT32:
         if (to.isMemory()) {
-            FloatRegister temp = ScratchFloatReg;
-            masm.loadFloat32(cycleSlot(), temp);
+            FloatRegister temp = ScratchFloat32Reg;
+            masm.loadFloat32(cycleSlot(slotId, 0), temp);
             masm.storeFloat32(temp, getAdjustedAddress(to));
         } else {
-            masm.loadFloat32(cycleSlot(), to.floatReg());
+            uint32_t offset = 0;
+            if (from.floatReg().numAlignedAliased() == 1)
+                offset = sizeof(float);
+            masm.loadFloat32(cycleSlot(slotId, offset), to.floatReg());
         }
         break;
       case MoveOp::DOUBLE:
         if (to.isMemory()) {
-            FloatRegister temp = ScratchFloatReg;
-            masm.loadDouble(cycleSlot(), temp);
+            FloatRegister temp = ScratchDoubleReg;
+            masm.loadDouble(cycleSlot(slotId, 0), temp);
             masm.storeDouble(temp, getAdjustedAddress(to));
         } else {
-            masm.loadDouble(cycleSlot(), to.floatReg());
+            masm.loadDouble(cycleSlot(slotId, 0), to.floatReg());
         }
         break;
       case MoveOp::INT32:
         MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t));
       case MoveOp::GENERAL:
+        MOZ_ASSERT(slotId == 0);
         if (to.isMemory()) {
             Register temp = tempReg();
-            masm.loadPtr(cycleSlot(), temp);
+            masm.loadPtr(cycleSlot(0, 0), temp);
             masm.storePtr(temp, getAdjustedAddress(to));
         } else {
             // Second scratch register should not be moved by MoveEmitter.
             MOZ_ASSERT(to.reg() != spilledReg_);
-            masm.loadPtr(cycleSlot(), to.reg());
+            masm.loadPtr(cycleSlot(0, 0), to.reg());
         }
         break;
       default:
         MOZ_CRASH("Unexpected move type");
     }
 }
 
 void
@@ -197,19 +206,19 @@ MoveEmitterMIPS::emitMove(const MoveOper
     } else {
         MOZ_CRASH("Invalid emitMove arguments.");
     }
 }
 
 void
 MoveEmitterMIPS::emitFloat32Move(const MoveOperand &from, const MoveOperand &to)
 {
-    // Ensure that we can use ScratchFloatReg in memory move.
-    MOZ_ASSERT_IF(from.isFloatReg(), from.floatReg() != ScratchFloatReg);
-    MOZ_ASSERT_IF(to.isFloatReg(), to.floatReg() != ScratchFloatReg);
+    // Ensure that we can use ScratchFloat32Reg in memory move.
+    MOZ_ASSERT_IF(from.isFloatReg(), from.floatReg() != ScratchFloat32Reg);
+    MOZ_ASSERT_IF(to.isFloatReg(), to.floatReg() != ScratchFloat32Reg);
 
     if (from.isFloatReg()) {
         if (to.isFloatReg()) {
             masm.moveFloat32(from.floatReg(), to.floatReg());
         } else if (to.isGeneralReg()) {
             // This should only be used when passing float parameter in a1,a2,a3
             MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3);
             masm.moveFromFloat32(from.floatReg(), to.reg());
@@ -223,27 +232,27 @@ MoveEmitterMIPS::emitFloat32Move(const M
     } else if (to.isGeneralReg()) {
         MOZ_ASSERT(from.isMemory());
         // This should only be used when passing float parameter in a1,a2,a3
         MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3);
         masm.loadPtr(getAdjustedAddress(from), to.reg());
     } else {
         MOZ_ASSERT(from.isMemory());
         MOZ_ASSERT(to.isMemory());
-        masm.loadFloat32(getAdjustedAddress(from), ScratchFloatReg);
-        masm.storeFloat32(ScratchFloatReg, getAdjustedAddress(to));
+        masm.loadFloat32(getAdjustedAddress(from), ScratchFloat32Reg);
+        masm.storeFloat32(ScratchFloat32Reg, getAdjustedAddress(to));
     }
 }
 
 void
 MoveEmitterMIPS::emitDoubleMove(const MoveOperand &from, const MoveOperand &to)
 {
-    // Ensure that we can use ScratchFloatReg in memory move.
-    MOZ_ASSERT_IF(from.isFloatReg(), from.floatReg() != ScratchFloatReg);
-    MOZ_ASSERT_IF(to.isFloatReg(), to.floatReg() != ScratchFloatReg);
+    // Ensure that we can use ScratchDoubleReg in memory move.
+    MOZ_ASSERT_IF(from.isFloatReg(), from.floatReg() != ScratchDoubleReg);
+    MOZ_ASSERT_IF(to.isFloatReg(), to.floatReg() != ScratchDoubleReg);
 
     if (from.isFloatReg()) {
         if (to.isFloatReg()) {
             masm.moveDouble(from.floatReg(), to.floatReg());
         } else if (to.isGeneralReg()) {
             // Used for passing double parameter in a2,a3 register pair.
             // Two moves are added for one double parameter by
             // MacroAssemblerMIPSCompat::passABIArg
@@ -269,38 +278,46 @@ MoveEmitterMIPS::emitDoubleMove(const Mo
             masm.loadPtr(getAdjustedAddress(from), a2);
         else if(to.reg() == a3)
             masm.loadPtr(Address(from.base(), getAdjustedOffset(from) + sizeof(uint32_t)), a3);
         else
             MOZ_CRASH("Invalid emitDoubleMove arguments.");
     } else {
         MOZ_ASSERT(from.isMemory());
         MOZ_ASSERT(to.isMemory());
-        masm.loadDouble(getAdjustedAddress(from), ScratchFloatReg);
-        masm.storeDouble(ScratchFloatReg, getAdjustedAddress(to));
+        masm.loadDouble(getAdjustedAddress(from), ScratchDoubleReg);
+        masm.storeDouble(ScratchDoubleReg, getAdjustedAddress(to));
     }
 }
 
 void
 MoveEmitterMIPS::emit(const MoveOp &move)
 {
     const MoveOperand &from = move.from();
     const MoveOperand &to = move.to();
 
+    if (move.isCycleEnd() && move.isCycleBegin()) {
+        // A fun consequence of aliased registers is you can have multiple
+        // cycles at once, and one can end exactly where another begins.
+        breakCycle(from, to, move.endCycleType(), move.cycleBeginSlot());
+        completeCycle(from, to, move.type(), move.cycleEndSlot());
+        return;
+    }
+
     if (move.isCycleEnd()) {
         MOZ_ASSERT(inCycle_);
-        completeCycle(from, to, move.type());
-        inCycle_ = false;
+        completeCycle(from, to, move.type(), move.cycleEndSlot());
+        MOZ_ASSERT(inCycle_ > 0);
+        inCycle_--;
         return;
     }
 
     if (move.isCycleBegin()) {
-        MOZ_ASSERT(!inCycle_);
-        breakCycle(from, to, move.endCycleType());
-        inCycle_ = true;
+        breakCycle(from, to, move.endCycleType(), move.cycleBeginSlot());
+        inCycle_++;
     }
 
     switch (move.type()) {
       case MoveOp::FLOAT32:
         emitFloat32Move(from, to);
         break;
       case MoveOp::DOUBLE:
         emitDoubleMove(from, to);
@@ -313,17 +330,17 @@ MoveEmitterMIPS::emit(const MoveOp &move
       default:
         MOZ_CRASH("Unexpected move type");
     }
 }
 
 void
 MoveEmitterMIPS::assertDone()
 {
-    MOZ_ASSERT(!inCycle_);
+    MOZ_ASSERT(inCycle_ == 0);
 }
 
 void
 MoveEmitterMIPS::finish()
 {
     assertDone();
 
     masm.freeStack(masm.framePushed() - pushedAtStart_);
--- a/js/src/jit/mips/MoveEmitter-mips.h
+++ b/js/src/jit/mips/MoveEmitter-mips.h
@@ -12,17 +12,17 @@
 
 namespace js {
 namespace jit {
 
 class CodeGenerator;
 
 class MoveEmitterMIPS
 {
-    bool inCycle_;
+    uint32_t inCycle_;
     MacroAssemblerMIPSCompat &masm;
 
     // Original stack push value.
     uint32_t pushedAtStart_;
 
     // These store stack offsets to spill locations, snapshotting
     // codegen->framePushed_ at the time they were allocated. They are -1 if no
     // stack space has been allocated for that particular spill.
@@ -33,25 +33,27 @@ class MoveEmitterMIPS
     // assigned InvalidReg. If no corresponding spill space has been assigned,
     // then these registers do not need to be spilled.
     Register spilledReg_;
     FloatRegister spilledFloatReg_;
 
     void assertDone();
     Register tempReg();
     FloatRegister tempFloatReg();
-    Address cycleSlot() const;
+    Address cycleSlot(uint32_t slot, uint32_t subslot) const;
     int32_t getAdjustedOffset(const MoveOperand &operand);
     Address getAdjustedAddress(const MoveOperand &operand);
 
     void emitMove(const MoveOperand &from, const MoveOperand &to);
     void emitFloat32Move(const MoveOperand &from, const MoveOperand &to);
     void emitDoubleMove(const MoveOperand &from, const MoveOperand &to);
-    void breakCycle(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type);
-    void completeCycle(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type);
+    void breakCycle(const MoveOperand &from, const MoveOperand &to,
+                    MoveOp::Type type, uint32_t slot);
+    void completeCycle(const MoveOperand &from, const MoveOperand &to,
+                       MoveOp::Type type, uint32_t slot);
     void emit(const MoveOp &move);
 
   public:
     MoveEmitterMIPS(MacroAssemblerMIPSCompat &masm);
     ~MoveEmitterMIPS();
     void emit(const MoveResolver &moves);
     void finish();
 };
--- a/js/src/jit/mips/Simulator-mips.cpp
+++ b/js/src/jit/mips/Simulator-mips.cpp
@@ -922,17 +922,17 @@ MipsDebugger::debug()
                 if (argc == 2) {
                     int32_t value;
                     if (strcmp(arg1, "all") == 0) {
                         printAllRegs();
                     } else if (strcmp(arg1, "allf") == 0) {
                         printAllRegsIncludingFPU();
                     } else {
                         Register reg = Register::FromName(arg1);
-                        FloatRegister fReg = FloatRegister::FromName(arg1);
+                        FloatRegister fReg(FloatRegister::FromName(arg1));
                         if (reg != InvalidReg) {
                             value = getRegisterValue(reg.code());
                             printf("%s: 0x%08x %d \n", arg1, value, value);
                         } else if (fReg.code() != FloatRegisters::Invalid) {
                             MOZ_CRASH("NYI");
                         } else {
                             printf("%s unrecognized\n", arg1);
                         }
--- a/js/src/jit/mips/Trampoline-mips.cpp
+++ b/js/src/jit/mips/Trampoline-mips.cpp
@@ -335,21 +335,19 @@ JitRuntime::generateInvalidator(JSContex
     for (uint32_t i = 0; i < Registers::Total; i++) {
         Address address = Address(StackPointer, InvalidationBailoutStack::offsetOfRegs() +
                                                 i * sizeof(uintptr_t));
         masm.storePtr(Register::FromCode(i), address);
     }
 
     // Save floating point registers
     // We can use as_sd because stack is alligned.
-    // :TODO: (Bug 972836) // Fix this once odd regs can be used as float32
-    // only. For now we skip saving odd regs for O32 ABI.
     uint32_t increment = 2;
-    for (uint32_t i = 0; i < FloatRegisters::Total; i += increment)
-        masm.as_sd(FloatRegister::FromCode(i), StackPointer,
+    for (uint32_t i = 0; i < FloatRegisters::TotalDouble; i ++)
+        masm.as_sd(FloatRegister::FromIndex(i, FloatRegister::Double), StackPointer,
                    InvalidationBailoutStack::offsetOfFpRegs() + i * sizeof(double));
 
     // Pass pointer to InvalidationBailoutStack structure.
     masm.movePtr(StackPointer, a0);
 
     // Reserve place for return value and BailoutInfo pointer
     masm.subPtr(Imm32(2 * sizeof(uintptr_t)), StackPointer);
     // Pass pointer to return value.
@@ -559,21 +557,18 @@ PushBailoutFrame(MacroAssembler &masm, u
     // Save general purpose registers.
     for (uint32_t i = 0; i < Registers::Total; i++) {
         uint32_t off = BailoutStack::offsetOfRegs() + i * sizeof(uintptr_t);
         masm.storePtr(Register::FromCode(i), Address(StackPointer, off));
     }
 
     // Save floating point registers
     // We can use as_sd because stack is alligned.
-    // :TODO: (Bug 972836) // Fix this once odd regs can be used as float32
-    // only. For now we skip saving odd regs for O32 ABI.
-    uint32_t increment = 2;
-    for (uint32_t i = 0; i < FloatRegisters::Total; i += increment)
-        masm.as_sd(FloatRegister::FromCode(i), StackPointer,
+    for (uint32_t i = 0; i < FloatRegisters::TotalDouble; i++)
+        masm.as_sd(FloatRegister::FromIndex(i, FloatRegister::Double), StackPointer,
                    BailoutStack::offsetOfFpRegs() + i * sizeof(double));
 
     // Store the frameSize_ or tableOffset_ stored in ra
     // See: JitRuntime::generateBailoutTable()
     // See: CodeGeneratorMIPS::generateOutOfLineCode()
     masm.storePtr(ra, Address(StackPointer, BailoutStack::offsetOfFrameSize()));
 
     // Put frame class to stack
@@ -807,18 +802,18 @@ JitRuntime::generateVMWrapper(JSContext 
             break;
           case VMFunction::WordByRef:
             masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS),
                             MoveOp::GENERAL);
             argDisp += sizeof(uint32_t);
             break;
           case VMFunction::DoubleByRef:
             // Copy double sized argument to aligned place.
-            masm.ma_ld(ScratchFloatReg, Address(argsBase, argDisp));
-            masm.as_sd(ScratchFloatReg, doubleArgs, doubleArgDisp);
+            masm.ma_ld(ScratchDoubleReg, Address(argsBase, argDisp));
+            masm.as_sd(ScratchDoubleReg, doubleArgs, doubleArgDisp);
             masm.passABIArg(MoveOperand(doubleArgs, doubleArgDisp, MoveOperand::EFFECTIVE_ADDRESS),
                             MoveOp::GENERAL);
             doubleArgDisp += sizeof(double);
             argDisp += sizeof(double);
             break;
         }
     }
 
@@ -868,17 +863,17 @@ JitRuntime::generateVMWrapper(JSContext 
 
       case Type_Bool:
         masm.load8ZeroExtend(Address(StackPointer, 0), ReturnReg);
         masm.freeStack(sizeof(uintptr_t));
         break;
 
       case Type_Double:
         if (cx->runtime()->jitSupportsFloatingPoint) {
-            masm.as_ld(ReturnFloatReg, StackPointer, 0);
+            masm.as_ld(ReturnDoubleReg, StackPointer, 0);
         } else {
             masm.assumeUnreachable("Unable to load into float reg, with no FP support.");
         }
         masm.freeStack(sizeof(double));
         break;
 
       default:
         MOZ_ASSERT(f.outParam == Type_Void);