Skip to content

Commit 5f805b6

Browse files
committed
Add unittests for BlotMapVector and change it to use Optional<> in its internal representation to remove a leak.
1 parent 654ca4e commit 5f805b6

File tree

9 files changed

+859
-155
lines changed

9 files changed

+859
-155
lines changed

include/swift/Basic/BlotMapVector.h

Lines changed: 60 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,35 @@
1414
#define SWIFT_BASIC_BLOTMAPVECTOR_H
1515

1616
#include "llvm/ADT/DenseMap.h"
17+
#include "swift/Basic/LLVM.h"
1718
#include "swift/Basic/Range.h"
1819
#include <vector>
1920

2021
namespace swift {
21-
/// \brief An associative container with fast insertion-order (deterministic)
22-
/// iteration over its elements. Plus the special blot operation.
23-
template<typename KeyT, typename ValueT,
24-
typename MapTy=llvm::DenseMap<KeyT, size_t>,
25-
typename VectorTy=std::vector<std::pair<KeyT, ValueT>>>
26-
class BlotMapVector {
22+
23+
template <typename KeyT, typename ValueT>
24+
bool compareKeyAgainstDefaultKey(const std::pair<KeyT, ValueT> &Pair) {
25+
return Pair.first == KeyT();
26+
}
27+
28+
/// \brief An associative container with fast insertion-order (deterministic)
29+
/// iteration over its elements. Plus the special blot operation.
30+
template <typename KeyT, typename ValueT,
31+
typename MapTy = llvm::DenseMap<KeyT, size_t>,
32+
typename VectorTy = std::vector<Optional<std::pair<KeyT, ValueT>>>>
33+
class BlotMapVector {
2734
/// Map keys to indices in Vector.
2835
MapTy Map;
2936

3037
/// Keys and values.
3138
VectorTy Vector;
3239

3340
public:
34-
typedef typename VectorTy::iterator iterator;
35-
typedef typename VectorTy::const_iterator const_iterator;
41+
using iterator = typename VectorTy::iterator;
42+
using const_iterator = typename VectorTy::const_iterator;
43+
using key_type = KeyT;
44+
using mapped_type = ValueT;
45+
3646
iterator begin() { return Vector.begin(); }
3747
iterator end() { return Vector.end(); }
3848
const_iterator begin() const { return Vector.begin(); }
@@ -42,38 +52,20 @@ template<typename KeyT, typename ValueT,
4252
return swift::make_range(begin(), end());
4353
}
4454

45-
#ifdef XDEBUG
46-
~BlotMapVector() {
47-
assert(Vector.size() >= Map.size()); // May differ due to blotting.
48-
for (typename MapTy::const_iterator I = Map.begin(), E = Map.end();
49-
I != E; ++I) {
50-
assert(I->second < Vector.size());
51-
assert(Vector[I->second].first == I->first);
52-
}
53-
for (typename VectorTy::const_iterator I = Vector.begin(),
54-
E = Vector.end(); I != E; ++I)
55-
assert(!I->first ||
56-
(Map.count(I->first) &&
57-
Map[I->first] == size_t(I - Vector.begin())));
58-
}
59-
#endif
60-
6155
ValueT &operator[](const KeyT &Arg) {
62-
std::pair<typename MapTy::iterator, bool> Pair =
63-
Map.insert(std::make_pair(Arg, size_t(0)));
56+
auto Pair = Map.insert(std::make_pair(Arg, size_t(0)));
6457
if (Pair.second) {
6558
size_t Num = Vector.size();
6659
Pair.first->second = Num;
67-
Vector.push_back(std::make_pair(Arg, ValueT()));
68-
return Vector[Num].second;
60+
Vector.push_back({std::make_pair(Arg, ValueT())});
61+
return (*Vector[Num]).second;
6962
}
70-
return Vector[Pair.first->second].second;
63+
return Vector[Pair.first->second].getValue().second;
7164
}
7265

7366
std::pair<iterator, bool>
7467
insert(const std::pair<KeyT, ValueT> &InsertPair) {
75-
std::pair<typename MapTy::iterator, bool> Pair =
76-
Map.insert(std::make_pair(InsertPair.first, size_t(0)));
68+
auto Pair = Map.insert(std::make_pair(InsertPair.first, size_t(0)));
7769
if (Pair.second) {
7870
size_t Num = Vector.size();
7971
Pair.first->second = Num;
@@ -86,35 +78,63 @@ template<typename KeyT, typename ValueT,
8678
iterator find(const KeyT &Key) {
8779
typename MapTy::iterator It = Map.find(Key);
8880
if (It == Map.end()) return Vector.end();
89-
return Vector.begin() + It->second;
81+
auto Iter = Vector.begin() + It->second;
82+
if (!Iter->hasValue())
83+
return Vector.end();
84+
return Iter;
9085
}
9186

9287
const_iterator find(const KeyT &Key) const {
93-
typename MapTy::const_iterator It = Map.find(Key);
94-
if (It == Map.end()) return Vector.end();
95-
return Vector.begin() + It->second;
88+
return const_cast<BlotMapVector &>(*this)->find(Key);
9689
}
9790

91+
/// This is similar to erase, but instead of removing the element from the
92+
/// vector, it just zeros out the key in the vector. This leaves iterators
93+
/// intact, but clients must be prepared for zeroed-out keys when iterating.
94+
void erase(const KeyT &Key) { blot(Key); }
95+
96+
/// This is similar to erase, but instead of removing the element from the
97+
/// vector, it just zeros out the key in the vector. This leaves iterators
98+
/// intact, but clients must be prepared for zeroed-out keys when iterating.
99+
void erase(iterator I) { erase((*I)->first); }
100+
98101
/// This is similar to erase, but instead of removing the element from the
99102
/// vector, it just zeros out the key in the vector. This leaves iterators
100103
/// intact, but clients must be prepared for zeroed-out keys when iterating.
101104
void blot(const KeyT &Key) {
102105
typename MapTy::iterator It = Map.find(Key);
103106
if (It == Map.end()) return;
104-
Vector[It->second].first = KeyT();
107+
Vector[It->second] = None;
105108
Map.erase(It);
106109
}
107110

108111
void clear() {
109112
Map.clear();
110113
Vector.clear();
111114
}
115+
116+
unsigned size() const { return Map.size(); }
117+
118+
ValueT lookup(const KeyT &Val) const {
119+
auto Iter = Map.find(Val);
120+
if (Iter == Map.end())
121+
return ValueT();
122+
auto &P = Vector[Iter->second];
123+
if (!P.hasValue())
124+
return ValueT();
125+
return P->second;
126+
}
127+
128+
size_t count(const KeyT &Val) const { return Map.count(Val); }
129+
130+
bool empty() const { return Map.empty(); }
112131
};
113132

114-
template <typename KeyT, typename ValueT, unsigned N,
115-
typename MapT=llvm::SmallDenseMap<KeyT, size_t, N>,
116-
typename VectorT=llvm::SmallVector<std::pair<KeyT, ValueT>, N>>
117-
class SmallBlotMapVector : public BlotMapVector<KeyT, ValueT, MapT, VectorT> {
133+
template <typename KeyT, typename ValueT, unsigned N,
134+
typename MapT = llvm::SmallDenseMap<KeyT, size_t, N>,
135+
typename VectorT =
136+
llvm::SmallVector<Optional<std::pair<KeyT, ValueT>>, N>>
137+
class SmallBlotMapVector : public BlotMapVector<KeyT, ValueT, MapT, VectorT> {
118138
public:
119139
SmallBlotMapVector() {}
120140
};

lib/SILAnalysis/ARC/ARCBBState.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,11 @@ using ARCBBState = ARCSequenceDataflowEvaluator::ARCBBState;
3030
/// operation.
3131
void ARCBBState::mergeSuccBottomUp(ARCBBState &SuccBBState) {
3232
// For each [(SILValue, BottomUpState)] that we are tracking...
33-
for (std::pair<SILValue, BottomUpRefCountState> &Pair : getBottomupStates()) {
34-
SILValue RefCountedValue = Pair.first;
33+
for (auto &Pair : getBottomupStates()) {
34+
if (!Pair.hasValue())
35+
continue;
36+
37+
SILValue RefCountedValue = Pair->first;
3538

3639
// If our SILValue was blotted, skip it. This will be ignored for the rest
3740
// of the ARC optimization.
@@ -49,7 +52,7 @@ void ARCBBState::mergeSuccBottomUp(ARCBBState &SuccBBState) {
4952
continue;
5053
}
5154

52-
SILValue OtherRefCountedValue = Other->first;
55+
SILValue OtherRefCountedValue = (*Other)->first;
5356

5457
// If the other ref count value was blotted, blot our value and continue.
5558
// This has the effect of an intersection since we already checked earlier
@@ -59,8 +62,8 @@ void ARCBBState::mergeSuccBottomUp(ARCBBState &SuccBBState) {
5962
continue;
6063
}
6164

62-
BottomUpRefCountState &RefCountState = Pair.second;
63-
BottomUpRefCountState &OtherRefCountState = Other->second;
65+
BottomUpRefCountState &RefCountState = Pair->second;
66+
BottomUpRefCountState &OtherRefCountState = (*Other)->second;
6467

6568
// Ok, now we know that the merged set can safely represent a set of
6669
// of instructions which together semantically act as one ref count
@@ -81,8 +84,11 @@ void ARCBBState::initSuccBottomUp(ARCBBState &SuccBBState) {
8184
/// Merge in the state of the predecessor basic block.
8285
void ARCBBState::mergePredTopDown(ARCBBState &PredBBState) {
8386
// For each [(SILValue, TopDownState)] that we are tracking...
84-
for (std::pair<SILValue, TopDownRefCountState> &Pair : getTopDownStates()) {
85-
SILValue RefCountedValue = Pair.first;
87+
for (auto &Pair : getTopDownStates()) {
88+
if (!Pair.hasValue())
89+
continue;
90+
91+
SILValue RefCountedValue = Pair->first;
8692

8793
// If our SILValue was blotted, skip it. This will be ignored in the rest of
8894
// the optimizer.
@@ -100,7 +106,7 @@ void ARCBBState::mergePredTopDown(ARCBBState &PredBBState) {
100106
continue;
101107
}
102108

103-
SILValue OtherRefCountedValue = Other->first;
109+
SILValue OtherRefCountedValue = (*Other)->first;
104110

105111
// If the other ref count value was blotted, blot our value and continue.
106112
// This has the effect of an intersection.
@@ -111,8 +117,8 @@ void ARCBBState::mergePredTopDown(ARCBBState &PredBBState) {
111117

112118
// Ok, so now we know that the ref counted value we are tracking was not
113119
// blotted on either side. Grab the states.
114-
TopDownRefCountState &RefCountState = Pair.second;
115-
TopDownRefCountState &OtherRefCountState = Other->second;
120+
TopDownRefCountState &RefCountState = Pair->second;
121+
TopDownRefCountState &OtherRefCountState = (*Other)->second;
116122

117123
// Attempt to merge Other into this ref count state. If we fail, blot this
118124
// ref counted value and continue.

0 commit comments

Comments
 (0)