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 ®) { 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 */