Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef jit_RegisterSets_h
8 : #define jit_RegisterSets_h
9 :
10 : #include "mozilla/MathAlgorithms.h"
11 :
12 : #include "jit/JitAllocPolicy.h"
13 : #include "jit/Registers.h"
14 :
15 : namespace js {
16 : namespace jit {
17 :
18 : struct AnyRegister {
19 : typedef uint32_t Code;
20 :
21 : static const uint32_t Total = Registers::Total + FloatRegisters::Total;
22 : static const uint32_t Invalid = UINT_MAX;
23 :
24 : private:
25 : Code code_;
26 :
27 : public:
28 24055 : AnyRegister() = default;
29 :
30 34170 : explicit AnyRegister(Register gpr) {
31 34170 : code_ = gpr.code();
32 34170 : }
33 5594 : explicit AnyRegister(FloatRegister fpu) {
34 5594 : code_ = fpu.code() + Registers::Total;
35 5594 : }
36 572 : static AnyRegister FromCode(uint32_t i) {
37 572 : MOZ_ASSERT(i < Total);
38 572 : AnyRegister r;
39 572 : r.code_ = i;
40 572 : return r;
41 : }
42 192814 : bool isFloat() const {
43 192814 : return code_ >= Registers::Total;
44 : }
45 72719 : Register gpr() const {
46 72719 : MOZ_ASSERT(!isFloat());
47 72719 : return Register::FromCode(code_);
48 : }
49 2718 : FloatRegister fpu() const {
50 2718 : MOZ_ASSERT(isFloat());
51 2718 : return FloatRegister::FromCode(code_ - Registers::Total);
52 : }
53 30594 : bool operator ==(AnyRegister other) const {
54 30594 : return code_ == other.code_;
55 : }
56 : bool operator !=(AnyRegister other) const {
57 : return code_ != other.code_;
58 : }
59 5034 : const char* name() const {
60 5034 : return isFloat() ? fpu().name() : gpr().name();
61 : }
62 26012 : Code code() const {
63 26012 : return code_;
64 : }
65 : bool volatile_() const {
66 : return isFloat() ? fpu().volatile_() : gpr().volatile_();
67 : }
68 22971 : AnyRegister aliased(uint32_t aliasIdx) const {
69 22971 : AnyRegister ret;
70 22971 : if (isFloat()) {
71 123 : FloatRegister fret;
72 123 : fpu().aliased(aliasIdx, &fret);
73 123 : ret = AnyRegister(fret);
74 : } else {
75 22848 : Register gret;
76 22848 : gpr().aliased(aliasIdx, &gret);
77 22848 : ret = AnyRegister(gret);
78 : }
79 22971 : MOZ_ASSERT_IF(aliasIdx == 0, ret == *this);
80 22971 : return ret;
81 : }
82 41917 : uint32_t numAliased() const {
83 41917 : if (isFloat())
84 164 : return fpu().numAliased();
85 41753 : return gpr().numAliased();
86 : }
87 0 : bool aliases(const AnyRegister& other) const {
88 0 : if (isFloat() && other.isFloat())
89 0 : return fpu().aliases(other.fpu());
90 0 : if (!isFloat() && !other.isFloat())
91 0 : return gpr().aliases(other.gpr());
92 0 : return false;
93 : }
94 : // do the two registers hold the same type of data (e.g. both float32, both gpr)
95 : bool isCompatibleReg (const AnyRegister other) const {
96 : if (isFloat() && other.isFloat())
97 : return fpu().equiv(other.fpu());
98 : if (!isFloat() && !other.isFloat())
99 : return true;
100 : return false;
101 : }
102 :
103 : };
104 :
105 : // Registers to hold a boxed value. Uses one register on 64 bit
106 : // platforms, two registers on 32 bit platforms.
107 : class ValueOperand
108 : {
109 : #if defined(JS_NUNBOX32)
110 : Register type_;
111 : Register payload_;
112 :
113 : public:
114 : constexpr ValueOperand(Register type, Register payload)
115 : : type_(type), payload_(payload)
116 : { }
117 :
118 : Register typeReg() const {
119 : return type_;
120 : }
121 : Register payloadReg() const {
122 : return payload_;
123 : }
124 : bool aliases(Register reg) const {
125 : return type_ == reg || payload_ == reg;
126 : }
127 : Register scratchReg() const {
128 : return payloadReg();
129 : }
130 : bool operator==(const ValueOperand& o) const {
131 : return type_ == o.type_ && payload_ == o.payload_;
132 : }
133 : bool operator!=(const ValueOperand& o) const {
134 : return !(*this == o);
135 : }
136 :
137 : #elif defined(JS_PUNBOX64)
138 : Register value_;
139 :
140 : public:
141 683 : explicit constexpr ValueOperand(Register value)
142 683 : : value_(value)
143 683 : { }
144 :
145 118433 : Register valueReg() const {
146 118433 : return value_;
147 : }
148 282 : bool aliases(Register reg) const {
149 282 : return value_ == reg;
150 : }
151 21331 : Register scratchReg() const {
152 21331 : return valueReg();
153 : }
154 73076 : bool operator==(const ValueOperand& o) const {
155 73076 : return value_ == o.value_;
156 : }
157 : bool operator!=(const ValueOperand& o) const {
158 : return !(*this == o);
159 : }
160 : #endif
161 :
162 210 : ValueOperand() = default;
163 : };
164 :
165 : // Registers to hold either either a typed or untyped value.
166 : class TypedOrValueRegister
167 : {
168 : // Type of value being stored.
169 : MIRType type_;
170 :
171 453 : union U {
172 : AnyRegister typed;
173 : ValueOperand value;
174 : } data;
175 :
176 : public:
177 :
178 : TypedOrValueRegister() = default;
179 :
180 124 : TypedOrValueRegister(MIRType type, AnyRegister reg)
181 124 : : type_(type)
182 : {
183 124 : data.typed = reg;
184 124 : }
185 :
186 329 : MOZ_IMPLICIT TypedOrValueRegister(ValueOperand value)
187 329 : : type_(MIRType::Value)
188 : {
189 329 : data.value = value;
190 329 : }
191 :
192 2614 : MIRType type() const {
193 2614 : return type_;
194 : }
195 :
196 281 : bool hasTyped() const {
197 281 : return type() != MIRType::None && type() != MIRType::Value;
198 : }
199 :
200 1793 : bool hasValue() const {
201 1793 : return type() == MIRType::Value;
202 : }
203 :
204 213 : AnyRegister typedReg() const {
205 213 : MOZ_ASSERT(hasTyped());
206 213 : return data.typed;
207 : }
208 :
209 900 : ValueOperand valueReg() const {
210 900 : MOZ_ASSERT(hasValue());
211 900 : return data.value;
212 : }
213 :
214 : AnyRegister scratchReg() {
215 : if (hasValue())
216 : return AnyRegister(valueReg().scratchReg());
217 : return typedReg();
218 : }
219 : };
220 :
221 : // A constant value, or registers to hold a typed/untyped value.
222 : class ConstantOrRegister
223 : {
224 : // Whether a constant value is being stored.
225 : bool constant_;
226 :
227 : // Space to hold either a Value or a TypedOrValueRegister.
228 163 : union U {
229 : Value constant;
230 : TypedOrValueRegister reg;
231 : } data;
232 :
233 73 : const Value& dataValue() const {
234 73 : MOZ_ASSERT(constant());
235 73 : return data.constant;
236 : }
237 39 : void setDataValue(const Value& value) {
238 39 : MOZ_ASSERT(constant());
239 39 : data.constant = value;
240 39 : }
241 149 : const TypedOrValueRegister& dataReg() const {
242 149 : MOZ_ASSERT(!constant());
243 149 : return data.reg;
244 : }
245 122 : void setDataReg(const TypedOrValueRegister& reg) {
246 122 : MOZ_ASSERT(!constant());
247 122 : data.reg = reg;
248 122 : }
249 :
250 : public:
251 :
252 2 : ConstantOrRegister()
253 2 : {}
254 :
255 39 : MOZ_IMPLICIT ConstantOrRegister(const Value& value)
256 39 : : constant_(true)
257 : {
258 39 : setDataValue(value);
259 39 : }
260 :
261 122 : MOZ_IMPLICIT ConstantOrRegister(TypedOrValueRegister reg)
262 122 : : constant_(false)
263 : {
264 122 : setDataReg(reg);
265 122 : }
266 :
267 567 : bool constant() const {
268 567 : return constant_;
269 : }
270 :
271 73 : const Value& value() const {
272 73 : return dataValue();
273 : }
274 :
275 149 : const TypedOrValueRegister& reg() const {
276 149 : return dataReg();
277 : }
278 : };
279 :
280 : struct RegisterOrInt32Constant {
281 : bool isRegister_;
282 : union {
283 : Register reg_;
284 : int32_t constant_;
285 : };
286 :
287 3 : explicit RegisterOrInt32Constant(Register reg)
288 3 : : isRegister_(true), reg_(reg)
289 3 : { }
290 :
291 4 : explicit RegisterOrInt32Constant(int32_t index)
292 4 : : isRegister_(false), constant_(index)
293 4 : { }
294 :
295 8 : inline void bumpConstant(int diff) {
296 8 : MOZ_ASSERT(!isRegister_);
297 8 : constant_ += diff;
298 8 : }
299 10 : inline Register reg() const {
300 10 : MOZ_ASSERT(isRegister_);
301 10 : return reg_;
302 : }
303 4 : inline int32_t constant() const {
304 4 : MOZ_ASSERT(!isRegister_);
305 4 : return constant_;
306 : }
307 22 : inline bool isRegister() const {
308 22 : return isRegister_;
309 : }
310 0 : inline bool isConstant() const {
311 0 : return !isRegister_;
312 : }
313 : };
314 :
315 : template <typename T>
316 : class TypedRegisterSet
317 : {
318 : public:
319 : typedef T RegType;
320 : typedef typename T::SetType SetType;
321 :
322 : private:
323 : SetType bits_;
324 :
325 : public:
326 56808 : explicit constexpr TypedRegisterSet(SetType bits)
327 56808 : : bits_(bits)
328 56808 : { }
329 :
330 42510 : constexpr TypedRegisterSet() : bits_(0)
331 42510 : { }
332 857267 : constexpr TypedRegisterSet(const TypedRegisterSet<T>& set) : bits_(set.bits_)
333 857267 : { }
334 :
335 2340 : static inline TypedRegisterSet All() {
336 2340 : return TypedRegisterSet(T::Codes::AllocatableMask);
337 : }
338 168 : static inline TypedRegisterSet Intersect(const TypedRegisterSet& lhs,
339 : const TypedRegisterSet& rhs) {
340 168 : return TypedRegisterSet(lhs.bits_ & rhs.bits_);
341 : }
342 : static inline TypedRegisterSet Union(const TypedRegisterSet& lhs,
343 : const TypedRegisterSet& rhs) {
344 : return TypedRegisterSet(lhs.bits_ | rhs.bits_);
345 : }
346 42 : static inline TypedRegisterSet Not(const TypedRegisterSet& in) {
347 42 : return TypedRegisterSet(~in.bits_ & T::Codes::AllocatableMask);
348 : }
349 : static inline TypedRegisterSet Subtract(const TypedRegisterSet& lhs,
350 : const TypedRegisterSet& rhs)
351 : {
352 : return TypedRegisterSet(lhs.bits_ & ~rhs.bits_);
353 : }
354 0 : static inline TypedRegisterSet VolatileNot(const TypedRegisterSet& in) {
355 : const SetType allocatableVolatile =
356 0 : T::Codes::AllocatableMask & T::Codes::VolatileMask;
357 0 : return TypedRegisterSet(~in.bits_ & allocatableVolatile);
358 : }
359 25610 : static inline TypedRegisterSet Volatile() {
360 25610 : return TypedRegisterSet(T::Codes::AllocatableMask & T::Codes::VolatileMask);
361 : }
362 40 : static inline TypedRegisterSet NonVolatile() {
363 40 : return TypedRegisterSet(T::Codes::AllocatableMask & T::Codes::NonVolatileMask);
364 : }
365 :
366 589257 : bool empty() const {
367 589257 : return !bits_;
368 : }
369 1609 : void clear() {
370 1609 : bits_ = 0;
371 1609 : }
372 :
373 687225 : bool hasRegisterIndex(T reg) const {
374 687225 : return !!(bits_ & (SetType(1) << reg.code()));
375 : }
376 80489 : bool hasAllocatable(T reg) const {
377 80489 : return !(~bits_ & reg.alignedOrDominatedAliasedSet());
378 : }
379 :
380 3440 : void addRegisterIndex(T reg) {
381 3440 : bits_ |= (SetType(1) << reg.code());
382 3440 : }
383 27343 : void addAllocatable(T reg) {
384 27343 : bits_ |= reg.alignedOrDominatedAliasedSet();
385 27342 : }
386 :
387 :
388 515635 : void takeRegisterIndex(T reg) {
389 515635 : bits_ &= ~(SetType(1) << reg.code());
390 515625 : }
391 53606 : void takeAllocatable(T reg) {
392 53606 : bits_ &= ~reg.alignedOrDominatedAliasedSet();
393 53606 : }
394 :
395 : static constexpr RegTypeName DefaultType = RegType::DefaultType;
396 :
397 : template <RegTypeName Name>
398 1033689 : SetType allLive() const {
399 1033689 : return T::template LiveAsIndexableSet<Name>(bits_);
400 : }
401 : template <RegTypeName Name>
402 18961 : SetType allAllocatable() const {
403 18961 : return T::template AllocatableAsIndexableSet<Name>(bits_);
404 : }
405 :
406 207456 : static RegType FirstRegister(SetType set) {
407 207456 : return RegType::FromCode(RegType::FirstBit(set));
408 : }
409 845224 : static RegType LastRegister(SetType set) {
410 845224 : return RegType::FromCode(RegType::LastBit(set));
411 : }
412 :
413 56142 : SetType bits() const {
414 56142 : return bits_;
415 : }
416 45552 : uint32_t size() const {
417 45552 : return T::SetSize(bits_);
418 : }
419 : bool operator ==(const TypedRegisterSet<T>& other) const {
420 : return other.bits_ == bits_;
421 : }
422 23565 : TypedRegisterSet<T> reduceSetForPush() const {
423 23565 : return T::ReduceSetForPush(*this);
424 : }
425 22729 : uint32_t getPushSizeInBytes() const {
426 22729 : return T::GetPushSizeInBytes(*this);
427 : }
428 : };
429 :
430 : typedef TypedRegisterSet<Register> GeneralRegisterSet;
431 : typedef TypedRegisterSet<FloatRegister> FloatRegisterSet;
432 :
433 : class AnyRegisterIterator;
434 :
435 138455 : class RegisterSet {
436 : GeneralRegisterSet gpr_;
437 : FloatRegisterSet fpu_;
438 :
439 : friend class AnyRegisterIterator;
440 :
441 : public:
442 16134 : RegisterSet()
443 16134 : { }
444 12998 : constexpr RegisterSet(const GeneralRegisterSet& gpr, const FloatRegisterSet& fpu)
445 12998 : : gpr_(gpr),
446 12998 : fpu_(fpu)
447 12998 : { }
448 8 : static inline RegisterSet All() {
449 8 : return RegisterSet(GeneralRegisterSet::All(), FloatRegisterSet::All());
450 : }
451 4 : static inline RegisterSet Intersect(const RegisterSet& lhs, const RegisterSet& rhs) {
452 8 : return RegisterSet(GeneralRegisterSet::Intersect(lhs.gpr_, rhs.gpr_),
453 12 : FloatRegisterSet::Intersect(lhs.fpu_, rhs.fpu_));
454 : }
455 : static inline RegisterSet Union(const RegisterSet& lhs, const RegisterSet& rhs) {
456 : return RegisterSet(GeneralRegisterSet::Union(lhs.gpr_, rhs.gpr_),
457 : FloatRegisterSet::Union(lhs.fpu_, rhs.fpu_));
458 : }
459 0 : static inline RegisterSet Not(const RegisterSet& in) {
460 0 : return RegisterSet(GeneralRegisterSet::Not(in.gpr_),
461 0 : FloatRegisterSet::Not(in.fpu_));
462 : }
463 0 : static inline RegisterSet VolatileNot(const RegisterSet& in) {
464 0 : return RegisterSet(GeneralRegisterSet::VolatileNot(in.gpr_),
465 0 : FloatRegisterSet::VolatileNot(in.fpu_));
466 : }
467 12643 : static inline RegisterSet Volatile() {
468 12643 : return RegisterSet(GeneralRegisterSet::Volatile(), FloatRegisterSet::Volatile());
469 : }
470 :
471 : bool empty() const {
472 : return fpu_.empty() && gpr_.empty();
473 : }
474 : void clear() {
475 : fpu_.clear();
476 : gpr_.clear();
477 : }
478 11516 : bool emptyGeneral() const {
479 11516 : return gpr_.empty();
480 : }
481 406 : bool emptyFloat() const {
482 406 : return fpu_.empty();
483 : }
484 :
485 : static constexpr RegTypeName DefaultType = RegTypeName::GPR;
486 :
487 82607 : constexpr GeneralRegisterSet gprs() const {
488 82607 : return gpr_;
489 : }
490 113077 : GeneralRegisterSet& gprs() {
491 113077 : return gpr_;
492 : }
493 166407 : constexpr FloatRegisterSet fpus() const {
494 166407 : return fpu_;
495 : }
496 23180 : FloatRegisterSet& fpus() {
497 23180 : return fpu_;
498 : }
499 : bool operator ==(const RegisterSet& other) const {
500 : return other.gpr_ == gpr_ && other.fpu_ == fpu_;
501 : }
502 :
503 : };
504 :
505 : // There are 2 use cases for register sets:
506 : //
507 : // 1. To serve as a pool of allocatable register. This is useful for working
508 : // on the code produced by some stub where free registers are available, or
509 : // when we can release some registers.
510 : //
511 : // 2. To serve as a list of typed registers. This is useful for working with
512 : // live registers and to manipulate them with the proper instructions. This
513 : // is used by the register allocator to fill the Safepoints.
514 : //
515 : // These 2 uses cases can be used on top of 3 different backend representation
516 : // of register sets, which are either GeneralRegisterSet, FloatRegisterSet, or
517 : // RegisterSet (for both). These classes are used to store the bit sets to
518 : // represent each register.
519 : //
520 : // Each use case defines an Accessor class, such as AllocatableSetAccessor or
521 : // LiveSetAccessor, which is parameterized with the type of the register
522 : // set. These accessors are in charge of manipulating the register set in a
523 : // consistent way.
524 : //
525 : // The RegSetCommonInterface class is used to wrap the accessors with convenient
526 : // shortcuts which are based on the accessors.
527 : //
528 : // Then, to avoid to many levels of complexity while using these interfaces,
529 : // shortcut templates are created to make it easy to distinguish between a
530 : // register set used for allocating registers, or a register set used for making
531 : // a collection of allocated (live) registers.
532 : //
533 : // This separation exists to prevent mixing LiveSet and AllocatableSet
534 : // manipulations of the same register set, and ensure safety while avoiding
535 : // false positive.
536 :
537 : template <typename RegisterSet>
538 : class AllocatableSet;
539 :
540 : template <typename RegisterSet>
541 : class LiveSet;
542 :
543 : // Base accessors classes have the minimal set of raw methods to manipulate the register set
544 : // given as parameter in a consistent manner. These methods are:
545 : //
546 : // - all<Type>: Returns a bit-set of all the register of a specific type
547 : // which are present.
548 : //
549 : // - has: Returns if all the bits needed to take a register are present.
550 : //
551 : // - takeUnchecked: Subtracts the bits used to represent the register in the
552 : // register set.
553 : //
554 : // - addUnchecked: Adds the bits used to represent the register in the
555 : // register set.
556 :
557 : // The AllocatableSet accessors are used to make a pool of unused
558 : // registers. Taking or adding registers should consider the aliasing rules of
559 : // the architecture. For example, on ARM, the following piece of code should
560 : // work fine, knowing that the double register |d0| is composed of float
561 : // registers |s0| and |s1|:
562 : //
563 : // AllocatableFloatRegisterSet regs;
564 : // regs.add(s0);
565 : // regs.add(s1);
566 : // // d0 is now available.
567 : // regs.take(d0);
568 : //
569 : // These accessors are useful for allocating registers within the functions used
570 : // to generate stubs, trampolines, and inline caches (BaselineIC, IonCache).
571 : template <typename Set>
572 232 : class AllocatableSetAccessors
573 : {
574 : public:
575 : typedef Set RegSet;
576 : typedef typename RegSet::RegType RegType;
577 : typedef typename RegSet::SetType SetType;
578 :
579 : protected:
580 : RegSet set_;
581 :
582 : template <RegTypeName Name>
583 6432 : SetType all() const {
584 6432 : return set_.template allAllocatable<Name>();
585 : }
586 :
587 : public:
588 574 : AllocatableSetAccessors() : set_() {}
589 1643 : explicit constexpr AllocatableSetAccessors(SetType set) : set_(set) {}
590 2064 : explicit constexpr AllocatableSetAccessors(RegSet set) : set_(set) {}
591 :
592 16751 : bool has(RegType reg) const {
593 16751 : return set_.hasAllocatable(reg);
594 : }
595 :
596 : template <RegTypeName Name>
597 : bool hasAny(RegType reg) const {
598 : return all<Name>() != 0;
599 : }
600 :
601 1738 : void addUnchecked(RegType reg) {
602 1738 : set_.addAllocatable(reg);
603 1738 : }
604 :
605 12315 : void takeUnchecked(RegType reg) {
606 12315 : set_.takeAllocatable(reg);
607 12315 : }
608 : };
609 :
610 : // Specialization of the AllocatableSet accessors for the RegisterSet aggregate.
611 : template <>
612 : class AllocatableSetAccessors<RegisterSet>
613 : {
614 : public:
615 : typedef RegisterSet RegSet;
616 : typedef AnyRegister RegType;
617 : typedef char SetType;
618 :
619 : protected:
620 : RegisterSet set_;
621 :
622 : template <RegTypeName Name>
623 12529 : GeneralRegisterSet::SetType allGpr() const {
624 12529 : return set_.gprs().allAllocatable<Name>();
625 : }
626 : template <RegTypeName Name>
627 : FloatRegisterSet::SetType allFpu() const {
628 : return set_.fpus().allAllocatable<Name>();
629 : }
630 :
631 : public:
632 4503 : AllocatableSetAccessors() : set_() {}
633 : explicit constexpr AllocatableSetAccessors(SetType) = delete;
634 11909 : explicit constexpr AllocatableSetAccessors(RegisterSet set) : set_(set) {}
635 :
636 63681 : bool has(Register reg) const {
637 63681 : return set_.gprs().hasAllocatable(reg);
638 : }
639 56 : bool has(FloatRegister reg) const {
640 56 : return set_.fpus().hasAllocatable(reg);
641 : }
642 :
643 25577 : void addUnchecked(Register reg) {
644 25577 : set_.gprs().addAllocatable(reg);
645 25576 : }
646 28 : void addUnchecked(FloatRegister reg) {
647 28 : set_.fpus().addAllocatable(reg);
648 28 : }
649 :
650 41264 : void takeUnchecked(Register reg) {
651 41264 : set_.gprs().takeAllocatable(reg);
652 41264 : }
653 28 : void takeUnchecked(FloatRegister reg) {
654 28 : set_.fpus().takeAllocatable(reg);
655 28 : }
656 : };
657 :
658 :
659 : // The LiveSet accessors are used to collect a list of allocated
660 : // registers. Taking or adding a register should *not* consider the aliases, as
661 : // we care about interpreting the registers with the correct type. For example,
662 : // on x64, where one float registers can be interpreted as an Simd128, a Double,
663 : // or a Float, adding xmm0 as an Simd128, does not make the register available
664 : // as a Double.
665 : //
666 : // LiveFloatRegisterSet regs;
667 : // regs.add(xmm0.asSimd128());
668 : // regs.take(xmm0); // Assert!
669 : //
670 : // These accessors are useful for recording the result of a register allocator,
671 : // such as what the Backtracking allocator do on the Safepoints.
672 : template <typename Set>
673 6351 : class LiveSetAccessors
674 : {
675 : public:
676 : typedef Set RegSet;
677 : typedef typename RegSet::RegType RegType;
678 : typedef typename RegSet::SetType SetType;
679 :
680 : protected:
681 : RegSet set_;
682 :
683 : template <RegTypeName Name>
684 1033216 : SetType all() const {
685 1033216 : return set_.template allLive<Name>();
686 : }
687 :
688 : public:
689 839 : LiveSetAccessors() : set_() {}
690 : explicit constexpr LiveSetAccessors(SetType set) : set_(set) {}
691 48738 : explicit constexpr LiveSetAccessors(RegSet set) : set_(set) {}
692 :
693 519888 : bool has(RegType reg) const {
694 519888 : return set_.hasRegisterIndex(reg);
695 : }
696 :
697 2775 : void addUnchecked(RegType reg) {
698 2775 : set_.addRegisterIndex(reg);
699 2775 : }
700 :
701 515127 : void takeUnchecked(RegType reg) {
702 515127 : set_.takeRegisterIndex(reg);
703 515117 : }
704 : };
705 :
706 : // Specialization of the LiveSet accessors for the RegisterSet aggregate.
707 : template <>
708 33375 : class LiveSetAccessors<RegisterSet>
709 : {
710 : public:
711 : typedef RegisterSet RegSet;
712 : typedef AnyRegister RegType;
713 : typedef char SetType;
714 :
715 : protected:
716 : RegisterSet set_;
717 :
718 : template <RegTypeName Name>
719 112 : GeneralRegisterSet::SetType allGpr() const {
720 112 : return set_.gprs().allLive<Name>();
721 : }
722 : template <RegTypeName Name>
723 360 : FloatRegisterSet::SetType allFpu() const {
724 360 : return set_.fpus().allLive<Name>();
725 : }
726 :
727 : public:
728 11631 : LiveSetAccessors() : set_() {}
729 : explicit constexpr LiveSetAccessors(SetType) = delete;
730 11773 : explicit constexpr LiveSetAccessors(RegisterSet set) : set_(set) {}
731 :
732 1438 : bool has(Register reg) const {
733 1438 : return set_.gprs().hasRegisterIndex(reg);
734 : }
735 165911 : bool has(FloatRegister reg) const {
736 165911 : return set_.fpus().hasRegisterIndex(reg);
737 : }
738 :
739 647 : void addUnchecked(Register reg) {
740 647 : set_.gprs().addRegisterIndex(reg);
741 647 : }
742 18 : void addUnchecked(FloatRegister reg) {
743 18 : set_.fpus().addRegisterIndex(reg);
744 18 : }
745 :
746 148 : void takeUnchecked(Register reg) {
747 148 : set_.gprs().takeRegisterIndex(reg);
748 148 : }
749 360 : void takeUnchecked(FloatRegister reg) {
750 360 : set_.fpus().takeRegisterIndex(reg);
751 360 : }
752 : };
753 :
754 : #define DEFINE_ACCESSOR_CONSTRUCTORS_(REGSET) \
755 : typedef typename Parent::RegSet RegSet; \
756 : typedef typename Parent::RegType RegType; \
757 : typedef typename Parent::SetType SetType; \
758 : \
759 : constexpr REGSET() : Parent() {} \
760 : explicit constexpr REGSET(SetType set) : Parent(set) {} \
761 : explicit constexpr REGSET(RegSet set) : Parent(set) {}
762 :
763 : // This class adds checked accessors on top of the unchecked variants defined by
764 : // AllocatableSet and LiveSet accessors. Also it defines interface which are
765 : // specialized to the register set implementation, such as |getAny| and
766 : // |takeAny| variants.
767 : template <class Accessors, typename Set>
768 6583 : class SpecializedRegSet : public Accessors
769 : {
770 : typedef Accessors Parent;
771 :
772 : public:
773 53858 : DEFINE_ACCESSOR_CONSTRUCTORS_(SpecializedRegSet)
774 :
775 5080 : SetType bits() const {
776 5080 : return this->Parent::set_.bits();
777 : }
778 :
779 : using Parent::has;
780 :
781 : using Parent::addUnchecked;
782 4324 : void add(RegType reg) {
783 4324 : MOZ_ASSERT(!has(reg));
784 4324 : addUnchecked(reg);
785 4324 : }
786 :
787 : using Parent::takeUnchecked;
788 527081 : void take(RegType reg) {
789 527081 : MOZ_ASSERT(has(reg));
790 527081 : takeUnchecked(reg);
791 527071 : }
792 :
793 : template <RegTypeName Name>
794 0 : bool hasAny() const {
795 0 : return Parent::template all<Name>() != 0;
796 : }
797 :
798 : template <RegTypeName Name = RegSet::DefaultType>
799 194458 : RegType getFirst() const {
800 194458 : SetType set = Parent::template all<Name>();
801 194458 : MOZ_ASSERT(set);
802 194458 : return RegSet::FirstRegister(set);
803 : }
804 : template <RegTypeName Name = RegSet::DefaultType>
805 845224 : RegType getLast() const {
806 845224 : SetType set = Parent::template all<Name>();
807 845224 : MOZ_ASSERT(set);
808 845224 : return RegSet::LastRegister(set);
809 : }
810 : template <RegTypeName Name = RegSet::DefaultType>
811 15747 : RegType getAny() const {
812 : // The choice of first or last here is mostly arbitrary, as they are
813 : // about the same speed on popular architectures. We choose first, as
814 : // it has the advantage of using the "lower" registers more often. These
815 : // registers are sometimes more efficient (e.g. optimized encodings for
816 : // EAX on x86).
817 15747 : return getFirst<Name>();
818 : }
819 :
820 : template <RegTypeName Name = RegSet::DefaultType>
821 : RegType getAnyExcluding(RegType preclude) {
822 : if (!has(preclude))
823 : return getAny<Name>();
824 :
825 : take(preclude);
826 : RegType result = getAny<Name>();
827 : add(preclude);
828 : return result;
829 : }
830 :
831 : template <RegTypeName Name = RegSet::DefaultType>
832 6674 : RegType takeAny() {
833 6674 : RegType reg = getAny<Name>();
834 6674 : take(reg);
835 6674 : return reg;
836 : }
837 : template <RegTypeName Name = RegSet::DefaultType>
838 89360 : RegType takeFirst() {
839 89360 : RegType reg = getFirst<Name>();
840 89360 : take(reg);
841 89359 : return reg;
842 : }
843 : template <RegTypeName Name = RegSet::DefaultType>
844 422248 : RegType takeLast() {
845 422248 : RegType reg = getLast<Name>();
846 422306 : take(reg);
847 422300 : return reg;
848 : }
849 :
850 172 : ValueOperand takeAnyValue() {
851 : #if defined(JS_NUNBOX32)
852 : return ValueOperand(takeAny<RegTypeName::GPR>(), takeAny<RegTypeName::GPR>());
853 : #elif defined(JS_PUNBOX64)
854 172 : return ValueOperand(takeAny<RegTypeName::GPR>());
855 : #else
856 : #error "Bad architecture"
857 : #endif
858 : }
859 :
860 37 : bool aliases(ValueOperand v) const {
861 : #ifdef JS_NUNBOX32
862 : return has(v.typeReg()) || has(v.payloadReg());
863 : #else
864 37 : return has(v.valueReg());
865 : #endif
866 : }
867 :
868 : template <RegTypeName Name = RegSet::DefaultType>
869 : RegType takeAnyExcluding(RegType preclude) {
870 : RegType reg = getAnyExcluding<Name>(preclude);
871 : take(reg);
872 : return reg;
873 : }
874 : };
875 :
876 : // Specialization of the accessors for the RegisterSet aggregate.
877 : template <class Accessors>
878 33375 : class SpecializedRegSet<Accessors, RegisterSet> : public Accessors
879 : {
880 : typedef Accessors Parent;
881 :
882 : public:
883 39816 : DEFINE_ACCESSOR_CONSTRUCTORS_(SpecializedRegSet)
884 :
885 4848 : GeneralRegisterSet gprs() const {
886 4848 : return this->Parent::set_.gprs();
887 : }
888 45450 : GeneralRegisterSet& gprs() {
889 45450 : return this->Parent::set_.gprs();
890 : }
891 80 : FloatRegisterSet fpus() const {
892 80 : return this->Parent::set_.fpus();
893 : }
894 22746 : FloatRegisterSet& fpus() {
895 22746 : return this->Parent::set_.fpus();
896 : }
897 :
898 11516 : bool emptyGeneral() const {
899 11516 : return this->Parent::set_.emptyGeneral();
900 : }
901 406 : bool emptyFloat() const {
902 406 : return this->Parent::set_.emptyFloat();
903 : }
904 :
905 : using Parent::has;
906 401 : bool has(AnyRegister reg) const {
907 401 : return reg.isFloat() ? has(reg.fpu()) : has(reg.gpr());
908 : }
909 :
910 : template <RegTypeName Name>
911 : bool hasAny() const {
912 : if (Name == RegTypeName::GPR)
913 : return Parent::template allGpr<RegTypeName::GPR>() != 0;
914 : return Parent::template allFpu<Name>() != 0;
915 : }
916 :
917 : using Parent::addUnchecked;
918 527 : void addUnchecked(AnyRegister reg) {
919 527 : if (reg.isFloat())
920 17 : addUnchecked(reg.fpu());
921 : else
922 510 : addUnchecked(reg.gpr());
923 527 : }
924 :
925 25714 : void add(Register reg) {
926 25714 : MOZ_ASSERT(!has(reg));
927 25714 : addUnchecked(reg);
928 25713 : }
929 29 : void add(FloatRegister reg) {
930 29 : MOZ_ASSERT(!has(reg));
931 29 : addUnchecked(reg);
932 29 : }
933 6 : void add(AnyRegister reg) {
934 6 : if (reg.isFloat())
935 1 : add(reg.fpu());
936 : else
937 5 : add(reg.gpr());
938 6 : }
939 :
940 : using Parent::takeUnchecked;
941 : void takeUnchecked(AnyRegister reg) {
942 : if (reg.isFloat())
943 : takeUnchecked(reg.fpu());
944 : else
945 : takeUnchecked(reg.gpr());
946 : }
947 :
948 38218 : void take(Register reg) {
949 38218 : MOZ_ASSERT(has(reg));
950 38218 : takeUnchecked(reg);
951 38218 : }
952 388 : void take(FloatRegister reg) {
953 388 : MOZ_ASSERT(has(reg));
954 388 : takeUnchecked(reg);
955 388 : }
956 0 : void take(AnyRegister reg) {
957 0 : if (reg.isFloat())
958 0 : take(reg.fpu());
959 : else
960 0 : take(reg.gpr());
961 0 : }
962 :
963 12641 : Register getAnyGeneral() const {
964 12641 : GeneralRegisterSet::SetType set = Parent::template allGpr<RegTypeName::GPR>();
965 12641 : MOZ_ASSERT(set);
966 12641 : return GeneralRegisterSet::FirstRegister(set);
967 : }
968 : template <RegTypeName Name = RegTypeName::Float64>
969 360 : FloatRegister getAnyFloat() const {
970 360 : FloatRegisterSet::SetType set = Parent::template allFpu<Name>();
971 360 : MOZ_ASSERT(set);
972 360 : return FloatRegisterSet::FirstRegister(set);
973 : }
974 :
975 12641 : Register takeAnyGeneral() {
976 12641 : Register reg = getAnyGeneral();
977 12641 : take(reg);
978 12641 : return reg;
979 : }
980 : template <RegTypeName Name = RegTypeName::Float64>
981 360 : FloatRegister takeAnyFloat() {
982 360 : FloatRegister reg = getAnyFloat<Name>();
983 360 : take(reg);
984 360 : return reg;
985 : }
986 : ValueOperand takeAnyValue() {
987 : #if defined(JS_NUNBOX32)
988 : return ValueOperand(takeAnyGeneral(), takeAnyGeneral());
989 : #elif defined(JS_PUNBOX64)
990 : return ValueOperand(takeAnyGeneral());
991 : #else
992 : #error "Bad architecture"
993 : #endif
994 : }
995 : };
996 :
997 :
998 : // Interface which is common to all register set implementations. It overloads
999 : // |add|, |take| and |takeUnchecked| methods for types such as |ValueOperand|
1000 : // and |TypedOrValueRegister|.
1001 : template <class Accessors, typename Set>
1002 39958 : class CommonRegSet : public SpecializedRegSet<Accessors, Set>
1003 : {
1004 : typedef SpecializedRegSet<Accessors, Set> Parent;
1005 :
1006 : public:
1007 93673 : DEFINE_ACCESSOR_CONSTRUCTORS_(CommonRegSet)
1008 :
1009 10835 : RegSet set() const {
1010 10835 : return this->Parent::set_;
1011 : }
1012 1190 : RegSet& set() {
1013 1190 : return this->Parent::set_;
1014 : }
1015 :
1016 575656 : bool empty() const {
1017 575656 : return this->Parent::set_.empty();
1018 : }
1019 1609 : void clear() {
1020 1609 : this->Parent::set_.clear();
1021 1609 : }
1022 :
1023 : using Parent::add;
1024 1006 : void add(ValueOperand value) {
1025 : #if defined(JS_NUNBOX32)
1026 : add(value.payloadReg());
1027 : add(value.typeReg());
1028 : #elif defined(JS_PUNBOX64)
1029 1006 : add(value.valueReg());
1030 : #else
1031 : #error "Bad architecture"
1032 : #endif
1033 1006 : }
1034 :
1035 : using Parent::addUnchecked;
1036 1 : void addUnchecked(ValueOperand value) {
1037 : #if defined(JS_NUNBOX32)
1038 : addUnchecked(value.payloadReg());
1039 : addUnchecked(value.typeReg());
1040 : #elif defined(JS_PUNBOX64)
1041 1 : addUnchecked(value.valueReg());
1042 : #else
1043 : #error "Bad architecture"
1044 : #endif
1045 1 : }
1046 :
1047 23 : void add(TypedOrValueRegister reg) {
1048 23 : if (reg.hasValue())
1049 17 : add(reg.valueReg());
1050 6 : else if (reg.hasTyped())
1051 6 : add(reg.typedReg());
1052 23 : }
1053 :
1054 : using Parent::take;
1055 1393 : void take(ValueOperand value) {
1056 : #if defined(JS_NUNBOX32)
1057 : take(value.payloadReg());
1058 : take(value.typeReg());
1059 : #elif defined(JS_PUNBOX64)
1060 1393 : take(value.valueReg());
1061 : #else
1062 : #error "Bad architecture"
1063 : #endif
1064 1393 : }
1065 : void take(TypedOrValueRegister reg) {
1066 : if (reg.hasValue())
1067 : take(reg.valueReg());
1068 : else if (reg.hasTyped())
1069 : take(reg.typedReg());
1070 : }
1071 :
1072 : using Parent::takeUnchecked;
1073 10 : void takeUnchecked(ValueOperand value) {
1074 : #if defined(JS_NUNBOX32)
1075 : takeUnchecked(value.payloadReg());
1076 : takeUnchecked(value.typeReg());
1077 : #elif defined(JS_PUNBOX64)
1078 10 : takeUnchecked(value.valueReg());
1079 : #else
1080 : #error "Bad architecture"
1081 : #endif
1082 10 : }
1083 : void takeUnchecked(TypedOrValueRegister reg) {
1084 : if (reg.hasValue())
1085 : takeUnchecked(reg.valueReg());
1086 : else if (reg.hasTyped())
1087 : takeUnchecked(reg.typedReg());
1088 : }
1089 : };
1090 :
1091 :
1092 : // These classes do not provide any additional members, they only use their
1093 : // constructors to forward to the common interface for all register sets. The
1094 : // only benefit of these classes is to provide user friendly names.
1095 : template <typename Set>
1096 6351 : class LiveSet : public CommonRegSet<LiveSetAccessors<Set>, Set>
1097 : {
1098 : typedef CommonRegSet<LiveSetAccessors<Set>, Set> Parent;
1099 :
1100 : public:
1101 49576 : DEFINE_ACCESSOR_CONSTRUCTORS_(LiveSet)
1102 : };
1103 :
1104 : template <typename Set>
1105 232 : class AllocatableSet : public CommonRegSet<AllocatableSetAccessors<Set>, Set>
1106 : {
1107 : typedef CommonRegSet<AllocatableSetAccessors<Set>, Set> Parent;
1108 :
1109 : public:
1110 4281 : DEFINE_ACCESSOR_CONSTRUCTORS_(AllocatableSet)
1111 :
1112 : LiveSet<Set> asLiveSet() const {
1113 : return LiveSet<Set>(this->set());
1114 : }
1115 : };
1116 :
1117 : #define DEFINE_ACCESSOR_CONSTRUCTORS_FOR_REGISTERSET_(REGSET) \
1118 : typedef Parent::RegSet RegSet; \
1119 : typedef Parent::RegType RegType; \
1120 : typedef Parent::SetType SetType; \
1121 : \
1122 : constexpr REGSET() : Parent() {} \
1123 : explicit constexpr REGSET(SetType) = delete; \
1124 : explicit constexpr REGSET(RegSet set) : Parent(set) {} \
1125 : constexpr REGSET(GeneralRegisterSet gpr, FloatRegisterSet fpu) \
1126 : : Parent(RegisterSet(gpr, fpu)) \
1127 : {} \
1128 : REGSET(REGSET<GeneralRegisterSet> gpr, REGSET<FloatRegisterSet> fpu) \
1129 : : Parent(RegisterSet(gpr.set(), fpu.set())) \
1130 : {}
1131 :
1132 : template <>
1133 33375 : class LiveSet<RegisterSet>
1134 : : public CommonRegSet<LiveSetAccessors<RegisterSet>, RegisterSet>
1135 : {
1136 : // Note: We have to provide a qualified name for LiveSetAccessors, as it is
1137 : // interpreted as being the specialized class name inherited from the parent
1138 : // class specialization.
1139 : typedef CommonRegSet<jit::LiveSetAccessors<RegisterSet>, RegisterSet> Parent;
1140 :
1141 : public:
1142 23404 : DEFINE_ACCESSOR_CONSTRUCTORS_FOR_REGISTERSET_(LiveSet)
1143 : };
1144 :
1145 : template <>
1146 : class AllocatableSet<RegisterSet>
1147 : : public CommonRegSet<AllocatableSetAccessors<RegisterSet>, RegisterSet>
1148 : {
1149 : // Note: We have to provide a qualified name for AllocatableSetAccessors, as
1150 : // it is interpreted as being the specialized class name inherited from the
1151 : // parent class specialization.
1152 : typedef CommonRegSet<jit::AllocatableSetAccessors<RegisterSet>, RegisterSet> Parent;
1153 :
1154 : public:
1155 16412 : DEFINE_ACCESSOR_CONSTRUCTORS_FOR_REGISTERSET_(AllocatableSet)
1156 :
1157 10692 : LiveSet<RegisterSet> asLiveSet() const {
1158 10692 : return LiveSet<RegisterSet>(this->set());
1159 : }
1160 : };
1161 :
1162 : #undef DEFINE_ACCESSOR_CONSTRUCTORS_FOR_REGISTERSET_
1163 : #undef DEFINE_ACCESSOR_CONSTRUCTORS_
1164 :
1165 : typedef AllocatableSet<GeneralRegisterSet> AllocatableGeneralRegisterSet;
1166 : typedef AllocatableSet<FloatRegisterSet> AllocatableFloatRegisterSet;
1167 : typedef AllocatableSet<RegisterSet> AllocatableRegisterSet;
1168 :
1169 : typedef LiveSet<GeneralRegisterSet> LiveGeneralRegisterSet;
1170 : typedef LiveSet<FloatRegisterSet> LiveFloatRegisterSet;
1171 : typedef LiveSet<RegisterSet> LiveRegisterSet;
1172 :
1173 : // iterates in whatever order happens to be convenient.
1174 : // Use TypedRegisterBackwardIterator or TypedRegisterForwardIterator if a
1175 : // specific order is required.
1176 : template <typename T>
1177 : class TypedRegisterIterator
1178 : {
1179 : LiveSet<TypedRegisterSet<T>> regset_;
1180 :
1181 : public:
1182 116 : explicit TypedRegisterIterator(TypedRegisterSet<T> regset) : regset_(regset)
1183 116 : { }
1184 : explicit TypedRegisterIterator(LiveSet<TypedRegisterSet<T>> regset) : regset_(regset)
1185 : { }
1186 : TypedRegisterIterator(const TypedRegisterIterator& other) : regset_(other.regset_)
1187 : { }
1188 :
1189 13143 : bool more() const {
1190 13143 : return !regset_.empty();
1191 : }
1192 2482 : TypedRegisterIterator<T>& operator ++() {
1193 2482 : regset_.template takeAny<RegTypeName::Any>();
1194 2482 : return *this;
1195 : }
1196 6833 : T operator*() const {
1197 6833 : return regset_.template getAny<RegTypeName::Any>();
1198 : }
1199 : };
1200 :
1201 : // iterates backwards, that is, rn to r0
1202 : template <typename T>
1203 : class TypedRegisterBackwardIterator
1204 : {
1205 : LiveSet<TypedRegisterSet<T>> regset_;
1206 :
1207 : public:
1208 35070 : explicit TypedRegisterBackwardIterator(TypedRegisterSet<T> regset) : regset_(regset)
1209 35070 : { }
1210 880 : explicit TypedRegisterBackwardIterator(LiveSet<TypedRegisterSet<T>> regset) : regset_(regset)
1211 880 : { }
1212 : TypedRegisterBackwardIterator(const TypedRegisterBackwardIterator& other)
1213 : : regset_(other.regset_)
1214 : { }
1215 :
1216 458243 : bool more() const {
1217 458243 : return !regset_.empty();
1218 : }
1219 422248 : TypedRegisterBackwardIterator<T>& operator ++() {
1220 422248 : regset_.template takeLast<RegTypeName::Any>();
1221 422301 : return *this;
1222 : }
1223 423033 : T operator*() const {
1224 423033 : return regset_.template getLast<RegTypeName::Any>();
1225 : }
1226 : };
1227 :
1228 : // iterates forwards, that is r0 to rn
1229 : template <typename T>
1230 : class TypedRegisterForwardIterator
1231 : {
1232 : LiveSet<TypedRegisterSet<T>> regset_;
1233 :
1234 : public:
1235 11221 : explicit TypedRegisterForwardIterator(TypedRegisterSet<T> regset) : regset_(regset)
1236 11222 : { }
1237 40 : explicit TypedRegisterForwardIterator(LiveSet<TypedRegisterSet<T>> regset) : regset_(regset)
1238 40 : { }
1239 : TypedRegisterForwardIterator(const TypedRegisterForwardIterator& other) : regset_(other.regset_)
1240 : { }
1241 :
1242 100621 : bool more() const {
1243 100621 : return !regset_.empty();
1244 : }
1245 89360 : TypedRegisterForwardIterator<T>& operator ++() {
1246 89360 : regset_.template takeFirst<RegTypeName::Any>();
1247 89359 : return *this;
1248 : }
1249 89359 : T operator*() const {
1250 89359 : return regset_.template getFirst<RegTypeName::Any>();
1251 : }
1252 : };
1253 :
1254 : typedef TypedRegisterIterator<Register> GeneralRegisterIterator;
1255 : typedef TypedRegisterIterator<FloatRegister> FloatRegisterIterator;
1256 : typedef TypedRegisterBackwardIterator<Register> GeneralRegisterBackwardIterator;
1257 : typedef TypedRegisterBackwardIterator<FloatRegister> FloatRegisterBackwardIterator;
1258 : typedef TypedRegisterForwardIterator<Register> GeneralRegisterForwardIterator;
1259 : typedef TypedRegisterForwardIterator<FloatRegister> FloatRegisterForwardIterator;
1260 :
1261 : class AnyRegisterIterator
1262 : {
1263 : GeneralRegisterIterator geniter_;
1264 : FloatRegisterIterator floatiter_;
1265 :
1266 : public:
1267 : AnyRegisterIterator()
1268 : : geniter_(GeneralRegisterSet::All()), floatiter_(FloatRegisterSet::All())
1269 : { }
1270 : AnyRegisterIterator(GeneralRegisterSet genset, FloatRegisterSet floatset)
1271 : : geniter_(genset), floatiter_(floatset)
1272 : { }
1273 : explicit AnyRegisterIterator(const RegisterSet& set)
1274 : : geniter_(set.gpr_), floatiter_(set.fpu_)
1275 : { }
1276 38 : explicit AnyRegisterIterator(const LiveSet<RegisterSet>& set)
1277 38 : : geniter_(set.gprs()), floatiter_(set.fpus())
1278 38 : { }
1279 : AnyRegisterIterator(const AnyRegisterIterator& other)
1280 : : geniter_(other.geniter_), floatiter_(other.floatiter_)
1281 : { }
1282 2280 : bool more() const {
1283 2280 : return geniter_.more() || floatiter_.more();
1284 : }
1285 2242 : AnyRegisterIterator& operator ++() {
1286 2242 : if (geniter_.more())
1287 532 : ++geniter_;
1288 : else
1289 1710 : ++floatiter_;
1290 2242 : return *this;
1291 : }
1292 6593 : AnyRegister operator*() const {
1293 6593 : if (geniter_.more())
1294 1508 : return AnyRegister(*geniter_);
1295 5085 : return AnyRegister(*floatiter_);
1296 : }
1297 : };
1298 :
1299 : class ABIArg
1300 : {
1301 : public:
1302 : enum Kind {
1303 : GPR,
1304 : #ifdef JS_CODEGEN_REGISTER_PAIR
1305 : GPR_PAIR,
1306 : #endif
1307 : FPU,
1308 : Stack
1309 : };
1310 :
1311 : private:
1312 : Kind kind_;
1313 : union {
1314 : Register::Code gpr_;
1315 : FloatRegister::Code fpu_;
1316 : uint32_t offset_;
1317 : } u;
1318 :
1319 : public:
1320 37199 : ABIArg() : kind_(Kind(-1)) { u.offset_ = -1; }
1321 19652 : explicit ABIArg(Register gpr) : kind_(GPR) { u.gpr_ = gpr.code(); }
1322 : explicit ABIArg(Register gprLow, Register gprHigh)
1323 : {
1324 : #if defined(JS_CODEGEN_REGISTER_PAIR)
1325 : kind_ = GPR_PAIR;
1326 : #else
1327 : MOZ_CRASH("Unsupported type of ABI argument.");
1328 : #endif
1329 : u.gpr_ = gprLow.code();
1330 : MOZ_ASSERT(u.gpr_ % 2 == 0);
1331 : MOZ_ASSERT(u.gpr_ + 1 == gprHigh.code());
1332 : }
1333 5 : explicit ABIArg(FloatRegister fpu) : kind_(FPU) { u.fpu_ = fpu.code(); }
1334 16 : explicit ABIArg(uint32_t offset) : kind_(Stack) { u.offset_ = offset; }
1335 :
1336 39346 : Kind kind() const { return kind_; }
1337 : #ifdef JS_CODEGEN_REGISTER_PAIR
1338 : bool isGeneralRegPair() const { return kind_ == GPR_PAIR; }
1339 : #else
1340 : bool isGeneralRegPair() const { return false; }
1341 : #endif
1342 :
1343 19652 : Register gpr() const {
1344 19652 : MOZ_ASSERT(kind() == GPR);
1345 19652 : return Register::FromCode(u.gpr_);
1346 : }
1347 0 : Register64 gpr64() const {
1348 : #ifdef JS_PUNBOX64
1349 0 : return Register64(gpr());
1350 : #else
1351 : return Register64(oddGpr(), evenGpr());
1352 : #endif
1353 : }
1354 : Register evenGpr() const {
1355 : MOZ_ASSERT(isGeneralRegPair());
1356 : return Register::FromCode(u.gpr_);
1357 : }
1358 : Register oddGpr() const {
1359 : MOZ_ASSERT(isGeneralRegPair());
1360 : return Register::FromCode(u.gpr_ + 1);
1361 : }
1362 5 : FloatRegister fpu() const {
1363 5 : MOZ_ASSERT(kind() == FPU);
1364 5 : return FloatRegister::FromCode(u.fpu_);
1365 : }
1366 16 : uint32_t offsetFromArgBase() const {
1367 16 : MOZ_ASSERT(kind() == Stack);
1368 16 : return u.offset_;
1369 : }
1370 :
1371 0 : bool argInRegister() const { return kind() != Stack; }
1372 0 : AnyRegister reg() const { return kind_ == GPR ? AnyRegister(gpr()) : AnyRegister(fpu()); }
1373 :
1374 0 : bool operator==(const ABIArg& rhs) const {
1375 0 : if (kind_ != rhs.kind_)
1376 0 : return false;
1377 :
1378 0 : switch((int8_t)kind_) {
1379 0 : case GPR: return u.gpr_ == rhs.u.gpr_;
1380 : #if defined(JS_CODEGEN_REGISTER_PAIR)
1381 : case GPR_PAIR: return u.gpr_ == rhs.u.gpr_;
1382 : #endif
1383 0 : case FPU: return u.fpu_ == rhs.u.fpu_;
1384 0 : case Stack: return u.offset_ == rhs.u.offset_;
1385 0 : case -1: return true;
1386 0 : default: MOZ_CRASH("Invalid value for ABIArg kind");
1387 : }
1388 : }
1389 :
1390 0 : bool operator!=(const ABIArg& rhs) const {
1391 0 : return !(*this == rhs);
1392 : }
1393 : };
1394 :
1395 : // Get the set of registers which should be saved by a block of code which
1396 : // clobbers all registers besides |unused|, but does not clobber floating point
1397 : // registers.
1398 : inline LiveGeneralRegisterSet
1399 40 : SavedNonVolatileRegisters(const AllocatableGeneralRegisterSet& unused)
1400 : {
1401 40 : LiveGeneralRegisterSet result;
1402 :
1403 280 : for (GeneralRegisterIterator iter(GeneralRegisterSet::NonVolatile()); iter.more(); ++iter) {
1404 240 : Register reg = *iter;
1405 240 : if (!unused.has(reg))
1406 80 : result.add(reg);
1407 : }
1408 :
1409 : // Some platforms require the link register to be saved, if calls can be made.
1410 : #if defined(JS_CODEGEN_ARM)
1411 : result.add(Register::FromCode(Registers::lr));
1412 : #elif defined(JS_CODEGEN_ARM64)
1413 : result.add(Register::FromCode(Registers::lr));
1414 : #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
1415 : result.add(Register::FromCode(Registers::ra));
1416 : #endif
1417 :
1418 40 : return result;
1419 : }
1420 :
1421 : } // namespace jit
1422 : } // namespace js
1423 :
1424 : #endif /* jit_RegisterSets_h */
|