| 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 27 matching lines...) Expand all Loading... |
| 38 kConstInteger64, | 38 kConstInteger64, |
| 39 kConstFloat, | 39 kConstFloat, |
| 40 kConstDouble, | 40 kConstDouble, |
| 41 kConstRelocatable, | 41 kConstRelocatable, |
| 42 kConstUndef, | 42 kConstUndef, |
| 43 kConst_Target, // leave space for target-specific constant kinds | 43 kConst_Target, // leave space for target-specific constant kinds |
| 44 kConst_Max = kConst_Target + MaxTargetKinds, | 44 kConst_Max = kConst_Target + MaxTargetKinds, |
| 45 kVariable, | 45 kVariable, |
| 46 kVariable_Target, // leave space for target-specific variable kinds | 46 kVariable_Target, // leave space for target-specific variable kinds |
| 47 kVariable_Max = kVariable_Target + MaxTargetKinds, | 47 kVariable_Max = kVariable_Target + MaxTargetKinds, |
| 48 // Target-specific operand classes use kTarget as the starting | 48 // Target-specific operand classes use kTarget as the starting point for |
| 49 // point for their Kind enum space. Note that the value-spaces are shared | 49 // their Kind enum space. Note that the value-spaces are shared across |
| 50 // across targets. To avoid confusion over the definition of shared | 50 // targets. To avoid confusion over the definition of shared values, an |
| 51 // values, an object specific to one target should never be passed | 51 // object specific to one target should never be passed to a different |
| 52 // to a different target. | 52 // target. |
| 53 kTarget, | 53 kTarget, |
| 54 kTarget_Max = std::numeric_limits<uint8_t>::max(), | 54 kTarget_Max = std::numeric_limits<uint8_t>::max(), |
| 55 }; | 55 }; |
| 56 static_assert(kTarget <= kTarget_Max, "Must not be above max."); | 56 static_assert(kTarget <= kTarget_Max, "Must not be above max."); |
| 57 OperandKind getKind() const { return Kind; } | 57 OperandKind getKind() const { return Kind; } |
| 58 Type getType() const { return Ty; } | 58 Type getType() const { return Ty; } |
| 59 | 59 |
| 60 /// Every Operand keeps an array of the Variables referenced in the operand. | 60 /// Every Operand keeps an array of the Variables referenced in the operand. |
| 61 /// This is so that the liveness operations can get quick access to the | 61 /// This is so that the liveness operations can get quick access to the |
| 62 /// variables of interest, without having to dig so far into the operand. | 62 /// variables of interest, without having to dig so far into the operand. |
| 63 SizeT getNumVars() const { return NumVars; } | 63 SizeT getNumVars() const { return NumVars; } |
| 64 Variable *getVar(SizeT I) const { | 64 Variable *getVar(SizeT I) const { |
| 65 assert(I < getNumVars()); | 65 assert(I < getNumVars()); |
| 66 return Vars[I]; | 66 return Vars[I]; |
| 67 } | 67 } |
| 68 virtual void emit(const Cfg *Func) const = 0; | 68 virtual void emit(const Cfg *Func) const = 0; |
| 69 | 69 |
| 70 /// \name Dumping functions. | 70 /// \name Dumping functions. |
| 71 /// @{ | 71 /// @{ |
| 72 | 72 |
| 73 /// The dump(Func,Str) implementation must be sure to handle the | 73 /// The dump(Func,Str) implementation must be sure to handle the situation |
| 74 /// situation where Func==nullptr. | 74 /// where Func==nullptr. |
| 75 virtual void dump(const Cfg *Func, Ostream &Str) const = 0; | 75 virtual void dump(const Cfg *Func, Ostream &Str) const = 0; |
| 76 void dump(const Cfg *Func) const { | 76 void dump(const Cfg *Func) const { |
| 77 if (!BuildDefs::dump()) | 77 if (!BuildDefs::dump()) |
| 78 return; | 78 return; |
| 79 assert(Func); | 79 assert(Func); |
| 80 dump(Func, Func->getContext()->getStrDump()); | 80 dump(Func, Func->getContext()->getStrDump()); |
| 81 } | 81 } |
| 82 void dump(Ostream &Str) const { | 82 void dump(Ostream &Str) const { |
| 83 if (BuildDefs::dump()) | 83 if (BuildDefs::dump()) |
| 84 dump(nullptr, Str); | 84 dump(nullptr, Str); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 98 SizeT NumVars = 0; | 98 SizeT NumVars = 0; |
| 99 Variable **Vars = nullptr; | 99 Variable **Vars = nullptr; |
| 100 }; | 100 }; |
| 101 | 101 |
| 102 template <class StreamType> | 102 template <class StreamType> |
| 103 inline StreamType &operator<<(StreamType &Str, const Operand &Op) { | 103 inline StreamType &operator<<(StreamType &Str, const Operand &Op) { |
| 104 Op.dump(Str); | 104 Op.dump(Str); |
| 105 return Str; | 105 return Str; |
| 106 } | 106 } |
| 107 | 107 |
| 108 /// Constant is the abstract base class for constants. All | 108 /// Constant is the abstract base class for constants. All constants are |
| 109 /// constants are allocated from a global arena and are pooled. | 109 /// allocated from a global arena and are pooled. |
| 110 class Constant : public Operand { | 110 class Constant : public Operand { |
| 111 Constant() = delete; | 111 Constant() = delete; |
| 112 Constant(const Constant &) = delete; | 112 Constant(const Constant &) = delete; |
| 113 Constant &operator=(const Constant &) = delete; | 113 Constant &operator=(const Constant &) = delete; |
| 114 | 114 |
| 115 public: | 115 public: |
| 116 void emitPoolLabel(Ostream &Str) const { | 116 void emitPoolLabel(Ostream &Str) const { |
| 117 Str << ".L$" << getType() << "$" << PoolEntryID; | 117 Str << ".L$" << getType() << "$" << PoolEntryID; |
| 118 } | 118 } |
| 119 void emit(const Cfg *Func) const override { emit(Func->getTarget()); } | 119 void emit(const Cfg *Func) const override { emit(Func->getTarget()); } |
| 120 virtual void emit(TargetLowering *Target) const = 0; | 120 virtual void emit(TargetLowering *Target) const = 0; |
| 121 | 121 |
| 122 static bool classof(const Operand *Operand) { | 122 static bool classof(const Operand *Operand) { |
| 123 OperandKind Kind = Operand->getKind(); | 123 OperandKind Kind = Operand->getKind(); |
| 124 return Kind >= kConst_Base && Kind <= kConst_Max; | 124 return Kind >= kConst_Base && Kind <= kConst_Max; |
| 125 } | 125 } |
| 126 | 126 |
| 127 /// Judge if this given immediate should be randomized or pooled | 127 /// Judge if this given immediate should be randomized or pooled By default |
| 128 /// By default should return false, only constant integers should | 128 /// should return false, only constant integers should truly go through this |
| 129 /// truly go through this method. | 129 /// method. |
| 130 virtual bool shouldBeRandomizedOrPooled(const GlobalContext *Ctx) { | 130 virtual bool shouldBeRandomizedOrPooled(const GlobalContext *Ctx) { |
| 131 (void)Ctx; | 131 (void)Ctx; |
| 132 return false; | 132 return false; |
| 133 } | 133 } |
| 134 | 134 |
| 135 void setShouldBePooled(bool R) { shouldBePooled = R; } | 135 void setShouldBePooled(bool R) { shouldBePooled = R; } |
| 136 | 136 |
| 137 bool getShouldBePooled() const { return shouldBePooled; } | 137 bool getShouldBePooled() const { return shouldBePooled; } |
| 138 | 138 |
| 139 protected: | 139 protected: |
| 140 Constant(OperandKind Kind, Type Ty, uint32_t PoolEntryID) | 140 Constant(OperandKind Kind, Type Ty, uint32_t PoolEntryID) |
| 141 : Operand(Kind, Ty), PoolEntryID(PoolEntryID), shouldBePooled(false) { | 141 : Operand(Kind, Ty), PoolEntryID(PoolEntryID), shouldBePooled(false) { |
| 142 Vars = nullptr; | 142 Vars = nullptr; |
| 143 NumVars = 0; | 143 NumVars = 0; |
| 144 } | 144 } |
| 145 /// PoolEntryID is an integer that uniquely identifies the constant | 145 /// PoolEntryID is an integer that uniquely identifies the constant within its |
| 146 /// within its constant pool. It is used for building the constant | 146 /// constant pool. It is used for building the constant pool in the object |
| 147 /// pool in the object code and for referencing its entries. | 147 /// code and for referencing its entries. |
| 148 const uint32_t PoolEntryID; | 148 const uint32_t PoolEntryID; |
| 149 /// Whether we should pool this constant. Usually Float/Double and pooled | 149 /// Whether we should pool this constant. Usually Float/Double and pooled |
| 150 /// Integers should be flagged true. | 150 /// Integers should be flagged true. |
| 151 bool shouldBePooled; | 151 bool shouldBePooled; |
| 152 }; | 152 }; |
| 153 | 153 |
| 154 /// ConstantPrimitive<> wraps a primitive type. | 154 /// ConstantPrimitive<> wraps a primitive type. |
| 155 template <typename T, Operand::OperandKind K> | 155 template <typename T, Operand::OperandKind K> |
| 156 class ConstantPrimitive : public Constant { | 156 class ConstantPrimitive : public Constant { |
| 157 ConstantPrimitive() = delete; | 157 ConstantPrimitive() = delete; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 212 bool ConstantInteger32::shouldBeRandomizedOrPooled(const GlobalContext *Ctx); | 212 bool ConstantInteger32::shouldBeRandomizedOrPooled(const GlobalContext *Ctx); |
| 213 | 213 |
| 214 template <> | 214 template <> |
| 215 inline void ConstantInteger64::dump(const Cfg *, Ostream &Str) const { | 215 inline void ConstantInteger64::dump(const Cfg *, Ostream &Str) const { |
| 216 if (!BuildDefs::dump()) | 216 if (!BuildDefs::dump()) |
| 217 return; | 217 return; |
| 218 assert(getType() == IceType_i64); | 218 assert(getType() == IceType_i64); |
| 219 Str << static_cast<int64_t>(getValue()); | 219 Str << static_cast<int64_t>(getValue()); |
| 220 } | 220 } |
| 221 | 221 |
| 222 /// RelocatableTuple bundles the parameters that are used to | 222 /// RelocatableTuple bundles the parameters that are used to construct an |
| 223 /// construct an ConstantRelocatable. It is done this way so that | 223 /// ConstantRelocatable. It is done this way so that ConstantRelocatable can fit |
| 224 /// ConstantRelocatable can fit into the global constant pool | 224 /// into the global constant pool template mechanism. |
| 225 /// template mechanism. | |
| 226 class RelocatableTuple { | 225 class RelocatableTuple { |
| 227 RelocatableTuple() = delete; | 226 RelocatableTuple() = delete; |
| 228 RelocatableTuple &operator=(const RelocatableTuple &) = delete; | 227 RelocatableTuple &operator=(const RelocatableTuple &) = delete; |
| 229 | 228 |
| 230 public: | 229 public: |
| 231 RelocatableTuple(const RelocOffsetT Offset, const IceString &Name, | 230 RelocatableTuple(const RelocOffsetT Offset, const IceString &Name, |
| 232 bool SuppressMangling) | 231 bool SuppressMangling) |
| 233 : Offset(Offset), Name(Name), SuppressMangling(SuppressMangling) {} | 232 : Offset(Offset), Name(Name), SuppressMangling(SuppressMangling) {} |
| 234 RelocatableTuple(const RelocatableTuple &) = default; | 233 RelocatableTuple(const RelocatableTuple &) = default; |
| 235 | 234 |
| 236 const RelocOffsetT Offset; | 235 const RelocOffsetT Offset; |
| 237 const IceString Name; | 236 const IceString Name; |
| 238 bool SuppressMangling; | 237 bool SuppressMangling; |
| 239 }; | 238 }; |
| 240 | 239 |
| 241 bool operator==(const RelocatableTuple &A, const RelocatableTuple &B); | 240 bool operator==(const RelocatableTuple &A, const RelocatableTuple &B); |
| 242 | 241 |
| 243 /// ConstantRelocatable represents a symbolic constant combined with | 242 /// ConstantRelocatable represents a symbolic constant combined with a fixed |
| 244 /// a fixed offset. | 243 /// offset. |
| 245 class ConstantRelocatable : public Constant { | 244 class ConstantRelocatable : public Constant { |
| 246 ConstantRelocatable() = delete; | 245 ConstantRelocatable() = delete; |
| 247 ConstantRelocatable(const ConstantRelocatable &) = delete; | 246 ConstantRelocatable(const ConstantRelocatable &) = delete; |
| 248 ConstantRelocatable &operator=(const ConstantRelocatable &) = delete; | 247 ConstantRelocatable &operator=(const ConstantRelocatable &) = delete; |
| 249 | 248 |
| 250 public: | 249 public: |
| 251 static ConstantRelocatable *create(GlobalContext *Ctx, Type Ty, | 250 static ConstantRelocatable *create(GlobalContext *Ctx, Type Ty, |
| 252 const RelocatableTuple &Tuple, | 251 const RelocatableTuple &Tuple, |
| 253 uint32_t PoolEntryID) { | 252 uint32_t PoolEntryID) { |
| 254 assert(!Ctx->isIRGenerationDisabled() && | 253 assert(!Ctx->isIRGenerationDisabled() && |
| (...skipping 20 matching lines...) Expand all Loading... |
| 275 private: | 274 private: |
| 276 ConstantRelocatable(Type Ty, RelocOffsetT Offset, const IceString &Name, | 275 ConstantRelocatable(Type Ty, RelocOffsetT Offset, const IceString &Name, |
| 277 bool SuppressMangling, uint32_t PoolEntryID) | 276 bool SuppressMangling, uint32_t PoolEntryID) |
| 278 : Constant(kConstRelocatable, Ty, PoolEntryID), Offset(Offset), | 277 : Constant(kConstRelocatable, Ty, PoolEntryID), Offset(Offset), |
| 279 Name(Name), SuppressMangling(SuppressMangling) {} | 278 Name(Name), SuppressMangling(SuppressMangling) {} |
| 280 const RelocOffsetT Offset; /// fixed offset to add | 279 const RelocOffsetT Offset; /// fixed offset to add |
| 281 const IceString Name; /// optional for debug/dump | 280 const IceString Name; /// optional for debug/dump |
| 282 bool SuppressMangling; | 281 bool SuppressMangling; |
| 283 }; | 282 }; |
| 284 | 283 |
| 285 /// ConstantUndef represents an unspecified bit pattern. Although it is | 284 /// ConstantUndef represents an unspecified bit pattern. Although it is legal to |
| 286 /// legal to lower ConstantUndef to any value, backends should try to | 285 /// lower ConstantUndef to any value, backends should try to make code |
| 287 /// make code generation deterministic by lowering ConstantUndefs to 0. | 286 /// generation deterministic by lowering ConstantUndefs to 0. |
| 288 class ConstantUndef : public Constant { | 287 class ConstantUndef : public Constant { |
| 289 ConstantUndef() = delete; | 288 ConstantUndef() = delete; |
| 290 ConstantUndef(const ConstantUndef &) = delete; | 289 ConstantUndef(const ConstantUndef &) = delete; |
| 291 ConstantUndef &operator=(const ConstantUndef &) = delete; | 290 ConstantUndef &operator=(const ConstantUndef &) = delete; |
| 292 | 291 |
| 293 public: | 292 public: |
| 294 static ConstantUndef *create(GlobalContext *Ctx, Type Ty, | 293 static ConstantUndef *create(GlobalContext *Ctx, Type Ty, |
| 295 uint32_t PoolEntryID) { | 294 uint32_t PoolEntryID) { |
| 296 assert(!Ctx->isIRGenerationDisabled() && | 295 assert(!Ctx->isIRGenerationDisabled() && |
| 297 "Attempt to build undefined constant when IR generation disabled"); | 296 "Attempt to build undefined constant when IR generation disabled"); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 308 | 307 |
| 309 static bool classof(const Operand *Operand) { | 308 static bool classof(const Operand *Operand) { |
| 310 return Operand->getKind() == kConstUndef; | 309 return Operand->getKind() == kConstUndef; |
| 311 } | 310 } |
| 312 | 311 |
| 313 private: | 312 private: |
| 314 ConstantUndef(Type Ty, uint32_t PoolEntryID) | 313 ConstantUndef(Type Ty, uint32_t PoolEntryID) |
| 315 : Constant(kConstUndef, Ty, PoolEntryID) {} | 314 : Constant(kConstUndef, Ty, PoolEntryID) {} |
| 316 }; | 315 }; |
| 317 | 316 |
| 318 /// RegWeight is a wrapper for a uint32_t weight value, with a | 317 /// RegWeight is a wrapper for a uint32_t weight value, with a special value |
| 319 /// special value that represents infinite weight, and an addWeight() | 318 /// that represents infinite weight, and an addWeight() method that ensures that |
| 320 /// method that ensures that W+infinity=infinity. | 319 /// W+infinity=infinity. |
| 321 class RegWeight { | 320 class RegWeight { |
| 322 public: | 321 public: |
| 323 RegWeight() = default; | 322 RegWeight() = default; |
| 324 explicit RegWeight(uint32_t Weight) : Weight(Weight) {} | 323 explicit RegWeight(uint32_t Weight) : Weight(Weight) {} |
| 325 RegWeight(const RegWeight &) = default; | 324 RegWeight(const RegWeight &) = default; |
| 326 RegWeight &operator=(const RegWeight &) = default; | 325 RegWeight &operator=(const RegWeight &) = default; |
| 327 const static uint32_t Inf = ~0; /// Force regalloc to give a register | 326 const static uint32_t Inf = ~0; /// Force regalloc to give a register |
| 328 const static uint32_t Zero = 0; /// Force regalloc NOT to give a register | 327 const static uint32_t Zero = 0; /// Force regalloc NOT to give a register |
| 329 const static uint32_t Max = Inf - 1; /// Max natural weight. | 328 const static uint32_t Max = Inf - 1; /// Max natural weight. |
| 330 void addWeight(uint32_t Delta) { | 329 void addWeight(uint32_t Delta) { |
| 331 if (Delta == Inf) | 330 if (Delta == Inf) |
| 332 Weight = Inf; | 331 Weight = Inf; |
| 333 else if (Weight != Inf) | 332 else if (Weight != Inf) |
| 334 if (Utils::add_overflow(Weight, Delta, &Weight) || Weight == Inf) | 333 if (Utils::add_overflow(Weight, Delta, &Weight) || Weight == Inf) |
| 335 Weight = Max; | 334 Weight = Max; |
| 336 } | 335 } |
| 337 void addWeight(const RegWeight &Other) { addWeight(Other.Weight); } | 336 void addWeight(const RegWeight &Other) { addWeight(Other.Weight); } |
| 338 void setWeight(uint32_t Val) { Weight = Val; } | 337 void setWeight(uint32_t Val) { Weight = Val; } |
| 339 uint32_t getWeight() const { return Weight; } | 338 uint32_t getWeight() const { return Weight; } |
| 340 | 339 |
| 341 private: | 340 private: |
| 342 uint32_t Weight = 0; | 341 uint32_t Weight = 0; |
| 343 }; | 342 }; |
| 344 Ostream &operator<<(Ostream &Str, const RegWeight &W); | 343 Ostream &operator<<(Ostream &Str, const RegWeight &W); |
| 345 bool operator<(const RegWeight &A, const RegWeight &B); | 344 bool operator<(const RegWeight &A, const RegWeight &B); |
| 346 bool operator<=(const RegWeight &A, const RegWeight &B); | 345 bool operator<=(const RegWeight &A, const RegWeight &B); |
| 347 bool operator==(const RegWeight &A, const RegWeight &B); | 346 bool operator==(const RegWeight &A, const RegWeight &B); |
| 348 | 347 |
| 349 /// LiveRange is a set of instruction number intervals representing | 348 /// LiveRange is a set of instruction number intervals representing a variable's |
| 350 /// a variable's live range. Generally there is one interval per basic | 349 /// live range. Generally there is one interval per basic block where the |
| 351 /// block where the variable is live, but adjacent intervals get | 350 /// variable is live, but adjacent intervals get coalesced into a single |
| 352 /// coalesced into a single interval. | 351 /// interval. |
| 353 class LiveRange { | 352 class LiveRange { |
| 354 public: | 353 public: |
| 355 LiveRange() = default; | 354 LiveRange() = default; |
| 356 /// Special constructor for building a kill set. The advantage is | 355 /// Special constructor for building a kill set. The advantage is that we can |
| 357 /// that we can reserve the right amount of space in advance. | 356 /// reserve the right amount of space in advance. |
| 358 explicit LiveRange(const std::vector<InstNumberT> &Kills) { | 357 explicit LiveRange(const std::vector<InstNumberT> &Kills) { |
| 359 Range.reserve(Kills.size()); | 358 Range.reserve(Kills.size()); |
| 360 for (InstNumberT I : Kills) | 359 for (InstNumberT I : Kills) |
| 361 addSegment(I, I); | 360 addSegment(I, I); |
| 362 } | 361 } |
| 363 LiveRange(const LiveRange &) = default; | 362 LiveRange(const LiveRange &) = default; |
| 364 LiveRange &operator=(const LiveRange &) = default; | 363 LiveRange &operator=(const LiveRange &) = default; |
| 365 | 364 |
| 366 void reset() { | 365 void reset() { |
| 367 Range.clear(); | 366 Range.clear(); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 385 void trim(InstNumberT Lower); | 384 void trim(InstNumberT Lower); |
| 386 | 385 |
| 387 void dump(Ostream &Str) const; | 386 void dump(Ostream &Str) const; |
| 388 | 387 |
| 389 private: | 388 private: |
| 390 using RangeElementType = std::pair<InstNumberT, InstNumberT>; | 389 using RangeElementType = std::pair<InstNumberT, InstNumberT>; |
| 391 /// RangeType is arena-allocated from the Cfg's allocator. | 390 /// RangeType is arena-allocated from the Cfg's allocator. |
| 392 using RangeType = | 391 using RangeType = |
| 393 std::vector<RangeElementType, CfgLocalAllocator<RangeElementType>>; | 392 std::vector<RangeElementType, CfgLocalAllocator<RangeElementType>>; |
| 394 RangeType Range; | 393 RangeType Range; |
| 395 /// TrimmedBegin is an optimization for the overlaps() computation. | 394 /// TrimmedBegin is an optimization for the overlaps() computation. Since the |
| 396 /// Since the linear-scan algorithm always calls it as overlaps(Cur) | 395 /// linear-scan algorithm always calls it as overlaps(Cur) and Cur advances |
| 397 /// and Cur advances monotonically according to live range start, we | 396 /// monotonically according to live range start, we can optimize overlaps() by |
| 398 /// can optimize overlaps() by ignoring all segments that end before | 397 /// ignoring all segments that end before the start of Cur's range. The |
| 399 /// the start of Cur's range. The linear-scan code enables this by | 398 /// linear-scan code enables this by calling trim() on the ranges of interest |
| 400 /// calling trim() on the ranges of interest as Cur advances. Note | 399 /// as Cur advances. Note that linear-scan also has to initialize TrimmedBegin |
| 401 /// that linear-scan also has to initialize TrimmedBegin at the | 400 /// at the beginning by calling untrim(). |
| 402 /// beginning by calling untrim(). | |
| 403 RangeType::const_iterator TrimmedBegin; | 401 RangeType::const_iterator TrimmedBegin; |
| 404 }; | 402 }; |
| 405 | 403 |
| 406 Ostream &operator<<(Ostream &Str, const LiveRange &L); | 404 Ostream &operator<<(Ostream &Str, const LiveRange &L); |
| 407 | 405 |
| 408 /// Variable represents an operand that is register-allocated or | 406 /// Variable represents an operand that is register-allocated or |
| 409 /// stack-allocated. If it is register-allocated, it will ultimately | 407 /// stack-allocated. If it is register-allocated, it will ultimately have a |
| 410 /// have a non-negative RegNum field. | 408 /// non-negative RegNum field. |
| 411 class Variable : public Operand { | 409 class Variable : public Operand { |
| 412 Variable() = delete; | 410 Variable() = delete; |
| 413 Variable(const Variable &) = delete; | 411 Variable(const Variable &) = delete; |
| 414 Variable &operator=(const Variable &) = delete; | 412 Variable &operator=(const Variable &) = delete; |
| 415 | 413 |
| 416 enum RegRequirement { | 414 enum RegRequirement { |
| 417 RR_MayHaveRegister, | 415 RR_MayHaveRegister, |
| 418 RR_MustHaveRegister, | 416 RR_MustHaveRegister, |
| 419 RR_MustNotHaveRegister, | 417 RR_MustNotHaveRegister, |
| 420 }; | 418 }; |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 488 } | 486 } |
| 489 | 487 |
| 490 Variable *getLo() const { return LoVar; } | 488 Variable *getLo() const { return LoVar; } |
| 491 Variable *getHi() const { return HiVar; } | 489 Variable *getHi() const { return HiVar; } |
| 492 void setLoHi(Variable *Lo, Variable *Hi) { | 490 void setLoHi(Variable *Lo, Variable *Hi) { |
| 493 assert(LoVar == nullptr); | 491 assert(LoVar == nullptr); |
| 494 assert(HiVar == nullptr); | 492 assert(HiVar == nullptr); |
| 495 LoVar = Lo; | 493 LoVar = Lo; |
| 496 HiVar = Hi; | 494 HiVar = Hi; |
| 497 } | 495 } |
| 498 /// Creates a temporary copy of the variable with a different type. | 496 /// Creates a temporary copy of the variable with a different type. Used |
| 499 /// Used primarily for syntactic correctness of textual assembly | 497 /// primarily for syntactic correctness of textual assembly emission. Note |
| 500 /// emission. Note that only basic information is copied, in | 498 /// that only basic information is copied, in particular not IsArgument, |
| 501 /// particular not IsArgument, IsImplicitArgument, IgnoreLiveness, | 499 /// IsImplicitArgument, IgnoreLiveness, RegNumTmp, Live, LoVar, HiVar, |
| 502 /// RegNumTmp, Live, LoVar, HiVar, VarsReal. | 500 /// VarsReal. |
| 503 Variable *asType(Type Ty); | 501 Variable *asType(Type Ty); |
| 504 | 502 |
| 505 void emit(const Cfg *Func) const override; | 503 void emit(const Cfg *Func) const override; |
| 506 using Operand::dump; | 504 using Operand::dump; |
| 507 void dump(const Cfg *Func, Ostream &Str) const override; | 505 void dump(const Cfg *Func, Ostream &Str) const override; |
| 508 | 506 |
| 509 /// Return reg num of base register, if different from stack/frame register. | 507 /// Return reg num of base register, if different from stack/frame register. |
| 510 virtual int32_t getBaseRegNum() const { return NoRegister; } | 508 virtual int32_t getBaseRegNum() const { return NoRegister; } |
| 511 | 509 |
| 512 static bool classof(const Operand *Operand) { | 510 static bool classof(const Operand *Operand) { |
| 513 OperandKind Kind = Operand->getKind(); | 511 OperandKind Kind = Operand->getKind(); |
| 514 return Kind >= kVariable && Kind <= kVariable_Max; | 512 return Kind >= kVariable && Kind <= kVariable_Max; |
| 515 } | 513 } |
| 516 | 514 |
| 517 protected: | 515 protected: |
| 518 Variable(OperandKind K, Type Ty, SizeT Index) | 516 Variable(OperandKind K, Type Ty, SizeT Index) |
| 519 : Operand(K, Ty), Number(Index) { | 517 : Operand(K, Ty), Number(Index) { |
| 520 Vars = VarsReal; | 518 Vars = VarsReal; |
| 521 Vars[0] = this; | 519 Vars[0] = this; |
| 522 NumVars = 1; | 520 NumVars = 1; |
| 523 } | 521 } |
| 524 /// Number is unique across all variables, and is used as a | 522 /// Number is unique across all variables, and is used as a (bit)vector index |
| 525 /// (bit)vector index for liveness analysis. | 523 /// for liveness analysis. |
| 526 const SizeT Number; | 524 const SizeT Number; |
| 527 Cfg::IdentifierIndexType NameIndex = Cfg::IdentifierIndexInvalid; | 525 Cfg::IdentifierIndexType NameIndex = Cfg::IdentifierIndexInvalid; |
| 528 bool IsArgument = false; | 526 bool IsArgument = false; |
| 529 bool IsImplicitArgument = false; | 527 bool IsImplicitArgument = false; |
| 530 /// IgnoreLiveness means that the variable should be ignored when | 528 /// IgnoreLiveness means that the variable should be ignored when constructing |
| 531 /// constructing and validating live ranges. This is usually | 529 /// and validating live ranges. This is usually reserved for the stack |
| 532 /// reserved for the stack pointer. | 530 /// pointer. |
| 533 bool IgnoreLiveness = false; | 531 bool IgnoreLiveness = false; |
| 534 /// StackOffset is the canonical location on stack (only if | 532 /// StackOffset is the canonical location on stack (only if RegNum==NoRegister |
| 535 /// RegNum==NoRegister || IsArgument). | 533 /// || IsArgument). |
| 536 int32_t StackOffset = 0; | 534 int32_t StackOffset = 0; |
| 537 /// RegNum is the allocated register, or NoRegister if it isn't | 535 /// RegNum is the allocated register, or NoRegister if it isn't |
| 538 /// register-allocated. | 536 /// register-allocated. |
| 539 int32_t RegNum = NoRegister; | 537 int32_t RegNum = NoRegister; |
| 540 /// RegNumTmp is the tentative assignment during register allocation. | 538 /// RegNumTmp is the tentative assignment during register allocation. |
| 541 int32_t RegNumTmp = NoRegister; | 539 int32_t RegNumTmp = NoRegister; |
| 542 RegRequirement RegRequirement = RR_MayHaveRegister; | 540 RegRequirement RegRequirement = RR_MayHaveRegister; |
| 543 LiveRange Live; | 541 LiveRange Live; |
| 544 // LoVar and HiVar are needed for lowering from 64 to 32 bits. When | 542 // LoVar and HiVar are needed for lowering from 64 to 32 bits. When lowering |
| 545 // lowering from I64 to I32 on a 32-bit architecture, we split the | 543 // from I64 to I32 on a 32-bit architecture, we split the variable into two |
| 546 // variable into two machine-size pieces. LoVar is the low-order | 544 // machine-size pieces. LoVar is the low-order machine-size portion, and |
| 547 // machine-size portion, and HiVar is the remaining high-order | 545 // HiVar is the remaining high-order portion. |
| 548 // portion. TODO: It's wasteful to penalize all variables on all | 546 // TODO: It's wasteful to penalize all variables on all targets this way; use |
| 549 // targets this way; use a sparser representation. It's also | 547 // a sparser representation. It's also wasteful for a 64-bit target. |
| 550 // wasteful for a 64-bit target. | |
| 551 Variable *LoVar = nullptr; | 548 Variable *LoVar = nullptr; |
| 552 Variable *HiVar = nullptr; | 549 Variable *HiVar = nullptr; |
| 553 /// VarsReal (and Operand::Vars) are set up such that Vars[0] == | 550 /// VarsReal (and Operand::Vars) are set up such that Vars[0] == this. |
| 554 /// this. | |
| 555 Variable *VarsReal[1]; | 551 Variable *VarsReal[1]; |
| 556 }; | 552 }; |
| 557 | 553 |
| 558 enum MetadataKind { | 554 enum MetadataKind { |
| 559 VMK_Uses, /// Track only uses, not defs | 555 VMK_Uses, /// Track only uses, not defs |
| 560 VMK_SingleDefs, /// Track uses+defs, but only record single def | 556 VMK_SingleDefs, /// Track uses+defs, but only record single def |
| 561 VMK_All /// Track uses+defs, including full def list | 557 VMK_All /// Track uses+defs, including full def list |
| 562 }; | 558 }; |
| 563 using InstDefList = std::vector<const Inst *, CfgLocalAllocator<const Inst *>>; | 559 using InstDefList = std::vector<const Inst *, CfgLocalAllocator<const Inst *>>; |
| 564 | 560 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 604 | 600 |
| 605 /// VariablesMetadata analyzes and summarizes the metadata for the complete set | 601 /// VariablesMetadata analyzes and summarizes the metadata for the complete set |
| 606 /// of Variables. | 602 /// of Variables. |
| 607 class VariablesMetadata { | 603 class VariablesMetadata { |
| 608 VariablesMetadata() = delete; | 604 VariablesMetadata() = delete; |
| 609 VariablesMetadata(const VariablesMetadata &) = delete; | 605 VariablesMetadata(const VariablesMetadata &) = delete; |
| 610 VariablesMetadata &operator=(const VariablesMetadata &) = delete; | 606 VariablesMetadata &operator=(const VariablesMetadata &) = delete; |
| 611 | 607 |
| 612 public: | 608 public: |
| 613 explicit VariablesMetadata(const Cfg *Func) : Func(Func) {} | 609 explicit VariablesMetadata(const Cfg *Func) : Func(Func) {} |
| 614 /// Initialize the state by traversing all instructions/variables in | 610 /// Initialize the state by traversing all instructions/variables in the CFG. |
| 615 /// the CFG. | |
| 616 void init(MetadataKind TrackingKind); | 611 void init(MetadataKind TrackingKind); |
| 617 /// Add a single node. This is called by init(), and can be called | 612 /// Add a single node. This is called by init(), and can be called |
| 618 /// incrementally from elsewhere, e.g. after edge-splitting. | 613 /// incrementally from elsewhere, e.g. after edge-splitting. |
| 619 void addNode(CfgNode *Node); | 614 void addNode(CfgNode *Node); |
| 620 /// Returns whether the given Variable is tracked in this object. It should | 615 /// Returns whether the given Variable is tracked in this object. It should |
| 621 /// only return false if changes were made to the CFG after running init(), in | 616 /// only return false if changes were made to the CFG after running init(), in |
| 622 /// which case the state is stale and the results shouldn't be trusted (but it | 617 /// which case the state is stale and the results shouldn't be trusted (but it |
| 623 /// may be OK e.g. for dumping). | 618 /// may be OK e.g. for dumping). |
| 624 bool isTracked(const Variable *Var) const { | 619 bool isTracked(const Variable *Var) const { |
| 625 return Var->getIndex() < Metadata.size(); | 620 return Var->getIndex() < Metadata.size(); |
| 626 } | 621 } |
| 627 | 622 |
| 628 /// Returns whether the given Variable has multiple definitions. | 623 /// Returns whether the given Variable has multiple definitions. |
| 629 bool isMultiDef(const Variable *Var) const; | 624 bool isMultiDef(const Variable *Var) const; |
| 630 /// Returns the first definition instruction of the given Variable. This is | 625 /// Returns the first definition instruction of the given Variable. This is |
| 631 /// only valid for variables whose definitions are all within the same block, | 626 /// only valid for variables whose definitions are all within the same block, |
| 632 /// e.g. T after the lowered sequence "T=B; T+=C; A=T", for which | 627 /// e.g. T after the lowered sequence "T=B; T+=C; A=T", for which |
| 633 /// getFirstDefinition(T) would return the "T=B" instruction. For variables | 628 /// getFirstDefinition(T) would return the "T=B" instruction. For variables |
| 634 /// with definitions span multiple blocks, nullptr is returned. | 629 /// with definitions span multiple blocks, nullptr is returned. |
| 635 const Inst *getFirstDefinition(const Variable *Var) const; | 630 const Inst *getFirstDefinition(const Variable *Var) const; |
| 636 /// Returns the definition instruction of the given Variable, when | 631 /// Returns the definition instruction of the given Variable, when the |
| 637 /// the variable has exactly one definition. Otherwise, nullptr is | 632 /// variable has exactly one definition. Otherwise, nullptr is returned. |
| 638 /// returned. | |
| 639 const Inst *getSingleDefinition(const Variable *Var) const; | 633 const Inst *getSingleDefinition(const Variable *Var) const; |
| 640 /// Returns the list of all definition instructions of the given Variable. | 634 /// Returns the list of all definition instructions of the given Variable. |
| 641 const InstDefList &getLatterDefinitions(const Variable *Var) const; | 635 const InstDefList &getLatterDefinitions(const Variable *Var) const; |
| 642 | 636 |
| 643 /// Returns whether the given Variable is live across multiple | 637 /// Returns whether the given Variable is live across multiple blocks. Mainly, |
| 644 /// blocks. Mainly, this is used to partition Variables into | 638 /// this is used to partition Variables into single-block versus multi-block |
| 645 /// single-block versus multi-block sets for leveraging sparsity in | 639 /// sets for leveraging sparsity in liveness analysis, and for implementing |
| 646 /// liveness analysis, and for implementing simple stack slot | 640 /// simple stack slot coalescing. As a special case, function arguments are |
| 647 /// coalescing. As a special case, function arguments are always | 641 /// always considered multi-block because they are live coming into the entry |
| 648 /// considered multi-block because they are live coming into the | 642 /// block. |
| 649 /// entry block. | |
| 650 bool isMultiBlock(const Variable *Var) const; | 643 bool isMultiBlock(const Variable *Var) const; |
| 651 /// Returns the node that the given Variable is used in, assuming | 644 /// Returns the node that the given Variable is used in, assuming |
| 652 /// isMultiBlock() returns false. Otherwise, nullptr is returned. | 645 /// isMultiBlock() returns false. Otherwise, nullptr is returned. |
| 653 CfgNode *getLocalUseNode(const Variable *Var) const; | 646 CfgNode *getLocalUseNode(const Variable *Var) const; |
| 654 | 647 |
| 655 /// Returns the total use weight computed as the sum of uses multiplied by a | 648 /// Returns the total use weight computed as the sum of uses multiplied by a |
| 656 /// loop nest depth factor for each use. | 649 /// loop nest depth factor for each use. |
| 657 RegWeight getUseWeight(const Variable *Var) const; | 650 RegWeight getUseWeight(const Variable *Var) const; |
| 658 | 651 |
| 659 private: | 652 private: |
| 660 const Cfg *Func; | 653 const Cfg *Func; |
| 661 MetadataKind Kind; | 654 MetadataKind Kind; |
| 662 std::vector<VariableTracking> Metadata; | 655 std::vector<VariableTracking> Metadata; |
| 663 const static InstDefList NoDefinitions; | 656 const static InstDefList NoDefinitions; |
| 664 }; | 657 }; |
| 665 | 658 |
| 666 } // end of namespace Ice | 659 } // end of namespace Ice |
| 667 | 660 |
| 668 #endif // SUBZERO_SRC_ICEOPERAND_H | 661 #endif // SUBZERO_SRC_ICEOPERAND_H |
| OLD | NEW |