Bug 1321521 - RegisterSets: Add a register type to getAny and add the equivalent hasAny function. r=lth
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Mon, 16 Jan 2017 12:47:34 +0000
changeset 357606 54d34c02426840cf68b051ccaea81facc8a6afc3
parent 357605 f329799b4fae58129f88797ec4ade91b9d7cb9cb
child 357607 b8192f69e1a05783226e43b849f379e1bc04c3c4
push id10621
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 16:02:43 +0000
treeherdermozilla-aurora@dca7b42e6c67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslth
bugs1321521
milestone53.0a1
Bug 1321521 - RegisterSets: Add a register type to getAny and add the equivalent hasAny function. r=lth
js/src/jit/BacktrackingAllocator.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/RegisterSets.h
js/src/jit/Registers.h
js/src/jit/StupidAllocator.cpp
js/src/jit/arm/Architecture-arm.h
js/src/jit/arm64/Architecture-arm64.h
js/src/jit/mips-shared/Architecture-mips-shared.h
js/src/jit/shared/Architecture-shared.h
js/src/jit/x86-shared/Architecture-x86-shared.h
js/src/jsapi-tests/testJitRegisterSet.cpp
js/src/wasm/WasmBaselineCompile.cpp
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -414,17 +414,17 @@ BacktrackingAllocator::init()
     }
 
     LiveRegisterSet remainingRegisters(allRegisters_.asLiveSet());
     while (!remainingRegisters.emptyGeneral()) {
         AnyRegister reg = AnyRegister(remainingRegisters.takeAnyGeneral());
         registers[reg.code()].allocatable = true;
     }
     while (!remainingRegisters.emptyFloat()) {
-        AnyRegister reg = AnyRegister(remainingRegisters.takeAnyFloat());
+        AnyRegister reg = AnyRegister(remainingRegisters.takeAnyFloat<RegTypeName::Any>());
         registers[reg.code()].allocatable = true;
     }
 
     LifoAlloc* lifoAlloc = mir->alloc().lifoAlloc();
     for (size_t i = 0; i < AnyRegister::Total; i++) {
         registers[i].reg = AnyRegister::FromCode(i);
         registers[i].allocations.setAllocator(lifoAlloc);
     }
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4681,17 +4681,17 @@ CodeGenerator::generateArgumentsChecks(b
     // before entering the function and bailout when arguments don't match.
     // For debug purpose, this is can also be used to force/check that the
     // arguments are correct. Upon fail it will hit a breakpoint.
 
     MIRGraph& mir = gen->graph();
     MResumePoint* rp = mir.entryResumePoint();
 
     // No registers are allocated yet, so it's safe to grab anything.
-    Register temp = GeneralRegisterSet(EntryTempMask).getAny();
+    Register temp = AllocatableGeneralRegisterSet(EntryTempMask).getAny();
 
     const CompileInfo& info = gen->info();
 
     Label miss;
     for (uint32_t i = info.startArgSlot(); i < info.endArgSlot(); i++) {
         // All initial parameters are guaranteed to be MParameters.
         MParameter* param = rp->getOperand(i)->toParameter();
         const TypeSet* types = param->resultTypeSet();
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -387,32 +387,32 @@ class TypedRegisterSet
 
     void takeRegisterIndex(T reg) {
         bits_ &= ~(SetType(1) << reg.code());
     }
     void takeAllocatable(T reg) {
         bits_ &= ~reg.alignedOrDominatedAliasedSet();
     }
 
-    T getAny() const {
-        // The choice of first or last here is mostly arbitrary, as they are
-        // about the same speed on popular architectures. We choose first, as
-        // it has the advantage of using the "lower" registers more often. These
-        // registers are sometimes more efficient (e.g. optimized encodings for
-        // EAX on x86).
-        return getFirst();
+    static constexpr RegTypeName DefaultType = RegType::DefaultType;
+
+    template <RegTypeName Name>
+    SetType allLive() const {
+        return T::template LiveAsIndexableSet<Name>(bits_);
     }
-    T getFirst() const {
-        MOZ_ASSERT(!empty());
-        return T::FromCode(T::FirstBit(bits_));
+    template <RegTypeName Name>
+    SetType allAllocatable() const {
+        return T::template AllocatableAsIndexableSet<Name>(bits_);
     }
-    T getLast() const {
-        MOZ_ASSERT(!empty());
-        int ireg = T::LastBit(bits_);
-        return T::FromCode(ireg);
+
+    static RegType FirstRegister(SetType set) {
+        return RegType::FromCode(RegType::FirstBit(set));
+    }
+    static RegType LastRegister(SetType set) {
+        return RegType::FromCode(RegType::LastBit(set));
     }
 
     SetType bits() const {
         return bits_;
     }
     uint32_t size() const {
         return T::SetSize(bits_);
     }
@@ -476,16 +476,19 @@ class RegisterSet {
         gpr_.clear();
     }
     bool emptyGeneral() const {
         return gpr_.empty();
     }
     bool emptyFloat() const {
         return fpu_.empty();
     }
+
+    static constexpr RegTypeName DefaultType = RegTypeName::GPR;
+
     constexpr GeneralRegisterSet gprs() const {
         return gpr_;
     }
     GeneralRegisterSet& gprs() {
         return gpr_;
     }
     constexpr FloatRegisterSet fpus() const {
         return fpu_;
@@ -535,16 +538,19 @@ template <typename RegisterSet>
 class AllocatableSet;
 
 template <typename RegisterSet>
 class LiveSet;
 
 // Base accessors classes have the minimal set of raw methods to manipulate the register set
 // given as parameter in a consistent manner.  These methods are:
 //
+//    - all<Type>: Returns a bit-set of all the register of a specific type
+//      which are present.
+//
 //    - has: Returns if all the bits needed to take a register are present.
 //
 //    - takeUnchecked: Subtracts the bits used to represent the register in the
 //      register set.
 //
 //    - addUnchecked: Adds the bits used to represent the register in the
 //      register set.
 
@@ -568,25 +574,35 @@ class AllocatableSetAccessors
   public:
     typedef Set RegSet;
     typedef typename RegSet::RegType RegType;
     typedef typename RegSet::SetType SetType;
 
   protected:
     RegSet set_;
 
+    template <RegTypeName Name>
+    SetType all() const {
+        return set_.template allAllocatable<Name>();
+    }
+
   public:
     AllocatableSetAccessors() : set_() {}
     explicit constexpr AllocatableSetAccessors(SetType set) : set_(set) {}
     explicit constexpr AllocatableSetAccessors(RegSet set) : set_(set) {}
 
     bool has(RegType reg) const {
         return set_.hasAllocatable(reg);
     }
 
+    template <RegTypeName Name>
+    bool hasAny(RegType reg) const {
+        return all<Name>() != 0;
+    }
+
     void addUnchecked(RegType reg) {
         set_.addAllocatable(reg);
     }
 
     void takeUnchecked(RegType reg) {
         set_.takeAllocatable(reg);
     }
 };
@@ -598,16 +614,25 @@ class AllocatableSetAccessors<RegisterSe
   public:
     typedef RegisterSet RegSet;
     typedef AnyRegister RegType;
     typedef char SetType;
 
   protected:
     RegisterSet set_;
 
+    template <RegTypeName Name>
+    GeneralRegisterSet::SetType allGpr() const {
+        return set_.gprs().allAllocatable<Name>();
+    }
+    template <RegTypeName Name>
+    FloatRegisterSet::SetType allFpu() const {
+        return set_.fpus().allAllocatable<Name>();
+    }
+
   public:
     AllocatableSetAccessors() : set_() {}
     explicit constexpr AllocatableSetAccessors(SetType) = delete;
     explicit constexpr AllocatableSetAccessors(RegisterSet set) : set_(set) {}
 
     bool has(Register reg) const {
         return set_.gprs().hasAllocatable(reg);
     }
@@ -650,16 +675,21 @@ class LiveSetAccessors
   public:
     typedef Set RegSet;
     typedef typename RegSet::RegType RegType;
     typedef typename RegSet::SetType SetType;
 
   protected:
     RegSet set_;
 
+    template <RegTypeName Name>
+    SetType all() const {
+        return set_.template allLive<Name>();
+    }
+
   public:
     LiveSetAccessors() : set_() {}
     explicit constexpr LiveSetAccessors(SetType set) : set_(set) {}
     explicit constexpr LiveSetAccessors(RegSet set) : set_(set) {}
 
     bool has(RegType reg) const {
         return set_.hasRegisterIndex(reg);
     }
@@ -680,16 +710,25 @@ class LiveSetAccessors<RegisterSet>
   public:
     typedef RegisterSet RegSet;
     typedef AnyRegister RegType;
     typedef char SetType;
 
   protected:
     RegisterSet set_;
 
+    template <RegTypeName Name>
+    GeneralRegisterSet::SetType allGpr() const {
+        return set_.gprs().allLive<Name>();
+    }
+    template <RegTypeName Name>
+    FloatRegisterSet::SetType allFpu() const {
+        return set_.fpus().allLive<Name>();
+    }
+
   public:
     LiveSetAccessors() : set_() {}
     explicit constexpr LiveSetAccessors(SetType) = delete;
     explicit constexpr LiveSetAccessors(RegisterSet set) : set_(set) {}
 
     bool has(Register reg) const {
         return set_.gprs().hasRegisterIndex(reg);
     }
@@ -746,72 +785,94 @@ class SpecializedRegSet : public Accesso
     }
 
     using Parent::takeUnchecked;
     void take(RegType reg) {
         MOZ_ASSERT(has(reg));
         takeUnchecked(reg);
     }
 
-    RegType getAny() const {
-        return this->Parent::set_.getAny();
-    }
-    RegType getFirst() const {
-        return this->Parent::set_.getFirst();
-    }
-    RegType getLast() const {
-        return this->Parent::set_.getLast();
+    template <RegTypeName Name>
+    bool hasAny() const {
+        return Parent::template all<Name>() != 0;
     }
 
+    template <RegTypeName Name = RegSet::DefaultType>
+    RegType getFirst() const {
+        SetType set = Parent::template all<Name>();
+        MOZ_ASSERT(set);
+        return RegSet::FirstRegister(set);
+    }
+    template <RegTypeName Name = RegSet::DefaultType>
+    RegType getLast() const {
+        SetType set = Parent::template all<Name>();
+        MOZ_ASSERT(set);
+        return RegSet::LastRegister(set);
+    }
+    template <RegTypeName Name = RegSet::DefaultType>
+    RegType getAny() const {
+        // The choice of first or last here is mostly arbitrary, as they are
+        // about the same speed on popular architectures. We choose first, as
+        // it has the advantage of using the "lower" registers more often. These
+        // registers are sometimes more efficient (e.g. optimized encodings for
+        // EAX on x86).
+        return getFirst<Name>();
+    }
+
+    template <RegTypeName Name = RegSet::DefaultType>
     RegType getAnyExcluding(RegType preclude) {
         if (!has(preclude))
-            return getAny();
+            return getAny<Name>();
 
         take(preclude);
-        RegType result = getAny();
+        RegType result = getAny<Name>();
         add(preclude);
         return result;
     }
 
+    template <RegTypeName Name = RegSet::DefaultType>
     RegType takeAny() {
-        RegType reg = getAny();
+        RegType reg = getAny<Name>();
         take(reg);
         return reg;
     }
+    template <RegTypeName Name = RegSet::DefaultType>
     RegType takeFirst() {
-        RegType reg = getFirst();
+        RegType reg = getFirst<Name>();
         take(reg);
         return reg;
     }
+    template <RegTypeName Name = RegSet::DefaultType>
     RegType takeLast() {
-        RegType reg = getLast();
+        RegType reg = getLast<Name>();
         take(reg);
         return reg;
     }
 
     ValueOperand takeAnyValue() {
 #if defined(JS_NUNBOX32)
-        return ValueOperand(takeAny(), takeAny());
+        return ValueOperand(takeAny<RegTypeName::GPR>(), takeAny<RegTypeName::GPR>());
 #elif defined(JS_PUNBOX64)
-        return ValueOperand(takeAny());
+        return ValueOperand(takeAny<RegTypeName::GPR>());
 #else
 #error "Bad architecture"
 #endif
     }
 
     bool aliases(ValueOperand v) const {
 #ifdef JS_NUNBOX32
         return has(v.typeReg()) || has(v.payloadReg());
 #else
         return has(v.valueReg());
 #endif
     }
 
+    template <RegTypeName Name = RegSet::DefaultType>
     RegType takeAnyExcluding(RegType preclude) {
-        RegType reg = getAnyExcluding(preclude);
+        RegType reg = getAnyExcluding<Name>(preclude);
         take(reg);
         return reg;
     }
 };
 
 // Specialization of the accessors for the RegisterSet aggregate.
 template <class Accessors>
 class SpecializedRegSet<Accessors, RegisterSet> : public Accessors
@@ -836,22 +897,27 @@ class SpecializedRegSet<Accessors, Regis
 
     bool emptyGeneral() const {
         return this->Parent::set_.emptyGeneral();
     }
     bool emptyFloat() const {
         return this->Parent::set_.emptyFloat();
     }
 
-
     using Parent::has;
     bool has(AnyRegister reg) const {
         return reg.isFloat() ? has(reg.fpu()) : has(reg.gpr());
     }
 
+    template <RegTypeName Name>
+    bool hasAny() const {
+        if (Name == RegTypeName::GPR)
+            return Parent::template allGpr<RegTypeName::GPR>() != 0;
+        return Parent::template allFpu<Name>() != 0;
+    }
 
     using Parent::addUnchecked;
     void addUnchecked(AnyRegister reg) {
         if (reg.isFloat())
             addUnchecked(reg.fpu());
         else
             addUnchecked(reg.gpr());
     }
@@ -890,29 +956,35 @@ class SpecializedRegSet<Accessors, Regis
     void take(AnyRegister reg) {
         if (reg.isFloat())
             take(reg.fpu());
         else
             take(reg.gpr());
     }
 
     Register getAnyGeneral() const {
-        return this->Parent::set_.gprs().getAny();
+        GeneralRegisterSet::SetType set = Parent::template allGpr<RegTypeName::GPR>();
+        MOZ_ASSERT(set);
+        return GeneralRegisterSet::FirstRegister(set);
     }
+    template <RegTypeName Name = RegTypeName::Float64>
     FloatRegister getAnyFloat() const {
-        return this->Parent::set_.fpus().getAny();
+        FloatRegisterSet::SetType set = Parent::template allFpu<Name>();
+        MOZ_ASSERT(set);
+        return FloatRegisterSet::FirstRegister(set);
     }
 
     Register takeAnyGeneral() {
         Register reg = getAnyGeneral();
         take(reg);
         return reg;
     }
+    template <RegTypeName Name = RegTypeName::Float64>
     FloatRegister takeAnyFloat() {
-        FloatRegister reg = getAnyFloat();
+        FloatRegister reg = getAnyFloat<Name>();
         take(reg);
         return reg;
     }
     ValueOperand takeAnyValue() {
 #if defined(JS_NUNBOX32)
         return ValueOperand(takeAnyGeneral(), takeAnyGeneral());
 #elif defined(JS_PUNBOX64)
         return ValueOperand(takeAnyGeneral());
@@ -1100,21 +1172,21 @@ class TypedRegisterIterator
     { }
     TypedRegisterIterator(const TypedRegisterIterator& other) : regset_(other.regset_)
     { }
 
     bool more() const {
         return !regset_.empty();
     }
     TypedRegisterIterator<T>& operator ++() {
-        regset_.takeAny();
+        regset_.template takeAny<RegTypeName::Any>();
         return *this;
     }
     T operator*() const {
-        return regset_.getAny();
+        return regset_.template getAny<RegTypeName::Any>();
     }
 };
 
 // iterates backwards, that is, rn to r0
 template <typename T>
 class TypedRegisterBackwardIterator
 {
     LiveSet<TypedRegisterSet<T>> regset_;
@@ -1127,21 +1199,21 @@ class TypedRegisterBackwardIterator
     TypedRegisterBackwardIterator(const TypedRegisterBackwardIterator& other)
       : regset_(other.regset_)
     { }
 
     bool more() const {
         return !regset_.empty();
     }
     TypedRegisterBackwardIterator<T>& operator ++() {
-        regset_.takeLast();
+        regset_.template takeLast<RegTypeName::Any>();
         return *this;
     }
     T operator*() const {
-        return regset_.getLast();
+        return regset_.template getLast<RegTypeName::Any>();
     }
 };
 
 // iterates forwards, that is r0 to rn
 template <typename T>
 class TypedRegisterForwardIterator
 {
     LiveSet<TypedRegisterSet<T>> regset_;
@@ -1153,21 +1225,21 @@ class TypedRegisterForwardIterator
     { }
     TypedRegisterForwardIterator(const TypedRegisterForwardIterator& other) : regset_(other.regset_)
     { }
 
     bool more() const {
         return !regset_.empty();
     }
     TypedRegisterForwardIterator<T>& operator ++() {
-        regset_.takeFirst();
+        regset_.template takeFirst<RegTypeName::Any>();
         return *this;
     }
     T operator*() const {
-        return regset_.getFirst();
+        return regset_.template getFirst<RegTypeName::Any>();
     }
 };
 
 typedef TypedRegisterIterator<Register> GeneralRegisterIterator;
 typedef TypedRegisterIterator<FloatRegister> FloatRegisterIterator;
 typedef TypedRegisterBackwardIterator<Register> GeneralRegisterBackwardIterator;
 typedef TypedRegisterBackwardIterator<FloatRegister> FloatRegisterBackwardIterator;
 typedef TypedRegisterForwardIterator<Register> GeneralRegisterForwardIterator;
--- a/js/src/jit/Registers.h
+++ b/js/src/jit/Registers.h
@@ -83,27 +83,58 @@ struct Register {
         MOZ_ASSERT(aliasIdx == 0);
         *ret = *this;
     }
 
     SetType alignedOrDominatedAliasedSet() const {
         return SetType(1) << code();
     }
 
+    static constexpr RegTypeName DefaultType = RegTypeName::GPR;
+
+    template <RegTypeName = DefaultType>
+    static SetType LiveAsIndexableSet(SetType s) {
+        return SetType(0);
+    }
+
+    template <RegTypeName Name = DefaultType>
+    static SetType AllocatableAsIndexableSet(SetType s) {
+        static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable");
+        return SetType(0);
+    }
+
     static uint32_t SetSize(SetType x) {
         return Codes::SetSize(x);
     }
     static uint32_t FirstBit(SetType x) {
         return Codes::FirstBit(x);
     }
     static uint32_t LastBit(SetType x) {
         return Codes::LastBit(x);
     }
 };
 
+template <> inline Register::SetType
+Register::LiveAsIndexableSet<RegTypeName::GPR>(SetType set)
+{
+    return set;
+}
+
+template <> inline Register::SetType
+Register::LiveAsIndexableSet<RegTypeName::Any>(SetType set)
+{
+    return set;
+}
+
+template <> inline Register::SetType
+Register::AllocatableAsIndexableSet<RegTypeName::GPR>(SetType set)
+{
+    return set;
+}
+
 #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
--- a/js/src/jit/StupidAllocator.cpp
+++ b/js/src/jit/StupidAllocator.cpp
@@ -76,17 +76,18 @@ StupidAllocator::init()
     // Assign physical registers to the tracked allocation.
     {
         registerCount = 0;
         LiveRegisterSet remainingRegisters(allRegisters_.asLiveSet());
         while (!remainingRegisters.emptyGeneral())
             registers[registerCount++].reg = AnyRegister(remainingRegisters.takeAnyGeneral());
 
         while (!remainingRegisters.emptyFloat())
-            registers[registerCount++].reg = AnyRegister(remainingRegisters.takeAnyFloat());
+            registers[registerCount++].reg =
+                AnyRegister(remainingRegisters.takeAnyFloat<RegTypeName::Any>());
 
         MOZ_ASSERT(registerCount <= MAX_REGISTERS);
     }
 
     return true;
 }
 
 bool
--- a/js/src/jit/arm/Architecture-arm.h
+++ b/js/src/jit/arm/Architecture-arm.h
@@ -7,16 +7,18 @@
 #ifndef jit_arm_Architecture_arm_h
 #define jit_arm_Architecture_arm_h
 
 #include "mozilla/MathAlgorithms.h"
 
 #include <limits.h>
 #include <stdint.h>
 
+#include "jit/shared/Architecture-shared.h"
+
 #include "js/Utility.h"
 
 // GCC versions 4.6 and above define __ARM_PCS_VFP to denote a hard-float
 // ABI target. The iOS toolchain doesn't define anything specific here,
 // but iOS always supports VFP.
 #if defined(__ARM_PCS_VFP) || defined(XP_IOS)
 #define JS_CODEGEN_ARM_HARDFP
 #endif
@@ -280,16 +282,47 @@ class FloatRegisters
     static const uint32_t Total = 48;
     static const uint32_t TotalDouble = 16;
     static const uint32_t TotalSingle = 32;
     static const uint32_t Allocatable = 45;
     // There are only 32 places that we can put values.
     static const uint32_t TotalPhys = 32;
     static uint32_t ActualTotalPhys();
 
+    // ARM float registers overlap in a way that for 1 double registers, in the
+    // range d0-d15, we have 2 singles register in the range s0-s31. d16-d31
+    // have no single register aliases.  The aliasing rule state that d{n}
+    // aliases s{2n} and s{2n+1}, for n in [0 .. 15].
+    //
+    // The register set is used to represent either allocatable register or live
+    // registers. The register maps d0-d15 and s0-s31 to a single bit each. The
+    // registers d16-d31 are not used at the moment.
+    //
+    // uuuu uuuu uuuu uuuu dddd dddd dddd dddd ssss ssss ssss ssss ssss ssss ssss ssss
+    //                     ^                 ^ ^                                     ^
+    //                     '-- d15      d0 --' '-- s31                          s0 --'
+    //
+    // LiveSet are handled by adding the bit of each register without
+    // considering the aliases.
+    //
+    // AllocatableSet are handled by adding and removing the bit of each
+    // aligned-or-dominated-aliased registers.
+    //
+    //     ...0...00... : s{2n}, s{2n+1} and d{n} are not available
+    //     ...1...01... : s{2n} is available (*)
+    //     ...0...10... : s{2n+1} is available
+    //     ...1...11... : s{2n}, s{2n+1} and d{n} are available
+    //
+    // (*) Note that d{n} bit is set, but is not available because s{2n+1} bit
+    // is not set, which is required as d{n} dominates s{2n+1}. The d{n} bit is
+    // set, because s{2n} is aligned.
+    //
+    //        |        d{n}       |
+    //        | s{2n+1} |  s{2n}  |
+    //
     typedef uint64_t SetType;
     static const SetType AllSingleMask = (1ull << TotalSingle) - 1;
     static const SetType AllDoubleMask = ((1ull << TotalDouble) - 1) << TotalSingle;
     static const SetType AllMask = AllDoubleMask | AllSingleMask;
 
     // d15 is the ScratchFloatReg.
     static const SetType NonVolatileDoubleMask =
          ((1ULL << d8) |
@@ -352,30 +385,27 @@ class VFPRegister
     };
 
     typedef FloatRegisters Codes;
     typedef Codes::Code Code;
     typedef Codes::Encoding Encoding;
 
   protected:
     RegType kind : 2;
-    // ARM doesn't have more than 32 registers. Don't take more bits than we'll
-    // need. Presently, we don't have plans to address the upper and lower
-    // halves of the double registers seprately, so 5 bits should suffice. If we
-    // do decide to address them seprately (vmov, I'm looking at you), we will
-    // likely specify it as a separate field.
   public:
+    // ARM doesn't have more than 32 registers of each type, so 5 bits should
+    // suffice.
     uint32_t code_ : 5;
   protected:
     bool _isInvalid : 1;
     bool _isMissing : 1;
 
   public:
     constexpr VFPRegister(uint32_t r, RegType k)
-      : kind(k), code_ (Code(r)), _isInvalid(false), _isMissing(false)
+      : kind(k), code_(Code(r)), _isInvalid(false), _isMissing(false)
     { }
     constexpr VFPRegister()
       : kind(Double), code_(Code(0)), _isInvalid(true), _isMissing(false)
     { }
 
     constexpr VFPRegister(RegType k, uint32_t id, bool invalid, bool missing) :
         kind(k), code_(Code(id)), _isInvalid(invalid), _isMissing(missing) {
     }
@@ -528,17 +558,17 @@ class VFPRegister
     // This function is used to ensure that Register set can take all Single
     // registers, even if we are taking a mix of either double or single
     // registers.
     //
     //   s0.alignedOrDominatedAliasedSet() == s0 | d0.
     //   s1.alignedOrDominatedAliasedSet() == s1.
     //   d0.alignedOrDominatedAliasedSet() == s0 | s1 | d0.
     //
-    // This way the Allocator register set does not have to do any arithmetics
+    // This way the Allocatable register set does not have to do any arithmetics
     // to know if a register is available or not, as we have the following
     // relations:
     //
     //   d0.alignedOrDominatedAliasedSet() ==
     //       s0.alignedOrDominatedAliasedSet() | s1.alignedOrDominatedAliasedSet()
     //
     //   s0.alignedOrDominatedAliasedSet() & s1.alignedOrDominatedAliasedSet() == 0
     //
@@ -548,16 +578,29 @@ class VFPRegister
                 return SetType(1) << code_;
             return (SetType(1) << code_) | (SetType(1) << (32 + code_ / 2));
         }
 
         MOZ_ASSERT(isDouble());
         return (SetType(0b11) << (code_ * 2)) | (SetType(1) << (32 + code_));
     }
 
