michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jit_RegisterSets_h michael@0: #define jit_RegisterSets_h michael@0: michael@0: #include "mozilla/Alignment.h" michael@0: #include "mozilla/MathAlgorithms.h" michael@0: michael@0: #include "jit/IonAllocPolicy.h" michael@0: #include "jit/Registers.h" michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: struct AnyRegister { michael@0: typedef uint32_t Code; michael@0: michael@0: static const uint32_t Total = Registers::Total + FloatRegisters::Total; michael@0: static const uint32_t Invalid = UINT_MAX; michael@0: michael@0: union { michael@0: Registers::Code gpr_; michael@0: FloatRegisters::Code fpu_; michael@0: }; michael@0: bool isFloat_; michael@0: michael@0: AnyRegister() michael@0: { } michael@0: explicit AnyRegister(Register gpr) { michael@0: gpr_ = gpr.code(); michael@0: isFloat_ = false; michael@0: } michael@0: explicit AnyRegister(FloatRegister fpu) { michael@0: fpu_ = fpu.code(); michael@0: isFloat_ = true; michael@0: } michael@0: static AnyRegister FromCode(uint32_t i) { michael@0: JS_ASSERT(i < Total); michael@0: AnyRegister r; michael@0: if (i < Registers::Total) { michael@0: r.gpr_ = Register::Code(i); michael@0: r.isFloat_ = false; michael@0: } else { michael@0: r.fpu_ = FloatRegister::Code(i - Registers::Total); michael@0: r.isFloat_ = true; michael@0: } michael@0: return r; michael@0: } michael@0: bool isFloat() const { michael@0: return isFloat_; michael@0: } michael@0: Register gpr() const { michael@0: JS_ASSERT(!isFloat()); michael@0: return Register::FromCode(gpr_); michael@0: } michael@0: FloatRegister fpu() const { michael@0: JS_ASSERT(isFloat()); michael@0: return FloatRegister::FromCode(fpu_); michael@0: } michael@0: bool operator ==(const AnyRegister &other) const { michael@0: return isFloat() michael@0: ? (other.isFloat() && fpu_ == other.fpu_) michael@0: : (!other.isFloat() && gpr_ == other.gpr_); michael@0: } michael@0: bool operator !=(const AnyRegister &other) const { michael@0: return isFloat() michael@0: ? (!other.isFloat() || fpu_ != other.fpu_) michael@0: : (other.isFloat() || gpr_ != other.gpr_); michael@0: } michael@0: const char *name() const { michael@0: return isFloat() michael@0: ? FloatRegister::FromCode(fpu_).name() michael@0: : Register::FromCode(gpr_).name(); michael@0: } michael@0: const Code code() const { michael@0: return isFloat() michael@0: ? fpu_ + Registers::Total michael@0: : gpr_; michael@0: } michael@0: bool volatile_() const { michael@0: return isFloat() ? fpu().volatile_() : gpr().volatile_(); michael@0: } michael@0: }; michael@0: michael@0: // Registers to hold a boxed value. Uses one register on 64 bit michael@0: // platforms, two registers on 32 bit platforms. michael@0: class ValueOperand michael@0: { michael@0: #if defined(JS_NUNBOX32) michael@0: Register type_; michael@0: Register payload_; michael@0: michael@0: public: michael@0: MOZ_CONSTEXPR ValueOperand(Register type, Register payload) michael@0: : type_(type), payload_(payload) michael@0: { } michael@0: michael@0: Register typeReg() const { michael@0: return type_; michael@0: } michael@0: Register payloadReg() const { michael@0: return payload_; michael@0: } michael@0: michael@0: Register scratchReg() const { michael@0: return payloadReg(); michael@0: } michael@0: bool operator==(const ValueOperand &o) const { michael@0: return type_ == o.type_ && payload_ == o.payload_; michael@0: } michael@0: bool operator!=(const ValueOperand &o) const { michael@0: return !(*this == o); michael@0: } michael@0: michael@0: #elif defined(JS_PUNBOX64) michael@0: Register value_; michael@0: michael@0: public: michael@0: explicit MOZ_CONSTEXPR ValueOperand(Register value) michael@0: : value_(value) michael@0: { } michael@0: michael@0: Register valueReg() const { michael@0: return value_; michael@0: } michael@0: michael@0: Register scratchReg() const { michael@0: return valueReg(); michael@0: } michael@0: bool operator==(const ValueOperand &o) const { michael@0: return value_ == o.value_; michael@0: } michael@0: bool operator!=(const ValueOperand &o) const { michael@0: return !(*this == o); michael@0: } michael@0: #endif michael@0: michael@0: ValueOperand() {} michael@0: }; michael@0: michael@0: // Registers to hold either either a typed or untyped value. michael@0: class TypedOrValueRegister michael@0: { michael@0: // Type of value being stored. michael@0: MIRType type_; michael@0: michael@0: // Space to hold either an AnyRegister or a ValueOperand. michael@0: union U { michael@0: mozilla::AlignedStorage2 typed; michael@0: mozilla::AlignedStorage2 value; michael@0: } data; michael@0: michael@0: AnyRegister &dataTyped() { michael@0: JS_ASSERT(hasTyped()); michael@0: return *data.typed.addr(); michael@0: } michael@0: ValueOperand &dataValue() { michael@0: JS_ASSERT(hasValue()); michael@0: return *data.value.addr(); michael@0: } michael@0: michael@0: const AnyRegister &dataTyped() const { michael@0: JS_ASSERT(hasTyped()); michael@0: return *data.typed.addr(); michael@0: } michael@0: const ValueOperand &dataValue() const { michael@0: JS_ASSERT(hasValue()); michael@0: return *data.value.addr(); michael@0: } michael@0: michael@0: public: michael@0: michael@0: TypedOrValueRegister() michael@0: : type_(MIRType_None) michael@0: {} michael@0: michael@0: TypedOrValueRegister(MIRType type, AnyRegister reg) michael@0: : type_(type) michael@0: { michael@0: dataTyped() = reg; michael@0: } michael@0: michael@0: TypedOrValueRegister(ValueOperand value) michael@0: : type_(MIRType_Value) michael@0: { michael@0: dataValue() = value; michael@0: } michael@0: michael@0: MIRType type() const { michael@0: return type_; michael@0: } michael@0: michael@0: bool hasTyped() const { michael@0: return type() != MIRType_None && type() != MIRType_Value; michael@0: } michael@0: michael@0: bool hasValue() const { michael@0: return type() == MIRType_Value; michael@0: } michael@0: michael@0: AnyRegister typedReg() const { michael@0: return dataTyped(); michael@0: } michael@0: michael@0: ValueOperand valueReg() const { michael@0: return dataValue(); michael@0: } michael@0: michael@0: AnyRegister scratchReg() { michael@0: if (hasValue()) michael@0: return AnyRegister(valueReg().scratchReg()); michael@0: return typedReg(); michael@0: } michael@0: }; michael@0: michael@0: // A constant value, or registers to hold a typed/untyped value. michael@0: class ConstantOrRegister michael@0: { michael@0: // Whether a constant value is being stored. michael@0: bool constant_; michael@0: michael@0: // Space to hold either a Value or a TypedOrValueRegister. michael@0: union U { michael@0: mozilla::AlignedStorage2 constant; michael@0: mozilla::AlignedStorage2 reg; michael@0: } data; michael@0: michael@0: Value &dataValue() { michael@0: JS_ASSERT(constant()); michael@0: return *data.constant.addr(); michael@0: } michael@0: TypedOrValueRegister &dataReg() { michael@0: JS_ASSERT(!constant()); michael@0: return *data.reg.addr(); michael@0: } michael@0: michael@0: public: michael@0: michael@0: ConstantOrRegister() michael@0: {} michael@0: michael@0: ConstantOrRegister(Value value) michael@0: : constant_(true) michael@0: { michael@0: dataValue() = value; michael@0: } michael@0: michael@0: ConstantOrRegister(TypedOrValueRegister reg) michael@0: : constant_(false) michael@0: { michael@0: dataReg() = reg; michael@0: } michael@0: michael@0: bool constant() { michael@0: return constant_; michael@0: } michael@0: michael@0: Value value() { michael@0: return dataValue(); michael@0: } michael@0: michael@0: TypedOrValueRegister reg() { michael@0: return dataReg(); michael@0: } michael@0: }; michael@0: michael@0: struct Int32Key { michael@0: bool isRegister_; michael@0: union { michael@0: Register reg_; michael@0: int32_t constant_; michael@0: }; michael@0: michael@0: explicit Int32Key(Register reg) michael@0: : isRegister_(true), reg_(reg) michael@0: { } michael@0: michael@0: explicit Int32Key(int32_t index) michael@0: : isRegister_(false), constant_(index) michael@0: { } michael@0: michael@0: inline void bumpConstant(int diff) { michael@0: JS_ASSERT(!isRegister_); michael@0: constant_ += diff; michael@0: } michael@0: inline Register reg() const { michael@0: JS_ASSERT(isRegister_); michael@0: return reg_; michael@0: } michael@0: inline int32_t constant() const { michael@0: JS_ASSERT(!isRegister_); michael@0: return constant_; michael@0: } michael@0: inline bool isRegister() const { michael@0: return isRegister_; michael@0: } michael@0: inline bool isConstant() const { michael@0: return !isRegister_; michael@0: } michael@0: }; michael@0: michael@0: template michael@0: class TypedRegisterSet michael@0: { michael@0: uint32_t bits_; michael@0: michael@0: public: michael@0: explicit MOZ_CONSTEXPR TypedRegisterSet(uint32_t bits) michael@0: : bits_(bits) michael@0: { } michael@0: michael@0: MOZ_CONSTEXPR TypedRegisterSet() : bits_(0) michael@0: { } michael@0: MOZ_CONSTEXPR TypedRegisterSet(const TypedRegisterSet &set) : bits_(set.bits_) michael@0: { } michael@0: michael@0: static inline TypedRegisterSet All() { michael@0: return TypedRegisterSet(T::Codes::AllocatableMask); michael@0: } michael@0: static inline TypedRegisterSet Intersect(const TypedRegisterSet &lhs, michael@0: const TypedRegisterSet &rhs) { michael@0: return TypedRegisterSet(lhs.bits_ & rhs.bits_); michael@0: } michael@0: static inline TypedRegisterSet Union(const TypedRegisterSet &lhs, michael@0: const TypedRegisterSet &rhs) { michael@0: return TypedRegisterSet(lhs.bits_ | rhs.bits_); michael@0: } michael@0: static inline TypedRegisterSet Not(const TypedRegisterSet &in) { michael@0: return TypedRegisterSet(~in.bits_ & T::Codes::AllocatableMask); michael@0: } michael@0: static inline TypedRegisterSet VolatileNot(const TypedRegisterSet &in) { michael@0: const uint32_t allocatableVolatile = michael@0: T::Codes::AllocatableMask & T::Codes::VolatileMask; michael@0: return TypedRegisterSet(~in.bits_ & allocatableVolatile); michael@0: } michael@0: static inline TypedRegisterSet Volatile() { michael@0: return TypedRegisterSet(T::Codes::AllocatableMask & T::Codes::VolatileMask); michael@0: } michael@0: static inline TypedRegisterSet NonVolatile() { michael@0: return TypedRegisterSet(T::Codes::AllocatableMask & T::Codes::NonVolatileMask); michael@0: } michael@0: bool has(T reg) const { michael@0: return !!(bits_ & (1 << reg.code())); michael@0: } michael@0: void addUnchecked(T reg) { michael@0: bits_ |= (1 << reg.code()); michael@0: } michael@0: void add(T reg) { michael@0: JS_ASSERT(!has(reg)); michael@0: addUnchecked(reg); michael@0: } michael@0: void add(ValueOperand value) { michael@0: #if defined(JS_NUNBOX32) michael@0: add(value.payloadReg()); michael@0: add(value.typeReg()); michael@0: #elif defined(JS_PUNBOX64) michael@0: add(value.valueReg()); michael@0: #else michael@0: #error "Bad architecture" michael@0: #endif michael@0: } michael@0: // Determemine if some register are still allocated. This function should michael@0: // be used with the set of allocatable registers used for the initialization michael@0: // of the current set. michael@0: bool someAllocated(const TypedRegisterSet &allocatable) const { michael@0: return allocatable.bits_ & ~bits_; michael@0: } michael@0: bool empty() const { michael@0: return !bits_; michael@0: } michael@0: void take(T reg) { michael@0: JS_ASSERT(has(reg)); michael@0: takeUnchecked(reg); michael@0: } michael@0: void takeUnchecked(T reg) { michael@0: bits_ &= ~(1 << reg.code()); michael@0: } michael@0: void take(ValueOperand value) { michael@0: #if defined(JS_NUNBOX32) michael@0: take(value.payloadReg()); michael@0: take(value.typeReg()); michael@0: #elif defined(JS_PUNBOX64) michael@0: take(value.valueReg()); michael@0: #else michael@0: #error "Bad architecture" michael@0: #endif michael@0: } michael@0: void takeUnchecked(ValueOperand value) { michael@0: #if defined(JS_NUNBOX32) michael@0: takeUnchecked(value.payloadReg()); michael@0: takeUnchecked(value.typeReg()); michael@0: #elif defined(JS_PUNBOX64) michael@0: takeUnchecked(value.valueReg()); michael@0: #else michael@0: #error "Bad architecture" michael@0: #endif michael@0: } michael@0: ValueOperand takeValueOperand() { michael@0: #if defined(JS_NUNBOX32) michael@0: return ValueOperand(takeAny(), takeAny()); michael@0: #elif defined(JS_PUNBOX64) michael@0: return ValueOperand(takeAny()); michael@0: #else michael@0: #error "Bad architecture" michael@0: #endif michael@0: } michael@0: T getAny() const { michael@0: // The choice of first or last here is mostly arbitrary, as they are michael@0: // about the same speed on popular architectures. We choose first, as michael@0: // it has the advantage of using the "lower" registers more often. These michael@0: // registers are sometimes more efficient (e.g. optimized encodings for michael@0: // EAX on x86). michael@0: return getFirst(); michael@0: } michael@0: T getAnyExcluding(T preclude) { michael@0: JS_ASSERT(!empty()); michael@0: if (!has(preclude)) michael@0: return getAny(); michael@0: michael@0: take(preclude); michael@0: JS_ASSERT(!empty()); michael@0: T result = getAny(); michael@0: add(preclude); michael@0: return result; michael@0: } michael@0: T getFirst() const { michael@0: JS_ASSERT(!empty()); michael@0: return T::FromCode(mozilla::CountTrailingZeroes32(bits_)); michael@0: } michael@0: T getLast() const { michael@0: JS_ASSERT(!empty()); michael@0: int ireg = 31 - mozilla::CountLeadingZeroes32(bits_); michael@0: return T::FromCode(ireg); michael@0: } michael@0: T takeAny() { michael@0: JS_ASSERT(!empty()); michael@0: T reg = getAny(); michael@0: take(reg); michael@0: return reg; michael@0: } michael@0: T takeAnyExcluding(T preclude) { michael@0: T reg = getAnyExcluding(preclude); michael@0: take(reg); michael@0: return reg; michael@0: } michael@0: ValueOperand takeAnyValue() { michael@0: #if defined(JS_NUNBOX32) michael@0: T type = takeAny(); michael@0: T payload = takeAny(); michael@0: return ValueOperand(type, payload); michael@0: #elif defined(JS_PUNBOX64) michael@0: T reg = takeAny(); michael@0: return ValueOperand(reg); michael@0: #else michael@0: #error "Bad architecture" michael@0: #endif michael@0: } michael@0: T takeFirst() { michael@0: JS_ASSERT(!empty()); michael@0: T reg = getFirst(); michael@0: take(reg); michael@0: return reg; michael@0: } michael@0: T takeLast() { michael@0: JS_ASSERT(!empty()); michael@0: T reg = getLast(); michael@0: take(reg); michael@0: return reg; michael@0: } michael@0: void clear() { michael@0: bits_ = 0; michael@0: } michael@0: uint32_t bits() const { michael@0: return bits_; michael@0: } michael@0: uint32_t size() const { michael@0: return mozilla::CountPopulation32(bits_); michael@0: } michael@0: bool operator ==(const TypedRegisterSet &other) const { michael@0: return other.bits_ == bits_; michael@0: } michael@0: }; michael@0: michael@0: typedef TypedRegisterSet GeneralRegisterSet; michael@0: typedef TypedRegisterSet FloatRegisterSet; michael@0: michael@0: class AnyRegisterIterator; michael@0: michael@0: class RegisterSet { michael@0: GeneralRegisterSet gpr_; michael@0: FloatRegisterSet fpu_; michael@0: michael@0: friend class AnyRegisterIterator; michael@0: michael@0: public: michael@0: RegisterSet() michael@0: { } michael@0: MOZ_CONSTEXPR RegisterSet(const GeneralRegisterSet &gpr, const FloatRegisterSet &fpu) michael@0: : gpr_(gpr), michael@0: fpu_(fpu) michael@0: { } michael@0: static inline RegisterSet All() { michael@0: return RegisterSet(GeneralRegisterSet::All(), FloatRegisterSet::All()); michael@0: } michael@0: static inline RegisterSet Intersect(const RegisterSet &lhs, const RegisterSet &rhs) { michael@0: return RegisterSet(GeneralRegisterSet::Intersect(lhs.gpr_, rhs.gpr_), michael@0: FloatRegisterSet::Intersect(lhs.fpu_, rhs.fpu_)); michael@0: } michael@0: static inline RegisterSet Union(const RegisterSet &lhs, const RegisterSet &rhs) { michael@0: return RegisterSet(GeneralRegisterSet::Union(lhs.gpr_, rhs.gpr_), michael@0: FloatRegisterSet::Union(lhs.fpu_, rhs.fpu_)); michael@0: } michael@0: static inline RegisterSet Not(const RegisterSet &in) { michael@0: return RegisterSet(GeneralRegisterSet::Not(in.gpr_), michael@0: FloatRegisterSet::Not(in.fpu_)); michael@0: } michael@0: static inline RegisterSet VolatileNot(const RegisterSet &in) { michael@0: return RegisterSet(GeneralRegisterSet::VolatileNot(in.gpr_), michael@0: FloatRegisterSet::VolatileNot(in.fpu_)); michael@0: } michael@0: static inline RegisterSet Volatile() { michael@0: return RegisterSet(GeneralRegisterSet::Volatile(), FloatRegisterSet::Volatile()); michael@0: } michael@0: bool has(Register reg) const { michael@0: return gpr_.has(reg); michael@0: } michael@0: bool has(FloatRegister reg) const { michael@0: return fpu_.has(reg); michael@0: } michael@0: bool has(AnyRegister reg) const { michael@0: return reg.isFloat() ? has(reg.fpu()) : has(reg.gpr()); michael@0: } michael@0: void add(Register reg) { michael@0: gpr_.add(reg); michael@0: } michael@0: void add(FloatRegister reg) { michael@0: fpu_.add(reg); michael@0: } michael@0: void add(const AnyRegister &any) { michael@0: if (any.isFloat()) michael@0: add(any.fpu()); michael@0: else michael@0: add(any.gpr()); michael@0: } michael@0: void add(ValueOperand value) { michael@0: #if defined(JS_NUNBOX32) michael@0: add(value.payloadReg()); michael@0: add(value.typeReg()); michael@0: #elif defined(JS_PUNBOX64) michael@0: add(value.valueReg()); michael@0: #else michael@0: #error "Bad architecture" michael@0: #endif michael@0: } michael@0: void add(TypedOrValueRegister reg) { michael@0: if (reg.hasValue()) michael@0: add(reg.valueReg()); michael@0: else if (reg.hasTyped()) michael@0: add(reg.typedReg()); michael@0: } michael@0: void addUnchecked(Register reg) { michael@0: gpr_.addUnchecked(reg); michael@0: } michael@0: void addUnchecked(FloatRegister reg) { michael@0: fpu_.addUnchecked(reg); michael@0: } michael@0: void addUnchecked(const AnyRegister &any) { michael@0: if (any.isFloat()) michael@0: addUnchecked(any.fpu()); michael@0: else michael@0: addUnchecked(any.gpr()); michael@0: } michael@0: bool empty(bool floats) const { michael@0: return floats ? fpu_.empty() : gpr_.empty(); michael@0: } michael@0: FloatRegister takeFloat() { michael@0: return fpu_.takeAny(); michael@0: } michael@0: Register takeGeneral() { michael@0: return gpr_.takeAny(); michael@0: } michael@0: ValueOperand takeValueOperand() { michael@0: #if defined(JS_NUNBOX32) michael@0: return ValueOperand(takeGeneral(), takeGeneral()); michael@0: #elif defined(JS_PUNBOX64) michael@0: return ValueOperand(takeGeneral()); michael@0: #else michael@0: #error "Bad architecture" michael@0: #endif michael@0: } michael@0: void take(const AnyRegister ®) { michael@0: if (reg.isFloat()) michael@0: fpu_.take(reg.fpu()); michael@0: else michael@0: gpr_.take(reg.gpr()); michael@0: } michael@0: AnyRegister takeAny(bool isFloat) { michael@0: if (isFloat) michael@0: return AnyRegister(takeFloat()); michael@0: return AnyRegister(takeGeneral()); michael@0: } michael@0: void clear() { michael@0: gpr_.clear(); michael@0: fpu_.clear(); michael@0: } michael@0: MOZ_CONSTEXPR GeneralRegisterSet gprs() const { michael@0: return gpr_; michael@0: } michael@0: MOZ_CONSTEXPR FloatRegisterSet fpus() const { michael@0: return fpu_; michael@0: } michael@0: bool operator ==(const RegisterSet &other) const { michael@0: return other.gpr_ == gpr_ && other.fpu_ == fpu_; michael@0: } michael@0: michael@0: void takeUnchecked(Register reg) { michael@0: gpr_.takeUnchecked(reg); michael@0: } michael@0: void takeUnchecked(FloatRegister reg) { michael@0: fpu_.takeUnchecked(reg); michael@0: } michael@0: void takeUnchecked(AnyRegister reg) { michael@0: if (reg.isFloat()) michael@0: fpu_.takeUnchecked(reg.fpu()); michael@0: else michael@0: gpr_.takeUnchecked(reg.gpr()); michael@0: } michael@0: void takeUnchecked(ValueOperand value) { michael@0: gpr_.takeUnchecked(value); michael@0: } michael@0: void takeUnchecked(TypedOrValueRegister reg) { michael@0: if (reg.hasValue()) michael@0: takeUnchecked(reg.valueReg()); michael@0: else if (reg.hasTyped()) michael@0: takeUnchecked(reg.typedReg()); michael@0: } michael@0: }; michael@0: michael@0: // iterates in whatever order happens to be convenient. michael@0: // Use TypedRegisterBackwardIterator or TypedRegisterForwardIterator if a michael@0: // specific order is required. michael@0: template michael@0: class TypedRegisterIterator michael@0: { michael@0: TypedRegisterSet regset_; michael@0: michael@0: public: michael@0: TypedRegisterIterator(TypedRegisterSet regset) : regset_(regset) michael@0: { } michael@0: TypedRegisterIterator(const TypedRegisterIterator &other) : regset_(other.regset_) michael@0: { } michael@0: michael@0: bool more() const { michael@0: return !regset_.empty(); michael@0: } michael@0: TypedRegisterIterator operator ++(int) { michael@0: TypedRegisterIterator old(*this); michael@0: regset_.takeAny(); michael@0: return old; michael@0: } michael@0: TypedRegisterIterator& operator ++() { michael@0: regset_.takeAny(); michael@0: return *this; michael@0: } michael@0: T operator *() const { michael@0: return regset_.getAny(); michael@0: } michael@0: }; michael@0: michael@0: // iterates backwards, that is, rn to r0 michael@0: template michael@0: class TypedRegisterBackwardIterator michael@0: { michael@0: TypedRegisterSet regset_; michael@0: michael@0: public: michael@0: TypedRegisterBackwardIterator(TypedRegisterSet regset) : regset_(regset) michael@0: { } michael@0: TypedRegisterBackwardIterator(const TypedRegisterBackwardIterator &other) michael@0: : regset_(other.regset_) michael@0: { } michael@0: michael@0: bool more() const { michael@0: return !regset_.empty(); michael@0: } michael@0: TypedRegisterBackwardIterator operator ++(int) { michael@0: TypedRegisterBackwardIterator old(*this); michael@0: regset_.takeLast(); michael@0: return old; michael@0: } michael@0: TypedRegisterBackwardIterator& operator ++() { michael@0: regset_.takeLast(); michael@0: return *this; michael@0: } michael@0: T operator *() const { michael@0: return regset_.getLast(); michael@0: } michael@0: }; michael@0: michael@0: // iterates forwards, that is r0 to rn michael@0: template michael@0: class TypedRegisterForwardIterator michael@0: { michael@0: TypedRegisterSet regset_; michael@0: michael@0: public: michael@0: TypedRegisterForwardIterator(TypedRegisterSet regset) : regset_(regset) michael@0: { } michael@0: TypedRegisterForwardIterator(const TypedRegisterForwardIterator &other) : regset_(other.regset_) michael@0: { } michael@0: michael@0: bool more() const { michael@0: return !regset_.empty(); michael@0: } michael@0: TypedRegisterForwardIterator operator ++(int) { michael@0: TypedRegisterForwardIterator old(*this); michael@0: regset_.takeFirst(); michael@0: return old; michael@0: } michael@0: TypedRegisterForwardIterator& operator ++() { michael@0: regset_.takeFirst(); michael@0: return *this; michael@0: } michael@0: T operator *() const { michael@0: return regset_.getFirst(); michael@0: } michael@0: }; michael@0: michael@0: typedef TypedRegisterIterator GeneralRegisterIterator; michael@0: typedef TypedRegisterIterator FloatRegisterIterator; michael@0: typedef TypedRegisterBackwardIterator GeneralRegisterBackwardIterator; michael@0: typedef TypedRegisterBackwardIterator FloatRegisterBackwardIterator; michael@0: typedef TypedRegisterForwardIterator GeneralRegisterForwardIterator; michael@0: typedef TypedRegisterForwardIterator FloatRegisterForwardIterator; michael@0: michael@0: class AnyRegisterIterator michael@0: { michael@0: GeneralRegisterIterator geniter_; michael@0: FloatRegisterIterator floatiter_; michael@0: michael@0: public: michael@0: AnyRegisterIterator() michael@0: : geniter_(GeneralRegisterSet::All()), floatiter_(FloatRegisterSet::All()) michael@0: { } michael@0: AnyRegisterIterator(GeneralRegisterSet genset, FloatRegisterSet floatset) michael@0: : geniter_(genset), floatiter_(floatset) michael@0: { } michael@0: AnyRegisterIterator(const RegisterSet &set) michael@0: : geniter_(set.gpr_), floatiter_(set.fpu_) michael@0: { } michael@0: AnyRegisterIterator(const AnyRegisterIterator &other) michael@0: : geniter_(other.geniter_), floatiter_(other.floatiter_) michael@0: { } michael@0: bool more() const { michael@0: return geniter_.more() || floatiter_.more(); michael@0: } michael@0: AnyRegisterIterator operator ++(int) { michael@0: AnyRegisterIterator old(*this); michael@0: if (geniter_.more()) michael@0: geniter_++; michael@0: else michael@0: floatiter_++; michael@0: return old; michael@0: } michael@0: AnyRegister operator *() const { michael@0: if (geniter_.more()) michael@0: return AnyRegister(*geniter_); michael@0: return AnyRegister(*floatiter_); michael@0: } michael@0: }; michael@0: michael@0: class ABIArg michael@0: { michael@0: public: michael@0: enum Kind { GPR, FPU, Stack }; michael@0: michael@0: private: michael@0: Kind kind_; michael@0: union { michael@0: Registers::Code gpr_; michael@0: FloatRegisters::Code fpu_; michael@0: uint32_t offset_; michael@0: } u; michael@0: michael@0: public: michael@0: ABIArg() : kind_(Kind(-1)) { u.offset_ = -1; } michael@0: ABIArg(Register gpr) : kind_(GPR) { u.gpr_ = gpr.code(); } michael@0: ABIArg(FloatRegister fpu) : kind_(FPU) { u.fpu_ = fpu.code(); } michael@0: ABIArg(uint32_t offset) : kind_(Stack) { u.offset_ = offset; } michael@0: michael@0: Kind kind() const { return kind_; } michael@0: Register gpr() const { JS_ASSERT(kind() == GPR); return Register::FromCode(u.gpr_); } michael@0: FloatRegister fpu() const { JS_ASSERT(kind() == FPU); return FloatRegister::FromCode(u.fpu_); } michael@0: uint32_t offsetFromArgBase() const { JS_ASSERT(kind() == Stack); return u.offset_; } michael@0: michael@0: bool argInRegister() const { return kind() != Stack; } michael@0: AnyRegister reg() const { return kind_ == GPR ? AnyRegister(gpr()) : AnyRegister(fpu()); } michael@0: }; michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif /* jit_RegisterSets_h */