Skip to content

Commit c214af8

Browse files
authored
[SandboxVec][Interval] Implement intersection and difference operations (#110549)
This patch implements a few set operations for the intervals. These include: - operator==() and operator!=() for comparing two intervals. - disjoint() - intersection() - difference, which uses operator-()
1 parent 96f37ae commit c214af8

File tree

2 files changed

+216
-0
lines changed

2 files changed

+216
-0
lines changed

llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,64 @@ template <typename T> class Interval {
118118
const_iterator end() const {
119119
return const_iterator(To != nullptr ? To->getNextNode() : nullptr, *this);
120120
}
121+
/// Equality.
122+
bool operator==(const Interval &Other) const {
123+
return From == Other.From && To == Other.To;
124+
}
125+
/// Inequality.
126+
bool operator!=(const Interval &Other) const { return !(*this == Other); }
127+
/// \Returns true if this and \p Other have nothing in common.
128+
bool disjoint(const Interval &Other) const {
129+
if (Other.empty())
130+
return true;
131+
if (empty())
132+
return true;
133+
return Other.To->comesBefore(From) || To->comesBefore(Other.From);
134+
}
135+
/// \Returns the intersection between this and \p Other.
136+
// Example:
137+
// |----| this
138+
// |---| Other
139+
// |-| this->getIntersection(Other)
140+
Interval intersection(const Interval &Other) const {
141+
if (empty())
142+
return *this;
143+
if (Other.empty())
144+
return Interval();
145+
// 1. No overlap
146+
// A---B this
147+
// C--D Other
148+
if (To->comesBefore(Other.From) || Other.To->comesBefore(From))
149+
return Interval();
150+
// 2. Overlap.
151+
// A---B this
152+
// C--D Other
153+
auto NewFromI = From->comesBefore(Other.From) ? Other.From : From;
154+
auto NewToI = To->comesBefore(Other.To) ? To : Other.To;
155+
return Interval(NewFromI, NewToI);
156+
}
157+
/// Difference operation. This returns up to two intervals.
158+
// Example:
159+
// |--------| this
160+
// |-| Other
161+
// |-| |--| this - Other
162+
SmallVector<Interval, 2> operator-(const Interval &Other) {
163+
if (disjoint(Other))
164+
return {*this};
165+
if (Other.empty())
166+
return {*this};
167+
if (*this == Other)
168+
return {Interval()};
169+
Interval Intersection = intersection(Other);
170+
SmallVector<Interval, 2> Result;
171+
// Part 1, skip if empty.
172+
if (From != Intersection.From)
173+
Result.emplace_back(From, Intersection.From->getPrevNode());
174+
// Part 2, skip if empty.
175+
if (Intersection.To != To)
176+
Result.emplace_back(Intersection.To->getNextNode(), To);
177+
return Result;
178+
}
121179
};
122180

123181
} // namespace llvm::sandboxir

llvm/unittests/Transforms/Vectorize/SandboxVectorizer/IntervalTest.cpp

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "llvm/SandboxIR/Function.h"
1313
#include "llvm/SandboxIR/Instruction.h"
1414
#include "llvm/Support/SourceMgr.h"
15+
#include "gmock/gmock-matchers.h"
1516
#include "gtest/gtest.h"
1617

