Skip to content

Conversation

@vporpo
Copy link
Contributor

@vporpo vporpo commented Dec 10, 2024

This patch implements the notifier for Instruction intervals. It updates the interval's top/bottom.

@llvmbot
Copy link
Member

llvmbot commented Dec 10, 2024

@llvm/pr-subscribers-vectorizers

@llvm/pr-subscribers-llvm-transforms

Author: vporpo (vporpo)

Changes

This patch implements the notifier for Instruction intervals. It updates the interval's top/bottom.


Full diff: https://github.com/llvm/llvm-project/pull/119471.diff

2 Files Affected:

  • (modified) llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h (+24)
  • (modified) llvm/unittests/Transforms/Vectorize/SandboxVectorizer/IntervalTest.cpp (+109)
diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h
index e2d0b82489ddc7..922dd2c3a1f893 100644
--- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h
+++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h
@@ -21,8 +21,10 @@
 #define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_INSTRINTERVAL_H
 
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/SandboxIR/Instruction.h"
 #include "llvm/Support/raw_ostream.h"
 #include <iterator>
+#include <type_traits>
 
 namespace llvm::sandboxir {
 
@@ -207,6 +209,28 @@ template <typename T> class Interval {
     return {NewTop, NewBottom};
   }
 
+  /// Update the interval when \p I is about to be moved before \p Before.
+  // SFINAE disables this for non-Instructions.
+  template <typename HelperT = T>
+  std::enable_if_t<std::is_same<HelperT, Instruction>::value, void>
+  notifyMoveInstr(HelperT *I, decltype(I->getIterator()) BeforeIt) {
+    assert(contains(I) && "Expect `I` in interval!");
+    assert(I->getIterator() != BeforeIt && "Can't move `I` before itself!");
+
+    // Nothing to do if the instruction won't move.
+    if (std::next(I->getIterator()) == BeforeIt)
+      return;
+
+    T *NewTop = Top->getIterator() == BeforeIt ? I
+                : I == Top                     ? Top->getNextNode()
+                                               : Top;
+    T *NewBottom = std::next(Bottom->getIterator()) == BeforeIt ? I
+                   : I == Bottom ? Bottom->getPrevNode()
+                                 : Bottom;
+    Top = NewTop;
+    Bottom = NewBottom;
+  }
+
 #ifndef NDEBUG
   void print(raw_ostream &OS) const {
     auto *Top = top();
diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/IntervalTest.cpp b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/IntervalTest.cpp
index b04e4fc7cffcae..32521ed79a314b 100644
--- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/IntervalTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/IntervalTest.cpp
@@ -331,3 +331,112 @@ define void @foo(i8 %v0) {
     EXPECT_THAT(getPtrVec(SingleUnion), testing::ElementsAre(I0, I1, I2, Ret));
   }
 }
+
+TEST_F(IntervalTest, NotifyMoveInstr) {
+  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++;
+  {
+    // Assert that we don't try to move external instr to the interval.
+    sandboxir::Interval<sandboxir::Instruction> I2Ret(I2, Ret);
+#ifndef NDEBUG
+    EXPECT_DEATH(I2Ret.notifyMoveInstr(I0, Ret->getIterator()), ".*interval.*");
+#endif // NDEBUG
+  }
+  {
+    // Assert that we don't move before self.
+    sandboxir::Interval<sandboxir::Instruction> I2Ret(I2, Ret);
+#ifndef NDEBUG
+    EXPECT_DEATH(I2Ret.notifyMoveInstr(Ret, Ret->getIterator()), ".*self.*");
+#endif // NDEBUG
+  }
+  {
+    // Single-element interval.
+    sandboxir::Interval<sandboxir::Instruction> I2I2(I2, I2);
+    I2I2.notifyMoveInstr(I2, Ret->getIterator());
+    EXPECT_EQ(I2I2.top(), I2);
+    EXPECT_EQ(I2I2.bottom(), I2);
+  }
+  {
+    // Two-element interval swap.
+    sandboxir::Interval<sandboxir::Instruction> I1I2(I1, I2);
+    I1I2.notifyMoveInstr(I2, I1->getIterator());
+    I2->moveBefore(I1);
+    EXPECT_EQ(I1I2.top(), I2);
+    EXPECT_EQ(I1I2.bottom(), I1);
+
+    I2->moveAfter(I1);
+  }
+  {
+    // Move to same position.
+    sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
+    I0Ret.notifyMoveInstr(I0, I1->getIterator());
+    I0->moveBefore(I1);
+    EXPECT_EQ(I0Ret.top(), I0);
+    EXPECT_EQ(I0Ret.bottom(), Ret);
+  }
+  {
+    // Move internal to internal.
+    sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
+    I0Ret.notifyMoveInstr(I2, I1->getIterator());
+    I2->moveBefore(I1);
+    EXPECT_EQ(I0Ret.top(), I0);
+    EXPECT_EQ(I0Ret.bottom(), Ret);
+
+    I2->moveAfter(I1);
+  }
+  {
+    // Move internal before top.
+    sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
+    I0Ret.notifyMoveInstr(I2, I0->getIterator());
+    I2->moveBefore(I0);
+    EXPECT_EQ(I0Ret.top(), I2);
+    EXPECT_EQ(I0Ret.bottom(), Ret);
+
+    I2->moveAfter(I1);
+  }
+  {
+    // Move internal to bottom.
+    sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
+    I0Ret.notifyMoveInstr(I2, BB->end());
+    I2->moveAfter(Ret);
+    EXPECT_EQ(I0Ret.top(), I0);
+    EXPECT_EQ(I0Ret.bottom(), I2);
+
+    I2->moveAfter(I1);
+  }
+  {
+    // Move bottom before internal.
+    sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
+    I0Ret.notifyMoveInstr(Ret, I2->getIterator());
+    Ret->moveBefore(I2);
+    EXPECT_EQ(I0Ret.top(), I0);
+    EXPECT_EQ(I0Ret.bottom(), I2);
+
+    Ret->moveAfter(I2);
+  }
+  {
+    // Move bottom before top.
+    sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
+    I0Ret.notifyMoveInstr(Ret, I0->getIterator());
+    Ret->moveBefore(I0);
+    EXPECT_EQ(I0Ret.top(), Ret);
+    EXPECT_EQ(I0Ret.bottom(), I2);
+
+    Ret->moveAfter(I2);
+  }
+}

This patch implements the notifier for Instruction intervals.
It updates the interval's top/bottom.
@vporpo
Copy link
Contributor Author

vporpo commented Dec 11, 2024

rebase

@vporpo vporpo merged commit 3769fcb into llvm:main Dec 16, 2024
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants