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 /// \file | 10 /// \file |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 325 const static uint32_t Zero = 0; /// Force regalloc NOT to give a register | 325 const static uint32_t Zero = 0; /// Force regalloc NOT to give a register |
| 326 void addWeight(uint32_t Delta) { | 326 void addWeight(uint32_t Delta) { |
| 327 if (Delta == Inf) | 327 if (Delta == Inf) |
| 328 Weight = Inf; | 328 Weight = Inf; |
| 329 else if (Weight != Inf) | 329 else if (Weight != Inf) |
| 330 Weight += Delta; | 330 Weight += Delta; |
| 331 } | 331 } |
| 332 void addWeight(const RegWeight &Other) { addWeight(Other.Weight); } | 332 void addWeight(const RegWeight &Other) { addWeight(Other.Weight); } |
| 333 void setWeight(uint32_t Val) { Weight = Val; } | 333 void setWeight(uint32_t Val) { Weight = Val; } |
| 334 uint32_t getWeight() const { return Weight; } | 334 uint32_t getWeight() const { return Weight; } |
| 335 bool isInf() const { return Weight == Inf; } | 335 bool isInf() const { return Weight == Inf; } |
|
jvoung (off chromium)
2015/08/26 21:45:46
It looks like the isInf() method isn't used anymor
ascull
2015/08/26 22:06:39
Done.
| |
| 336 bool isZero() const { return Weight == Zero; } | 336 bool isZero() const { return Weight == Zero; } |
|
jvoung (off chromium)
2015/08/26 21:45:46
similar for isZero
ascull
2015/08/26 22:06:39
Done.
| |
| 337 | 337 |
| 338 private: | 338 private: |
| 339 uint32_t Weight = 0; | 339 uint32_t Weight = 0; |
| 340 }; | 340 }; |
| 341 Ostream &operator<<(Ostream &Str, const RegWeight &W); | 341 Ostream &operator<<(Ostream &Str, const RegWeight &W); |
| 342 bool operator<(const RegWeight &A, const RegWeight &B); | 342 bool operator<(const RegWeight &A, const RegWeight &B); |
| 343 bool operator<=(const RegWeight &A, const RegWeight &B); | 343 bool operator<=(const RegWeight &A, const RegWeight &B); |
| 344 bool operator==(const RegWeight &A, const RegWeight &B); | 344 bool operator==(const RegWeight &A, const RegWeight &B); |
| 345 | 345 |
| 346 enum RegRequirement { | |
|
jvoung (off chromium)
2015/08/26 21:45:47
Should this enum be scoped in RegWeight? (near the
ascull
2015/08/26 22:06:39
It is separate from RegWeight which is an 'infinit
| |
| 347 ShouldHaveRegister, | |
| 348 MustHaveRegister, | |
| 349 MustNotHaveRegister, | |
| 350 }; | |
| 351 | |
| 346 /// LiveRange is a set of instruction number intervals representing | 352 /// LiveRange is a set of instruction number intervals representing |
| 347 /// a variable's live range. Generally there is one interval per basic | 353 /// a variable's live range. Generally there is one interval per basic |
| 348 /// block where the variable is live, but adjacent intervals get | 354 /// block where the variable is live, but adjacent intervals get |
| 349 /// coalesced into a single interval. LiveRange also includes a | 355 /// coalesced into a single interval. LiveRange also includes a |
| 350 /// weight, in case e.g. we want a live range to have higher weight | 356 /// weight, in case e.g. we want a live range to have higher weight |
|
jvoung (off chromium)
2015/08/26 21:45:46
LiveRange doesn't include the weight field anymore
ascull
2015/08/26 22:06:39
Yes, the weight is managed by the Variable which,
| |
| 351 /// inside a loop. | 357 /// inside a loop. |
| 352 class LiveRange { | 358 class LiveRange { |
| 353 public: | 359 public: |
| 354 LiveRange() = default; | 360 LiveRange() = default; |
| 355 /// Special constructor for building a kill set. The advantage is | 361 /// Special constructor for building a kill set. The advantage is |
| 356 /// that we can reserve the right amount of space in advance. | 362 /// that we can reserve the right amount of space in advance. |
| 357 explicit LiveRange(const std::vector<InstNumberT> &Kills) { | 363 explicit LiveRange(const std::vector<InstNumberT> &Kills) { |
| 358 Range.reserve(Kills.size()); | 364 Range.reserve(Kills.size()); |
| 359 for (InstNumberT I : Kills) | 365 for (InstNumberT I : Kills) |
| 360 addSegment(I, I); | 366 addSegment(I, I); |
| 361 } | 367 } |
| 362 LiveRange(const LiveRange &) = default; | 368 LiveRange(const LiveRange &) = default; |
| 363 LiveRange &operator=(const LiveRange &) = default; | 369 LiveRange &operator=(const LiveRange &) = default; |
| 364 | 370 |
| 365 void reset() { | 371 void reset() { |
| 366 Range.clear(); | 372 Range.clear(); |
| 367 Weight.setWeight(0); | |
| 368 untrim(); | 373 untrim(); |
| 369 } | 374 } |
| 370 void addSegment(InstNumberT Start, InstNumberT End); | 375 void addSegment(InstNumberT Start, InstNumberT End); |
| 371 | 376 |
| 372 bool endsBefore(const LiveRange &Other) const; | 377 bool endsBefore(const LiveRange &Other) const; |
| 373 bool overlaps(const LiveRange &Other, bool UseTrimmed = false) const; | 378 bool overlaps(const LiveRange &Other, bool UseTrimmed = false) const; |
| 374 bool overlapsInst(InstNumberT OtherBegin, bool UseTrimmed = false) const; | 379 bool overlapsInst(InstNumberT OtherBegin, bool UseTrimmed = false) const; |
| 375 bool containsValue(InstNumberT Value, bool IsDest) const; | 380 bool containsValue(InstNumberT Value, bool IsDest) const; |
| 376 bool isEmpty() const { return Range.empty(); } | 381 bool isEmpty() const { return Range.empty(); } |
| 377 InstNumberT getStart() const { | 382 InstNumberT getStart() const { |
| 378 return Range.empty() ? -1 : Range.begin()->first; | 383 return Range.empty() ? -1 : Range.begin()->first; |
| 379 } | 384 } |
| 380 InstNumberT getEnd() const { | 385 InstNumberT getEnd() const { |
| 381 return Range.empty() ? -1 : Range.rbegin()->second; | 386 return Range.empty() ? -1 : Range.rbegin()->second; |
| 382 } | 387 } |
| 383 | 388 |
| 384 void untrim() { TrimmedBegin = Range.begin(); } | 389 void untrim() { TrimmedBegin = Range.begin(); } |
| 385 void trim(InstNumberT Lower); | 390 void trim(InstNumberT Lower); |
| 386 | 391 |
| 387 RegWeight getWeight() const { return Weight; } | |
| 388 void setWeight(const RegWeight &NewWeight) { Weight = NewWeight; } | |
| 389 void addWeight(uint32_t Delta) { Weight.addWeight(Delta); } | |
| 390 void dump(Ostream &Str) const; | 392 void dump(Ostream &Str) const; |
| 391 | 393 |
| 392 private: | 394 private: |
| 393 typedef std::pair<InstNumberT, InstNumberT> RangeElementType; | 395 typedef std::pair<InstNumberT, InstNumberT> RangeElementType; |
| 394 /// RangeType is arena-allocated from the Cfg's allocator. | 396 /// RangeType is arena-allocated from the Cfg's allocator. |
| 395 typedef std::vector<RangeElementType, CfgLocalAllocator<RangeElementType>> | 397 typedef std::vector<RangeElementType, CfgLocalAllocator<RangeElementType>> |
| 396 RangeType; | 398 RangeType; |
| 397 RangeType Range; | 399 RangeType Range; |
| 398 RegWeight Weight = RegWeight(0); | |
| 399 /// TrimmedBegin is an optimization for the overlaps() computation. | 400 /// TrimmedBegin is an optimization for the overlaps() computation. |
| 400 /// Since the linear-scan algorithm always calls it as overlaps(Cur) | 401 /// Since the linear-scan algorithm always calls it as overlaps(Cur) |
| 401 /// and Cur advances monotonically according to live range start, we | 402 /// and Cur advances monotonically according to live range start, we |
| 402 /// can optimize overlaps() by ignoring all segments that end before | 403 /// can optimize overlaps() by ignoring all segments that end before |
| 403 /// the start of Cur's range. The linear-scan code enables this by | 404 /// the start of Cur's range. The linear-scan code enables this by |
| 404 /// calling trim() on the ranges of interest as Cur advances. Note | 405 /// calling trim() on the ranges of interest as Cur advances. Note |
| 405 /// that linear-scan also has to initialize TrimmedBegin at the | 406 /// that linear-scan also has to initialize TrimmedBegin at the |
| 406 /// beginning by calling untrim(). | 407 /// beginning by calling untrim(). |
| 407 RangeType::const_iterator TrimmedBegin; | 408 RangeType::const_iterator TrimmedBegin; |
| 408 }; | 409 }; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 447 int32_t getRegNum() const { return RegNum; } | 448 int32_t getRegNum() const { return RegNum; } |
| 448 void setRegNum(int32_t NewRegNum) { | 449 void setRegNum(int32_t NewRegNum) { |
| 449 // Regnum shouldn't be set more than once. | 450 // Regnum shouldn't be set more than once. |
| 450 assert(!hasReg() || RegNum == NewRegNum); | 451 assert(!hasReg() || RegNum == NewRegNum); |
| 451 RegNum = NewRegNum; | 452 RegNum = NewRegNum; |
| 452 } | 453 } |
| 453 bool hasRegTmp() const { return getRegNumTmp() != NoRegister; } | 454 bool hasRegTmp() const { return getRegNumTmp() != NoRegister; } |
| 454 int32_t getRegNumTmp() const { return RegNumTmp; } | 455 int32_t getRegNumTmp() const { return RegNumTmp; } |
| 455 void setRegNumTmp(int32_t NewRegNum) { RegNumTmp = NewRegNum; } | 456 void setRegNumTmp(int32_t NewRegNum) { RegNumTmp = NewRegNum; } |
| 456 | 457 |
| 457 RegWeight getWeight() const { return Weight; } | 458 RegWeight getWeight() const { |
| 458 void setWeight(uint32_t NewWeight) { Weight = RegWeight(NewWeight); } | 459 return RegWeight(mustHaveReg() ? RegWeight::Inf : mustNotHaveReg() |
| 459 void setWeightInfinite() { setWeight(RegWeight::Inf); } | 460 ? RegWeight::Zero |
| 461 : UseWeight); | |
| 462 } | |
| 463 void resetUses() { UseWeight = 0; } | |
| 464 void addUse(uint32_t Weight) { UseWeight += Weight; } | |
| 465 | |
| 466 void setMustHaveReg() { RegRequirement = MustHaveRegister; } | |
| 467 bool mustHaveReg() const { return RegRequirement == MustHaveRegister; } | |
| 468 void setMustNotHaveReg() { RegRequirement = MustNotHaveRegister; } | |
| 469 bool mustNotHaveReg() const { return RegRequirement == MustNotHaveRegister; } | |
| 460 | 470 |
| 461 LiveRange &getLiveRange() { return Live; } | 471 LiveRange &getLiveRange() { return Live; } |
| 462 const LiveRange &getLiveRange() const { return Live; } | 472 const LiveRange &getLiveRange() const { return Live; } |
| 463 void setLiveRange(const LiveRange &Range) { Live = Range; } | 473 void setLiveRange(const LiveRange &Range) { Live = Range; } |
| 464 void resetLiveRange() { Live.reset(); } | 474 void resetLiveRange() { |
| 475 Live.reset(); | |
| 476 resetUses(); | |
| 477 } | |
| 465 void addLiveRange(InstNumberT Start, InstNumberT End, uint32_t WeightDelta) { | 478 void addLiveRange(InstNumberT Start, InstNumberT End, uint32_t WeightDelta) { |
| 466 assert(!getIgnoreLiveness()); | 479 assert(!getIgnoreLiveness()); |
| 467 assert(WeightDelta != RegWeight::Inf); | 480 assert(WeightDelta != RegWeight::Inf); |
|
jvoung (off chromium)
2015/08/26 21:45:46
WeightDelta is only used in assert builds now and
ascull
2015/08/26 22:06:39
Done.
| |
| 468 Live.addSegment(Start, End); | 481 Live.addSegment(Start, End); |
| 469 if (Weight.isInf()) | |
| 470 Live.setWeight(RegWeight(RegWeight::Inf)); | |
| 471 else | |
| 472 Live.addWeight(WeightDelta * Weight.getWeight()); | |
| 473 } | |
| 474 void setLiveRangeInfiniteWeight() { | |
| 475 Live.setWeight(RegWeight(RegWeight::Inf)); | |
| 476 } | 482 } |
| 477 void trimLiveRange(InstNumberT Start) { Live.trim(Start); } | 483 void trimLiveRange(InstNumberT Start) { Live.trim(Start); } |
| 478 void untrimLiveRange() { Live.untrim(); } | 484 void untrimLiveRange() { Live.untrim(); } |
| 479 bool rangeEndsBefore(const Variable *Other) const { | 485 bool rangeEndsBefore(const Variable *Other) const { |
| 480 return Live.endsBefore(Other->Live); | 486 return Live.endsBefore(Other->Live); |
| 481 } | 487 } |
| 482 bool rangeOverlaps(const Variable *Other) const { | 488 bool rangeOverlaps(const Variable *Other) const { |
| 483 const bool UseTrimmed = true; | 489 const bool UseTrimmed = true; |
| 484 return Live.overlaps(Other->Live, UseTrimmed); | 490 return Live.overlaps(Other->Live, UseTrimmed); |
| 485 } | 491 } |
| 486 bool rangeOverlapsStart(const Variable *Other) const { | 492 bool rangeOverlapsStart(const Variable *Other) const { |
| 487 const bool UseTrimmed = true; | 493 const bool UseTrimmed = true; |
| 488 return Live.overlapsInst(Other->Live.getStart(), UseTrimmed); | 494 return Live.overlapsInst(Other->Live.getStart(), UseTrimmed); |
| 489 } | 495 } |
| 490 | 496 |
| 491 Variable *getLo() const { return LoVar; } | 497 Variable *getLo() const { return LoVar; } |
| 492 Variable *getHi() const { return HiVar; } | 498 Variable *getHi() const { return HiVar; } |
| 493 void setLoHi(Variable *Lo, Variable *Hi) { | 499 void setLoHi(Variable *Lo, Variable *Hi) { |
| 494 assert(LoVar == nullptr); | 500 assert(LoVar == nullptr); |
| 495 assert(HiVar == nullptr); | 501 assert(HiVar == nullptr); |
| 496 LoVar = Lo; | 502 LoVar = Lo; |
| 497 HiVar = Hi; | 503 HiVar = Hi; |
| 498 } | 504 } |
| 499 /// Creates a temporary copy of the variable with a different type. | 505 /// Creates a temporary copy of the variable with a different type. |
| 500 /// Used primarily for syntactic correctness of textual assembly | 506 /// Used primarily for syntactic correctness of textual assembly |
| 501 /// emission. Note that only basic information is copied, in | 507 /// emission. Note that only basic information is copied, in |
| 502 /// particular not IsArgument, IsImplicitArgument, IgnoreLiveness, | 508 /// particular not IsArgument, IsImplicitArgument, IgnoreLiveness, |
| 503 /// RegNumTmp, Weight, Live, LoVar, HiVar, VarsReal. | 509 /// RegNumTmp, Weight, Live, LoVar, HiVar, VarsReal. |
|
jvoung (off chromium)
2015/08/26 21:45:46
Weight -> UseWeight ?
ascull
2015/08/26 22:06:39
UseWeight -> Weight. Missed this refactor.
| |
| 504 Variable *asType(Type Ty); | 510 Variable *asType(Type Ty); |
| 505 | 511 |
| 506 void emit(const Cfg *Func) const override; | 512 void emit(const Cfg *Func) const override; |
| 507 using Operand::dump; | 513 using Operand::dump; |
| 508 void dump(const Cfg *Func, Ostream &Str) const override; | 514 void dump(const Cfg *Func, Ostream &Str) const override; |
| 509 | 515 |
| 510 /// Return reg num of base register, if different from stack/frame register. | 516 /// Return reg num of base register, if different from stack/frame register. |
| 511 virtual int32_t getBaseRegNum() const { return NoRegister; } | 517 virtual int32_t getBaseRegNum() const { return NoRegister; } |
| 512 | 518 |
| 513 static bool classof(const Operand *Operand) { | 519 static bool classof(const Operand *Operand) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 533 /// reserved for the stack pointer. | 539 /// reserved for the stack pointer. |
| 534 bool IgnoreLiveness = false; | 540 bool IgnoreLiveness = false; |
| 535 /// StackOffset is the canonical location on stack (only if | 541 /// StackOffset is the canonical location on stack (only if |
| 536 /// RegNum==NoRegister || IsArgument). | 542 /// RegNum==NoRegister || IsArgument). |
| 537 int32_t StackOffset = 0; | 543 int32_t StackOffset = 0; |
| 538 /// RegNum is the allocated register, or NoRegister if it isn't | 544 /// RegNum is the allocated register, or NoRegister if it isn't |
| 539 /// register-allocated. | 545 /// register-allocated. |
| 540 int32_t RegNum = NoRegister; | 546 int32_t RegNum = NoRegister; |
| 541 /// RegNumTmp is the tentative assignment during register allocation. | 547 /// RegNumTmp is the tentative assignment during register allocation. |
| 542 int32_t RegNumTmp = NoRegister; | 548 int32_t RegNumTmp = NoRegister; |
| 543 RegWeight Weight = RegWeight(1); // Register allocation priority | 549 /// \name Register allocation priority |
| 550 /// @{ | |
| 551 uint32_t UseWeight = 0; /// Calculated by use count and loop nest depth. | |
| 552 RegRequirement RegRequirement = ShouldHaveRegister; | |
| 553 /// @} | |
| 544 LiveRange Live; | 554 LiveRange Live; |
| 545 // LoVar and HiVar are needed for lowering from 64 to 32 bits. When | 555 // LoVar and HiVar are needed for lowering from 64 to 32 bits. When |
| 546 // lowering from I64 to I32 on a 32-bit architecture, we split the | 556 // lowering from I64 to I32 on a 32-bit architecture, we split the |
| 547 // variable into two machine-size pieces. LoVar is the low-order | 557 // variable into two machine-size pieces. LoVar is the low-order |
| 548 // machine-size portion, and HiVar is the remaining high-order | 558 // machine-size portion, and HiVar is the remaining high-order |
| 549 // portion. TODO: It's wasteful to penalize all variables on all | 559 // portion. TODO: It's wasteful to penalize all variables on all |
| 550 // targets this way; use a sparser representation. It's also | 560 // targets this way; use a sparser representation. It's also |
| 551 // wasteful for a 64-bit target. | 561 // wasteful for a 64-bit target. |
| 552 Variable *LoVar = nullptr; | 562 Variable *LoVar = nullptr; |
| 553 Variable *HiVar = nullptr; | 563 Variable *HiVar = nullptr; |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 656 private: | 666 private: |
| 657 const Cfg *Func; | 667 const Cfg *Func; |
| 658 MetadataKind Kind; | 668 MetadataKind Kind; |
| 659 std::vector<VariableTracking> Metadata; | 669 std::vector<VariableTracking> Metadata; |
| 660 const static InstDefList NoDefinitions; | 670 const static InstDefList NoDefinitions; |
| 661 }; | 671 }; |
| 662 | 672 |
| 663 } // end of namespace Ice | 673 } // end of namespace Ice |
| 664 | 674 |
| 665 #endif // SUBZERO_SRC_ICEOPERAND_H | 675 #endif // SUBZERO_SRC_ICEOPERAND_H |
| OLD | NEW |