diff options
| -rw-r--r-- | llvm/include/llvm/CodeGen/GlobalISel/RegBankSelect.h | 63 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp | 126 |
2 files changed, 188 insertions, 1 deletions
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/RegBankSelect.h b/llvm/include/llvm/CodeGen/GlobalISel/RegBankSelect.h index b3ac16aa9e0..80ecd2f2f44 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/RegBankSelect.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/RegBankSelect.h @@ -70,6 +70,7 @@ namespace llvm { // Forward declarations. +class BlockFrequency; class MachineRegisterInfo; class TargetRegisterInfo; @@ -80,6 +81,68 @@ public: static char ID; private: + /// Helper class used to represent the cost for mapping an instruction. + /// When mapping an instruction, we may introduce some repairing code. + /// In most cases, the repairing code is local to the instruction, + /// thus, we can omit the basic block frequency from the cost. + /// However, some alternatives may produce non-local cost, e.g., when + /// repairing a phi, and thus we then need to scale the local cost + /// to the non-local cost. This class does this for us. + /// \note: We could simply always scale the cost. The problem is that + /// there are higher chances that we saturate the cost easier and end + /// up having the same cost for actually different alternatives. + /// Another option would be to use APInt everywhere. + class MappingCost { + private: + /// Cost of the local instructions. + /// This cost is free of basic block frequency. + uint64_t LocalCost; + /// Cost of the non-local instructions. + /// This cost should include the frequency of the related blocks. + uint64_t NonLocalCost; + /// Frequency of the block where the local instructions live. + uint64_t LocalFreq; + + MappingCost(uint64_t LocalCost, uint64_t NonLocalCost, uint64_t LocalFreq) + : LocalCost(LocalCost), NonLocalCost(NonLocalCost), + LocalFreq(LocalFreq) {} + + /// Check if this cost is saturated. + bool isSaturated() const; + + public: + /// Create a MappingCost assuming that most of the instructions + /// will occur in a basic block with \p LocalFreq frequency. + MappingCost(const BlockFrequency &LocalFreq); + + /// Add \p Cost to the local cost. + /// \return true if this cost is saturated, false otherwise. + bool addLocalCost(uint64_t Cost); + + /// Add \p Cost to the non-local cost. + /// Non-local cost should reflect the frequency of their placement. + /// \return true if this cost is saturated, false otherwise. + bool addNonLocalCost(uint64_t Cost); + + /// Saturate the cost to the maximal representable value. + void saturate(); + + /// Return an instance of MappingCost that represents an + /// impossible mapping. + static MappingCost ImpossibleCost(); + + /// Check if this is less than \p Cost. + bool operator<(const MappingCost &Cost) const; + /// Check if this is equal to \p Cost. + bool operator==(const MappingCost &Cost) const; + /// Check if this is not equal to \p Cost. + bool operator!=(const MappingCost &Cost) const { return !(*this == Cost); } + /// Check if this is greater than \p Cost. + bool operator>(const MappingCost &Cost) const { + return *this != Cost && Cost < *this; + } + }; + /// Interface to the target lowering info related /// to register banks. const RegisterBankInfo *RBI; diff --git a/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp b/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp index 8a6e1cb3623..2bd1534d722 100644 --- a/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp +++ b/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp @@ -10,10 +10,11 @@ /// This file implements the RegBankSelect class. //===----------------------------------------------------------------------===// -#include "llvm/ADT/PostOrderIterator.h" #include "llvm/CodeGen/GlobalISel/RegBankSelect.h" +#include "llvm/ADT/PostOrderIterator.h" #include "llvm/CodeGen/GlobalISel/RegisterBank.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/BlockFrequency.h" #include "llvm/Support/Debug.h" #include "llvm/Target/TargetSubtargetInfo.h" @@ -252,3 +253,126 @@ bool RegBankSelect::runOnMachineFunction(MachineFunction &MF) { assignInstr(MI); return false; } + +//------------------------------------------------------------------------------ +// Helper Class Implementation +//------------------------------------------------------------------------------ +RegBankSelect::MappingCost::MappingCost(const BlockFrequency &LocalFreq) + : LocalCost(0), NonLocalCost(0), LocalFreq(LocalFreq.getFrequency()) {} + +bool RegBankSelect::MappingCost::addLocalCost(uint64_t Cost) { + // Check if this overflows. + if (LocalCost + Cost < LocalCost) { + saturate(); + return true; + } + LocalCost += Cost; + return isSaturated(); +} + +bool RegBankSelect::MappingCost::addNonLocalCost(uint64_t Cost) { + // Check if this overflows. + if (NonLocalCost + Cost < NonLocalCost) { + saturate(); + return true; + } + NonLocalCost += Cost; + return isSaturated(); +} + +bool RegBankSelect::MappingCost::isSaturated() const { + return LocalCost == UINT64_MAX - 1 && NonLocalCost == UINT64_MAX && + LocalFreq == UINT64_MAX; +} + +void RegBankSelect::MappingCost::saturate() { + *this = ImpossibleCost(); + --LocalCost; +} + +RegBankSelect::MappingCost RegBankSelect::MappingCost::ImpossibleCost() { + return MappingCost(UINT64_MAX, UINT64_MAX, UINT64_MAX); +} + +bool RegBankSelect::MappingCost::operator<(const MappingCost &Cost) const { + // Sort out the easy cases. + if (*this == Cost) + return false; + // If one is impossible to realize the other is cheaper unless it is + // impossible as well. + if ((*this == ImpossibleCost()) || (Cost == ImpossibleCost())) + return (*this == ImpossibleCost()) < (Cost == ImpossibleCost()); + // If one is saturated the other is cheaper, unless it is saturated + // as well. + if (isSaturated() || Cost.isSaturated()) + return isSaturated() < Cost.isSaturated(); + // At this point we know both costs hold sensible values. + + // If both values have a different base frequency, there is no much + // we can do but to scale everything. + // However, if they have the same base frequency we can avoid making + // complicated computation. + uint64_t ThisLocalAdjust; + uint64_t OtherLocalAdjust; + if (LLVM_LIKELY(LocalFreq == Cost.LocalFreq)) { + + // At this point, we know the local costs are comparable. + // Do the case that do not involve potential overflow first. + if (NonLocalCost == Cost.NonLocalCost) + // Since the non-local costs do not discriminate on the result, + // just compare the local costs. + return LocalCost < Cost.LocalCost; + + // The base costs are comparable so we may only keep the relative + // value to increase our chances of avoiding overflows. + ThisLocalAdjust = 0; + OtherLocalAdjust = 0; + if (LocalCost < Cost.LocalCost) + OtherLocalAdjust = Cost.LocalCost - LocalCost; + else + ThisLocalAdjust = LocalCost - Cost.LocalCost; + + } else { + ThisLocalAdjust = LocalCost; + OtherLocalAdjust = Cost.LocalCost; + } + + // The non-local costs are comparable, just keep the relative value. + uint64_t ThisNonLocalAdjust = 0; + uint64_t OtherNonLocalAdjust = 0; + if (NonLocalCost < Cost.NonLocalCost) + OtherNonLocalAdjust = Cost.NonLocalCost - NonLocalCost; + else + ThisNonLocalAdjust = NonLocalCost - Cost.NonLocalCost; + // Scale everything to make them comparable. + uint64_t ThisScaledCost = ThisLocalAdjust * LocalFreq; + // Check for overflow on that operation. + bool ThisOverflows = ThisLocalAdjust && (ThisScaledCost < ThisLocalAdjust || + ThisScaledCost < LocalFreq); + uint64_t OtherScaledCost = OtherLocalAdjust * Cost.LocalFreq; + // Check for overflow on the last operation. + bool OtherOverflows = + OtherLocalAdjust && + (OtherScaledCost < OtherLocalAdjust || OtherScaledCost < Cost.LocalFreq); + // Add the non-local costs. + ThisOverflows |= ThisNonLocalAdjust && + ThisScaledCost + ThisNonLocalAdjust < ThisNonLocalAdjust; + ThisScaledCost += ThisNonLocalAdjust; + OtherOverflows |= OtherNonLocalAdjust && + OtherScaledCost + OtherNonLocalAdjust < OtherNonLocalAdjust; + OtherScaledCost += OtherNonLocalAdjust; + // If both overflows, we cannot compare without additional + // precision, e.g., APInt. Just give up on that case. + if (ThisOverflows && OtherOverflows) + return false; + // If one overflows but not the other, we can still compare. + if (ThisOverflows || OtherOverflows) + return ThisOverflows < OtherOverflows; + // Otherwise, just compare the values. + return ThisScaledCost < OtherScaledCost; +} + +bool RegBankSelect::MappingCost::operator==(const MappingCost &Cost) const { + return LocalCost == Cost.LocalCost && NonLocalCost == Cost.NonLocalCost && + LocalFreq == Cost.LocalFreq; +} |

