Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions llvm/lib/CodeGen/MachinePipeliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,61 @@ void MachinePipeliner::setPragmaPipelineOptions(MachineLoop &L) {
}
}

/// Depth-first search to detect cycles among PHI dependencies.
/// Returns true if a cycle is detected within the PHI-only subgraph.
static bool hasPHICycleDFS(
unsigned Reg, const DenseMap<unsigned, SmallVector<unsigned, 2>> &PhiDeps,
SmallSet<unsigned, 8> &Visited, SmallSet<unsigned, 8> &RecStack) {

// If Reg is not a PHI-def it cannot contribute to a PHI cycle.
auto It = PhiDeps.find(Reg);
if (It == PhiDeps.end())
return false;

if (RecStack.count(Reg))
return true; // backedge.
if (Visited.count(Reg))
return false;

Visited.insert(Reg);
RecStack.insert(Reg);

for (unsigned Dep : It->second) {
if (hasPHICycleDFS(Dep, PhiDeps, Visited, RecStack))
return true;
}

RecStack.erase(Reg);
return false;
}

static bool hasPHICycle(const MachineBasicBlock *LoopHeader,
const MachineRegisterInfo &MRI) {
DenseMap<unsigned, SmallVector<unsigned, 2>> PhiDeps;

// Collect PHI nodes and their dependencies.
for (const MachineInstr &MI : LoopHeader->phis()) {
unsigned DefReg = MI.getOperand(0).getReg();
auto Ins = PhiDeps.try_emplace(DefReg).first;

// PHI operands are (Reg, MBB) pairs starting at index 1.
for (unsigned I = 1; I < MI.getNumOperands(); I += 2)
Ins->second.push_back(MI.getOperand(I).getReg());
}

// DFS to detect cycles among PHI nodes.
SmallSet<unsigned, 8> Visited, RecStack;

// Start DFS from each PHI-def.
for (const auto &KV : PhiDeps) {
unsigned Reg = KV.first;
if (hasPHICycleDFS(Reg, PhiDeps, Visited, RecStack))
return true;
}

return false;
}

/// Return true if the loop can be software pipelined. The algorithm is
/// restricted to loops with a single basic block. Make sure that the
/// branch in the loop can be analyzed.
Expand All @@ -502,6 +557,11 @@ bool MachinePipeliner::canPipelineLoop(MachineLoop &L) {
return false;
}

if (hasPHICycle(L.getHeader(), MF->getRegInfo())) {
LLVM_DEBUG(dbgs() << "Cannot pipeline loop due to PHI cycle\n");
return false;
}

if (disabledByPragma) {
ORE->emit([&]() {
return MachineOptimizationRemarkAnalysis(DEBUG_TYPE, "canPipelineLoop",
Expand Down
23 changes: 23 additions & 0 deletions llvm/test/CodeGen/Hexagon/swp-phi-cycle.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
; RUN: llc -mtriple=hexagon-unknown-linux-gnu -enable-pipeliner -debug-only=pipeliner < %s 2>&1 | FileCheck %s
; REQUIRES: asserts

; CHECK: Cannot pipeline loop due to PHI cycle

define void @phi_cycle_loop(i32 %a, i32 %b) {
entry:
br label %loop

loop:
%1 = phi i32 [ %a, %entry ], [ %3, %loop ]
%2 = phi i32 [ %a, %entry ], [ %1, %loop ]
%3 = phi i32 [ %b, %entry ], [ %2, %loop ]

; Prevent PHI elimination by using all values
%add1 = add i32 %1, %2
%add2 = add i32 %add1, %3
%cmp = icmp slt i32 %add2, 100
br i1 %cmp, label %loop, label %exit

exit:
ret void
}
Loading