• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_COMPILER_OPTIMIZING_LOCATIONS_H_
18 #define ART_COMPILER_OPTIMIZING_LOCATIONS_H_
19 
20 #include "base/arena_containers.h"
21 #include "base/arena_object.h"
22 #include "base/bit_field.h"
23 #include "base/bit_vector.h"
24 #include "base/value_object.h"
25 
26 namespace art {
27 
28 class HConstant;
29 class HInstruction;
30 class Location;
31 
32 std::ostream& operator<<(std::ostream& os, const Location& location);
33 
34 /**
35  * A Location is an abstraction over the potential location
36  * of an instruction. It could be in register or stack.
37  */
38 class Location : public ValueObject {
39  public:
40   enum OutputOverlap {
41     kOutputOverlap,
42     kNoOutputOverlap
43   };
44 
45   enum Kind {
46     kInvalid = 0,
47     kConstant = 1,
48     kStackSlot = 2,  // 32bit stack slot.
49     kDoubleStackSlot = 3,  // 64bit stack slot.
50 
51     kRegister = 4,  // Core register.
52 
53     // We do not use the value 5 because it conflicts with kLocationConstantMask.
54     kDoNotUse5 = 5,
55 
56     kFpuRegister = 6,  // Float register.
57 
58     kRegisterPair = 7,  // Long register.
59 
60     kFpuRegisterPair = 8,  // Double register.
61 
62     // We do not use the value 9 because it conflicts with kLocationConstantMask.
63     kDoNotUse9 = 9,
64 
65     // Unallocated location represents a location that is not fixed and can be
66     // allocated by a register allocator.  Each unallocated location has
67     // a policy that specifies what kind of location is suitable. Payload
68     // contains register allocation policy.
69     kUnallocated = 10,
70   };
71 
Location()72   Location() : ValueObject(), value_(kInvalid) {
73     // Verify that non-constant location kinds do not interfere with kConstant.
74     static_assert((kInvalid & kLocationConstantMask) != kConstant, "TagError");
75     static_assert((kUnallocated & kLocationConstantMask) != kConstant, "TagError");
76     static_assert((kStackSlot & kLocationConstantMask) != kConstant, "TagError");
77     static_assert((kDoubleStackSlot & kLocationConstantMask) != kConstant, "TagError");
78     static_assert((kRegister & kLocationConstantMask) != kConstant, "TagError");
79     static_assert((kFpuRegister & kLocationConstantMask) != kConstant, "TagError");
80     static_assert((kRegisterPair & kLocationConstantMask) != kConstant, "TagError");
81     static_assert((kFpuRegisterPair & kLocationConstantMask) != kConstant, "TagError");
82     static_assert((kConstant & kLocationConstantMask) == kConstant, "TagError");
83 
84     DCHECK(!IsValid());
85   }
86 
Location(const Location & other)87   Location(const Location& other) : value_(other.value_) {}
88 
89   Location& operator=(const Location& other) {
90     value_ = other.value_;
91     return *this;
92   }
93 
IsConstant()94   bool IsConstant() const {
95     return (value_ & kLocationConstantMask) == kConstant;
96   }
97 
ConstantLocation(HConstant * constant)98   static Location ConstantLocation(HConstant* constant) {
99     DCHECK(constant != nullptr);
100     return Location(kConstant | reinterpret_cast<uintptr_t>(constant));
101   }
102 
GetConstant()103   HConstant* GetConstant() const {
104     DCHECK(IsConstant());
105     return reinterpret_cast<HConstant*>(value_ & ~kLocationConstantMask);
106   }
107 
IsValid()108   bool IsValid() const {
109     return value_ != kInvalid;
110   }
111 
IsInvalid()112   bool IsInvalid() const {
113     return !IsValid();
114   }
115 
116   // Empty location. Used if there the location should be ignored.
NoLocation()117   static Location NoLocation() {
118     return Location();
119   }
120 
121   // Register locations.
RegisterLocation(int reg)122   static Location RegisterLocation(int reg) {
123     return Location(kRegister, reg);
124   }
125 
FpuRegisterLocation(int reg)126   static Location FpuRegisterLocation(int reg) {
127     return Location(kFpuRegister, reg);
128   }
129 
RegisterPairLocation(int low,int high)130   static Location RegisterPairLocation(int low, int high) {
131     return Location(kRegisterPair, low << 16 | high);
132   }
133 
FpuRegisterPairLocation(int low,int high)134   static Location FpuRegisterPairLocation(int low, int high) {
135     return Location(kFpuRegisterPair, low << 16 | high);
136   }
137 
IsRegister()138   bool IsRegister() const {
139     return GetKind() == kRegister;
140   }
141 
IsFpuRegister()142   bool IsFpuRegister() const {
143     return GetKind() == kFpuRegister;
144   }
145 
IsRegisterPair()146   bool IsRegisterPair() const {
147     return GetKind() == kRegisterPair;
148   }
149 
IsFpuRegisterPair()150   bool IsFpuRegisterPair() const {
151     return GetKind() == kFpuRegisterPair;
152   }
153 
IsRegisterKind()154   bool IsRegisterKind() const {
155     return IsRegister() || IsFpuRegister() || IsRegisterPair() || IsFpuRegisterPair();
156   }
157 
reg()158   int reg() const {
159     DCHECK(IsRegister() || IsFpuRegister());
160     return GetPayload();
161   }
162 
low()163   int low() const {
164     DCHECK(IsPair());
165     return GetPayload() >> 16;
166   }
167 
high()168   int high() const {
169     DCHECK(IsPair());
170     return GetPayload() & 0xFFFF;
171   }
172 
173   template <typename T>
AsRegister()174   T AsRegister() const {
175     DCHECK(IsRegister());
176     return static_cast<T>(reg());
177   }
178 
179   template <typename T>
AsFpuRegister()180   T AsFpuRegister() const {
181     DCHECK(IsFpuRegister());
182     return static_cast<T>(reg());
183   }
184 
185   template <typename T>
AsRegisterPairLow()186   T AsRegisterPairLow() const {
187     DCHECK(IsRegisterPair());
188     return static_cast<T>(low());
189   }
190 
191   template <typename T>
AsRegisterPairHigh()192   T AsRegisterPairHigh() const {
193     DCHECK(IsRegisterPair());
194     return static_cast<T>(high());
195   }
196 
197   template <typename T>
AsFpuRegisterPairLow()198   T AsFpuRegisterPairLow() const {
199     DCHECK(IsFpuRegisterPair());
200     return static_cast<T>(low());
201   }
202 
203   template <typename T>
AsFpuRegisterPairHigh()204   T AsFpuRegisterPairHigh() const {
205     DCHECK(IsFpuRegisterPair());
206     return static_cast<T>(high());
207   }
208 
IsPair()209   bool IsPair() const {
210     return IsRegisterPair() || IsFpuRegisterPair();
211   }
212 
ToLow()213   Location ToLow() const {
214     if (IsRegisterPair()) {
215       return Location::RegisterLocation(low());
216     } else if (IsFpuRegisterPair()) {
217       return Location::FpuRegisterLocation(low());
218     } else {
219       DCHECK(IsDoubleStackSlot());
220       return Location::StackSlot(GetStackIndex());
221     }
222   }
223 
ToHigh()224   Location ToHigh() const {
225     if (IsRegisterPair()) {
226       return Location::RegisterLocation(high());
227     } else if (IsFpuRegisterPair()) {
228       return Location::FpuRegisterLocation(high());
229     } else {
230       DCHECK(IsDoubleStackSlot());
231       return Location::StackSlot(GetHighStackIndex(4));
232     }
233   }
234 
EncodeStackIndex(intptr_t stack_index)235   static uintptr_t EncodeStackIndex(intptr_t stack_index) {
236     DCHECK(-kStackIndexBias <= stack_index);
237     DCHECK(stack_index < kStackIndexBias);
238     return static_cast<uintptr_t>(kStackIndexBias + stack_index);
239   }
240 
StackSlot(intptr_t stack_index)241   static Location StackSlot(intptr_t stack_index) {
242     uintptr_t payload = EncodeStackIndex(stack_index);
243     Location loc(kStackSlot, payload);
244     // Ensure that sign is preserved.
245     DCHECK_EQ(loc.GetStackIndex(), stack_index);
246     return loc;
247   }
248 
IsStackSlot()249   bool IsStackSlot() const {
250     return GetKind() == kStackSlot;
251   }
252 
DoubleStackSlot(intptr_t stack_index)253   static Location DoubleStackSlot(intptr_t stack_index) {
254     uintptr_t payload = EncodeStackIndex(stack_index);
255     Location loc(kDoubleStackSlot, payload);
256     // Ensure that sign is preserved.
257     DCHECK_EQ(loc.GetStackIndex(), stack_index);
258     return loc;
259   }
260 
IsDoubleStackSlot()261   bool IsDoubleStackSlot() const {
262     return GetKind() == kDoubleStackSlot;
263   }
264 
GetStackIndex()265   intptr_t GetStackIndex() const {
266     DCHECK(IsStackSlot() || IsDoubleStackSlot());
267     // Decode stack index manually to preserve sign.
268     return GetPayload() - kStackIndexBias;
269   }
270 
GetHighStackIndex(uintptr_t word_size)271   intptr_t GetHighStackIndex(uintptr_t word_size) const {
272     DCHECK(IsDoubleStackSlot());
273     // Decode stack index manually to preserve sign.
274     return GetPayload() - kStackIndexBias + word_size;
275   }
276 
GetKind()277   Kind GetKind() const {
278     return IsConstant() ? kConstant : KindField::Decode(value_);
279   }
280 
Equals(Location other)281   bool Equals(Location other) const {
282     return value_ == other.value_;
283   }
284 
Contains(Location other)285   bool Contains(Location other) const {
286     if (Equals(other)) {
287       return true;
288     } else if (IsPair() || IsDoubleStackSlot()) {
289       return ToLow().Equals(other) || ToHigh().Equals(other);
290     }
291     return false;
292   }
293 
OverlapsWith(Location other)294   bool OverlapsWith(Location other) const {
295     // Only check the overlapping case that can happen with our register allocation algorithm.
296     bool overlap = Contains(other) || other.Contains(*this);
297     if (kIsDebugBuild && !overlap) {
298       // Note: These are also overlapping cases. But we are not able to handle them in
299       // ParallelMoveResolverWithSwap. Make sure that we do not meet such case with our compiler.
300       if ((IsPair() && other.IsPair()) || (IsDoubleStackSlot() && other.IsDoubleStackSlot())) {
301         DCHECK(!Contains(other.ToLow()));
302         DCHECK(!Contains(other.ToHigh()));
303       }
304     }
305     return overlap;
306   }
307 
DebugString()308   const char* DebugString() const {
309     switch (GetKind()) {
310       case kInvalid: return "I";
311       case kRegister: return "R";
312       case kStackSlot: return "S";
313       case kDoubleStackSlot: return "DS";
314       case kUnallocated: return "U";
315       case kConstant: return "C";
316       case kFpuRegister: return "F";
317       case kRegisterPair: return "RP";
318       case kFpuRegisterPair: return "FP";
319       case kDoNotUse5:  // fall-through
320       case kDoNotUse9:
321         LOG(FATAL) << "Should not use this location kind";
322     }
323     UNREACHABLE();
324     return "?";
325   }
326 
327   // Unallocated locations.
328   enum Policy {
329     kAny,
330     kRequiresRegister,
331     kRequiresFpuRegister,
332     kSameAsFirstInput,
333   };
334 
IsUnallocated()335   bool IsUnallocated() const {
336     return GetKind() == kUnallocated;
337   }
338 
UnallocatedLocation(Policy policy)339   static Location UnallocatedLocation(Policy policy) {
340     return Location(kUnallocated, PolicyField::Encode(policy));
341   }
342 
343   // Any free register is suitable to replace this unallocated location.
Any()344   static Location Any() {
345     return UnallocatedLocation(kAny);
346   }
347 
RequiresRegister()348   static Location RequiresRegister() {
349     return UnallocatedLocation(kRequiresRegister);
350   }
351 
RequiresFpuRegister()352   static Location RequiresFpuRegister() {
353     return UnallocatedLocation(kRequiresFpuRegister);
354   }
355 
356   static Location RegisterOrConstant(HInstruction* instruction);
357   static Location RegisterOrInt32Constant(HInstruction* instruction);
358   static Location ByteRegisterOrConstant(int reg, HInstruction* instruction);
359   static Location FpuRegisterOrConstant(HInstruction* instruction);
360   static Location FpuRegisterOrInt32Constant(HInstruction* instruction);
361 
362   // The location of the first input to the instruction will be
363   // used to replace this unallocated location.
SameAsFirstInput()364   static Location SameAsFirstInput() {
365     return UnallocatedLocation(kSameAsFirstInput);
366   }
367 
GetPolicy()368   Policy GetPolicy() const {
369     DCHECK(IsUnallocated());
370     return PolicyField::Decode(GetPayload());
371   }
372 
GetEncoding()373   uintptr_t GetEncoding() const {
374     return GetPayload();
375   }
376 
377  private:
378   // Number of bits required to encode Kind value.
379   static constexpr uint32_t kBitsForKind = 4;
380   static constexpr uint32_t kBitsForPayload = kBitsPerIntPtrT - kBitsForKind;
381   static constexpr uintptr_t kLocationConstantMask = 0x3;
382 
Location(uintptr_t value)383   explicit Location(uintptr_t value) : value_(value) {}
384 
Location(Kind kind,uintptr_t payload)385   Location(Kind kind, uintptr_t payload)
386       : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {}
387 
GetPayload()388   uintptr_t GetPayload() const {
389     return PayloadField::Decode(value_);
390   }
391 
392   typedef BitField<Kind, 0, kBitsForKind> KindField;
393   typedef BitField<uintptr_t, kBitsForKind, kBitsForPayload> PayloadField;
394 
395   // Layout for kUnallocated locations payload.
396   typedef BitField<Policy, 0, 3> PolicyField;
397 
398   // Layout for stack slots.
399   static const intptr_t kStackIndexBias =
400       static_cast<intptr_t>(1) << (kBitsForPayload - 1);
401 
402   // Location either contains kind and payload fields or a tagged handle for
403   // a constant locations. Values of enumeration Kind are selected in such a
404   // way that none of them can be interpreted as a kConstant tag.
405   uintptr_t value_;
406 };
407 std::ostream& operator<<(std::ostream& os, const Location::Kind& rhs);
408 std::ostream& operator<<(std::ostream& os, const Location::Policy& rhs);
409 
410 class RegisterSet : public ValueObject {
411  public:
RegisterSet()412   RegisterSet() : core_registers_(0), floating_point_registers_(0) {}
413 
Add(Location loc)414   void Add(Location loc) {
415     if (loc.IsRegister()) {
416       core_registers_ |= (1 << loc.reg());
417     } else {
418       DCHECK(loc.IsFpuRegister());
419       floating_point_registers_ |= (1 << loc.reg());
420     }
421   }
422 
Remove(Location loc)423   void Remove(Location loc) {
424     if (loc.IsRegister()) {
425       core_registers_ &= ~(1 << loc.reg());
426     } else {
427       DCHECK(loc.IsFpuRegister()) << loc;
428       floating_point_registers_ &= ~(1 << loc.reg());
429     }
430   }
431 
ContainsCoreRegister(uint32_t id)432   bool ContainsCoreRegister(uint32_t id) const {
433     return Contains(core_registers_, id);
434   }
435 
ContainsFloatingPointRegister(uint32_t id)436   bool ContainsFloatingPointRegister(uint32_t id) const {
437     return Contains(floating_point_registers_, id);
438   }
439 
Contains(uint32_t register_set,uint32_t reg)440   static bool Contains(uint32_t register_set, uint32_t reg) {
441     return (register_set & (1 << reg)) != 0;
442   }
443 
GetNumberOfRegisters()444   size_t GetNumberOfRegisters() const {
445     return __builtin_popcount(core_registers_) + __builtin_popcount(floating_point_registers_);
446   }
447 
GetCoreRegisters()448   uint32_t GetCoreRegisters() const {
449     return core_registers_;
450   }
451 
GetFloatingPointRegisters()452   uint32_t GetFloatingPointRegisters() const {
453     return floating_point_registers_;
454   }
455 
456  private:
457   uint32_t core_registers_;
458   uint32_t floating_point_registers_;
459 
460   DISALLOW_COPY_AND_ASSIGN(RegisterSet);
461 };
462 
463 static constexpr bool kIntrinsified = true;
464 
465 /**
466  * The code generator computes LocationSummary for each instruction so that
467  * the instruction itself knows what code to generate: where to find the inputs
468  * and where to place the result.
469  *
470  * The intent is to have the code for generating the instruction independent of
471  * register allocation. A register allocator just has to provide a LocationSummary.
472  */
473 class LocationSummary : public ArenaObject<kArenaAllocLocationSummary> {
474  public:
475   enum CallKind {
476     kNoCall,
477     kCallOnSlowPath,
478     kCall
479   };
480 
481   LocationSummary(HInstruction* instruction,
482                   CallKind call_kind = kNoCall,
483                   bool intrinsified = false);
484 
SetInAt(uint32_t at,Location location)485   void SetInAt(uint32_t at, Location location) {
486     inputs_[at] = location;
487   }
488 
InAt(uint32_t at)489   Location InAt(uint32_t at) const {
490     return inputs_[at];
491   }
492 
GetInputCount()493   size_t GetInputCount() const {
494     return inputs_.size();
495   }
496 
497   void SetOut(Location location, Location::OutputOverlap overlaps = Location::kOutputOverlap) {
498     DCHECK(output_.IsInvalid());
499     output_overlaps_ = overlaps;
500     output_ = location;
501   }
502 
UpdateOut(Location location)503   void UpdateOut(Location location) {
504     // There are two reasons for updating an output:
505     // 1) Parameters, where we only know the exact stack slot after
506     //    doing full register allocation.
507     // 2) Unallocated location.
508     DCHECK(output_.IsStackSlot() || output_.IsDoubleStackSlot() || output_.IsUnallocated());
509     output_ = location;
510   }
511 
AddTemp(Location location)512   void AddTemp(Location location) {
513     temps_.push_back(location);
514   }
515 
GetTemp(uint32_t at)516   Location GetTemp(uint32_t at) const {
517     return temps_[at];
518   }
519 
SetTempAt(uint32_t at,Location location)520   void SetTempAt(uint32_t at, Location location) {
521     DCHECK(temps_[at].IsUnallocated() || temps_[at].IsInvalid());
522     temps_[at] = location;
523   }
524 
GetTempCount()525   size_t GetTempCount() const {
526     return temps_.size();
527   }
528 
HasTemps()529   bool HasTemps() const { return !temps_.empty(); }
530 
Out()531   Location Out() const { return output_; }
532 
CanCall()533   bool CanCall() const { return call_kind_ != kNoCall; }
WillCall()534   bool WillCall() const { return call_kind_ == kCall; }
OnlyCallsOnSlowPath()535   bool OnlyCallsOnSlowPath() const { return call_kind_ == kCallOnSlowPath; }
NeedsSafepoint()536   bool NeedsSafepoint() const { return CanCall(); }
537 
SetStackBit(uint32_t index)538   void SetStackBit(uint32_t index) {
539     stack_mask_->SetBit(index);
540   }
541 
ClearStackBit(uint32_t index)542   void ClearStackBit(uint32_t index) {
543     stack_mask_->ClearBit(index);
544   }
545 
SetRegisterBit(uint32_t reg_id)546   void SetRegisterBit(uint32_t reg_id) {
547     register_mask_ |= (1 << reg_id);
548   }
549 
GetRegisterMask()550   uint32_t GetRegisterMask() const {
551     return register_mask_;
552   }
553 
RegisterContainsObject(uint32_t reg_id)554   bool RegisterContainsObject(uint32_t reg_id) {
555     return RegisterSet::Contains(register_mask_, reg_id);
556   }
557 
AddLiveRegister(Location location)558   void AddLiveRegister(Location location) {
559     live_registers_.Add(location);
560   }
561 
GetStackMask()562   BitVector* GetStackMask() const {
563     return stack_mask_;
564   }
565 
GetLiveRegisters()566   RegisterSet* GetLiveRegisters() {
567     return &live_registers_;
568   }
569 
GetNumberOfLiveRegisters()570   size_t GetNumberOfLiveRegisters() const {
571     return live_registers_.GetNumberOfRegisters();
572   }
573 
OutputUsesSameAs(uint32_t input_index)574   bool OutputUsesSameAs(uint32_t input_index) const {
575     return (input_index == 0)
576         && output_.IsUnallocated()
577         && (output_.GetPolicy() == Location::kSameAsFirstInput);
578   }
579 
IsFixedInput(uint32_t input_index)580   bool IsFixedInput(uint32_t input_index) const {
581     Location input = inputs_[input_index];
582     return input.IsRegister()
583         || input.IsFpuRegister()
584         || input.IsPair()
585         || input.IsStackSlot()
586         || input.IsDoubleStackSlot();
587   }
588 
OutputCanOverlapWithInputs()589   bool OutputCanOverlapWithInputs() const {
590     return output_overlaps_ == Location::kOutputOverlap;
591   }
592 
Intrinsified()593   bool Intrinsified() const {
594     return intrinsified_;
595   }
596 
SetIntrinsified(bool intrinsified)597   void SetIntrinsified(bool intrinsified) {
598     intrinsified_ = intrinsified;
599   }
600 
601  private:
602   ArenaVector<Location> inputs_;
603   ArenaVector<Location> temps_;
604   // Whether the output overlaps with any of the inputs. If it overlaps, then it cannot
605   // share the same register as the inputs.
606   Location::OutputOverlap output_overlaps_;
607   Location output_;
608   const CallKind call_kind_;
609 
610   // Mask of objects that live in the stack.
611   BitVector* stack_mask_;
612 
613   // Mask of objects that live in register.
614   uint32_t register_mask_;
615 
616   // Registers that are in use at this position.
617   RegisterSet live_registers_;
618 
619   // Whether these are locations for an intrinsified call.
620   bool intrinsified_;
621 
622   ART_FRIEND_TEST(RegisterAllocatorTest, ExpectedInRegisterHint);
623   ART_FRIEND_TEST(RegisterAllocatorTest, SameAsFirstInputHint);
624   DISALLOW_COPY_AND_ASSIGN(LocationSummary);
625 };
626 
627 }  // namespace art
628 
629 #endif  // ART_COMPILER_OPTIMIZING_LOCATIONS_H_
630