Backed out changeset d7e148db2e85 (bug 1321521) for build bustage a=backout CLOSED TREE

MozReview-Commit-ID: By0dyqjsVJb
This commit is contained in:
Wes Kocher 2017-01-13 10:35:23 -08:00
parent 8921f7c68c
commit 45ab3c2bb5
12 changed files with 66 additions and 457 deletions

View File

@ -419,7 +419,7 @@ BacktrackingAllocator::init()
registers[reg.code()].allocatable = true;
}
while (!remainingRegisters.emptyFloat()) {
AnyRegister reg = AnyRegister(remainingRegisters.takeAnyFloat<RegTypeName::Any>());
AnyRegister reg = AnyRegister(remainingRegisters.takeAnyFloat());
registers[reg.code()].allocatable = true;
}

View File

@ -4686,7 +4686,7 @@ CodeGenerator::generateArgumentsChecks(bool bailout)
MResumePoint* rp = mir.entryResumePoint();
// 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();

View File

@ -392,22 +392,22 @@ class TypedRegisterSet
bits_ &= ~reg.alignedOrDominatedAliasedSet();
}
static constexpr enum RegTypeName DefaultType = RegType::DefaultType;
template <enum RegTypeName Name>
SetType allLive() const {
return T::template LiveAsIndexableSet<Name>(bits_);
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();
}
template <enum RegTypeName Name>
SetType allAllocatable() const {
return T::template AllocatableAsIndexableSet<Name>(bits_);
T getFirst() const {
MOZ_ASSERT(!empty());
return T::FromCode(T::FirstBit(bits_));
}
static RegType FirstRegister(SetType set) {
return RegType::FromCode(RegType::FirstBit(set));
}
static RegType LastRegister(SetType set) {
return RegType::FromCode(RegType::LastBit(set));
T getLast() const {
MOZ_ASSERT(!empty());
int ireg = T::LastBit(bits_);
return T::FromCode(ireg);
}
SetType bits() const {
@ -481,9 +481,6 @@ class RegisterSet {
bool emptyFloat() const {
return fpu_.empty();
}
static constexpr enum RegTypeName DefaultType = RegTypeName::GPR;
constexpr GeneralRegisterSet gprs() const {
return gpr_;
}
@ -543,9 +540,6 @@ 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
@ -579,11 +573,6 @@ class AllocatableSetAccessors
protected:
RegSet set_;
template <enum RegTypeName Name>
SetType all() const {
return set_.template allAllocatable<Name>();
}
public:
AllocatableSetAccessors() : set_() {}
explicit constexpr AllocatableSetAccessors(SetType set) : set_(set) {}
@ -593,11 +582,6 @@ class AllocatableSetAccessors
return set_.hasAllocatable(reg);
}
template <enum RegTypeName Name>
bool hasAny(RegType reg) const {
return all<Name>() != 0;
}
void addUnchecked(RegType reg) {
set_.addAllocatable(reg);
}
@ -619,15 +603,6 @@ class AllocatableSetAccessors<RegisterSet>
protected:
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:
AllocatableSetAccessors() : set_() {}
explicit constexpr AllocatableSetAccessors(SetType) = delete;
@ -680,11 +655,6 @@ class LiveSetAccessors
protected:
RegSet set_;
template <enum RegTypeName Name>
SetType all() const {
return set_.template allLive<Name>();
}
public:
LiveSetAccessors() : set_() {}
explicit constexpr LiveSetAccessors(SetType set) : set_(set) {}
@ -715,15 +685,6 @@ class LiveSetAccessors<RegisterSet>
protected:
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:
LiveSetAccessors() : set_() {}
explicit constexpr LiveSetAccessors(SetType) = delete;
@ -790,68 +751,47 @@ class SpecializedRegSet : public Accessors
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 {
// 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>();
return this->Parent::set_.getAny();
}
RegType getFirst() const {
return this->Parent::set_.getFirst();
}
RegType getLast() const {
return this->Parent::set_.getLast();
}
template <enum RegTypeName Name = RegSet::DefaultType>
RegType getAnyExcluding(RegType preclude) {
if (!has(preclude))
return getAny<Name>();
return getAny();
take(preclude);
RegType result = getAny<Name>();
RegType result = getAny();
add(preclude);
return result;
}
template <enum RegTypeName Name = RegSet::DefaultType>
RegType takeAny() {
RegType reg = getAny<Name>();
RegType reg = getAny();
take(reg);
return reg;
}
template <enum RegTypeName Name = RegSet::DefaultType>
RegType takeFirst() {
RegType reg = getFirst<Name>();
RegType reg = getFirst();
take(reg);
return reg;
}
template <enum RegTypeName Name = RegSet::DefaultType>
RegType takeLast() {
RegType reg = getLast<Name>();
RegType reg = getLast();
take(reg);
return reg;
}
ValueOperand takeAnyValue() {
#if defined(JS_NUNBOX32)
return ValueOperand(takeAny<RegTypeName::GPR>(), takeAny<RegTypeName::GPR>());
return ValueOperand(takeAny(), takeAny());
#elif defined(JS_PUNBOX64)
return ValueOperand(takeAny<RegTypeName::GPR>());
return ValueOperand(takeAny());
#else
#error "Bad architecture"
#endif
@ -865,9 +805,8 @@ class SpecializedRegSet : public Accessors
#endif
}
template <enum RegTypeName Name = RegSet::DefaultType>
RegType takeAnyExcluding(RegType preclude) {
RegType reg = getAnyExcluding<Name>(preclude);
RegType reg = getAnyExcluding(preclude);
take(reg);
return reg;
}
@ -902,17 +841,12 @@ class SpecializedRegSet<Accessors, RegisterSet> : public Accessors
return this->Parent::set_.emptyFloat();
}
using Parent::has;
bool has(AnyRegister reg) const {
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;
void addUnchecked(AnyRegister reg) {
@ -961,15 +895,10 @@ class SpecializedRegSet<Accessors, RegisterSet> : public Accessors
}
Register getAnyGeneral() const {
GeneralRegisterSet::SetType set = Parent::template allGpr<RegTypeName::GPR>();
MOZ_ASSERT(set);
return GeneralRegisterSet::FirstRegister(set);
return this->Parent::set_.gprs().getAny();
}
template <enum RegTypeName Name = RegTypeName::Float64>
FloatRegister getAnyFloat() const {
FloatRegisterSet::SetType set = Parent::template allFpu<Name>();
MOZ_ASSERT(set);
return FloatRegisterSet::FirstRegister(set);
return this->Parent::set_.fpus().getAny();
}
Register takeAnyGeneral() {
@ -977,9 +906,8 @@ class SpecializedRegSet<Accessors, RegisterSet> : public Accessors
take(reg);
return reg;
}
template <enum RegTypeName Name = RegTypeName::Float64>
FloatRegister takeAnyFloat() {
FloatRegister reg = getAnyFloat<Name>();
FloatRegister reg = getAnyFloat();
take(reg);
return reg;
}
@ -1177,11 +1105,11 @@ class TypedRegisterIterator
return !regset_.empty();
}
TypedRegisterIterator<T>& operator ++() {
regset_.template takeAny<RegTypeName::Any>();
regset_.takeAny();
return *this;
}
T operator*() const {
return regset_.template getAny<RegTypeName::Any>();
return regset_.getAny();
}
};
@ -1204,11 +1132,11 @@ class TypedRegisterBackwardIterator
return !regset_.empty();
}
TypedRegisterBackwardIterator<T>& operator ++() {
regset_.template takeLast<RegTypeName::Any>();
regset_.takeLast();
return *this;
}
T operator*() const {
return regset_.template getLast<RegTypeName::Any>();
return regset_.getLast();
}
};
@ -1230,11 +1158,11 @@ class TypedRegisterForwardIterator
return !regset_.empty();
}
TypedRegisterForwardIterator<T>& operator ++() {
regset_.template takeFirst<RegTypeName::Any>();
regset_.takeFirst();
return *this;
}
T operator*() const {
return regset_.template getFirst<RegTypeName::Any>();
return regset_.getFirst();
}
};

