Skip to content

Commit 4d92975

Browse files
authored
[SandboxVec][Scheduler] Don't allow rescheduling of already scheduled (#128050)
This patch implements the check for not allowing re-scheduling of instructions that have already been scheduled in a scheduling bundle. Rescheduling should only happen if the instructions were temporarily scheduled in singleton bundles during a previous call to `trySchedule()`.
1 parent 62c209b commit 4d92975

File tree

4 files changed

+300
-31
lines changed

4 files changed

+300
-31
lines changed

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ class SchedBundle {
133133
N->clearSchedBundle();
134134
}
135135
bool empty() const { return Nodes.empty(); }
136+
/// Singleton bundles are created when scheduling instructions temporarily to
137+
/// fill in the schedule until we schedule the vector bundle. These are
138+
/// non-vector bundles containing just a single instruction.
139+
bool isSingleton() const { return Nodes.size() == 1u; }
136140
DGNode *back() const { return Nodes.back(); }
137141
using iterator = ContainerTy::iterator;
138142
using const_iterator = ContainerTy::const_iterator;
@@ -190,10 +194,12 @@ class Scheduler {
190194
/// The scheduling state of the instructions in the bundle.
191195
enum class BndlSchedState {
192196
NoneScheduled, ///> No instruction in the bundle was previously scheduled.
193-
PartiallyOrDifferentlyScheduled, ///> Only some of the instrs in the bundle
194-
/// were previously scheduled, or all of
195-
/// them were but not in the same
196-
/// SchedBundle.
197+
AlreadyScheduled, ///> At least one instruction in the bundle belongs to a
198+
/// different non-singleton scheduling bundle.
199+
TemporarilyScheduled, ///> Instructions were temporarily scheduled as
200+
/// singleton bundles or some of them were not
201+
/// scheduled at all. None of them were in a vector
202+
///(non-singleton) bundle.
197203
FullyScheduled, ///> All instrs in the bundle were previously scheduled and
198204
/// were in the same SchedBundle.
199205
};
@@ -246,6 +252,11 @@ class Scheduler {
246252
class SchedulerInternalsAttorney {
247253
public:
248254
static DependencyGraph &getDAG(Scheduler &Sched) { return Sched.DAG; }
255+
using BndlSchedState = Scheduler::BndlSchedState;
256+
static BndlSchedState getBndlSchedState(const Scheduler &Sched,
257+
ArrayRef<Instruction *> Instrs) {
258+
return Sched.getBndlSchedState(Instrs);
259+
}
249260
};
250261

251262
} // namespace llvm::sandboxir

llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -161,30 +161,36 @@ bool Scheduler::tryScheduleUntil(ArrayRef<Instruction *> Instrs) {
161161
Scheduler::BndlSchedState
162162
Scheduler::getBndlSchedState(ArrayRef<Instruction *> Instrs) const {
163163
assert(!Instrs.empty() && "Expected non-empty bundle");
164-
bool PartiallyScheduled = false;
165-
bool FullyScheduled = true;
166-
for (auto *I : Instrs) {
164+
auto *N0 = DAG.getNode(Instrs[0]);
165+
auto *SB0 = N0 != nullptr ? N0->getSchedBundle() : nullptr;
166+
bool AllUnscheduled = SB0 == nullptr;
167+
bool FullyScheduled = SB0 != nullptr && !SB0->isSingleton();
168+
for (auto *I : drop_begin(Instrs)) {
167169
auto *N = DAG.getNode(I);
168-
if (N != nullptr && N->scheduled())
169-
PartiallyScheduled = true;
170-
else
171-
FullyScheduled = false;
172-
}
173-
if (FullyScheduled) {
174-
// If not all instrs in the bundle are in the same SchedBundle then this
175-
// should be considered as partially-scheduled, because we will need to
176-
// re-schedule.
177-
SchedBundle *SB = DAG.getNode(Instrs[0])->getSchedBundle();
178-
assert(SB != nullptr && "FullyScheduled assumes that there is an SB!");
179-
if (any_of(drop_begin(Instrs), [this, SB](sandboxir::Value *SBV) {
180-
return DAG.getNode(cast<sandboxir::Instruction>(SBV))
181-
->getSchedBundle() != SB;
182-
}))
170+
auto *SB = N != nullptr ? N->getSchedBundle() : nullptr;
171+
if (SB != nullptr) {
172+
// We found a scheduled instr, so there is now way all are unscheduled.
173+
AllUnscheduled = false;
174+
if (SB->isSingleton()) {
175+
// We found an instruction in a temporarily scheduled singleton. There
176+
// is no way that all instructions are scheduled in the same bundle.
177+
FullyScheduled = false;
178+
}
179+
}
180+
181+
if (SB != SB0) {
182+
// Either one of SB, SB0 is null, or they are in different bundles, so
183+
// Instrs are definitely not in the same vector bundle.
183184
FullyScheduled = false;
185+
// One of SB, SB0 are in a vector bundle and they differ.
186+
if ((SB != nullptr && !SB->isSingleton()) ||
187+
(SB0 != nullptr && !SB0->isSingleton()))
188+
return BndlSchedState::AlreadyScheduled;
189+
}
184190
}
185-
return FullyScheduled ? BndlSchedState::FullyScheduled
186-
: PartiallyScheduled ? BndlSchedState::PartiallyOrDifferentlyScheduled
187-
: BndlSchedState::NoneScheduled;
191+
return AllUnscheduled ? BndlSchedState::NoneScheduled
192+
: FullyScheduled ? BndlSchedState::FullyScheduled
193+
: BndlSchedState::TemporarilyScheduled;
188194
}
189195

190196
void Scheduler::trimSchedule(ArrayRef<Instruction *> Instrs) {
@@ -203,13 +209,14 @@ void Scheduler::trimSchedule(ArrayRef<Instruction *> Instrs) {
203209
//
204210
Instruction *TopI = &*ScheduleTopItOpt.value();
205211
Instruction *LowestI = VecUtils::getLowest(Instrs);
206-
// Destroy the schedule bundles from LowestI all the way to the top.
212+
// Destroy the singleton schedule bundles from LowestI all the way to the top.
207213
for (auto *I = LowestI, *E = TopI->getPrevNode(); I != E;
208214
I = I->getPrevNode()) {
209215
auto *N = DAG.getNode(I);
210216
if (N == nullptr)
211217
continue;
212-
if (auto *SB = N->getSchedBundle())
218+
auto *SB = N->getSchedBundle();
219+
if (SB->isSingleton())
213220
eraseBundle(SB);
214221
}
215222
// The DAG Nodes contain state like the number of UnscheduledSuccs and the
@@ -259,7 +266,12 @@ bool Scheduler::trySchedule(ArrayRef<Instruction *> Instrs) {
259266
case BndlSchedState::FullyScheduled:
260267
// Nothing to do.
261268
return true;
262-
case BndlSchedState::PartiallyOrDifferentlyScheduled:
269+
case BndlSchedState::AlreadyScheduled:
270+
// Instructions are part of a different vector schedule, so we can't
271+
// schedule \p Instrs in the same bundle (without destroying the existing
272+
// schedule).
273+
return false;
274+
case BndlSchedState::TemporarilyScheduled:
263275
// If one or more instrs are already scheduled we need to destroy the
264276
// top-most part of the schedule that includes the instrs in the bundle and
265277
// re-schedule.

llvm/test/Transforms/SandboxVectorizer/bottomup_basic.ll

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,3 +386,33 @@ define void @vecInstrsPlacement(ptr %ptr0) {
386386
store double %add1, ptr %ptr1
387387
ret void
388388
}
389+
390+
; During the bottom-up traversal we form bundle {ldA0,ldA1} but later when we
391+
; visit the RHS operands of the additions we try to form {ldA1,ldA2}
392+
; which is not allowed.
393+
define void @instrsInMultipleBundles(ptr noalias %ptr) {
394+
; CHECK-LABEL: define void @instrsInMultipleBundles(
395+
; CHECK-SAME: ptr noalias [[PTR:%.*]]) {
396+
; CHECK-NEXT: [[GEP0:%.*]] = getelementptr i8, ptr [[PTR]], i64 0
397+
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i8, ptr [[PTR]], i64 2
398+
; CHECK-NEXT: [[LDA2:%.*]] = load i8, ptr [[GEP2]], align 1
399+
; CHECK-NEXT: [[VECL:%.*]] = load <2 x i8>, ptr [[GEP0]], align 1
400+
; CHECK-NEXT: [[VEXT:%.*]] = extractelement <2 x i8> [[VECL]], i32 1
401+
; CHECK-NEXT: [[VINS:%.*]] = insertelement <2 x i8> poison, i8 [[VEXT]], i32 0
402+
; CHECK-NEXT: [[VINS1:%.*]] = insertelement <2 x i8> [[VINS]], i8 [[LDA2]], i32 1
403+
; CHECK-NEXT: [[VEC:%.*]] = add <2 x i8> [[VECL]], [[VINS1]]
404+
; CHECK-NEXT: store <2 x i8> [[VEC]], ptr [[GEP0]], align 1
405+
; CHECK-NEXT: ret void
406+
;
407+
%gep0 = getelementptr i8, ptr %ptr, i64 0
408+
%gep1 = getelementptr i8, ptr %ptr, i64 1
409+
%gep2 = getelementptr i8, ptr %ptr, i64 2
410+
%ldA0 = load i8, ptr %gep0
411+
%ldA1 = load i8, ptr %gep1
412+
%ldA2 = load i8, ptr %gep2
413+
%add0 = add i8 %ldA0, %ldA1
414+
%add1 = add i8 %ldA1, %ldA2
415+
store i8 %add0, ptr %gep0
416+
store i8 %add1, ptr %gep1
417+
ret void
418+
}

0 commit comments

Comments
 (0)