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 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 | 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 | 406 /// value if no register is assigned. Its public ctor allows direct use of enum |
407 /// RegNumT(Reg_eax), but not things like RegNumT(Reg_eax+1). This is to try to | 407 /// values, such as RegNumT(Reg_eax), but not things like RegNumT(Reg_eax+1). |
408 /// prevent inappropriate assumptions about enum ordering. If needed, the | 408 /// This is to try to prevent inappropriate assumptions about enum ordering. If |
409 /// fromInt() method can be used, such as when a RegNumT is based on a bitvector | 409 /// needed, the fromInt() method can be used, such as when a RegNumT is based |
410 /// index. | 410 /// on a bitvector index. |
411 class RegNumT { | 411 class RegNumT { |
412 public: | 412 public: |
413 using BaseType = uint32_t; | 413 using BaseType = uint32_t; |
414 RegNumT() = default; | 414 RegNumT() = default; |
415 RegNumT(const RegNumT &) = default; | 415 RegNumT(const RegNumT &) = default; |
416 template <typename AnyEnum> | 416 template <typename AnyEnum> |
417 RegNumT(AnyEnum Value, | 417 RegNumT(AnyEnum Value, |
418 typename std::enable_if<std::is_enum<AnyEnum>::value, int>::type = 0) | 418 typename std::enable_if<std::is_enum<AnyEnum>::value, int>::type = 0) |
419 : Value(Value) { | 419 : Value(Value) { |
420 validate(Value); | 420 validate(Value); |
(...skipping 13 matching lines...) Expand all Loading... |
434 /// upper bound of allowable values. | 434 /// upper bound of allowable values. |
435 static void setLimit(BaseType Value) { | 435 static void setLimit(BaseType Value) { |
436 // Make sure it's only called once. | 436 // Make sure it's only called once. |
437 assert(Limit == 0); | 437 assert(Limit == 0); |
438 assert(Value != 0); | 438 assert(Value != 0); |
439 Limit = Value; | 439 Limit = Value; |
440 } | 440 } |
441 // Define NoRegisterValue as an enum value so that it can be used as an | 441 // Define NoRegisterValue as an enum value so that it can be used as an |
442 // argument for the public ctor if desired. | 442 // argument for the public ctor if desired. |
443 enum { NoRegisterValue = std::numeric_limits<BaseType>::max() }; | 443 enum { NoRegisterValue = std::numeric_limits<BaseType>::max() }; |
444 const static RegNumT NoRegister /* = NoRegisterValue */; | 444 |
| 445 bool hasValue() const { return Value != NoRegisterValue; } |
| 446 bool hasNoValue() const { return !hasValue(); } |
445 | 447 |
446 private: | 448 private: |
447 BaseType Value = NoRegisterValue; | 449 BaseType Value = NoRegisterValue; |
448 static BaseType Limit; | 450 static BaseType Limit; |
449 /// Private ctor called only by fromInt() and fixme(). | 451 /// Private ctor called only by fromInt() and fixme(). |
450 RegNumT(BaseType Value) : Value(Value) { validate(Value); } | 452 RegNumT(BaseType Value) : Value(Value) { validate(Value); } |
451 /// The ctor calls this to validate against the target-supplied limit. | 453 /// The ctor calls this to validate against the target-supplied limit. |
452 static void validate(BaseType Value) { | 454 static void validate(BaseType Value) { |
453 (void)Value; | 455 (void)Value; |
454 assert(Value == NoRegisterValue || Value < Limit); | 456 assert(Value == NoRegisterValue || Value < Limit); |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
639 bool getIgnoreLiveness() const { return IgnoreLiveness; } | 641 bool getIgnoreLiveness() const { return IgnoreLiveness; } |
640 | 642 |
641 int32_t getStackOffset() const { return StackOffset; } | 643 int32_t getStackOffset() const { return StackOffset; } |
642 void setStackOffset(int32_t Offset) { StackOffset = Offset; } | 644 void setStackOffset(int32_t Offset) { StackOffset = Offset; } |
643 /// Returns the variable's stack offset in symbolic form, to improve | 645 /// Returns the variable's stack offset in symbolic form, to improve |
644 /// readability in DecorateAsm mode. | 646 /// readability in DecorateAsm mode. |
645 IceString getSymbolicStackOffset(const Cfg *Func) const { | 647 IceString getSymbolicStackOffset(const Cfg *Func) const { |
646 return "lv$" + getName(Func); | 648 return "lv$" + getName(Func); |
647 } | 649 } |
648 | 650 |
649 bool hasReg() const { return getRegNum() != RegNumT::NoRegister; } | 651 bool hasReg() const { return getRegNum().hasValue(); } |
650 RegNumT getRegNum() const { return RegNum; } | 652 RegNumT getRegNum() const { return RegNum; } |
651 void setRegNum(RegNumT NewRegNum) { | 653 void setRegNum(RegNumT NewRegNum) { |
652 // Regnum shouldn't be set more than once. | 654 // Regnum shouldn't be set more than once. |
653 assert(!hasReg() || RegNum == NewRegNum); | 655 assert(!hasReg() || RegNum == NewRegNum); |
654 RegNum = NewRegNum; | 656 RegNum = NewRegNum; |
655 } | 657 } |
656 bool hasRegTmp() const { return getRegNumTmp() != RegNumT::NoRegister; } | 658 bool hasRegTmp() const { return getRegNumTmp().hasValue(); } |
657 RegNumT getRegNumTmp() const { return RegNumTmp; } | 659 RegNumT getRegNumTmp() const { return RegNumTmp; } |
658 void setRegNumTmp(RegNumT NewRegNum) { RegNumTmp = NewRegNum; } | 660 void setRegNumTmp(RegNumT NewRegNum) { RegNumTmp = NewRegNum; } |
659 | 661 |
660 RegWeight getWeight(const Cfg *Func) const; | 662 RegWeight getWeight(const Cfg *Func) const; |
661 | 663 |
662 void setMustHaveReg() { RegRequirement = RR_MustHaveRegister; } | 664 void setMustHaveReg() { RegRequirement = RR_MustHaveRegister; } |
663 bool mustHaveReg() const { return RegRequirement == RR_MustHaveRegister; } | 665 bool mustHaveReg() const { return RegRequirement == RR_MustHaveRegister; } |
664 void setMustNotHaveReg() { RegRequirement = RR_MustNotHaveRegister; } | 666 void setMustNotHaveReg() { RegRequirement = RR_MustNotHaveRegister; } |
665 bool mustNotHaveReg() const { | 667 bool mustNotHaveReg() const { |
666 return RegRequirement == RR_MustNotHaveRegister; | 668 return RegRequirement == RR_MustNotHaveRegister; |
(...skipping 28 matching lines...) Expand all Loading... |
695 } | 697 } |
696 bool rangeOverlapsStart(const Variable *Other) const { | 698 bool rangeOverlapsStart(const Variable *Other) const { |
697 constexpr bool UseTrimmed = true; | 699 constexpr bool UseTrimmed = true; |
698 return Live.overlapsInst(Other->Live.getStart(), UseTrimmed); | 700 return Live.overlapsInst(Other->Live.getStart(), UseTrimmed); |
699 } | 701 } |
700 | 702 |
701 /// Creates a temporary copy of the variable with a different type. Used | 703 /// Creates a temporary copy of the variable with a different type. Used |
702 /// primarily for syntactic correctness of textual assembly emission. Note | 704 /// primarily for syntactic correctness of textual assembly emission. Note |
703 /// that only basic information is copied, in particular not IsArgument, | 705 /// that only basic information is copied, in particular not IsArgument, |
704 /// IsImplicitArgument, IgnoreLiveness, RegNumTmp, Live, LoVar, HiVar, | 706 /// IsImplicitArgument, IgnoreLiveness, RegNumTmp, Live, LoVar, HiVar, |
705 /// VarsReal. If NewRegNum!=NoRegister, then that register assignment is made | 707 /// VarsReal. If NewRegNum.hasValue(), then that register assignment is made |
706 /// instead of copying the existing assignment. | 708 /// instead of copying the existing assignment. |
707 const Variable *asType(Type Ty, RegNumT NewRegNum) const; | 709 const Variable *asType(Type Ty, RegNumT NewRegNum) const; |
708 | 710 |
709 void emit(const Cfg *Func) const override; | 711 void emit(const Cfg *Func) const override; |
710 using Operand::dump; | 712 using Operand::dump; |
711 void dump(const Cfg *Func, Ostream &Str) const override; | 713 void dump(const Cfg *Func, Ostream &Str) const override; |
712 | 714 |
713 /// Return reg num of base register, if different from stack/frame register. | 715 /// Return reg num of base register, if different from stack/frame register. |
714 virtual RegNumT getBaseRegNum() const { return RegNumT::NoRegister; } | 716 virtual RegNumT getBaseRegNum() const { return RegNumT(); } |
715 | 717 |
716 static bool classof(const Operand *Operand) { | 718 static bool classof(const Operand *Operand) { |
717 OperandKind Kind = Operand->getKind(); | 719 OperandKind Kind = Operand->getKind(); |
718 return Kind >= kVariable && Kind <= kVariable_Max; | 720 return Kind >= kVariable && Kind <= kVariable_Max; |
719 } | 721 } |
720 | 722 |
721 protected: | 723 protected: |
722 Variable(OperandKind K, Type Ty, SizeT Index) | 724 Variable(OperandKind K, Type Ty, SizeT Index) |
723 : Operand(K, Ty), Number(Index), | 725 : Operand(K, Ty), Number(Index), |
724 RegisterClass(static_cast<RegClass>(Ty)) { | 726 RegisterClass(static_cast<RegClass>(Ty)) { |
725 Vars = VarsReal; | 727 Vars = VarsReal; |
726 Vars[0] = this; | 728 Vars[0] = this; |
727 NumVars = 1; | 729 NumVars = 1; |
728 } | 730 } |
729 /// Number is unique across all variables, and is used as a (bit)vector index | 731 /// Number is unique across all variables, and is used as a (bit)vector index |
730 /// for liveness analysis. | 732 /// for liveness analysis. |
731 const SizeT Number; | 733 const SizeT Number; |
732 Cfg::IdentifierIndexType NameIndex = Cfg::IdentifierIndexInvalid; | 734 Cfg::IdentifierIndexType NameIndex = Cfg::IdentifierIndexInvalid; |
733 bool IsArgument = false; | 735 bool IsArgument = false; |
734 bool IsImplicitArgument = false; | 736 bool IsImplicitArgument = false; |
735 /// IgnoreLiveness means that the variable should be ignored when constructing | 737 /// IgnoreLiveness means that the variable should be ignored when constructing |
736 /// and validating live ranges. This is usually reserved for the stack | 738 /// and validating live ranges. This is usually reserved for the stack |
737 /// pointer and other physical registers specifically referenced by name. | 739 /// pointer and other physical registers specifically referenced by name. |
738 bool IgnoreLiveness = false; | 740 bool IgnoreLiveness = false; |
739 // If IsRematerializable, RegNum keeps track of which register (stack or frame | 741 // If IsRematerializable, RegNum keeps track of which register (stack or frame |
740 // pointer), and StackOffset is the known offset from that register. | 742 // pointer), and StackOffset is the known offset from that register. |
741 bool IsRematerializable = false; | 743 bool IsRematerializable = false; |
742 RegRequirement RegRequirement = RR_MayHaveRegister; | 744 RegRequirement RegRequirement = RR_MayHaveRegister; |
743 RegClass RegisterClass; | 745 RegClass RegisterClass; |
744 /// RegNum is the allocated register, or NoRegister if it isn't | 746 /// RegNum is the allocated register, (as long as RegNum.hasValue() is true). |
745 /// register-allocated. | 747 RegNumT RegNum; |
746 RegNumT RegNum = RegNumT::NoRegister; | |
747 /// RegNumTmp is the tentative assignment during register allocation. | 748 /// RegNumTmp is the tentative assignment during register allocation. |
748 RegNumT RegNumTmp = RegNumT::NoRegister; | 749 RegNumT RegNumTmp; |
749 /// StackOffset is the canonical location on stack (only if | 750 /// StackOffset is the canonical location on stack (only if |
750 /// RegNum==NoRegister || IsArgument). | 751 /// RegNum.hasNoValue() || IsArgument). |
751 int32_t StackOffset = 0; | 752 int32_t StackOffset = 0; |
752 LiveRange Live; | 753 LiveRange Live; |
753 /// VarsReal (and Operand::Vars) are set up such that Vars[0] == this. | 754 /// VarsReal (and Operand::Vars) are set up such that Vars[0] == this. |
754 Variable *VarsReal[1]; | 755 Variable *VarsReal[1]; |
755 }; | 756 }; |
756 | 757 |
757 // Variable64On32 represents a 64-bit variable on a 32-bit architecture. In | 758 // Variable64On32 represents a 64-bit variable on a 32-bit architecture. In |
758 // this situation the variable must be split into a low and a high word. | 759 // this situation the variable must be split into a low and a high word. |
759 class Variable64On32 : public Variable { | 760 class Variable64On32 : public Variable { |
760 Variable64On32() = delete; | 761 Variable64On32() = delete; |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
923 private: | 924 private: |
924 const Cfg *Func; | 925 const Cfg *Func; |
925 MetadataKind Kind; | 926 MetadataKind Kind; |
926 CfgVector<VariableTracking> Metadata; | 927 CfgVector<VariableTracking> Metadata; |
927 const static InstDefList NoDefinitions; | 928 const static InstDefList NoDefinitions; |
928 }; | 929 }; |
929 | 930 |
930 } // end of namespace Ice | 931 } // end of namespace Ice |
931 | 932 |
932 #endif // SUBZERO_SRC_ICEOPERAND_H | 933 #endif // SUBZERO_SRC_ICEOPERAND_H |
OLD | NEW |