View File

@ -88,19 +88,6 @@ struct Register {
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) {
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)
static const uint32_t INT64LOW_OFFSET = 0 * sizeof(int32_t);
static const uint32_t INT64HIGH_OFFSET = 1 * sizeof(int32_t);

View File

@ -81,8 +81,7 @@ StupidAllocator::init()
registers[registerCount++].reg = AnyRegister(remainingRegisters.takeAnyGeneral());
while (!remainingRegisters.emptyFloat())
registers[registerCount++].reg =
AnyRegister(remainingRegisters.takeAnyFloat<RegTypeName::Any>());
registers[registerCount++].reg = AnyRegister(remainingRegisters.takeAnyFloat());
MOZ_ASSERT(registerCount <= MAX_REGISTERS);
}

View File

@ -12,8 +12,6 @@
#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
@ -287,37 +285,6 @@ class FloatRegisters
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;
@ -390,9 +357,12 @@ class VFPRegister
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;
@ -400,7 +370,7 @@ class VFPRegister
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)
@ -563,7 +533,7 @@ class VFPRegister
// s1.alignedOrDominatedAliasedSet() == s1.
// 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
// relations:
//
@ -583,19 +553,6 @@ class VFPRegister
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_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
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.
typedef VFPRegister FloatRegister;

View File

@ -10,8 +10,6 @@
#include "mozilla/Assertions.h"
#include "mozilla/MathAlgorithms.h"
#include "jit/shared/Architecture-shared.h"
#include "js/Utility.h"
namespace js {
@ -271,8 +269,8 @@ class FloatRegisters
(1 << FloatRegisters::d30)) * SpreadCoefficient;
static const SetType VolatileMask = AllMask & ~NonVolatileMask;
static const SetType AllDoubleMask = AllPhysMask << TotalPhys;
static const SetType AllSingleMask = AllPhysMask;
static const SetType AllDoubleMask = AllMask;
static const SetType AllSingleMask = AllMask;
static const SetType WrapperMask = VolatileMask;
@ -432,19 +430,6 @@ struct FloatRegister
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 uint32_t GetSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
@ -455,24 +440,6 @@ struct FloatRegister
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

View File

@ -12,8 +12,6 @@
#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

View File

@ -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 */

View File

@ -15,8 +15,6 @@
#include <string.h>
#include "jit/shared/Architecture-shared.h"
#include "jit/x86-shared/Constants-x86-shared.h"
namespace js {
@ -264,7 +262,6 @@ class FloatRegisters {
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 =
@ -439,48 +436,11 @@ struct FloatRegister {
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 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

View File

@ -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) \
do { \
Register reg = Register::FromCode(index);
@ -142,70 +136,3 @@ BEGIN_TEST(testJitRegisterSet_FPU)
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)

View File

@ -206,18 +206,6 @@ static const Register ScratchRegARM = CallTempReg2;
# 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
@ -802,9 +790,17 @@ class BaseCompiler
// 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_.hasAny<RegTypeOf<t>::value>();
return !!(availFPU_.bits() & maskFromTypeFPU<t>());
}
bool isAvailable(FloatRegister r) {
@ -818,7 +814,12 @@ class BaseCompiler
template<MIRType t>
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) {