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 13 matching lines...) Expand all Loading... | |
24 namespace compiler { | 24 namespace compiler { |
25 | 25 |
26 class Schedule; | 26 class Schedule; |
27 | 27 |
28 class InstructionOperand { | 28 class InstructionOperand { |
29 public: | 29 public: |
30 static const int kInvalidVirtualRegister = -1; | 30 static const int kInvalidVirtualRegister = -1; |
31 | 31 |
32 // TODO(dcarney): recover bit. INVALID can be represented as UNALLOCATED with | 32 // TODO(dcarney): recover bit. INVALID can be represented as UNALLOCATED with |
33 // kInvalidVirtualRegister and some DCHECKS. | 33 // kInvalidVirtualRegister and some DCHECKS. |
34 enum Kind { INVALID, UNALLOCATED, CONSTANT, IMMEDIATE, ALLOCATED }; | 34 enum Kind { INVALID, UNALLOCATED, CONSTANT, IMMEDIATE, EXPLICIT, ALLOCATED }; |
35 | 35 |
36 InstructionOperand() : InstructionOperand(INVALID) {} | 36 InstructionOperand() : InstructionOperand(INVALID) {} |
37 | 37 |
38 Kind kind() const { return KindField::decode(value_); } | 38 Kind kind() const { return KindField::decode(value_); } |
39 | 39 |
40 #define INSTRUCTION_OPERAND_PREDICATE(name, type) \ | 40 #define INSTRUCTION_OPERAND_PREDICATE(name, type) \ |
41 bool Is##name() const { return kind() == type; } | 41 bool Is##name() const { return kind() == type; } |
42 INSTRUCTION_OPERAND_PREDICATE(Invalid, INVALID) | 42 INSTRUCTION_OPERAND_PREDICATE(Invalid, INVALID) |
43 INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED) | 43 INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED) |
44 INSTRUCTION_OPERAND_PREDICATE(Constant, CONSTANT) | 44 INSTRUCTION_OPERAND_PREDICATE(Constant, CONSTANT) |
45 INSTRUCTION_OPERAND_PREDICATE(Immediate, IMMEDIATE) | 45 INSTRUCTION_OPERAND_PREDICATE(Immediate, IMMEDIATE) |
46 INSTRUCTION_OPERAND_PREDICATE(Explicit, EXPLICIT) | |
Mircea Trofin
2015/10/15 15:05:38
Maybe this would be a good time to add a short des
danno
2015/10/23 08:07:49
Done
| |
46 INSTRUCTION_OPERAND_PREDICATE(Allocated, ALLOCATED) | 47 INSTRUCTION_OPERAND_PREDICATE(Allocated, ALLOCATED) |
47 #undef INSTRUCTION_OPERAND_PREDICATE | 48 #undef INSTRUCTION_OPERAND_PREDICATE |
48 | 49 |
49 inline bool IsRegister() const; | 50 inline bool IsRegister() const; |
50 inline bool IsDoubleRegister() const; | 51 inline bool IsDoubleRegister() const; |
51 inline bool IsStackSlot() const; | 52 inline bool IsStackSlot() const; |
52 inline bool IsDoubleStackSlot() const; | 53 inline bool IsDoubleStackSlot() const; |
53 | 54 |
54 template <typename SubKindOperand> | 55 template <typename SubKindOperand> |
55 static SubKindOperand* New(Zone* zone, const SubKindOperand& op) { | 56 static SubKindOperand* New(Zone* zone, const SubKindOperand& op) { |
56 void* buffer = zone->New(sizeof(op)); | 57 void* buffer = zone->New(sizeof(op)); |
57 return new (buffer) SubKindOperand(op); | 58 return new (buffer) SubKindOperand(op); |
58 } | 59 } |
59 | 60 |
60 static void ReplaceWith(InstructionOperand* dest, | 61 static void ReplaceWith(InstructionOperand* dest, |
61 const InstructionOperand* src) { | 62 const InstructionOperand* src) { |
62 *dest = *src; | 63 *dest = *src; |
63 } | 64 } |
64 | 65 |
65 bool Equals(const InstructionOperand& that) const { | 66 bool Equals(const InstructionOperand& that) const { |
66 return this->value_ == that.value_; | 67 return this->value_ == that.value_; |
67 } | 68 } |
68 | 69 |
69 bool Compare(const InstructionOperand& that) const { | 70 bool Compare(const InstructionOperand& that) const { |
70 return this->value_ < that.value_; | 71 return this->value_ < that.value_; |
71 } | 72 } |
72 | 73 |
73 bool EqualsModuloType(const InstructionOperand& that) const { | 74 bool EqualsCanonicalizeType(const InstructionOperand& that) const { |
74 return this->GetValueModuloType() == that.GetValueModuloType(); | 75 return this->GetValueCanonicalizeType() == that.GetValueCanonicalizeType(); |
75 } | 76 } |
76 | 77 |
77 bool CompareModuloType(const InstructionOperand& that) const { | 78 bool CompareCanonicalizeType(const InstructionOperand& that) const { |
78 return this->GetValueModuloType() < that.GetValueModuloType(); | 79 return this->GetValueCanonicalizeType() < that.GetValueCanonicalizeType(); |
79 } | 80 } |
80 | 81 |
81 protected: | 82 protected: |
82 explicit InstructionOperand(Kind kind) : value_(KindField::encode(kind)) {} | 83 explicit InstructionOperand(Kind kind) : value_(KindField::encode(kind)) {} |
83 | 84 |
84 inline uint64_t GetValueModuloType() const; | 85 inline uint64_t GetValueCanonicalizeType() const; |
85 | 86 |
86 class KindField : public BitField64<Kind, 0, 3> {}; | 87 class KindField : public BitField64<Kind, 0, 3> {}; |
87 | 88 |
88 uint64_t value_; | 89 uint64_t value_; |
89 }; | 90 }; |
90 | 91 |
91 | 92 |
92 struct PrintableInstructionOperand { | 93 struct PrintableInstructionOperand { |
93 const RegisterConfiguration* register_configuration_; | 94 const RegisterConfiguration* register_configuration_; |
94 InstructionOperand op_; | 95 InstructionOperand op_; |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
346 } | 347 } |
347 | 348 |
348 INSTRUCTION_OPERAND_CASTS(ImmediateOperand, IMMEDIATE); | 349 INSTRUCTION_OPERAND_CASTS(ImmediateOperand, IMMEDIATE); |
349 | 350 |
350 STATIC_ASSERT(KindField::kSize == 3); | 351 STATIC_ASSERT(KindField::kSize == 3); |
351 class TypeField : public BitField64<ImmediateType, 3, 1> {}; | 352 class TypeField : public BitField64<ImmediateType, 3, 1> {}; |
352 class ValueField : public BitField64<int32_t, 32, 32> {}; | 353 class ValueField : public BitField64<int32_t, 32, 32> {}; |
353 }; | 354 }; |
354 | 355 |
355 | 356 |
356 class AllocatedOperand : public InstructionOperand { | 357 class LocationOperand : public InstructionOperand { |
357 public: | 358 public: |
358 // TODO(dcarney): machine_type makes this now redundant. Just need to know is | 359 enum LocationKind { REGISTER, STACK_SLOT }; |
359 // the operand is a slot or a register. | |
360 enum AllocatedKind { | |
361 STACK_SLOT, | |
362 DOUBLE_STACK_SLOT, | |
363 REGISTER, | |
364 DOUBLE_REGISTER | |
365 }; | |
366 | 360 |
367 AllocatedOperand(AllocatedKind kind, MachineType machine_type, int index) | 361 LocationOperand(InstructionOperand::Kind operand_kind, |
368 : InstructionOperand(ALLOCATED) { | 362 LocationOperand::LocationKind location_kind, |
369 DCHECK_IMPLIES(kind == REGISTER || kind == DOUBLE_REGISTER, index >= 0); | 363 MachineType machine_type, int index) |
364 : InstructionOperand(operand_kind) { | |
365 DCHECK_IMPLIES(location_kind == REGISTER, index >= 0); | |
370 DCHECK(IsSupportedMachineType(machine_type)); | 366 DCHECK(IsSupportedMachineType(machine_type)); |
371 value_ |= AllocatedKindField::encode(kind); | 367 value_ |= LocationKindField::encode(location_kind); |
372 value_ |= MachineTypeField::encode(machine_type); | 368 value_ |= MachineTypeField::encode(machine_type); |
373 value_ |= static_cast<int64_t>(index) << IndexField::kShift; | 369 value_ |= static_cast<int64_t>(index) << IndexField::kShift; |
374 } | 370 } |
375 | 371 |
376 int index() const { | 372 int index() const { |
377 DCHECK(STACK_SLOT == allocated_kind() || | 373 DCHECK(IsStackSlot() || IsDoubleStackSlot()); |
378 DOUBLE_STACK_SLOT == allocated_kind()); | |
379 return static_cast<int64_t>(value_) >> IndexField::kShift; | 374 return static_cast<int64_t>(value_) >> IndexField::kShift; |
380 } | 375 } |
381 | 376 |
382 Register GetRegister() const { | 377 Register GetRegister() const { |
383 DCHECK(REGISTER == allocated_kind() || DOUBLE_REGISTER == allocated_kind()); | 378 DCHECK(IsRegister()); |
384 return Register::from_code(static_cast<int64_t>(value_) >> | 379 return Register::from_code(static_cast<int64_t>(value_) >> |
385 IndexField::kShift); | 380 IndexField::kShift); |
386 } | 381 } |
387 | 382 |
388 DoubleRegister GetDoubleRegister() const { | 383 DoubleRegister GetDoubleRegister() const { |
389 DCHECK(REGISTER == allocated_kind() || DOUBLE_REGISTER == allocated_kind()); | 384 DCHECK(IsDoubleRegister()); |
390 return DoubleRegister::from_code(static_cast<int64_t>(value_) >> | 385 return DoubleRegister::from_code(static_cast<int64_t>(value_) >> |
391 IndexField::kShift); | 386 IndexField::kShift); |
392 } | 387 } |
393 | 388 |
394 AllocatedKind allocated_kind() const { | 389 LocationKind location_kind() const { |
395 return AllocatedKindField::decode(value_); | 390 return LocationKindField::decode(value_); |
396 } | 391 } |
397 | 392 |
398 MachineType machine_type() const { return MachineTypeField::decode(value_); } | 393 MachineType machine_type() const { return MachineTypeField::decode(value_); } |
399 | 394 |
400 static AllocatedOperand* New(Zone* zone, AllocatedKind kind, | |
401 MachineType machine_type, int index) { | |
402 return InstructionOperand::New(zone, | |
403 AllocatedOperand(kind, machine_type, index)); | |
404 } | |
405 | |
406 static bool IsSupportedMachineType(MachineType machine_type) { | 395 static bool IsSupportedMachineType(MachineType machine_type) { |
407 if (RepresentationOf(machine_type) != machine_type) return false; | 396 if (RepresentationOf(machine_type) != machine_type) return false; |
408 switch (machine_type) { | 397 switch (machine_type) { |
409 case kRepWord32: | 398 case kRepWord32: |
410 case kRepWord64: | 399 case kRepWord64: |
411 case kRepFloat32: | 400 case kRepFloat32: |
412 case kRepFloat64: | 401 case kRepFloat64: |
413 case kRepTagged: | 402 case kRepTagged: |
414 return true; | 403 return true; |
415 default: | 404 default: |
416 return false; | 405 return false; |
417 } | 406 } |
418 } | 407 } |
419 | 408 |
420 INSTRUCTION_OPERAND_CASTS(AllocatedOperand, ALLOCATED); | 409 static LocationOperand* cast(InstructionOperand* op) { |
410 DCHECK(ALLOCATED == op->kind() || EXPLICIT == op->kind()); | |
411 return static_cast<LocationOperand*>(op); | |
412 } | |
413 | |
414 static const LocationOperand* cast(const InstructionOperand* op) { | |
415 DCHECK(ALLOCATED == op->kind() || EXPLICIT == op->kind()); | |
416 return static_cast<const LocationOperand*>(op); | |
417 } | |
418 | |
419 static LocationOperand cast(const InstructionOperand& op) { | |
420 DCHECK(ALLOCATED == op.kind() || EXPLICIT == op.kind()); | |
421 return *static_cast<const LocationOperand*>(&op); | |
422 } | |
421 | 423 |
422 STATIC_ASSERT(KindField::kSize == 3); | 424 STATIC_ASSERT(KindField::kSize == 3); |
423 class AllocatedKindField : public BitField64<AllocatedKind, 3, 2> {}; | 425 class LocationKindField : public BitField64<LocationKind, 3, 2> {}; |
424 class MachineTypeField : public BitField64<MachineType, 5, 16> {}; | 426 class MachineTypeField : public BitField64<MachineType, 5, 16> {}; |
425 class IndexField : public BitField64<int32_t, 35, 29> {}; | 427 class IndexField : public BitField64<int32_t, 35, 29> {}; |
426 }; | 428 }; |
427 | 429 |
428 | 430 |
431 class ExplicitOperand : public LocationOperand { | |
432 public: | |
433 ExplicitOperand(LocationKind kind, MachineType machine_type, int index) | |
434 : LocationOperand(EXPLICIT, kind, machine_type, index) {} | |
435 | |
436 static ExplicitOperand* New(Zone* zone, LocationKind kind, | |
437 MachineType machine_type, int index) { | |
438 return InstructionOperand::New(zone, | |
439 ExplicitOperand(kind, machine_type, index)); | |
440 } | |
441 | |
442 INSTRUCTION_OPERAND_CASTS(ExplicitOperand, EXPLICIT); | |
443 }; | |
444 | |
445 | |
446 class AllocatedOperand : public LocationOperand { | |
447 public: | |
448 AllocatedOperand(LocationKind kind, MachineType machine_type, int index) | |
449 : LocationOperand(ALLOCATED, kind, machine_type, index) {} | |
450 | |
451 static AllocatedOperand* New(Zone* zone, LocationKind kind, | |
452 MachineType machine_type, int index) { | |
453 return InstructionOperand::New(zone, | |
454 AllocatedOperand(kind, machine_type, index)); | |
455 } | |
456 | |
457 INSTRUCTION_OPERAND_CASTS(AllocatedOperand, ALLOCATED); | |
458 }; | |
459 | |
460 | |
429 #undef INSTRUCTION_OPERAND_CASTS | 461 #undef INSTRUCTION_OPERAND_CASTS |
430 | 462 |
431 | 463 |
432 #define ALLOCATED_OPERAND_LIST(V) \ | 464 bool InstructionOperand::IsRegister() const { |
433 V(StackSlot, STACK_SLOT) \ | 465 return (IsAllocated() || IsExplicit()) && |
434 V(DoubleStackSlot, DOUBLE_STACK_SLOT) \ | 466 LocationOperand::cast(this)->location_kind() == |
435 V(Register, REGISTER) \ | 467 LocationOperand::REGISTER && |
436 V(DoubleRegister, DOUBLE_REGISTER) | 468 !IsFloatingPoint(LocationOperand::cast(this)->machine_type()); |
469 } | |
437 | 470 |
471 bool InstructionOperand::IsDoubleRegister() const { | |
472 return (IsAllocated() || IsExplicit()) && | |
473 LocationOperand::cast(this)->location_kind() == | |
474 LocationOperand::REGISTER && | |
475 IsFloatingPoint(LocationOperand::cast(this)->machine_type()); | |
476 } | |
438 | 477 |
439 #define ALLOCATED_OPERAND_IS(SubKind, kOperandKind) \ | 478 bool InstructionOperand::IsStackSlot() const { |
440 bool InstructionOperand::Is##SubKind() const { \ | 479 return (IsAllocated() || IsExplicit()) && |
441 return IsAllocated() && \ | 480 LocationOperand::cast(this)->location_kind() == |
442 AllocatedOperand::cast(this)->allocated_kind() == \ | 481 LocationOperand::STACK_SLOT && |
443 AllocatedOperand::kOperandKind; \ | 482 !IsFloatingPoint(LocationOperand::cast(this)->machine_type()); |
444 } | 483 } |
445 ALLOCATED_OPERAND_LIST(ALLOCATED_OPERAND_IS) | |
446 #undef ALLOCATED_OPERAND_IS | |
447 | 484 |
485 bool InstructionOperand::IsDoubleStackSlot() const { | |
486 return (IsAllocated() || IsExplicit()) && | |
487 LocationOperand::cast(this)->location_kind() == | |
488 LocationOperand::STACK_SLOT && | |
489 IsFloatingPoint(LocationOperand::cast(this)->machine_type()); | |
490 } | |
448 | 491 |
449 // TODO(dcarney): these subkinds are now pretty useless, nuke. | 492 uint64_t InstructionOperand::GetValueCanonicalizeType() const { |
450 #define ALLOCATED_OPERAND_CLASS(SubKind, kOperandKind) \ | 493 if (IsAllocated() || IsExplicit()) { |
451 class SubKind##Operand final : public AllocatedOperand { \ | |
452 public: \ | |
453 explicit SubKind##Operand(MachineType machine_type, int index) \ | |
454 : AllocatedOperand(kOperandKind, machine_type, index) {} \ | |
455 \ | |
456 static SubKind##Operand* New(Zone* zone, MachineType machine_type, \ | |
457 int index) { \ | |
458 return InstructionOperand::New(zone, \ | |
459 SubKind##Operand(machine_type, index)); \ | |
460 } \ | |
461 \ | |
462 static SubKind##Operand* cast(InstructionOperand* op) { \ | |
463 DCHECK_EQ(kOperandKind, AllocatedOperand::cast(op)->allocated_kind()); \ | |
464 return reinterpret_cast<SubKind##Operand*>(op); \ | |
465 } \ | |
466 \ | |
467 static const SubKind##Operand* cast(const InstructionOperand* op) { \ | |
468 DCHECK_EQ(kOperandKind, AllocatedOperand::cast(op)->allocated_kind()); \ | |
469 return reinterpret_cast<const SubKind##Operand*>(op); \ | |
470 } \ | |
471 \ | |
472 static SubKind##Operand cast(const InstructionOperand& op) { \ | |
473 DCHECK_EQ(kOperandKind, AllocatedOperand::cast(op).allocated_kind()); \ | |
474 return *static_cast<const SubKind##Operand*>(&op); \ | |
475 } \ | |
476 }; | |
477 ALLOCATED_OPERAND_LIST(ALLOCATED_OPERAND_CLASS) | |
478 #undef ALLOCATED_OPERAND_CLASS | |
479 | |
480 | |
481 uint64_t InstructionOperand::GetValueModuloType() const { | |
482 if (IsAllocated()) { | |
483 // TODO(dcarney): put machine type last and mask. | 494 // TODO(dcarney): put machine type last and mask. |
484 return AllocatedOperand::MachineTypeField::update(this->value_, kMachNone); | 495 MachineType canonicalized_machine_type = |
496 IsFloatingPoint(LocationOperand::cast(this)->machine_type()) | |
497 ? kMachFloat64 | |
498 : kMachNone; | |
499 return LocationOperand::MachineTypeField::update( | |
500 this->value_, canonicalized_machine_type); | |
485 } | 501 } |
486 return this->value_; | 502 return this->value_; |
487 } | 503 } |
488 | 504 |
489 | 505 |
490 // Required for maps that don't care about machine type. | 506 // Required for maps that don't care about machine type. |
491 struct CompareOperandModuloType { | 507 struct CompareOperandModuloType { |
492 bool operator()(const InstructionOperand& a, | 508 bool operator()(const InstructionOperand& a, |
493 const InstructionOperand& b) const { | 509 const InstructionOperand& b) const { |
494 return a.CompareModuloType(b); | 510 return a.CompareCanonicalizeType(b); |
495 } | 511 } |
496 }; | 512 }; |
497 | 513 |
498 | 514 |
499 class MoveOperands final : public ZoneObject { | 515 class MoveOperands final : public ZoneObject { |
500 public: | 516 public: |
501 MoveOperands(const InstructionOperand& source, | 517 MoveOperands(const InstructionOperand& source, |
502 const InstructionOperand& destination) | 518 const InstructionOperand& destination) |
503 : source_(source), destination_(destination) { | 519 : source_(source), destination_(destination) { |
504 DCHECK(!source.IsInvalid() && !destination.IsInvalid()); | 520 DCHECK(!source.IsInvalid() && !destination.IsInvalid()); |
(...skipping 11 matching lines...) Expand all Loading... | |
516 | 532 |
517 // The gap resolver marks moves as "in-progress" by clearing the | 533 // The gap resolver marks moves as "in-progress" by clearing the |
518 // destination (but not the source). | 534 // destination (but not the source). |
519 bool IsPending() const { | 535 bool IsPending() const { |
520 return destination_.IsInvalid() && !source_.IsInvalid(); | 536 return destination_.IsInvalid() && !source_.IsInvalid(); |
521 } | 537 } |
522 void SetPending() { destination_ = InstructionOperand(); } | 538 void SetPending() { destination_ = InstructionOperand(); } |
523 | 539 |
524 // True if this move a move into the given destination operand. | 540 // True if this move a move into the given destination operand. |
525 bool Blocks(const InstructionOperand& operand) const { | 541 bool Blocks(const InstructionOperand& operand) const { |
526 return !IsEliminated() && source().EqualsModuloType(operand); | 542 return !IsEliminated() && source().EqualsCanonicalizeType(operand); |
527 } | 543 } |
528 | 544 |
529 // A move is redundant if it's been eliminated or if its source and | 545 // A move is redundant if it's been eliminated or if its source and |
530 // destination are the same. | 546 // destination are the same. |
531 bool IsRedundant() const { | 547 bool IsRedundant() const { |
532 DCHECK_IMPLIES(!destination_.IsInvalid(), !destination_.IsConstant()); | 548 DCHECK_IMPLIES(!destination_.IsInvalid(), !destination_.IsConstant()); |
533 return IsEliminated() || source_.EqualsModuloType(destination_); | 549 return IsEliminated() || source_.EqualsCanonicalizeType(destination_); |
534 } | 550 } |
535 | 551 |
536 // We clear both operands to indicate move that's been eliminated. | 552 // We clear both operands to indicate move that's been eliminated. |
537 void Eliminate() { source_ = destination_ = InstructionOperand(); } | 553 void Eliminate() { source_ = destination_ = InstructionOperand(); } |
538 bool IsEliminated() const { | 554 bool IsEliminated() const { |
539 DCHECK_IMPLIES(source_.IsInvalid(), destination_.IsInvalid()); | 555 DCHECK_IMPLIES(source_.IsInvalid(), destination_.IsInvalid()); |
540 return source_.IsInvalid(); | 556 return source_.IsInvalid(); |
541 } | 557 } |
542 | 558 |
543 private: | 559 private: |
(...skipping 684 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1228 | 1244 |
1229 | 1245 |
1230 std::ostream& operator<<(std::ostream& os, | 1246 std::ostream& operator<<(std::ostream& os, |
1231 const PrintableInstructionSequence& code); | 1247 const PrintableInstructionSequence& code); |
1232 | 1248 |
1233 } // namespace compiler | 1249 } // namespace compiler |
1234 } // namespace internal | 1250 } // namespace internal |
1235 } // namespace v8 | 1251 } // namespace v8 |
1236 | 1252 |
1237 #endif // V8_COMPILER_INSTRUCTION_H_ | 1253 #endif // V8_COMPILER_INSTRUCTION_H_ |
OLD | NEW |