| 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 // UnallocatedOperands are place-holder operands created before register |
| 44 // allocation. They later are assigned registers and become AllocatedOperands. |
| 43 INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED) | 45 INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED) |
| 46 // Constant operands participate in register allocation. They are allocated to |
| 47 // registers but have a special "spilling" behavior. When a ConstantOperand |
| 48 // value must be rematerialized, it is loaded from an immediate constant |
| 49 // rather from an unspilled slot. |
| 44 INSTRUCTION_OPERAND_PREDICATE(Constant, CONSTANT) | 50 INSTRUCTION_OPERAND_PREDICATE(Constant, CONSTANT) |
| 51 // ImmediateOperands do not participate in register allocation and are only |
| 52 // embedded directly in instructions, e.g. small integers and on some |
| 53 // platforms Objects. |
| 45 INSTRUCTION_OPERAND_PREDICATE(Immediate, IMMEDIATE) | 54 INSTRUCTION_OPERAND_PREDICATE(Immediate, IMMEDIATE) |
| 55 // ExplicitOperands do not participate in register allocation. They are |
| 56 // created by the instruction selector for direct access to registers and |
| 57 // stack slots, completely bypassing the register allocator. They are never |
| 58 // associated with a virtual register |
| 59 INSTRUCTION_OPERAND_PREDICATE(Explicit, EXPLICIT) |
| 60 // AllocatedOperands are registers or stack slots that are assigned by the |
| 61 // register allocator and are always associated with a virtual register. |
| 46 INSTRUCTION_OPERAND_PREDICATE(Allocated, ALLOCATED) | 62 INSTRUCTION_OPERAND_PREDICATE(Allocated, ALLOCATED) |
| 47 #undef INSTRUCTION_OPERAND_PREDICATE | 63 #undef INSTRUCTION_OPERAND_PREDICATE |
| 48 | 64 |
| 49 inline bool IsRegister() const; | 65 inline bool IsRegister() const; |
| 50 inline bool IsDoubleRegister() const; | 66 inline bool IsDoubleRegister() const; |
| 51 inline bool IsStackSlot() const; | 67 inline bool IsStackSlot() const; |
| 52 inline bool IsDoubleStackSlot() const; | 68 inline bool IsDoubleStackSlot() const; |
| 53 | 69 |
| 54 template <typename SubKindOperand> | 70 template <typename SubKindOperand> |
| 55 static SubKindOperand* New(Zone* zone, const SubKindOperand& op) { | 71 static SubKindOperand* New(Zone* zone, const SubKindOperand& op) { |
| 56 void* buffer = zone->New(sizeof(op)); | 72 void* buffer = zone->New(sizeof(op)); |
| 57 return new (buffer) SubKindOperand(op); | 73 return new (buffer) SubKindOperand(op); |
| 58 } | 74 } |
| 59 | 75 |
| 60 static void ReplaceWith(InstructionOperand* dest, | 76 static void ReplaceWith(InstructionOperand* dest, |
| 61 const InstructionOperand* src) { | 77 const InstructionOperand* src) { |
| 62 *dest = *src; | 78 *dest = *src; |
| 63 } | 79 } |
| 64 | 80 |
| 65 bool Equals(const InstructionOperand& that) const { | 81 bool Equals(const InstructionOperand& that) const { |
| 66 return this->value_ == that.value_; | 82 return this->value_ == that.value_; |
| 67 } | 83 } |
| 68 | 84 |
| 69 bool Compare(const InstructionOperand& that) const { | 85 bool Compare(const InstructionOperand& that) const { |
| 70 return this->value_ < that.value_; | 86 return this->value_ < that.value_; |
| 71 } | 87 } |
| 72 | 88 |
| 73 bool EqualsModuloType(const InstructionOperand& that) const { | 89 bool EqualsCanonicalized(const InstructionOperand& that) const { |
| 74 return this->GetValueModuloType() == that.GetValueModuloType(); | 90 return this->GetCanonicalizedValue() == that.GetCanonicalizedValue(); |
| 75 } | 91 } |
| 76 | 92 |
| 77 bool CompareModuloType(const InstructionOperand& that) const { | 93 bool CompareCanonicalized(const InstructionOperand& that) const { |
| 78 return this->GetValueModuloType() < that.GetValueModuloType(); | 94 return this->GetCanonicalizedValue() < that.GetCanonicalizedValue(); |
| 79 } | 95 } |
| 80 | 96 |
| 81 protected: | 97 protected: |
| 82 explicit InstructionOperand(Kind kind) : value_(KindField::encode(kind)) {} | 98 explicit InstructionOperand(Kind kind) : value_(KindField::encode(kind)) {} |
| 83 | 99 |
| 84 inline uint64_t GetValueModuloType() const; | 100 inline uint64_t GetCanonicalizedValue() const; |
| 85 | 101 |
| 86 class KindField : public BitField64<Kind, 0, 3> {}; | 102 class KindField : public BitField64<Kind, 0, 3> {}; |
| 87 | 103 |
| 88 uint64_t value_; | 104 uint64_t value_; |
| 89 }; | 105 }; |
| 90 | 106 |
| 91 | 107 |
| 92 struct PrintableInstructionOperand { | 108 struct PrintableInstructionOperand { |
| 93 const RegisterConfiguration* register_configuration_; | 109 const RegisterConfiguration* register_configuration_; |
| 94 InstructionOperand op_; | 110 InstructionOperand op_; |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 346 } | 362 } |
| 347 | 363 |
| 348 INSTRUCTION_OPERAND_CASTS(ImmediateOperand, IMMEDIATE); | 364 INSTRUCTION_OPERAND_CASTS(ImmediateOperand, IMMEDIATE); |
| 349 | 365 |
| 350 STATIC_ASSERT(KindField::kSize == 3); | 366 STATIC_ASSERT(KindField::kSize == 3); |
| 351 class TypeField : public BitField64<ImmediateType, 3, 1> {}; | 367 class TypeField : public BitField64<ImmediateType, 3, 1> {}; |
| 352 class ValueField : public BitField64<int32_t, 32, 32> {}; | 368 class ValueField : public BitField64<int32_t, 32, 32> {}; |
| 353 }; | 369 }; |
| 354 | 370 |
| 355 | 371 |
| 356 class AllocatedOperand : public InstructionOperand { | 372 class LocationOperand : public InstructionOperand { |
| 357 public: | 373 public: |
| 358 // TODO(dcarney): machine_type makes this now redundant. Just need to know is | 374 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 | 375 |
| 367 AllocatedOperand(AllocatedKind kind, MachineType machine_type, int index) | 376 LocationOperand(InstructionOperand::Kind operand_kind, |
| 368 : InstructionOperand(ALLOCATED) { | 377 LocationOperand::LocationKind location_kind, |
| 369 DCHECK_IMPLIES(kind == REGISTER || kind == DOUBLE_REGISTER, index >= 0); | 378 MachineType machine_type, int index) |
| 379 : InstructionOperand(operand_kind) { |
| 380 DCHECK_IMPLIES(location_kind == REGISTER, index >= 0); |
| 370 DCHECK(IsSupportedMachineType(machine_type)); | 381 DCHECK(IsSupportedMachineType(machine_type)); |
| 371 value_ |= AllocatedKindField::encode(kind); | 382 value_ |= LocationKindField::encode(location_kind); |
| 372 value_ |= MachineTypeField::encode(machine_type); | 383 value_ |= MachineTypeField::encode(machine_type); |
| 373 value_ |= static_cast<int64_t>(index) << IndexField::kShift; | 384 value_ |= static_cast<int64_t>(index) << IndexField::kShift; |
| 374 } | 385 } |
| 375 | 386 |
| 376 int index() const { | 387 int index() const { |
| 377 DCHECK(STACK_SLOT == allocated_kind() || | 388 DCHECK(IsStackSlot() || IsDoubleStackSlot()); |
| 378 DOUBLE_STACK_SLOT == allocated_kind()); | |
| 379 return static_cast<int64_t>(value_) >> IndexField::kShift; | 389 return static_cast<int64_t>(value_) >> IndexField::kShift; |
| 380 } | 390 } |
| 381 | 391 |
| 382 Register GetRegister() const { | 392 Register GetRegister() const { |
| 383 DCHECK(REGISTER == allocated_kind() || DOUBLE_REGISTER == allocated_kind()); | 393 DCHECK(IsRegister()); |
| 384 return Register::from_code(static_cast<int64_t>(value_) >> | 394 return Register::from_code(static_cast<int64_t>(value_) >> |
| 385 IndexField::kShift); | 395 IndexField::kShift); |
| 386 } | 396 } |
| 387 | 397 |
| 388 DoubleRegister GetDoubleRegister() const { | 398 DoubleRegister GetDoubleRegister() const { |
| 389 DCHECK(REGISTER == allocated_kind() || DOUBLE_REGISTER == allocated_kind()); | 399 DCHECK(IsDoubleRegister()); |
| 390 return DoubleRegister::from_code(static_cast<int64_t>(value_) >> | 400 return DoubleRegister::from_code(static_cast<int64_t>(value_) >> |
| 391 IndexField::kShift); | 401 IndexField::kShift); |
| 392 } | 402 } |
| 393 | 403 |
| 394 AllocatedKind allocated_kind() const { | 404 LocationKind location_kind() const { |
| 395 return AllocatedKindField::decode(value_); | 405 return LocationKindField::decode(value_); |
| 396 } | 406 } |
| 397 | 407 |
| 398 MachineType machine_type() const { return MachineTypeField::decode(value_); } | 408 MachineType machine_type() const { return MachineTypeField::decode(value_); } |
| 399 | 409 |
| 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) { | 410 static bool IsSupportedMachineType(MachineType machine_type) { |
| 407 if (RepresentationOf(machine_type) != machine_type) return false; | 411 if (RepresentationOf(machine_type) != machine_type) return false; |
| 408 switch (machine_type) { | 412 switch (machine_type) { |
| 409 case kRepWord32: | 413 case kRepWord32: |
| 410 case kRepWord64: | 414 case kRepWord64: |
| 411 case kRepFloat32: | 415 case kRepFloat32: |
| 412 case kRepFloat64: | 416 case kRepFloat64: |
| 413 case kRepTagged: | 417 case kRepTagged: |
| 414 return true; | 418 return true; |
| 415 default: | 419 default: |
| 416 return false; | 420 return false; |
| 417 } | 421 } |
| 418 } | 422 } |
| 419 | 423 |
| 420 INSTRUCTION_OPERAND_CASTS(AllocatedOperand, ALLOCATED); | 424 static LocationOperand* cast(InstructionOperand* op) { |
| 425 DCHECK(ALLOCATED == op->kind() || EXPLICIT == op->kind()); |
| 426 return static_cast<LocationOperand*>(op); |
| 427 } |
| 428 |
| 429 static const LocationOperand* cast(const InstructionOperand* op) { |
| 430 DCHECK(ALLOCATED == op->kind() || EXPLICIT == op->kind()); |
| 431 return static_cast<const LocationOperand*>(op); |
| 432 } |
| 433 |
| 434 static LocationOperand cast(const InstructionOperand& op) { |
| 435 DCHECK(ALLOCATED == op.kind() || EXPLICIT == op.kind()); |
| 436 return *static_cast<const LocationOperand*>(&op); |
| 437 } |
| 421 | 438 |
| 422 STATIC_ASSERT(KindField::kSize == 3); | 439 STATIC_ASSERT(KindField::kSize == 3); |
| 423 class AllocatedKindField : public BitField64<AllocatedKind, 3, 2> {}; | 440 class LocationKindField : public BitField64<LocationKind, 3, 2> {}; |
| 424 class MachineTypeField : public BitField64<MachineType, 5, 16> {}; | 441 class MachineTypeField : public BitField64<MachineType, 5, 16> {}; |
| 425 class IndexField : public BitField64<int32_t, 35, 29> {}; | 442 class IndexField : public BitField64<int32_t, 35, 29> {}; |
| 426 }; | 443 }; |
| 427 | 444 |
| 428 | 445 |
| 446 class ExplicitOperand : public LocationOperand { |
| 447 public: |
| 448 ExplicitOperand(LocationKind kind, MachineType machine_type, int index); |
| 449 |
| 450 static ExplicitOperand* New(Zone* zone, LocationKind kind, |
| 451 MachineType machine_type, int index) { |
| 452 return InstructionOperand::New(zone, |
| 453 ExplicitOperand(kind, machine_type, index)); |
| 454 } |
| 455 |
| 456 INSTRUCTION_OPERAND_CASTS(ExplicitOperand, EXPLICIT); |
| 457 }; |
| 458 |
| 459 |
| 460 class AllocatedOperand : public LocationOperand { |
| 461 public: |
| 462 AllocatedOperand(LocationKind kind, MachineType machine_type, int index) |
| 463 : LocationOperand(ALLOCATED, kind, machine_type, index) {} |
| 464 |
| 465 static AllocatedOperand* New(Zone* zone, LocationKind kind, |
| 466 MachineType machine_type, int index) { |
| 467 return InstructionOperand::New(zone, |
| 468 AllocatedOperand(kind, machine_type, index)); |
| 469 } |
| 470 |
| 471 INSTRUCTION_OPERAND_CASTS(AllocatedOperand, ALLOCATED); |
| 472 }; |
| 473 |
| 474 |
| 429 #undef INSTRUCTION_OPERAND_CASTS | 475 #undef INSTRUCTION_OPERAND_CASTS |
| 430 | 476 |
| 431 | 477 |
| 432 #define ALLOCATED_OPERAND_LIST(V) \ | 478 bool InstructionOperand::IsRegister() const { |
| 433 V(StackSlot, STACK_SLOT) \ | 479 return (IsAllocated() || IsExplicit()) && |
| 434 V(DoubleStackSlot, DOUBLE_STACK_SLOT) \ | 480 LocationOperand::cast(this)->location_kind() == |
| 435 V(Register, REGISTER) \ | 481 LocationOperand::REGISTER && |
| 436 V(DoubleRegister, DOUBLE_REGISTER) | 482 !IsFloatingPoint(LocationOperand::cast(this)->machine_type()); |
| 483 } |
| 437 | 484 |
| 485 bool InstructionOperand::IsDoubleRegister() const { |
| 486 return (IsAllocated() || IsExplicit()) && |
| 487 LocationOperand::cast(this)->location_kind() == |
| 488 LocationOperand::REGISTER && |
| 489 IsFloatingPoint(LocationOperand::cast(this)->machine_type()); |
| 490 } |
| 438 | 491 |
| 439 #define ALLOCATED_OPERAND_IS(SubKind, kOperandKind) \ | 492 bool InstructionOperand::IsStackSlot() const { |
| 440 bool InstructionOperand::Is##SubKind() const { \ | 493 return (IsAllocated() || IsExplicit()) && |
| 441 return IsAllocated() && \ | 494 LocationOperand::cast(this)->location_kind() == |
| 442 AllocatedOperand::cast(this)->allocated_kind() == \ | 495 LocationOperand::STACK_SLOT && |
| 443 AllocatedOperand::kOperandKind; \ | 496 !IsFloatingPoint(LocationOperand::cast(this)->machine_type()); |
| 444 } | 497 } |
| 445 ALLOCATED_OPERAND_LIST(ALLOCATED_OPERAND_IS) | |
| 446 #undef ALLOCATED_OPERAND_IS | |
| 447 | 498 |
| 499 bool InstructionOperand::IsDoubleStackSlot() const { |
| 500 return (IsAllocated() || IsExplicit()) && |
| 501 LocationOperand::cast(this)->location_kind() == |
| 502 LocationOperand::STACK_SLOT && |
| 503 IsFloatingPoint(LocationOperand::cast(this)->machine_type()); |
| 504 } |
| 448 | 505 |
| 449 // TODO(dcarney): these subkinds are now pretty useless, nuke. | 506 uint64_t InstructionOperand::GetCanonicalizedValue() const { |
| 450 #define ALLOCATED_OPERAND_CLASS(SubKind, kOperandKind) \ | 507 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. | 508 // TODO(dcarney): put machine type last and mask. |
| 484 return AllocatedOperand::MachineTypeField::update(this->value_, kMachNone); | 509 MachineType canonicalized_machine_type = |
| 510 IsFloatingPoint(LocationOperand::cast(this)->machine_type()) |
| 511 ? kMachFloat64 |
| 512 : kMachNone; |
| 513 return InstructionOperand::KindField::update( |
| 514 LocationOperand::MachineTypeField::update(this->value_, |
| 515 canonicalized_machine_type), |
| 516 LocationOperand::EXPLICIT); |
| 485 } | 517 } |
| 486 return this->value_; | 518 return this->value_; |
| 487 } | 519 } |
| 488 | 520 |
| 489 | 521 |
| 490 // Required for maps that don't care about machine type. | 522 // Required for maps that don't care about machine type. |
| 491 struct CompareOperandModuloType { | 523 struct CompareOperandModuloType { |
| 492 bool operator()(const InstructionOperand& a, | 524 bool operator()(const InstructionOperand& a, |
| 493 const InstructionOperand& b) const { | 525 const InstructionOperand& b) const { |
| 494 return a.CompareModuloType(b); | 526 return a.CompareCanonicalized(b); |
| 495 } | 527 } |
| 496 }; | 528 }; |
| 497 | 529 |
| 498 | 530 |
| 499 class MoveOperands final : public ZoneObject { | 531 class MoveOperands final : public ZoneObject { |
| 500 public: | 532 public: |
| 501 MoveOperands(const InstructionOperand& source, | 533 MoveOperands(const InstructionOperand& source, |
| 502 const InstructionOperand& destination) | 534 const InstructionOperand& destination) |
| 503 : source_(source), destination_(destination) { | 535 : source_(source), destination_(destination) { |
| 504 DCHECK(!source.IsInvalid() && !destination.IsInvalid()); | 536 DCHECK(!source.IsInvalid() && !destination.IsInvalid()); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 516 | 548 |
| 517 // The gap resolver marks moves as "in-progress" by clearing the | 549 // The gap resolver marks moves as "in-progress" by clearing the |
| 518 // destination (but not the source). | 550 // destination (but not the source). |
| 519 bool IsPending() const { | 551 bool IsPending() const { |
| 520 return destination_.IsInvalid() && !source_.IsInvalid(); | 552 return destination_.IsInvalid() && !source_.IsInvalid(); |
| 521 } | 553 } |
| 522 void SetPending() { destination_ = InstructionOperand(); } | 554 void SetPending() { destination_ = InstructionOperand(); } |
| 523 | 555 |
| 524 // True if this move a move into the given destination operand. | 556 // True if this move a move into the given destination operand. |
| 525 bool Blocks(const InstructionOperand& operand) const { | 557 bool Blocks(const InstructionOperand& operand) const { |
| 526 return !IsEliminated() && source().EqualsModuloType(operand); | 558 return !IsEliminated() && source().EqualsCanonicalized(operand); |
| 527 } | 559 } |
| 528 | 560 |
| 529 // A move is redundant if it's been eliminated or if its source and | 561 // A move is redundant if it's been eliminated or if its source and |
| 530 // destination are the same. | 562 // destination are the same. |
| 531 bool IsRedundant() const { | 563 bool IsRedundant() const { |
| 532 DCHECK_IMPLIES(!destination_.IsInvalid(), !destination_.IsConstant()); | 564 DCHECK_IMPLIES(!destination_.IsInvalid(), !destination_.IsConstant()); |
| 533 return IsEliminated() || source_.EqualsModuloType(destination_); | 565 return IsEliminated() || source_.EqualsCanonicalized(destination_); |
| 534 } | 566 } |
| 535 | 567 |
| 536 // We clear both operands to indicate move that's been eliminated. | 568 // We clear both operands to indicate move that's been eliminated. |
| 537 void Eliminate() { source_ = destination_ = InstructionOperand(); } | 569 void Eliminate() { source_ = destination_ = InstructionOperand(); } |
| 538 bool IsEliminated() const { | 570 bool IsEliminated() const { |
| 539 DCHECK_IMPLIES(source_.IsInvalid(), destination_.IsInvalid()); | 571 DCHECK_IMPLIES(source_.IsInvalid(), destination_.IsInvalid()); |
| 540 return source_.IsInvalid(); | 572 return source_.IsInvalid(); |
| 541 } | 573 } |
| 542 | 574 |
| 543 private: | 575 private: |
| (...skipping 684 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1228 | 1260 |
| 1229 | 1261 |
| 1230 std::ostream& operator<<(std::ostream& os, | 1262 std::ostream& operator<<(std::ostream& os, |
| 1231 const PrintableInstructionSequence& code); | 1263 const PrintableInstructionSequence& code); |
| 1232 | 1264 |
| 1233 } // namespace compiler | 1265 } // namespace compiler |
| 1234 } // namespace internal | 1266 } // namespace internal |
| 1235 } // namespace v8 | 1267 } // namespace v8 |
| 1236 | 1268 |
| 1237 #endif // V8_COMPILER_INSTRUCTION_H_ | 1269 #endif // V8_COMPILER_INSTRUCTION_H_ |
| OLD | NEW |