[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