OLD | NEW |
1 //===- subzero/src/IceOperand.h - High-level operands -----------*- C++ -*-===// | 1 //===- subzero/src/IceOperand.h - High-level operands -----------*- C++ -*-===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 /// | 9 /// |
10 /// \file | 10 /// \file |
(...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 } | 395 } |
396 | 396 |
397 static bool classof(const Operand *Operand) { | 397 static bool classof(const Operand *Operand) { |
398 return Operand->getKind() == kConstUndef; | 398 return Operand->getKind() == kConstUndef; |
399 } | 399 } |
400 | 400 |
401 private: | 401 private: |
402 ConstantUndef(Type Ty) : Constant(kConstUndef, Ty) {} | 402 ConstantUndef(Type Ty) : Constant(kConstUndef, Ty) {} |
403 }; | 403 }; |
404 | 404 |
| 405 /// RegNumT is for holding target-specific register numbers, plus the sentinel |
| 406 /// value NoRegister. Its public ctor allows direct use of enum values, such as |
| 407 /// RegNumT(Reg_eax), but not things like RegNumT(Reg_eax+1). This is to try to |
| 408 /// prevent inappropriate assumptions about enum ordering. If needed, the |
| 409 /// fromInt() method can be used, such as when a RegNumT is based on a bitvector |
| 410 /// index. |
| 411 class RegNumT { |
| 412 public: |
| 413 using BaseType = uint32_t; |
| 414 RegNumT() = default; |
| 415 RegNumT(const RegNumT &) = default; |
| 416 template <typename AnyEnum> |
| 417 RegNumT(AnyEnum Value, |
| 418 typename std::enable_if<std::is_enum<AnyEnum>::value, int>::type = 0) |
| 419 : Value(Value) { |
| 420 validate(Value); |
| 421 } |
| 422 RegNumT &operator=(const RegNumT &) = default; |
| 423 operator unsigned() const { return Value; } |
| 424 /// Asserts that the register is valid, i.e. not NoRegisterValue. Note that |
| 425 /// the ctor already does the target-specific limit check. |
| 426 void assertIsValid() const { assert(Value != NoRegisterValue); } |
| 427 static RegNumT fromInt(BaseType Value) { return RegNumT(Value); } |
| 428 /// Marks cases that inappropriately add/subtract RegNumT values, and |
| 429 /// therefore need to be fixed because they make assumptions about register |
| 430 /// enum value ordering. TODO(stichnot): Remove fixme() as soon as all |
| 431 /// current uses are fixed/removed. |
| 432 static RegNumT fixme(BaseType Value) { return RegNumT(Value); } |
| 433 /// The target's staticInit() method should call setLimit() to register the |
| 434 /// upper bound of allowable values. |
| 435 static void setLimit(BaseType Value) { |
| 436 // Make sure it's only called once. |
| 437 assert(Limit == 0); |
| 438 assert(Value != 0); |
| 439 Limit = Value; |
| 440 } |
| 441 // Define NoRegisterValue as an enum value so that it can be used as an |
| 442 // argument for the public ctor if desired. |
| 443 enum { NoRegisterValue = std::numeric_limits<BaseType>::max() }; |
| 444 const static RegNumT NoRegister /* = NoRegisterValue */; |
| 445 |
| 446 private: |
| 447 BaseType Value = NoRegisterValue; |
| 448 static BaseType Limit; |
| 449 /// Private ctor called only by fromInt() and fixme(). |
| 450 RegNumT(BaseType Value) : Value(Value) { validate(Value); } |
| 451 /// The ctor calls this to validate against the target-supplied limit. |
| 452 static void validate(BaseType Value) { |
| 453 (void)Value; |
| 454 assert(Value == NoRegisterValue || Value < Limit); |
| 455 } |
| 456 /// Disallow operators that inappropriately make assumptions about register |
| 457 /// enum value ordering. |
| 458 bool operator<(const RegNumT &) = delete; |
| 459 bool operator<=(const RegNumT &) = delete; |
| 460 bool operator>(const RegNumT &) = delete; |
| 461 bool operator>=(const RegNumT &) = delete; |
| 462 }; |
| 463 |
| 464 /// RegNumBVIter wraps llvm::SmallBitVector so that instead of this pattern: |
| 465 /// |
| 466 /// for (int i = V.find_first(); i != -1; i = V.find_next(i)) { |
| 467 /// RegNumT RegNum = RegNumT::fromInt(i); |
| 468 /// ... |
| 469 /// } |
| 470 /// |
| 471 /// this cleaner pattern can be used: |
| 472 /// |
| 473 /// for (RegNumT RegNum : RegNumBVIter(V)) { |
| 474 /// ... |
| 475 /// } |
| 476 class RegNumBVIter { |
| 477 using T = llvm::SmallBitVector; |
| 478 static constexpr int Sentinel = -1; |
| 479 RegNumBVIter() = delete; |
| 480 RegNumBVIter(const RegNumBVIter &) = delete; |
| 481 RegNumBVIter &operator=(const RegNumBVIter &) = delete; |
| 482 |
| 483 public: |
| 484 class Iterator { |
| 485 Iterator() = delete; |
| 486 Iterator &operator=(const Iterator &) = delete; |
| 487 |
| 488 public: |
| 489 explicit Iterator(const T &V) : V(V), Current(V.find_first()) {} |
| 490 Iterator(const T &V, int Value) : V(V), Current(Value) {} |
| 491 Iterator(const Iterator &) = default; |
| 492 RegNumT operator*() { |
| 493 assert(Current != Sentinel); |
| 494 return RegNumT::fromInt(Current); |
| 495 } |
| 496 Iterator &operator++() { |
| 497 assert(Current != Sentinel); |
| 498 Current = V.find_next(Current); |
| 499 return *this; |
| 500 } |
| 501 bool operator!=(Iterator &Other) { return Current != Other.Current; } |
| 502 |
| 503 private: |
| 504 const T &V; |
| 505 int Current; |
| 506 }; |
| 507 |
| 508 explicit RegNumBVIter(const T &V) : V(V) {} |
| 509 Iterator begin() { return Iterator(V); } |
| 510 Iterator end() { return Iterator(V, Sentinel); } |
| 511 |
| 512 private: |
| 513 const T &V; |
| 514 }; |
| 515 |
405 /// RegWeight is a wrapper for a uint32_t weight value, with a special value | 516 /// RegWeight is a wrapper for a uint32_t weight value, with a special value |
406 /// that represents infinite weight, and an addWeight() method that ensures that | 517 /// that represents infinite weight, and an addWeight() method that ensures that |
407 /// W+infinity=infinity. | 518 /// W+infinity=infinity. |
408 class RegWeight { | 519 class RegWeight { |
409 public: | 520 public: |
| 521 using BaseType = uint32_t; |
410 RegWeight() = default; | 522 RegWeight() = default; |
411 explicit RegWeight(uint32_t Weight) : Weight(Weight) {} | 523 explicit RegWeight(BaseType Weight) : Weight(Weight) {} |
412 RegWeight(const RegWeight &) = default; | 524 RegWeight(const RegWeight &) = default; |
413 RegWeight &operator=(const RegWeight &) = default; | 525 RegWeight &operator=(const RegWeight &) = default; |
414 constexpr static uint32_t Inf = ~0; /// Force regalloc to give a register | 526 constexpr static BaseType Inf = ~0; /// Force regalloc to give a register |
415 constexpr static uint32_t Zero = 0; /// Force regalloc NOT to give a register | 527 constexpr static BaseType Zero = 0; /// Force regalloc NOT to give a register |
416 constexpr static uint32_t Max = Inf - 1; /// Max natural weight. | 528 constexpr static BaseType Max = Inf - 1; /// Max natural weight. |
417 void addWeight(uint32_t Delta) { | 529 void addWeight(BaseType Delta) { |
418 if (Delta == Inf) | 530 if (Delta == Inf) |
419 Weight = Inf; | 531 Weight = Inf; |
420 else if (Weight != Inf) | 532 else if (Weight != Inf) |
421 if (Utils::add_overflow(Weight, Delta, &Weight) || Weight == Inf) | 533 if (Utils::add_overflow(Weight, Delta, &Weight) || Weight == Inf) |
422 Weight = Max; | 534 Weight = Max; |
423 } | 535 } |
424 void addWeight(const RegWeight &Other) { addWeight(Other.Weight); } | 536 void addWeight(const RegWeight &Other) { addWeight(Other.Weight); } |
425 void setWeight(uint32_t Val) { Weight = Val; } | 537 void setWeight(BaseType Val) { Weight = Val; } |
426 uint32_t getWeight() const { return Weight; } | 538 BaseType getWeight() const { return Weight; } |
427 | 539 |
428 private: | 540 private: |
429 uint32_t Weight = 0; | 541 BaseType Weight = 0; |
430 }; | 542 }; |
431 Ostream &operator<<(Ostream &Str, const RegWeight &W); | 543 Ostream &operator<<(Ostream &Str, const RegWeight &W); |
432 bool operator<(const RegWeight &A, const RegWeight &B); | 544 bool operator<(const RegWeight &A, const RegWeight &B); |
433 bool operator<=(const RegWeight &A, const RegWeight &B); | 545 bool operator<=(const RegWeight &A, const RegWeight &B); |
434 bool operator==(const RegWeight &A, const RegWeight &B); | 546 bool operator==(const RegWeight &A, const RegWeight &B); |
435 | 547 |
436 /// LiveRange is a set of instruction number intervals representing a variable's | 548 /// LiveRange is a set of instruction number intervals representing a variable's |
437 /// live range. Generally there is one interval per basic block where the | 549 /// live range. Generally there is one interval per basic block where the |
438 /// variable is live, but adjacent intervals get coalesced into a single | 550 /// variable is live, but adjacent intervals get coalesced into a single |
439 /// interval. | 551 /// interval. |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
527 bool getIgnoreLiveness() const { return IgnoreLiveness; } | 639 bool getIgnoreLiveness() const { return IgnoreLiveness; } |
528 | 640 |
529 int32_t getStackOffset() const { return StackOffset; } | 641 int32_t getStackOffset() const { return StackOffset; } |
530 void setStackOffset(int32_t Offset) { StackOffset = Offset; } | 642 void setStackOffset(int32_t Offset) { StackOffset = Offset; } |
531 /// Returns the variable's stack offset in symbolic form, to improve | 643 /// Returns the variable's stack offset in symbolic form, to improve |
532 /// readability in DecorateAsm mode. | 644 /// readability in DecorateAsm mode. |
533 IceString getSymbolicStackOffset(const Cfg *Func) const { | 645 IceString getSymbolicStackOffset(const Cfg *Func) const { |
534 return "lv$" + getName(Func); | 646 return "lv$" + getName(Func); |
535 } | 647 } |
536 | 648 |
537 static constexpr int32_t NoRegister = -1; | 649 bool hasReg() const { return getRegNum() != RegNumT::NoRegister; } |
538 bool hasReg() const { return getRegNum() != NoRegister; } | 650 RegNumT getRegNum() const { return RegNum; } |
539 int32_t getRegNum() const { return RegNum; } | 651 void setRegNum(RegNumT NewRegNum) { |
540 void setRegNum(int32_t NewRegNum) { | |
541 // Regnum shouldn't be set more than once. | 652 // Regnum shouldn't be set more than once. |
542 assert(!hasReg() || RegNum == NewRegNum); | 653 assert(!hasReg() || RegNum == NewRegNum); |
543 RegNum = NewRegNum; | 654 RegNum = NewRegNum; |
544 } | 655 } |
545 bool hasRegTmp() const { return getRegNumTmp() != NoRegister; } | 656 bool hasRegTmp() const { return getRegNumTmp() != RegNumT::NoRegister; } |
546 int32_t getRegNumTmp() const { return RegNumTmp; } | 657 RegNumT getRegNumTmp() const { return RegNumTmp; } |
547 void setRegNumTmp(int32_t NewRegNum) { RegNumTmp = NewRegNum; } | 658 void setRegNumTmp(RegNumT NewRegNum) { RegNumTmp = NewRegNum; } |
548 | 659 |
549 RegWeight getWeight(const Cfg *Func) const; | 660 RegWeight getWeight(const Cfg *Func) const; |
550 | 661 |
551 void setMustHaveReg() { RegRequirement = RR_MustHaveRegister; } | 662 void setMustHaveReg() { RegRequirement = RR_MustHaveRegister; } |
552 bool mustHaveReg() const { return RegRequirement == RR_MustHaveRegister; } | 663 bool mustHaveReg() const { return RegRequirement == RR_MustHaveRegister; } |
553 void setMustNotHaveReg() { RegRequirement = RR_MustNotHaveRegister; } | 664 void setMustNotHaveReg() { RegRequirement = RR_MustNotHaveRegister; } |
554 bool mustNotHaveReg() const { | 665 bool mustNotHaveReg() const { |
555 return RegRequirement == RR_MustNotHaveRegister; | 666 return RegRequirement == RR_MustNotHaveRegister; |
556 } | 667 } |
557 void setRematerializable(int32_t NewRegNum, int32_t NewOffset) { | 668 void setRematerializable(RegNumT NewRegNum, int32_t NewOffset) { |
558 IsRematerializable = true; | 669 IsRematerializable = true; |
559 setRegNum(NewRegNum); | 670 setRegNum(NewRegNum); |
560 setStackOffset(NewOffset); | 671 setStackOffset(NewOffset); |
561 setMustHaveReg(); | 672 setMustHaveReg(); |
562 } | 673 } |
563 bool isRematerializable() const { return IsRematerializable; } | 674 bool isRematerializable() const { return IsRematerializable; } |
564 | 675 |
565 void setRegClass(uint8_t RC) { RegisterClass = static_cast<RegClass>(RC); } | 676 void setRegClass(uint8_t RC) { RegisterClass = static_cast<RegClass>(RC); } |
566 RegClass getRegClass() const { return RegisterClass; } | 677 RegClass getRegClass() const { return RegisterClass; } |
567 | 678 |
(...skipping 18 matching lines...) Expand all Loading... |
586 constexpr bool UseTrimmed = true; | 697 constexpr bool UseTrimmed = true; |
587 return Live.overlapsInst(Other->Live.getStart(), UseTrimmed); | 698 return Live.overlapsInst(Other->Live.getStart(), UseTrimmed); |
588 } | 699 } |
589 | 700 |
590 /// Creates a temporary copy of the variable with a different type. Used | 701 /// Creates a temporary copy of the variable with a different type. Used |
591 /// primarily for syntactic correctness of textual assembly emission. Note | 702 /// primarily for syntactic correctness of textual assembly emission. Note |
592 /// that only basic information is copied, in particular not IsArgument, | 703 /// that only basic information is copied, in particular not IsArgument, |
593 /// IsImplicitArgument, IgnoreLiveness, RegNumTmp, Live, LoVar, HiVar, | 704 /// IsImplicitArgument, IgnoreLiveness, RegNumTmp, Live, LoVar, HiVar, |
594 /// VarsReal. If NewRegNum!=NoRegister, then that register assignment is made | 705 /// VarsReal. If NewRegNum!=NoRegister, then that register assignment is made |
595 /// instead of copying the existing assignment. | 706 /// instead of copying the existing assignment. |
596 const Variable *asType(Type Ty, int32_t NewRegNum) const; | 707 const Variable *asType(Type Ty, RegNumT NewRegNum) const; |
597 | 708 |
598 void emit(const Cfg *Func) const override; | 709 void emit(const Cfg *Func) const override; |
599 using Operand::dump; | 710 using Operand::dump; |
600 void dump(const Cfg *Func, Ostream &Str) const override; | 711 void dump(const Cfg *Func, Ostream &Str) const override; |
601 | 712 |
602 /// Return reg num of base register, if different from stack/frame register. | 713 /// Return reg num of base register, if different from stack/frame register. |
603 virtual int32_t getBaseRegNum() const { return NoRegister; } | 714 virtual RegNumT getBaseRegNum() const { return RegNumT::NoRegister; } |
604 | 715 |
605 static bool classof(const Operand *Operand) { | 716 static bool classof(const Operand *Operand) { |
606 OperandKind Kind = Operand->getKind(); | 717 OperandKind Kind = Operand->getKind(); |
607 return Kind >= kVariable && Kind <= kVariable_Max; | 718 return Kind >= kVariable && Kind <= kVariable_Max; |
608 } | 719 } |
609 | 720 |
610 protected: | 721 protected: |
611 Variable(OperandKind K, Type Ty, SizeT Index) | 722 Variable(OperandKind K, Type Ty, SizeT Index) |
612 : Operand(K, Ty), Number(Index), | 723 : Operand(K, Ty), Number(Index), |
613 RegisterClass(static_cast<RegClass>(Ty)) { | 724 RegisterClass(static_cast<RegClass>(Ty)) { |
(...skipping 11 matching lines...) Expand all Loading... |
625 /// and validating live ranges. This is usually reserved for the stack | 736 /// and validating live ranges. This is usually reserved for the stack |
626 /// pointer and other physical registers specifically referenced by name. | 737 /// pointer and other physical registers specifically referenced by name. |
627 bool IgnoreLiveness = false; | 738 bool IgnoreLiveness = false; |
628 // If IsRematerializable, RegNum keeps track of which register (stack or frame | 739 // If IsRematerializable, RegNum keeps track of which register (stack or frame |
629 // pointer), and StackOffset is the known offset from that register. | 740 // pointer), and StackOffset is the known offset from that register. |
630 bool IsRematerializable = false; | 741 bool IsRematerializable = false; |
631 RegRequirement RegRequirement = RR_MayHaveRegister; | 742 RegRequirement RegRequirement = RR_MayHaveRegister; |
632 RegClass RegisterClass; | 743 RegClass RegisterClass; |
633 /// RegNum is the allocated register, or NoRegister if it isn't | 744 /// RegNum is the allocated register, or NoRegister if it isn't |
634 /// register-allocated. | 745 /// register-allocated. |
635 int32_t RegNum = NoRegister; | 746 RegNumT RegNum = RegNumT::NoRegister; |
636 /// RegNumTmp is the tentative assignment during register allocation. | 747 /// RegNumTmp is the tentative assignment during register allocation. |
637 int32_t RegNumTmp = NoRegister; | 748 RegNumT RegNumTmp = RegNumT::NoRegister; |
638 /// StackOffset is the canonical location on stack (only if | 749 /// StackOffset is the canonical location on stack (only if |
639 /// RegNum==NoRegister || IsArgument). | 750 /// RegNum==NoRegister || IsArgument). |
640 int32_t StackOffset = 0; | 751 int32_t StackOffset = 0; |
641 LiveRange Live; | 752 LiveRange Live; |
642 /// VarsReal (and Operand::Vars) are set up such that Vars[0] == this. | 753 /// VarsReal (and Operand::Vars) are set up such that Vars[0] == this. |
643 Variable *VarsReal[1]; | 754 Variable *VarsReal[1]; |
644 }; | 755 }; |
645 | 756 |
646 // Variable64On32 represents a 64-bit variable on a 32-bit architecture. In | 757 // Variable64On32 represents a 64-bit variable on a 32-bit architecture. In |
647 // this situation the variable must be split into a low and a high word. | 758 // this situation the variable must be split into a low and a high word. |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
812 private: | 923 private: |
813 const Cfg *Func; | 924 const Cfg *Func; |
814 MetadataKind Kind; | 925 MetadataKind Kind; |
815 CfgVector<VariableTracking> Metadata; | 926 CfgVector<VariableTracking> Metadata; |
816 const static InstDefList NoDefinitions; | 927 const static InstDefList NoDefinitions; |
817 }; | 928 }; |
818 | 929 |
819 } // end of namespace Ice | 930 } // end of namespace Ice |
820 | 931 |
821 #endif // SUBZERO_SRC_ICEOPERAND_H | 932 #endif // SUBZERO_SRC_ICEOPERAND_H |
OLD | NEW |