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_object.h"
21 #include "base/bit_field.h"
22 #include "base/bit_vector.h"
23 #include "base/value_object.h"
24 #include "utils/growable_array.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() : 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) : ValueObject(), 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 RegisterOrInt32LongConstant(HInstruction* instruction);
358   static Location ByteRegisterOrConstant(int reg, HInstruction* instruction);
359 
360   // The location of the first input to the instruction will be
361   // used to replace this unallocated location.
SameAsFirstInput()362   static Location SameAsFirstInput() {
363     return UnallocatedLocation(kSameAsFirstInput);
364   }
365 
GetPolicy()366   Policy GetPolicy() const {
367     DCHECK(IsUnallocated());
368     return PolicyField::Decode(GetPayload());
369   }
370 
GetEncoding()371   uintptr_t GetEncoding() const {
372     return GetPayload();
373   }
374 
375  private:
376   // Number of bits required to encode Kind value.
377   static constexpr uint32_t kBitsForKind = 4;
378   static constexpr uint32_t kBitsForPayload = kBitsPerIntPtrT - kBitsForKind;
379   static constexpr uintptr_t kLocationConstantMask = 0x3;
380 
Location(uintptr_t value)381   explicit Location(uintptr_t value) : value_(value) {}
382 
Location(Kind kind,uintptr_t payload)383   Location(Kind kind, uintptr_t payload)
384       : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {}
385 
GetPayload()386   uintptr_t GetPayload() const {
387     return PayloadField::Decode(value_);
388   }
389 
390   typedef BitField<Kind, 0, kBitsForKind> KindField;
391   typedef BitField<uintptr_t, kBitsForKind, kBitsForPayload> PayloadField;
392 
393   // Layout for kUnallocated locations payload.
394   typedef BitField<Policy, 0, 3> PolicyField;
395 
396   // Layout for stack slots.
397   static const intptr_t kStackIndexBias =
398       static_cast<intptr_t>(1) << (kBitsForPayload - 1);
399 
400   // Location either contains kind and payload fields or a tagged handle for
401   // a constant locations. Values of enumeration Kind are selected in such a
402   // way that none of them can be interpreted as a kConstant tag.
403   uintptr_t value_;
404 };
405 std::ostream& operator<<(std::ostream& os, const Location::Kind& rhs);
406 std::ostream& operator<<(std::ostream& os, const Location::Policy& rhs);
407 
408 class RegisterSet : public ValueObject {
409  public:
RegisterSet()410   RegisterSet() : core_registers_(0), floating_point_registers_(0) {}
411 
Add(Location loc)412   void Add(Location loc) {
413     if (loc.IsRegister()) {
414       core_registers_ |= (1 << loc.reg());
415     } else {
416       DCHECK(loc.IsFpuRegister());
417       floating_point_registers_ |= (1 << loc.reg());
418     }
419   }
420 
Remove(Location loc)421   void Remove(Location loc) {
422     if (loc.IsRegister()) {
423       core_registers_ &= ~(1 << loc.reg());
424     } else {
425       DCHECK(loc.IsFpuRegister()) << loc;
426       floating_point_registers_ &= ~(1 << loc.reg());
427     }
428   }
429 
ContainsCoreRegister(uint32_t id)430   bool ContainsCoreRegister(uint32_t id) {
431     return Contains(core_registers_, id);
432   }
433 
ContainsFloatingPointRegister(uint32_t id)434   bool ContainsFloatingPointRegister(uint32_t id) {
435     return Contains(floating_point_registers_, id);
436   }
437 
Contains(uint32_t register_set,uint32_t reg)438   static bool Contains(uint32_t register_set, uint32_t reg) {
439     return (register_set & (1 << reg)) != 0;
440   }
441 
GetNumberOfRegisters()442   size_t GetNumberOfRegisters() const {
443     return __builtin_popcount(core_registers_) + __builtin_popcount(floating_point_registers_);
444   }
445 
GetCoreRegisters()446   uint32_t GetCoreRegisters() const {
447     return core_registers_;
448   }
449 
GetFloatingPointRegisters()450   uint32_t GetFloatingPointRegisters() const {
451     return floating_point_registers_;
452   }
453 
454  private:
455   uint32_t core_registers_;
456   uint32_t floating_point_registers_;
457 
458   DISALLOW_COPY_AND_ASSIGN(RegisterSet);
459 };
460 
461 static constexpr bool kIntrinsified = true;
462 
463 /**
464  * The code generator computes LocationSummary for each instruction so that
465  * the instruction itself knows what code to generate: where to find the inputs
466  * and where to place the result.
467  *
468  * The intent is to have the code for generating the instruction independent of
469  * register allocation. A register allocator just has to provide a LocationSummary.
470  */
471 class LocationSummary : public ArenaObject<kArenaAllocMisc> {
472  public:
473   enum CallKind {
474     kNoCall,
475     kCallOnSlowPath,
476     kCall
477   };
478 
479   LocationSummary(HInstruction* instruction,
480                   CallKind call_kind = kNoCall,
481                   bool intrinsified = false);
482 
SetInAt(uint32_t at,Location location)483   void SetInAt(uint32_t at, Location location) {
484     DCHECK(inputs_.Get(at).IsUnallocated() || inputs_.Get(at).IsInvalid());
485     inputs_.Put(at, location);
486   }
487 
InAt(uint32_t at)488   Location InAt(uint32_t at) const {
489     return inputs_.Get(at);
490   }
491 
GetInputCount()492   size_t GetInputCount() const {
493     return inputs_.Size();
494   }
495 
496   void SetOut(Location location, Location::OutputOverlap overlaps = Location::kOutputOverlap) {
497     DCHECK(output_.IsInvalid());
498     output_overlaps_ = overlaps;
499     output_ = location;
500   }
501 
UpdateOut(Location location)502   void UpdateOut(Location location) {
503     // There are two reasons for updating an output:
504     // 1) Parameters, where we only know the exact stack slot after
505     //    doing full register allocation.
506     // 2) Unallocated location.
507     DCHECK(output_.IsStackSlot() || output_.IsDoubleStackSlot() || output_.IsUnallocated());
508     output_ = location;
509   }
510 
AddTemp(Location location)511   void AddTemp(Location location) {
512     temps_.Add(location);
513   }
514 
GetTemp(uint32_t at)515   Location GetTemp(uint32_t at) const {
516     return temps_.Get(at);
517   }
518 
SetTempAt(uint32_t at,Location location)519   void SetTempAt(uint32_t at, Location location) {
520     DCHECK(temps_.Get(at).IsUnallocated() || temps_.Get(at).IsInvalid());
521     temps_.Put(at, location);
522   }
523 
GetTempCount()524   size_t GetTempCount() const {
525     return temps_.Size();
526   }
527 
Out()528   Location Out() const { return output_; }
529 
CanCall()530   bool CanCall() const { return call_kind_ != kNoCall; }
WillCall()531   bool WillCall() const { return call_kind_ == kCall; }
OnlyCallsOnSlowPath()532   bool OnlyCallsOnSlowPath() const { return call_kind_ == kCallOnSlowPath; }
NeedsSafepoint()533   bool NeedsSafepoint() const { return CanCall(); }
534 
SetStackBit(uint32_t index)535   void SetStackBit(uint32_t index) {
536     stack_mask_->SetBit(index);
537   }
538 
ClearStackBit(uint32_t index)539   void ClearStackBit(uint32_t index) {
540     stack_mask_->ClearBit(index);
541   }
542 
SetRegisterBit(uint32_t reg_id)543   void SetRegisterBit(uint32_t reg_id) {
544     register_mask_ |= (1 << reg_id);
545   }
546 
GetRegisterMask()547   uint32_t GetRegisterMask() const {
548     return register_mask_;
549   }
550 
RegisterContainsObject(uint32_t reg_id)551   bool RegisterContainsObject(uint32_t reg_id) {
552     return RegisterSet::Contains(register_mask_, reg_id);
553   }
554 
AddLiveRegister(Location location)555   void AddLiveRegister(Location location) {
556     live_registers_.Add(location);
557   }
558 
GetStackMask()559   BitVector* GetStackMask() const {
560     return stack_mask_;
561   }
562 
GetLiveRegisters()563   RegisterSet* GetLiveRegisters() {
564     return &live_registers_;
565   }
566 
GetNumberOfLiveRegisters()567   size_t GetNumberOfLiveRegisters() const {
568     return live_registers_.GetNumberOfRegisters();
569   }
570 
OutputUsesSameAs(uint32_t input_index)571   bool OutputUsesSameAs(uint32_t input_index) const {
572     return (input_index == 0)
573         && output_.IsUnallocated()
574         && (output_.GetPolicy() == Location::kSameAsFirstInput);
575   }
576 
IsFixedInput(uint32_t input_index)577   bool IsFixedInput(uint32_t input_index) const {
578     Location input = inputs_.Get(input_index);
579     return input.IsRegister()
580         || input.IsFpuRegister()
581         || input.IsPair()
582         || input.IsStackSlot()
583         || input.IsDoubleStackSlot();
584   }
585 
OutputCanOverlapWithInputs()586   bool OutputCanOverlapWithInputs() const {
587     return output_overlaps_ == Location::kOutputOverlap;
588   }
589 
Intrinsified()590   bool Intrinsified() const {
591     return intrinsified_;
592   }
593 
594  private:
595   GrowableArray<Location> inputs_;
596   GrowableArray<Location> temps_;
597   // Whether the output overlaps with any of the inputs. If it overlaps, then it cannot
598   // share the same register as the inputs.
599   Location::OutputOverlap output_overlaps_;
600   Location output_;
601   const CallKind call_kind_;
602 
603   // Mask of objects that live in the stack.
604   BitVector* stack_mask_;
605 
606   // Mask of objects that live in register.
607   uint32_t register_mask_;
608 
609   // Registers that are in use at this position.
610   RegisterSet live_registers_;
611 
612   // Whether these are locations for an intrinsified call.
613   const bool intrinsified_;
614 
615   ART_FRIEND_TEST(RegisterAllocatorTest, ExpectedInRegisterHint);
616   ART_FRIEND_TEST(RegisterAllocatorTest, SameAsFirstInputHint);
617   DISALLOW_COPY_AND_ASSIGN(LocationSummary);
618 };
619 
620 }  // namespace art
621 
622 #endif  // ART_COMPILER_OPTIMIZING_LOCATIONS_H_
623