diff --git a/llvm/lib/CodeGen/MachinePipeliner.cpp b/llvm/lib/CodeGen/MachinePipeliner.cpp index e2f7dfc5cadd5..0ded0d6fc2f5d 100644 --- a/llvm/lib/CodeGen/MachinePipeliner.cpp +++ b/llvm/lib/CodeGen/MachinePipeliner.cpp @@ -485,6 +485,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> &PhiDeps, + SmallSet &Visited, SmallSet &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> 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 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. @@ -499,6 +554,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", diff --git a/llvm/test/CodeGen/Hexagon/swp-phi-cycle.ll b/llvm/test/CodeGen/Hexagon/swp-phi-cycle.ll new file mode 100644 index 0000000000000..1b4fc464fa092 --- /dev/null +++ b/llvm/test/CodeGen/Hexagon/swp-phi-cycle.ll @@ -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 +}