+    static constexpr RegTypeName DefaultType = RegTypeName::Float64;
+
+    template <RegTypeName = DefaultType>
+    static SetType LiveAsIndexableSet(SetType s) {
+        return SetType(0);
+    }
+
+    template <RegTypeName Name = DefaultType>
+    static SetType AllocatableAsIndexableSet(SetType s) {
+        static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable");
+        return SetType(0);
+    }
+
     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<VFPRegister> ReduceSetForPush(const TypedRegisterSet<VFPRegister>& s);
@@ -567,16 +610,89 @@ class VFPRegister
         return mozilla::CountTrailingZeroes64(x);
     }
     static uint32_t LastBit(SetType x) {
         return 63 - mozilla::CountLeadingZeroes64(x);
     }
 
 };
 
+template <> inline VFPRegister::SetType
+VFPRegister::LiveAsIndexableSet<RegTypeName::Float32>(SetType set)
+{
+    return set & FloatRegisters::AllSingleMask;
+}
+
+template <> inline VFPRegister::SetType
+VFPRegister::LiveAsIndexableSet<RegTypeName::Float64>(SetType set)
+{
+    return set & FloatRegisters::AllDoubleMask;
+}
+
+template <> inline VFPRegister::SetType
+VFPRegister::LiveAsIndexableSet<RegTypeName::Any>(SetType set)
+{
+    return set;
+}
+
+template <> inline VFPRegister::SetType
+VFPRegister::AllocatableAsIndexableSet<RegTypeName::Float32>(SetType set)
+{
+    // Single registers are not dominating any smaller registers, thus masking
+    // is enough to convert an allocatable set into a set of register list all
+    // single register available.
+    return set & FloatRegisters::AllSingleMask;
+}
+
+template <> inline VFPRegister::SetType
+VFPRegister::AllocatableAsIndexableSet<RegTypeName::Float64>(SetType set)
+{
+    // An allocatable float register set is represented as follow:
+    //
+    // uuuu uuuu uuuu uuuu dddd dddd dddd dddd ssss ssss ssss ssss ssss ssss ssss ssss
+    //                     ^                 ^ ^                                     ^
+    //                     '-- d15      d0 --' '-- s31                          s0 --'
+    //
+    //     ...0...00... : s{2n}, s{2n+1} and d{n} are not available
+    //     ...1...01... : s{2n} is available
+    //     ...0...10... : s{2n+1} is available
+    //     ...1...11... : s{2n}, s{2n+1} and d{n} are available
+    //
+    // The goal of this function is to return the set of double registers which
+    // are available as an indexable bit set. This implies that iff a double bit
+    // is set in the returned set, then the register is available.
+    //
+    // To do so, this functions converts the 32 bits set of single registers
+    // into a 16 bits set of equivalent double registers. Then, we mask out
+    // double registers which do not have all the single register that compose
+    // them. As d{n} bit is set when s{2n} is available, we only need to take
+    // s{2n+1} into account.
+
+    // Convert  s7s6s5s4 s3s2s1s0  into  s7s5s3s1, for all s0-s31.
+    SetType s2d = AllocatableAsIndexableSet<RegTypeName::Float32>(set);
+    static_assert(FloatRegisters::TotalSingle == 32, "Wrong mask");
+    s2d = (0xaaaaaaaa & s2d) >> 1; // Filter s{2n+1} registers.
+    // Group adjacent bits as follow:
+    //     0.0.s3.s1 == ((0.s3.0.s1) >> 1 | (0.s3.0.s1)) & 0b0011;
+    s2d = ((s2d >> 1) | s2d) & 0x33333333; // 0a0b --> 00ab
+    s2d = ((s2d >> 2) | s2d) & 0x0f0f0f0f; // 00ab00cd --> 0000abcd
+    s2d = ((s2d >> 4) | s2d) & 0x00ff00ff;
+    s2d = ((s2d >> 8) | s2d) & 0x0000ffff;
+    // Move the s7s5s3s1 to the aliased double positions.
+    s2d = s2d << FloatRegisters::TotalSingle;
+
+    // Note: We currently do not use any representation for d16-d31.
+    static_assert(FloatRegisters::TotalDouble == 16,
+        "d16-d31 do not have a single register mapping");
+
+    // Filter out any double register which are not allocatable due to
+    // non-aligned dominated single registers.
+    return set & s2d;
+}
+
 // The only floating point register set that we work with are the VFP Registers.
 typedef VFPRegister FloatRegister;
 
 uint32_t GetARMFlags();
 bool HasARMv7();
 bool HasMOVWT();
 bool HasLDSTREXBHD();           // {LD,ST}REX{B,H,D}
 bool HasDMBDSBISB();            // DMB, DSB, and ISB
