OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #ifndef VM_LOCATIONS_H_ | 5 #ifndef VM_LOCATIONS_H_ |
6 #define VM_LOCATIONS_H_ | 6 #define VM_LOCATIONS_H_ |
7 | 7 |
8 #include "vm/allocation.h" | 8 #include "vm/allocation.h" |
9 #include "vm/assembler.h" | 9 #include "vm/assembler.h" |
10 #include "vm/bitfield.h" | 10 #include "vm/bitfield.h" |
11 | 11 |
12 namespace dart { | 12 namespace dart { |
13 | 13 |
| 14 class BufferFormatter; |
14 | 15 |
15 // Location objects are used to connect register allocator and code generator. | 16 // Location objects are used to connect register allocator and code generator. |
16 // Instruction templates used by code generator have a corresponding | 17 // Instruction templates used by code generator have a corresponding |
17 // LocationSummary object which specifies expected location for every input | 18 // LocationSummary object which specifies expected location for every input |
18 // and output. | 19 // and output. |
19 // Each location is encoded as a single word: low 2 bits denote location kind, | 20 // Each location is encoded as a single word: low 2 bits denote location kind, |
20 // rest is kind specific location payload e.g. for REGISTER kind payload is | 21 // rest is kind specific location payload e.g. for REGISTER kind payload is |
21 // register code (value of the Register enumeration). | 22 // register code (value of the Register enumeration). |
22 class Location : public ValueObject { | 23 class Location : public ValueObject { |
23 public: | 24 public: |
| 25 // Constant payload can overlap with kind field so Kind values |
| 26 // have to be chosen in a way that their last 2 bits are never |
| 27 // the same as kConstant. |
24 enum Kind { | 28 enum Kind { |
25 kInvalid, | 29 kInvalid = 0, |
| 30 |
| 31 kConstant = 1, |
26 | 32 |
27 // Unallocated location represents a location that is not fixed and can be | 33 // Unallocated location represents a location that is not fixed and can be |
28 // allocated by a register allocator. Each unallocated location has | 34 // allocated by a register allocator. Each unallocated location has |
29 // a policy that specifies what kind of location is suitable. | 35 // a policy that specifies what kind of location is suitable. |
30 kUnallocated, | 36 kUnallocated = 2, |
31 | 37 |
32 // Register location represents a fixed register. | 38 // Register location represents a fixed register. |
33 kRegister | 39 kRegister = 3 |
34 }; | 40 }; |
35 | 41 |
36 Location() : value_(KindField::encode(kInvalid)) { } | 42 static const uword kInvalidLocation = 0; |
| 43 static const uword kConstantMask = 0x3; |
37 | 44 |
38 Kind kind() const { return KindField::decode(value_); } | 45 Location() : value_(kInvalidLocation) { |
| 46 ASSERT(IsInvalid()); |
| 47 } |
| 48 |
| 49 bool IsInvalid() const { |
| 50 return value_ == kInvalidLocation; |
| 51 } |
| 52 |
| 53 // Constants. |
| 54 bool IsConstant() const { |
| 55 ASSERT((kConstant & kConstantMask) == kConstant); |
| 56 return (value_ & kConstantMask) == kConstant; |
| 57 } |
| 58 |
| 59 static Location Constant(const Object& obj) { |
| 60 Location loc(reinterpret_cast<uword>(&obj) | kConstant); |
| 61 ASSERT(&obj == &loc.constant()); |
| 62 return loc; |
| 63 } |
| 64 |
| 65 const Object& constant() { |
| 66 ASSERT(IsConstant()); |
| 67 return *reinterpret_cast<const Object*>(value_ & ~kConstantMask); |
| 68 } |
39 | 69 |
40 // Unallocated locations. | 70 // Unallocated locations. |
41 enum Policy { | 71 enum Policy { |
42 kRequiresRegister, | 72 kRequiresRegister, |
43 kSameAsFirstInput, | 73 kSameAsFirstInput, |
44 }; | 74 }; |
45 | 75 |
| 76 bool IsUnallocated() const { |
| 77 return kind() == kUnallocated; |
| 78 } |
| 79 |
46 static Location UnallocatedLocation(Policy policy) { | 80 static Location UnallocatedLocation(Policy policy) { |
47 return Location(kUnallocated, PolicyField::encode(policy)); | 81 return Location(kUnallocated, PolicyField::encode(policy)); |
48 } | 82 } |
49 | 83 |
50 // Any free register is suitable to replace this unallocated location. | 84 // Any free register is suitable to replace this unallocated location. |
51 static Location RequiresRegister() { | 85 static Location RequiresRegister() { |
52 return UnallocatedLocation(kRequiresRegister); | 86 return UnallocatedLocation(kRequiresRegister); |
53 } | 87 } |
54 | 88 |
55 // The location of the first input to the instruction will be | 89 // The location of the first input to the instruction will be |
56 // used to replace this unallocated location. | 90 // used to replace this unallocated location. |
57 static Location SameAsFirstInput() { | 91 static Location SameAsFirstInput() { |
58 return UnallocatedLocation(kSameAsFirstInput); | 92 return UnallocatedLocation(kSameAsFirstInput); |
59 } | 93 } |
60 | 94 |
61 // Empty location. Used if there the location should be ignored. | 95 // Empty location. Used if there the location should be ignored. |
62 static Location NoLocation() { | 96 static Location NoLocation() { |
63 return Location(); | 97 return Location(); |
64 } | 98 } |
65 | 99 |
66 Policy policy() const { | 100 Policy policy() const { |
67 ASSERT(kind() == kUnallocated); | 101 ASSERT(IsUnallocated()); |
68 return PolicyField::decode(payload()); | 102 return PolicyField::decode(payload()); |
69 } | 103 } |
70 | 104 |
71 // Register locations. | 105 // Register locations. |
72 static Location RegisterLocation(Register reg) { | 106 static Location RegisterLocation(Register reg) { |
73 return Location(kRegister, static_cast<uword>(reg)); | 107 return Location(kRegister, static_cast<uword>(reg)); |
74 } | 108 } |
75 | 109 |
| 110 bool IsRegister() const { |
| 111 return kind() == kRegister; |
| 112 } |
| 113 |
76 Register reg() const { | 114 Register reg() const { |
77 ASSERT(kind() == kRegister); | 115 ASSERT(IsRegister()); |
78 return static_cast<Register>(payload()); | 116 return static_cast<Register>(payload()); |
79 } | 117 } |
80 | 118 |
| 119 const char* Name() const; |
| 120 |
| 121 // Compare two non-constant locations. |
| 122 bool Equals(Location other) const { |
| 123 ASSERT(!IsConstant() && !other.IsConstant()); |
| 124 return value_ == other.value_; |
| 125 } |
| 126 |
81 private: | 127 private: |
| 128 explicit Location(uword value) : value_(value) { } |
| 129 |
82 Location(Kind kind, uword payload) | 130 Location(Kind kind, uword payload) |
83 : value_(KindField::encode(kind) | PayloadField::encode(payload)) { } | 131 : value_(KindField::encode(kind) | PayloadField::encode(payload)) { } |
84 | 132 |
85 uword payload() const { | 133 uword payload() const { |
86 return PayloadField::decode(value_); | 134 return PayloadField::decode(value_); |
87 } | 135 } |
88 | 136 |
| 137 // If current location is constant might return something that |
| 138 // is not equal to any Kind. |
| 139 Kind kind() const { |
| 140 return KindField::decode(value_); |
| 141 } |
| 142 |
89 typedef BitField<Kind, 0, 2> KindField; | 143 typedef BitField<Kind, 0, 2> KindField; |
90 typedef BitField<uword, 2, kWordSize * kBitsPerByte - 2> PayloadField; | 144 typedef BitField<uword, 2, kWordSize * kBitsPerByte - 2> PayloadField; |
91 | 145 |
92 // Layout for kUnallocated locations payload. | 146 // Layout for kUnallocated locations payload. |
93 typedef BitField<Policy, 0, 1> PolicyField; | 147 typedef BitField<Policy, 0, 1> PolicyField; |
94 | 148 |
95 // TODO(vegorov): choose fixed size for this field. | 149 // Location either contains kind and payload fields or a tagged handle for |
| 150 // a constant locations. Values of enumeration Kind are selected in such a |
| 151 // way that none of them can be interpreted as a kConstant tag. |
96 uword value_; | 152 uword value_; |
97 }; | 153 }; |
98 | 154 |
99 | 155 |
100 // Specification of locations for inputs and output. | 156 // Specification of locations for inputs and output. |
101 class LocationSummary : public ZoneAllocated { | 157 class LocationSummary : public ZoneAllocated { |
102 public: | 158 public: |
103 enum ContainsCall { | 159 enum ContainsCall { |
104 kNoCall, | 160 kNoCall, |
105 kCall, | 161 kCall, |
(...skipping 23 matching lines...) Expand all Loading... |
129 } | 185 } |
130 | 186 |
131 intptr_t input_count() const { | 187 intptr_t input_count() const { |
132 return input_locations_.length(); | 188 return input_locations_.length(); |
133 } | 189 } |
134 | 190 |
135 Location in(intptr_t index) const { | 191 Location in(intptr_t index) const { |
136 return input_locations_[index]; | 192 return input_locations_[index]; |
137 } | 193 } |
138 | 194 |
| 195 Location* in_slot(intptr_t index) { |
| 196 return &input_locations_[index]; |
| 197 } |
| 198 |
139 void set_in(intptr_t index, Location loc) { | 199 void set_in(intptr_t index, Location loc) { |
140 input_locations_[index] = loc; | 200 input_locations_[index] = loc; |
141 } | 201 } |
142 | 202 |
143 intptr_t temp_count() const { | 203 intptr_t temp_count() const { |
144 return temp_locations_.length(); | 204 return temp_locations_.length(); |
145 } | 205 } |
146 | 206 |
147 Location temp(intptr_t index) const { | 207 Location temp(intptr_t index) const { |
148 return temp_locations_[index]; | 208 return temp_locations_[index]; |
149 } | 209 } |
150 | 210 |
| 211 Location* temp_slot(intptr_t index) { |
| 212 return &temp_locations_[index]; |
| 213 } |
| 214 |
151 void set_temp(intptr_t index, Location loc) { | 215 void set_temp(intptr_t index, Location loc) { |
152 temp_locations_[index] = loc; | 216 temp_locations_[index] = loc; |
153 } | 217 } |
154 | 218 |
155 Location out() const { | 219 Location out() const { |
156 return output_location_; | 220 return output_location_; |
157 } | 221 } |
158 | 222 |
| 223 Location* out_slot() { |
| 224 return &output_location_; |
| 225 } |
| 226 |
| 227 |
159 void set_out(Location loc) { | 228 void set_out(Location loc) { |
160 output_location_ = loc; | 229 output_location_ = loc; |
161 } | 230 } |
162 | 231 |
163 bool is_call() const { | 232 bool is_call() const { |
164 return is_call_; | 233 return is_call_; |
165 } | 234 } |
166 | 235 |
167 // TODO(vegorov): this is a temporary solution. Once we will start removing | 236 // TODO(vegorov): this is a temporary solution. Once we will start removing |
168 // comparison operations from the flow graph when they are fused with a branch | 237 // comparison operations from the flow graph when they are fused with a branch |
169 // we should eliminate this. | 238 // we should eliminate this. |
170 bool is_branch() const { | 239 bool is_branch() const { |
171 return is_branch_; | 240 return is_branch_; |
172 } | 241 } |
173 | 242 |
| 243 void PrintTo(BufferFormatter* f) const; |
| 244 |
174 static LocationSummary* Make(intptr_t input_count, | 245 static LocationSummary* Make(intptr_t input_count, |
175 Location out, | 246 Location out, |
176 ContainsCall contains_call = kNoCall, | 247 ContainsCall contains_call = kNoCall, |
177 ContainsBranch contains_branch = kNoBranch); | 248 ContainsBranch contains_branch = kNoBranch); |
178 | 249 |
179 private: | 250 private: |
180 // TODO(vegorov): replace with ZoneArray. | 251 // TODO(vegorov): replace with ZoneArray. |
181 GrowableArray<Location> input_locations_; | 252 GrowableArray<Location> input_locations_; |
182 GrowableArray<Location> temp_locations_; | 253 GrowableArray<Location> temp_locations_; |
183 Location output_location_; | 254 Location output_location_; |
184 | 255 |
185 const bool is_call_; | 256 const bool is_call_; |
186 const bool is_branch_; | 257 const bool is_branch_; |
187 }; | 258 }; |
188 | 259 |
189 | 260 |
190 } // namespace dart | 261 } // namespace dart |
191 | 262 |
192 #endif // VM_LOCATIONS_H_ | 263 #endif // VM_LOCATIONS_H_ |
OLD | NEW |