Chromium Code Reviews| Index: src/IceOperand.h |
| diff --git a/src/IceOperand.h b/src/IceOperand.h |
| index 91e9de0f3be83633cf5638664f972907083f0576..2b0a9bc977642d52c8f61b29a5e4aa3b38e2f716 100644 |
| --- a/src/IceOperand.h |
| +++ b/src/IceOperand.h |
| @@ -402,6 +402,116 @@ private: |
| ConstantUndef(Type Ty) : Constant(kConstUndef, Ty) {} |
| }; |
| +/// RegNumT is for holding target-specific register numbers, plus the sentinel |
| +/// value NoRegister. Its public ctor allows direct use of enum values, such as |
| +/// RegNumT(Reg_eax), but not things like RegNumT(Reg_eax+1). This is to try to |
| +/// prevent inappropriate assumptions about enum ordering. If needed, the |
| +/// fromInt() method can be used, such as when a RegNumT is based on a bitvector |
| +/// index. |
| +class RegNumT { |
| +public: |
| + using BaseType = uint32_t; |
| + RegNumT() = default; |
| + RegNumT(const RegNumT &) = default; |
| + template <typename AnyEnum> |
| + RegNumT(AnyEnum Value, |
| + typename std::enable_if<std::is_enum<AnyEnum>::value, int>::type = 0) |
| + : Value(Value) { |
| + validate(Value); |
| + } |
| + RegNumT &operator=(const RegNumT &) = default; |
| + operator unsigned() const { return Value; } |
| + /// Asserts that the register is valid, i.e. not NoRegister. Note that the |
| + /// ctor already does the target-specific limit check. |
| + void assertIsValid() const { assert(Value != NoRegister); } |
| + static RegNumT fromInt(BaseType Value) { return RegNumT(Value); } |
| + /// Marks cases that inappropriately add/subtract RegNumT values, and |
| + /// therefore need to be fixed because they make assumptions about register |
| + /// enum value ordering. TODO(stichnot): Remove fixme() as soon as all |
| + /// current uses are fixed/removed. |
| + static RegNumT fixme(BaseType Value) { return RegNumT(Value); } |
| + /// The target's staticInit() method should call setLimit() to register the |
| + /// upper bound of allowable values. |
| + static void setLimit(BaseType Value) { |
| + // Make sure it's only called once. |
| + assert(Limit == 0); |
| + assert(Value != 0); |
| + Limit = Value; |
| + } |
| + // 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
|
| + // for the public ctor. |
| + enum { NoRegister = std::numeric_limits<BaseType>::max() }; |
| + |
| +private: |
| + BaseType Value = NoRegister; |
| + static BaseType Limit; |
| + /// Private ctor called only by fromInt() and fixme(). |
| + RegNumT(BaseType Value) : Value(Value) { validate(Value); } |
| + /// The ctor calls this to validate against the target-supplied limit. |
| + static void validate(BaseType Value) { |
| + (void)Value; |
| + assert(Value == NoRegister || Value < Limit); |
| + } |
| + /// Disallow operators that inappropriately make assumptions about register |
| + /// enum value ordering. |
| + bool operator<(const RegNumT &) = delete; |
| + bool operator<=(const RegNumT &) = delete; |
| + bool operator>(const RegNumT &) = delete; |
| + bool operator>=(const RegNumT &) = delete; |
| +}; |
| + |
| +/// RegNumBitVector wraps llvm::SmallBitVector so that instead of this pattern: |
| +/// |
| +/// for (int i = V.find_first(); i != -1; i = V.find_next(i)) { |
| +/// RegNumT RegNum = RegNumT::fromInt(i); |
| +/// ... |
| +/// } |
| +/// |
| +/// this cleaner pattern can be used: |
| +/// |
| +/// for (RegNumT RegNum : RegNumBitVector(V)) { |
| +/// ... |
| +/// } |
| +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
|
| + using T = llvm::SmallBitVector; |
| + static constexpr int Sentinel = -1; |
| + RegNumBitVector() = delete; |
| + RegNumBitVector(const RegNumBitVector &) = delete; |
| + RegNumBitVector &operator=(const RegNumBitVector &) = delete; |
| + |
| +public: |
| + class Iterator { |
| + Iterator() = delete; |
| + Iterator &operator=(const Iterator &) = delete; |
| + |
| + public: |
| + explicit Iterator(const T &V) : V(V), Current(V.find_first()) {} |
| + Iterator(const T &V, int Value) : V(V), Current(Value) {} |
| + Iterator(const Iterator &) = default; |
| + RegNumT operator*() { |
| + assert(Current != Sentinel); |
| + return RegNumT::fromInt(Current); |
| + } |
| + Iterator &operator++() { |
| + assert(Current != Sentinel); |
| + Current = V.find_next(Current); |
| + return *this; |
| + } |
| + bool operator!=(Iterator &Other) { return Current != Other.Current; } |
| + |
| + private: |
| + const T &V; |
| + int Current; |
| + }; |
| + |
| + explicit RegNumBitVector(const T &V) : V(V) {} |
| + Iterator begin() { return Iterator(V); } |
| + Iterator end() { return Iterator(V, Sentinel); } |
| + |
| +private: |
| + const T &V; |
| +}; |
| + |
| /// RegWeight is a wrapper for a uint32_t weight value, with a special value |
| /// that represents infinite weight, and an addWeight() method that ensures that |
| /// W+infinity=infinity. |
| @@ -534,17 +644,16 @@ public: |
| return "lv$" + getName(Func); |
| } |
| - static constexpr int32_t NoRegister = -1; |
| - bool hasReg() const { return getRegNum() != NoRegister; } |
| - int32_t getRegNum() const { return RegNum; } |
| - void setRegNum(int32_t NewRegNum) { |
| + bool hasReg() const { return getRegNum() != RegNumT::NoRegister; } |
| + RegNumT getRegNum() const { return RegNum; } |
| + void setRegNum(RegNumT NewRegNum) { |
| // Regnum shouldn't be set more than once. |
| assert(!hasReg() || RegNum == NewRegNum); |
| RegNum = NewRegNum; |
| } |
| - bool hasRegTmp() const { return getRegNumTmp() != NoRegister; } |
| - int32_t getRegNumTmp() const { return RegNumTmp; } |
| - void setRegNumTmp(int32_t NewRegNum) { RegNumTmp = NewRegNum; } |
| + bool hasRegTmp() const { return getRegNumTmp() != RegNumT::NoRegister; } |
| + RegNumT getRegNumTmp() const { return RegNumTmp; } |
| + void setRegNumTmp(RegNumT NewRegNum) { RegNumTmp = NewRegNum; } |
| RegWeight getWeight(const Cfg *Func) const; |
| @@ -554,7 +663,7 @@ public: |
| bool mustNotHaveReg() const { |
| return RegRequirement == RR_MustNotHaveRegister; |
| } |
| - void setRematerializable(int32_t NewRegNum, int32_t NewOffset) { |
| + void setRematerializable(RegNumT NewRegNum, int32_t NewOffset) { |
| IsRematerializable = true; |
| setRegNum(NewRegNum); |
| setStackOffset(NewOffset); |
| @@ -593,14 +702,14 @@ public: |
| /// IsImplicitArgument, IgnoreLiveness, RegNumTmp, Live, LoVar, HiVar, |
| /// VarsReal. If NewRegNum!=NoRegister, then that register assignment is made |
| /// instead of copying the existing assignment. |
| - const Variable *asType(Type Ty, int32_t NewRegNum) const; |
| + const Variable *asType(Type Ty, RegNumT NewRegNum) const; |
| void emit(const Cfg *Func) const override; |
| using Operand::dump; |
| void dump(const Cfg *Func, Ostream &Str) const override; |
| /// Return reg num of base register, if different from stack/frame register. |
| - virtual int32_t getBaseRegNum() const { return NoRegister; } |
| + virtual RegNumT getBaseRegNum() const { return RegNumT::NoRegister; } |
| static bool classof(const Operand *Operand) { |
| OperandKind Kind = Operand->getKind(); |
| @@ -632,9 +741,9 @@ protected: |
| RegClass RegisterClass; |
| /// RegNum is the allocated register, or NoRegister if it isn't |
| /// register-allocated. |
| - int32_t RegNum = NoRegister; |
| + RegNumT RegNum = RegNumT::NoRegister; |
| /// RegNumTmp is the tentative assignment during register allocation. |
| - int32_t RegNumTmp = NoRegister; |
| + RegNumT RegNumTmp = RegNumT::NoRegister; |
| /// StackOffset is the canonical location on stack (only if |
| /// RegNum==NoRegister || IsArgument). |
| int32_t StackOffset = 0; |