--- a/js/src/jit/arm64/Architecture-arm64.h
+++ b/js/src/jit/arm64/Architecture-arm64.h
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_arm64_Architecture_arm64_h
 #define jit_arm64_Architecture_arm64_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/MathAlgorithms.h"
 
+#include "jit/shared/Architecture-shared.h"
+
 #include "js/Utility.h"
 
 namespace js {
 namespace jit {
 
 // AArch64 has 32 64-bit integer registers, x0 though x31.
 //  x31 is special and functions as both the stack pointer and a zero register.
 //  The bottom 32 bits of each of the X registers is accessible as w0 through w31.
@@ -264,18 +266,18 @@ class FloatRegisters
                 (1 << FloatRegisters::d20) | (1 << FloatRegisters::d21) |
                 (1 << FloatRegisters::d22) | (1 << FloatRegisters::d23) |
                 (1 << FloatRegisters::d24) | (1 << FloatRegisters::d25) |
                 (1 << FloatRegisters::d26) | (1 << FloatRegisters::d27) |
                 (1 << FloatRegisters::d28) | (1 << FloatRegisters::d29) |
                 (1 << FloatRegisters::d30)) * SpreadCoefficient;
 
     static const SetType VolatileMask = AllMask & ~NonVolatileMask;
-    static const SetType AllDoubleMask = AllMask;
-    static const SetType AllSingleMask = AllMask;
+    static const SetType AllDoubleMask = AllPhysMask << TotalPhys;
+    static const SetType AllSingleMask = AllPhysMask;
 
     static const SetType WrapperMask = VolatileMask;
 
     // d31 is the ScratchFloatReg.
     static const SetType NonAllocatableMask = (SetType(1) << FloatRegisters::d31) * SpreadCoefficient;
 
     // Registers that can be allocated without being saved, generally.
     static const SetType TempMask = VolatileMask & ~NonAllocatableMask;
@@ -399,17 +401,17 @@ struct FloatRegister
     }
     constexpr uint32_t size() const {
         return k_ == FloatRegisters::Double ? sizeof(double) : sizeof(float);
     }
     uint32_t numAlignedAliased() {
         return numAliased();
     }
     void alignedAliased(uint32_t aliasIdx, FloatRegister* ret) {
-        MOZ_ASSERT(aliasIdx == 0);
+        MOZ_ASSERT(aliasIdx < numAliased());
         aliased(aliasIdx, ret);
     }
     SetType alignedOrDominatedAliasedSet() const {
         return Codes::SpreadCoefficient << code_;
     }
 
     bool isSingle() const {
         return k_ == FloatRegisters::Single;
@@ -425,26 +427,57 @@ struct FloatRegister
         JS_STATIC_ASSERT(sizeof(SetType) == 8);
         return mozilla::CountTrailingZeroes64(x);
     }
     static uint32_t LastBit(SetType x) {
         JS_STATIC_ASSERT(sizeof(SetType) == 8);
         return 63 - mozilla::CountLeadingZeroes64(x);
     }
 
