js/src/jit/RegisterSets.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/RegisterSets.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,807 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef jit_RegisterSets_h
    1.11 +#define jit_RegisterSets_h
    1.12 +
    1.13 +#include "mozilla/Alignment.h"
    1.14 +#include "mozilla/MathAlgorithms.h"
    1.15 +
    1.16 +#include "jit/IonAllocPolicy.h"
    1.17 +#include "jit/Registers.h"
    1.18 +
    1.19 +namespace js {
    1.20 +namespace jit {
    1.21 +
    1.22 +struct AnyRegister {
    1.23 +    typedef uint32_t Code;
    1.24 +
    1.25 +    static const uint32_t Total = Registers::Total + FloatRegisters::Total;
    1.26 +    static const uint32_t Invalid = UINT_MAX;
    1.27 +
    1.28 +    union {
    1.29 +        Registers::Code gpr_;
    1.30 +        FloatRegisters::Code fpu_;
    1.31 +    };
    1.32 +    bool isFloat_;
    1.33 +
    1.34 +    AnyRegister()
    1.35 +    { }
    1.36 +    explicit AnyRegister(Register gpr) {
    1.37 +        gpr_ = gpr.code();
    1.38 +        isFloat_ = false;
    1.39 +    }
    1.40 +    explicit AnyRegister(FloatRegister fpu) {
    1.41 +        fpu_ = fpu.code();
    1.42 +        isFloat_ = true;
    1.43 +    }
    1.44 +    static AnyRegister FromCode(uint32_t i) {
    1.45 +        JS_ASSERT(i < Total);
    1.46 +        AnyRegister r;
    1.47 +        if (i < Registers::Total) {
    1.48 +            r.gpr_ = Register::Code(i);
    1.49 +            r.isFloat_ = false;
    1.50 +        } else {
    1.51 +            r.fpu_ = FloatRegister::Code(i - Registers::Total);
    1.52 +            r.isFloat_ = true;
    1.53 +        }
    1.54 +        return r;
    1.55 +    }
    1.56 +    bool isFloat() const {
    1.57 +        return isFloat_;
    1.58 +    }
    1.59 +    Register gpr() const {
    1.60 +        JS_ASSERT(!isFloat());
    1.61 +        return Register::FromCode(gpr_);
    1.62 +    }
    1.63 +    FloatRegister fpu() const {
    1.64 +        JS_ASSERT(isFloat());
    1.65 +        return FloatRegister::FromCode(fpu_);
    1.66 +    }
    1.67 +    bool operator ==(const AnyRegister &other) const {
    1.68 +        return isFloat()
    1.69 +               ? (other.isFloat() && fpu_ == other.fpu_)
    1.70 +               : (!other.isFloat() && gpr_ == other.gpr_);
    1.71 +    }
    1.72 +    bool operator !=(const AnyRegister &other) const {
    1.73 +        return isFloat()
    1.74 +               ? (!other.isFloat() || fpu_ != other.fpu_)
    1.75 +               : (other.isFloat() || gpr_ != other.gpr_);
    1.76 +    }
    1.77 +    const char *name() const {
    1.78 +        return isFloat()
    1.79 +               ? FloatRegister::FromCode(fpu_).name()
    1.80 +               : Register::FromCode(gpr_).name();
    1.81 +    }
    1.82 +    const Code code() const {
    1.83 +        return isFloat()
    1.84 +               ? fpu_ + Registers::Total
    1.85 +               : gpr_;
    1.86 +    }
    1.87 +    bool volatile_() const {
    1.88 +        return isFloat() ? fpu().volatile_() : gpr().volatile_();
    1.89 +    }
    1.90 +};
    1.91 +
    1.92 +// Registers to hold a boxed value. Uses one register on 64 bit
    1.93 +// platforms, two registers on 32 bit platforms.
    1.94 +class ValueOperand
    1.95 +{
    1.96 +#if defined(JS_NUNBOX32)
    1.97 +    Register type_;
    1.98 +    Register payload_;
    1.99 +
   1.100 +  public:
   1.101 +    MOZ_CONSTEXPR ValueOperand(Register type, Register payload)
   1.102 +      : type_(type), payload_(payload)
   1.103 +    { }
   1.104 +
   1.105 +    Register typeReg() const {
   1.106 +        return type_;
   1.107 +    }
   1.108 +    Register payloadReg() const {
   1.109 +        return payload_;
   1.110 +    }
   1.111 +
   1.112 +    Register scratchReg() const {
   1.113 +        return payloadReg();
   1.114 +    }
   1.115 +    bool operator==(const ValueOperand &o) const {
   1.116 +        return type_ == o.type_ && payload_ == o.payload_;
   1.117 +    }
   1.118 +    bool operator!=(const ValueOperand &o) const {
   1.119 +        return !(*this == o);
   1.120 +    }
   1.121 +
   1.122 +#elif defined(JS_PUNBOX64)
   1.123 +    Register value_;
   1.124 +
   1.125 +  public:
   1.126 +    explicit MOZ_CONSTEXPR ValueOperand(Register value)
   1.127 +      : value_(value)
   1.128 +    { }
   1.129 +
   1.130 +    Register valueReg() const {
   1.131 +        return value_;
   1.132 +    }
   1.133 +
   1.134 +    Register scratchReg() const {
   1.135 +        return valueReg();
   1.136 +    }
   1.137 +    bool operator==(const ValueOperand &o) const {
   1.138 +        return value_ == o.value_;
   1.139 +    }
   1.140 +    bool operator!=(const ValueOperand &o) const {
   1.141 +        return !(*this == o);
   1.142 +    }
   1.143 +#endif
   1.144 +
   1.145 +    ValueOperand() {}
   1.146 +};
   1.147 +
   1.148 +// Registers to hold either either a typed or untyped value.
   1.149 +class TypedOrValueRegister
   1.150 +{
   1.151 +    // Type of value being stored.
   1.152 +    MIRType type_;
   1.153 +
   1.154 +    // Space to hold either an AnyRegister or a ValueOperand.
   1.155 +    union U {
   1.156 +        mozilla::AlignedStorage2<AnyRegister> typed;
   1.157 +        mozilla::AlignedStorage2<ValueOperand> value;
   1.158 +    } data;
   1.159 +
   1.160 +    AnyRegister &dataTyped() {
   1.161 +        JS_ASSERT(hasTyped());
   1.162 +        return *data.typed.addr();
   1.163 +    }
   1.164 +    ValueOperand &dataValue() {
   1.165 +        JS_ASSERT(hasValue());
   1.166 +        return *data.value.addr();
   1.167 +    }
   1.168 +
   1.169 +    const AnyRegister &dataTyped() const {
   1.170 +        JS_ASSERT(hasTyped());
   1.171 +        return *data.typed.addr();
   1.172 +    }
   1.173 +    const ValueOperand &dataValue() const {
   1.174 +        JS_ASSERT(hasValue());
   1.175 +        return *data.value.addr();
   1.176 +    }
   1.177 +
   1.178 +  public:
   1.179 +
   1.180 +    TypedOrValueRegister()
   1.181 +      : type_(MIRType_None)
   1.182 +    {}
   1.183 +
   1.184 +    TypedOrValueRegister(MIRType type, AnyRegister reg)
   1.185 +      : type_(type)
   1.186 +    {
   1.187 +        dataTyped() = reg;
   1.188 +    }
   1.189 +
   1.190 +    TypedOrValueRegister(ValueOperand value)
   1.191 +      : type_(MIRType_Value)
   1.192 +    {
   1.193 +        dataValue() = value;
   1.194 +    }
   1.195 +
   1.196 +    MIRType type() const {
   1.197 +        return type_;
   1.198 +    }
   1.199 +
   1.200 +    bool hasTyped() const {
   1.201 +        return type() != MIRType_None && type() != MIRType_Value;
   1.202 +    }
   1.203 +
   1.204 +    bool hasValue() const {
   1.205 +        return type() == MIRType_Value;
   1.206 +    }
   1.207 +
   1.208 +    AnyRegister typedReg() const {
   1.209 +        return dataTyped();
   1.210 +    }
   1.211 +
   1.212 +    ValueOperand valueReg() const {
   1.213 +        return dataValue();
   1.214 +    }
   1.215 +
   1.216 +    AnyRegister scratchReg() {
   1.217 +        if (hasValue())
   1.218 +            return AnyRegister(valueReg().scratchReg());
   1.219 +        return typedReg();
   1.220 +    }
   1.221 +};
   1.222 +
   1.223 +// A constant value, or registers to hold a typed/untyped value.
   1.224 +class ConstantOrRegister
   1.225 +{
   1.226 +    // Whether a constant value is being stored.
   1.227 +    bool constant_;
   1.228 +
   1.229 +    // Space to hold either a Value or a TypedOrValueRegister.
   1.230 +    union U {
   1.231 +        mozilla::AlignedStorage2<Value> constant;
   1.232 +        mozilla::AlignedStorage2<TypedOrValueRegister> reg;
   1.233 +    } data;
   1.234 +
   1.235 +    Value &dataValue() {
   1.236 +        JS_ASSERT(constant());
   1.237 +        return *data.constant.addr();
   1.238 +    }
   1.239 +    TypedOrValueRegister &dataReg() {
   1.240 +        JS_ASSERT(!constant());
   1.241 +        return *data.reg.addr();
   1.242 +    }
   1.243 +
   1.244 +  public:
   1.245 +
   1.246 +    ConstantOrRegister()
   1.247 +    {}
   1.248 +
   1.249 +    ConstantOrRegister(Value value)
   1.250 +      : constant_(true)
   1.251 +    {
   1.252 +        dataValue() = value;
   1.253 +    }
   1.254 +
   1.255 +    ConstantOrRegister(TypedOrValueRegister reg)
   1.256 +      : constant_(false)
   1.257 +    {
   1.258 +        dataReg() = reg;
   1.259 +    }
   1.260 +
   1.261 +    bool constant() {
   1.262 +        return constant_;
   1.263 +    }
   1.264 +
   1.265 +    Value value() {
   1.266 +        return dataValue();
   1.267 +    }
   1.268 +
   1.269 +    TypedOrValueRegister reg() {
   1.270 +        return dataReg();
   1.271 +    }
   1.272 +};
   1.273 +
   1.274 +struct Int32Key {
   1.275 +    bool isRegister_;
   1.276 +    union {
   1.277 +        Register reg_;
   1.278 +        int32_t constant_;
   1.279 +    };
   1.280 +
   1.281 +    explicit Int32Key(Register reg)
   1.282 +      : isRegister_(true), reg_(reg)
   1.283 +    { }
   1.284 +
   1.285 +    explicit Int32Key(int32_t index)
   1.286 +      : isRegister_(false), constant_(index)
   1.287 +    { }
   1.288 +
   1.289 +    inline void bumpConstant(int diff) {
   1.290 +        JS_ASSERT(!isRegister_);
   1.291 +        constant_ += diff;
   1.292 +    }
   1.293 +    inline Register reg() const {
   1.294 +        JS_ASSERT(isRegister_);
   1.295 +        return reg_;
   1.296 +    }
   1.297 +    inline int32_t constant() const {
   1.298 +        JS_ASSERT(!isRegister_);
   1.299 +        return constant_;
   1.300 +    }
   1.301 +    inline bool isRegister() const {
   1.302 +        return isRegister_;
   1.303 +    }
   1.304 +    inline bool isConstant() const {
   1.305 +        return !isRegister_;
   1.306 +    }
   1.307 +};
   1.308 +
   1.309 +template <typename T>
   1.310 +class TypedRegisterSet
   1.311 +{
   1.312 +    uint32_t bits_;
   1.313 +
   1.314 +  public:
   1.315 +    explicit MOZ_CONSTEXPR TypedRegisterSet(uint32_t bits)
   1.316 +      : bits_(bits)
   1.317 +    { }
   1.318 +
   1.319 +    MOZ_CONSTEXPR TypedRegisterSet() : bits_(0)
   1.320 +    { }
   1.321 +    MOZ_CONSTEXPR TypedRegisterSet(const TypedRegisterSet<T> &set) : bits_(set.bits_)
   1.322 +    { }
   1.323 +
   1.324 +    static inline TypedRegisterSet All() {
   1.325 +        return TypedRegisterSet(T::Codes::AllocatableMask);
   1.326 +    }
   1.327 +    static inline TypedRegisterSet Intersect(const TypedRegisterSet &lhs,
   1.328 +                                             const TypedRegisterSet &rhs) {
   1.329 +        return TypedRegisterSet(lhs.bits_ & rhs.bits_);
   1.330 +    }
   1.331 +    static inline TypedRegisterSet Union(const TypedRegisterSet &lhs,
   1.332 +                                         const TypedRegisterSet &rhs) {
   1.333 +        return TypedRegisterSet(lhs.bits_ | rhs.bits_);
   1.334 +    }
   1.335 +    static inline TypedRegisterSet Not(const TypedRegisterSet &in) {
   1.336 +        return TypedRegisterSet(~in.bits_ & T::Codes::AllocatableMask);
   1.337 +    }
   1.338 +    static inline TypedRegisterSet VolatileNot(const TypedRegisterSet &in) {
   1.339 +        const uint32_t allocatableVolatile =
   1.340 +            T::Codes::AllocatableMask & T::Codes::VolatileMask;
   1.341 +        return TypedRegisterSet(~in.bits_ & allocatableVolatile);
   1.342 +    }
   1.343 +    static inline TypedRegisterSet Volatile() {
   1.344 +        return TypedRegisterSet(T::Codes::AllocatableMask & T::Codes::VolatileMask);
   1.345 +    }
   1.346 +    static inline TypedRegisterSet NonVolatile() {
   1.347 +        return TypedRegisterSet(T::Codes::AllocatableMask & T::Codes::NonVolatileMask);
   1.348 +    }
   1.349 +    bool has(T reg) const {
   1.350 +        return !!(bits_ & (1 << reg.code()));
   1.351 +    }
   1.352 +    void addUnchecked(T reg) {
   1.353 +        bits_ |= (1 << reg.code());
   1.354 +    }
   1.355 +    void add(T reg) {
   1.356 +        JS_ASSERT(!has(reg));
   1.357 +        addUnchecked(reg);
   1.358 +    }
   1.359 +    void add(ValueOperand value) {
   1.360 +#if defined(JS_NUNBOX32)
   1.361 +        add(value.payloadReg());
   1.362 +        add(value.typeReg());
   1.363 +#elif defined(JS_PUNBOX64)
   1.364 +        add(value.valueReg());
   1.365 +#else
   1.366 +#error "Bad architecture"
   1.367 +#endif
   1.368 +    }
   1.369 +    // Determemine if some register are still allocated.  This function should
   1.370 +    // be used with the set of allocatable registers used for the initialization
   1.371 +    // of the current set.
   1.372 +    bool someAllocated(const TypedRegisterSet &allocatable) const {
   1.373 +        return allocatable.bits_ & ~bits_;
   1.374 +    }
   1.375 +    bool empty() const {
   1.376 +        return !bits_;
   1.377 +    }
   1.378 +    void take(T reg) {
   1.379 +        JS_ASSERT(has(reg));
   1.380 +        takeUnchecked(reg);
   1.381 +    }
   1.382 +    void takeUnchecked(T reg) {
   1.383 +        bits_ &= ~(1 << reg.code());
   1.384 +    }
   1.385 +    void take(ValueOperand value) {
   1.386 +#if defined(JS_NUNBOX32)
   1.387 +        take(value.payloadReg());
   1.388 +        take(value.typeReg());
   1.389 +#elif defined(JS_PUNBOX64)
   1.390 +        take(value.valueReg());
   1.391 +#else
   1.392 +#error "Bad architecture"
   1.393 +#endif
   1.394 +    }
   1.395 +    void takeUnchecked(ValueOperand value) {
   1.396 +#if defined(JS_NUNBOX32)
   1.397 +        takeUnchecked(value.payloadReg());
   1.398 +        takeUnchecked(value.typeReg());
   1.399 +#elif defined(JS_PUNBOX64)
   1.400 +        takeUnchecked(value.valueReg());
   1.401 +#else
   1.402 +#error "Bad architecture"
   1.403 +#endif
   1.404 +    }
   1.405 +    ValueOperand takeValueOperand() {
   1.406 +#if defined(JS_NUNBOX32)
   1.407 +        return ValueOperand(takeAny(), takeAny());
   1.408 +#elif defined(JS_PUNBOX64)
   1.409 +        return ValueOperand(takeAny());
   1.410 +#else
   1.411 +#error "Bad architecture"
   1.412 +#endif
   1.413 +    }
   1.414 +    T getAny() const {
   1.415 +        // The choice of first or last here is mostly arbitrary, as they are
   1.416 +        // about the same speed on popular architectures. We choose first, as
   1.417 +        // it has the advantage of using the "lower" registers more often. These
   1.418 +        // registers are sometimes more efficient (e.g. optimized encodings for
   1.419 +        // EAX on x86).
   1.420 +        return getFirst();
   1.421 +    }
   1.422 +    T getAnyExcluding(T preclude) {
   1.423 +        JS_ASSERT(!empty());
   1.424 +        if (!has(preclude))
   1.425 +            return getAny();
   1.426 +
   1.427 +        take(preclude);
   1.428 +        JS_ASSERT(!empty());
   1.429 +        T result = getAny();
   1.430 +        add(preclude);
   1.431 +        return result;
   1.432 +    }
   1.433 +    T getFirst() const {
   1.434 +        JS_ASSERT(!empty());
   1.435 +        return T::FromCode(mozilla::CountTrailingZeroes32(bits_));
   1.436 +    }
   1.437 +    T getLast() const {
   1.438 +        JS_ASSERT(!empty());
   1.439 +        int ireg = 31 - mozilla::CountLeadingZeroes32(bits_);
   1.440 +        return T::FromCode(ireg);
   1.441 +    }
   1.442 +    T takeAny() {
   1.443 +        JS_ASSERT(!empty());
   1.444 +        T reg = getAny();
   1.445 +        take(reg);
   1.446 +        return reg;
   1.447 +    }
   1.448 +    T takeAnyExcluding(T preclude) {
   1.449 +        T reg = getAnyExcluding(preclude);
   1.450 +        take(reg);
   1.451 +        return reg;
   1.452 +    }
   1.453 +    ValueOperand takeAnyValue() {
   1.454 +#if defined(JS_NUNBOX32)
   1.455 +        T type = takeAny();
   1.456 +        T payload = takeAny();
   1.457 +        return ValueOperand(type, payload);
   1.458 +#elif defined(JS_PUNBOX64)
   1.459 +        T reg = takeAny();
   1.460 +        return ValueOperand(reg);
   1.461 +#else
   1.462 +#error "Bad architecture"
   1.463 +#endif
   1.464 +    }
   1.465 +    T takeFirst() {
   1.466 +        JS_ASSERT(!empty());
   1.467 +        T reg = getFirst();
   1.468 +        take(reg);
   1.469 +        return reg;
   1.470 +    }
   1.471 +    T takeLast() {
   1.472 +        JS_ASSERT(!empty());
   1.473 +        T reg = getLast();
   1.474 +        take(reg);
   1.475 +        return reg;
   1.476 +    }
   1.477 +    void clear() {
   1.478 +        bits_ = 0;
   1.479 +    }
   1.480 +    uint32_t bits() const {
   1.481 +        return bits_;
   1.482 +    }
   1.483 +    uint32_t size() const {
   1.484 +        return mozilla::CountPopulation32(bits_);
   1.485 +    }
   1.486 +    bool operator ==(const TypedRegisterSet<T> &other) const {
   1.487 +        return other.bits_ == bits_;
   1.488 +    }
   1.489 +};
   1.490 +
   1.491 +typedef TypedRegisterSet<Register> GeneralRegisterSet;
   1.492 +typedef TypedRegisterSet<FloatRegister> FloatRegisterSet;
   1.493 +
   1.494 +class AnyRegisterIterator;
   1.495 +
   1.496 +class RegisterSet {
   1.497 +    GeneralRegisterSet gpr_;
   1.498 +    FloatRegisterSet fpu_;
   1.499 +
   1.500 +    friend class AnyRegisterIterator;
   1.501 +
   1.502 +  public:
   1.503 +    RegisterSet()
   1.504 +    { }
   1.505 +    MOZ_CONSTEXPR RegisterSet(const GeneralRegisterSet &gpr, const FloatRegisterSet &fpu)
   1.506 +      : gpr_(gpr),
   1.507 +        fpu_(fpu)
   1.508 +    { }
   1.509 +    static inline RegisterSet All() {
   1.510 +        return RegisterSet(GeneralRegisterSet::All(), FloatRegisterSet::All());
   1.511 +    }
   1.512 +    static inline RegisterSet Intersect(const RegisterSet &lhs, const RegisterSet &rhs) {
   1.513 +        return RegisterSet(GeneralRegisterSet::Intersect(lhs.gpr_, rhs.gpr_),
   1.514 +                           FloatRegisterSet::Intersect(lhs.fpu_, rhs.fpu_));
   1.515 +    }
   1.516 +    static inline RegisterSet Union(const RegisterSet &lhs, const RegisterSet &rhs) {
   1.517 +        return RegisterSet(GeneralRegisterSet::Union(lhs.gpr_, rhs.gpr_),
   1.518 +                           FloatRegisterSet::Union(lhs.fpu_, rhs.fpu_));
   1.519 +    }
   1.520 +    static inline RegisterSet Not(const RegisterSet &in) {
   1.521 +        return RegisterSet(GeneralRegisterSet::Not(in.gpr_),
   1.522 +                           FloatRegisterSet::Not(in.fpu_));
   1.523 +    }
   1.524 +    static inline RegisterSet VolatileNot(const RegisterSet &in) {
   1.525 +        return RegisterSet(GeneralRegisterSet::VolatileNot(in.gpr_),
   1.526 +                           FloatRegisterSet::VolatileNot(in.fpu_));
   1.527 +    }
   1.528 +    static inline RegisterSet Volatile() {
   1.529 +        return RegisterSet(GeneralRegisterSet::Volatile(), FloatRegisterSet::Volatile());
   1.530 +    }
   1.531 +    bool has(Register reg) const {
   1.532 +        return gpr_.has(reg);
   1.533 +    }
   1.534 +    bool has(FloatRegister reg) const {
   1.535 +        return fpu_.has(reg);
   1.536 +    }
   1.537 +    bool has(AnyRegister reg) const {
   1.538 +        return reg.isFloat() ? has(reg.fpu()) : has(reg.gpr());
   1.539 +    }
   1.540 +    void add(Register reg) {
   1.541 +        gpr_.add(reg);
   1.542 +    }
   1.543 +    void add(FloatRegister reg) {
   1.544 +        fpu_.add(reg);
   1.545 +    }
   1.546 +    void add(const AnyRegister &any) {
   1.547 +        if (any.isFloat())
   1.548 +            add(any.fpu());
   1.549 +        else
   1.550 +            add(any.gpr());
   1.551 +    }
   1.552 +    void add(ValueOperand value) {
   1.553 +#if defined(JS_NUNBOX32)
   1.554 +        add(value.payloadReg());
   1.555 +        add(value.typeReg());
   1.556 +#elif defined(JS_PUNBOX64)
   1.557 +        add(value.valueReg());
   1.558 +#else
   1.559 +#error "Bad architecture"
   1.560 +#endif
   1.561 +    }
   1.562 +    void add(TypedOrValueRegister reg) {
   1.563 +        if (reg.hasValue())
   1.564 +            add(reg.valueReg());
   1.565 +        else if (reg.hasTyped())
   1.566 +            add(reg.typedReg());
   1.567 +    }
   1.568 +    void addUnchecked(Register reg) {
   1.569 +        gpr_.addUnchecked(reg);
   1.570 +    }
   1.571 +    void addUnchecked(FloatRegister reg) {
   1.572 +        fpu_.addUnchecked(reg);
   1.573 +    }
   1.574 +    void addUnchecked(const AnyRegister &any) {
   1.575 +        if (any.isFloat())
   1.576 +            addUnchecked(any.fpu());
   1.577 +        else
   1.578 +            addUnchecked(any.gpr());
   1.579 +    }
   1.580 +    bool empty(bool floats) const {
   1.581 +        return floats ? fpu_.empty() : gpr_.empty();
   1.582 +    }
   1.583 +    FloatRegister takeFloat() {
   1.584 +        return fpu_.takeAny();
   1.585 +    }
   1.586 +    Register takeGeneral() {
   1.587 +        return gpr_.takeAny();
   1.588 +    }
   1.589 +    ValueOperand takeValueOperand() {
   1.590 +#if defined(JS_NUNBOX32)
   1.591 +        return ValueOperand(takeGeneral(), takeGeneral());
   1.592 +#elif defined(JS_PUNBOX64)
   1.593 +        return ValueOperand(takeGeneral());
   1.594 +#else
   1.595 +#error "Bad architecture"
   1.596 +#endif
   1.597 +    }
   1.598 +    void take(const AnyRegister &reg) {
   1.599 +        if (reg.isFloat())
   1.600 +            fpu_.take(reg.fpu());
   1.601 +        else
   1.602 +            gpr_.take(reg.gpr());
   1.603 +    }
   1.604 +    AnyRegister takeAny(bool isFloat) {
   1.605 +        if (isFloat)
   1.606 +            return AnyRegister(takeFloat());
   1.607 +        return AnyRegister(takeGeneral());
   1.608 +    }
   1.609 +    void clear() {
   1.610 +        gpr_.clear();
   1.611 +        fpu_.clear();
   1.612 +    }
   1.613 +    MOZ_CONSTEXPR GeneralRegisterSet gprs() const {
   1.614 +        return gpr_;
   1.615 +    }
   1.616 +    MOZ_CONSTEXPR FloatRegisterSet fpus() const {
   1.617 +        return fpu_;
   1.618 +    }
   1.619 +    bool operator ==(const RegisterSet &other) const {
   1.620 +        return other.gpr_ == gpr_ && other.fpu_ == fpu_;
   1.621 +    }
   1.622 +
   1.623 +    void takeUnchecked(Register reg) {
   1.624 +        gpr_.takeUnchecked(reg);
   1.625 +    }
   1.626 +    void takeUnchecked(FloatRegister reg) {
   1.627 +        fpu_.takeUnchecked(reg);
   1.628 +    }
   1.629 +    void takeUnchecked(AnyRegister reg) {
   1.630 +        if (reg.isFloat())
   1.631 +            fpu_.takeUnchecked(reg.fpu());
   1.632 +        else
   1.633 +            gpr_.takeUnchecked(reg.gpr());
   1.634 +    }
   1.635 +    void takeUnchecked(ValueOperand value) {
   1.636 +        gpr_.takeUnchecked(value);
   1.637 +    }
   1.638 +    void takeUnchecked(TypedOrValueRegister reg) {
   1.639 +        if (reg.hasValue())
   1.640 +            takeUnchecked(reg.valueReg());
   1.641 +        else if (reg.hasTyped())
   1.642 +            takeUnchecked(reg.typedReg());
   1.643 +    }
   1.644 +};
   1.645 +
   1.646 +// iterates in whatever order happens to be convenient.
   1.647 +// Use TypedRegisterBackwardIterator or TypedRegisterForwardIterator if a
   1.648 +// specific order is required.
   1.649 +template <typename T>
   1.650 +class TypedRegisterIterator
   1.651 +{
   1.652 +    TypedRegisterSet<T> regset_;
   1.653 +
   1.654 +  public:
   1.655 +    TypedRegisterIterator(TypedRegisterSet<T> regset) : regset_(regset)
   1.656 +    { }
   1.657 +    TypedRegisterIterator(const TypedRegisterIterator &other) : regset_(other.regset_)
   1.658 +    { }
   1.659 +
   1.660 +    bool more() const {
   1.661 +        return !regset_.empty();
   1.662 +    }
   1.663 +    TypedRegisterIterator<T> operator ++(int) {
   1.664 +        TypedRegisterIterator<T> old(*this);
   1.665 +        regset_.takeAny();
   1.666 +        return old;
   1.667 +    }
   1.668 +    TypedRegisterIterator<T>& operator ++() {
   1.669 +        regset_.takeAny();
   1.670 +        return *this;
   1.671 +    }
   1.672 +    T operator *() const {
   1.673 +        return regset_.getAny();
   1.674 +    }
   1.675 +};
   1.676 +
   1.677 +// iterates backwards, that is, rn to r0
   1.678 +template <typename T>
   1.679 +class TypedRegisterBackwardIterator
   1.680 +{
   1.681 +    TypedRegisterSet<T> regset_;
   1.682 +
   1.683 +  public:
   1.684 +    TypedRegisterBackwardIterator(TypedRegisterSet<T> regset) : regset_(regset)
   1.685 +    { }
   1.686 +    TypedRegisterBackwardIterator(const TypedRegisterBackwardIterator &other)
   1.687 +      : regset_(other.regset_)
   1.688 +    { }
   1.689 +
   1.690 +    bool more() const {
   1.691 +        return !regset_.empty();
   1.692 +    }
   1.693 +    TypedRegisterBackwardIterator<T> operator ++(int) {
   1.694 +        TypedRegisterBackwardIterator<T> old(*this);
   1.695 +        regset_.takeLast();
   1.696 +        return old;
   1.697 +    }
   1.698 +    TypedRegisterBackwardIterator<T>& operator ++() {
   1.699 +        regset_.takeLast();
   1.700 +        return *this;
   1.701 +    }
   1.702 +    T operator *() const {
   1.703 +        return regset_.getLast();
   1.704 +    }
   1.705 +};
   1.706 +
   1.707 +// iterates forwards, that is r0 to rn
   1.708 +template <typename T>
   1.709 +class TypedRegisterForwardIterator
   1.710 +{
   1.711 +    TypedRegisterSet<T> regset_;
   1.712 +
   1.713 +  public:
   1.714 +    TypedRegisterForwardIterator(TypedRegisterSet<T> regset) : regset_(regset)
   1.715 +    { }
   1.716 +    TypedRegisterForwardIterator(const TypedRegisterForwardIterator &other) : regset_(other.regset_)
   1.717 +    { }
   1.718 +
   1.719 +    bool more() const {
   1.720 +        return !regset_.empty();
   1.721 +    }
   1.722 +    TypedRegisterForwardIterator<T> operator ++(int) {
   1.723 +        TypedRegisterForwardIterator<T> old(*this);
   1.724 +        regset_.takeFirst();
   1.725 +        return old;
   1.726 +    }
   1.727 +    TypedRegisterForwardIterator<T>& operator ++() {
   1.728 +        regset_.takeFirst();
   1.729 +        return *this;
   1.730 +    }
   1.731 +    T operator *() const {
   1.732 +        return regset_.getFirst();
   1.733 +    }
   1.734 +};
   1.735 +
   1.736 +typedef TypedRegisterIterator<Register> GeneralRegisterIterator;
   1.737 +typedef TypedRegisterIterator<FloatRegister> FloatRegisterIterator;
   1.738 +typedef TypedRegisterBackwardIterator<Register> GeneralRegisterBackwardIterator;
   1.739 +typedef TypedRegisterBackwardIterator<FloatRegister> FloatRegisterBackwardIterator;
   1.740 +typedef TypedRegisterForwardIterator<Register> GeneralRegisterForwardIterator;
   1.741 +typedef TypedRegisterForwardIterator<FloatRegister> FloatRegisterForwardIterator;
   1.742 +
   1.743 +class AnyRegisterIterator
   1.744 +{
   1.745 +    GeneralRegisterIterator geniter_;
   1.746 +    FloatRegisterIterator floatiter_;
   1.747 +
   1.748 +  public:
   1.749 +    AnyRegisterIterator()
   1.750 +      : geniter_(GeneralRegisterSet::All()), floatiter_(FloatRegisterSet::All())
   1.751 +    { }
   1.752 +    AnyRegisterIterator(GeneralRegisterSet genset, FloatRegisterSet floatset)
   1.753 +      : geniter_(genset), floatiter_(floatset)
   1.754 +    { }
   1.755 +    AnyRegisterIterator(const RegisterSet &set)
   1.756 +      : geniter_(set.gpr_), floatiter_(set.fpu_)
   1.757 +    { }
   1.758 +    AnyRegisterIterator(const AnyRegisterIterator &other)
   1.759 +      : geniter_(other.geniter_), floatiter_(other.floatiter_)
   1.760 +    { }
   1.761 +    bool more() const {
   1.762 +        return geniter_.more() || floatiter_.more();
   1.763 +    }
   1.764 +    AnyRegisterIterator operator ++(int) {
   1.765 +        AnyRegisterIterator old(*this);
   1.766 +        if (geniter_.more())
   1.767 +            geniter_++;
   1.768 +        else
   1.769 +            floatiter_++;
   1.770 +        return old;
   1.771 +    }
   1.772 +    AnyRegister operator *() const {
   1.773 +        if (geniter_.more())
   1.774 +            return AnyRegister(*geniter_);
   1.775 +        return AnyRegister(*floatiter_);
   1.776 +    }
   1.777 +};
   1.778 +
   1.779 +class ABIArg
   1.780 +{
   1.781 +  public:
   1.782 +    enum Kind { GPR, FPU, Stack };
   1.783 +
   1.784 +  private:
   1.785 +    Kind kind_;
   1.786 +    union {
   1.787 +        Registers::Code gpr_;
   1.788 +        FloatRegisters::Code fpu_;
   1.789 +        uint32_t offset_;
   1.790 +    } u;
   1.791 +
   1.792 +  public:
   1.793 +    ABIArg() : kind_(Kind(-1)) { u.offset_ = -1; }
   1.794 +    ABIArg(Register gpr) : kind_(GPR) { u.gpr_ = gpr.code(); }
   1.795 +    ABIArg(FloatRegister fpu) : kind_(FPU) { u.fpu_ = fpu.code(); }
   1.796 +    ABIArg(uint32_t offset) : kind_(Stack) { u.offset_ = offset; }
   1.797 +
   1.798 +    Kind kind() const { return kind_; }
   1.799 +    Register gpr() const { JS_ASSERT(kind() == GPR); return Register::FromCode(u.gpr_); }
   1.800 +    FloatRegister fpu() const { JS_ASSERT(kind() == FPU); return FloatRegister::FromCode(u.fpu_); }
   1.801 +    uint32_t offsetFromArgBase() const { JS_ASSERT(kind() == Stack); return u.offset_; }
   1.802 +
   1.803 +    bool argInRegister() const { return kind() != Stack; }
   1.804 +    AnyRegister reg() const { return kind_ == GPR ? AnyRegister(gpr()) : AnyRegister(fpu()); }
   1.805 +};
   1.806 +
   1.807 +} // namespace jit
   1.808 +} // namespace js
   1.809 +
   1.810 +#endif /* jit_RegisterSets_h */

mercurial