OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_COMPILER_INSTRUCTION_H_ | 5 #ifndef V8_COMPILER_INSTRUCTION_H_ |
6 #define V8_COMPILER_INSTRUCTION_H_ | 6 #define V8_COMPILER_INSTRUCTION_H_ |
7 | 7 |
8 #include <deque> | 8 #include <deque> |
9 #include <iosfwd> | 9 #include <iosfwd> |
10 #include <map> | 10 #include <map> |
(...skipping 17 matching lines...) Expand all Loading... |
28 const InstructionCode kSourcePositionInstruction = -1; | 28 const InstructionCode kSourcePositionInstruction = -1; |
29 | 29 |
30 class InstructionOperand { | 30 class InstructionOperand { |
31 public: | 31 public: |
32 static const int kInvalidVirtualRegister = -1; | 32 static const int kInvalidVirtualRegister = -1; |
33 | 33 |
34 // TODO(dcarney): recover bit. INVALID can be represented as UNALLOCATED with | 34 // TODO(dcarney): recover bit. INVALID can be represented as UNALLOCATED with |
35 // kInvalidVirtualRegister and some DCHECKS. | 35 // kInvalidVirtualRegister and some DCHECKS. |
36 enum Kind { INVALID, UNALLOCATED, CONSTANT, IMMEDIATE, ALLOCATED }; | 36 enum Kind { INVALID, UNALLOCATED, CONSTANT, IMMEDIATE, ALLOCATED }; |
37 | 37 |
38 InstructionOperand() | 38 InstructionOperand() : InstructionOperand(INVALID) {} |
39 : InstructionOperand(INVALID, 0, kInvalidVirtualRegister) {} | |
40 | 39 |
41 Kind kind() const { return KindField::decode(value_); } | 40 Kind kind() const { return KindField::decode(value_); } |
42 | 41 |
43 #define INSTRUCTION_OPERAND_PREDICATE(name, type) \ | 42 #define INSTRUCTION_OPERAND_PREDICATE(name, type) \ |
44 bool Is##name() const { return kind() == type; } | 43 bool Is##name() const { return kind() == type; } |
45 INSTRUCTION_OPERAND_PREDICATE(Invalid, INVALID) | 44 INSTRUCTION_OPERAND_PREDICATE(Invalid, INVALID) |
46 INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED) | 45 INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED) |
47 INSTRUCTION_OPERAND_PREDICATE(Constant, CONSTANT) | 46 INSTRUCTION_OPERAND_PREDICATE(Constant, CONSTANT) |
48 INSTRUCTION_OPERAND_PREDICATE(Immediate, IMMEDIATE) | 47 INSTRUCTION_OPERAND_PREDICATE(Immediate, IMMEDIATE) |
49 INSTRUCTION_OPERAND_PREDICATE(Allocated, ALLOCATED) | 48 INSTRUCTION_OPERAND_PREDICATE(Allocated, ALLOCATED) |
(...skipping 18 matching lines...) Expand all Loading... |
68 void* buffer = zone->New(sizeof(op)); | 67 void* buffer = zone->New(sizeof(op)); |
69 return new (buffer) SubKindOperand(op); | 68 return new (buffer) SubKindOperand(op); |
70 } | 69 } |
71 | 70 |
72 static void ReplaceWith(InstructionOperand* dest, | 71 static void ReplaceWith(InstructionOperand* dest, |
73 const InstructionOperand* src) { | 72 const InstructionOperand* src) { |
74 *dest = *src; | 73 *dest = *src; |
75 } | 74 } |
76 | 75 |
77 protected: | 76 protected: |
78 InstructionOperand(Kind kind, int index, int virtual_register) { | 77 explicit InstructionOperand(Kind kind) : value_(KindField::encode(kind)) {} |
79 if (kind != UNALLOCATED && kind != CONSTANT) { | |
80 DCHECK(virtual_register == kInvalidVirtualRegister); | |
81 } | |
82 value_ = KindField::encode(kind); | |
83 value_ |= | |
84 VirtualRegisterField::encode(static_cast<uint32_t>(virtual_register)); | |
85 value_ |= static_cast<int64_t>(index) << IndexField::kShift; | |
86 } | |
87 | 78 |
88 typedef BitField64<Kind, 0, 3> KindField; | 79 class KindField : public BitField64<Kind, 0, 3> {}; |
89 typedef BitField64<uint32_t, 3, 32> VirtualRegisterField; | |
90 typedef BitField64<int32_t, 35, 29> IndexField; | |
91 | 80 |
92 uint64_t value_; | 81 uint64_t value_; |
93 }; | 82 }; |
94 | 83 |
95 struct PrintableInstructionOperand { | 84 struct PrintableInstructionOperand { |
96 const RegisterConfiguration* register_configuration_; | 85 const RegisterConfiguration* register_configuration_; |
97 const InstructionOperand* op_; | 86 const InstructionOperand* op_; |
98 }; | 87 }; |
99 | 88 |
100 std::ostream& operator<<(std::ostream& os, | 89 std::ostream& operator<<(std::ostream& os, |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 // output). | 128 // output). |
140 USED_AT_START, | 129 USED_AT_START, |
141 | 130 |
142 // USED_AT_END operand is treated as live until the end of | 131 // USED_AT_END operand is treated as live until the end of |
143 // instruction. This means that register allocator will not reuse it's | 132 // instruction. This means that register allocator will not reuse it's |
144 // register for any other operand inside instruction. | 133 // register for any other operand inside instruction. |
145 USED_AT_END | 134 USED_AT_END |
146 }; | 135 }; |
147 | 136 |
148 UnallocatedOperand(ExtendedPolicy policy, int virtual_register) | 137 UnallocatedOperand(ExtendedPolicy policy, int virtual_register) |
149 : InstructionOperand(UNALLOCATED, 0, virtual_register) { | 138 : UnallocatedOperand(virtual_register) { |
150 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); | 139 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); |
151 value_ |= ExtendedPolicyField::encode(policy); | 140 value_ |= ExtendedPolicyField::encode(policy); |
152 value_ |= LifetimeField::encode(USED_AT_END); | 141 value_ |= LifetimeField::encode(USED_AT_END); |
153 } | 142 } |
154 | 143 |
155 UnallocatedOperand(BasicPolicy policy, int index, int virtual_register) | 144 UnallocatedOperand(BasicPolicy policy, int index, int virtual_register) |
156 : InstructionOperand(UNALLOCATED, 0, virtual_register) { | 145 : UnallocatedOperand(virtual_register) { |
157 DCHECK(policy == FIXED_SLOT); | 146 DCHECK(policy == FIXED_SLOT); |
158 value_ |= BasicPolicyField::encode(policy); | 147 value_ |= BasicPolicyField::encode(policy); |
159 value_ |= static_cast<int64_t>(index) << FixedSlotIndexField::kShift; | 148 value_ |= static_cast<int64_t>(index) << FixedSlotIndexField::kShift; |
160 DCHECK(this->fixed_slot_index() == index); | 149 DCHECK(this->fixed_slot_index() == index); |
161 } | 150 } |
162 | 151 |
163 UnallocatedOperand(ExtendedPolicy policy, int index, int virtual_register) | 152 UnallocatedOperand(ExtendedPolicy policy, int index, int virtual_register) |
164 : InstructionOperand(UNALLOCATED, 0, virtual_register) { | 153 : UnallocatedOperand(virtual_register) { |
165 DCHECK(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER); | 154 DCHECK(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER); |
166 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); | 155 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); |
167 value_ |= ExtendedPolicyField::encode(policy); | 156 value_ |= ExtendedPolicyField::encode(policy); |
168 value_ |= LifetimeField::encode(USED_AT_END); | 157 value_ |= LifetimeField::encode(USED_AT_END); |
169 value_ |= FixedRegisterField::encode(index); | 158 value_ |= FixedRegisterField::encode(index); |
170 } | 159 } |
171 | 160 |
172 UnallocatedOperand(ExtendedPolicy policy, Lifetime lifetime, | 161 UnallocatedOperand(ExtendedPolicy policy, Lifetime lifetime, |
173 int virtual_register) | 162 int virtual_register) |
174 : InstructionOperand(UNALLOCATED, 0, virtual_register) { | 163 : UnallocatedOperand(virtual_register) { |
175 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); | 164 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); |
176 value_ |= ExtendedPolicyField::encode(policy); | 165 value_ |= ExtendedPolicyField::encode(policy); |
177 value_ |= LifetimeField::encode(lifetime); | 166 value_ |= LifetimeField::encode(lifetime); |
178 } | 167 } |
179 | 168 |
180 UnallocatedOperand* Copy(Zone* zone) { return New(zone, *this); } | 169 UnallocatedOperand* Copy(Zone* zone) { return New(zone, *this); } |
181 | 170 |
182 UnallocatedOperand* CopyUnconstrained(Zone* zone) { | 171 UnallocatedOperand* CopyUnconstrained(Zone* zone) { |
183 return New(zone, UnallocatedOperand(ANY, virtual_register())); | 172 return New(zone, UnallocatedOperand(ANY, virtual_register())); |
184 } | 173 } |
185 | 174 |
186 // The encoding used for UnallocatedOperand operands depends on the policy | |
187 // that is | |
188 // stored within the operand. The FIXED_SLOT policy uses a compact encoding | |
189 // because it accommodates a larger pay-load. | |
190 // | |
191 // For FIXED_SLOT policy: | |
192 // +------------------------------------------------+ | |
193 // | slot_index | 0 | virtual_register | 001 | | |
194 // +------------------------------------------------+ | |
195 // | |
196 // For all other (extended) policies: | |
197 // +-----------------------------------------------------+ | |
198 // | reg_index | L | PPP | 1 | virtual_register | 001 | | |
199 // +-----------------------------------------------------+ | |
200 // L ... Lifetime | |
201 // P ... Policy | |
202 // | |
203 // The slot index is a signed value which requires us to decode it manually | |
204 // instead of using the BitField utility class. | |
205 | |
206 // All bits fit into the index field. | |
207 STATIC_ASSERT(IndexField::kShift == 35); | |
208 | |
209 // BitFields for all unallocated operands. | |
210 class BasicPolicyField : public BitField64<BasicPolicy, 35, 1> {}; | |
211 | |
212 // BitFields specific to BasicPolicy::FIXED_SLOT. | |
213 class FixedSlotIndexField : public BitField64<int, 36, 28> {}; | |
214 | |
215 // BitFields specific to BasicPolicy::EXTENDED_POLICY. | |
216 class ExtendedPolicyField : public BitField64<ExtendedPolicy, 36, 3> {}; | |
217 class LifetimeField : public BitField64<Lifetime, 39, 1> {}; | |
218 class FixedRegisterField : public BitField64<int, 40, 6> {}; | |
219 | |
220 // Predicates for the operand policy. | 175 // Predicates for the operand policy. |
221 bool HasAnyPolicy() const { | 176 bool HasAnyPolicy() const { |
222 return basic_policy() == EXTENDED_POLICY && extended_policy() == ANY; | 177 return basic_policy() == EXTENDED_POLICY && extended_policy() == ANY; |
223 } | 178 } |
224 bool HasFixedPolicy() const { | 179 bool HasFixedPolicy() const { |
225 return basic_policy() == FIXED_SLOT || | 180 return basic_policy() == FIXED_SLOT || |
226 extended_policy() == FIXED_REGISTER || | 181 extended_policy() == FIXED_REGISTER || |
227 extended_policy() == FIXED_DOUBLE_REGISTER; | 182 extended_policy() == FIXED_DOUBLE_REGISTER; |
228 } | 183 } |
229 bool HasRegisterPolicy() const { | 184 bool HasRegisterPolicy() const { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 value_ = VirtualRegisterField::update(value_, static_cast<uint32_t>(id)); | 240 value_ = VirtualRegisterField::update(value_, static_cast<uint32_t>(id)); |
286 } | 241 } |
287 | 242 |
288 // [lifetime]: Only for non-FIXED_SLOT. | 243 // [lifetime]: Only for non-FIXED_SLOT. |
289 bool IsUsedAtStart() const { | 244 bool IsUsedAtStart() const { |
290 DCHECK(basic_policy() == EXTENDED_POLICY); | 245 DCHECK(basic_policy() == EXTENDED_POLICY); |
291 return LifetimeField::decode(value_) == USED_AT_START; | 246 return LifetimeField::decode(value_) == USED_AT_START; |
292 } | 247 } |
293 | 248 |
294 INSTRUCTION_OPERAND_CASTS(UnallocatedOperand, UNALLOCATED); | 249 INSTRUCTION_OPERAND_CASTS(UnallocatedOperand, UNALLOCATED); |
| 250 |
| 251 // The encoding used for UnallocatedOperand operands depends on the policy |
| 252 // that is |
| 253 // stored within the operand. The FIXED_SLOT policy uses a compact encoding |
| 254 // because it accommodates a larger pay-load. |
| 255 // |
| 256 // For FIXED_SLOT policy: |
| 257 // +------------------------------------------------+ |
| 258 // | slot_index | 0 | virtual_register | 001 | |
| 259 // +------------------------------------------------+ |
| 260 // |
| 261 // For all other (extended) policies: |
| 262 // +-----------------------------------------------------+ |
| 263 // | reg_index | L | PPP | 1 | virtual_register | 001 | |
| 264 // +-----------------------------------------------------+ |
| 265 // L ... Lifetime |
| 266 // P ... Policy |
| 267 // |
| 268 // The slot index is a signed value which requires us to decode it manually |
| 269 // instead of using the BitField utility class. |
| 270 |
| 271 STATIC_ASSERT(KindField::kSize == 3); |
| 272 |
| 273 class VirtualRegisterField : public BitField64<uint32_t, 3, 32> {}; |
| 274 |
| 275 // BitFields for all unallocated operands. |
| 276 class BasicPolicyField : public BitField64<BasicPolicy, 35, 1> {}; |
| 277 |
| 278 // BitFields specific to BasicPolicy::FIXED_SLOT. |
| 279 class FixedSlotIndexField : public BitField64<int, 36, 28> {}; |
| 280 |
| 281 // BitFields specific to BasicPolicy::EXTENDED_POLICY. |
| 282 class ExtendedPolicyField : public BitField64<ExtendedPolicy, 36, 3> {}; |
| 283 class LifetimeField : public BitField64<Lifetime, 39, 1> {}; |
| 284 class FixedRegisterField : public BitField64<int, 40, 6> {}; |
| 285 |
| 286 private: |
| 287 explicit UnallocatedOperand(int virtual_register) |
| 288 : InstructionOperand(UNALLOCATED) { |
| 289 value_ |= |
| 290 VirtualRegisterField::encode(static_cast<uint32_t>(virtual_register)); |
| 291 } |
295 }; | 292 }; |
296 | 293 |
297 | 294 |
298 class ConstantOperand : public InstructionOperand { | 295 class ConstantOperand : public InstructionOperand { |
299 public: | 296 public: |
300 explicit ConstantOperand(int virtual_register) | 297 explicit ConstantOperand(int virtual_register) |
301 : InstructionOperand(CONSTANT, 0, virtual_register) {} | 298 : InstructionOperand(CONSTANT) { |
| 299 value_ |= |
| 300 VirtualRegisterField::encode(static_cast<uint32_t>(virtual_register)); |
| 301 } |
302 | 302 |
303 int32_t virtual_register() const { | 303 int32_t virtual_register() const { |
304 return static_cast<int32_t>(VirtualRegisterField::decode(value_)); | 304 return static_cast<int32_t>(VirtualRegisterField::decode(value_)); |
305 } | 305 } |
306 | 306 |
307 static ConstantOperand* New(Zone* zone, int virtual_register) { | 307 static ConstantOperand* New(Zone* zone, int virtual_register) { |
308 return InstructionOperand::New(zone, ConstantOperand(virtual_register)); | 308 return InstructionOperand::New(zone, ConstantOperand(virtual_register)); |
309 } | 309 } |
310 | 310 |
311 INSTRUCTION_OPERAND_CASTS(ConstantOperand, CONSTANT); | 311 INSTRUCTION_OPERAND_CASTS(ConstantOperand, CONSTANT); |
| 312 |
| 313 STATIC_ASSERT(KindField::kSize == 3); |
| 314 class VirtualRegisterField : public BitField64<uint32_t, 3, 32> {}; |
312 }; | 315 }; |
313 | 316 |
314 | 317 |
315 class ImmediateOperand : public InstructionOperand { | 318 class ImmediateOperand : public InstructionOperand { |
316 public: | 319 public: |
317 explicit ImmediateOperand(int index) | 320 explicit ImmediateOperand(int index) : InstructionOperand(IMMEDIATE) { |
318 : InstructionOperand(IMMEDIATE, index, kInvalidVirtualRegister) {} | 321 value_ |= static_cast<int64_t>(index) << IndexField::kShift; |
| 322 } |
319 | 323 |
320 int index() const { | 324 int index() const { |
321 return static_cast<int64_t>(value_) >> IndexField::kShift; | 325 return static_cast<int64_t>(value_) >> IndexField::kShift; |
322 } | 326 } |
323 | 327 |
324 static ImmediateOperand* New(Zone* zone, int index) { | 328 static ImmediateOperand* New(Zone* zone, int index) { |
325 return InstructionOperand::New(zone, ImmediateOperand(index)); | 329 return InstructionOperand::New(zone, ImmediateOperand(index)); |
326 } | 330 } |
327 | 331 |
328 INSTRUCTION_OPERAND_CASTS(ImmediateOperand, IMMEDIATE); | 332 INSTRUCTION_OPERAND_CASTS(ImmediateOperand, IMMEDIATE); |
| 333 |
| 334 STATIC_ASSERT(KindField::kSize == 3); |
| 335 class IndexField : public BitField64<int32_t, 35, 29> {}; |
329 }; | 336 }; |
330 | 337 |
331 | 338 |
332 class AllocatedOperand : public InstructionOperand { | 339 class AllocatedOperand : public InstructionOperand { |
333 public: | 340 public: |
334 enum AllocatedKind { | 341 enum AllocatedKind { |
335 STACK_SLOT, | 342 STACK_SLOT, |
336 DOUBLE_STACK_SLOT, | 343 DOUBLE_STACK_SLOT, |
337 REGISTER, | 344 REGISTER, |
338 DOUBLE_REGISTER | 345 DOUBLE_REGISTER |
339 }; | 346 }; |
340 | 347 |
341 AllocatedOperand(AllocatedKind kind, int index) | 348 AllocatedOperand(AllocatedKind kind, int index) |
342 : InstructionOperand(ALLOCATED, index, kInvalidVirtualRegister) { | 349 : InstructionOperand(ALLOCATED) { |
343 if (kind == REGISTER || kind == DOUBLE_REGISTER) DCHECK(index >= 0); | 350 DCHECK_IMPLIES(kind == REGISTER || kind == DOUBLE_REGISTER, index >= 0); |
344 value_ = AllocatedKindField::update(value_, kind); | 351 value_ |= AllocatedKindField::encode(kind); |
| 352 value_ |= static_cast<int64_t>(index) << IndexField::kShift; |
345 } | 353 } |
346 | 354 |
347 int index() const { | 355 int index() const { |
348 return static_cast<int64_t>(value_) >> IndexField::kShift; | 356 return static_cast<int64_t>(value_) >> IndexField::kShift; |
349 } | 357 } |
350 | 358 |
351 AllocatedKind allocated_kind() const { | 359 AllocatedKind allocated_kind() const { |
352 return AllocatedKindField::decode(value_); | 360 return AllocatedKindField::decode(value_); |
353 } | 361 } |
354 | 362 |
355 static AllocatedOperand* New(Zone* zone, AllocatedKind kind, int index) { | 363 static AllocatedOperand* New(Zone* zone, AllocatedKind kind, int index) { |
356 return InstructionOperand::New(zone, AllocatedOperand(kind, index)); | 364 return InstructionOperand::New(zone, AllocatedOperand(kind, index)); |
357 } | 365 } |
358 | 366 |
359 INSTRUCTION_OPERAND_CASTS(AllocatedOperand, ALLOCATED); | 367 INSTRUCTION_OPERAND_CASTS(AllocatedOperand, ALLOCATED); |
360 | 368 |
361 private: | 369 STATIC_ASSERT(KindField::kSize == 3); |
362 typedef BitField64<AllocatedKind, 3, 2> AllocatedKindField; | 370 class AllocatedKindField : public BitField64<AllocatedKind, 3, 2> {}; |
| 371 class IndexField : public BitField64<int32_t, 35, 29> {}; |
363 }; | 372 }; |
364 | 373 |
365 | 374 |
366 #undef INSTRUCTION_OPERAND_CASTS | 375 #undef INSTRUCTION_OPERAND_CASTS |
367 | 376 |
368 | 377 |
369 #define ALLOCATED_OPERAND_LIST(V) \ | 378 #define ALLOCATED_OPERAND_LIST(V) \ |
370 V(StackSlot, STACK_SLOT) \ | 379 V(StackSlot, STACK_SLOT) \ |
371 V(DoubleStackSlot, DOUBLE_STACK_SLOT) \ | 380 V(DoubleStackSlot, DOUBLE_STACK_SLOT) \ |
372 V(Register, REGISTER) \ | 381 V(Register, REGISTER) \ |
(...skipping 741 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1114 | 1123 |
1115 | 1124 |
1116 std::ostream& operator<<(std::ostream& os, | 1125 std::ostream& operator<<(std::ostream& os, |
1117 const PrintableInstructionSequence& code); | 1126 const PrintableInstructionSequence& code); |
1118 | 1127 |
1119 } // namespace compiler | 1128 } // namespace compiler |
1120 } // namespace internal | 1129 } // namespace internal |
1121 } // namespace v8 | 1130 } // namespace v8 |
1122 | 1131 |
1123 #endif // V8_COMPILER_INSTRUCTION_H_ | 1132 #endif // V8_COMPILER_INSTRUCTION_H_ |
OLD | NEW |