+    static constexpr RegTypeName DefaultType = RegTypeName::Float64;
+
+    template <RegTypeName Name = DefaultType>
+    static SetType LiveAsIndexableSet(SetType s) {
+        return SetType(0);
+    }
+
+    template <RegTypeName Name = DefaultType>
+    static SetType AllocatableAsIndexableSet(SetType s) {
+        static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable");
+        return LiveAsIndexableSet<Name>(s);
+    }
+
     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();
 
   public:
     Code code_ : 8;
     FloatRegisters::Kind k_ : 1;
 };
 
+template <> inline FloatRegister::SetType
+FloatRegister::LiveAsIndexableSet<RegTypeName::Float32>(SetType set)
+{
+    return set & FloatRegisters::AllSingleMask;
+}
+
+template <> inline FloatRegister::SetType
+FloatRegister::LiveAsIndexableSet<RegTypeName::Float64>(SetType set)
+{
+    return set & FloatRegisters::AllDoubleMask;
+}
+
+template <> inline FloatRegister::SetType
+FloatRegister::LiveAsIndexableSet<RegTypeName::Any>(SetType set)
+{
+    return set;
+}
+
 // ARM/D32 has double registers that cannot be treated as float32.
 // Luckily, ARMv8 doesn't have the same misfortune.
 inline bool
 hasUnaliasedDouble()
 {
     return false;
 }
 
