| 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 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 378 RegNum = NewRegNum; | 378 RegNum = NewRegNum; |
| 379 } | 379 } |
| 380 bool hasRegTmp() const { return getRegNumTmp() != NoRegister; } | 380 bool hasRegTmp() const { return getRegNumTmp() != NoRegister; } |
| 381 int32_t getRegNumTmp() const { return RegNumTmp; } | 381 int32_t getRegNumTmp() const { return RegNumTmp; } |
| 382 void setRegNumTmp(int32_t NewRegNum) { RegNumTmp = NewRegNum; } | 382 void setRegNumTmp(int32_t NewRegNum) { RegNumTmp = NewRegNum; } |
| 383 | 383 |
| 384 RegWeight getWeight() const { return Weight; } | 384 RegWeight getWeight() const { return Weight; } |
| 385 void setWeight(uint32_t NewWeight) { Weight = NewWeight; } | 385 void setWeight(uint32_t NewWeight) { Weight = NewWeight; } |
| 386 void setWeightInfinite() { Weight = RegWeight::Inf; } | 386 void setWeightInfinite() { Weight = RegWeight::Inf; } |
| 387 | 387 |
| 388 Variable *getPreferredRegister() const { return RegisterPreference; } | |
| 389 bool getRegisterOverlap() const { return AllowRegisterOverlap; } | |
| 390 void setPreferredRegister(Variable *Prefer, bool Overlap) { | |
| 391 RegisterPreference = Prefer; | |
| 392 AllowRegisterOverlap = Overlap; | |
| 393 } | |
| 394 | |
| 395 const LiveRange &getLiveRange() const { return Live; } | 388 const LiveRange &getLiveRange() const { return Live; } |
| 396 void setLiveRange(const LiveRange &Range) { Live = Range; } | 389 void setLiveRange(const LiveRange &Range) { Live = Range; } |
| 397 void resetLiveRange() { Live.reset(); } | 390 void resetLiveRange() { Live.reset(); } |
| 398 void addLiveRange(InstNumberT Start, InstNumberT End, uint32_t WeightDelta) { | 391 void addLiveRange(InstNumberT Start, InstNumberT End, uint32_t WeightDelta) { |
| 399 assert(WeightDelta != RegWeight::Inf); | 392 assert(WeightDelta != RegWeight::Inf); |
| 400 Live.addSegment(Start, End); | 393 Live.addSegment(Start, End); |
| 401 if (Weight.isInf()) | 394 if (Weight.isInf()) |
| 402 Live.setWeight(RegWeight::Inf); | 395 Live.setWeight(RegWeight::Inf); |
| 403 else | 396 else |
| 404 Live.addWeight(WeightDelta * Weight.getWeight()); | 397 Live.addWeight(WeightDelta * Weight.getWeight()); |
| 405 } | 398 } |
| 406 void setLiveRangeInfiniteWeight() { Live.setWeight(RegWeight::Inf); } | 399 void setLiveRangeInfiniteWeight() { Live.setWeight(RegWeight::Inf); } |
| 407 | 400 |
| 408 Variable *getLo() const { return LoVar; } | 401 Variable *getLo() const { return LoVar; } |
| 409 Variable *getHi() const { return HiVar; } | 402 Variable *getHi() const { return HiVar; } |
| 410 void setLoHi(Variable *Lo, Variable *Hi) { | 403 void setLoHi(Variable *Lo, Variable *Hi) { |
| 411 assert(LoVar == NULL); | 404 assert(LoVar == NULL); |
| 412 assert(HiVar == NULL); | 405 assert(HiVar == NULL); |
| 413 LoVar = Lo; | 406 LoVar = Lo; |
| 414 HiVar = Hi; | 407 HiVar = Hi; |
| 415 } | 408 } |
| 416 // Creates a temporary copy of the variable with a different type. | 409 // Creates a temporary copy of the variable with a different type. |
| 417 // Used primarily for syntactic correctness of textual assembly | 410 // Used primarily for syntactic correctness of textual assembly |
| 418 // emission. Note that only basic information is copied, in | 411 // emission. Note that only basic information is copied, in |
| 419 // particular not DefInst, IsArgument, Weight, RegisterPreference, | 412 // particular not DefInst, IsArgument, Weight, LoVar, HiVar, |
| 420 // AllowRegisterOverlap, LoVar, HiVar, VarsReal. | 413 // VarsReal. |
| 421 Variable asType(Type Ty); | 414 Variable asType(Type Ty); |
| 422 | 415 |
| 423 virtual void emit(const Cfg *Func) const; | 416 virtual void emit(const Cfg *Func) const; |
| 424 using Operand::dump; | 417 using Operand::dump; |
| 425 virtual void dump(const Cfg *Func, Ostream &Str) const; | 418 virtual void dump(const Cfg *Func, Ostream &Str) const; |
| 426 | 419 |
| 427 static bool classof(const Operand *Operand) { | 420 static bool classof(const Operand *Operand) { |
| 428 OperandKind Kind = Operand->getKind(); | 421 OperandKind Kind = Operand->getKind(); |
| 429 return Kind >= kVariable && Kind <= kVariable_Num; | 422 return Kind >= kVariable && Kind <= kVariable_Num; |
| 430 } | 423 } |
| 431 | 424 |
| 432 // The destructor is public because of the asType() method. | 425 // The destructor is public because of the asType() method. |
| 433 virtual ~Variable() {} | 426 virtual ~Variable() {} |
| 434 | 427 |
| 435 protected: | 428 protected: |
| 436 Variable(OperandKind K, Type Ty, SizeT Index, const IceString &Name) | 429 Variable(OperandKind K, Type Ty, SizeT Index, const IceString &Name) |
| 437 : Operand(K, Ty), Number(Index), Name(Name), IsArgument(false), | 430 : Operand(K, Ty), Number(Index), Name(Name), IsArgument(false), |
| 438 IsImplicitArgument(false), StackOffset(0), RegNum(NoRegister), | 431 IsImplicitArgument(false), StackOffset(0), RegNum(NoRegister), |
| 439 RegNumTmp(NoRegister), Weight(1), RegisterPreference(NULL), | 432 RegNumTmp(NoRegister), Weight(1), LoVar(NULL), HiVar(NULL) { |
| 440 AllowRegisterOverlap(false), LoVar(NULL), HiVar(NULL) { | |
| 441 Vars = VarsReal; | 433 Vars = VarsReal; |
| 442 Vars[0] = this; | 434 Vars[0] = this; |
| 443 NumVars = 1; | 435 NumVars = 1; |
| 444 } | 436 } |
| 445 // Number is unique across all variables, and is used as a | 437 // Number is unique across all variables, and is used as a |
| 446 // (bit)vector index for liveness analysis. | 438 // (bit)vector index for liveness analysis. |
| 447 const SizeT Number; | 439 const SizeT Number; |
| 448 // Name is optional. | 440 // Name is optional. |
| 449 IceString Name; | 441 IceString Name; |
| 450 bool IsArgument; | 442 bool IsArgument; |
| 451 bool IsImplicitArgument; | 443 bool IsImplicitArgument; |
| 452 // StackOffset is the canonical location on stack (only if | 444 // StackOffset is the canonical location on stack (only if |
| 453 // RegNum<0 || IsArgument). | 445 // RegNum==NoRegister || IsArgument). |
| 454 int32_t StackOffset; | 446 int32_t StackOffset; |
| 455 // RegNum is the allocated register, or NoRegister if it isn't | 447 // RegNum is the allocated register, or NoRegister if it isn't |
| 456 // register-allocated. | 448 // register-allocated. |
| 457 int32_t RegNum; | 449 int32_t RegNum; |
| 458 // RegNumTmp is the tentative assignment during register allocation. | 450 // RegNumTmp is the tentative assignment during register allocation. |
| 459 int32_t RegNumTmp; | 451 int32_t RegNumTmp; |
| 460 RegWeight Weight; // Register allocation priority | 452 RegWeight Weight; // Register allocation priority |
| 461 // RegisterPreference says that if possible, the register allocator | |
| 462 // should prefer the register that was assigned to this linked | |
| 463 // variable. It also allows a spill slot to share its stack | |
| 464 // location with another variable, if that variable does not get | |
| 465 // register-allocated and therefore has a stack location. | |
| 466 Variable *RegisterPreference; | |
| 467 // AllowRegisterOverlap says that it is OK to honor | |
| 468 // RegisterPreference and "share" a register even if the two live | |
| 469 // ranges overlap. | |
| 470 bool AllowRegisterOverlap; | |
| 471 LiveRange Live; | 453 LiveRange Live; |
| 472 // LoVar and HiVar are needed for lowering from 64 to 32 bits. When | 454 // LoVar and HiVar are needed for lowering from 64 to 32 bits. When |
| 473 // lowering from I64 to I32 on a 32-bit architecture, we split the | 455 // lowering from I64 to I32 on a 32-bit architecture, we split the |
| 474 // variable into two machine-size pieces. LoVar is the low-order | 456 // variable into two machine-size pieces. LoVar is the low-order |
| 475 // machine-size portion, and HiVar is the remaining high-order | 457 // machine-size portion, and HiVar is the remaining high-order |
| 476 // portion. TODO: It's wasteful to penalize all variables on all | 458 // portion. TODO: It's wasteful to penalize all variables on all |
| 477 // targets this way; use a sparser representation. It's also | 459 // targets this way; use a sparser representation. It's also |
| 478 // wasteful for a 64-bit target. | 460 // wasteful for a 64-bit target. |
| 479 Variable *LoVar; | 461 Variable *LoVar; |
| 480 Variable *HiVar; | 462 Variable *HiVar; |
| 481 // VarsReal (and Operand::Vars) are set up such that Vars[0] == | 463 // VarsReal (and Operand::Vars) are set up such that Vars[0] == |
| 482 // this. | 464 // this. |
| 483 Variable *VarsReal[1]; | 465 Variable *VarsReal[1]; |
| 484 }; | 466 }; |
| 485 | 467 |
| 486 // VariableTracking tracks the metadata for a single variable. | 468 typedef std::vector<const Inst *> InstDefList; |
| 469 |
| 470 // VariableTracking tracks the metadata for a single variable. It is |
| 471 // only meant to be used internally by VariablesMetadata. |
| 487 class VariableTracking { | 472 class VariableTracking { |
| 488 public: | 473 public: |
| 489 enum MultiDefState { | 474 enum MultiDefState { |
| 490 // TODO(stichnot): Consider using just a simple counter. | 475 // TODO(stichnot): Consider using just a simple counter. |
| 491 MDS_Unknown, | 476 MDS_Unknown, |
| 492 MDS_SingleDef, | 477 MDS_SingleDef, |
| 493 MDS_MultiDef | 478 MDS_MultiDefSingleBlock, |
| 479 MDS_MultiDefMultiBlock |
| 494 }; | 480 }; |
| 495 enum MultiBlockState { | 481 enum MultiBlockState { |
| 496 MBS_Unknown, | 482 MBS_Unknown, |
| 497 MBS_SingleBlock, | 483 MBS_SingleBlock, |
| 498 MBS_MultiBlock | 484 MBS_MultiBlock |
| 499 }; | 485 }; |
| 500 VariableTracking() | 486 VariableTracking() |
| 501 : MultiDef(MDS_Unknown), MultiBlock(MBS_Unknown), SingleUseNode(NULL), | 487 : MultiDef(MDS_Unknown), MultiBlock(MBS_Unknown), SingleUseNode(NULL), |
| 502 SingleDefInst(NULL) {} | 488 SingleDefNode(NULL) {} |
| 503 MultiDefState getMultiDef() const { return MultiDef; } | 489 MultiDefState getMultiDef() const { return MultiDef; } |
| 504 MultiBlockState getMultiBlock() const { return MultiBlock; } | 490 MultiBlockState getMultiBlock() const { return MultiBlock; } |
| 505 const Inst *getDefinition() const { return SingleDefInst; } | 491 const Inst *getFirstDefinition() const; |
| 492 const Inst *getSingleDefinition() const; |
| 493 const InstDefList &getDefinitions() const { return Definitions; } |
| 506 const CfgNode *getNode() const { return SingleUseNode; } | 494 const CfgNode *getNode() const { return SingleUseNode; } |
| 507 void markUse(const Inst *Instr, const CfgNode *Node, bool IsFromDef, | 495 void markUse(const Inst *Instr, const CfgNode *Node, bool IsFromDef, |
| 508 bool IsImplicit); | 496 bool IsImplicit); |
| 509 void markDef(const Inst *Instr, const CfgNode *Node); | 497 void markDef(const Inst *Instr, const CfgNode *Node); |
| 510 | 498 |
| 511 private: | 499 private: |
| 512 VariableTracking &operator=(const VariableTracking &) LLVM_DELETED_FUNCTION; | 500 VariableTracking &operator=(const VariableTracking &) LLVM_DELETED_FUNCTION; |
| 513 MultiDefState MultiDef; | 501 MultiDefState MultiDef; |
| 514 MultiBlockState MultiBlock; | 502 MultiBlockState MultiBlock; |
| 515 const CfgNode *SingleUseNode; | 503 const CfgNode *SingleUseNode; |
| 516 const Inst *SingleDefInst; | 504 const CfgNode *SingleDefNode; |
| 505 // All definitions of the variable are collected here, in the order |
| 506 // encountered. Definitions in the same basic block are in |
| 507 // instruction order, but there's no guarantee for the basic block |
| 508 // order. |
| 509 InstDefList Definitions; |
| 517 }; | 510 }; |
| 518 | 511 |
| 519 // VariablesMetadata analyzes and summarizes the metadata for the | 512 // VariablesMetadata analyzes and summarizes the metadata for the |
| 520 // complete set of Variables. | 513 // complete set of Variables. |
| 521 class VariablesMetadata { | 514 class VariablesMetadata { |
| 522 public: | 515 public: |
| 523 VariablesMetadata(const Cfg *Func) : Func(Func) {} | 516 VariablesMetadata(const Cfg *Func) : Func(Func) {} |
| 517 // Initialize the state by traversing all instructions/variables in |
| 518 // the CFG. |
| 524 void init(); | 519 void init(); |
| 520 // Returns whether the given Variable is tracked in this object. It |
| 521 // should only return false if changes were made to the CFG after |
| 522 // running init(), in which case the state is stale and the results |
| 523 // shouldn't be trusted (but it may be OK e.g. for dumping). |
| 525 bool isTracked(const Variable *Var) const { | 524 bool isTracked(const Variable *Var) const { |
| 526 return Var->getIndex() < Metadata.size(); | 525 return Var->getIndex() < Metadata.size(); |
| 527 } | 526 } |
| 527 |
| 528 // Returns whether the given Variable has multiple definitions. |
| 528 bool isMultiDef(const Variable *Var) const; | 529 bool isMultiDef(const Variable *Var) const; |
| 529 const Inst *getDefinition(const Variable *Var) const; | 530 // Returns the first definition instruction of the given Variable. |
| 531 // This is only valid for variables whose definitions are all within |
| 532 // the same block, e.g. T after the lowered sequence "T=B; T+=C; |
| 533 // A=T", for which getFirstDefinition(T) would return the "T=B" |
| 534 // instruction. For variables with definitions span multiple |
| 535 // blocks, NULL is returned. |
| 536 const Inst *getFirstDefinition(const Variable *Var) const; |
| 537 // Returns the definition instruction of the given Variable, when |
| 538 // the variable has exactly one definition. Otherwise, NULL is |
| 539 // returned. |
| 540 const Inst *getSingleDefinition(const Variable *Var) const; |
| 541 // Returns the list of all definition instructions of the given |
| 542 // Variable. |
| 543 const InstDefList &getDefinitions(const Variable *Var) const; |
| 544 |
| 545 // Returns whether the given Variable is live across multiple |
| 546 // blocks. Mainly, this is used to partition Variables into |
| 547 // single-block versus multi-block sets for leveraging sparsity in |
| 548 // liveness analysis, and for implementing simple stack slot |
| 549 // coalescing. As a special case, function arguments are always |
| 550 // considered multi-block because they are live coming into the |
| 551 // entry block. |
| 530 bool isMultiBlock(const Variable *Var) const; | 552 bool isMultiBlock(const Variable *Var) const; |
| 553 // Returns the node that the given Variable is used in, assuming |
| 554 // isMultiBlock() returns false. Otherwise, NULL is returned. |
| 531 const CfgNode *getLocalUseNode(const Variable *Var) const; | 555 const CfgNode *getLocalUseNode(const Variable *Var) const; |
| 532 | 556 |
| 533 private: | 557 private: |
| 534 const Cfg *Func; | 558 const Cfg *Func; |
| 535 std::vector<VariableTracking> Metadata; | 559 std::vector<VariableTracking> Metadata; |
| 560 const static InstDefList NoDefinitions; |
| 536 VariablesMetadata(const VariablesMetadata &) LLVM_DELETED_FUNCTION; | 561 VariablesMetadata(const VariablesMetadata &) LLVM_DELETED_FUNCTION; |
| 537 VariablesMetadata &operator=(const VariablesMetadata &) LLVM_DELETED_FUNCTION; | 562 VariablesMetadata &operator=(const VariablesMetadata &) LLVM_DELETED_FUNCTION; |
| 538 }; | 563 }; |
| 539 | 564 |
| 540 } // end of namespace Ice | 565 } // end of namespace Ice |
| 541 | 566 |
| 542 #endif // SUBZERO_SRC_ICEOPERAND_H | 567 #endif // SUBZERO_SRC_ICEOPERAND_H |
| OLD | NEW |