Skip to content

Commit 68a3d5f

Browse files
committed
[MachinePipeliner] Detect a cycle in PHI dependencies early on
Abort pipelining in the below case %1 = phi i32 [ %a, %entry ], [ %3, %loop ] %2 = phi i32 [ %a, %entry ], [ %1, %loop ] %3 = phi i32 [ %b, %entry ], [ %2, %loop ]
1 parent de4aa9c commit 68a3d5f

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

llvm/lib/CodeGen/MachinePipeliner.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,56 @@ void MachinePipeliner::setPragmaPipelineOptions(MachineLoop &L) {
485485
}
486486
}
487487

488+
bool hasPHICycle(const MachineBasicBlock *LoopHeader,
489+
const MachineRegisterInfo &MRI) {
490+
DenseMap<unsigned, SmallVector<unsigned, 2>> PhiDeps;
491+
SmallSet<unsigned, 8> PhiRegs;
492+
493+
// Collect PHI nodes and their dependencies
494+
for (const MachineInstr &MI : *LoopHeader) {
495+
if (!MI.isPHI())
496+
continue;
497+
498+
unsigned DefReg = MI.getOperand(0).getReg();
499+
PhiRegs.insert(DefReg);
500+
501+
for (unsigned i = 1; i < MI.getNumOperands(); i += 2) {
502+
unsigned SrcReg = MI.getOperand(i).getReg();
503+
PhiDeps[DefReg].push_back(SrcReg);
504+
}
505+
}
506+
507+
// DFS to detect cycles
508+
SmallSet<unsigned, 8> Visited, RecStack;
509+
510+
std::function<bool(unsigned)> DFS = [&](unsigned Reg) -> bool {
511+
if (!PhiRegs.count(Reg))
512+
return false;
513+
if (RecStack.count(Reg))
514+
return true;
515+
if (Visited.count(Reg))
516+
return false;
517+
518+
Visited.insert(Reg);
519+
RecStack.insert(Reg);
520+
521+
for (unsigned Dep : PhiDeps[Reg]) {
522+
if (DFS(Dep))
523+
return true;
524+
}
525+
526+
RecStack.erase(Reg);
527+
return false;
528+
};
529+
530+
for (unsigned Reg : PhiRegs) {
531+
if (DFS(Reg))
532+
return true;
533+
}
534+
535+
return false;
536+
}
537+
488538
/// Return true if the loop can be software pipelined. The algorithm is
489539
/// restricted to loops with a single basic block. Make sure that the
490540
/// branch in the loop can be analyzed.
@@ -499,6 +549,11 @@ bool MachinePipeliner::canPipelineLoop(MachineLoop &L) {
499549
return false;
500550
}
501551

552+
if (hasPHICycle(L.getHeader(), MF->getRegInfo())) {
553+
LLVM_DEBUG(dbgs() << "Cannot pipeline loop due to PHI cycle\n");
554+
return false;
555+
}
556+
502557
if (disabledByPragma) {
503558
ORE->emit([&]() {
504559
return MachineOptimizationRemarkAnalysis(DEBUG_TYPE, "canPipelineLoop",
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
; RUN: llc -mtriple=hexagon-unknown-linux-gnu -enable-pipeliner -debug-only=pipeliner < %s 2>&1 | FileCheck %s
2+
3+
; CHECK: Cannot pipeline loop due to PHI cycle
4+
5+
define void @phi_cycle_loop(i32 %a, i32 %b) {
6+
entry:
7+
br label %loop
8+
9+
loop:
10+
%1 = phi i32 [ %a, %entry ], [ %3, %loop ]
11+
%2 = phi i32 [ %a, %entry ], [ %1, %loop ]
12+
%3 = phi i32 [ %b, %entry ], [ %2, %loop ]
13+
14+
; Prevent PHI elimination by using all values
15+
%add1 = add i32 %1, %2
16+
%add2 = add i32 %add1, %3
17+
%cmp = icmp slt i32 %add2, 100
18+
br i1 %cmp, label %loop, label %exit
19+
20+
exit:
21+
ret void
22+
}

0 commit comments

Comments
 (0)