Skip to content

Commit 3769fcb

Browse files
authored
[SandboxVec][Interval] Implement Interval::notifyMoveInstr() (#119471)
This patch implements the notifier for Instruction intervals. It updates the interval's top/bottom.
1 parent 0b442bc commit 3769fcb

File tree

2 files changed

+133
-0
lines changed

2 files changed

+133
-0
lines changed

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_INSTRINTERVAL_H
2222

2323
#include "llvm/ADT/ArrayRef.h"
24+
#include "llvm/SandboxIR/Instruction.h"
2425
#include "llvm/Support/raw_ostream.h"
2526
#include <iterator>
27+
#include <type_traits>
2628

2729
namespace llvm::sandboxir {
2830

@@ -207,6 +209,28 @@ template <typename T> class Interval {
207209
return {NewTop, NewBottom};
208210
}
209211

212+
/// Update the interval when \p I is about to be moved before \p Before.
213+
// SFINAE disables this for non-Instructions.
214+
template <typename HelperT = T>
215+
std::enable_if_t<std::is_same<HelperT, Instruction>::value, void>
216+
notifyMoveInstr(HelperT *I, decltype(I->getIterator()) BeforeIt) {
217+
assert(contains(I) && "Expect `I` in interval!");
218+
assert(I->getIterator() != BeforeIt && "Can't move `I` before itself!");
219+
220+
// Nothing to do if the instruction won't move.
221+
if (std::next(I->getIterator()) == BeforeIt)
222+
return;
223+
224+
T *NewTop = Top->getIterator() == BeforeIt ? I
225+
: I == Top ? Top->getNextNode()
226+
: Top;
227+
T *NewBottom = std::next(Bottom->getIterator()) == BeforeIt ? I
228+
: I == Bottom ? Bottom->getPrevNode()
229+
: Bottom;
230+
Top = NewTop;
231+
Bottom = NewBottom;
232+
}
233+
210234
#ifndef NDEBUG
211235
void print(raw_ostream &OS) const {
212236
auto *Top = top();

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

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,3 +331,112 @@ define void @foo(i8 %v0) {
331331
EXPECT_THAT(getPtrVec(SingleUnion), testing::ElementsAre(I0, I1, I2, Ret));
332332
}
333333
}
334+
335+
TEST_F(IntervalTest, NotifyMoveInstr) {
336+
parseIR(C, R"IR(
337+
define void @foo(i8 %v0) {
338+
%I0 = add i8 %v0, %v0
339+
%I1 = add i8 %v0, %v0
340+
%I2 = add i8 %v0, %v0
341+
ret void
342+
}
343+
)IR");
344+
Function &LLVMF = *M->getFunction("foo");
345+
sandboxir::Context Ctx(C);
346+
auto &F = *Ctx.createFunction(&LLVMF);
347+
auto *BB = &*F.begin();
348+
auto It = BB->begin();
349+
auto *I0 = &*It++;
350+
auto *I1 = &*It++;
351+
auto *I2 = &*It++;
352+
auto *Ret = &*It++;
353+
{
354+
// Assert that we don't try to move external instr to the interval.
355+
sandboxir::Interval<sandboxir::Instruction> I2Ret(I2, Ret);
356+
#ifndef NDEBUG
357+
EXPECT_DEATH(I2Ret.notifyMoveInstr(I0, Ret->getIterator()), ".*interval.*");
358+
#endif // NDEBUG
359+
}
360+
{
361+
// Assert that we don't move before self.
362+
sandboxir::Interval<sandboxir::Instruction> I2Ret(I2, Ret);
363+
#ifndef NDEBUG
364+
EXPECT_DEATH(I2Ret.notifyMoveInstr(Ret, Ret->getIterator()), ".*self.*");
365+
#endif // NDEBUG
366+
}
367+
{
368+
// Single-element interval.
369+
sandboxir::Interval<sandboxir::Instruction> I2I2(I2, I2);
370+
I2I2.notifyMoveInstr(I2, Ret->getIterator());
371+
EXPECT_EQ(I2I2.top(), I2);
372+
EXPECT_EQ(I2I2.bottom(), I2);
373+
}
374+
{
375+
// Two-element interval swap.
376+
sandboxir::Interval<sandboxir::Instruction> I1I2(I1, I2);
377+
I1I2.notifyMoveInstr(I2, I1->getIterator());
378+
I2->moveBefore(I1);
379+
EXPECT_EQ(I1I2.top(), I2);
380+
EXPECT_EQ(I1I2.bottom(), I1);
381+
382+
I2->moveAfter(I1);
383+
}
384+
{
385+
// Move to same position.
386+
sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
387+
I0Ret.notifyMoveInstr(I0, I1->getIterator());
388+
I0->moveBefore(I1);
389+
EXPECT_EQ(I0Ret.top(), I0);
390+
EXPECT_EQ(I0Ret.bottom(), Ret);
391+
}
392+
{
393+
// Move internal to internal.
394+
sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
395+
I0Ret.notifyMoveInstr(I2, I1->getIterator());
396+
I2->moveBefore(I1);
397+
EXPECT_EQ(I0Ret.top(), I0);
398+
EXPECT_EQ(I0Ret.bottom(), Ret);
399+
400+
I2->moveAfter(I1);
401+
}
402+
{
403+
// Move internal before top.
404+
sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
405+
I0Ret.notifyMoveInstr(I2, I0->getIterator());
406+
I2->moveBefore(I0);
407+
EXPECT_EQ(I0Ret.top(), I2);
408+
EXPECT_EQ(I0Ret.bottom(), Ret);
409+
410+
I2->moveAfter(I1);
411+
}
412+
{
413+
// Move internal to bottom.
414+
sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
415+
I0Ret.notifyMoveInstr(I2, BB->end());
416+
I2->moveAfter(Ret);
417+
EXPECT_EQ(I0Ret.top(), I0);
418+
EXPECT_EQ(I0Ret.bottom(), I2);
419+
420+
I2->moveAfter(I1);
421+
}
422+
{
423+
// Move bottom before internal.
424+
sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
425+
I0Ret.notifyMoveInstr(Ret, I2->getIterator());
426+
Ret->moveBefore(I2);
427+
EXPECT_EQ(I0Ret.top(), I0);
428+
EXPECT_EQ(I0Ret.bottom(), I2);
429+
430+
Ret->moveAfter(I2);
431+
}
432+
{
433+
// Move bottom before top.
434+
sandboxir::Interval<sandboxir::Instruction> I0Ret(I0, Ret);
435+
I0Ret.notifyMoveInstr(Ret, I0->getIterator());
436+
Ret->moveBefore(I0);
437+
EXPECT_EQ(I0Ret.top(), Ret);
438+
EXPECT_EQ(I0Ret.bottom(), I2);
439+
440+
Ret->moveAfter(I2);
441+
}
442+
}

0 commit comments

Comments
 (0)