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 NoRegister. Note that the | |
425 /// ctor already does the target-specific limit check. | |
426 void assertIsValid() const { assert(Value != NoRegister); } | |
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 NoRegister as an enum value so that it can be used as an argument | |
John
2016/02/10 16:01:51
nice. :)
Jim Stichnoth
2016/02/10 17:47:20
True, though that inhibits certain uses of "auto",
Jim Stichnoth
2016/02/10 18:47:30
I am now le refreshed, and realize the horror of t
| |
442 // for the public ctor. | |
443 enum { NoRegister = std::numeric_limits<BaseType>::max() }; | |
444 | |
445 private: | |
446 BaseType Value = NoRegister; | |
447 static BaseType Limit; | |
448 /// Private ctor called only by fromInt() and fixme(). | |
449 RegNumT(BaseType Value) : Value(Value) { validate(Value); } | |
450 /// The ctor calls this to validate against the target-supplied limit. | |
451 static void validate(BaseType Value) { | |
452 (void)Value; | |
453 assert(Value == NoRegister || Value < Limit); | |
454 } | |
455 /// Disallow operators that inappropriately make assumptions about register | |
456 /// enum value ordering. | |
457 bool operator<(const RegNumT &) = delete; | |
458 bool operator<=(const RegNumT &) = delete; | |
459 bool operator>(const RegNumT &) = delete; | |
460 bool operator>=(const RegNumT &) = delete; | |
461 }; | |
462 | |
463 /// RegNumBitVector wraps llvm::SmallBitVector so that instead of this pattern: | |
464 /// | |
465 /// for (int i = V.find_first(); i != -1; i = V.find_next(i)) { | |
466 /// RegNumT RegNum = RegNumT::fromInt(i); | |
467 /// ... | |
468 /// } | |
469 /// | |
470 /// this cleaner pattern can be used: | |
471 /// | |
472 /// for (RegNumT RegNum : RegNumBitVector(V)) { | |
473 /// ... | |
474 /// } | |
475 class RegNumBitVector { | |
John
2016/02/10 16:01:51
This is an iterator, so maybe just rename it to Re
Jim Stichnoth
2016/02/10 17:47:20
I was trying to control the identifier length a bi
| |
476 using T = llvm::SmallBitVector; | |
477 static constexpr int Sentinel = -1; | |
478 RegNumBitVector() = delete; | |
479 RegNumBitVector(const RegNumBitVector &) = delete; | |
480 RegNumBitVector &operator=(const RegNumBitVector &) = delete; | |
481 | |
482 public: | |
483 class Iterator { | |
484 Iterator() = delete; | |
485 Iterator &operator=(const Iterator &) = delete; | |
486 | |
487 public: | |
488 explicit Iterator(const T &V) : V(V), Current(V.find_first()) {} | |
489 Iterator(const T &V, int Value) : V(V), Current(Value) {} | |
490 Iterator(const Iterator &) = default; | |
491 RegNumT operator*() { | |
492 assert(Current != Sentinel); | |
493 return RegNumT::fromInt(Current); | |
494 } | |
495 Iterator &operator++() { | |
496 assert(Current != Sentinel); | |
497 Current = V.find_next(Current); | |
498 return *this; | |
499 } | |
500 bool operator!=(Iterator &Other) { return Current != Other.Current; } | |
501 | |
502 private: | |
503 const T &V; | |
504 int Current; | |
505 }; | |
506 | |
507 explicit RegNumBitVector(const T &V) : V(V) {} | |
508 Iterator begin() { return Iterator(V); } | |
509 Iterator end() { return Iterator(V, Sentinel); } | |
510 | |
511 private: | |
512 const T &V; | |
513 }; | |
514 | |
405 /// RegWeight is a wrapper for a uint32_t weight value, with a special value | 515 /// 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 | 516 /// that represents infinite weight, and an addWeight() method that ensures that |
407 /// W+infinity=infinity. | 517 /// W+infinity=infinity. |
408 class RegWeight { | 518 class RegWeight { |
409 public: | 519 public: |
410 RegWeight() = default; | 520 RegWeight() = default; |
411 explicit RegWeight(uint32_t Weight) : Weight(Weight) {} | 521 explicit RegWeight(uint32_t Weight) : Weight(Weight) {} |
412 RegWeight(const RegWeight &) = default; | 522 RegWeight(const RegWeight &) = default; |
413 RegWeight &operator=(const RegWeight &) = default; | 523 RegWeight &operator=(const RegWeight &) = default; |
414 constexpr static uint32_t Inf = ~0; /// Force regalloc to give a register | 524 constexpr static uint32_t Inf = ~0; /// Force regalloc to give a register |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
527 bool getIgnoreLiveness() const { return IgnoreLiveness; } | 637 bool getIgnoreLiveness() const { return IgnoreLiveness; } |
528 | 638 |
529 int32_t getStackOffset() const { return StackOffset; } | 639 int32_t getStackOffset() const { return StackOffset; } |
530 void setStackOffset(int32_t Offset) { StackOffset = Offset; } | 640 void setStackOffset(int32_t Offset) { StackOffset = Offset; } |
531 /// Returns the variable's stack offset in symbolic form, to improve | 641 /// Returns the variable's stack offset in symbolic form, to improve |
532 /// readability in DecorateAsm mode. | 642 /// readability in DecorateAsm mode. |
533 IceString getSymbolicStackOffset(const Cfg *Func) const { | 643 IceString getSymbolicStackOffset(const Cfg *Func) const { |
534 return "lv$" + getName(Func); | 644 return "lv$" + getName(Func); |
535 } | 645 } |
536 | 646 |
537 static constexpr int32_t NoRegister = -1; | 647 bool hasReg() const { return getRegNum() != RegNumT::NoRegister; } |
538 bool hasReg() const { return getRegNum() != NoRegister; } | 648 RegNumT getRegNum() const { return RegNum; } |
539 int32_t getRegNum() const { return RegNum; } | 649 void setRegNum(RegNumT NewRegNum) { |
540 void setRegNum(int32_t NewRegNum) { | |
541 // Regnum shouldn't be set more than once. | 650 // Regnum shouldn't be set more than once. |
542 assert(!hasReg() || RegNum == NewRegNum); | 651 assert(!hasReg() || RegNum == NewRegNum); |
543 RegNum = NewRegNum; | 652 RegNum = NewRegNum; |
544 } | 653 } |
545 bool hasRegTmp() const { return getRegNumTmp() != NoRegister; } | 654 bool hasRegTmp() const { return getRegNumTmp() != RegNumT::NoRegister; } |
546 int32_t getRegNumTmp() const { return RegNumTmp; } | 655 RegNumT getRegNumTmp() const { return RegNumTmp; } |
547 void setRegNumTmp(int32_t NewRegNum) { RegNumTmp = NewRegNum; } | 656 void setRegNumTmp(RegNumT NewRegNum) { RegNumTmp = NewRegNum; } |
548 | 657 |
549 RegWeight getWeight(const Cfg *Func) const; | 658 RegWeight getWeight(const Cfg *Func) const; |
550 | 659 |
551 void setMustHaveReg() { RegRequirement = RR_MustHaveRegister; } | 660 void setMustHaveReg() { RegRequirement = RR_MustHaveRegister; } |
552 bool mustHaveReg() const { return RegRequirement == RR_MustHaveRegister; } | 661 bool mustHaveReg() const { return RegRequirement == RR_MustHaveRegister; } |
553 void setMustNotHaveReg() { RegRequirement = RR_MustNotHaveRegister; } | 662 void setMustNotHaveReg() { RegRequirement = RR_MustNotHaveRegister; } |
554 bool mustNotHaveReg() const { | 663 bool mustNotHaveReg() const { |
555 return RegRequirement == RR_MustNotHaveRegister; | 664 return RegRequirement == RR_MustNotHaveRegister; |
556 } | 665 } |
557 void setRematerializable(int32_t NewRegNum, int32_t NewOffset) { | 666 void setRematerializable(RegNumT NewRegNum, int32_t NewOffset) { |
558 IsRematerializable = true; | 667 IsRematerializable = true; |
559 setRegNum(NewRegNum); | 668 setRegNum(NewRegNum); |
560 setStackOffset(NewOffset); | 669 setStackOffset(NewOffset); |
561 setMustHaveReg(); | 670 setMustHaveReg(); |
562 } | 671 } |
563 bool isRematerializable() const { return IsRematerializable; } | 672 bool isRematerializable() const { return IsRematerializable; } |
564 | 673 |
565 void setRegClass(uint8_t RC) { RegisterClass = static_cast<RegClass>(RC); } | 674 void setRegClass(uint8_t RC) { RegisterClass = static_cast<RegClass>(RC); } |
566 RegClass getRegClass() const { return RegisterClass; } | 675 RegClass getRegClass() const { return RegisterClass; } |
567 | 676 |
(...skipping 18 matching lines...) Expand all Loading... | |
586 constexpr bool UseTrimmed = true; | 695 constexpr bool UseTrimmed = true; |
587 return Live.overlapsInst(Other->Live.getStart(), UseTrimmed); | 696 return Live.overlapsInst(Other->Live.getStart(), UseTrimmed); |
588 } | 697 } |
589 | 698 |
590 /// Creates a temporary copy of the variable with a different type. Used | 699 /// Creates a temporary copy of the variable with a different type. Used |
591 /// primarily for syntactic correctness of textual assembly emission. Note | 700 /// primarily for syntactic correctness of textual assembly emission. Note |
592 /// that only basic information is copied, in particular not IsArgument, | 701 /// that only basic information is copied, in particular not IsArgument, |
593 /// IsImplicitArgument, IgnoreLiveness, RegNumTmp, Live, LoVar, HiVar, | 702 /// IsImplicitArgument, IgnoreLiveness, RegNumTmp, Live, LoVar, HiVar, |
594 /// VarsReal. If NewRegNum!=NoRegister, then that register assignment is made | 703 /// VarsReal. If NewRegNum!=NoRegister, then that register assignment is made |
595 /// instead of copying the existing assignment. | 704 /// instead of copying the existing assignment. |
596 const Variable *asType(Type Ty, int32_t NewRegNum) const; | 705 const Variable *asType(Type Ty, RegNumT NewRegNum) const; |
597 | 706 |
598 void emit(const Cfg *Func) const override; | 707 void emit(const Cfg *Func) const override; |
599 using Operand::dump; | 708 using Operand::dump; |
600 void dump(const Cfg *Func, Ostream &Str) const override; | 709 void dump(const Cfg *Func, Ostream &Str) const override; |
601 | 710 |
602 /// Return reg num of base register, if different from stack/frame register. | 711 /// Return reg num of base register, if different from stack/frame register. |
603 virtual int32_t getBaseRegNum() const { return NoRegister; } | 712 virtual RegNumT getBaseRegNum() const { return RegNumT::NoRegister; } |
604 | 713 |
605 static bool classof(const Operand *Operand) { | 714 static bool classof(const Operand *Operand) { |
606 OperandKind Kind = Operand->getKind(); | 715 OperandKind Kind = Operand->getKind(); |
607 return Kind >= kVariable && Kind <= kVariable_Max; | 716 return Kind >= kVariable && Kind <= kVariable_Max; |
608 } | 717 } |
609 | 718 |
610 protected: | 719 protected: |
611 Variable(OperandKind K, Type Ty, SizeT Index) | 720 Variable(OperandKind K, Type Ty, SizeT Index) |
612 : Operand(K, Ty), Number(Index), | 721 : Operand(K, Ty), Number(Index), |
613 RegisterClass(static_cast<RegClass>(Ty)) { | 722 RegisterClass(static_cast<RegClass>(Ty)) { |
(...skipping 11 matching lines...) Expand all Loading... | |
625 /// and validating live ranges. This is usually reserved for the stack | 734 /// and validating live ranges. This is usually reserved for the stack |
626 /// pointer and other physical registers specifically referenced by name. | 735 /// pointer and other physical registers specifically referenced by name. |
627 bool IgnoreLiveness = false; | 736 bool IgnoreLiveness = false; |
628 // If IsRematerializable, RegNum keeps track of which register (stack or frame | 737 // If IsRematerializable, RegNum keeps track of which register (stack or frame |
629 // pointer), and StackOffset is the known offset from that register. | 738 // pointer), and StackOffset is the known offset from that register. |
630 bool IsRematerializable = false; | 739 bool IsRematerializable = false; |
631 RegRequirement RegRequirement = RR_MayHaveRegister; | 740 RegRequirement RegRequirement = RR_MayHaveRegister; |
632 RegClass RegisterClass; | 741 RegClass RegisterClass; |
633 /// RegNum is the allocated register, or NoRegister if it isn't | 742 /// RegNum is the allocated register, or NoRegister if it isn't |
634 /// register-allocated. | 743 /// register-allocated. |
635 int32_t RegNum = NoRegister; | 744 RegNumT RegNum = RegNumT::NoRegister; |
636 /// RegNumTmp is the tentative assignment during register allocation. | 745 /// RegNumTmp is the tentative assignment during register allocation. |
637 int32_t RegNumTmp = NoRegister; | 746 RegNumT RegNumTmp = RegNumT::NoRegister; |
638 /// StackOffset is the canonical location on stack (only if | 747 /// StackOffset is the canonical location on stack (only if |
639 /// RegNum==NoRegister || IsArgument). | 748 /// RegNum==NoRegister || IsArgument). |
640 int32_t StackOffset = 0; | 749 int32_t StackOffset = 0; |
641 LiveRange Live; | 750 LiveRange Live; |
642 /// VarsReal (and Operand::Vars) are set up such that Vars[0] == this. | 751 /// VarsReal (and Operand::Vars) are set up such that Vars[0] == this. |
643 Variable *VarsReal[1]; | 752 Variable *VarsReal[1]; |
644 }; | 753 }; |
645 | 754 |
646 // Variable64On32 represents a 64-bit variable on a 32-bit architecture. In | 755 // 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. | 756 // 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: | 921 private: |
813 const Cfg *Func; | 922 const Cfg *Func; |
814 MetadataKind Kind; | 923 MetadataKind Kind; |
815 CfgVector<VariableTracking> Metadata; | 924 CfgVector<VariableTracking> Metadata; |
816 const static InstDefList NoDefinitions; | 925 const static InstDefList NoDefinitions; |
817 }; | 926 }; |
818 | 927 |
819 } // end of namespace Ice | 928 } // end of namespace Ice |
820 | 929 |
821 #endif // SUBZERO_SRC_ICEOPERAND_H | 930 #endif // SUBZERO_SRC_ICEOPERAND_H |
OLD | NEW |