Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(66)

Side by Side Diff: src/compiler/instruction.h

Issue 1389373002: [turbofan] Create ExplicitOperands to specify operands without virtual registers (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Review feedback Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/gap-resolver.cc ('k') | src/compiler/instruction.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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_
OLDNEW
« no previous file with comments | « src/compiler/gap-resolver.cc ('k') | src/compiler/instruction.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698