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 25 matching lines...) Expand all Loading... |
36 kConst_Base, | 36 kConst_Base, |
37 kConstInteger32, | 37 kConstInteger32, |
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 kVariable64On32, |
46 kVariable_Target, // leave space for target-specific variable kinds | 47 kVariable_Target, // leave space for target-specific variable kinds |
47 kVariable_Max = kVariable_Target + MaxTargetKinds, | 48 kVariable_Max = kVariable_Target + MaxTargetKinds, |
48 // Target-specific operand classes use kTarget as the starting point for | 49 // Target-specific operand classes use kTarget as the starting point for |
49 // their Kind enum space. Note that the value-spaces are shared across | 50 // their Kind enum space. Note that the value-spaces are shared across |
50 // targets. To avoid confusion over the definition of shared values, an | 51 // targets. To avoid confusion over the definition of shared values, an |
51 // object specific to one target should never be passed to a different | 52 // object specific to one target should never be passed to a different |
52 // target. | 53 // target. |
53 kTarget, | 54 kTarget, |
54 kTarget_Max = std::numeric_limits<uint8_t>::max(), | 55 kTarget_Max = std::numeric_limits<uint8_t>::max(), |
55 }; | 56 }; |
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
404 Ostream &operator<<(Ostream &Str, const LiveRange &L); | 405 Ostream &operator<<(Ostream &Str, const LiveRange &L); |
405 | 406 |
406 /// Variable represents an operand that is register-allocated or | 407 /// Variable represents an operand that is register-allocated or |
407 /// stack-allocated. If it is register-allocated, it will ultimately have a | 408 /// stack-allocated. If it is register-allocated, it will ultimately have a |
408 /// non-negative RegNum field. | 409 /// non-negative RegNum field. |
409 class Variable : public Operand { | 410 class Variable : public Operand { |
410 Variable() = delete; | 411 Variable() = delete; |
411 Variable(const Variable &) = delete; | 412 Variable(const Variable &) = delete; |
412 Variable &operator=(const Variable &) = delete; | 413 Variable &operator=(const Variable &) = delete; |
413 | 414 |
414 enum RegRequirement { | 415 enum RegRequirement : uint8_t { |
415 RR_MayHaveRegister, | 416 RR_MayHaveRegister, |
416 RR_MustHaveRegister, | 417 RR_MustHaveRegister, |
417 RR_MustNotHaveRegister, | 418 RR_MustNotHaveRegister, |
418 }; | 419 }; |
419 | 420 |
420 public: | 421 public: |
421 static Variable *create(Cfg *Func, Type Ty, SizeT Index) { | 422 static Variable *create(Cfg *Func, Type Ty, SizeT Index) { |
422 return new (Func->allocate<Variable>()) Variable(kVariable, Ty, Index); | 423 return new (Func->allocate<Variable>()) Variable(kVariable, Ty, Index); |
423 } | 424 } |
424 | 425 |
425 SizeT getIndex() const { return Number; } | 426 SizeT getIndex() const { return Number; } |
426 IceString getName(const Cfg *Func) const; | 427 IceString getName(const Cfg *Func) const; |
427 void setName(Cfg *Func, const IceString &NewName) { | 428 virtual void setName(Cfg *Func, const IceString &NewName) { |
428 // Make sure that the name can only be set once. | 429 // Make sure that the name can only be set once. |
429 assert(NameIndex == Cfg::IdentifierIndexInvalid); | 430 assert(NameIndex == Cfg::IdentifierIndexInvalid); |
430 if (!NewName.empty()) | 431 if (!NewName.empty()) |
431 NameIndex = Func->addIdentifierName(NewName); | 432 NameIndex = Func->addIdentifierName(NewName); |
432 } | 433 } |
433 | 434 |
434 bool getIsArg() const { return IsArgument; } | 435 bool getIsArg() const { return IsArgument; } |
435 void setIsArg(bool Val = true) { IsArgument = Val; } | 436 virtual void setIsArg(bool Val = true) { IsArgument = Val; } |
436 bool getIsImplicitArg() const { return IsImplicitArgument; } | 437 bool getIsImplicitArg() const { return IsImplicitArgument; } |
437 void setIsImplicitArg(bool Val = true) { IsImplicitArgument = Val; } | 438 void setIsImplicitArg(bool Val = true) { IsImplicitArgument = Val; } |
438 | 439 |
439 void setIgnoreLiveness() { IgnoreLiveness = true; } | 440 void setIgnoreLiveness() { IgnoreLiveness = true; } |
440 bool getIgnoreLiveness() const { return IgnoreLiveness; } | 441 bool getIgnoreLiveness() const { return IgnoreLiveness; } |
441 | 442 |
442 int32_t getStackOffset() const { return StackOffset; } | 443 int32_t getStackOffset() const { return StackOffset; } |
443 void setStackOffset(int32_t Offset) { StackOffset = Offset; } | 444 void setStackOffset(int32_t Offset) { StackOffset = Offset; } |
444 | 445 |
445 static const int32_t NoRegister = -1; | 446 static const int32_t NoRegister = -1; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
478 } | 479 } |
479 bool rangeOverlaps(const Variable *Other) const { | 480 bool rangeOverlaps(const Variable *Other) const { |
480 const bool UseTrimmed = true; | 481 const bool UseTrimmed = true; |
481 return Live.overlaps(Other->Live, UseTrimmed); | 482 return Live.overlaps(Other->Live, UseTrimmed); |
482 } | 483 } |
483 bool rangeOverlapsStart(const Variable *Other) const { | 484 bool rangeOverlapsStart(const Variable *Other) const { |
484 const bool UseTrimmed = true; | 485 const bool UseTrimmed = true; |
485 return Live.overlapsInst(Other->Live.getStart(), UseTrimmed); | 486 return Live.overlapsInst(Other->Live.getStart(), UseTrimmed); |
486 } | 487 } |
487 | 488 |
488 Variable *getLo() const { return LoVar; } | |
489 Variable *getHi() const { return HiVar; } | |
490 void setLoHi(Variable *Lo, Variable *Hi) { | |
491 assert(LoVar == nullptr); | |
492 assert(HiVar == nullptr); | |
493 LoVar = Lo; | |
494 HiVar = Hi; | |
495 } | |
496 /// Creates a temporary copy of the variable with a different type. Used | 489 /// Creates a temporary copy of the variable with a different type. Used |
497 /// primarily for syntactic correctness of textual assembly emission. Note | 490 /// primarily for syntactic correctness of textual assembly emission. Note |
498 /// that only basic information is copied, in particular not IsArgument, | 491 /// that only basic information is copied, in particular not IsArgument, |
499 /// IsImplicitArgument, IgnoreLiveness, RegNumTmp, Live, LoVar, HiVar, | 492 /// IsImplicitArgument, IgnoreLiveness, RegNumTmp, Live, LoVar, HiVar, |
500 /// VarsReal. | 493 /// VarsReal. |
501 Variable *asType(Type Ty); | 494 Variable *asType(Type Ty); |
502 | 495 |
503 void emit(const Cfg *Func) const override; | 496 void emit(const Cfg *Func) const override; |
504 using Operand::dump; | 497 using Operand::dump; |
505 void dump(const Cfg *Func, Ostream &Str) const override; | 498 void dump(const Cfg *Func, Ostream &Str) const override; |
(...skipping 16 matching lines...) Expand all Loading... |
522 /// Number is unique across all variables, and is used as a (bit)vector index | 515 /// Number is unique across all variables, and is used as a (bit)vector index |
523 /// for liveness analysis. | 516 /// for liveness analysis. |
524 const SizeT Number; | 517 const SizeT Number; |
525 Cfg::IdentifierIndexType NameIndex = Cfg::IdentifierIndexInvalid; | 518 Cfg::IdentifierIndexType NameIndex = Cfg::IdentifierIndexInvalid; |
526 bool IsArgument = false; | 519 bool IsArgument = false; |
527 bool IsImplicitArgument = false; | 520 bool IsImplicitArgument = false; |
528 /// IgnoreLiveness means that the variable should be ignored when constructing | 521 /// IgnoreLiveness means that the variable should be ignored when constructing |
529 /// and validating live ranges. This is usually reserved for the stack | 522 /// and validating live ranges. This is usually reserved for the stack |
530 /// pointer. | 523 /// pointer. |
531 bool IgnoreLiveness = false; | 524 bool IgnoreLiveness = false; |
532 /// StackOffset is the canonical location on stack (only if RegNum==NoRegister | 525 RegRequirement RegRequirement = RR_MayHaveRegister; |
533 /// || IsArgument). | |
534 int32_t StackOffset = 0; | |
535 /// RegNum is the allocated register, or NoRegister if it isn't | 526 /// RegNum is the allocated register, or NoRegister if it isn't |
536 /// register-allocated. | 527 /// register-allocated. |
537 int32_t RegNum = NoRegister; | 528 int32_t RegNum = NoRegister; |
538 /// RegNumTmp is the tentative assignment during register allocation. | 529 /// RegNumTmp is the tentative assignment during register allocation. |
539 int32_t RegNumTmp = NoRegister; | 530 int32_t RegNumTmp = NoRegister; |
540 RegRequirement RegRequirement = RR_MayHaveRegister; | 531 /// StackOffset is the canonical location on stack (only if |
| 532 /// RegNum==NoRegister || IsArgument). |
| 533 int32_t StackOffset = 0; |
541 LiveRange Live; | 534 LiveRange Live; |
542 // LoVar and HiVar are needed for lowering from 64 to 32 bits. When lowering | 535 /// VarsReal (and Operand::Vars) are set up such that Vars[0] == this. |
543 // from I64 to I32 on a 32-bit architecture, we split the variable into two | 536 Variable *VarsReal[1]; |
544 // machine-size pieces. LoVar is the low-order machine-size portion, and | 537 }; |
545 // HiVar is the remaining high-order portion. | 538 |
546 // TODO: It's wasteful to penalize all variables on all targets this way; use | 539 // Variable64On32 represents a 64-bit variable on a 32-bit architecture. In |
547 // a sparser representation. It's also wasteful for a 64-bit target. | 540 // this situation the variable must be split into a low and a high word. |
| 541 class Variable64On32 : public Variable { |
| 542 Variable64On32() = delete; |
| 543 Variable64On32(const Variable64On32 &) = delete; |
| 544 Variable64On32 &operator=(const Variable64On32 &) = delete; |
| 545 |
| 546 public: |
| 547 static Variable64On32 *create(Cfg *Func, Type Ty, SizeT Index) { |
| 548 return new (Func->allocate<Variable64On32>()) Variable64On32( |
| 549 kVariable64On32, Ty, Index); |
| 550 } |
| 551 |
| 552 void setName(Cfg *Func, const IceString &NewName) override { |
| 553 Variable::setName(Func, NewName); |
| 554 if (LoVar && HiVar) { |
| 555 LoVar->setName(Func, getName(Func) + "__lo"); |
| 556 HiVar->setName(Func, getName(Func) + "__hi"); |
| 557 } |
| 558 } |
| 559 |
| 560 void setIsArg(bool Val = true) override { |
| 561 Variable::setIsArg(Val); |
| 562 if (LoVar && HiVar) { |
| 563 LoVar->setIsArg(Val); |
| 564 HiVar->setIsArg(Val); |
| 565 } |
| 566 } |
| 567 |
| 568 Variable *getLo() const { |
| 569 assert(LoVar != nullptr); |
| 570 return LoVar; |
| 571 } |
| 572 Variable *getHi() const { |
| 573 assert(HiVar != nullptr); |
| 574 return HiVar; |
| 575 } |
| 576 |
| 577 void initHiLo(Cfg *Func) { |
| 578 assert(LoVar == nullptr); |
| 579 assert(HiVar == nullptr); |
| 580 LoVar = Func->makeVariable(IceType_i32); |
| 581 HiVar = Func->makeVariable(IceType_i32); |
| 582 LoVar->setIsArg(getIsArg()); |
| 583 HiVar->setIsArg(getIsArg()); |
| 584 LoVar->setName(Func, getName(Func) + "__lo"); |
| 585 HiVar->setName(Func, getName(Func) + "__hi"); |
| 586 } |
| 587 |
| 588 static bool classof(const Operand *Operand) { |
| 589 OperandKind Kind = Operand->getKind(); |
| 590 return Kind == kVariable64On32; |
| 591 } |
| 592 |
| 593 protected: |
| 594 Variable64On32(OperandKind K, Type Ty, SizeT Index) |
| 595 : Variable(K, Ty, Index) { |
| 596 assert(typeWidthInBytes(Ty) == 8); |
| 597 } |
| 598 |
548 Variable *LoVar = nullptr; | 599 Variable *LoVar = nullptr; |
549 Variable *HiVar = nullptr; | 600 Variable *HiVar = nullptr; |
550 /// VarsReal (and Operand::Vars) are set up such that Vars[0] == this. | |
551 Variable *VarsReal[1]; | |
552 }; | 601 }; |
553 | 602 |
554 enum MetadataKind { | 603 enum MetadataKind { |
555 VMK_Uses, /// Track only uses, not defs | 604 VMK_Uses, /// Track only uses, not defs |
556 VMK_SingleDefs, /// Track uses+defs, but only record single def | 605 VMK_SingleDefs, /// Track uses+defs, but only record single def |
557 VMK_All /// Track uses+defs, including full def list | 606 VMK_All /// Track uses+defs, including full def list |
558 }; | 607 }; |
559 using InstDefList = CfgVector<const Inst *>; | 608 using InstDefList = CfgVector<const Inst *>; |
560 | 609 |
561 /// VariableTracking tracks the metadata for a single variable. It is | 610 /// VariableTracking tracks the metadata for a single variable. It is |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
652 private: | 701 private: |
653 const Cfg *Func; | 702 const Cfg *Func; |
654 MetadataKind Kind; | 703 MetadataKind Kind; |
655 CfgVector<VariableTracking> Metadata; | 704 CfgVector<VariableTracking> Metadata; |
656 const static InstDefList NoDefinitions; | 705 const static InstDefList NoDefinitions; |
657 }; | 706 }; |
658 | 707 |
659 } // end of namespace Ice | 708 } // end of namespace Ice |
660 | 709 |
661 #endif // SUBZERO_SRC_ICEOPERAND_H | 710 #endif // SUBZERO_SRC_ICEOPERAND_H |
OLD | NEW |