[llvm] c214af8 - [SandboxVec][Interval] Implement intersection and difference operations (#110549)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 30 15:23:06 PDT 2024
Author: vporpo
Date: 2024-09-30T15:23:02-07:00
New Revision: c214af8454345a7986bce1395aad7f06b186352e
URL: https://github.com/llvm/llvm-project/commit/c214af8454345a7986bce1395aad7f06b186352e
DIFF: https://github.com/llvm/llvm-project/commit/c214af8454345a7986bce1395aad7f06b186352e.diff
LOG: [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-()
Added:
Modified:
llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h
llvm/unittests/Transforms/Vectorize/SandboxVectorizer/IntervalTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h
index d088c6c556f3a8..8f25ad109f6a61 100644
--- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h
+++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h
@@ -118,6 +118,64 @@ template <typename T> class Interval {
const_iterator end() const {
return const_iterator(To != nullptr ? To->getNextNode() : nullptr, *this);
}
+ /// Equality.
+ bool operator==(const Interval &Other) const {
+ return From == Other.From && To == Other.To;
+ }
+ /// Inequality.
+ bool operator!=(const Interval &Other) const { return !(*this == Other); }
+ /// \Returns true if this and \p Other have nothing in common.
+ bool disjoint(const Interval &Other) const {
+ if (Other.empty())
+ return true;
+ if (empty())
+ return true;
+ return Other.To->comesBefore(From) || To->comesBefore(Other.From);
+ }
+ /// \Returns the intersection between this and \p Other.
+ // Example:
+ // |----| this
+ // |---| Other
+ // |-| this->getIntersection(Other)
+ Interval intersection(const Interval &Other) const {
+ if (empty())
+ return *this;
+ if (Other.empty())
+ return Interval();
+ // 1. No overlap
+ // A---B this
+ // C--D Other
+ if (To->comesBefore(Other.From) || Other.To->comesBefore(From))
+ return Interval();
+ // 2. Overlap.
+ // A---B this
+ // C--D Other
+ auto NewFromI = From->comesBefore(Other.From) ? Other.From : From;
+ auto NewToI = To->comesBefore(Other.To) ? To : Other.To;
+ return Interval(NewFromI, NewToI);
+ }
+ /// Difference operation. This returns up to two intervals.
+ // Example:
+ // |--------| this
+ // |-| Other
+ // |-| |--| this - Other
+ SmallVector<Interval, 2> operator-(const Interval &Other) {
+ if (disjoint(Other))
+ return {*this};
+ if (Other.empty())
+ return {*this};
+ if (*this == Other)
+ return {Interval()};
+ Interval Intersection = intersection(Other);
+ SmallVector<Interval, 2> Result;
+ // Part 1, skip if empty.
+ if (From != Intersection.From)
+ Result.emplace_back(From, Intersection.From->getPrevNode());
+ // Part 2, skip if empty.
+ if (Intersection.To != To)
+ Result.emplace_back(Intersection.To->getNextNode(), To);
+ return Result;
+ }
};
} // namespace llvm::sandboxir
diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/IntervalTest.cpp b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/IntervalTest.cpp
index d463a61d5969b0..a697ce7727a9b0 100644
--- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/IntervalTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/IntervalTest.cpp
@@ -12,6 +12,7 @@
#include "llvm/SandboxIR/Function.h"
#include "llvm/SandboxIR/Instruction.h"
#include "llvm/Support/SourceMgr.h"
+#include "gmock/gmock-matchers.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -90,4 +91,161 @@ define void @foo(i8 %v0) {
auto BBIt = BB->begin();
for (auto &I : Intvl)
EXPECT_EQ(&I, &*BBIt++);
+ {
+ // Check equality.
+ EXPECT_TRUE(Empty == Empty);
+ EXPECT_FALSE(Empty == One);
+ EXPECT_TRUE(One == One);
+ sandboxir::Interval<sandboxir::Instruction> Intvl1(I0, I2);
+ sandboxir::Interval<sandboxir::Instruction> Intvl2(I0, I2);
+ EXPECT_TRUE(Intvl1 == Intvl1);
+ EXPECT_TRUE(Intvl1 == Intvl2);
+ }
+ {
+ // Check inequality.
+ EXPECT_FALSE(Empty != Empty);
+ EXPECT_TRUE(Empty != One);
+ EXPECT_FALSE(One != One);
+ sandboxir::Interval<sandboxir::Instruction> Intvl1(I0, I2);
+ sandboxir::Interval<sandboxir::Instruction> Intvl2(I0, I2);
+ EXPECT_FALSE(Intvl1 != Intvl1);
+ EXPECT_FALSE(Intvl1 != Intvl2);
+ }
+ {
+ // Check disjoint().
+ EXPECT_TRUE(Empty.disjoint(Empty));
+ EXPECT_TRUE(One.disjoint(Empty));
+ EXPECT_TRUE(Empty.disjoint(One));
+ sandboxir::Interval<sandboxir::Instruction> Intvl1(I0, I2);
+ sandboxir::Interval<sandboxir::Instruction> Intvl2(I1, Ret);
+ EXPECT_FALSE(Intvl1.disjoint(Intvl2));
+ sandboxir::Interval<sandboxir::Instruction> Intvl3(I2, I2);
+ EXPECT_FALSE(Intvl1.disjoint(Intvl3));
+ EXPECT_TRUE(Intvl1.disjoint(Empty));
+ }
+}
+
+// Helper function for returning a vector of instruction pointers from a range
+// of references.
+template <typename RangeT>
+static SmallVector<sandboxir::Instruction *> getPtrVec(RangeT Range) {
+ SmallVector<sandboxir::Instruction *> PtrVec;
+ for (sandboxir::Instruction &I : Range)
+ PtrVec.push_back(&I);
+ return PtrVec;
+}
+
+TEST_F(IntervalTest, Difference) {
+ parseIR(C, R"IR(
+define void @foo(i8 %v0) {
+ %I0 = add i8 %v0, %v0
+ %I1 = add i8 %v0, %v0
+ %I2 = add i8 %v0, %v0
+ ret void
+}
+)IR");
+ Function &LLVMF = *M->getFunction("foo");
+ sandboxir::Context Ctx(C);
+ auto &F = *Ctx.createFunction(&LLVMF);
+ auto *BB = &*F.begin();
+ auto It = BB->begin();
+ auto *I0 = &*It++;
+ auto *I1 = &*It++;
+ auto *I2 = &*It++;
+ auto *Ret = &*It++;
+
+ {
+ // Check [I0,Ret] - []
+ sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
+ sandboxir::Interval<sandboxir::Instruction> Empty;
+ auto Diffs = I0Ret - Empty;
+ EXPECT_EQ(Diffs.size(), 1u);
+ const sandboxir::Interval<sandboxir::Instruction> &Diff = Diffs[0];
+ EXPECT_THAT(getPtrVec(Diff), testing::ElementsAre(I0, I1, I2, Ret));
+ }
+ {
+ // Check [] - [I0,Ret]
+ sandboxir::Interval<sandboxir::Instruction> Empty;
+ sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
+ auto Diffs = Empty - I0Ret;
+ EXPECT_EQ(Diffs.size(), 1u);
+ const sandboxir::Interval<sandboxir::Instruction> &Diff = Diffs[0];
+ EXPECT_TRUE(Diff.empty());
+ }
+ {
+ // Check [I0,Ret] - [I0].
+ sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
+ sandboxir::Interval<sandboxir::Instruction> I0I0(I0, I0);
+ auto Diffs = I0Ret - I0I0;
+ EXPECT_EQ(Diffs.size(), 1u);
+ const sandboxir::Interval<sandboxir::Instruction> &Diff = Diffs[0];
+ EXPECT_THAT(getPtrVec(Diff), testing::ElementsAre(I1, I2, Ret));
+ }
+ {
+ // Check [I0,Ret] - [I1].
+ sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
+ sandboxir::Interval<sandboxir::Instruction> I1I1(I1, I1);
+ auto Diffs = I0Ret - I1I1;
+ EXPECT_EQ(Diffs.size(), 2u);
+ const sandboxir::Interval<sandboxir::Instruction> &Diff0 = Diffs[0];
+ EXPECT_THAT(getPtrVec(Diff0), testing::ElementsAre(I0));
+ const sandboxir::Interval<sandboxir::Instruction> &Diff1 = Diffs[1];
+ EXPECT_THAT(getPtrVec(Diff1), testing::ElementsAre(I2, Ret));
+ }
+}
+
+TEST_F(IntervalTest, Intersection) {
+ parseIR(C, R"IR(
+define void @foo(i8 %v0) {
+ %I0 = add i8 %v0, %v0
+ %I1 = add i8 %v0, %v0
+ %I2 = add i8 %v0, %v0
+ ret void
+}
+)IR");
+ Function &LLVMF = *M->getFunction("foo");
+ sandboxir::Context Ctx(C);
+ auto &F = *Ctx.createFunction(&LLVMF);
+ auto *BB = &*F.begin();
+ auto It = BB->begin();
+ auto *I0 = &*It++;
+ auto *I1 = &*It++;
+ [[maybe_unused]] auto *I2 = &*It++;
+ auto *Ret = &*It++;
+
+ {
+ // Check [I0,Ret] ^ []
+ sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
+ sandboxir::Interval<sandboxir::Instruction> Empty;
+ auto Intersection = I0Ret.intersection(Empty);
+ EXPECT_TRUE(Intersection.empty());
+ }
+ {
+ // Check [] ^ [I0,Ret]
+ sandboxir::Interval<sandboxir::Instruction> Empty;
+ sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
+ auto Intersection = Empty.intersection(I0Ret);
+ EXPECT_TRUE(Intersection.empty());
+ }
+ {
+ // Check [I0,Ret] ^ [I0]
+ sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
+ sandboxir::Interval<sandboxir::Instruction> I0I0(I0, I0);
+ auto Intersection = I0Ret.intersection(I0I0);
+ EXPECT_THAT(getPtrVec(Intersection), testing::ElementsAre(I0));
+ }
+ {
+ // Check [I0] ^ [I0,Ret]
+ sandboxir::Interval<sandboxir::Instruction> I0I0(I0, I0);
+ sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
+ auto Intersection = I0I0.intersection(I0Ret);
+ EXPECT_THAT(getPtrVec(Intersection), testing::ElementsAre(I0));
+ }
+ {
+ // Check [I0,Ret] ^ [I1].
+ sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
+ sandboxir::Interval<sandboxir::Instruction> I1I1(I1, I1);
+ auto Intersection = I0Ret.intersection(I1I1);
+ EXPECT_THAT(getPtrVec(Intersection), testing::ElementsAre(I1));
+ }
}
More information about the llvm-commits
mailing list