Skip to content

Commit b3f964b

Browse files
committed
[EquivalenceClasses] Introduce erase member function
Introduce 'erase(const ElemTy &V)' member function to allow the deletion of a certain value from EquivClasses. This is essential for certain scenarios that require modifying the contents of EquivClasses. This path also incidentally fixes a problem of inaccurate leader setting when EquivClasses unions two classes. This problem only arises in the presence of erase function.
1 parent 6ce0fd7 commit b3f964b

File tree

2 files changed

+88
-3
lines changed

2 files changed

+88
-3
lines changed

llvm/include/llvm/ADT/EquivalenceClasses.h

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,40 @@ template <class ElemTy> class EquivalenceClasses {
220220
return *ECV;
221221
}
222222

223+
/// erase - Erase a value from the union/find set, return if erase succeed.
224+
bool erase(const ElemTy &V) {
225+
if (!TheMapping.contains(V)) return false;
226+
const ECValue *cur = TheMapping[V];
227+
const ECValue *next = cur->getNext();
228+
if (cur->isLeader()) {
229+
if (next) {
230+
next->Leader = cur->Leader;
231+
auto nn = next->Next;
232+
next->Next = (const ECValue*)((intptr_t)nn | (intptr_t)1);
233+
}
234+
} else {
235+
const ECValue *leader = findLeader(V).Node;
236+
const ECValue *pre = leader;
237+
while (pre->getNext() != cur) {
238+
pre = pre->getNext();
239+
}
240+
if (!next) {
241+
pre->Next = nullptr;
242+
leader->Leader = pre;
243+
} else {
244+
pre->Next = (const ECValue*)((intptr_t)next | (intptr_t)pre->isLeader());
245+
next->Leader = pre;
246+
}
247+
}
248+
TheMapping.erase(V);
249+
for (auto I = Members.begin(); I != Members.end(); I++) {
250+
if (*I == cur) {
251+
Members.erase(I);
252+
break;
253+
}
254+
}
255+
return true;
256+
}
223257
/// findLeader - Given a value in the set, return a member iterator for the
224258
/// equivalence class it is in. This does the path-compression part that
225259
/// makes union-find "union findy". This returns an end iterator if the value
@@ -247,16 +281,18 @@ template <class ElemTy> class EquivalenceClasses {
247281
// Otherwise, this is a real union operation. Set the end of the L1 list to
248282
// point to the L2 leader node.
249283
const ECValue &L1LV = *L1.Node, &L2LV = *L2.Node;
250-
L1LV.getEndOfList()->setNext(&L2LV);
284+
const ECValue *L1LastV = L1LV.getEndOfList();
285+
286+
L1LastV->setNext(&L2LV);
251287

252288
// Update L1LV's end of list pointer.
253289
L1LV.Leader = L2LV.getEndOfList();
254290

255291
// Clear L2's leader flag:
256292
L2LV.Next = L2LV.getNext();
257293

258-
// L2's leader is now L1.
259-
L2LV.Leader = &L1LV;
294+
// L2's leader is now last value of L1.
295+
L2LV.Leader = L1LastV;
260296
return L1;
261297
}
262298

llvm/unittests/ADT/EquivalenceClassesTest.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,55 @@ TEST(EquivalenceClassesTest, SimpleMerge2) {
5959
EXPECT_TRUE(EqClasses.isEquivalent(i, j));
6060
}
6161

62+
TEST(EquivalenceClassesTest, SimpleErase1) {
63+
EquivalenceClasses<int> EqClasses;
64+
// Check that erase head success.
65+
// After erase A from (A, B ,C, D), <B, C, D> belong to one set.
66+
EqClasses.unionSets(0, 1);
67+
EqClasses.unionSets(2, 3);
68+
EqClasses.unionSets(0, 2);
69+
EXPECT_TRUE(EqClasses.erase(0));
70+
for (int i = 1; i < 4; ++i)
71+
for (int j = 1; j < 4; ++j)
72+
EXPECT_TRUE(EqClasses.isEquivalent(i, j));
73+
}
74+
75+
TEST(EquivalenceClassesTest, SimpleErase2) {
76+
EquivalenceClasses<int> EqClasses;
77+
// Check that erase tail success.
78+
// After erase D from (A, B ,C, D), <A, B, C> belong to one set.
79+
EqClasses.unionSets(0, 1);
80+
EqClasses.unionSets(2, 3);
81+
EqClasses.unionSets(0, 2);
82+
EXPECT_TRUE(EqClasses.erase(3));
83+
for (int i = 0; i < 3; ++i)
84+
for (int j = 0; j < 3; ++j)
85+
EXPECT_TRUE(EqClasses.isEquivalent(i, j));
86+
}
87+
88+
TEST(EquivalenceClassesTest, SimpleErase3) {
89+
EquivalenceClasses<int> EqClasses;
90+
// Check that erase a value in the middle success.
91+
// After erase B from (A, B ,C, D), <A, C, D> belong to one set.
92+
EqClasses.unionSets(0, 1);
93+
EqClasses.unionSets(2, 3);
94+
EqClasses.unionSets(0, 2);
95+
EXPECT_TRUE(EqClasses.erase(1));
96+
for (int i = 0; i < 3; ++i)
97+
for (int j = 0; j < 3; ++j)
98+
EXPECT_TRUE(EqClasses.isEquivalent(i, j) ^ ((i == 1) ^ (j == 1)));
99+
}
100+
101+
TEST(EquivalenceClassesTest, SimpleErase4) {
102+
EquivalenceClasses<int> EqClasses;
103+
// Check that erase a single class success.
104+
EqClasses.insert(0);
105+
EXPECT_TRUE(EqClasses.getNumClasses() == 1);
106+
EXPECT_TRUE(EqClasses.erase(0));
107+
EXPECT_TRUE(EqClasses.getNumClasses() == 0);
108+
EXPECT_FALSE(EqClasses.erase(1));
109+
}
110+
62111
TEST(EquivalenceClassesTest, TwoSets) {
63112
EquivalenceClasses<int> EqClasses;
64113
// Form sets of odd and even numbers, check that we split them into these

0 commit comments

Comments
 (0)