| 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(InstNumberT Start, InstNumberT End); |
| 252 |
| 253 bool endsBefore(const LiveRange &Other) const; |
| 254 bool overlaps(const LiveRange &Other) const; |
| 255 bool overlaps(InstNumberT OtherBegin) const; |
| 256 bool containsValue(InstNumberT Value) const; |
| 257 bool isEmpty() const { return Range.empty(); } |
| 258 InstNumberT getStart() const { |
| 259 return Range.empty() ? -1 : Range.begin()->first; |
| 260 } |
| 261 |
| 262 RegWeight getWeight() const { return Weight; } |
| 263 void setWeight(const RegWeight &NewWeight) { Weight = NewWeight; } |
| 264 void addWeight(uint32_t Delta) { Weight.addWeight(Delta); } |
| 265 void dump(Ostream &Str) const; |
| 266 |
| 267 // Defining USE_SET uses std::set to hold the segments instead of |
| 268 // std::list. Using std::list will be slightly faster, but is more |
| 269 // restrictive because new segments cannot be added in the middle. |
| 270 |
| 271 //#define USE_SET |
| 272 |
| 273 private: |
| 274 typedef std::pair<InstNumberT, InstNumberT> RangeElementType; |
| 275 #ifdef USE_SET |
| 276 typedef std::set<RangeElementType> RangeType; |
| 277 #else |
| 278 typedef std::list<RangeElementType> RangeType; |
| 279 #endif |
| 280 RangeType Range; |
| 281 RegWeight Weight; |
| 282 }; |
| 283 |
| 284 Ostream &operator<<(Ostream &Str, const LiveRange &L); |
| 285 |
| 231 // Variable represents an operand that is register-allocated or | 286 // Variable represents an operand that is register-allocated or |
| 232 // stack-allocated. If it is register-allocated, it will ultimately | 287 // stack-allocated. If it is register-allocated, it will ultimately |
| 233 // have a non-negative RegNum field. | 288 // have a non-negative RegNum field. |
| 234 class Variable : public Operand { | 289 class Variable : public Operand { |
| 235 public: | 290 public: |
| 236 static Variable *create(Cfg *Func, Type Ty, const CfgNode *Node, SizeT Index, | 291 static Variable *create(Cfg *Func, Type Ty, const CfgNode *Node, SizeT Index, |
| 237 const IceString &Name) { | 292 const IceString &Name) { |
| 238 return new (Func->allocate<Variable>()) Variable(Ty, Node, Index, Name); | 293 return new (Func->allocate<Variable>()) Variable(Ty, Node, Index, Name); |
| 239 } | 294 } |
| 240 | 295 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 256 void setStackOffset(int32_t Offset) { StackOffset = Offset; } | 311 void setStackOffset(int32_t Offset) { StackOffset = Offset; } |
| 257 | 312 |
| 258 static const int32_t NoRegister = -1; | 313 static const int32_t NoRegister = -1; |
| 259 bool hasReg() const { return getRegNum() != NoRegister; } | 314 bool hasReg() const { return getRegNum() != NoRegister; } |
| 260 int32_t getRegNum() const { return RegNum; } | 315 int32_t getRegNum() const { return RegNum; } |
| 261 void setRegNum(int32_t NewRegNum) { | 316 void setRegNum(int32_t NewRegNum) { |
| 262 // Regnum shouldn't be set more than once. | 317 // Regnum shouldn't be set more than once. |
| 263 assert(!hasReg() || RegNum == NewRegNum); | 318 assert(!hasReg() || RegNum == NewRegNum); |
| 264 RegNum = NewRegNum; | 319 RegNum = NewRegNum; |
| 265 } | 320 } |
| 321 bool hasRegTmp() const { return getRegNumTmp() != NoRegister; } |
| 322 int32_t getRegNumTmp() const { return RegNumTmp; } |
| 323 void setRegNumTmp(int32_t NewRegNum) { RegNumTmp = NewRegNum; } |
| 266 | 324 |
| 267 RegWeight getWeight() const { return Weight; } | 325 RegWeight getWeight() const { return Weight; } |
| 268 void setWeight(uint32_t NewWeight) { Weight = NewWeight; } | 326 void setWeight(uint32_t NewWeight) { Weight = NewWeight; } |
| 269 void setWeightInfinite() { Weight = RegWeight::Inf; } | 327 void setWeightInfinite() { Weight = RegWeight::Inf; } |
| 270 | 328 |
| 271 Variable *getPreferredRegister() const { return RegisterPreference; } | 329 Variable *getPreferredRegister() const { return RegisterPreference; } |
| 272 bool getRegisterOverlap() const { return AllowRegisterOverlap; } | 330 bool getRegisterOverlap() const { return AllowRegisterOverlap; } |
| 273 void setPreferredRegister(Variable *Prefer, bool Overlap) { | 331 void setPreferredRegister(Variable *Prefer, bool Overlap) { |
| 274 RegisterPreference = Prefer; | 332 RegisterPreference = Prefer; |
| 275 AllowRegisterOverlap = Overlap; | 333 AllowRegisterOverlap = Overlap; |
| 276 } | 334 } |
| 277 | 335 |
| 336 const LiveRange &getLiveRange() const { return Live; } |
| 337 void setLiveRange(const LiveRange &Range) { Live = Range; } |
| 338 void resetLiveRange() { Live.reset(); } |
| 339 void addLiveRange(InstNumberT Start, InstNumberT End, uint32_t WeightDelta) { |
| 340 assert(WeightDelta != RegWeight::Inf); |
| 341 Live.addSegment(Start, End); |
| 342 if (Weight.isInf()) |
| 343 Live.setWeight(RegWeight::Inf); |
| 344 else |
| 345 Live.addWeight(WeightDelta * Weight.getWeight()); |
| 346 } |
| 347 void setLiveRangeInfiniteWeight() { Live.setWeight(RegWeight::Inf); } |
| 348 |
| 278 Variable *getLo() const { return LoVar; } | 349 Variable *getLo() const { return LoVar; } |
| 279 Variable *getHi() const { return HiVar; } | 350 Variable *getHi() const { return HiVar; } |
| 280 void setLoHi(Variable *Lo, Variable *Hi) { | 351 void setLoHi(Variable *Lo, Variable *Hi) { |
| 281 assert(LoVar == NULL); | 352 assert(LoVar == NULL); |
| 282 assert(HiVar == NULL); | 353 assert(HiVar == NULL); |
| 283 LoVar = Lo; | 354 LoVar = Lo; |
| 284 HiVar = Hi; | 355 HiVar = Hi; |
| 285 } | 356 } |
| 286 // Creates a temporary copy of the variable with a different type. | 357 // Creates a temporary copy of the variable with a different type. |
| 287 // Used primarily for syntactic correctness of textual assembly | 358 // Used primarily for syntactic correctness of textual assembly |
| 288 // emission. Note that only basic information is copied, in | 359 // emission. Note that only basic information is copied, in |
| 289 // particular not DefInst, IsArgument, Weight, RegisterPreference, | 360 // particular not DefInst, IsArgument, Weight, RegisterPreference, |
| 290 // AllowRegisterOverlap, LoVar, HiVar, VarsReal. | 361 // AllowRegisterOverlap, LoVar, HiVar, VarsReal. |
| 291 Variable asType(Type Ty); | 362 Variable asType(Type Ty); |
| 292 | 363 |
| 293 virtual void emit(const Cfg *Func) const; | 364 virtual void emit(const Cfg *Func) const; |
| 294 virtual void dump(const Cfg *Func) const; | 365 virtual void dump(const Cfg *Func) const; |
| 295 | 366 |
| 296 static bool classof(const Operand *Operand) { | 367 static bool classof(const Operand *Operand) { |
| 297 return Operand->getKind() == kVariable; | 368 return Operand->getKind() == kVariable; |
| 298 } | 369 } |
| 299 | 370 |
| 300 // The destructor is public because of the asType() method. | 371 // The destructor is public because of the asType() method. |
| 301 virtual ~Variable() {} | 372 virtual ~Variable() {} |
| 302 | 373 |
| 303 private: | 374 private: |
| 304 Variable(Type Ty, const CfgNode *Node, SizeT Index, const IceString &Name) | 375 Variable(Type Ty, const CfgNode *Node, SizeT Index, const IceString &Name) |
| 305 : Operand(kVariable, Ty), Number(Index), Name(Name), DefInst(NULL), | 376 : Operand(kVariable, Ty), Number(Index), Name(Name), DefInst(NULL), |
| 306 DefNode(Node), IsArgument(false), StackOffset(0), RegNum(NoRegister), | 377 DefNode(Node), IsArgument(false), StackOffset(0), RegNum(NoRegister), |
| 307 Weight(1), RegisterPreference(NULL), AllowRegisterOverlap(false), | 378 RegNumTmp(NoRegister), Weight(1), RegisterPreference(NULL), |
| 308 LoVar(NULL), HiVar(NULL) { | 379 AllowRegisterOverlap(false), LoVar(NULL), HiVar(NULL) { |
| 309 Vars = VarsReal; | 380 Vars = VarsReal; |
| 310 Vars[0] = this; | 381 Vars[0] = this; |
| 311 NumVars = 1; | 382 NumVars = 1; |
| 312 } | 383 } |
| 313 Variable(const Variable &) LLVM_DELETED_FUNCTION; | 384 Variable(const Variable &) LLVM_DELETED_FUNCTION; |
| 314 Variable &operator=(const Variable &) LLVM_DELETED_FUNCTION; | 385 Variable &operator=(const Variable &) LLVM_DELETED_FUNCTION; |
| 315 // Number is unique across all variables, and is used as a | 386 // Number is unique across all variables, and is used as a |
| 316 // (bit)vector index for liveness analysis. | 387 // (bit)vector index for liveness analysis. |
| 317 const SizeT Number; | 388 const SizeT Number; |
| 318 // Name is optional. | 389 // Name is optional. |
| 319 const IceString Name; | 390 const IceString Name; |
| 320 // DefInst is the instruction that produces this variable as its | 391 // DefInst is the instruction that produces this variable as its |
| 321 // dest. | 392 // dest. |
| 322 Inst *DefInst; | 393 Inst *DefInst; |
| 323 // DefNode is the node where this variable was produced, and is | 394 // 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 | 395 // reset to NULL if it is used outside that node. This is used for |
| 325 // detecting isMultiblockLife(). TODO: Collapse this to a single | 396 // detecting isMultiblockLife(). TODO: Collapse this to a single |
| 326 // bit and use a separate pass to calculate the values across the | 397 // bit and use a separate pass to calculate the values across the |
| 327 // Cfg. This saves space in the Variable, and removes the fragility | 398 // Cfg. This saves space in the Variable, and removes the fragility |
| 328 // of incrementally computing and maintaining the information. | 399 // of incrementally computing and maintaining the information. |
| 329 const CfgNode *DefNode; | 400 const CfgNode *DefNode; |
| 330 bool IsArgument; | 401 bool IsArgument; |
| 331 // StackOffset is the canonical location on stack (only if | 402 // StackOffset is the canonical location on stack (only if |
| 332 // RegNum<0 || IsArgument). | 403 // RegNum<0 || IsArgument). |
| 333 int32_t StackOffset; | 404 int32_t StackOffset; |
| 334 // RegNum is the allocated register, or NoRegister if it isn't | 405 // RegNum is the allocated register, or NoRegister if it isn't |
| 335 // register-allocated. | 406 // register-allocated. |
| 336 int32_t RegNum; | 407 int32_t RegNum; |
| 408 // RegNumTmp is the tentative assignment during register allocation. |
| 409 int32_t RegNumTmp; |
| 337 RegWeight Weight; // Register allocation priority | 410 RegWeight Weight; // Register allocation priority |
| 338 // RegisterPreference says that if possible, the register allocator | 411 // RegisterPreference says that if possible, the register allocator |
| 339 // should prefer the register that was assigned to this linked | 412 // should prefer the register that was assigned to this linked |
| 340 // variable. It also allows a spill slot to share its stack | 413 // variable. It also allows a spill slot to share its stack |
| 341 // location with another variable, if that variable does not get | 414 // location with another variable, if that variable does not get |
| 342 // register-allocated and therefore has a stack location. | 415 // register-allocated and therefore has a stack location. |
| 343 Variable *RegisterPreference; | 416 Variable *RegisterPreference; |
| 344 // AllowRegisterOverlap says that it is OK to honor | 417 // AllowRegisterOverlap says that it is OK to honor |
| 345 // RegisterPreference and "share" a register even if the two live | 418 // RegisterPreference and "share" a register even if the two live |
| 346 // ranges overlap. | 419 // ranges overlap. |
| 347 bool AllowRegisterOverlap; | 420 bool AllowRegisterOverlap; |
| 421 LiveRange Live; |
| 348 // LoVar and HiVar are needed for lowering from 64 to 32 bits. When | 422 // 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 | 423 // 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 | 424 // variable into two machine-size pieces. LoVar is the low-order |
| 351 // machine-size portion, and HiVar is the remaining high-order | 425 // machine-size portion, and HiVar is the remaining high-order |
| 352 // portion. TODO: It's wasteful to penalize all variables on all | 426 // portion. TODO: It's wasteful to penalize all variables on all |
| 353 // targets this way; use a sparser representation. It's also | 427 // targets this way; use a sparser representation. It's also |
| 354 // wasteful for a 64-bit target. | 428 // wasteful for a 64-bit target. |
| 355 Variable *LoVar; | 429 Variable *LoVar; |
| 356 Variable *HiVar; | 430 Variable *HiVar; |
| 357 // VarsReal (and Operand::Vars) are set up such that Vars[0] == | 431 // VarsReal (and Operand::Vars) are set up such that Vars[0] == |
| 358 // this. | 432 // this. |
| 359 Variable *VarsReal[1]; | 433 Variable *VarsReal[1]; |
| 360 }; | 434 }; |
| 361 | 435 |
| 362 } // end of namespace Ice | 436 } // end of namespace Ice |
| 363 | 437 |
| 364 #endif // SUBZERO_SRC_ICEOPERAND_H | 438 #endif // SUBZERO_SRC_ICEOPERAND_H |
| OLD | NEW |