js/src/jit/RegisterSets.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:bca04be1d920
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/Alignment.h"
11 #include "mozilla/MathAlgorithms.h"
12
13 #include "jit/IonAllocPolicy.h"
14 #include "jit/Registers.h"
15
16 namespace js {
17 namespace jit {
18
19 struct AnyRegister {
20 typedef uint32_t Code;
21
22 static const uint32_t Total = Registers::Total + FloatRegisters::Total;
23 static const uint32_t Invalid = UINT_MAX;
24
25 union {
26 Registers::Code gpr_;
27 FloatRegisters::Code fpu_;
28 };
29 bool isFloat_;
30
31 AnyRegister()
32 { }
33 explicit AnyRegister(Register gpr) {
34 gpr_ = gpr.code();
35 isFloat_ = false;
36 }
37 explicit AnyRegister(FloatRegister fpu) {
38 fpu_ = fpu.code();
39 isFloat_ = true;
40 }
41 static AnyRegister FromCode(uint32_t i) {
42 JS_ASSERT(i < Total);
43 AnyRegister r;
44 if (i < Registers::Total) {
45 r.gpr_ = Register::Code(i);
46 r.isFloat_ = false;
47 } else {
48 r.fpu_ = FloatRegister::Code(i - Registers::Total);
49 r.isFloat_ = true;
50 }
51 return r;
52 }
53 bool isFloat() const {
54 return isFloat_;
55 }
56 Register gpr() const {
57 JS_ASSERT(!isFloat());
58 return Register::FromCode(gpr_);
59 }
60 FloatRegister fpu() const {
61 JS_ASSERT(isFloat());
62 return FloatRegister::FromCode(fpu_);
63 }
64 bool operator ==(const AnyRegister &other) const {
65 return isFloat()
66 ? (other.isFloat() && fpu_ == other.fpu_)
67 : (!other.isFloat() && gpr_ == other.gpr_);
68 }
69 bool operator !=(const AnyRegister &other) const {
70 return isFloat()
71 ? (!other.isFloat() || fpu_ != other.fpu_)
72 : (other.isFloat() || gpr_ != other.gpr_);
73 }
74 const char *name() const {
75 return isFloat()
76 ? FloatRegister::FromCode(fpu_).name()
77 : Register::FromCode(gpr_).name();
78 }
79 const Code code() const {
80 return isFloat()
81 ? fpu_ + Registers::Total
82 : gpr_;
83 }
84 bool volatile_() const {
85 return isFloat() ? fpu().volatile_() : gpr().volatile_();
86 }
87 };
88
89 // Registers to hold a boxed value. Uses one register on 64 bit
90 // platforms, two registers on 32 bit platforms.
91 class ValueOperand
92 {
93 #if defined(JS_NUNBOX32)
94 Register type_;
95 Register payload_;
96
97 public:
98 MOZ_CONSTEXPR ValueOperand(Register type, Register payload)
99 : type_(type), payload_(payload)
100 { }
101
102 Register typeReg() const {
103 return type_;
104 }
105 Register payloadReg() const {
106 return payload_;
107 }
108
109 Register scratchReg() const {
110 return payloadReg();
111 }
112 bool operator==(const ValueOperand &o) const {
113 return type_ == o.type_ && payload_ == o.payload_;
114 }
115 bool operator!=(const ValueOperand &o) const {
116 return !(*this == o);
117 }
118
119 #elif defined(JS_PUNBOX64)
120 Register value_;
121
122 public:
123 explicit MOZ_CONSTEXPR ValueOperand(Register value)
124 : value_(value)
125 { }
126
127 Register valueReg() const {
128 return value_;
129 }
130
131 Register scratchReg() const {
132 return valueReg();
133 }
134 bool operator==(const ValueOperand &o) const {
135 return value_ == o.value_;
136 }
137 bool operator!=(const ValueOperand &o) const {
138 return !(*this == o);
139 }
140 #endif
141
142 ValueOperand() {}
143 };
144
145 // Registers to hold either either a typed or untyped value.
146 class TypedOrValueRegister
147 {
148 // Type of value being stored.
149 MIRType type_;
150
151 // Space to hold either an AnyRegister or a ValueOperand.
152 union U {
153 mozilla::AlignedStorage2<AnyRegister> typed;
154 mozilla::AlignedStorage2<ValueOperand> value;
155 } data;
156
157 AnyRegister &dataTyped() {
158 JS_ASSERT(hasTyped());
159 return *data.typed.addr();
160 }
161 ValueOperand &dataValue() {
162 JS_ASSERT(hasValue());
163 return *data.value.addr();
164 }
165
166 const AnyRegister &dataTyped() const {
167 JS_ASSERT(hasTyped());
168 return *data.typed.addr();
169 }
170 const ValueOperand &dataValue() const {
171 JS_ASSERT(hasValue());
172 return *data.value.addr();
173 }
174
175 public:
176
177 TypedOrValueRegister()
178 : type_(MIRType_None)
179 {}
180
181 TypedOrValueRegister(MIRType type, AnyRegister reg)
182 : type_(type)
183 {
184 dataTyped() = reg;
185 }
186
187 TypedOrValueRegister(ValueOperand value)
188 : type_(MIRType_Value)
189 {
190 dataValue() = value;
191 }
192
193 MIRType type() const {
194 return type_;
195 }
196
197 bool hasTyped() const {
198 return type() != MIRType_None && type() != MIRType_Value;
199 }
200
201 bool hasValue() const {
202 return type() == MIRType_Value;
203 }
204
205 AnyRegister typedReg() const {
206 return dataTyped();
207 }
208
209 ValueOperand valueReg() const {
210 return dataValue();
211 }
212
213 AnyRegister scratchReg() {
214 if (hasValue())
215 return AnyRegister(valueReg().scratchReg());
216 return typedReg();
217 }
218 };
219
220 // A constant value, or registers to hold a typed/untyped value.
221 class ConstantOrRegister
222 {
223 // Whether a constant value is being stored.
224 bool constant_;
225
226 // Space to hold either a Value or a TypedOrValueRegister.
227 union U {
228 mozilla::AlignedStorage2<Value> constant;
229 mozilla::AlignedStorage2<TypedOrValueRegister> reg;
230 } data;
231
232 Value &dataValue() {
233 JS_ASSERT(constant());
234 return *data.constant.addr();
235 }
236 TypedOrValueRegister &dataReg() {
237 JS_ASSERT(!constant());
238 return *data.reg.addr();
239 }
240
241 public:
242
243 ConstantOrRegister()
244 {}
245
246 ConstantOrRegister(Value value)
247 : constant_(true)
248 {
249 dataValue() = value;
250 }
251
252 ConstantOrRegister(TypedOrValueRegister reg)
253 : constant_(false)
254 {
255 dataReg() = reg;
256 }
257
258 bool constant() {
259 return constant_;
260 }
261
262 Value value() {
263 return dataValue();
264 }
265
266 TypedOrValueRegister reg() {
267 return dataReg();
268 }
269 };
270
271 struct Int32Key {
272 bool isRegister_;
273 union {
274 Register reg_;
275 int32_t constant_;
276 };
277
278 explicit Int32Key(Register reg)
279 : isRegister_(true), reg_(reg)
280 { }
281
282 explicit Int32Key(int32_t index)
283 : isRegister_(false), constant_(index)
284 { }
285
286 inline void bumpConstant(int diff) {
287 JS_ASSERT(!isRegister_);
288 constant_ += diff;
289 }
290 inline Register reg() const {
291 JS_ASSERT(isRegister_);
292 return reg_;
293 }
294 inline int32_t constant() const {
295 JS_ASSERT(!isRegister_);
296 return constant_;
297 }
298 inline bool isRegister() const {
299 return isRegister_;
300 }
301 inline bool isConstant() const {
302 return !isRegister_;
303 }
304 };
305
306 template <typename T>
307 class TypedRegisterSet
308 {
309 uint32_t bits_;
310
311 public:
312 explicit MOZ_CONSTEXPR TypedRegisterSet(uint32_t bits)
313 : bits_(bits)
314 { }
315
316 MOZ_CONSTEXPR TypedRegisterSet() : bits_(0)
317 { }
318 MOZ_CONSTEXPR TypedRegisterSet(const TypedRegisterSet<T> &set) : bits_(set.bits_)
319 { }
320
321 static inline TypedRegisterSet All() {
322 return TypedRegisterSet(T::Codes::AllocatableMask);
323 }
324 static inline TypedRegisterSet Intersect(const TypedRegisterSet &lhs,
325 const TypedRegisterSet &rhs) {
326 return TypedRegisterSet(lhs.bits_ & rhs.bits_);
327 }
328 static inline TypedRegisterSet Union(const TypedRegisterSet &lhs,
329 const TypedRegisterSet &rhs) {
330 return TypedRegisterSet(lhs.bits_ | rhs.bits_);
331 }
332 static inline TypedRegisterSet Not(const TypedRegisterSet &in) {
333 return TypedRegisterSet(~in.bits_ & T::Codes::AllocatableMask);
334 }
335 static inline TypedRegisterSet VolatileNot(const TypedRegisterSet &in) {
336 const uint32_t allocatableVolatile =
337 T::Codes::AllocatableMask & T::Codes::VolatileMask;
338 return TypedRegisterSet(~in.bits_ & allocatableVolatile);
339 }
340 static inline TypedRegisterSet Volatile() {
341 return TypedRegisterSet(T::Codes::AllocatableMask & T::Codes::VolatileMask);
342 }
343 static inline TypedRegisterSet NonVolatile() {
344 return TypedRegisterSet(T::Codes::AllocatableMask & T::Codes::NonVolatileMask);
345 }
346 bool has(T reg) const {
347 return !!(bits_ & (1 << reg.code()));
348 }
349 void addUnchecked(T reg) {
350 bits_ |= (1 << reg.code());
351 }
352 void add(T reg) {
353 JS_ASSERT(!has(reg));
354 addUnchecked(reg);
355 }
356 void add(ValueOperand value) {
357 #if defined(JS_NUNBOX32)
358 add(value.payloadReg());
359 add(value.typeReg());
360 #elif defined(JS_PUNBOX64)
361 add(value.valueReg());
362 #else
363 #error "Bad architecture"
364 #endif
365 }
366 // Determemine if some register are still allocated. This function should
367 // be used with the set of allocatable registers used for the initialization
368 // of the current set.
369 bool someAllocated(const TypedRegisterSet &allocatable) const {
370 return allocatable.bits_ & ~bits_;
371 }
372 bool empty() const {
373 return !bits_;
374 }
375 void take(T reg) {
376 JS_ASSERT(has(reg));
377 takeUnchecked(reg);
378 }
379 void takeUnchecked(T reg) {
380 bits_ &= ~(1 << reg.code());
381 }
382 void take(ValueOperand value) {
383 #if defined(JS_NUNBOX32)
384 take(value.payloadReg());
385 take(value.typeReg());
386 #elif defined(JS_PUNBOX64)
387 take(value.valueReg());
388 #else
389 #error "Bad architecture"
390 #endif
391 }
392 void takeUnchecked(ValueOperand value) {
393 #if defined(JS_NUNBOX32)
394 takeUnchecked(value.payloadReg());
395 takeUnchecked(value.typeReg());
396 #elif defined(JS_PUNBOX64)
397 takeUnchecked(value.valueReg());
398 #else
399 #error "Bad architecture"
400 #endif
401 }
402 ValueOperand takeValueOperand() {
403 #if defined(JS_NUNBOX32)
404 return ValueOperand(takeAny(), takeAny());
405 #elif defined(JS_PUNBOX64)
406 return ValueOperand(takeAny());
407 #else
408 #error "Bad architecture"
409 #endif
410 }
411 T getAny() const {
412 // The choice of first or last here is mostly arbitrary, as they are
413 // about the same speed on popular architectures. We choose first, as
414 // it has the advantage of using the "lower" registers more often. These
415 // registers are sometimes more efficient (e.g. optimized encodings for
416 // EAX on x86).
417 return getFirst();
418 }
419 T getAnyExcluding(T preclude) {
420 JS_ASSERT(!empty());
421 if (!has(preclude))
422 return getAny();
423
424 take(preclude);
425 JS_ASSERT(!empty());
426 T result = getAny();
427 add(preclude);
428 return result;
429 }
430 T getFirst() const {
431 JS_ASSERT(!empty());
432 return T::FromCode(mozilla::CountTrailingZeroes32(bits_));
433 }
434 T getLast() const {
435 JS_ASSERT(!empty());
436 int ireg = 31 - mozilla::CountLeadingZeroes32(bits_);
437 return T::FromCode(ireg);
438 }
439 T takeAny() {
440 JS_ASSERT(!empty());
441 T reg = getAny();
442 take(reg);
443 return reg;
444 }
445 T takeAnyExcluding(T preclude) {
446 T reg = getAnyExcluding(preclude);
447 take(reg);
448 return reg;
449 }
450 ValueOperand takeAnyValue() {
451 #if defined(JS_NUNBOX32)
452 T type = takeAny();
453 T payload = takeAny();
454 return ValueOperand(type, payload);
455 #elif defined(JS_PUNBOX64)
456 T reg = takeAny();
457 return ValueOperand(reg);
458 #else
459 #error "Bad architecture"
460 #endif
461 }
462 T takeFirst() {
463 JS_ASSERT(!empty());
464 T reg = getFirst();
465 take(reg);
466 return reg;
467 }
468 T takeLast() {
469 JS_ASSERT(!empty());
470 T reg = getLast();
471 take(reg);
472 return reg;
473 }
474 void clear() {
475 bits_ = 0;
476 }
477 uint32_t bits() const {
478 return bits_;
479 }
480 uint32_t size() const {
481 return mozilla::CountPopulation32(bits_);
482 }
483 bool operator ==(const TypedRegisterSet<T> &other) const {
484 return other.bits_ == bits_;
485 }
486 };
487
488 typedef TypedRegisterSet<Register> GeneralRegisterSet;
489 typedef TypedRegisterSet<FloatRegister> FloatRegisterSet;
490
491 class AnyRegisterIterator;
492
493 class RegisterSet {
494 GeneralRegisterSet gpr_;
495 FloatRegisterSet fpu_;
496
497 friend class AnyRegisterIterator;
498
499 public:
500 RegisterSet()
501 { }
502 MOZ_CONSTEXPR RegisterSet(const GeneralRegisterSet &gpr, const FloatRegisterSet &fpu)
503 : gpr_(gpr),
504 fpu_(fpu)
505 { }
506 static inline RegisterSet All() {
507 return RegisterSet(GeneralRegisterSet::All(), FloatRegisterSet::All());
508 }
509 static inline RegisterSet Intersect(const RegisterSet &lhs, const RegisterSet &rhs) {
510 return RegisterSet(GeneralRegisterSet::Intersect(lhs.gpr_, rhs.gpr_),
511 FloatRegisterSet::Intersect(lhs.fpu_, rhs.fpu_));
512 }
513 static inline RegisterSet Union(const RegisterSet &lhs, const RegisterSet &rhs) {
514 return RegisterSet(GeneralRegisterSet::Union(lhs.gpr_, rhs.gpr_),
515 FloatRegisterSet::Union(lhs.fpu_, rhs.fpu_));
516 }
517 static inline RegisterSet Not(const RegisterSet &in) {
518 return RegisterSet(GeneralRegisterSet::Not(in.gpr_),
519 FloatRegisterSet::Not(in.fpu_));
520 }
521 static inline RegisterSet VolatileNot(const RegisterSet &in) {
522 return RegisterSet(GeneralRegisterSet::VolatileNot(in.gpr_),
523 FloatRegisterSet::VolatileNot(in.fpu_));
524 }
525 static inline RegisterSet Volatile() {
526 return RegisterSet(GeneralRegisterSet::Volatile(), FloatRegisterSet::Volatile());
527 }
528 bool has(Register reg) const {
529 return gpr_.has(reg);
530 }
531 bool has(FloatRegister reg) const {
532 return fpu_.has(reg);
533 }
534 bool has(AnyRegister reg) const {
535 return reg.isFloat() ? has(reg.fpu()) : has(reg.gpr());
536 }
537 void add(Register reg) {
538 gpr_.add(reg);
539 }
540 void add(FloatRegister reg) {
541 fpu_.add(reg);
542 }
543 void add(const AnyRegister &any) {
544 if (any.isFloat())
545 add(any.fpu());
546 else
547 add(any.gpr());
548 }
549 void add(ValueOperand value) {
550 #if defined(JS_NUNBOX32)
551 add(value.payloadReg());
552 add(value.typeReg());
553 #elif defined(JS_PUNBOX64)
554 add(value.valueReg());
555 #else
556 #error "Bad architecture"
557 #endif
558 }
559 void add(TypedOrValueRegister reg) {
560 if (reg.hasValue())
561 add(reg.valueReg());
562 else if (reg.hasTyped())
563 add(reg.typedReg());
564 }
565 void addUnchecked(Register reg) {
566 gpr_.addUnchecked(reg);
567 }
568 void addUnchecked(FloatRegister reg) {
569 fpu_.addUnchecked(reg);
570 }
571 void addUnchecked(const AnyRegister &any) {
572 if (any.isFloat())
573 addUnchecked(any.fpu());
574 else
575 addUnchecked(any.gpr());
576 }
577 bool empty(bool floats) const {
578 return floats ? fpu_.empty() : gpr_.empty();
579 }
580 FloatRegister takeFloat() {
581 return fpu_.takeAny();
582 }
583 Register takeGeneral() {
584 return gpr_.takeAny();
585 }
586 ValueOperand takeValueOperand() {
587 #if defined(JS_NUNBOX32)
588 return ValueOperand(takeGeneral(), takeGeneral());
589 #elif defined(JS_PUNBOX64)
590 return ValueOperand(takeGeneral());
591 #else
592 #error "Bad architecture"
593 #endif
594 }
595 void take(const AnyRegister &reg) {
596 if (reg.isFloat())
597 fpu_.take(reg.fpu());
598 else
599 gpr_.take(reg.gpr());
600 }
601 AnyRegister takeAny(bool isFloat) {
602 if (isFloat)
603 return AnyRegister(takeFloat());
604 return AnyRegister(takeGeneral());
605 }
606 void clear() {
607 gpr_.clear();
608 fpu_.clear();
609 }
610 MOZ_CONSTEXPR GeneralRegisterSet gprs() const {
611 return gpr_;
612 }
613 MOZ_CONSTEXPR FloatRegisterSet fpus() const {
614 return fpu_;
615 }
616 bool operator ==(const RegisterSet &other) const {
617 return other.gpr_ == gpr_ && other.fpu_ == fpu_;
618 }
619
620 void takeUnchecked(Register reg) {
621 gpr_.takeUnchecked(reg);
622 }
623 void takeUnchecked(FloatRegister reg) {
624 fpu_.takeUnchecked(reg);
625 }
626 void takeUnchecked(AnyRegister reg) {
627 if (reg.isFloat())
628 fpu_.takeUnchecked(reg.fpu());
629 else
630 gpr_.takeUnchecked(reg.gpr());
631 }
632 void takeUnchecked(ValueOperand value) {
633 gpr_.takeUnchecked(value);
634 }
635 void takeUnchecked(TypedOrValueRegister reg) {
636 if (reg.hasValue())
637 takeUnchecked(reg.valueReg());
638 else if (reg.hasTyped())
639 takeUnchecked(reg.typedReg());
640 }
641 };
642
643 // iterates in whatever order happens to be convenient.
644 // Use TypedRegisterBackwardIterator or TypedRegisterForwardIterator if a
645 // specific order is required.
646 template <typename T>
647 class TypedRegisterIterator
648 {
649 TypedRegisterSet<T> regset_;
650
651 public:
652 TypedRegisterIterator(TypedRegisterSet<T> regset) : regset_(regset)
653 { }
654 TypedRegisterIterator(const TypedRegisterIterator &other) : regset_(other.regset_)
655 { }
656
657 bool more() const {
658 return !regset_.empty();
659 }
660 TypedRegisterIterator<T> operator ++(int) {
661 TypedRegisterIterator<T> old(*this);
662 regset_.takeAny();
663 return old;
664 }
665 TypedRegisterIterator<T>& operator ++() {
666 regset_.takeAny();
667 return *this;
668 }
669 T operator *() const {
670 return regset_.getAny();
671 }
672 };
673
674 // iterates backwards, that is, rn to r0
675 template <typename T>
676 class TypedRegisterBackwardIterator
677 {
678 TypedRegisterSet<T> regset_;
679
680 public:
681 TypedRegisterBackwardIterator(TypedRegisterSet<T> regset) : regset_(regset)
682 { }
683 TypedRegisterBackwardIterator(const TypedRegisterBackwardIterator &other)
684 : regset_(other.regset_)
685 { }
686
687 bool more() const {
688 return !regset_.empty();
689 }
690 TypedRegisterBackwardIterator<T> operator ++(int) {
691 TypedRegisterBackwardIterator<T> old(*this);
692 regset_.takeLast();
693 return old;
694 }
695 TypedRegisterBackwardIterator<T>& operator ++() {
696 regset_.takeLast();
697 return *this;
698 }
699 T operator *() const {
700 return regset_.getLast();
701 }
702 };
703
704 // iterates forwards, that is r0 to rn
705 template <typename T>
706 class TypedRegisterForwardIterator
707 {
708 TypedRegisterSet<T> regset_;
709
710 public:
711 TypedRegisterForwardIterator(TypedRegisterSet<T> regset) : regset_(regset)
712 { }
713 TypedRegisterForwardIterator(const TypedRegisterForwardIterator &other) : regset_(other.regset_)
714 { }
715
716 bool more() const {
717 return !regset_.empty();
718 }
719 TypedRegisterForwardIterator<T> operator ++(int) {
720 TypedRegisterForwardIterator<T> old(*this);
721 regset_.takeFirst();
722 return old;
723 }
724 TypedRegisterForwardIterator<T>& operator ++() {
725 regset_.takeFirst();
726 return *this;
727 }
728 T operator *() const {
729 return regset_.getFirst();
730 }
731 };
732
733 typedef TypedRegisterIterator<Register> GeneralRegisterIterator;
734 typedef TypedRegisterIterator<FloatRegister> FloatRegisterIterator;
735 typedef TypedRegisterBackwardIterator<Register> GeneralRegisterBackwardIterator;
736 typedef TypedRegisterBackwardIterator<FloatRegister> FloatRegisterBackwardIterator;
737 typedef TypedRegisterForwardIterator<Register> GeneralRegisterForwardIterator;
738 typedef TypedRegisterForwardIterator<FloatRegister> FloatRegisterForwardIterator;
739
740 class AnyRegisterIterator
741 {
742 GeneralRegisterIterator geniter_;
743 FloatRegisterIterator floatiter_;
744
745 public:
746 AnyRegisterIterator()
747 : geniter_(GeneralRegisterSet::All()), floatiter_(FloatRegisterSet::All())
748 { }
749 AnyRegisterIterator(GeneralRegisterSet genset, FloatRegisterSet floatset)
750 : geniter_(genset), floatiter_(floatset)
751 { }
752 AnyRegisterIterator(const RegisterSet &set)
753 : geniter_(set.gpr_), floatiter_(set.fpu_)
754 { }
755 AnyRegisterIterator(const AnyRegisterIterator &other)
756 : geniter_(other.geniter_), floatiter_(other.floatiter_)
757 { }
758 bool more() const {
759 return geniter_.more() || floatiter_.more();
760 }
761 AnyRegisterIterator operator ++(int) {
762 AnyRegisterIterator old(*this);
763 if (geniter_.more())
764 geniter_++;
765 else
766 floatiter_++;
767 return old;
768 }
769 AnyRegister operator *() const {
770 if (geniter_.more())
771 return AnyRegister(*geniter_);
772 return AnyRegister(*floatiter_);
773 }
774 };
775
776 class ABIArg
777 {
778 public:
779 enum Kind { GPR, FPU, Stack };
780
781 private:
782 Kind kind_;
783 union {
784 Registers::Code gpr_;
785 FloatRegisters::Code fpu_;
786 uint32_t offset_;
787 } u;
788
789 public:
790 ABIArg() : kind_(Kind(-1)) { u.offset_ = -1; }
791 ABIArg(Register gpr) : kind_(GPR) { u.gpr_ = gpr.code(); }
792 ABIArg(FloatRegister fpu) : kind_(FPU) { u.fpu_ = fpu.code(); }
793 ABIArg(uint32_t offset) : kind_(Stack) { u.offset_ = offset; }
794
795 Kind kind() const { return kind_; }
796 Register gpr() const { JS_ASSERT(kind() == GPR); return Register::FromCode(u.gpr_); }
797 FloatRegister fpu() const { JS_ASSERT(kind() == FPU); return FloatRegister::FromCode(u.fpu_); }
798 uint32_t offsetFromArgBase() const { JS_ASSERT(kind() == Stack); return u.offset_; }
799
800 bool argInRegister() const { return kind() != Stack; }
801 AnyRegister reg() const { return kind_ == GPR ? AnyRegister(gpr()) : AnyRegister(fpu()); }
802 };
803
804 } // namespace jit
805 } // namespace js
806
807 #endif /* jit_RegisterSets_h */

mercurial