1718
using namespace llvm;
@@ -90,4 +91,161 @@ define void @foo(i8 %v0) {
9091
auto BBIt = BB->begin();
9192
for (auto &I : Intvl)
9293
EXPECT_EQ(&I, &*BBIt++);
94+
{
95+
// Check equality.
96+
EXPECT_TRUE(Empty == Empty);
97+
EXPECT_FALSE(Empty == One);
98+
EXPECT_TRUE(One == One);
99+
sandboxir::Interval<sandboxir::Instruction> Intvl1(I0, I2);
100+
sandboxir::Interval<sandboxir::Instruction> Intvl2(I0, I2);
101+
EXPECT_TRUE(Intvl1 == Intvl1);
102+
EXPECT_TRUE(Intvl1 == Intvl2);
103+
}
104+
{
105+
// Check inequality.
106+
EXPECT_FALSE(Empty != Empty);
107+
EXPECT_TRUE(Empty != One);
108+
EXPECT_FALSE(One != One);
109+
sandboxir::Interval<sandboxir::Instruction> Intvl1(I0, I2);
110+
sandboxir::Interval<sandboxir::Instruction> Intvl2(I0, I2);
111+
EXPECT_FALSE(Intvl1 != Intvl1);
112+
EXPECT_FALSE(Intvl1 != Intvl2);
113+
}
114+
{
115+
// Check disjoint().
116+
EXPECT_TRUE(Empty.disjoint(Empty));
117+
EXPECT_TRUE(One.disjoint(Empty));
118+
EXPECT_TRUE(Empty.disjoint(One));
119+
sandboxir::Interval<sandboxir::Instruction> Intvl1(I0, I2);
120+
sandboxir::Interval<sandboxir::Instruction> Intvl2(I1, Ret);
121+
EXPECT_FALSE(Intvl1.disjoint(Intvl2));
122+
sandboxir::Interval<sandboxir::Instruction> Intvl3(I2, I2);
123+
EXPECT_FALSE(Intvl1.disjoint(Intvl3));
124+
EXPECT_TRUE(Intvl1.disjoint(Empty));
125+
}
126+
}
127+
128+
// Helper function for returning a vector of instruction pointers from a range
129+
// of references.
130+
template <typename RangeT>
131+
static SmallVector<sandboxir::Instruction *> getPtrVec(RangeT Range) {
132+
SmallVector<sandboxir::Instruction *> PtrVec;
133+
for (sandboxir::Instruction &I : Range)
134+
PtrVec.push_back(&I);
135+
return PtrVec;
136+
}
137+
138+
TEST_F(IntervalTest, Difference) {
139+
parseIR(C, R"IR(
140+
define void @foo(i8 %v0) {
141+
%I0 = add i8 %v0, %v0
142+
%I1 = add i8 %v0, %v0
143+
%I2 = add i8 %v0, %v0
144+
ret void
145+
}
146+
)IR");
147+
Function &LLVMF = *M->getFunction("foo");
148+
sandboxir::Context Ctx(C);
149+
auto &F = *Ctx.createFunction(&LLVMF);
150+
auto *BB = &*F.begin();
151+
auto It = BB->begin();
152+
auto *I0 = &*It++;
153+
auto *I1 = &*It++;
154+
auto *I2 = &*It++;
155+
auto *Ret = &*It++;
156+
157+
{
158+
// Check [I0,Ret] - []
159+
sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
160+
sandboxir::Interval<sandboxir::Instruction> Empty;
161+
auto Diffs = I0Ret - Empty;
162+
EXPECT_EQ(Diffs.size(), 1u);
163+
const sandboxir::Interval<sandboxir::Instruction> &Diff = Diffs[0];
164+
EXPECT_THAT(getPtrVec(Diff), testing::ElementsAre(I0, I1, I2, Ret));
165+
}
166+
{
167+
// Check [] - [I0,Ret]
168+
sandboxir::Interval<sandboxir::Instruction> Empty;
169+
sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
170+
auto Diffs = Empty - I0Ret;
171+
EXPECT_EQ(Diffs.size(), 1u);
172+
const sandboxir::Interval<sandboxir::Instruction> &Diff = Diffs[0];
173+
EXPECT_TRUE(Diff.empty());
174+
}
175+
{
176+
// Check [I0,Ret] - [I0].
177+
sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
178+
sandboxir::Interval<sandboxir::Instruction> I0I0(I0, I0);
179+
auto Diffs = I0Ret - I0I0;
180+
EXPECT_EQ(Diffs.size(), 1u);
181+
const sandboxir::Interval<sandboxir::Instruction> &Diff = Diffs[0];
182+
EXPECT_THAT(getPtrVec(Diff), testing::ElementsAre(I1, I2, Ret));
183+
}
184+
{
185+
// Check [I0,Ret] - [I1].
186+
sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
187+
sandboxir::Interval<sandboxir::Instruction> I1I1(I1, I1);
188+
auto Diffs = I0Ret - I1I1;
189+
EXPECT_EQ(Diffs.size(), 2u);
190+
const sandboxir::Interval<sandboxir::Instruction> &Diff0 = Diffs[0];
191+
EXPECT_THAT(getPtrVec(Diff0), testing::ElementsAre(I0));
192+
const sandboxir::Interval<sandboxir::Instruction> &Diff1 = Diffs[1];
193+
EXPECT_THAT(getPtrVec(Diff1), testing::ElementsAre(I2, Ret));
194+
}
195+
}
196+
197+
TEST_F(IntervalTest, Intersection) {
198+
parseIR(C, R"IR(
199+
define void @foo(i8 %v0) {
200+
%I0 = add i8 %v0, %v0
201+
%I1 = add i8 %v0, %v0
202+
%I2 = add i8 %v0, %v0
203+
ret void
204+
}
205+
)IR");
206+
Function &LLVMF = *M->getFunction("foo");
207+
sandboxir::Context Ctx(C);
208+
auto &F = *Ctx.createFunction(&LLVMF);
209+
auto *BB = &*F.begin();
210+
auto It = BB->begin();
211+
auto *I0 = &*It++;
212+
auto *I1 = &*It++;
213+
[[maybe_unused]] auto *I2 = &*It++;
214+
auto *Ret = &*It++;
215+
216+
{
217+
// Check [I0,Ret] ^ []
218+
sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
219+
sandboxir::Interval<sandboxir::Instruction> Empty;
220+
auto Intersection = I0Ret.intersection(Empty);
221+
EXPECT_TRUE(Intersection.empty());
222+
}
223+
{
224+
// Check [] ^ [I0,Ret]
225+
sandboxir::Interval<sandboxir::Instruction> Empty;
226+
sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
227+
auto Intersection = Empty.intersection(I0Ret);
228+
EXPECT_TRUE(Intersection.empty());
229+
}
230+
{
231+
// Check [I0,Ret] ^ [I0]
232+
sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
233+
sandboxir::Interval<sandboxir::Instruction> I0I0(I0, I0);
234+
auto Intersection = I0Ret.intersection(I0I0);
235+
EXPECT_THAT(getPtrVec(Intersection), testing::ElementsAre(I0));
236+
}
237+
{
238+
// Check [I0] ^ [I0,Ret]
239+
sandboxir::Interval<sandboxir::Instruction> I0I0(I0, I0);
240+
sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
241+
auto Intersection = I0I0.intersection(I0Ret);
242+
EXPECT_THAT(getPtrVec(Intersection), testing::ElementsAre(I0));
243+
}
244+
{
245+
// Check [I0,Ret] ^ [I1].
246+
sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
247+
sandboxir::Interval<sandboxir::Instruction> I1I1(I1, I1);
248+
auto Intersection = I0Ret.intersection(I1I1);
249+
EXPECT_THAT(getPtrVec(Intersection), testing::ElementsAre(I1));
250+
}
93251
}

0 commit comments

Comments
 (0)