| 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 // This file declares the Operand class and its target-independent | 10 // This file declares the Operand class and its target-independent |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 private: | 74 private: |
| 75 Operand(const Operand &) LLVM_DELETED_FUNCTION; | 75 Operand(const Operand &) LLVM_DELETED_FUNCTION; |
| 76 Operand &operator=(const Operand &) LLVM_DELETED_FUNCTION; | 76 Operand &operator=(const Operand &) LLVM_DELETED_FUNCTION; |
| 77 }; | 77 }; |
| 78 | 78 |
| 79 // Constant is the abstract base class for constants. All | 79 // Constant is the abstract base class for constants. All |
| 80 // constants are allocated from a global arena and are pooled. | 80 // constants are allocated from a global arena and are pooled. |
| 81 class Constant : public Operand { | 81 class Constant : public Operand { |
| 82 public: | 82 public: |
| 83 uint32_t getPoolEntryID() const { return PoolEntryID; } | 83 uint32_t getPoolEntryID() const { return PoolEntryID; } |
| 84 virtual void emit(const Cfg *Func) const = 0; | 84 virtual void emit(const Cfg *Func) const { emit(Func->getContext()); } |
| 85 virtual void dump(const Cfg *Func) const = 0; | 85 virtual void dump(const Cfg *Func) const { dump(Func->getContext()); } |
| 86 virtual void emit(GlobalContext *Ctx) const = 0; |
| 87 virtual void dump(GlobalContext *Ctx) const = 0; |
| 86 | 88 |
| 87 static bool classof(const Operand *Operand) { | 89 static bool classof(const Operand *Operand) { |
| 88 OperandKind Kind = Operand->getKind(); | 90 OperandKind Kind = Operand->getKind(); |
| 89 return Kind >= kConst_Base && Kind <= kConst_Num; | 91 return Kind >= kConst_Base && Kind <= kConst_Num; |
| 90 } | 92 } |
| 91 | 93 |
| 92 protected: | 94 protected: |
| 93 Constant(OperandKind Kind, Type Ty, uint32_t PoolEntryID) | 95 Constant(OperandKind Kind, Type Ty, uint32_t PoolEntryID) |
| 94 : Operand(Kind, Ty), PoolEntryID(PoolEntryID) { | 96 : Operand(Kind, Ty), PoolEntryID(PoolEntryID) { |
| 95 Vars = NULL; | 97 Vars = NULL; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 109 // ConstantPrimitive<> wraps a primitive type. | 111 // ConstantPrimitive<> wraps a primitive type. |
| 110 template <typename T, Operand::OperandKind K> | 112 template <typename T, Operand::OperandKind K> |
| 111 class ConstantPrimitive : public Constant { | 113 class ConstantPrimitive : public Constant { |
| 112 public: | 114 public: |
| 113 static ConstantPrimitive *create(GlobalContext *Ctx, Type Ty, T Value, | 115 static ConstantPrimitive *create(GlobalContext *Ctx, Type Ty, T Value, |
| 114 uint32_t PoolEntryID) { | 116 uint32_t PoolEntryID) { |
| 115 return new (Ctx->allocate<ConstantPrimitive>()) | 117 return new (Ctx->allocate<ConstantPrimitive>()) |
| 116 ConstantPrimitive(Ty, Value, PoolEntryID); | 118 ConstantPrimitive(Ty, Value, PoolEntryID); |
| 117 } | 119 } |
| 118 T getValue() const { return Value; } | 120 T getValue() const { return Value; } |
| 119 virtual void emit(const Cfg *Func) const { | 121 using Constant::emit; |
| 120 Ostream &Str = Func->getContext()->getStrEmit(); | 122 virtual void emit(GlobalContext *Ctx) const { |
| 123 Ostream &Str = Ctx->getStrEmit(); |
| 121 Str << getValue(); | 124 Str << getValue(); |
| 122 } | 125 } |
| 123 virtual void dump(const Cfg *Func) const { | 126 using Constant::dump; |
| 124 Ostream &Str = Func->getContext()->getStrDump(); | 127 virtual void dump(GlobalContext *Ctx) const { |
| 128 Ostream &Str = Ctx->getStrDump(); |
| 125 Str << getValue(); | 129 Str << getValue(); |
| 126 } | 130 } |
| 127 | 131 |
| 128 static bool classof(const Operand *Operand) { | 132 static bool classof(const Operand *Operand) { |
| 129 return Operand->getKind() == K; | 133 return Operand->getKind() == K; |
| 130 } | 134 } |
| 131 | 135 |
| 132 private: | 136 private: |
| 133 ConstantPrimitive(Type Ty, T Value, uint32_t PoolEntryID) | 137 ConstantPrimitive(Type Ty, T Value, uint32_t PoolEntryID) |
| 134 : Constant(K, Ty, PoolEntryID), Value(Value) {} | 138 : Constant(K, Ty, PoolEntryID), Value(Value) {} |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 static ConstantRelocatable *create(GlobalContext *Ctx, Type Ty, | 175 static ConstantRelocatable *create(GlobalContext *Ctx, Type Ty, |
| 172 const RelocatableTuple &Tuple, | 176 const RelocatableTuple &Tuple, |
| 173 uint32_t PoolEntryID) { | 177 uint32_t PoolEntryID) { |
| 174 return new (Ctx->allocate<ConstantRelocatable>()) ConstantRelocatable( | 178 return new (Ctx->allocate<ConstantRelocatable>()) ConstantRelocatable( |
| 175 Ty, Tuple.Offset, Tuple.Name, Tuple.SuppressMangling, PoolEntryID); | 179 Ty, Tuple.Offset, Tuple.Name, Tuple.SuppressMangling, PoolEntryID); |
| 176 } | 180 } |
| 177 int64_t getOffset() const { return Offset; } | 181 int64_t getOffset() const { return Offset; } |
| 178 IceString getName() const { return Name; } | 182 IceString getName() const { return Name; } |
| 179 void setSuppressMangling(bool Value) { SuppressMangling = Value; } | 183 void setSuppressMangling(bool Value) { SuppressMangling = Value; } |
| 180 bool getSuppressMangling() const { return SuppressMangling; } | 184 bool getSuppressMangling() const { return SuppressMangling; } |
| 181 virtual void emit(const Cfg *Func) const; | 185 using Constant::emit; |
| 182 virtual void dump(const Cfg *Func) const; | 186 using Constant::dump; |
| 187 virtual void emit(GlobalContext *Ctx) const; |
| 188 virtual void dump(GlobalContext *Ctx) const; |
| 183 | 189 |
| 184 static bool classof(const Operand *Operand) { | 190 static bool classof(const Operand *Operand) { |
| 185 OperandKind Kind = Operand->getKind(); | 191 OperandKind Kind = Operand->getKind(); |
| 186 return Kind == kConstRelocatable; | 192 return Kind == kConstRelocatable; |
| 187 } | 193 } |
| 188 | 194 |
| 189 private: | 195 private: |
| 190 ConstantRelocatable(Type Ty, int64_t Offset, const IceString &Name, | 196 ConstantRelocatable(Type Ty, int64_t Offset, const IceString &Name, |
| 191 bool SuppressMangling, uint32_t PoolEntryID) | 197 bool SuppressMangling, uint32_t PoolEntryID) |
| 192 : Constant(kConstRelocatable, Ty, PoolEntryID), Offset(Offset), | 198 : Constant(kConstRelocatable, Ty, PoolEntryID), Offset(Offset), |
| (...skipping 28 matching lines...) Expand all Loading... |
| 221 bool isInf() const { return Weight == Inf; } | 227 bool isInf() const { return Weight == Inf; } |
| 222 | 228 |
| 223 private: | 229 private: |
| 224 uint32_t Weight; | 230 uint32_t Weight; |
| 225 }; | 231 }; |
| 226 Ostream &operator<<(Ostream &Str, const RegWeight &W); | 232 Ostream &operator<<(Ostream &Str, const RegWeight &W); |
| 227 bool operator<(const RegWeight &A, const RegWeight &B); | 233 bool operator<(const RegWeight &A, const RegWeight &B); |
| 228 bool operator<=(const RegWeight &A, const RegWeight &B); | 234 bool operator<=(const RegWeight &A, const RegWeight &B); |
| 229 bool operator==(const RegWeight &A, const RegWeight &B); | 235 bool operator==(const RegWeight &A, const RegWeight &B); |
| 230 | 236 |
| 237 // LiveRange is a set of instruction number intervals representing |
| 238 // a variable's live range. Generally there is one interval per basic |
| 239 // block where the variable is live, but adjacent intervals get |
| 240 // coalesced into a single interval. LiveRange also includes a |
| 241 // weight, in case e.g. we want a live range to have higher weight |
| 242 // inside a loop. |
| 243 class LiveRange { |
| 244 public: |
| 245 LiveRange() : Weight(0) {} |
| 246 |
| 247 void reset() { |
| 248 Range.clear(); |
| 249 Weight.setWeight(0); |
| 250 } |
| 251 void addSegment(int32_t Start, int32_t End); |
| 252 |
| 253 bool endsBefore(const LiveRange &Other) const; |
| 254 bool overlaps(const LiveRange &Other) const; |
| 255 bool containsValue(int32_t Value) const; |
| 256 bool isEmpty() const { return Range.empty(); } |
| 257 int32_t getStart() const { return Range.empty() ? -1 : Range.begin()->first; } |
| 258 |
| 259 RegWeight getWeight() const { return Weight; } |
| 260 void setWeight(const RegWeight &NewWeight) { Weight = NewWeight; } |
| 261 void addWeight(uint32_t Delta) { Weight.addWeight(Delta); } |
| 262 void dump(Ostream &Str) const; |
| 263 |
| 264 // Defining USE_SET uses std::set to hold the segments instead of |
| 265 // std::list. Using std::list will be slightly faster, but is more |
| 266 // restrictive because new segments cannot be added in the middle. |
| 267 |
| 268 //#define USE_SET |
| 269 |
| 270 private: |
| 271 typedef std::pair<int32_t, int32_t> RangeElementType; |
| 272 #ifdef USE_SET |
| 273 typedef std::set<RangeElementType> RangeType; |
| 274 #else |
| 275 typedef std::list<RangeElementType> RangeType; |
| 276 #endif |
| 277 RangeType Range; |
| 278 RegWeight Weight; |
| 279 }; |
| 280 |
| 281 Ostream &operator<<(Ostream &Str, const LiveRange &L); |
| 282 |
| 231 // Variable represents an operand that is register-allocated or | 283 // Variable represents an operand that is register-allocated or |
| 232 // stack-allocated. If it is register-allocated, it will ultimately | 284 // stack-allocated. If it is register-allocated, it will ultimately |
| 233 // have a non-negative RegNum field. | 285 // have a non-negative RegNum field. |
| 234 class Variable : public Operand { | 286 class Variable : public Operand { |
| 235 public: | 287 public: |
| 236 static Variable *create(Cfg *Func, Type Ty, const CfgNode *Node, SizeT Index, | 288 static Variable *create(Cfg *Func, Type Ty, const CfgNode *Node, SizeT Index, |
| 237 const IceString &Name) { | 289 const IceString &Name) { |
| 238 return new (Func->allocate<Variable>()) Variable(Ty, Node, Index, Name); | 290 return new (Func->allocate<Variable>()) Variable(Ty, Node, Index, Name); |
| 239 } | 291 } |
| 240 | 292 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 256 void setStackOffset(int32_t Offset) { StackOffset = Offset; } | 308 void setStackOffset(int32_t Offset) { StackOffset = Offset; } |
| 257 | 309 |
| 258 static const int32_t NoRegister = -1; | 310 static const int32_t NoRegister = -1; |
| 259 bool hasReg() const { return getRegNum() != NoRegister; } | 311 bool hasReg() const { return getRegNum() != NoRegister; } |
| 260 int32_t getRegNum() const { return RegNum; } | 312 int32_t getRegNum() const { return RegNum; } |
| 261 void setRegNum(int32_t NewRegNum) { | 313 void setRegNum(int32_t NewRegNum) { |
| 262 // Regnum shouldn't be set more than once. | 314 // Regnum shouldn't be set more than once. |
| 263 assert(!hasReg() || RegNum == NewRegNum); | 315 assert(!hasReg() || RegNum == NewRegNum); |
| 264 RegNum = NewRegNum; | 316 RegNum = NewRegNum; |
| 265 } | 317 } |
| 318 bool hasRegTmp() const { return getRegNumTmp() != NoRegister; } |
| 319 int32_t getRegNumTmp() const { return RegNumTmp; } |
| 320 void setRegNumTmp(int32_t NewRegNum) { RegNumTmp = NewRegNum; } |
| 266 | 321 |
| 267 RegWeight getWeight() const { return Weight; } | 322 RegWeight getWeight() const { return Weight; } |
| 268 void setWeight(uint32_t NewWeight) { Weight = NewWeight; } | 323 void setWeight(uint32_t NewWeight) { Weight = NewWeight; } |
| 269 void setWeightInfinite() { Weight = RegWeight::Inf; } | 324 void setWeightInfinite() { Weight = RegWeight::Inf; } |
| 270 | 325 |
| 271 Variable *getPreferredRegister() const { return RegisterPreference; } | 326 Variable *getPreferredRegister() const { return RegisterPreference; } |
| 272 bool getRegisterOverlap() const { return AllowRegisterOverlap; } | 327 bool getRegisterOverlap() const { return AllowRegisterOverlap; } |
| 273 void setPreferredRegister(Variable *Prefer, bool Overlap) { | 328 void setPreferredRegister(Variable *Prefer, bool Overlap) { |
| 274 RegisterPreference = Prefer; | 329 RegisterPreference = Prefer; |
| 275 AllowRegisterOverlap = Overlap; | 330 AllowRegisterOverlap = Overlap; |
| 276 } | 331 } |
| 277 | 332 |
| 333 const LiveRange &getLiveRange() const { return Live; } |
| 334 void setLiveRange(const LiveRange &Range) { Live = Range; } |
| 335 void resetLiveRange() { Live.reset(); } |
| 336 void addLiveRange(int32_t Start, int32_t End, uint32_t WeightDelta) { |
| 337 assert(WeightDelta != RegWeight::Inf); |
| 338 Live.addSegment(Start, End); |
| 339 if (Weight.isInf()) |
| 340 Live.setWeight(RegWeight::Inf); |
| 341 else |
| 342 Live.addWeight(WeightDelta * Weight.getWeight()); |
| 343 } |
| 344 void setLiveRangeInfiniteWeight() { Live.setWeight(RegWeight::Inf); } |
| 345 |
| 278 Variable *getLo() const { return LoVar; } | 346 Variable *getLo() const { return LoVar; } |
| 279 Variable *getHi() const { return HiVar; } | 347 Variable *getHi() const { return HiVar; } |
| 280 void setLoHi(Variable *Lo, Variable *Hi) { | 348 void setLoHi(Variable *Lo, Variable *Hi) { |
| 281 assert(LoVar == NULL); | 349 assert(LoVar == NULL); |
| 282 assert(HiVar == NULL); | 350 assert(HiVar == NULL); |
| 283 LoVar = Lo; | 351 LoVar = Lo; |
| 284 HiVar = Hi; | 352 HiVar = Hi; |
| 285 } | 353 } |
| 286 // Creates a temporary copy of the variable with a different type. | 354 // Creates a temporary copy of the variable with a different type. |
| 287 // Used primarily for syntactic correctness of textual assembly | 355 // Used primarily for syntactic correctness of textual assembly |
| 288 // emission. Note that only basic information is copied, in | 356 // emission. Note that only basic information is copied, in |
| 289 // particular not DefInst, IsArgument, Weight, RegisterPreference, | 357 // particular not DefInst, IsArgument, Weight, RegisterPreference, |
| 290 // AllowRegisterOverlap, LoVar, HiVar, VarsReal. | 358 // AllowRegisterOverlap, LoVar, HiVar, VarsReal. |
| 291 Variable asType(Type Ty); | 359 Variable asType(Type Ty); |
| 292 | 360 |
| 293 virtual void emit(const Cfg *Func) const; | 361 virtual void emit(const Cfg *Func) const; |
| 294 virtual void dump(const Cfg *Func) const; | 362 virtual void dump(const Cfg *Func) const; |
| 295 | 363 |
| 296 static bool classof(const Operand *Operand) { | 364 static bool classof(const Operand *Operand) { |
| 297 return Operand->getKind() == kVariable; | 365 return Operand->getKind() == kVariable; |
| 298 } | 366 } |
| 299 | 367 |
| 300 // The destructor is public because of the asType() method. | 368 // The destructor is public because of the asType() method. |
| 301 virtual ~Variable() {} | 369 virtual ~Variable() {} |
| 302 | 370 |
| 303 private: | 371 private: |
| 304 Variable(Type Ty, const CfgNode *Node, SizeT Index, const IceString &Name) | 372 Variable(Type Ty, const CfgNode *Node, SizeT Index, const IceString &Name) |
| 305 : Operand(kVariable, Ty), Number(Index), Name(Name), DefInst(NULL), | 373 : Operand(kVariable, Ty), Number(Index), Name(Name), DefInst(NULL), |
| 306 DefNode(Node), IsArgument(false), StackOffset(0), RegNum(NoRegister), | 374 DefNode(Node), IsArgument(false), StackOffset(0), RegNum(NoRegister), |
| 307 Weight(1), RegisterPreference(NULL), AllowRegisterOverlap(false), | 375 RegNumTmp(NoRegister), Weight(1), RegisterPreference(NULL), |
| 308 LoVar(NULL), HiVar(NULL) { | 376 AllowRegisterOverlap(false), LoVar(NULL), HiVar(NULL) { |
| 309 Vars = VarsReal; | 377 Vars = VarsReal; |
| 310 Vars[0] = this; | 378 Vars[0] = this; |
| 311 NumVars = 1; | 379 NumVars = 1; |
| 312 } | 380 } |
| 313 Variable(const Variable &) LLVM_DELETED_FUNCTION; | 381 Variable(const Variable &) LLVM_DELETED_FUNCTION; |
| 314 Variable &operator=(const Variable &) LLVM_DELETED_FUNCTION; | 382 Variable &operator=(const Variable &) LLVM_DELETED_FUNCTION; |
| 315 // Number is unique across all variables, and is used as a | 383 // Number is unique across all variables, and is used as a |
| 316 // (bit)vector index for liveness analysis. | 384 // (bit)vector index for liveness analysis. |
| 317 const SizeT Number; | 385 const SizeT Number; |
| 318 // Name is optional. | 386 // Name is optional. |
| 319 const IceString Name; | 387 const IceString Name; |
| 320 // DefInst is the instruction that produces this variable as its | 388 // DefInst is the instruction that produces this variable as its |
| 321 // dest. | 389 // dest. |
| 322 Inst *DefInst; | 390 Inst *DefInst; |
| 323 // DefNode is the node where this variable was produced, and is | 391 // DefNode is the node where this variable was produced, and is |
| 324 // reset to NULL if it is used outside that node. This is used for | 392 // reset to NULL if it is used outside that node. This is used for |
| 325 // detecting isMultiblockLife(). TODO: Collapse this to a single | 393 // detecting isMultiblockLife(). TODO: Collapse this to a single |
| 326 // bit and use a separate pass to calculate the values across the | 394 // bit and use a separate pass to calculate the values across the |
| 327 // Cfg. This saves space in the Variable, and removes the fragility | 395 // Cfg. This saves space in the Variable, and removes the fragility |
| 328 // of incrementally computing and maintaining the information. | 396 // of incrementally computing and maintaining the information. |
| 329 const CfgNode *DefNode; | 397 const CfgNode *DefNode; |
| 330 bool IsArgument; | 398 bool IsArgument; |
| 331 // StackOffset is the canonical location on stack (only if | 399 // StackOffset is the canonical location on stack (only if |
| 332 // RegNum<0 || IsArgument). | 400 // RegNum<0 || IsArgument). |
| 333 int32_t StackOffset; | 401 int32_t StackOffset; |
| 334 // RegNum is the allocated register, or NoRegister if it isn't | 402 // RegNum is the allocated register, or NoRegister if it isn't |
| 335 // register-allocated. | 403 // register-allocated. |
| 336 int32_t RegNum; | 404 int32_t RegNum; |
| 405 // RegNumTmp is the tentative assignment during register allocation. |
| 406 int32_t RegNumTmp; |
| 337 RegWeight Weight; // Register allocation priority | 407 RegWeight Weight; // Register allocation priority |
| 338 // RegisterPreference says that if possible, the register allocator | 408 // RegisterPreference says that if possible, the register allocator |
| 339 // should prefer the register that was assigned to this linked | 409 // should prefer the register that was assigned to this linked |
| 340 // variable. It also allows a spill slot to share its stack | 410 // variable. It also allows a spill slot to share its stack |
| 341 // location with another variable, if that variable does not get | 411 // location with another variable, if that variable does not get |
| 342 // register-allocated and therefore has a stack location. | 412 // register-allocated and therefore has a stack location. |
| 343 Variable *RegisterPreference; | 413 Variable *RegisterPreference; |
| 344 // AllowRegisterOverlap says that it is OK to honor | 414 // AllowRegisterOverlap says that it is OK to honor |
| 345 // RegisterPreference and "share" a register even if the two live | 415 // RegisterPreference and "share" a register even if the two live |
| 346 // ranges overlap. | 416 // ranges overlap. |
| 347 bool AllowRegisterOverlap; | 417 bool AllowRegisterOverlap; |
| 418 LiveRange Live; |
| 348 // LoVar and HiVar are needed for lowering from 64 to 32 bits. When | 419 // LoVar and HiVar are needed for lowering from 64 to 32 bits. When |
| 349 // lowering from I64 to I32 on a 32-bit architecture, we split the | 420 // lowering from I64 to I32 on a 32-bit architecture, we split the |
| 350 // variable into two machine-size pieces. LoVar is the low-order | 421 // variable into two machine-size pieces. LoVar is the low-order |
| 351 // machine-size portion, and HiVar is the remaining high-order | 422 // machine-size portion, and HiVar is the remaining high-order |
| 352 // portion. TODO: It's wasteful to penalize all variables on all | 423 // portion. TODO: It's wasteful to penalize all variables on all |
| 353 // targets this way; use a sparser representation. It's also | 424 // targets this way; use a sparser representation. It's also |
| 354 // wasteful for a 64-bit target. | 425 // wasteful for a 64-bit target. |
| 355 Variable *LoVar; | 426 Variable *LoVar; |
| 356 Variable *HiVar; | 427 Variable *HiVar; |
| 357 // VarsReal (and Operand::Vars) are set up such that Vars[0] == | 428 // VarsReal (and Operand::Vars) are set up such that Vars[0] == |
| 358 // this. | 429 // this. |
| 359 Variable *VarsReal[1]; | 430 Variable *VarsReal[1]; |
| 360 }; | 431 }; |
| 361 | 432 |
| 362 } // end of namespace Ice | 433 } // end of namespace Ice |
| 363 | 434 |
| 364 #endif // SUBZERO_SRC_ICEOPERAND_H | 435 #endif // SUBZERO_SRC_ICEOPERAND_H |
| OLD | NEW |