mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 14:45:29 +00:00
Backed out changeset d7e148db2e85 (bug 1321521
) for build bustage a=backout CLOSED TREE
MozReview-Commit-ID: By0dyqjsVJb
This commit is contained in:
parent
8921f7c68c
commit
45ab3c2bb5
@ -419,7 +419,7 @@ BacktrackingAllocator::init()
|
|||||||
registers[reg.code()].allocatable = true;
|
registers[reg.code()].allocatable = true;
|
||||||
}
|
}
|
||||||
while (!remainingRegisters.emptyFloat()) {
|
while (!remainingRegisters.emptyFloat()) {
|
||||||
AnyRegister reg = AnyRegister(remainingRegisters.takeAnyFloat<RegTypeName::Any>());
|
AnyRegister reg = AnyRegister(remainingRegisters.takeAnyFloat());
|
||||||
registers[reg.code()].allocatable = true;
|
registers[reg.code()].allocatable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4686,7 +4686,7 @@ CodeGenerator::generateArgumentsChecks(bool bailout)
|
|||||||
MResumePoint* rp = mir.entryResumePoint();
|
MResumePoint* rp = mir.entryResumePoint();
|
||||||
|
|
||||||
// No registers are allocated yet, so it's safe to grab anything.
|
// No registers are allocated yet, so it's safe to grab anything.
|
||||||
Register temp = AllocatableGeneralRegisterSet(EntryTempMask).getAny();
|
Register temp = GeneralRegisterSet(EntryTempMask).getAny();
|
||||||
|
|
||||||
const CompileInfo& info = gen->info();
|
const CompileInfo& info = gen->info();
|
||||||
|
|
||||||
|
@ -392,22 +392,22 @@ class TypedRegisterSet
|
|||||||
bits_ &= ~reg.alignedOrDominatedAliasedSet();
|
bits_ &= ~reg.alignedOrDominatedAliasedSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr enum RegTypeName DefaultType = RegType::DefaultType;
|
T getAny() const {
|
||||||
|
// The choice of first or last here is mostly arbitrary, as they are
|
||||||
template <enum RegTypeName Name>
|
// about the same speed on popular architectures. We choose first, as
|
||||||
SetType allLive() const {
|
// it has the advantage of using the "lower" registers more often. These
|
||||||
return T::template LiveAsIndexableSet<Name>(bits_);
|
// registers are sometimes more efficient (e.g. optimized encodings for
|
||||||
|
// EAX on x86).
|
||||||
|
return getFirst();
|
||||||
}
|
}
|
||||||
template <enum RegTypeName Name>
|
T getFirst() const {
|
||||||
SetType allAllocatable() const {
|
MOZ_ASSERT(!empty());
|
||||||
return T::template AllocatableAsIndexableSet<Name>(bits_);
|
return T::FromCode(T::FirstBit(bits_));
|
||||||
}
|
}
|
||||||
|
T getLast() const {
|
||||||
static RegType FirstRegister(SetType set) {
|
MOZ_ASSERT(!empty());
|
||||||
return RegType::FromCode(RegType::FirstBit(set));
|
int ireg = T::LastBit(bits_);
|
||||||
}
|
return T::FromCode(ireg);
|
||||||
static RegType LastRegister(SetType set) {
|
|
||||||
return RegType::FromCode(RegType::LastBit(set));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetType bits() const {
|
SetType bits() const {
|
||||||
@ -481,9 +481,6 @@ class RegisterSet {
|
|||||||
bool emptyFloat() const {
|
bool emptyFloat() const {
|
||||||
return fpu_.empty();
|
return fpu_.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr enum RegTypeName DefaultType = RegTypeName::GPR;
|
|
||||||
|
|
||||||
constexpr GeneralRegisterSet gprs() const {
|
constexpr GeneralRegisterSet gprs() const {
|
||||||
return gpr_;
|
return gpr_;
|
||||||
}
|
}
|
||||||
@ -543,9 +540,6 @@ class LiveSet;
|
|||||||
// Base accessors classes have the minimal set of raw methods to manipulate the register set
|
// 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:
|
// 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.
|
// - has: Returns if all the bits needed to take a register are present.
|
||||||
//
|
//
|
||||||
// - takeUnchecked: Subtracts the bits used to represent the register in the
|
// - takeUnchecked: Subtracts the bits used to represent the register in the
|
||||||
@ -579,11 +573,6 @@ class AllocatableSetAccessors
|
|||||||
protected:
|
protected:
|
||||||
RegSet set_;
|
RegSet set_;
|
||||||
|
|
||||||
template <enum RegTypeName Name>
|
|
||||||
SetType all() const {
|
|
||||||
return set_.template allAllocatable<Name>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AllocatableSetAccessors() : set_() {}
|
AllocatableSetAccessors() : set_() {}
|
||||||
explicit constexpr AllocatableSetAccessors(SetType set) : set_(set) {}
|
explicit constexpr AllocatableSetAccessors(SetType set) : set_(set) {}
|
||||||
@ -593,11 +582,6 @@ class AllocatableSetAccessors
|
|||||||
return set_.hasAllocatable(reg);
|
return set_.hasAllocatable(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <enum RegTypeName Name>
|
|
||||||
bool hasAny(RegType reg) const {
|
|
||||||
return all<Name>() != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addUnchecked(RegType reg) {
|
void addUnchecked(RegType reg) {
|
||||||
set_.addAllocatable(reg);
|
set_.addAllocatable(reg);
|
||||||
}
|
}
|
||||||
@ -619,15 +603,6 @@ class AllocatableSetAccessors<RegisterSet>
|
|||||||
protected:
|
protected:
|
||||||
RegisterSet set_;
|
RegisterSet set_;
|
||||||
|
|
||||||
template <enum RegTypeName Name>
|
|
||||||
GeneralRegisterSet::SetType allGpr() const {
|
|
||||||
return set_.gprs().allAllocatable<Name>();
|
|
||||||
}
|
|
||||||
template <enum RegTypeName Name>
|
|
||||||
FloatRegisterSet::SetType allFpu() const {
|
|
||||||
return set_.fpus().allAllocatable<Name>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AllocatableSetAccessors() : set_() {}
|
AllocatableSetAccessors() : set_() {}
|
||||||
explicit constexpr AllocatableSetAccessors(SetType) = delete;
|
explicit constexpr AllocatableSetAccessors(SetType) = delete;
|
||||||
@ -680,11 +655,6 @@ class LiveSetAccessors
|
|||||||
protected:
|
protected:
|
||||||
RegSet set_;
|
RegSet set_;
|
||||||
|
|
||||||
template <enum RegTypeName Name>
|
|
||||||
SetType all() const {
|
|
||||||
return set_.template allLive<Name>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LiveSetAccessors() : set_() {}
|
LiveSetAccessors() : set_() {}
|
||||||
explicit constexpr LiveSetAccessors(SetType set) : set_(set) {}
|
explicit constexpr LiveSetAccessors(SetType set) : set_(set) {}
|
||||||
@ -715,15 +685,6 @@ class LiveSetAccessors<RegisterSet>
|
|||||||
protected:
|
protected:
|
||||||
RegisterSet set_;
|
RegisterSet set_;
|
||||||
|
|
||||||
template <enum RegTypeName Name>
|
|
||||||
GeneralRegisterSet::SetType allGpr() const {
|
|
||||||
return set_.gprs().allLive<Name>();
|
|
||||||
}
|
|
||||||
template <enum RegTypeName Name>
|
|
||||||
FloatRegisterSet::SetType allFpu() const {
|
|
||||||
return set_.fpus().allLive<Name>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LiveSetAccessors() : set_() {}
|
LiveSetAccessors() : set_() {}
|
||||||
explicit constexpr LiveSetAccessors(SetType) = delete;
|
explicit constexpr LiveSetAccessors(SetType) = delete;
|
||||||
@ -790,68 +751,47 @@ class SpecializedRegSet : public Accessors
|
|||||||
takeUnchecked(reg);
|
takeUnchecked(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <enum RegTypeName Name>
|
|
||||||
bool hasAny() const {
|
|
||||||
return Parent::template all<Name>() != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <enum RegTypeName Name = RegSet::DefaultType>
|
|
||||||
RegType getFirst() const {
|
|
||||||
SetType set = Parent::template all<Name>();
|
|
||||||
MOZ_ASSERT(set);
|
|
||||||
return RegSet::FirstRegister(set);
|
|
||||||
}
|
|
||||||
template <enum RegTypeName Name = RegSet::DefaultType>
|
|
||||||
RegType getLast() const {
|
|
||||||
SetType set = Parent::template all<Name>();
|
|
||||||
MOZ_ASSERT(set);
|
|
||||||
return RegSet::LastRegister(set);
|
|
||||||
}
|
|
||||||
template <enum RegTypeName Name = RegSet::DefaultType>
|
|
||||||
RegType getAny() const {
|
RegType getAny() const {
|
||||||
// The choice of first or last here is mostly arbitrary, as they are
|
return this->Parent::set_.getAny();
|
||||||
// about the same speed on popular architectures. We choose first, as
|
}
|
||||||
// it has the advantage of using the "lower" registers more often. These
|
RegType getFirst() const {
|
||||||
// registers are sometimes more efficient (e.g. optimized encodings for
|
return this->Parent::set_.getFirst();
|
||||||
// EAX on x86).
|
}
|
||||||
return getFirst<Name>();
|
RegType getLast() const {
|
||||||
|
return this->Parent::set_.getLast();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <enum RegTypeName Name = RegSet::DefaultType>
|
|
||||||
RegType getAnyExcluding(RegType preclude) {
|
RegType getAnyExcluding(RegType preclude) {
|
||||||
if (!has(preclude))
|
if (!has(preclude))
|
||||||
return getAny<Name>();
|
return getAny();
|
||||||
|
|
||||||
take(preclude);
|
take(preclude);
|
||||||
RegType result = getAny<Name>();
|
RegType result = getAny();
|
||||||
add(preclude);
|
add(preclude);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <enum RegTypeName Name = RegSet::DefaultType>
|
|
||||||
RegType takeAny() {
|
RegType takeAny() {
|
||||||
RegType reg = getAny<Name>();
|
RegType reg = getAny();
|
||||||
take(reg);
|
take(reg);
|
||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
template <enum RegTypeName Name = RegSet::DefaultType>
|
|
||||||
RegType takeFirst() {
|
RegType takeFirst() {
|
||||||
RegType reg = getFirst<Name>();
|
RegType reg = getFirst();
|
||||||
take(reg);
|
take(reg);
|
||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
template <enum RegTypeName Name = RegSet::DefaultType>
|
|
||||||
RegType takeLast() {
|
RegType takeLast() {
|
||||||
RegType reg = getLast<Name>();
|
RegType reg = getLast();
|
||||||
take(reg);
|
take(reg);
|
||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueOperand takeAnyValue() {
|
ValueOperand takeAnyValue() {
|
||||||
#if defined(JS_NUNBOX32)
|
#if defined(JS_NUNBOX32)
|
||||||
return ValueOperand(takeAny<RegTypeName::GPR>(), takeAny<RegTypeName::GPR>());
|
return ValueOperand(takeAny(), takeAny());
|
||||||
#elif defined(JS_PUNBOX64)
|
#elif defined(JS_PUNBOX64)
|
||||||
return ValueOperand(takeAny<RegTypeName::GPR>());
|
return ValueOperand(takeAny());
|
||||||
#else
|
#else
|
||||||
#error "Bad architecture"
|
#error "Bad architecture"
|
||||||
#endif
|
#endif
|
||||||
@ -865,9 +805,8 @@ class SpecializedRegSet : public Accessors
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <enum RegTypeName Name = RegSet::DefaultType>
|
|
||||||
RegType takeAnyExcluding(RegType preclude) {
|
RegType takeAnyExcluding(RegType preclude) {
|
||||||
RegType reg = getAnyExcluding<Name>(preclude);
|
RegType reg = getAnyExcluding(preclude);
|
||||||
take(reg);
|
take(reg);
|
||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
@ -902,17 +841,12 @@ class SpecializedRegSet<Accessors, RegisterSet> : public Accessors
|
|||||||
return this->Parent::set_.emptyFloat();
|
return this->Parent::set_.emptyFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
using Parent::has;
|
using Parent::has;
|
||||||
bool has(AnyRegister reg) const {
|
bool has(AnyRegister reg) const {
|
||||||
return reg.isFloat() ? has(reg.fpu()) : has(reg.gpr());
|
return reg.isFloat() ? has(reg.fpu()) : has(reg.gpr());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <enum 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;
|
using Parent::addUnchecked;
|
||||||
void addUnchecked(AnyRegister reg) {
|
void addUnchecked(AnyRegister reg) {
|
||||||
@ -961,15 +895,10 @@ class SpecializedRegSet<Accessors, RegisterSet> : public Accessors
|
|||||||
}
|
}
|
||||||
|
|
||||||
Register getAnyGeneral() const {
|
Register getAnyGeneral() const {
|
||||||
GeneralRegisterSet::SetType set = Parent::template allGpr<RegTypeName::GPR>();
|
return this->Parent::set_.gprs().getAny();
|
||||||
MOZ_ASSERT(set);
|
|
||||||
return GeneralRegisterSet::FirstRegister(set);
|
|
||||||
}
|
}
|
||||||
template <enum RegTypeName Name = RegTypeName::Float64>
|
|
||||||
FloatRegister getAnyFloat() const {
|
FloatRegister getAnyFloat() const {
|
||||||
FloatRegisterSet::SetType set = Parent::template allFpu<Name>();
|
return this->Parent::set_.fpus().getAny();
|
||||||
MOZ_ASSERT(set);
|
|
||||||
return FloatRegisterSet::FirstRegister(set);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Register takeAnyGeneral() {
|
Register takeAnyGeneral() {
|
||||||
@ -977,9 +906,8 @@ class SpecializedRegSet<Accessors, RegisterSet> : public Accessors
|
|||||||
take(reg);
|
take(reg);
|
||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
template <enum RegTypeName Name = RegTypeName::Float64>
|
|
||||||
FloatRegister takeAnyFloat() {
|
FloatRegister takeAnyFloat() {
|
||||||
FloatRegister reg = getAnyFloat<Name>();
|
FloatRegister reg = getAnyFloat();
|
||||||
take(reg);
|
take(reg);
|
||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
@ -1177,11 +1105,11 @@ class TypedRegisterIterator
|
|||||||
return !regset_.empty();
|
return !regset_.empty();
|
||||||
}
|
}
|
||||||
TypedRegisterIterator<T>& operator ++() {
|
TypedRegisterIterator<T>& operator ++() {
|
||||||
regset_.template takeAny<RegTypeName::Any>();
|
regset_.takeAny();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
T operator*() const {
|
T operator*() const {
|
||||||
return regset_.template getAny<RegTypeName::Any>();
|
return regset_.getAny();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1204,11 +1132,11 @@ class TypedRegisterBackwardIterator
|
|||||||
return !regset_.empty();
|
return !regset_.empty();
|
||||||
}
|
}
|
||||||
TypedRegisterBackwardIterator<T>& operator ++() {
|
TypedRegisterBackwardIterator<T>& operator ++() {
|
||||||
regset_.template takeLast<RegTypeName::Any>();
|
regset_.takeLast();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
T operator*() const {
|
T operator*() const {
|
||||||
return regset_.template getLast<RegTypeName::Any>();
|
return regset_.getLast();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1230,11 +1158,11 @@ class TypedRegisterForwardIterator
|
|||||||
return !regset_.empty();
|
return !regset_.empty();
|
||||||
}
|
}
|
||||||
TypedRegisterForwardIterator<T>& operator ++() {
|
TypedRegisterForwardIterator<T>& operator ++() {
|
||||||
regset_.template takeFirst<RegTypeName::Any>();
|
regset_.takeFirst();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
T operator*() const {
|
T operator*() const {
|
||||||
return regset_.template getFirst<RegTypeName::Any>();
|
return regset_.getFirst();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -88,19 +88,6 @@ struct Register {
|
|||||||
return SetType(1) << code();
|
return SetType(1) << code();
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr enum RegTypeName DefaultType = RegTypeName::GPR;
|
|
||||||
|
|
||||||
template <enum RegTypeName = DefaultType>
|
|
||||||
static SetType LiveAsIndexableSet(SetType s) {
|
|
||||||
return SetType(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <enum 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 uint32_t SetSize(SetType x) {
|
||||||
return Codes::SetSize(x);
|
return Codes::SetSize(x);
|
||||||
}
|
}
|
||||||
@ -112,24 +99,6 @@ struct Register {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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)
|
#if defined(JS_NUNBOX32)
|
||||||
static const uint32_t INT64LOW_OFFSET = 0 * sizeof(int32_t);
|
static const uint32_t INT64LOW_OFFSET = 0 * sizeof(int32_t);
|
||||||
static const uint32_t INT64HIGH_OFFSET = 1 * sizeof(int32_t);
|
static const uint32_t INT64HIGH_OFFSET = 1 * sizeof(int32_t);
|
||||||
|
@ -81,8 +81,7 @@ StupidAllocator::init()
|
|||||||
registers[registerCount++].reg = AnyRegister(remainingRegisters.takeAnyGeneral());
|
registers[registerCount++].reg = AnyRegister(remainingRegisters.takeAnyGeneral());
|
||||||
|
|
||||||
while (!remainingRegisters.emptyFloat())
|
while (!remainingRegisters.emptyFloat())
|
||||||
registers[registerCount++].reg =
|
registers[registerCount++].reg = AnyRegister(remainingRegisters.takeAnyFloat());
|
||||||
AnyRegister(remainingRegisters.takeAnyFloat<RegTypeName::Any>());
|
|
||||||
|
|
||||||
MOZ_ASSERT(registerCount <= MAX_REGISTERS);
|
MOZ_ASSERT(registerCount <= MAX_REGISTERS);
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,6 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "jit/shared/Architecture-shared.h"
|
|
||||||
|
|
||||||
#include "js/Utility.h"
|
#include "js/Utility.h"
|
||||||
|
|
||||||
// GCC versions 4.6 and above define __ARM_PCS_VFP to denote a hard-float
|
// GCC versions 4.6 and above define __ARM_PCS_VFP to denote a hard-float
|
||||||
@ -287,37 +285,6 @@ class FloatRegisters
|
|||||||
static const uint32_t TotalPhys = 32;
|
static const uint32_t TotalPhys = 32;
|
||||||
static uint32_t ActualTotalPhys();
|
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;
|
typedef uint64_t SetType;
|
||||||
static const SetType AllSingleMask = (1ull << TotalSingle) - 1;
|
static const SetType AllSingleMask = (1ull << TotalSingle) - 1;
|
||||||
static const SetType AllDoubleMask = ((1ull << TotalDouble) - 1) << TotalSingle;
|
static const SetType AllDoubleMask = ((1ull << TotalDouble) - 1) << TotalSingle;
|
||||||
@ -390,9 +357,12 @@ class VFPRegister
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
RegType kind : 2;
|
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:
|
public:
|
||||||
// ARM doesn't have more than 32 registers of each type, so 5 bits should
|
|
||||||
// suffice.
|
|
||||||
uint32_t code_ : 5;
|
uint32_t code_ : 5;
|
||||||
protected:
|
protected:
|
||||||
bool _isInvalid : 1;
|
bool _isInvalid : 1;
|
||||||
@ -400,7 +370,7 @@ class VFPRegister
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr VFPRegister(uint32_t r, RegType k)
|
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()
|
constexpr VFPRegister()
|
||||||
: kind(Double), code_(Code(0)), _isInvalid(true), _isMissing(false)
|
: kind(Double), code_(Code(0)), _isInvalid(true), _isMissing(false)
|
||||||
@ -563,7 +533,7 @@ class VFPRegister
|
|||||||
// s1.alignedOrDominatedAliasedSet() == s1.
|
// s1.alignedOrDominatedAliasedSet() == s1.
|
||||||
// d0.alignedOrDominatedAliasedSet() == s0 | s1 | d0.
|
// d0.alignedOrDominatedAliasedSet() == s0 | s1 | d0.
|
||||||
//
|
//
|
||||||
// This way the Allocatable register set does not have to do any arithmetics
|
// This way the Allocator register set does not have to do any arithmetics
|
||||||
// to know if a register is available or not, as we have the following
|
// to know if a register is available or not, as we have the following
|
||||||
// relations:
|
// relations:
|
||||||
//
|
//
|
||||||
@ -583,19 +553,6 @@ class VFPRegister
|
|||||||
return (SetType(0b11) << (code_ * 2)) | (SetType(1) << (32 + code_));
|
return (SetType(0b11) << (code_ * 2)) | (SetType(1) << (32 + code_));
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr enum RegTypeName DefaultType = RegTypeName::Float64;
|
|
||||||
|
|
||||||
template <enum RegTypeName = DefaultType>
|
|
||||||
static SetType LiveAsIndexableSet(SetType s) {
|
|
||||||
return SetType(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <enum 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 uint32_t SetSize(SetType x) {
|
||||||
static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
|
static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
|
||||||
return mozilla::CountPopulation32(x);
|
return mozilla::CountPopulation32(x);
|
||||||
@ -615,79 +572,6 @@ class VFPRegister
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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.
|
// The only floating point register set that we work with are the VFP Registers.
|
||||||
typedef VFPRegister FloatRegister;
|
typedef VFPRegister FloatRegister;
|
||||||
|
|
||||||
|
@ -10,8 +10,6 @@
|
|||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/MathAlgorithms.h"
|
#include "mozilla/MathAlgorithms.h"
|
||||||
|
|
||||||
#include "jit/shared/Architecture-shared.h"
|
|
||||||
|
|
||||||
#include "js/Utility.h"
|
#include "js/Utility.h"
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
@ -271,8 +269,8 @@ class FloatRegisters
|
|||||||
(1 << FloatRegisters::d30)) * SpreadCoefficient;
|
(1 << FloatRegisters::d30)) * SpreadCoefficient;
|
||||||
|
|
||||||
static const SetType VolatileMask = AllMask & ~NonVolatileMask;
|
static const SetType VolatileMask = AllMask & ~NonVolatileMask;
|
||||||
static const SetType AllDoubleMask = AllPhysMask << TotalPhys;
|
static const SetType AllDoubleMask = AllMask;
|
||||||
static const SetType AllSingleMask = AllPhysMask;
|
static const SetType AllSingleMask = AllMask;
|
||||||
|
|
||||||
static const SetType WrapperMask = VolatileMask;
|
static const SetType WrapperMask = VolatileMask;
|
||||||
|
|
||||||
@ -432,19 +430,6 @@ struct FloatRegister
|
|||||||
return 63 - mozilla::CountLeadingZeroes64(x);
|
return 63 - mozilla::CountLeadingZeroes64(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr enum RegTypeName DefaultType = RegTypeName::Float64;
|
|
||||||
|
|
||||||
template <enum RegTypeName = DefaultType>
|
|
||||||
static SetType LiveAsIndexableSet(SetType s) {
|
|
||||||
return SetType(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <enum 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 TypedRegisterSet<FloatRegister> ReduceSetForPush(const TypedRegisterSet<FloatRegister>& s);
|
||||||
static uint32_t GetSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
|
static uint32_t GetSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
|
||||||
static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
|
static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
|
||||||
@ -455,24 +440,6 @@ struct FloatRegister
|
|||||||
FloatRegisters::Kind k_ : 1;
|
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.
|
// ARM/D32 has double registers that cannot be treated as float32.
|
||||||
// Luckily, ARMv8 doesn't have the same misfortune.
|
// Luckily, ARMv8 doesn't have the same misfortune.
|
||||||
inline bool
|
inline bool
|
||||||
|
@ -12,8 +12,6 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "jit/shared/Architecture-shared.h"
|
|
||||||
|
|
||||||
#include "js/Utility.h"
|
#include "js/Utility.h"
|
||||||
|
|
||||||
// gcc appears to use _mips_hard_float to denote
|
// gcc appears to use _mips_hard_float to denote
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
/* -*- 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 */
|
|
@ -15,8 +15,6 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "jit/shared/Architecture-shared.h"
|
|
||||||
|
|
||||||
#include "jit/x86-shared/Constants-x86-shared.h"
|
#include "jit/x86-shared/Constants-x86-shared.h"
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
@ -264,7 +262,6 @@ class FloatRegisters {
|
|||||||
static const SetType AllMask = AllPhysMask * Spread;
|
static const SetType AllMask = AllPhysMask * Spread;
|
||||||
static const SetType AllDoubleMask = AllPhysMask * SpreadDouble;
|
static const SetType AllDoubleMask = AllPhysMask * SpreadDouble;
|
||||||
static const SetType AllSingleMask = AllPhysMask * SpreadSingle;
|
static const SetType AllSingleMask = AllPhysMask * SpreadSingle;
|
||||||
static const SetType AllVector128Mask = AllPhysMask * SpreadSimd128;
|
|
||||||
|
|
||||||
#if defined(JS_CODEGEN_X86)
|
#if defined(JS_CODEGEN_X86)
|
||||||
static const SetType NonAllocatableMask =
|
static const SetType NonAllocatableMask =
|
||||||
@ -439,48 +436,11 @@ struct FloatRegister {
|
|||||||
return Codes::Spread << reg_;
|
return Codes::Spread << reg_;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr enum RegTypeName DefaultType = RegTypeName::Float64;
|
|
||||||
|
|
||||||
template <enum RegTypeName = DefaultType>
|
|
||||||
static SetType LiveAsIndexableSet(SetType s) {
|
|
||||||
return SetType(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <enum 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 TypedRegisterSet<FloatRegister> ReduceSetForPush(const TypedRegisterSet<FloatRegister>& s);
|
||||||
static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
|
static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
|
||||||
uint32_t getRegisterDumpOffsetInBytes();
|
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
|
// Arm/D32 has double registers that can NOT be treated as float32
|
||||||
// and this requires some dances in lowering.
|
// and this requires some dances in lowering.
|
||||||
inline bool
|
inline bool
|
||||||
|
@ -35,12 +35,6 @@ CoPrime(size_t a, size_t b)
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#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) \
|
#define FOR_ALL_REGISTERS(Register, reg) \
|
||||||
do { \
|
do { \
|
||||||
Register reg = Register::FromCode(index);
|
Register reg = Register::FromCode(index);
|
||||||
@ -142,70 +136,3 @@ BEGIN_TEST(testJitRegisterSet_FPU)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
END_TEST(testJitRegisterSet_FPU)
|
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)
|
|
||||||
|
@ -206,18 +206,6 @@ static const Register ScratchRegARM = CallTempReg2;
|
|||||||
# define FLOAT_TO_I64_CALLOUT
|
# define FLOAT_TO_I64_CALLOUT
|
||||||
#endif
|
#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
|
class BaseCompiler
|
||||||
{
|
{
|
||||||
// We define our own ScratchRegister abstractions, deferring to
|
// We define our own ScratchRegister abstractions, deferring to
|
||||||
@ -802,9 +790,17 @@ class BaseCompiler
|
|||||||
// allocated then d0 is not allocatable; if s0 and s1 are freed
|
// allocated then d0 is not allocatable; if s0 and s1 are freed
|
||||||
// individually then d0 becomes allocatable.
|
// 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>
|
template<MIRType t>
|
||||||
bool hasFPU() {
|
bool hasFPU() {
|
||||||
return availFPU_.hasAny<RegTypeOf<t>::value>();
|
return !!(availFPU_.bits() & maskFromTypeFPU<t>());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAvailable(FloatRegister r) {
|
bool isAvailable(FloatRegister r) {
|
||||||
@ -818,7 +814,12 @@ class BaseCompiler
|
|||||||
|
|
||||||
template<MIRType t>
|
template<MIRType t>
|
||||||
FloatRegister allocFPU() {
|
FloatRegister allocFPU() {
|
||||||
return availFPU_.takeAny<RegTypeOf<t>::value>();
|
MOZ_ASSERT(hasFPU<t>());
|
||||||
|
FloatRegister r =
|
||||||
|
FloatRegisterSet::Intersect(FloatRegisterSet(availFPU_.bits()),
|
||||||
|
FloatRegisterSet(maskFromTypeFPU<t>())).getAny();
|
||||||
|
availFPU_.take(r);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeFPU(FloatRegister r) {
|
void freeFPU(FloatRegister r) {
|
||||||
|
Loading…
Reference in New Issue
Block a user