--- a/js/src/jit/mips-shared/Architecture-mips-shared.h
+++ b/js/src/jit/mips-shared/Architecture-mips-shared.h
@@ -7,16 +7,18 @@
 #ifndef jit_mips_shared_Architecture_mips_shared_h
 #define jit_mips_shared_Architecture_mips_shared_h
 
 #include "mozilla/MathAlgorithms.h"
 
 #include <limits.h>
 #include <stdint.h>
 
+#include "jit/shared/Architecture-shared.h"
+
 #include "js/Utility.h"
 
 // gcc appears to use _mips_hard_float to denote
 // that the target is a hard-float target.
 #ifdef _mips_hard_float
 #define JS_CODEGEN_MIPS_HARDFP
 #endif
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit/shared/Architecture-shared.h
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_shared_Architecture_shared_h
+#define jit_shared_Architecture_shared_h
+
+namespace js {
+namespace jit {
+
+enum class RegTypeName {
+    GPR,
+    Float32,
+    Float64,
+    Vector128,
+    Any
+};
+
+} // namespace jit
+} // namespace js
+
+#endif /* jit_shared_Architecture_shared_h */
--- a/js/src/jit/x86-shared/Architecture-x86-shared.h
+++ b/js/src/jit/x86-shared/Architecture-x86-shared.h
@@ -10,16 +10,18 @@
 #if !defined(JS_CODEGEN_X86) && !defined(JS_CODEGEN_X64)
 # error "Unsupported architecture!"
 #endif
 
 #include "mozilla/MathAlgorithms.h"
 
 #include <string.h>
 
