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