| 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 |