+#include "jit/shared/Architecture-shared.h"
+
 #include "jit/x86-shared/Constants-x86-shared.h"
 
 namespace js {
 namespace jit {
 
 // Does this architecture support SIMD conversions between Uint32x4 and Float32x4?
 static constexpr bool SupportsUint32x4FloatConversions = false;
 
@@ -257,16 +259,17 @@ class FloatRegisters {
     static const SetType SpreadScalar = SpreadSingle | SpreadDouble;
     static const SetType SpreadVector = SpreadSimd128;
     static const SetType Spread = SpreadScalar | SpreadVector;
 
     static const SetType AllPhysMask = ((1 << TotalPhys) - 1);
     static const SetType AllMask = AllPhysMask * Spread;
     static const SetType AllDoubleMask = AllPhysMask * SpreadDouble;
     static const SetType AllSingleMask = AllPhysMask * SpreadSingle;
+    static const SetType AllVector128Mask = AllPhysMask * SpreadSimd128;
 
 #if defined(JS_CODEGEN_X86)
     static const SetType NonAllocatableMask =
         Spread * (1 << X86Encoding::xmm7);     // This is ScratchDoubleReg.
 
 #elif defined(JS_CODEGEN_X64)
     static const SetType NonAllocatableMask =
         Spread * (1 << X86Encoding::xmm15);    // This is ScratchDoubleReg.
@@ -431,21 +434,58 @@ struct FloatRegister {
     void alignedAliased(uint32_t aliasIdx, FloatRegister* ret) const {
         aliased(aliasIdx, ret);
     }
 
     SetType alignedOrDominatedAliasedSet() const {
         return Codes::Spread << reg_;
     }
 
+    static constexpr RegTypeName DefaultType = RegTypeName::Float64;
+
+    template <RegTypeName = DefaultType>
+    static SetType LiveAsIndexableSet(SetType s) {
+        return SetType(0);
+    }
+
+    template <RegTypeName Name = DefaultType>
+    static SetType AllocatableAsIndexableSet(SetType s) {
+        static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable");
+        return LiveAsIndexableSet<Name>(s);
+    }
+
     static TypedRegisterSet<FloatRegister> ReduceSetForPush(const TypedRegisterSet<FloatRegister>& s);
     static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
     uint32_t getRegisterDumpOffsetInBytes();
 };
 
+template <> inline FloatRegister::SetType
+FloatRegister::LiveAsIndexableSet<RegTypeName::Float32>(SetType set)
+{
+    return set & FloatRegisters::AllSingleMask;
+}
+
+template <> inline FloatRegister::SetType
+FloatRegister::LiveAsIndexableSet<RegTypeName::Float64>(SetType set)
+{
+    return set & FloatRegisters::AllDoubleMask;
+}
+
+template <> inline FloatRegister::SetType
+FloatRegister::LiveAsIndexableSet<RegTypeName::Vector128>(SetType set)
+{
+    return set & FloatRegisters::AllVector128Mask;
+}
+
+template <> inline FloatRegister::SetType
+FloatRegister::LiveAsIndexableSet<RegTypeName::Any>(SetType set)
+{
+    return set;
+}
+
 // Arm/D32 has double registers that can NOT be treated as float32
 // and this requires some dances in lowering.
 inline bool
 hasUnaliasedDouble()
 {
     return false;
 }
 
--- a/js/src/jsapi-tests/testJitRegisterSet.cpp
+++ b/js/src/jsapi-tests/testJitRegisterSet.cpp
@@ -30,16 +30,22 @@ CoPrime(size_t a, size_t b)
             continue;                                       \
         for (size_t start = 0; start < RegTotal; start++) { \
             size_t index = start;
 
 #define END_INDEX_WALK                                      \
         }                                                   \
     }
 
+#define BEGIN_All_WALK(RegTotal)                            \
+    static const size_t Total = RegTotal;                   \
+    size_t walk = 1;                                        \
+    size_t start = 0;                                       \
+    size_t index = start;
+
 #define FOR_ALL_REGISTERS(Register, reg)            \
     do {                                            \
         Register reg = Register::FromCode(index);
 
 #define END_FOR_ALL_REGISTERS                    \
         index = (index + walk) % Total;          \
     } while(index != start)
 
@@ -131,8 +137,75 @@ BEGIN_TEST(testJitRegisterSet_FPU)
 
     CHECK(liveRegs.empty());
     CHECK(pool.set() == FloatRegisterSet::All());
 
     END_INDEX_WALK
     return true;
 }
 END_TEST(testJitRegisterSet_FPU)
+
+void pullAllFpus(AllocatableFloatRegisterSet& set, uint32_t& max_bits, uint32_t bits) {
+    FloatRegisterSet allocSet(set.bits());
+    FloatRegisterSet available_f32(allocSet.allAllocatable<RegTypeName::Float32>());
+    FloatRegisterSet available_f64(allocSet.allAllocatable<RegTypeName::Float64>());
+    FloatRegisterSet available_v128(allocSet.allAllocatable<RegTypeName::Vector128>());
+    for (FloatRegisterIterator it(available_f32); it.more(); ++it) {
+        FloatRegister tmp = *it;
+        set.take(tmp);
+        pullAllFpus(set, max_bits, bits + 32);
+        set.add(tmp);
+    }
+    for (FloatRegisterIterator it(available_f64); it.more(); ++it) {
+        FloatRegister tmp = *it;
+        set.take(tmp);
+        pullAllFpus(set, max_bits, bits + 64);
+        set.add(tmp);
+    }
+    for (FloatRegisterIterator it(available_v128); it.more(); ++it) {
+        FloatRegister tmp = *it;
+        set.take(tmp);
+        pullAllFpus(set, max_bits, bits + 128);
+        set.add(tmp);
+    }
+    if (bits >= max_bits)
+        max_bits = bits;
+}
+
+BEGIN_TEST(testJitRegisterSet_FPU_Aliases)
+{
+    BEGIN_All_WALK(FloatRegisters::Total);
+    FOR_ALL_REGISTERS(FloatRegister, reg) {
+        AllocatableFloatRegisterSet pool;
+        pool.add(reg);
+
+        uint32_t alias_bits = 0;
+        for (uint32_t i = 0; i < reg.numAlignedAliased(); i++) {
+            FloatRegister alias;
+            reg.alignedAliased(i, &alias);
+
+            if (alias.isSingle()) {
+                if (alias_bits <= 32)
+                    alias_bits = 32;
+            } else if (alias.isDouble()) {
+                if (alias_bits <= 64)
+                    alias_bits = 64;
+            } else if (alias.isSimd128()) {
+                if (alias_bits <= 128)
+                    alias_bits = 128;
+            }
+        }
+
+        uint32_t max_bits = 0;
+        pullAllFpus(pool, max_bits, 0);
+
+        // By adding one register, we expect that we should not be able to pull
+        // more than any of its aligned aliases.  This rule should hold for both
+        // x64 and ARM.
+        CHECK(max_bits <= alias_bits);
+
+        // We added one register, we expect to be able to pull it back.
+        CHECK(max_bits > 0);
+    } END_FOR_ALL_REGISTERS;
+
+    return true;
+}
+END_TEST(testJitRegisterSet_FPU_Aliases)
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -201,16 +201,28 @@ static const Register FuncPtrCallTemp = 
 // worth it yet.  CallTempReg2 seems safe.
 static const Register ScratchRegARM = CallTempReg2;
 
 # define INT_DIV_I64_CALLOUT
 # define I64_TO_FLOAT_CALLOUT
 # define FLOAT_TO_I64_CALLOUT
 #endif
 
+template<MIRType t>
+struct RegTypeOf {
+    static_assert(t == MIRType::Float32 || t == MIRType::Double, "Float mask type");
+};
+
+template<> struct RegTypeOf<MIRType::Float32> {
+    static constexpr RegTypeName value = RegTypeName::Float32;
+};
+template<> struct RegTypeOf<MIRType::Double> {
+    static constexpr RegTypeName value = RegTypeName::Float64;
+};
+
 class BaseCompiler
 {
     // We define our own ScratchRegister abstractions, deferring to
     // the platform's when possible.
 
 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
     typedef ScratchDoubleScope ScratchF64;
 #else
@@ -786,45 +798,32 @@ class BaseCompiler
     // ScratchFloat32Register is the same as ScratchDoubleRegister.
     //
     // It's a basic invariant of the AllocatableRegisterSet that it
     // deals properly with aliasing of registers: if s0 or s1 are
     // allocated then d0 is not allocatable; if s0 and s1 are freed
     // individually then d0 becomes allocatable.
 
     template<MIRType t>
-    FloatRegisters::SetType maskFromTypeFPU() {
-        static_assert(t == MIRType::Float32 || t == MIRType::Double, "Float mask type");
-        if (t == MIRType::Float32)
-            return FloatRegisters::AllSingleMask;
-        return FloatRegisters::AllDoubleMask;
-    }
-
-    template<MIRType t>
     bool hasFPU() {
-        return !!(availFPU_.bits() & maskFromTypeFPU<t>());
+        return availFPU_.hasAny<RegTypeOf<t>::value>();
     }
 
     bool isAvailable(FloatRegister r) {
         return availFPU_.has(r);
     }
 
     void allocFPU(FloatRegister r) {
         MOZ_ASSERT(isAvailable(r));
         availFPU_.take(r);
     }
 
     template<MIRType t>
     FloatRegister allocFPU() {
-        MOZ_ASSERT(hasFPU<t>());
-        FloatRegister r =
-            FloatRegisterSet::Intersect(FloatRegisterSet(availFPU_.bits()),
-                                        FloatRegisterSet(maskFromTypeFPU<t>())).getAny();
-        availFPU_.take(r);
-        return r;
+        return availFPU_.takeAny<RegTypeOf<t>::value>();
     }
 
     void freeFPU(FloatRegister r) {
         availFPU_.add(r);
     }
 
     ////////////////////////////////////////////////////////////
     //