Skip to content

[SandboxVec][Interval] Implement Interval::notifyMoveInstr() #119471

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 16, 2024

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