1// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_COMPILER_BACKEND_LOCATIONS_H_
6#define RUNTIME_VM_COMPILER_BACKEND_LOCATIONS_H_
7
8#if defined(DART_PRECOMPILED_RUNTIME)
9#error "AOT runtime should not use compiler sources (including header files)"
10#endif // defined(DART_PRECOMPILED_RUNTIME)
11
12#include "vm/allocation.h"
13#include "vm/bitfield.h"
14#include "vm/bitmap.h"
15#include "vm/compiler/assembler/assembler.h"
16#include "vm/constants.h"
17#include "vm/cpu.h"
18
19namespace dart {
20
21class BaseTextBuffer;
22class ConstantInstr;
23class Definition;
24class PairLocation;
25class Value;
26
27#define FOR_EACH_REPRESENTATION_KIND(M) \
28 M(NoRepresentation) \
29 M(Tagged) \
30 M(Untagged) \
31 M(UnboxedDouble) \
32 M(UnboxedFloat) \
33 M(UnboxedInt32) \
34 M(UnboxedUint32) \
35 M(UnboxedInt64) \
36 M(UnboxedFloat32x4) \
37 M(UnboxedInt32x4) \
38 M(UnboxedFloat64x2) \
39 M(PairOfTagged)
40
41enum Representation {
42#define DECLARE_REPRESENTATION(name) k##name,
43 FOR_EACH_REPRESENTATION_KIND(DECLARE_REPRESENTATION)
44#undef DECLARE_REPRESENTATION
45 kNumRepresentations
46};
47
48// 'UnboxedFfiIntPtr' should be able to hold a pointer of the target word-size.
49// On a 32-bit platform, it's an unsigned 32-bit int because it should be
50// zero-extended to 64-bits, not sign-extended (pointers are inherently
51// unsigned).
52//
53// Issue(36370): Use [kUnboxedIntPtr] instead.
54static constexpr Representation kUnboxedFfiIntPtr =
55 compiler::target::kWordSize == 4 ? kUnboxedUint32 : kUnboxedInt64;
56
57// The representation which can be used for native pointers. We use signed 32/64
58// bit representation to be able to do arithmetic on pointers.
59static constexpr Representation kUnboxedIntPtr =
60 compiler::target::kWordSize == 4 ? kUnboxedInt32 : kUnboxedInt64;
61
62// Location objects are used to connect register allocator and code generator.
63// Instruction templates used by code generator have a corresponding
64// LocationSummary object which specifies expected location for every input
65// and output.
66// Each location is encoded as a single word: for non-constant locations
67// low 4 bits denote location kind, rest is kind specific location payload
68// e.g. for REGISTER kind payload is register code (value of the Register
69// enumeration), constant locations contain a tagged (low 2 bits are set to 01)
70// Object handle.
71//
72// Locations must satisfy the following invariant: if two locations' encodings
73// are bitwise unequal then these two locations are guaranteed to be disjoint.
74// Properties like representation belong to the value that is stored in
75// the location not to the location itself.
76class Location : public ValueObject {
77 private:
78 enum {
79 // Number of bits required to encode Kind value.
80 kKindBitsPos = 0,
81 kKindBitsSize = 5,
82
83 kPayloadBitsPos = kKindBitsPos + kKindBitsSize,
84 kPayloadBitsSize = kBitsPerWord - kPayloadBitsPos,
85 };
86
87 static const uword kInvalidLocation = 0;
88 static const uword kLocationTagMask = 0x3;
89
90 public:
91 static bool ParseRepresentation(const char* str, Representation* out);
92 static const char* RepresentationToCString(Representation repr);
93
94 // Constant payload can overlap with kind field so Kind values
95 // have to be chosen in a way that their last 2 bits are never
96 // the same as kConstantTag or kPairLocationTag.
97 // Note that two locations with different kinds should never point to
98 // the same place. For example kQuadStackSlot location should never intersect
99 // with kDoubleStackSlot location.
100 enum Kind : intptr_t {
101 // This location is invalid. Payload must be zero.
102 kInvalid = 0,
103
104 // Constant value. This location contains a tagged Object handle.
105 kConstantTag = 1,
106
107 // This location contains a tagged pointer to a PairLocation.
108 kPairLocationTag = 2,
109
110 // Unallocated location represents a location that is not fixed and can be
111 // allocated by a register allocator. Each unallocated location has
112 // a policy that specifies what kind of location is suitable. Payload
113 // contains register allocation policy.
114 kUnallocated = 3,
115
116 // Spill slots allocated by the register allocator. Payload contains
117 // a spill index.
118 kStackSlot = 4, // Word size slot.
119 kDoubleStackSlot = 7, // 64bit stack slot.
120 kQuadStackSlot = 11, // 128bit stack slot.
121
122 // Register location represents a fixed register. Payload contains
123 // register code.
124 kRegister = 8,
125
126 // FpuRegister location represents a fixed fpu register. Payload contains
127 // its code.
128 kFpuRegister = 12,
129 };
130
131 Location() : value_(kInvalidLocation) {
132 // Verify that non-tagged location kinds do not interfere with location tags
133 // (kConstantTag and kPairLocationTag).
134 COMPILE_ASSERT((kInvalid & kLocationTagMask) != kConstantTag);
135 COMPILE_ASSERT((kInvalid & kLocationTagMask) != kPairLocationTag);
136
137 COMPILE_ASSERT((kUnallocated & kLocationTagMask) != kConstantTag);
138 COMPILE_ASSERT((kUnallocated & kLocationTagMask) != kPairLocationTag);
139
140 COMPILE_ASSERT((kStackSlot & kLocationTagMask) != kConstantTag);
141 COMPILE_ASSERT((kStackSlot & kLocationTagMask) != kPairLocationTag);
142
143 COMPILE_ASSERT((kDoubleStackSlot & kLocationTagMask) != kConstantTag);
144 COMPILE_ASSERT((kDoubleStackSlot & kLocationTagMask) != kPairLocationTag);
145
146 COMPILE_ASSERT((kQuadStackSlot & kLocationTagMask) != kConstantTag);
147 COMPILE_ASSERT((kQuadStackSlot & kLocationTagMask) != kPairLocationTag);
148
149 COMPILE_ASSERT((kRegister & kLocationTagMask) != kConstantTag);
150 COMPILE_ASSERT((kRegister & kLocationTagMask) != kPairLocationTag);
151
152 COMPILE_ASSERT((kFpuRegister & kLocationTagMask) != kConstantTag);
153 COMPILE_ASSERT((kFpuRegister & kLocationTagMask) != kPairLocationTag);
154
155 // Verify tags and tagmask.
156 COMPILE_ASSERT((kConstantTag & kLocationTagMask) == kConstantTag);
157
158 COMPILE_ASSERT((kPairLocationTag & kLocationTagMask) == kPairLocationTag);
159
160 ASSERT(IsInvalid());
161 }
162
163 Location(const Location& other) : ValueObject(), value_(other.value_) {}
164
165 Location& operator=(const Location& other) {
166 value_ = other.value_;
167 return *this;
168 }
169
170 bool IsInvalid() const { return value_ == kInvalidLocation; }
171
172 // Constants.
173 bool IsConstant() const {
174 return (value_ & kLocationTagMask) == kConstantTag;
175 }
176
177 static Location Constant(const ConstantInstr* obj) {
178 Location loc(reinterpret_cast<uword>(obj) | kConstantTag);
179 ASSERT(obj == loc.constant_instruction());
180 return loc;
181 }
182
183 ConstantInstr* constant_instruction() const {
184 ASSERT(IsConstant());
185 return reinterpret_cast<ConstantInstr*>(value_ & ~kLocationTagMask);
186 }
187
188 const Object& constant() const;
189
190 bool IsPairLocation() const {
191 return (value_ & kLocationTagMask) == kPairLocationTag;
192 }
193
194 static Location Pair(Location first, Location second);
195
196 PairLocation* AsPairLocation() const;
197
198 // For pair locations, returns the ith component (for i in {0, 1}).
199 Location Component(intptr_t i) const;
200
201 // Unallocated locations.
202 enum Policy {
203 kAny,
204 kPrefersRegister,
205 kRequiresRegister,
206 kRequiresFpuRegister,
207 kWritableRegister,
208 kSameAsFirstInput,
209 };
210
211 bool IsUnallocated() const { return kind() == kUnallocated; }
212
213 bool IsRegisterBeneficial() { return !Equals(Any()); }
214
215 static Location UnallocatedLocation(Policy policy) {
216 return Location(kUnallocated, PolicyField::encode(policy));
217 }
218
219 // Any free register is suitable to replace this unallocated location.
220 static Location Any() { return UnallocatedLocation(kAny); }
221
222 static Location PrefersRegister() {
223 return UnallocatedLocation(kPrefersRegister);
224 }
225
226 static Location RequiresRegister() {
227 return UnallocatedLocation(kRequiresRegister);
228 }
229
230 static Location RequiresFpuRegister() {
231 return UnallocatedLocation(kRequiresFpuRegister);
232 }
233
234 static Location WritableRegister() {
235 return UnallocatedLocation(kWritableRegister);
236 }
237
238 // The location of the first input to the instruction will be
239 // used to replace this unallocated location.
240 static Location SameAsFirstInput() {
241 return UnallocatedLocation(kSameAsFirstInput);
242 }
243
244 // Empty location. Used if there the location should be ignored.
245 static Location NoLocation() { return Location(); }
246
247 Policy policy() const {
248 ASSERT(IsUnallocated());
249 return PolicyField::decode(payload());
250 }
251
252 // Register locations.
253 static Location RegisterLocation(Register reg) {
254 return Location(kRegister, reg);
255 }
256
257 bool IsRegister() const { return kind() == kRegister; }
258
259 Register reg() const {
260 ASSERT(IsRegister());
261 return static_cast<Register>(payload());
262 }
263
264 // FpuRegister locations.
265 static Location FpuRegisterLocation(FpuRegister reg) {
266 return Location(kFpuRegister, reg);
267 }
268
269 bool IsFpuRegister() const { return kind() == kFpuRegister; }
270
271 FpuRegister fpu_reg() const {
272 ASSERT(IsFpuRegister());
273 return static_cast<FpuRegister>(payload());
274 }
275
276 static bool IsMachineRegisterKind(Kind kind) {
277 return (kind == kRegister) || (kind == kFpuRegister);
278 }
279
280 static Location MachineRegisterLocation(Kind kind, intptr_t reg) {
281 if (kind == kRegister) {
282 return RegisterLocation(static_cast<Register>(reg));
283 } else {
284 ASSERT(kind == kFpuRegister);
285 return FpuRegisterLocation(static_cast<FpuRegister>(reg));
286 }
287 }
288
289 bool IsMachineRegister() const { return IsMachineRegisterKind(kind()); }
290
291 intptr_t register_code() const {
292 ASSERT(IsMachineRegister());
293 return static_cast<intptr_t>(payload());
294 }
295
296 static uword EncodeStackIndex(intptr_t stack_index) {
297 ASSERT((-kStackIndexBias <= stack_index) &&
298 (stack_index < kStackIndexBias));
299 return static_cast<uword>(kStackIndexBias + stack_index);
300 }
301
302 static Location StackSlot(intptr_t stack_index, Register base) {
303 uword payload = StackSlotBaseField::encode(base) |
304 StackIndexField::encode(EncodeStackIndex(stack_index));
305 Location loc(kStackSlot, payload);
306 // Ensure that sign is preserved.
307 ASSERT(loc.stack_index() == stack_index);
308 return loc;
309 }
310
311 bool IsStackSlot() const { return kind() == kStackSlot; }
312
313 static Location DoubleStackSlot(intptr_t stack_index, Register base) {
314 uword payload = StackSlotBaseField::encode(base) |
315 StackIndexField::encode(EncodeStackIndex(stack_index));
316 Location loc(kDoubleStackSlot, payload);
317 // Ensure that sign is preserved.
318 ASSERT(loc.stack_index() == stack_index);
319 return loc;
320 }
321
322 bool IsDoubleStackSlot() const { return kind() == kDoubleStackSlot; }
323
324 static Location QuadStackSlot(intptr_t stack_index, Register base) {
325 uword payload = StackSlotBaseField::encode(base) |
326 StackIndexField::encode(EncodeStackIndex(stack_index));
327 Location loc(kQuadStackSlot, payload);
328 // Ensure that sign is preserved.
329 ASSERT(loc.stack_index() == stack_index);
330 return loc;
331 }
332
333 bool IsQuadStackSlot() const { return kind() == kQuadStackSlot; }
334
335 Register base_reg() const {
336 ASSERT(HasStackIndex());
337 return StackSlotBaseField::decode(payload());
338 }
339
340 intptr_t stack_index() const {
341 ASSERT(HasStackIndex());
342 // Decode stack index manually to preserve sign.
343 return StackIndexField::decode(payload()) - kStackIndexBias;
344 }
345
346 bool HasStackIndex() const {
347 return IsStackSlot() || IsDoubleStackSlot() || IsQuadStackSlot();
348 }
349
350 // Returns the offset from the frame pointer for stack slot locations.
351 intptr_t ToStackSlotOffset() const;
352
353 const char* Name() const;
354 void PrintTo(BaseTextBuffer* f) const;
355 void Print() const;
356 const char* ToCString() const;
357
358 // Compare two locations.
359 bool Equals(Location other) const { return value_ == other.value_; }
360
361 // If current location is constant might return something that
362 // is not equal to any Kind.
363 Kind kind() const { return KindField::decode(value_); }
364
365 Location Copy() const;
366
367 static Location read(uword value) { return Location(value); }
368 uword write() const { return value_; }
369
370 private:
371 explicit Location(uword value) : value_(value) {}
372
373 void set_stack_index(intptr_t index) {
374 ASSERT(HasStackIndex());
375 value_ = PayloadField::update(
376 StackIndexField::update(EncodeStackIndex(index), payload()), value_);
377 }
378
379 void set_base_reg(Register reg) {
380 ASSERT(HasStackIndex());
381 value_ = PayloadField::update(StackSlotBaseField::update(reg, payload()),
382 value_);
383 }
384
385 Location(Kind kind, uword payload)
386 : value_(KindField::encode(kind) | PayloadField::encode(payload)) {}
387
388 uword payload() const { return PayloadField::decode(value_); }
389
390 class KindField : public BitField<uword, Kind, kKindBitsPos, kKindBitsSize> {
391 };
392 class PayloadField
393 : public BitField<uword, uword, kPayloadBitsPos, kPayloadBitsSize> {};
394
395 // Layout for kUnallocated locations payload.
396 typedef BitField<uword, Policy, 0, 3> PolicyField;
397
398// Layout for stack slots.
399#if defined(ARCH_IS_64_BIT)
400 static const intptr_t kBitsForBaseReg = 6;
401#else
402 static const intptr_t kBitsForBaseReg = 5;
403#endif
404 static const intptr_t kBitsForStackIndex = kPayloadBitsSize - kBitsForBaseReg;
405 class StackSlotBaseField
406 : public BitField<uword, Register, 0, kBitsForBaseReg> {};
407 class StackIndexField
408 : public BitField<uword, intptr_t, kBitsForBaseReg, kBitsForStackIndex> {
409 };
410 COMPILE_ASSERT(1 << kBitsForBaseReg >= kNumberOfCpuRegisters);
411
412 static const intptr_t kStackIndexBias = static_cast<intptr_t>(1)
413 << (kBitsForStackIndex - 1);
414
415 // Location either contains kind and payload fields or a tagged handle for
416 // a constant locations. Values of enumeration Kind are selected in such a
417 // way that none of them can be interpreted as a kConstant tag.
418 uword value_;
419};
420
421Location LocationArgumentsDescriptorLocation();
422Location LocationExceptionLocation();
423Location LocationStackTraceLocation();
424// Constants.
425Location LocationRegisterOrConstant(Value* value);
426Location LocationRegisterOrSmiConstant(Value* value);
427Location LocationWritableRegisterOrSmiConstant(Value* value);
428Location LocationFixedRegisterOrConstant(Value* value, Register reg);
429Location LocationFixedRegisterOrSmiConstant(Value* value, Register reg);
430Location LocationAnyOrConstant(Value* value);
431
432Location LocationRemapForSlowPath(Location loc,
433 Definition* def,
434 intptr_t* cpu_reg_slots,
435 intptr_t* fpu_reg_slots);
436
437// Return a memory operand for stack slot locations.
438compiler::Address LocationToStackSlotAddress(Location loc);
439
440class PairLocation : public ZoneAllocated {
441 public:
442 PairLocation() {
443 for (intptr_t i = 0; i < kPairLength; i++) {
444 ASSERT(locations_[i].IsInvalid());
445 }
446 }
447
448 intptr_t length() const { return kPairLength; }
449
450 Location At(intptr_t i) const {
451 ASSERT(i >= 0);
452 ASSERT(i < kPairLength);
453 return locations_[i];
454 }
455
456 void SetAt(intptr_t i, Location loc) {
457 ASSERT(i >= 0);
458 ASSERT(i < kPairLength);
459 locations_[i] = loc;
460 }
461
462 Location* SlotAt(intptr_t i) {
463 ASSERT(i >= 0);
464 ASSERT(i < kPairLength);
465 return &locations_[i];
466 }
467
468 private:
469 static const intptr_t kPairLength = 2;
470 Location locations_[kPairLength];
471};
472
473template <typename T>
474class SmallSet {
475 public:
476 SmallSet() : data_(0) {}
477
478 explicit SmallSet(intptr_t data) : data_(data) {}
479
480 bool Contains(T value) const { return (data_ & ToMask(value)) != 0; }
481
482 void Add(T value) { data_ |= ToMask(value); }
483
484 void Remove(T value) { data_ &= ~ToMask(value); }
485
486 bool IsEmpty() const { return data_ == 0; }
487
488 intptr_t data() const { return data_; }
489
490 private:
491 static intptr_t ToMask(T value) {
492 ASSERT(static_cast<intptr_t>(value) < (kWordSize * kBitsPerByte));
493 return 1 << static_cast<intptr_t>(value);
494 }
495
496 intptr_t data_;
497};
498
499class RegisterSet : public ValueObject {
500 public:
501 RegisterSet()
502 : cpu_registers_(), untagged_cpu_registers_(), fpu_registers_() {
503 ASSERT(kNumberOfCpuRegisters <= (kWordSize * kBitsPerByte));
504 ASSERT(kNumberOfFpuRegisters <= (kWordSize * kBitsPerByte));
505 }
506
507 void AddAllNonReservedRegisters(bool include_fpu_registers) {
508 for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; --i) {
509 if ((kReservedCpuRegisters & (1 << i)) != 0u) continue;
510 Add(Location::RegisterLocation(static_cast<Register>(i)));
511 }
512
513 if (include_fpu_registers) {
514 for (intptr_t i = kNumberOfFpuRegisters - 1; i >= 0; --i) {
515 Add(Location::FpuRegisterLocation(static_cast<FpuRegister>(i)));
516 }
517 }
518 }
519
520 // Adds all registers which don't have a special purpose (e.g. FP, SP, PC,
521 // CSP, etc.).
522 void AddAllGeneralRegisters() {
523 for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; --i) {
524 Register reg = static_cast<Register>(i);
525 if (reg == FPREG || reg == SPREG) continue;
526#if defined(TARGET_ARCH_ARM)
527 if (reg == PC) continue;
528#elif defined(TARGET_ARCH_ARM64)
529 if (reg == R31) continue;
530#endif
531 Add(Location::RegisterLocation(reg));
532 }
533
534#if defined(TARGET_ARCH_ARM)
535 if (TargetCPUFeatures::vfp_supported()) {
536#endif
537 for (intptr_t i = kNumberOfFpuRegisters - 1; i >= 0; --i) {
538 Add(Location::FpuRegisterLocation(static_cast<FpuRegister>(i)));
539 }
540#if defined(TARGET_ARCH_ARM)
541 }
542#endif
543 }
544
545 void AddAllArgumentRegisters() {
546 // All (native) arguments are passed on the stack in IA32.
547#if !defined(TARGET_ARCH_IA32)
548 for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
549 const Register reg = static_cast<Register>(i);
550 if (IsArgumentRegister(reg)) {
551 Add(Location::RegisterLocation(reg));
552 }
553 }
554 for (intptr_t i = 0; i < kNumberOfFpuRegisters; ++i) {
555 const FpuRegister reg = static_cast<FpuRegister>(i);
556 if (IsFpuArgumentRegister(reg)) {
557 Add(Location::FpuRegisterLocation(reg));
558 }
559 }
560#endif
561 }
562
563 void Add(Location loc, Representation rep = kTagged) {
564 if (loc.IsRegister()) {
565 cpu_registers_.Add(loc.reg());
566 if (rep != kTagged) {
567 // CPU register contains an untagged value.
568 MarkUntagged(loc);
569 }
570 } else if (loc.IsFpuRegister()) {
571 fpu_registers_.Add(loc.fpu_reg());
572 }
573 }
574
575 void Remove(Location loc) {
576 if (loc.IsRegister()) {
577 cpu_registers_.Remove(loc.reg());
578 } else if (loc.IsFpuRegister()) {
579 fpu_registers_.Remove(loc.fpu_reg());
580 }
581 }
582
583 bool Contains(Location loc) {
584 if (loc.IsRegister()) {
585 return ContainsRegister(loc.reg());
586 } else if (loc.IsFpuRegister()) {
587 return ContainsFpuRegister(loc.fpu_reg());
588 } else {
589 UNREACHABLE();
590 return false;
591 }
592 }
593
594 void DebugPrint();
595
596 void MarkUntagged(Location loc) {
597 ASSERT(loc.IsRegister());
598 untagged_cpu_registers_.Add(loc.reg());
599 }
600
601 bool HasUntaggedValues() const {
602 return !untagged_cpu_registers_.IsEmpty() || !fpu_registers_.IsEmpty();
603 }
604
605 bool IsTagged(Register reg) const {
606 return !untagged_cpu_registers_.Contains(reg);
607 }
608
609 bool ContainsRegister(Register reg) const {
610 return cpu_registers_.Contains(reg);
611 }
612
613 bool ContainsFpuRegister(FpuRegister fpu_reg) const {
614 return fpu_registers_.Contains(fpu_reg);
615 }
616
617 intptr_t CpuRegisterCount() const { return RegisterCount(cpu_registers()); }
618 intptr_t FpuRegisterCount() const { return RegisterCount(fpu_registers()); }
619
620 static intptr_t RegisterCount(intptr_t registers);
621 static bool Contains(intptr_t register_set, intptr_t reg) {
622 return (register_set & (1 << reg)) != 0;
623 }
624
625 intptr_t cpu_registers() const { return cpu_registers_.data(); }
626 intptr_t fpu_registers() const { return fpu_registers_.data(); }
627
628 private:
629 SmallSet<Register> cpu_registers_;
630 SmallSet<Register> untagged_cpu_registers_;
631 SmallSet<FpuRegister> fpu_registers_;
632
633 DISALLOW_COPY_AND_ASSIGN(RegisterSet);
634};
635
636// Specification of locations for inputs and output.
637class LocationSummary : public ZoneAllocated {
638 public:
639 enum ContainsCall {
640 kNoCall, // Used registers must be reserved as tmp.
641 kCall, // Registers have been saved and can be used without reservation.
642 kCallCalleeSafe, // Registers will be saved by the callee.
643 kCallOnSlowPath, // Used registers must be reserved as tmp.
644 kCallOnSharedSlowPath // Registers used to invoke shared stub must be
645 // reserved as tmp.
646 };
647
648 LocationSummary(Zone* zone,
649 intptr_t input_count,
650 intptr_t temp_count,
651 LocationSummary::ContainsCall contains_call);
652
653 intptr_t input_count() const { return num_inputs_; }
654
655 Location in(intptr_t index) const {
656 ASSERT(index >= 0);
657 ASSERT(index < num_inputs_);
658 return input_locations_[index];
659 }
660
661 Location* in_slot(intptr_t index) {
662 ASSERT(index >= 0);
663 ASSERT(index < num_inputs_);
664 return &input_locations_[index];
665 }
666
667 void set_in(intptr_t index, Location loc);
668
669 intptr_t temp_count() const { return num_temps_; }
670
671 Location temp(intptr_t index) const {
672 ASSERT(index >= 0);
673 ASSERT(index < num_temps_);
674 return temp_locations_[index];
675 }
676
677 Location* temp_slot(intptr_t index) {
678 ASSERT(index >= 0);
679 ASSERT(index < num_temps_);
680 return &temp_locations_[index];
681 }
682
683 void set_temp(intptr_t index, Location loc) {
684 ASSERT(index >= 0);
685 ASSERT(index < num_temps_);
686 ASSERT(!always_calls() || loc.IsMachineRegister());
687 temp_locations_[index] = loc;
688 }
689
690 intptr_t output_count() const { return 1; }
691
692 Location out(intptr_t index) const {
693 ASSERT(index == 0);
694 return output_location_;
695 }
696
697 Location* out_slot(intptr_t index) {
698 ASSERT(index == 0);
699 return &output_location_;
700 }
701
702 void set_out(intptr_t index, Location loc);
703
704 BitmapBuilder* stack_bitmap() {
705 if (stack_bitmap_ == NULL) {
706 stack_bitmap_ = new BitmapBuilder();
707 }
708 return stack_bitmap_;
709 }
710 void SetStackBit(intptr_t index) { stack_bitmap()->Set(index, true); }
711
712 bool always_calls() const {
713 return contains_call_ == kCall || contains_call_ == kCallCalleeSafe;
714 }
715
716 bool callee_safe_call() const { return contains_call_ == kCallCalleeSafe; }
717
718 bool can_call() { return contains_call_ != kNoCall; }
719
720 bool HasCallOnSlowPath() { return can_call() && !always_calls(); }
721
722 bool call_on_shared_slow_path() const {
723 return contains_call_ == kCallOnSharedSlowPath;
724 }
725
726 void PrintTo(BaseTextBuffer* f) const;
727
728 static LocationSummary* Make(Zone* zone,
729 intptr_t input_count,
730 Location out,
731 ContainsCall contains_call);
732
733 RegisterSet* live_registers() { return &live_registers_; }
734
735#if defined(DEBUG)
736 // Debug only verification that ensures that writable registers are correctly
737 // preserved on the slow path.
738 void DiscoverWritableInputs();
739 void CheckWritableInputs();
740#endif
741
742 private:
743 const intptr_t num_inputs_;
744 Location* input_locations_;
745 const intptr_t num_temps_;
746 Location* temp_locations_;
747 Location output_location_;
748
749 BitmapBuilder* stack_bitmap_;
750
751 const ContainsCall contains_call_;
752 RegisterSet live_registers_;
753
754#if defined(DEBUG)
755 intptr_t writable_inputs_;
756#endif
757};
758
759} // namespace dart
760
761#endif // RUNTIME_VM_COMPILER_BACKEND_LOCATIONS_H_
762