| //===- IntegersSubsetMapping.h - Mapping subset ==> Successor ---*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| /// @file |
| /// IntegersSubsetMapping is mapping from A to B, where |
| /// Items in A is subsets of integers, |
| /// Items in B some pointers (Successors). |
| /// If user which to add another subset for successor that is already |
| /// exists in mapping, IntegersSubsetMapping merges existing subset with |
| /// added one. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_SUPPORT_INTEGERSSUBSETMAPPING_H |
| #define LLVM_SUPPORT_INTEGERSSUBSETMAPPING_H |
| |
| #include "llvm/Support/IntegersSubset.h" |
| #include <list> |
| #include <map> |
| #include <vector> |
| |
| namespace llvm { |
| |
| template <class SuccessorClass, |
| class IntegersSubsetTy = IntegersSubset, |
| class IntTy = IntItem> |
| class IntegersSubsetMapping { |
| // FIXME: To much similar iterators typedefs, similar names. |
| // - Rename RangeIterator to the cluster iterator. |
| // - Remove unused "add" methods. |
| // - Class contents needs cleaning. |
| public: |
| |
| typedef IntRange<IntTy> RangeTy; |
| |
| struct RangeEx : public RangeTy { |
| RangeEx() : Weight(1) {} |
| RangeEx(const RangeTy &R) : RangeTy(R), Weight(1) {} |
| RangeEx(const RangeTy &R, unsigned W) : RangeTy(R), Weight(W) {} |
| RangeEx(const IntTy &C) : RangeTy(C), Weight(1) {} |
| RangeEx(const IntTy &L, const IntTy &H) : RangeTy(L, H), Weight(1) {} |
| RangeEx(const IntTy &L, const IntTy &H, unsigned W) : |
| RangeTy(L, H), Weight(W) {} |
| unsigned Weight; |
| }; |
| |
| typedef std::pair<RangeEx, SuccessorClass*> Cluster; |
| |
| typedef std::list<RangeTy> RangesCollection; |
| typedef typename RangesCollection::iterator RangesCollectionIt; |
| typedef typename RangesCollection::const_iterator RangesCollectionConstIt; |
| typedef IntegersSubsetMapping<SuccessorClass, IntegersSubsetTy, IntTy> self; |
| |
| protected: |
| |
| typedef std::list<Cluster> CaseItems; |
| typedef typename CaseItems::iterator CaseItemIt; |
| typedef typename CaseItems::const_iterator CaseItemConstIt; |
| |
| // TODO: Change unclean CRS prefixes to SubsetMap for example. |
| typedef std::map<SuccessorClass*, RangesCollection > CRSMap; |
| typedef typename CRSMap::iterator CRSMapIt; |
| |
| struct ClustersCmp { |
| bool operator()(const Cluster &C1, const Cluster &C2) { |
| return C1.first < C2.first; |
| } |
| }; |
| |
| CaseItems Items; |
| bool Sorted; |
| |
| bool isIntersected(CaseItemIt& LItem, CaseItemIt& RItem) { |
| return LItem->first.getHigh() >= RItem->first.getLow(); |
| } |
| |
| bool isJoinable(CaseItemIt& LItem, CaseItemIt& RItem) { |
| if (LItem->second != RItem->second) { |
| assert(!isIntersected(LItem, RItem) && |
| "Intersected items with different successors!"); |
| return false; |
| } |
| APInt RLow = RItem->first.getLow(); |
| if (RLow != APInt::getNullValue(RLow.getBitWidth())) |
| --RLow; |
| return LItem->first.getHigh() >= RLow; |
| } |
| |
| void sort() { |
| if (!Sorted) { |
| std::vector<Cluster> clustersVector; |
| clustersVector.reserve(Items.size()); |
| clustersVector.insert(clustersVector.begin(), Items.begin(), Items.end()); |
| std::sort(clustersVector.begin(), clustersVector.end(), ClustersCmp()); |
| Items.clear(); |
| Items.insert(Items.begin(), clustersVector.begin(), clustersVector.end()); |
| Sorted = true; |
| } |
| } |
| |
| enum DiffProcessState { |
| L_OPENED, |
| INTERSECT_OPENED, |
| R_OPENED, |
| ALL_IS_CLOSED |
| }; |
| |
| class DiffStateMachine { |
| |
| DiffProcessState State; |
| IntTy OpenPt; |
| SuccessorClass *CurrentLSuccessor; |
| SuccessorClass *CurrentRSuccessor; |
| |
| self *LeftMapping; |
| self *IntersectionMapping; |
| self *RightMapping; |
| |
| public: |
| |
| typedef |
| IntegersSubsetMapping<SuccessorClass, IntegersSubsetTy, IntTy> MappingTy; |
| |
| DiffStateMachine(MappingTy *L, |
| MappingTy *Intersection, |
| MappingTy *R) : |
| State(ALL_IS_CLOSED), |
| LeftMapping(L), |
| IntersectionMapping(Intersection), |
| RightMapping(R) |
| {} |
| |
| void onLOpen(const IntTy &Pt, SuccessorClass *S) { |
| switch (State) { |
| case R_OPENED: |
| if (Pt > OpenPt/*Don't add empty ranges.*/ && RightMapping) |
| RightMapping->add(OpenPt, Pt-1, CurrentRSuccessor); |
| State = INTERSECT_OPENED; |
| break; |
| case ALL_IS_CLOSED: |
| State = L_OPENED; |
| break; |
| default: |
| assert(0 && "Got unexpected point."); |
| break; |
| } |
| CurrentLSuccessor = S; |
| OpenPt = Pt; |
| } |
| |
| void onLClose(const IntTy &Pt) { |
| switch (State) { |
| case L_OPENED: |
| assert(Pt >= OpenPt && |
| "Subset is not sorted or contains overlapped ranges"); |
| if (LeftMapping) |
| LeftMapping->add(OpenPt, Pt, CurrentLSuccessor); |
| State = ALL_IS_CLOSED; |
| break; |
| case INTERSECT_OPENED: |
| if (IntersectionMapping) |
| IntersectionMapping->add(OpenPt, Pt, CurrentLSuccessor); |
| OpenPt = Pt + 1; |
| State = R_OPENED; |
| break; |
| default: |
| assert(0 && "Got unexpected point."); |
| break; |
| } |
| } |
| |
| void onROpen(const IntTy &Pt, SuccessorClass *S) { |
| switch (State) { |
| case L_OPENED: |
| if (Pt > OpenPt && LeftMapping) |
| LeftMapping->add(OpenPt, Pt-1, CurrentLSuccessor); |
| State = INTERSECT_OPENED; |
| break; |
| case ALL_IS_CLOSED: |
| State = R_OPENED; |
| break; |
| default: |
| assert(0 && "Got unexpected point."); |
| break; |
| } |
| CurrentRSuccessor = S; |
| OpenPt = Pt; |
| } |
| |
| void onRClose(const IntTy &Pt) { |
| switch (State) { |
| case R_OPENED: |
| assert(Pt >= OpenPt && |
| "Subset is not sorted or contains overlapped ranges"); |
| if (RightMapping) |
| RightMapping->add(OpenPt, Pt, CurrentRSuccessor); |
| State = ALL_IS_CLOSED; |
| break; |
| case INTERSECT_OPENED: |
| if (IntersectionMapping) |
| IntersectionMapping->add(OpenPt, Pt, CurrentLSuccessor); |
| OpenPt = Pt + 1; |
| State = L_OPENED; |
| break; |
| default: |
| assert(0 && "Got unexpected point."); |
| break; |
| } |
| } |
| |
| void onLROpen(const IntTy &Pt, |
| SuccessorClass *LS, |
| SuccessorClass *RS) { |
| switch (State) { |
| case ALL_IS_CLOSED: |
| State = INTERSECT_OPENED; |
| break; |
| default: |
| assert(0 && "Got unexpected point."); |
| break; |
| } |
| CurrentLSuccessor = LS; |
| CurrentRSuccessor = RS; |
| OpenPt = Pt; |
| } |
| |
| void onLRClose(const IntTy &Pt) { |
| switch (State) { |
| case INTERSECT_OPENED: |
| if (IntersectionMapping) |
| IntersectionMapping->add(OpenPt, Pt, CurrentLSuccessor); |
| State = ALL_IS_CLOSED; |
| break; |
| default: |
| assert(0 && "Got unexpected point."); |
| break; |
| } |
| } |
| |
| bool isLOpened() { return State == L_OPENED; } |
| bool isROpened() { return State == R_OPENED; } |
| }; |
| |
| public: |
| |
| // Don't public CaseItems itself. Don't allow edit the Items directly. |
| // Just present the user way to iterate over the internal collection |
| // sharing iterator, begin() and end(). Editing should be controlled by |
| // factory. |
| typedef CaseItemIt RangeIterator; |
| |
| typedef std::pair<SuccessorClass*, IntegersSubsetTy> Case; |
| typedef std::list<Case> Cases; |
| typedef typename Cases::iterator CasesIt; |
| |
| IntegersSubsetMapping() { |
| Sorted = false; |
| } |
| |
| bool verify() { |
| RangeIterator DummyErrItem; |
| return verify(DummyErrItem); |
| } |
| |
| bool verify(RangeIterator& errItem) { |
| if (Items.empty()) |
| return true; |
| sort(); |
| for (CaseItemIt j = Items.begin(), i = j++, e = Items.end(); |
| j != e; i = j++) { |
| if (isIntersected(i, j) && i->second != j->second) { |
| errItem = j; |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool isOverlapped(self &RHS) { |
| if (Items.empty() || RHS.empty()) |
| return true; |
| |
| for (CaseItemIt L = Items.begin(), R = RHS.Items.begin(), |
| el = Items.end(), er = RHS.Items.end(); L != el && R != er;) { |
| |
| const RangeTy &LRange = L->first; |
| const RangeTy &RRange = R->first; |
| |
| if (LRange.getLow() > RRange.getLow()) { |
| if (RRange.isSingleNumber() || LRange.getLow() > RRange.getHigh()) |
| ++R; |
| else |
| return true; |
| } else if (LRange.getLow() < RRange.getLow()) { |
| if (LRange.isSingleNumber() || LRange.getHigh() < RRange.getLow()) |
| ++L; |
| else |
| return true; |
| } else // iRange.getLow() == jRange.getLow() |
| return true; |
| } |
| return false; |
| } |
| |
| |
| void optimize() { |
| if (Items.size() < 2) |
| return; |
| sort(); |
| CaseItems OldItems = Items; |
| Items.clear(); |
| const IntTy *Low = &OldItems.begin()->first.getLow(); |
| const IntTy *High = &OldItems.begin()->first.getHigh(); |
| unsigned Weight = OldItems.begin()->first.Weight; |
| SuccessorClass *Successor = OldItems.begin()->second; |
| for (CaseItemIt j = OldItems.begin(), i = j++, e = OldItems.end(); |
| j != e; i = j++) { |
| if (isJoinable(i, j)) { |
| const IntTy *CurHigh = &j->first.getHigh(); |
| Weight += j->first.Weight; |
| if (*CurHigh > *High) |
| High = CurHigh; |
| } else { |
| RangeEx R(*Low, *High, Weight); |
| add(R, Successor); |
| Low = &j->first.getLow(); |
| High = &j->first.getHigh(); |
| Weight = j->first.Weight; |
| Successor = j->second; |
| } |
| } |
| RangeEx R(*Low, *High, Weight); |
| add(R, Successor); |
| // We recollected the Items, but we kept it sorted. |
| Sorted = true; |
| } |
| |
| /// Adds a constant value. |
| void add(const IntTy &C, SuccessorClass *S = 0) { |
| RangeTy R(C); |
| add(R, S); |
| } |
| |
| /// Adds a range. |
| void add(const IntTy &Low, const IntTy &High, SuccessorClass *S = 0) { |
| RangeTy R(Low, High); |
| add(R, S); |
| } |
| void add(const RangeTy &R, SuccessorClass *S = 0) { |
| RangeEx REx = R; |
| add(REx, S); |
| } |
| void add(const RangeEx &R, SuccessorClass *S = 0) { |
| Items.push_back(std::make_pair(R, S)); |
| Sorted = false; |
| } |
| |
| /// Adds all ranges and values from given ranges set to the current |
| /// mapping. |
| void add(const IntegersSubsetTy &CRS, SuccessorClass *S = 0, |
| unsigned Weight = 0) { |
| unsigned ItemWeight = 1; |
| if (Weight) |
| // Weight is associated with CRS, for now we perform a division to |
| // get the weight for each item. |
| ItemWeight = Weight / CRS.getNumItems(); |
| for (unsigned i = 0, e = CRS.getNumItems(); i < e; ++i) { |
| RangeTy R = CRS.getItem(i); |
| RangeEx REx(R, ItemWeight); |
| add(REx, S); |
| } |
| } |
| |
| void add(self& RHS) { |
| Items.insert(Items.end(), RHS.Items.begin(), RHS.Items.end()); |
| } |
| |
| void add(self& RHS, SuccessorClass *S) { |
| for (CaseItemIt i = RHS.Items.begin(), e = RHS.Items.end(); i != e; ++i) |
| add(i->first, S); |
| } |
| |
| void add(const RangesCollection& RHS, SuccessorClass *S = 0) { |
| for (RangesCollectionConstIt i = RHS.begin(), e = RHS.end(); i != e; ++i) |
| add(*i, S); |
| } |
| |
| /// Removes items from set. |
| void removeItem(RangeIterator i) { Items.erase(i); } |
| |
| /// Moves whole case from current mapping to the NewMapping object. |
| void detachCase(self& NewMapping, SuccessorClass *Succ) { |
| for (CaseItemIt i = Items.begin(); i != Items.end();) |
| if (i->second == Succ) { |
| NewMapping.add(i->first, i->second); |
| Items.erase(i++); |
| } else |
| ++i; |
| } |
| |
| /// Removes all clusters for given successor. |
| void removeCase(SuccessorClass *Succ) { |
| for (CaseItemIt i = Items.begin(); i != Items.end();) |
| if (i->second == Succ) { |
| Items.erase(i++); |
| } else |
| ++i; |
| } |
| |
| /// Find successor that satisfies given value. |
| SuccessorClass *findSuccessor(const IntTy& Val) { |
| for (CaseItemIt i = Items.begin(); i != Items.end(); ++i) { |
| if (i->first.isInRange(Val)) |
| return i->second; |
| } |
| return 0; |
| } |
| |
| /// Calculates the difference between this mapping and RHS. |
| /// THIS without RHS is placed into LExclude, |
| /// RHS without THIS is placed into RExclude, |
| /// THIS intersect RHS is placed into Intersection. |
| void diff(self *LExclude, self *Intersection, self *RExclude, |
| const self& RHS) { |
| |
| DiffStateMachine Machine(LExclude, Intersection, RExclude); |
| |
| CaseItemConstIt L = Items.begin(), R = RHS.Items.begin(); |
| while (L != Items.end() && R != RHS.Items.end()) { |
| const Cluster &LCluster = *L; |
| const RangeEx &LRange = LCluster.first; |
| const Cluster &RCluster = *R; |
| const RangeEx &RRange = RCluster.first; |
| |
| if (LRange.getHigh() < RRange.getLow()) { |
| Machine.onLOpen(LRange.getLow(), LCluster.second); |
| Machine.onLClose(LRange.getHigh()); |
| ++L; |
| continue; |
| } |
| |
| if (LRange.getLow() > RRange.getHigh()) { |
| Machine.onROpen(RRange.getLow(), RCluster.second); |
| Machine.onRClose(RRange.getHigh()); |
| ++R; |
| continue; |
| } |
| |
| if (LRange.getLow() < RRange.getLow()) { |
| // May be opened in previous iteration. |
| if (!Machine.isLOpened()) |
| Machine.onLOpen(LRange.getLow(), LCluster.second); |
| Machine.onROpen(RRange.getLow(), RCluster.second); |
| } |
| else if (RRange.getLow() < LRange.getLow()) { |
| if (!Machine.isROpened()) |
| Machine.onROpen(RRange.getLow(), RCluster.second); |
| Machine.onLOpen(LRange.getLow(), LCluster.second); |
| } |
| else |
| Machine.onLROpen(LRange.getLow(), LCluster.second, RCluster.second); |
| |
| if (LRange.getHigh() < RRange.getHigh()) { |
| Machine.onLClose(LRange.getHigh()); |
| ++L; |
| while(L != Items.end() && L->first.getHigh() < RRange.getHigh()) { |
| Machine.onLOpen(L->first.getLow(), L->second); |
| Machine.onLClose(L->first.getHigh()); |
| ++L; |
| } |
| } |
| else if (RRange.getHigh() < LRange.getHigh()) { |
| Machine.onRClose(RRange.getHigh()); |
| ++R; |
| while(R != RHS.Items.end() && R->first.getHigh() < LRange.getHigh()) { |
| Machine.onROpen(R->first.getLow(), R->second); |
| Machine.onRClose(R->first.getHigh()); |
| ++R; |
| } |
| } |
| else { |
| Machine.onLRClose(LRange.getHigh()); |
| ++L; |
| ++R; |
| } |
| } |
| |
| if (L != Items.end()) { |
| if (Machine.isLOpened()) { |
| Machine.onLClose(L->first.getHigh()); |
| ++L; |
| } |
| if (LExclude) |
| while (L != Items.end()) { |
| LExclude->add(L->first, L->second); |
| ++L; |
| } |
| } else if (R != RHS.Items.end()) { |
| if (Machine.isROpened()) { |
| Machine.onRClose(R->first.getHigh()); |
| ++R; |
| } |
| if (RExclude) |
| while (R != RHS.Items.end()) { |
| RExclude->add(R->first, R->second); |
| ++R; |
| } |
| } |
| } |
| |
| /// Builds the finalized case objects. |
| void getCases(Cases& TheCases, bool PreventMerging = false) { |
| //FIXME: PreventMerging is a temporary parameter. |
| //Currently a set of passes is still knows nothing about |
| //switches with case ranges, and if these passes meet switch |
| //with complex case that crashs the application. |
| if (PreventMerging) { |
| for (RangeIterator i = this->begin(); i != this->end(); ++i) { |
| RangesCollection SingleRange; |
| SingleRange.push_back(i->first); |
| TheCases.push_back(std::make_pair(i->second, |
| IntegersSubsetTy(SingleRange))); |
| } |
| return; |
| } |
| CRSMap TheCRSMap; |
| for (RangeIterator i = this->begin(); i != this->end(); ++i) |
| TheCRSMap[i->second].push_back(i->first); |
| for (CRSMapIt i = TheCRSMap.begin(), e = TheCRSMap.end(); i != e; ++i) |
| TheCases.push_back(std::make_pair(i->first, IntegersSubsetTy(i->second))); |
| } |
| |
| /// Builds the finalized case objects ignoring successor values, as though |
| /// all ranges belongs to the same successor. |
| IntegersSubsetTy getCase() { |
| RangesCollection Ranges; |
| for (RangeIterator i = this->begin(); i != this->end(); ++i) |
| Ranges.push_back(i->first); |
| return IntegersSubsetTy(Ranges); |
| } |
| |
| /// Returns pointer to value of case if it is single-numbered or 0 |
| /// in another case. |
| const IntTy* getCaseSingleNumber(SuccessorClass *Succ) { |
| const IntTy* Res = 0; |
| for (CaseItemIt i = Items.begin(); i != Items.end(); ++i) |
| if (i->second == Succ) { |
| if (!i->first.isSingleNumber()) |
| return 0; |
| if (Res) |
| return 0; |
| else |
| Res = &(i->first.getLow()); |
| } |
| return Res; |
| } |
| |
| /// Returns true if there is no ranges and values inside. |
| bool empty() const { return Items.empty(); } |
| |
| void clear() { |
| Items.clear(); |
| // Don't reset Sorted flag: |
| // 1. For empty mapping it matters nothing. |
| // 2. After first item will added Sorted flag will cleared. |
| } |
| |
| // Returns number of clusters |
| unsigned size() const { |
| return Items.size(); |
| } |
| |
| RangeIterator begin() { return Items.begin(); } |
| RangeIterator end() { return Items.end(); } |
| }; |
| |
| class BasicBlock; |
| typedef IntegersSubsetMapping<BasicBlock> IntegersSubsetToBB; |
| |
| } |
| |
| #endif /* LLVM_SUPPORT_INTEGERSSUBSETMAPPING_CRSBUILDER_H */ |