Chromium Code Reviews| 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 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 340 Ostream &operator<<(Ostream &Str, const LiveRange &L); | 340 Ostream &operator<<(Ostream &Str, const LiveRange &L); |
| 341 | 341 |
| 342 // Variable represents an operand that is register-allocated or | 342 // Variable represents an operand that is register-allocated or |
| 343 // stack-allocated. If it is register-allocated, it will ultimately | 343 // stack-allocated. If it is register-allocated, it will ultimately |
| 344 // have a non-negative RegNum field. | 344 // have a non-negative RegNum field. |
| 345 class Variable : public Operand { | 345 class Variable : public Operand { |
| 346 Variable(const Variable &) LLVM_DELETED_FUNCTION; | 346 Variable(const Variable &) LLVM_DELETED_FUNCTION; |
| 347 Variable &operator=(const Variable &) LLVM_DELETED_FUNCTION; | 347 Variable &operator=(const Variable &) LLVM_DELETED_FUNCTION; |
| 348 | 348 |
| 349 public: | 349 public: |
| 350 static Variable *create(Cfg *Func, Type Ty, const CfgNode *Node, SizeT Index, | 350 static Variable *create(Cfg *Func, Type Ty, SizeT Index, |
| 351 const IceString &Name) { | 351 const IceString &Name) { |
| 352 return new (Func->allocate<Variable>()) | 352 return new (Func->allocate<Variable>()) |
| 353 Variable(kVariable, Ty, Node, Index, Name); | 353 Variable(kVariable, Ty, Index, Name); |
| 354 } | 354 } |
| 355 | 355 |
| 356 SizeT getIndex() const { return Number; } | 356 SizeT getIndex() const { return Number; } |
| 357 IceString getName() const; | 357 IceString getName() const; |
| 358 void setName(IceString &NewName) { | 358 void setName(IceString &NewName) { |
| 359 // Make sure that the name can only be set once. | 359 // Make sure that the name can only be set once. |
| 360 assert(Name.empty()); | 360 assert(Name.empty()); |
| 361 Name = NewName; | 361 Name = NewName; |
| 362 } | 362 } |
| 363 | 363 |
| 364 Inst *getDefinition() const { return DefInst; } | |
| 365 void setDefinition(Inst *Inst, const CfgNode *Node); | |
| 366 void replaceDefinition(Inst *Inst, const CfgNode *Node); | |
| 367 | |
| 368 const CfgNode *getLocalUseNode() const { return DefNode; } | |
| 369 bool isMultiblockLife() const { return (DefNode == NULL); } | |
| 370 void setUse(const Inst *Inst, const CfgNode *Node); | |
| 371 | |
| 372 // Multidef means a variable is non-SSA and has multiple defining | |
| 373 // instructions. Currently this classification is limited to SSA | |
| 374 // lowering temporaries where the definitions are in different basic | |
| 375 // blocks, and it is not maintained during target lowering when the | |
| 376 // same temporary may be updated in consecutive instructions. | |
| 377 bool getIsMultidef() const { return IsMultidef; } | |
| 378 void setIsMultidef() { IsMultidef = true; } | |
| 379 | |
| 380 bool getIsArg() const { return IsArgument; } | 364 bool getIsArg() const { return IsArgument; } |
| 381 void setIsArg(Cfg *Func, bool IsArg = true); | 365 void setIsArg(bool Val = true) { IsArgument = Val; } |
| 382 | 366 |
| 383 int32_t getStackOffset() const { return StackOffset; } | 367 int32_t getStackOffset() const { return StackOffset; } |
| 384 void setStackOffset(int32_t Offset) { StackOffset = Offset; } | 368 void setStackOffset(int32_t Offset) { StackOffset = Offset; } |
| 385 | 369 |
| 386 static const int32_t NoRegister = -1; | 370 static const int32_t NoRegister = -1; |
| 387 bool hasReg() const { return getRegNum() != NoRegister; } | 371 bool hasReg() const { return getRegNum() != NoRegister; } |
| 388 int32_t getRegNum() const { return RegNum; } | 372 int32_t getRegNum() const { return RegNum; } |
| 389 void setRegNum(int32_t NewRegNum) { | 373 void setRegNum(int32_t NewRegNum) { |
| 390 // Regnum shouldn't be set more than once. | 374 // Regnum shouldn't be set more than once. |
| 391 assert(!hasReg() || RegNum == NewRegNum); | 375 assert(!hasReg() || RegNum == NewRegNum); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 440 | 424 |
| 441 static bool classof(const Operand *Operand) { | 425 static bool classof(const Operand *Operand) { |
| 442 OperandKind Kind = Operand->getKind(); | 426 OperandKind Kind = Operand->getKind(); |
| 443 return Kind >= kVariable && Kind <= kVariable_Num; | 427 return Kind >= kVariable && Kind <= kVariable_Num; |
| 444 } | 428 } |
| 445 | 429 |
| 446 // The destructor is public because of the asType() method. | 430 // The destructor is public because of the asType() method. |
| 447 virtual ~Variable() {} | 431 virtual ~Variable() {} |
| 448 | 432 |
| 449 protected: | 433 protected: |
| 450 Variable(OperandKind K, Type Ty, const CfgNode *Node, SizeT Index, | 434 Variable(OperandKind K, Type Ty, SizeT Index, const IceString &Name) |
| 451 const IceString &Name) | 435 : Operand(K, Ty), Number(Index), Name(Name), IsArgument(false), |
| 452 : Operand(K, Ty), Number(Index), Name(Name), DefInst(NULL), DefNode(Node), | 436 StackOffset(0), RegNum(NoRegister), RegNumTmp(NoRegister), Weight(1), |
| 453 IsMultidef(false), IsArgument(false), StackOffset(0), | |
| 454 RegNum(NoRegister), RegNumTmp(NoRegister), Weight(1), | |
| 455 RegisterPreference(NULL), AllowRegisterOverlap(false), LoVar(NULL), | 437 RegisterPreference(NULL), AllowRegisterOverlap(false), LoVar(NULL), |
| 456 HiVar(NULL) { | 438 HiVar(NULL) { |
| 457 Vars = VarsReal; | 439 Vars = VarsReal; |
| 458 Vars[0] = this; | 440 Vars[0] = this; |
| 459 NumVars = 1; | 441 NumVars = 1; |
| 460 } | 442 } |
| 461 // Number is unique across all variables, and is used as a | 443 // Number is unique across all variables, and is used as a |
| 462 // (bit)vector index for liveness analysis. | 444 // (bit)vector index for liveness analysis. |
| 463 const SizeT Number; | 445 const SizeT Number; |
| 464 // Name is optional. | 446 // Name is optional. |
| 465 IceString Name; | 447 IceString Name; |
| 466 // DefInst is the instruction that produces this variable as its | |
| 467 // dest. | |
| 468 Inst *DefInst; | |
| 469 // DefNode is the node where this variable was produced, and is | |
| 470 // reset to NULL if it is used outside that node. This is used for | |
| 471 // detecting isMultiblockLife(). TODO: Collapse this to a single | |
| 472 // bit and use a separate pass to calculate the values across the | |
| 473 // Cfg. This saves space in the Variable, and removes the fragility | |
| 474 // of incrementally computing and maintaining the information. | |
| 475 const CfgNode *DefNode; | |
| 476 bool IsMultidef; | |
| 477 bool IsArgument; | 448 bool IsArgument; |
| 478 // StackOffset is the canonical location on stack (only if | 449 // StackOffset is the canonical location on stack (only if |
| 479 // RegNum<0 || IsArgument). | 450 // RegNum<0 || IsArgument). |
| 480 int32_t StackOffset; | 451 int32_t StackOffset; |
| 481 // RegNum is the allocated register, or NoRegister if it isn't | 452 // RegNum is the allocated register, or NoRegister if it isn't |
| 482 // register-allocated. | 453 // register-allocated. |
| 483 int32_t RegNum; | 454 int32_t RegNum; |
| 484 // RegNumTmp is the tentative assignment during register allocation. | 455 // RegNumTmp is the tentative assignment during register allocation. |
| 485 int32_t RegNumTmp; | 456 int32_t RegNumTmp; |
| 486 RegWeight Weight; // Register allocation priority | 457 RegWeight Weight; // Register allocation priority |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 502 // portion. TODO: It's wasteful to penalize all variables on all | 473 // portion. TODO: It's wasteful to penalize all variables on all |
| 503 // targets this way; use a sparser representation. It's also | 474 // targets this way; use a sparser representation. It's also |
| 504 // wasteful for a 64-bit target. | 475 // wasteful for a 64-bit target. |
| 505 Variable *LoVar; | 476 Variable *LoVar; |
| 506 Variable *HiVar; | 477 Variable *HiVar; |
| 507 // VarsReal (and Operand::Vars) are set up such that Vars[0] == | 478 // VarsReal (and Operand::Vars) are set up such that Vars[0] == |
| 508 // this. | 479 // this. |
| 509 Variable *VarsReal[1]; | 480 Variable *VarsReal[1]; |
| 510 }; | 481 }; |
| 511 | 482 |
| 483 // VariableTracking tracks the metadata for a single variable. | |
| 484 class VariableTracking { | |
| 485 public: | |
| 486 enum MultiDefState { | |
| 487 // TODO(stichnot): Consider using just a simple counter. | |
| 488 MDS_Unknown, | |
| 489 MDS_SingleDef, | |
| 490 MDS_MultiDef | |
| 491 }; | |
| 492 enum MultiBlockState { | |
| 493 MBS_Unknown, | |
| 494 MBS_SingleBlock, | |
| 495 MBS_MultiBlock | |
| 496 }; | |
| 497 VariableTracking() | |
| 498 : MultiDef(MDS_Unknown), MultiBlock(MBS_Unknown), SingleUseNode(NULL), | |
| 499 SingleDefInst(NULL) {} | |
| 500 MultiDefState getMultiDef() const { return MultiDef; } | |
| 501 MultiBlockState getMultiBlock() const { return MultiBlock; } | |
| 502 const Inst *getDefinition() const { return SingleDefInst; } | |
| 503 const CfgNode *getNode() const { return SingleUseNode; } | |
| 504 void markUse(const Inst *Instr, const CfgNode *Node, bool IsFromDef) { | |
|
jvoung (off chromium)
2014/09/22 17:07:29
Should markUse not be inlined, since it seems like
Jim Stichnoth
2014/09/22 21:00:46
Done, and the same for markDef() for symmetry.
| |
| 505 // TODO(stichnot): If the use occurs as a source operand in the | |
| 506 // first instruction of the block, and its definition is in this | |
| 507 // block's only predecessor, we might consider not marking this as | |
| 508 // a separate use. This may also apply if it's the first | |
| 509 // instruction of the block that actually uses a Variable. | |
| 510 // assert(Node); | |
|
jvoung (off chromium)
2014/09/22 17:07:29
assert(Node); is commented out -- just remove?
Th
Jim Stichnoth
2014/09/22 21:00:46
VariablesMetadata::init() passes in Node=NULL for
| |
| 511 switch (MultiBlock) { | |
| 512 case MBS_Unknown: | |
| 513 MultiBlock = MBS_SingleBlock; | |
| 514 SingleUseNode = Node; | |
| 515 break; | |
| 516 case MBS_SingleBlock: | |
| 517 if (SingleUseNode != Node) { | |
| 518 MultiBlock = MBS_MultiBlock; | |
| 519 SingleUseNode = NULL; | |
| 520 } | |
| 521 break; | |
| 522 case MBS_MultiBlock: | |
| 523 break; | |
| 524 } | |
| 525 // A phi source variable conservatively needs to be marked as | |
| 526 // multi-block, even if its definition is in the same block. This | |
| 527 // is because there can be additional control flow before | |
| 528 // branching back to this node, and the variable is live | |
| 529 // throughout those nodes. | |
| 530 if (Node == NULL || (!IsFromDef && Instr && llvm::isa<InstPhi>(Instr))) { | |
| 531 MultiBlock = MBS_MultiBlock; | |
| 532 SingleUseNode = NULL; | |
| 533 } | |
| 534 } | |
| 535 void markDef(const Inst *Instr, const CfgNode *Node) { | |
| 536 // TODO(stichnot): If the definition occurs in the last | |
| 537 // instruction of the block, consider not marking this as a | |
| 538 // separate use. But be careful not to omit all uses of the | |
| 539 // variable if markDef() and markUse() both use this optimization. | |
| 540 const bool IsFromDef = true; | |
| 541 markUse(Instr, Node, IsFromDef); | |
| 542 switch (MultiDef) { | |
| 543 case MDS_Unknown: | |
| 544 MultiDef = MDS_SingleDef; | |
| 545 SingleDefInst = Instr; | |
| 546 break; | |
| 547 case MDS_SingleDef: | |
| 548 MultiDef = MDS_MultiDef; | |
| 549 SingleDefInst = NULL; | |
| 550 break; | |
| 551 case MDS_MultiDef: | |
| 552 break; | |
| 553 } | |
| 554 } | |
| 555 | |
| 556 private: | |
| 557 VariableTracking &operator=(const VariableTracking &) LLVM_DELETED_FUNCTION; | |
| 558 MultiDefState MultiDef; | |
| 559 MultiBlockState MultiBlock; | |
| 560 const CfgNode *SingleUseNode; | |
| 561 const Inst *SingleDefInst; | |
| 562 }; | |
| 563 | |
| 564 // VariablesMetadata analyzes and summarizes the metadata for the | |
| 565 // complete set of Variables. | |
| 566 class VariablesMetadata { | |
| 567 public: | |
| 568 VariablesMetadata(const Cfg *Func) : Func(Func) {} | |
| 569 void init(); | |
| 570 bool isTracked(const Variable *Var) const { | |
| 571 return Var->getIndex() < Metadata.size(); | |
| 572 } | |
| 573 bool isMultiDef(const Variable *Var) const; | |
| 574 const Inst *getDefinition(const Variable *Var) const; | |
| 575 bool isMultiBlock(const Variable *Var) const; | |
| 576 const CfgNode *getLocalUseNode(const Variable *Var) const; | |
| 577 | |
| 578 private: | |
| 579 const Cfg *Func; | |
| 580 std::vector<VariableTracking> Metadata; | |
| 581 VariablesMetadata(const VariablesMetadata &) LLVM_DELETED_FUNCTION; | |
| 582 VariablesMetadata &operator=(const VariablesMetadata &) LLVM_DELETED_FUNCTION; | |
| 583 }; | |
| 584 | |
| 512 } // end of namespace Ice | 585 } // end of namespace Ice |
| 513 | 586 |
| 514 #endif // SUBZERO_SRC_ICEOPERAND_H | 587 #endif // SUBZERO_SRC_ICEOPERAND_H |
| OLD | NEW |