diff --git a/llvm/include/llvm/CodeGen/MachinePipeliner.h b/llvm/include/llvm/CodeGen/MachinePipeliner.h --- a/llvm/include/llvm/CodeGen/MachinePipeliner.h +++ b/llvm/include/llvm/CodeGen/MachinePipeliner.h @@ -58,6 +58,7 @@ class SMSchedule; extern cl::opt SwpEnableCopyToPhi; +extern cl::opt SwpForceIssueWidth; /// The main class in the implementation of the target independent /// software pipeliner pass. @@ -444,46 +445,85 @@ private: const MCSubtargetInfo *STI; const MCSchedModel &SM; + const TargetSubtargetInfo *ST; + const TargetInstrInfo *TII; const bool UseDFA; - std::unique_ptr DFAResources; + /// DFA resources for each slot + llvm::SmallVector> DFAResources; + /// Modulo Reservation Table. When a resource with ID R is consumed in cycle + /// C, it is counted in MRT[C mod II][R]. (Used when UseDFA == F) + llvm::SmallVector> MRT; + /// The number of scheduled instructions for each slot + llvm::SmallVector NumScheduledInsts; /// Each processor resource is associated with a so-called processor resource /// mask. This vector allows to correlate processor resource IDs with /// processor resource masks. There is exactly one element per each processor /// resource declared by the scheduling model. llvm::SmallVector ProcResourceMasks; + int InitiationInterval; + /// The number of instructions that can be scheduled at a cycle. + int IssueWidth; + + int calculateResMIIDFA(const SmallVectorImpl &Insts, + const SwingSchedulerDAG *DAG) const; + /// Check if MRT is overbooked + bool isOverbooked() const; + /// Reserve resources on MRT + void reserveResources(const MCSchedClassDesc *SCDesc, int Cycle); + /// Unreserve resources on MRT + void unreserveResources(const MCSchedClassDesc *SCDesc, int Cycle); + + /// Return M satisfying Dividend = Divisor * X + M, 0 < M < abs(Divisor). + /// The slot on MRT to reserve a resource for the cycle C is positiveModulo(C, + /// II). + int positiveModulo(int Dividend, int Divisor) const { + int R = Dividend % Divisor; + if (R < 0) + R += Divisor; + return R; + } - llvm::SmallVector ProcResourceCount; +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dumpMRT() const; +#endif public: ResourceManager(const TargetSubtargetInfo *ST) - : STI(ST), SM(ST->getSchedModel()), UseDFA(ST->useDFAforSMS()), + : STI(ST), SM(ST->getSchedModel()), ST(ST), TII(ST->getInstrInfo()), + UseDFA(ST->useDFAforSMS()), ProcResourceMasks(SM.getNumProcResourceKinds(), 0), - ProcResourceCount(SM.getNumProcResourceKinds(), 0) { - if (UseDFA) - DFAResources.reset(ST->getInstrInfo()->CreateTargetScheduleState(*ST)); + IssueWidth(SM.IssueWidth) { initProcResourceVectors(SM, ProcResourceMasks); + if (IssueWidth <= 0) + // If IssueWidth is not specified, set a sufficiently large value + IssueWidth = 100; + if (SwpForceIssueWidth > 0) + IssueWidth = SwpForceIssueWidth; } void initProcResourceVectors(const MCSchedModel &SM, SmallVectorImpl &Masks); /// Check if the resources occupied by a MCInstrDesc are available in /// the current state. - bool canReserveResources(const MCInstrDesc *MID) const; + bool canReserveResources(const MCInstrDesc *MID, int Cycle); /// Reserve the resources occupied by a MCInstrDesc and change the current /// state to reflect that change. - void reserveResources(const MCInstrDesc *MID); + void reserveResources(const MCInstrDesc *MID, int Cycle); /// Check if the resources occupied by a machine instruction are available /// in the current state. - bool canReserveResources(const MachineInstr &MI) const; + bool canReserveResources(const MachineInstr &MI, int Cycle); /// Reserve the resources occupied by a machine instruction and change the /// current state to reflect that change. - void reserveResources(const MachineInstr &MI); + void reserveResources(const MachineInstr &MI, int Cycle); - /// Reset the state - void clearResources(); + int calculateResMII(const SmallVectorImpl &Insts, + const SwingSchedulerDAG *DAG) const; + + /// Initialize resources with the initiation interval II. + void init(int II); }; /// This class represents the scheduled code. The main data structure is a @@ -533,7 +573,10 @@ } /// Set the initiation interval for this schedule. - void setInitiationInterval(int ii) { InitiationInterval = ii; } + void setInitiationInterval(int ii) { + InitiationInterval = ii; + ProcItinResources.init(ii); + } /// Return the initiation interval for this schedule. int getInitiationInterval() const { return InitiationInterval; } diff --git a/llvm/lib/CodeGen/MachinePipeliner.cpp b/llvm/lib/CodeGen/MachinePipeliner.cpp --- a/llvm/lib/CodeGen/MachinePipeliner.cpp +++ b/llvm/lib/CodeGen/MachinePipeliner.cpp @@ -43,6 +43,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/CycleAnalysis.h" #include "llvm/Analysis/MemoryLocation.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/ValueTracking.h" @@ -84,9 +85,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -121,6 +124,12 @@ cl::desc("Size limit for the MII."), cl::Hidden, cl::init(27)); +/// A command line argument to force pipeliner to use specified initial +/// interval. +static cl::opt SwpForceII("pipeliner-force-ii", + cl::desc("Force pipeliner to use specified II."), + cl::Hidden, cl::init(-1)); + /// A command line argument to limit the number of stages in the pipeline. static cl::opt SwpMaxStages("pipeliner-max-stages", @@ -172,6 +181,13 @@ cl::init(true), cl::desc("Enable CopyToPhi DAG Mutation")); +/// A command line argument to force pipeliner to use specified issue +/// width. +cl::opt SwpForceIssueWidth( + "pipeliner-force-issue-width", + cl::desc("Force pipeliner to use specified issue width."), cl::Hidden, + cl::init(-1)); + } // end namespace llvm unsigned SwingSchedulerDAG::Circuits::MaxPaths = 5; @@ -454,14 +470,18 @@ } void SwingSchedulerDAG::setMII(unsigned ResMII, unsigned RecMII) { - if (II_setByPragma > 0) + if (SwpForceII > 0) + MII = SwpForceII; + else if (II_setByPragma > 0) MII = II_setByPragma; else MII = std::max(ResMII, RecMII); } void SwingSchedulerDAG::setMAX_II() { - if (II_setByPragma > 0) + if (SwpForceII > 0) + MAX_II = SwpForceII; + else if (II_setByPragma > 0) MAX_II = II_setByPragma; else MAX_II = MII + 10; @@ -1095,9 +1115,7 @@ unsigned SwingSchedulerDAG::calculateResMII() { LLVM_DEBUG(dbgs() << "calculateResMII:\n"); - SmallVector Resources; MachineBasicBlock *MBB = Loop.getHeader(); - Resources.push_back(new ResourceManager(&MF.getSubtarget())); // Sort the instructions by the number of available choices for scheduling, // least to most. Use the number of critical resources as the tie breaker. @@ -1107,58 +1125,19 @@ FUS.calcCriticalResources(MI); PriorityQueue, FuncUnitSorter> FuncUnitOrder(FUS); + SmallVector InstsSorted; for (MachineInstr &MI : llvm::make_range(MBB->getFirstNonPHI(), MBB->getFirstTerminator())) FuncUnitOrder.push(&MI); while (!FuncUnitOrder.empty()) { - MachineInstr *MI = FuncUnitOrder.top(); + InstsSorted.push_back(FuncUnitOrder.top()); FuncUnitOrder.pop(); - if (TII->isZeroCost(MI->getOpcode())) - continue; - // Attempt to reserve the instruction in an existing DFA. At least one - // DFA is needed for each cycle. - unsigned NumCycles = getSUnit(MI)->Latency; - unsigned ReservedCycles = 0; - SmallVectorImpl::iterator RI = Resources.begin(); - SmallVectorImpl::iterator RE = Resources.end(); - LLVM_DEBUG({ - dbgs() << "Trying to reserve resource for " << NumCycles - << " cycles for \n"; - MI->dump(); - }); - for (unsigned C = 0; C < NumCycles; ++C) - while (RI != RE) { - if ((*RI)->canReserveResources(*MI)) { - (*RI)->reserveResources(*MI); - ++ReservedCycles; - break; - } - RI++; - } - LLVM_DEBUG(dbgs() << "ReservedCycles:" << ReservedCycles - << ", NumCycles:" << NumCycles << "\n"); - // Add new DFAs, if needed, to reserve resources. - for (unsigned C = ReservedCycles; C < NumCycles; ++C) { - LLVM_DEBUG(if (SwpDebugResource) dbgs() - << "NewResource created to reserve resources" - << "\n"); - ResourceManager *NewResource = new ResourceManager(&MF.getSubtarget()); - assert(NewResource->canReserveResources(*MI) && "Reserve error."); - NewResource->reserveResources(*MI); - Resources.push_back(NewResource); - } - } - int Resmii = Resources.size(); - LLVM_DEBUG(dbgs() << "Return Res MII:" << Resmii << "\n"); - // Delete the memory for each of the DFAs that were created earlier. - for (ResourceManager *RI : Resources) { - ResourceManager *D = RI; - delete D; } - Resources.clear(); - return Resmii; + + ResourceManager RM(&MF.getSubtarget()); + return RM.calculateResMII(InstsSorted, this); } /// Calculate the recurrence-constrainted minimum initiation interval. @@ -2375,28 +2354,15 @@ for (int curCycle = StartCycle; curCycle != termCycle; forward ? ++curCycle : --curCycle) { - // Add the already scheduled instructions at the specified cycle to the - // DFA. - ProcItinResources.clearResources(); - for (int checkCycle = FirstCycle + ((curCycle - FirstCycle) % II); - checkCycle <= LastCycle; checkCycle += II) { - std::deque &cycleInstrs = ScheduledInstrs[checkCycle]; - - for (SUnit *CI : cycleInstrs) { - if (ST.getInstrInfo()->isZeroCost(CI->getInstr()->getOpcode())) - continue; - assert(ProcItinResources.canReserveResources(*CI->getInstr()) && - "These instructions have already been scheduled."); - ProcItinResources.reserveResources(*CI->getInstr()); - } - } if (ST.getInstrInfo()->isZeroCost(SU->getInstr()->getOpcode()) || - ProcItinResources.canReserveResources(*SU->getInstr())) { + ProcItinResources.canReserveResources(*SU->getInstr(), curCycle)) { LLVM_DEBUG({ dbgs() << "\tinsert at cycle " << curCycle << " "; SU->getInstr()->dump(); }); + if (!ST.getInstrInfo()->isZeroCost(SU->getInstr()->getOpcode())) + ProcItinResources.reserveResources(*SU->getInstr(), curCycle); ScheduledInstrs[curCycle].push_back(SU); InstrToCycle.insert(std::make_pair(SU, curCycle)); if (curCycle > LastCycle) @@ -3025,6 +2991,25 @@ LLVM_DUMP_METHOD void SMSchedule::dump() const { print(dbgs()); } LLVM_DUMP_METHOD void NodeSet::dump() const { print(dbgs()); } +void ResourceManager::dumpMRT() const { + LLVM_DEBUG({ + if (UseDFA) + return; + std::stringstream SS; + SS << "MRT:\n"; + SS << std::setw(4) << "Slot"; + for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) + SS << std::setw(3) << I; + SS << std::setw(7) << "#Insts" << "\n"; + for (int Slot = 0; Slot < InitiationInterval; ++Slot) { + SS << std::setw(4) << Slot; + for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) + SS << std::setw(3) << MRT[Slot][I]; + SS << std::setw(7) << NumScheduledInsts[Slot] << "\n"; + } + dbgs() << SS.str(); + }); +} #endif void ResourceManager::initProcResourceVectors( @@ -3069,14 +3054,15 @@ }); } -bool ResourceManager::canReserveResources(const MCInstrDesc *MID) const { +bool ResourceManager::canReserveResources(const MCInstrDesc *MID, int Cycle) { LLVM_DEBUG({ if (SwpDebugResource) dbgs() << "canReserveResources:\n"; }); if (UseDFA) - return DFAResources->canReserveResources(MID); + return DFAResources[positiveModulo(Cycle, InitiationInterval)] + ->canReserveResources(MID); unsigned InsnClass = MID->getSchedClass(); const MCSchedClassDesc *SCDesc = SM.getSchedClassDesc(InsnClass); @@ -3088,35 +3074,28 @@ return true; } - const MCWriteProcResEntry *I = STI->getWriteProcResBegin(SCDesc); - const MCWriteProcResEntry *E = STI->getWriteProcResEnd(SCDesc); - for (; I != E; ++I) { - if (!I->Cycles) - continue; - const MCProcResourceDesc *ProcResource = - SM.getProcResource(I->ProcResourceIdx); - unsigned NumUnits = ProcResource->NumUnits; - LLVM_DEBUG({ - if (SwpDebugResource) - dbgs() << format(" %16s(%2d): Count: %2d, NumUnits:%2d, Cycles:%2d\n", - ProcResource->Name, I->ProcResourceIdx, - ProcResourceCount[I->ProcResourceIdx], NumUnits, - I->Cycles); - }); - if (ProcResourceCount[I->ProcResourceIdx] >= NumUnits) - return false; + bool Result; + if (NumScheduledInsts[positiveModulo(Cycle, InitiationInterval)] >= + IssueWidth) { + Result = false; + } else { + reserveResources(SCDesc, Cycle); + Result = !isOverbooked(); + unreserveResources(SCDesc, Cycle); } - LLVM_DEBUG(if (SwpDebugResource) dbgs() << "return true\n\n";); - return true; + + LLVM_DEBUG(if (SwpDebugResource) dbgs() << "return " << Result << "\n\n";); + return Result; } -void ResourceManager::reserveResources(const MCInstrDesc *MID) { +void ResourceManager::reserveResources(const MCInstrDesc *MID, int Cycle) { LLVM_DEBUG({ if (SwpDebugResource) dbgs() << "reserveResources:\n"; }); if (UseDFA) - return DFAResources->reserveResources(MID); + return DFAResources[positiveModulo(Cycle, InitiationInterval)] + ->reserveResources(MID); unsigned InsnClass = MID->getSchedClass(); const MCSchedClassDesc *SCDesc = SM.getSchedClassDesc(InsnClass); @@ -3127,39 +3106,187 @@ }); return; } - for (const MCWriteProcResEntry &PRE : - make_range(STI->getWriteProcResBegin(SCDesc), - STI->getWriteProcResEnd(SCDesc))) { - if (!PRE.Cycles) - continue; - ++ProcResourceCount[PRE.ProcResourceIdx]; - LLVM_DEBUG({ - if (SwpDebugResource) { - const MCProcResourceDesc *ProcResource = - SM.getProcResource(PRE.ProcResourceIdx); - dbgs() << format(" %16s(%2d): Count: %2d, NumUnits:%2d, Cycles:%2d\n", - ProcResource->Name, PRE.ProcResourceIdx, - ProcResourceCount[PRE.ProcResourceIdx], - ProcResource->NumUnits, PRE.Cycles); - } - }); - } + + ++NumScheduledInsts[positiveModulo(Cycle, InitiationInterval)]; + reserveResources(SCDesc, Cycle); + LLVM_DEBUG({ - if (SwpDebugResource) + if (SwpDebugResource) { + dumpMRT(); dbgs() << "reserveResources: done!\n\n"; + } }); } -bool ResourceManager::canReserveResources(const MachineInstr &MI) const { - return canReserveResources(&MI.getDesc()); +bool ResourceManager::canReserveResources(const MachineInstr &MI, int Cycle) { + return canReserveResources(&MI.getDesc(), Cycle); +} + +void ResourceManager::reserveResources(const MachineInstr &MI, int Cycle) { + return reserveResources(&MI.getDesc(), Cycle); } -void ResourceManager::reserveResources(const MachineInstr &MI) { - return reserveResources(&MI.getDesc()); +void ResourceManager::reserveResources(const MCSchedClassDesc *SCDesc, + int Cycle) { + assert(!UseDFA); + for (const MCWriteProcResEntry &PRE : make_range( + STI->getWriteProcResBegin(SCDesc), STI->getWriteProcResEnd(SCDesc))) + for (int C = Cycle; C < Cycle + PRE.Cycles; C++) + ++MRT[positiveModulo(C, InitiationInterval)][PRE.ProcResourceIdx]; } -void ResourceManager::clearResources() { +void ResourceManager::unreserveResources(const MCSchedClassDesc *SCDesc, + int Cycle) { + assert(!UseDFA); + for (const MCWriteProcResEntry &PRE : make_range( + STI->getWriteProcResBegin(SCDesc), STI->getWriteProcResEnd(SCDesc))) + for (int C = Cycle; C < Cycle + PRE.Cycles; C++) + --MRT[positiveModulo(C, InitiationInterval)][PRE.ProcResourceIdx]; +} + +bool ResourceManager::isOverbooked() const { + assert(!UseDFA); + for (int Slot = 0; Slot < InitiationInterval; ++Slot) { + for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) { + const MCProcResourceDesc *Desc = SM.getProcResource(I); + if (MRT[Slot][I] > Desc->NumUnits) + return true; + } + } + return false; +} + +int ResourceManager::calculateResMIIDFA( + const SmallVectorImpl &Insts, + const SwingSchedulerDAG *DAG) const { + + SmallVector, 8> Resources; + Resources.push_back( + std::unique_ptr(TII->CreateTargetScheduleState(*ST))); + + for (auto *MI : Insts) { + if (TII->isZeroCost(MI->getOpcode())) + continue; + + // Attempt to reserve the instruction in an existing DFA. At least one + // DFA is needed for each cycle. + unsigned NumCycles = DAG->getSUnit(MI)->Latency; + unsigned ReservedCycles = 0; + auto *RI = Resources.begin(); + auto *RE = Resources.end(); + LLVM_DEBUG({ + dbgs() << "Trying to reserve resource for " << NumCycles + << " cycles for \n"; + MI->dump(); + }); + for (unsigned C = 0; C < NumCycles; ++C) + while (RI != RE) { + if ((*RI)->canReserveResources(*MI)) { + (*RI)->reserveResources(*MI); + ++ReservedCycles; + break; + } + RI++; + } + LLVM_DEBUG(dbgs() << "ReservedCycles:" << ReservedCycles + << ", NumCycles:" << NumCycles << "\n"); + // Add new DFAs, if needed, to reserve resources. + for (unsigned C = ReservedCycles; C < NumCycles; ++C) { + LLVM_DEBUG(if (SwpDebugResource) dbgs() + << "NewResource created to reserve resources" + << "\n"); + auto *NewResource = TII->CreateTargetScheduleState(*ST); + assert(NewResource->canReserveResources(*MI) && "Reserve error."); + NewResource->reserveResources(*MI); + Resources.push_back(std::unique_ptr(NewResource)); + } + } + + int Resmii = Resources.size(); + LLVM_DEBUG(dbgs() << "Return Res MII:" << Resmii << "\n"); + return Resmii; +} + +int ResourceManager::calculateResMII( + const SmallVectorImpl &Insts, + const SwingSchedulerDAG *DAG) const { if (UseDFA) - return DFAResources->clearResources(); - std::fill(ProcResourceCount.begin(), ProcResourceCount.end(), 0); + return calculateResMIIDFA(Insts, DAG); + + // Count each resource consumption and divide it by the number of units. + // ResMII is the max value among them. + + int NumInsts = 0; + SmallVector ResourceCount(SM.getNumProcResourceKinds()); + for (MachineInstr *MI : Insts) { + if (TII->isZeroCost(MI->getOpcode())) + continue; + + const MCSchedClassDesc *SCDesc = + SM.getSchedClassDesc(MI->getDesc().getSchedClass()); + if (!SCDesc->isValid()) + continue; + + LLVM_DEBUG(if (SwpDebugResource) DAG->dumpNode(*DAG->getSUnit(MI));); + ++NumInsts; + for (const MCWriteProcResEntry &PRE : + make_range(STI->getWriteProcResBegin(SCDesc), + STI->getWriteProcResEnd(SCDesc))) { + LLVM_DEBUG({ + if (SwpDebugResource) { + const MCProcResourceDesc *Desc = + SM.getProcResource(PRE.ProcResourceIdx); + dbgs() << Desc->Name << ": " << PRE.Cycles << ", "; + } + }); + ResourceCount[PRE.ProcResourceIdx] += PRE.Cycles; + } + LLVM_DEBUG(if (SwpDebugResource) dbgs() << "\n"); + } + + int Result = (NumInsts + IssueWidth - 1) / IssueWidth; + LLVM_DEBUG({ + if (SwpDebugResource) + dbgs() << "#Insts: " << NumInsts << ", " + << "IssueWidth: " << IssueWidth << ", " + << "Cycles: " << Result << "\n"; + }); + + LLVM_DEBUG({ + if (SwpDebugResource) { + std::stringstream SS; + SS << std::setw(2) << "ID" << std::setw(16) << "Name" << std::setw(10) + << "Units" << std::setw(10) << "Consumed" << std::setw(10) << "Cycles" + << "\n"; + dbgs() << SS.str(); + } + }); + for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) { + const MCProcResourceDesc *Desc = SM.getProcResource(I); + int Cycles = (ResourceCount[I] + Desc->NumUnits - 1) / Desc->NumUnits; + LLVM_DEBUG({ + if (SwpDebugResource) { + std::stringstream SS; + SS << std::setw(2) << I << std::setw(16) << Desc->Name << std::setw(10) + << Desc->NumUnits << std::setw(10) << ResourceCount[I] + << std::setw(10) << Cycles << "\n"; + dbgs() << SS.str(); + } + }); + if (Cycles > Result) + Result = Cycles; + } + return Result; +} + +void ResourceManager::init(int II) { + InitiationInterval = II; + DFAResources.clear(); + DFAResources.resize(II); + for (auto &I : DFAResources) + I.reset(ST->getInstrInfo()->CreateTargetScheduleState(*ST)); + MRT.clear(); + MRT.resize(II, SmallVector(SM.getNumProcResourceKinds())); + NumScheduledInsts.clear(); + NumScheduledInsts.resize(II); } diff --git a/llvm/test/CodeGen/PowerPC/sms-iterator.ll b/llvm/test/CodeGen/PowerPC/sms-iterator.ll --- a/llvm/test/CodeGen/PowerPC/sms-iterator.ll +++ b/llvm/test/CodeGen/PowerPC/sms-iterator.ll @@ -5,7 +5,7 @@ %0 = type { i32, [16 x double] } -; CHECK: MII = 8 MAX_II = 18 +; CHECK: MII = 3 MAX_II = 13 (rec=3, res=2) define dso_local fastcc double @_ZN3povL9polysolveEiPdS0_() unnamed_addr #0 { br label %1 diff --git a/llvm/test/CodeGen/PowerPC/sms-phi-1.ll b/llvm/test/CodeGen/PowerPC/sms-phi-1.ll --- a/llvm/test/CodeGen/PowerPC/sms-phi-1.ll +++ b/llvm/test/CodeGen/PowerPC/sms-phi-1.ll @@ -1,6 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=powerpc64le-unknown-linux-gnu -verify-machineinstrs\ -; RUN: -mcpu=pwr9 --ppc-enable-pipeliner 2>&1 | FileCheck %s +; RUN: -mcpu=pwr9 --ppc-enable-pipeliner --pipeliner-force-ii=4 2>&1 | FileCheck %s define void @main() nounwind #0 { ; CHECK-LABEL: main: diff --git a/llvm/test/CodeGen/PowerPC/sms-phi-2.ll b/llvm/test/CodeGen/PowerPC/sms-phi-2.ll --- a/llvm/test/CodeGen/PowerPC/sms-phi-2.ll +++ b/llvm/test/CodeGen/PowerPC/sms-phi-2.ll @@ -1,6 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=powerpc64le-unknown-linux-gnu -verify-machineinstrs\ -; RUN: -mcpu=pwr9 --ppc-enable-pipeliner 2>&1 | FileCheck %s +; RUN: -mcpu=pwr9 --ppc-enable-pipeliner --pipeliner-force-ii=15 2>&1 | FileCheck %s define void @phi2(i32, i32, i8*) local_unnamed_addr { ; CHECK-LABEL: phi2: