#include "llvm/CodeGen/MachineScheduler.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PriorityQueue.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/CodeGen/LiveInterval.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachinePassRegistry.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterClassInfo.h"
#include "llvm/CodeGen/RegisterPressure.h"
#include "llvm/CodeGen/ScheduleDAG.h"
#include "llvm/CodeGen/ScheduleDAGInstrs.h"
#include "llvm/CodeGen/ScheduleDAGMutation.h"
#include "llvm/CodeGen/ScheduleDFS.h"
#include "llvm/CodeGen/ScheduleHazardRecognizer.h"
#include "llvm/CodeGen/SlotIndexes.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSchedule.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/CodeGenTypes/MachineValueType.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/InitializePasses.h"
#include "llvm/MC/LaneBitmask.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <iterator>
#include <limits>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
usingnamespacellvm;
#define DEBUG_TYPE …
STATISTIC(NumClustered, "Number of load/store pairs clustered");
namespace llvm {
cl::opt<bool> ForceTopDown("misched-topdown", cl::Hidden,
cl::desc("Force top-down list scheduling"));
cl::opt<bool> ForceBottomUp("misched-bottomup", cl::Hidden,
cl::desc("Force bottom-up list scheduling"));
namespace MISchedPostRASched {
enum Direction { … };
}
cl::opt<MISchedPostRASched::Direction> PostRADirection(
"misched-postra-direction", cl::Hidden,
cl::desc("Post reg-alloc list scheduling direction"),
cl::init(MISchedPostRASched::TopDown),
cl::values(
clEnumValN(MISchedPostRASched::TopDown, "topdown",
"Force top-down post reg-alloc list scheduling"),
clEnumValN(MISchedPostRASched::BottomUp, "bottomup",
"Force bottom-up post reg-alloc list scheduling"),
clEnumValN(MISchedPostRASched::Bidirectional, "bidirectional",
"Force bidirectional post reg-alloc list scheduling")));
cl::opt<bool>
DumpCriticalPathLength("misched-dcpl", cl::Hidden,
cl::desc("Print critical path length to stdout"));
cl::opt<bool> VerifyScheduling(
"verify-misched", cl::Hidden,
cl::desc("Verify machine instrs before and after machine scheduling"));
#ifndef NDEBUG
cl::opt<bool> ViewMISchedDAGs(
"view-misched-dags", cl::Hidden,
cl::desc("Pop up a window to show MISched dags after they are processed"));
cl::opt<bool> PrintDAGs("misched-print-dags", cl::Hidden,
cl::desc("Print schedule DAGs"));
cl::opt<bool> MISchedDumpReservedCycles(
"misched-dump-reserved-cycles", cl::Hidden, cl::init(false),
cl::desc("Dump resource usage at schedule boundary."));
cl::opt<bool> MischedDetailResourceBooking(
"misched-detail-resource-booking", cl::Hidden, cl::init(false),
cl::desc("Show details of invoking getNextResoufceCycle."));
#else
const bool ViewMISchedDAGs = …;
const bool PrintDAGs = …;
const bool MischedDetailResourceBooking = …;
#ifdef LLVM_ENABLE_DUMP
const bool MISchedDumpReservedCycles = false;
#endif
#endif
}
#ifndef NDEBUG
static cl::opt<unsigned> ViewMISchedCutoff("view-misched-cutoff", cl::Hidden,
cl::desc("Hide nodes with more predecessor/successor than cutoff"));
static cl::opt<unsigned> MISchedCutoff("misched-cutoff", cl::Hidden,
cl::desc("Stop scheduling after N instructions"), cl::init(~0U));
static cl::opt<std::string> SchedOnlyFunc("misched-only-func", cl::Hidden,
cl::desc("Only schedule this function"));
static cl::opt<unsigned> SchedOnlyBlock("misched-only-block", cl::Hidden,
cl::desc("Only schedule this MBB#"));
#endif
static cl::opt<unsigned> ReadyListLimit("misched-limit", cl::Hidden,
cl::desc("Limit ready list to N instructions"), cl::init(256));
static cl::opt<bool> EnableRegPressure("misched-regpressure", cl::Hidden,
cl::desc("Enable register pressure scheduling."), cl::init(true));
static cl::opt<bool> EnableCyclicPath("misched-cyclicpath", cl::Hidden,
cl::desc("Enable cyclic critical path analysis."), cl::init(true));
static cl::opt<bool> EnableMemOpCluster("misched-cluster", cl::Hidden,
cl::desc("Enable memop clustering."),
cl::init(true));
static cl::opt<bool>
ForceFastCluster("force-fast-cluster", cl::Hidden,
cl::desc("Switch to fast cluster algorithm with the lost "
"of some fusion opportunities"),
cl::init(false));
static cl::opt<unsigned>
FastClusterThreshold("fast-cluster-threshold", cl::Hidden,
cl::desc("The threshold for fast cluster"),
cl::init(1000));
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
static cl::opt<bool> MISchedDumpScheduleTrace(
"misched-dump-schedule-trace", cl::Hidden, cl::init(false),
cl::desc("Dump resource usage at schedule boundary."));
static cl::opt<unsigned>
HeaderColWidth("misched-dump-schedule-trace-col-header-width", cl::Hidden,
cl::desc("Set width of the columns with "
"the resources and schedule units"),
cl::init(19));
static cl::opt<unsigned>
ColWidth("misched-dump-schedule-trace-col-width", cl::Hidden,
cl::desc("Set width of the columns showing resource booking."),
cl::init(5));
static cl::opt<bool> MISchedSortResourcesInTrace(
"misched-sort-resources-in-trace", cl::Hidden, cl::init(true),
cl::desc("Sort the resources printed in the dump trace"));
#endif
static cl::opt<unsigned>
MIResourceCutOff("misched-resource-cutoff", cl::Hidden,
cl::desc("Number of intervals to track"), cl::init(10));
static const unsigned MinSubtreeSize = …;
void MachineSchedStrategy::anchor() { … }
void ScheduleDAGMutation::anchor() { … }
MachineSchedContext::MachineSchedContext() { … }
MachineSchedContext::~MachineSchedContext() { … }
namespace {
class MachineSchedulerBase : public MachineSchedContext,
public MachineFunctionPass { … };
class MachineScheduler : public MachineSchedulerBase { … };
class PostMachineScheduler : public MachineSchedulerBase { … };
}
char MachineScheduler::ID = …;
char &llvm::MachineSchedulerID = …;
INITIALIZE_PASS_BEGIN(MachineScheduler, DEBUG_TYPE,
"Machine Instruction Scheduler", false, false)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(SlotIndexesWrapperPass)
INITIALIZE_PASS_DEPENDENCY(LiveIntervalsWrapperPass)
INITIALIZE_PASS_END(MachineScheduler, DEBUG_TYPE,
"Machine Instruction Scheduler", false, false)
MachineScheduler::MachineScheduler() : … { … }
void MachineScheduler::getAnalysisUsage(AnalysisUsage &AU) const { … }
char PostMachineScheduler::ID = …;
char &llvm::PostMachineSchedulerID = …;
INITIALIZE_PASS_BEGIN(PostMachineScheduler, "postmisched",
"PostRA Machine Instruction Scheduler", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_END(PostMachineScheduler, "postmisched",
"PostRA Machine Instruction Scheduler", false, false)
PostMachineScheduler::PostMachineScheduler() : … { … }
void PostMachineScheduler::getAnalysisUsage(AnalysisUsage &AU) const { … }
MachinePassRegistry<MachineSchedRegistry::ScheduleDAGCtor>
MachineSchedRegistry::Registry;
static ScheduleDAGInstrs *useDefaultMachineSched(MachineSchedContext *C) { … }
static cl::opt<MachineSchedRegistry::ScheduleDAGCtor, false,
RegisterPassParser<MachineSchedRegistry>>
MachineSchedOpt("misched",
cl::init(&useDefaultMachineSched), cl::Hidden,
cl::desc("Machine instruction scheduler to use"));
static MachineSchedRegistry
DefaultSchedRegistry("default", "Use the target's default scheduler choice.",
useDefaultMachineSched);
static cl::opt<bool> EnableMachineSched(
"enable-misched",
cl::desc("Enable the machine instruction scheduling pass."), cl::init(true),
cl::Hidden);
static cl::opt<bool> EnablePostRAMachineSched(
"enable-post-misched",
cl::desc("Enable the post-ra machine instruction scheduling pass."),
cl::init(true), cl::Hidden);
static MachineBasicBlock::const_iterator
priorNonDebug(MachineBasicBlock::const_iterator I,
MachineBasicBlock::const_iterator Beg) { … }
static MachineBasicBlock::iterator
priorNonDebug(MachineBasicBlock::iterator I,
MachineBasicBlock::const_iterator Beg) { … }
static MachineBasicBlock::const_iterator
nextIfDebug(MachineBasicBlock::const_iterator I,
MachineBasicBlock::const_iterator End) { … }
static MachineBasicBlock::iterator
nextIfDebug(MachineBasicBlock::iterator I,
MachineBasicBlock::const_iterator End) { … }
ScheduleDAGInstrs *MachineScheduler::createMachineScheduler() { … }
ScheduleDAGInstrs *PostMachineScheduler::createPostMachineScheduler() { … }
bool MachineScheduler::runOnMachineFunction(MachineFunction &mf) { … }
bool PostMachineScheduler::runOnMachineFunction(MachineFunction &mf) { … }
static bool isSchedBoundary(MachineBasicBlock::iterator MI,
MachineBasicBlock *MBB,
MachineFunction *MF,
const TargetInstrInfo *TII) { … }
namespace {
struct SchedRegion { … };
}
MBBRegionsVector;
static void
getSchedRegions(MachineBasicBlock *MBB,
MBBRegionsVector &Regions,
bool RegionsTopDown) { … }
void MachineSchedulerBase::scheduleRegions(ScheduleDAGInstrs &Scheduler,
bool FixKillFlags) { … }
void MachineSchedulerBase::print(raw_ostream &O, const Module* m) const { … }
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void ReadyQueue::dump() const {
dbgs() << "Queue " << Name << ": ";
for (const SUnit *SU : Queue)
dbgs() << SU->NodeNum << " ";
dbgs() << "\n";
}
#endif
ScheduleDAGMI::~ScheduleDAGMI() = default;
void ScheduleDAGMI::releaseSucc(SUnit *SU, SDep *SuccEdge) { … }
void ScheduleDAGMI::releaseSuccessors(SUnit *SU) { … }
void ScheduleDAGMI::releasePred(SUnit *SU, SDep *PredEdge) { … }
void ScheduleDAGMI::releasePredecessors(SUnit *SU) { … }
void ScheduleDAGMI::startBlock(MachineBasicBlock *bb) { … }
void ScheduleDAGMI::finishBlock() { … }
void ScheduleDAGMI::enterRegion(MachineBasicBlock *bb,
MachineBasicBlock::iterator begin,
MachineBasicBlock::iterator end,
unsigned regioninstrs)
{ … }
void ScheduleDAGMI::moveInstruction(
MachineInstr *MI, MachineBasicBlock::iterator InsertPos) { … }
bool ScheduleDAGMI::checkSchedLimit() { … }
void ScheduleDAGMI::schedule() { … }
void ScheduleDAGMI::postProcessDAG() { … }
void ScheduleDAGMI::
findRootsAndBiasEdges(SmallVectorImpl<SUnit*> &TopRoots,
SmallVectorImpl<SUnit*> &BotRoots) { … }
void ScheduleDAGMI::initQueues(ArrayRef<SUnit*> TopRoots,
ArrayRef<SUnit*> BotRoots) { … }
void ScheduleDAGMI::updateQueues(SUnit *SU, bool IsTopNode) { … }
void ScheduleDAGMI::placeDebugValues() { … }
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
static const char *scheduleTableLegend = " i: issue\n x: resource booked";
LLVM_DUMP_METHOD void ScheduleDAGMI::dumpScheduleTraceTopDown() const {
if (!SchedModel.hasInstrSchedModel())
return;
if (BB->size() < 2)
return;
dbgs() << " * Schedule table (TopDown):\n";
dbgs() << scheduleTableLegend << "\n";
const unsigned FirstCycle = getSUnit(&*(std::begin(*this)))->TopReadyCycle;
unsigned LastCycle = getSUnit(&*(std::prev(std::end(*this))))->TopReadyCycle;
for (MachineInstr &MI : *this) {
SUnit *SU = getSUnit(&MI);
if (!SU)
continue;
const MCSchedClassDesc *SC = getSchedClass(SU);
for (TargetSchedModel::ProcResIter PI = SchedModel.getWriteProcResBegin(SC),
PE = SchedModel.getWriteProcResEnd(SC);
PI != PE; ++PI) {
if (SU->TopReadyCycle + PI->ReleaseAtCycle - 1 > LastCycle)
LastCycle = SU->TopReadyCycle + PI->ReleaseAtCycle - 1;
}
}
dbgs() << llvm::left_justify("Cycle", HeaderColWidth);
for (unsigned C = FirstCycle; C <= LastCycle; ++C)
dbgs() << llvm::left_justify("| " + std::to_string(C), ColWidth);
dbgs() << "|\n";
for (MachineInstr &MI : *this) {
SUnit *SU = getSUnit(&MI);
if (!SU) {
dbgs() << "Missing SUnit\n";
continue;
}
std::string NodeName("SU(");
NodeName += std::to_string(SU->NodeNum) + ")";
dbgs() << llvm::left_justify(NodeName, HeaderColWidth);
unsigned C = FirstCycle;
for (; C <= LastCycle; ++C) {
if (C == SU->TopReadyCycle)
dbgs() << llvm::left_justify("| i", ColWidth);
else
dbgs() << llvm::left_justify("|", ColWidth);
}
dbgs() << "|\n";
const MCSchedClassDesc *SC = getSchedClass(SU);
SmallVector<MCWriteProcResEntry, 4> ResourcesIt(
make_range(SchedModel.getWriteProcResBegin(SC),
SchedModel.getWriteProcResEnd(SC)));
if (MISchedSortResourcesInTrace)
llvm::stable_sort(ResourcesIt,
[](const MCWriteProcResEntry &LHS,
const MCWriteProcResEntry &RHS) -> bool {
return LHS.AcquireAtCycle < RHS.AcquireAtCycle ||
(LHS.AcquireAtCycle == RHS.AcquireAtCycle &&
LHS.ReleaseAtCycle < RHS.ReleaseAtCycle);
});
for (const MCWriteProcResEntry &PI : ResourcesIt) {
C = FirstCycle;
const std::string ResName =
SchedModel.getResourceName(PI.ProcResourceIdx);
dbgs() << llvm::right_justify(ResName + " ", HeaderColWidth);
for (; C < SU->TopReadyCycle + PI.AcquireAtCycle; ++C) {
dbgs() << llvm::left_justify("|", ColWidth);
}
for (unsigned I = 0, E = PI.ReleaseAtCycle - PI.AcquireAtCycle; I != E;
++I, ++C)
dbgs() << llvm::left_justify("| x", ColWidth);
while (C++ <= LastCycle)
dbgs() << llvm::left_justify("|", ColWidth);
dbgs() << "| \n";
}
}
}
LLVM_DUMP_METHOD void ScheduleDAGMI::dumpScheduleTraceBottomUp() const {
if (!SchedModel.hasInstrSchedModel())
return;
if (BB->size() < 2)
return;
dbgs() << " * Schedule table (BottomUp):\n";
dbgs() << scheduleTableLegend << "\n";
const int FirstCycle = getSUnit(&*(std::begin(*this)))->BotReadyCycle;
int LastCycle = getSUnit(&*(std::prev(std::end(*this))))->BotReadyCycle;
for (MachineInstr &MI : *this) {
SUnit *SU = getSUnit(&MI);
if (!SU)
continue;
const MCSchedClassDesc *SC = getSchedClass(SU);
for (TargetSchedModel::ProcResIter PI = SchedModel.getWriteProcResBegin(SC),
PE = SchedModel.getWriteProcResEnd(SC);
PI != PE; ++PI) {
if ((int)SU->BotReadyCycle - PI->ReleaseAtCycle + 1 < LastCycle)
LastCycle = (int)SU->BotReadyCycle - PI->ReleaseAtCycle + 1;
}
}
dbgs() << llvm::left_justify("Cycle", HeaderColWidth);
for (int C = FirstCycle; C >= LastCycle; --C)
dbgs() << llvm::left_justify("| " + std::to_string(C), ColWidth);
dbgs() << "|\n";
for (MachineInstr &MI : *this) {
SUnit *SU = getSUnit(&MI);
if (!SU) {
dbgs() << "Missing SUnit\n";
continue;
}
std::string NodeName("SU(");
NodeName += std::to_string(SU->NodeNum) + ")";
dbgs() << llvm::left_justify(NodeName, HeaderColWidth);
int C = FirstCycle;
for (; C >= LastCycle; --C) {
if (C == (int)SU->BotReadyCycle)
dbgs() << llvm::left_justify("| i", ColWidth);
else
dbgs() << llvm::left_justify("|", ColWidth);
}
dbgs() << "|\n";
const MCSchedClassDesc *SC = getSchedClass(SU);
SmallVector<MCWriteProcResEntry, 4> ResourcesIt(
make_range(SchedModel.getWriteProcResBegin(SC),
SchedModel.getWriteProcResEnd(SC)));
if (MISchedSortResourcesInTrace)
llvm::stable_sort(ResourcesIt,
[](const MCWriteProcResEntry &LHS,
const MCWriteProcResEntry &RHS) -> bool {
return LHS.AcquireAtCycle < RHS.AcquireAtCycle ||
(LHS.AcquireAtCycle == RHS.AcquireAtCycle &&
LHS.ReleaseAtCycle < RHS.ReleaseAtCycle);
});
for (const MCWriteProcResEntry &PI : ResourcesIt) {
C = FirstCycle;
const std::string ResName =
SchedModel.getResourceName(PI.ProcResourceIdx);
dbgs() << llvm::right_justify(ResName + " ", HeaderColWidth);
for (; C > ((int)SU->BotReadyCycle - (int)PI.AcquireAtCycle); --C) {
dbgs() << llvm::left_justify("|", ColWidth);
}
for (unsigned I = 0, E = PI.ReleaseAtCycle - PI.AcquireAtCycle; I != E;
++I, --C)
dbgs() << llvm::left_justify("| x", ColWidth);
while (C-- >= LastCycle)
dbgs() << llvm::left_justify("|", ColWidth);
dbgs() << "| \n";
}
}
}
#endif
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void ScheduleDAGMI::dumpSchedule() const {
if (MISchedDumpScheduleTrace) {
if (DumpDir == DumpDirection::TopDown)
dumpScheduleTraceTopDown();
else if (DumpDir == DumpDirection::BottomUp)
dumpScheduleTraceBottomUp();
else if (DumpDir == DumpDirection::Bidirectional) {
dbgs() << "* Schedule table (Bidirectional): not implemented\n";
} else {
dbgs() << "* Schedule table: DumpDirection not set.\n";
}
}
for (MachineInstr &MI : *this) {
if (SUnit *SU = getSUnit(&MI))
dumpNode(*SU);
else
dbgs() << "Missing SUnit\n";
}
}
#endif
ScheduleDAGMILive::~ScheduleDAGMILive() { … }
void ScheduleDAGMILive::collectVRegUses(SUnit &SU) { … }
void ScheduleDAGMILive::enterRegion(MachineBasicBlock *bb,
MachineBasicBlock::iterator begin,
MachineBasicBlock::iterator end,
unsigned regioninstrs)
{ … }
void ScheduleDAGMILive::initRegPressure() { … }
void ScheduleDAGMILive::
updateScheduledPressure(const SUnit *SU,
const std::vector<unsigned> &NewMaxPressure) { … }
void ScheduleDAGMILive::updatePressureDiffs(
ArrayRef<RegisterMaskPair> LiveUses) { … }
void ScheduleDAGMILive::dump() const { … }
void ScheduleDAGMILive::schedule() { … }
void ScheduleDAGMILive::buildDAGWithRegPressure() { … }
void ScheduleDAGMILive::computeDFSResult() { … }
unsigned ScheduleDAGMILive::computeCyclicCriticalPath() { … }
void ScheduleDAGMILive::initQueues(ArrayRef<SUnit*> TopRoots,
ArrayRef<SUnit*> BotRoots) { … }
void ScheduleDAGMILive::scheduleMI(SUnit *SU, bool IsTopNode) { … }
namespace {
class BaseMemOpClusterMutation : public ScheduleDAGMutation { … };
class StoreClusterMutation : public BaseMemOpClusterMutation { … };
class LoadClusterMutation : public BaseMemOpClusterMutation { … };
}
namespace llvm {
std::unique_ptr<ScheduleDAGMutation>
createLoadClusterDAGMutation(const TargetInstrInfo *TII,
const TargetRegisterInfo *TRI,
bool ReorderWhileClustering) { … }
std::unique_ptr<ScheduleDAGMutation>
createStoreClusterDAGMutation(const TargetInstrInfo *TII,
const TargetRegisterInfo *TRI,
bool ReorderWhileClustering) { … }
}
void BaseMemOpClusterMutation::clusterNeighboringMemOps(
ArrayRef<MemOpInfo> MemOpRecords, bool FastCluster,
ScheduleDAGInstrs *DAG) { … }
void BaseMemOpClusterMutation::collectMemOpRecords(
std::vector<SUnit> &SUnits, SmallVectorImpl<MemOpInfo> &MemOpRecords) { … }
bool BaseMemOpClusterMutation::groupMemOps(
ArrayRef<MemOpInfo> MemOps, ScheduleDAGInstrs *DAG,
DenseMap<unsigned, SmallVector<MemOpInfo, 32>> &Groups) { … }
void BaseMemOpClusterMutation::apply(ScheduleDAGInstrs *DAG) { … }
namespace {
class CopyConstrain : public ScheduleDAGMutation { … };
}
namespace llvm {
std::unique_ptr<ScheduleDAGMutation>
createCopyConstrainDAGMutation(const TargetInstrInfo *TII,
const TargetRegisterInfo *TRI) { … }
}
void CopyConstrain::constrainLocalCopy(SUnit *CopySU, ScheduleDAGMILive *DAG) { … }
void CopyConstrain::apply(ScheduleDAGInstrs *DAGInstrs) { … }
static const unsigned InvalidCycle = …;
SchedBoundary::~SchedBoundary() { … }
static bool checkResourceLimit(unsigned LFactor, unsigned Count,
unsigned Latency, bool AfterSchedNode) { … }
void SchedBoundary::reset() { … }
void SchedRemainder::
init(ScheduleDAGMI *DAG, const TargetSchedModel *SchedModel) { … }
void SchedBoundary::
init(ScheduleDAGMI *dag, const TargetSchedModel *smodel, SchedRemainder *rem) { … }
unsigned SchedBoundary::getLatencyStallCycles(SUnit *SU) { … }
unsigned SchedBoundary::getNextResourceCycleByInstance(unsigned InstanceIdx,
unsigned ReleaseAtCycle,
unsigned AcquireAtCycle) { … }
std::pair<unsigned, unsigned>
SchedBoundary::getNextResourceCycle(const MCSchedClassDesc *SC, unsigned PIdx,
unsigned ReleaseAtCycle,
unsigned AcquireAtCycle) { … }
bool SchedBoundary::checkHazard(SUnit *SU) { … }
unsigned SchedBoundary::
findMaxLatency(ArrayRef<SUnit*> ReadySUs) { … }
unsigned SchedBoundary::
getOtherResourceCount(unsigned &OtherCritIdx) { … }
void SchedBoundary::releaseNode(SUnit *SU, unsigned ReadyCycle, bool InPQueue,
unsigned Idx) { … }
void SchedBoundary::bumpCycle(unsigned NextCycle) { … }
void SchedBoundary::incExecutedResources(unsigned PIdx, unsigned Count) { … }
unsigned SchedBoundary::countResource(const MCSchedClassDesc *SC, unsigned PIdx,
unsigned ReleaseAtCycle,
unsigned NextCycle,
unsigned AcquireAtCycle) { … }
void SchedBoundary::bumpNode(SUnit *SU) { … }
void SchedBoundary::releasePending() { … }
void SchedBoundary::removeReady(SUnit *SU) { … }
SUnit *SchedBoundary::pickOnlyChoice() { … }
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void SchedBoundary::dumpReservedCycles() const {
if (!SchedModel->hasInstrSchedModel())
return;
unsigned ResourceCount = SchedModel->getNumProcResourceKinds();
unsigned StartIdx = 0;
for (unsigned ResIdx = 0; ResIdx < ResourceCount; ++ResIdx) {
const unsigned NumUnits = SchedModel->getProcResource(ResIdx)->NumUnits;
std::string ResName = SchedModel->getResourceName(ResIdx);
for (unsigned UnitIdx = 0; UnitIdx < NumUnits; ++UnitIdx) {
dbgs() << ResName << "(" << UnitIdx << ") = ";
if (SchedModel && SchedModel->enableIntervals()) {
if (ReservedResourceSegments.count(StartIdx + UnitIdx))
dbgs() << ReservedResourceSegments.at(StartIdx + UnitIdx);
else
dbgs() << "{ }\n";
} else
dbgs() << ReservedCycles[StartIdx + UnitIdx] << "\n";
}
StartIdx += NumUnits;
}
}
LLVM_DUMP_METHOD void SchedBoundary::dumpScheduledState() const {
unsigned ResFactor;
unsigned ResCount;
if (ZoneCritResIdx) {
ResFactor = SchedModel->getResourceFactor(ZoneCritResIdx);
ResCount = getResourceCount(ZoneCritResIdx);
} else {
ResFactor = SchedModel->getMicroOpFactor();
ResCount = RetiredMOps * ResFactor;
}
unsigned LFactor = SchedModel->getLatencyFactor();
dbgs() << Available.getName() << " @" << CurrCycle << "c\n"
<< " Retired: " << RetiredMOps;
dbgs() << "\n Executed: " << getExecutedCount() / LFactor << "c";
dbgs() << "\n Critical: " << ResCount / LFactor << "c, "
<< ResCount / ResFactor << " "
<< SchedModel->getResourceName(ZoneCritResIdx)
<< "\n ExpectedLatency: " << ExpectedLatency << "c\n"
<< (IsResourceLimited ? " - Resource" : " - Latency")
<< " limited.\n";
if (MISchedDumpReservedCycles)
dumpReservedCycles();
}
#endif
void GenericSchedulerBase::SchedCandidate::
initResourceDelta(const ScheduleDAGMI *DAG,
const TargetSchedModel *SchedModel) { … }
static unsigned computeRemLatency(SchedBoundary &CurrZone) { … }
bool GenericSchedulerBase::shouldReduceLatency(const CandPolicy &Policy,
SchedBoundary &CurrZone,
bool ComputeRemLatency,
unsigned &RemLatency) const { … }
void GenericSchedulerBase::setPolicy(CandPolicy &Policy, bool IsPostRA,
SchedBoundary &CurrZone,
SchedBoundary *OtherZone) { … }
#ifndef NDEBUG
const char *GenericSchedulerBase::getReasonStr(
GenericSchedulerBase::CandReason Reason) {
switch (Reason) {
case NoCand: return "NOCAND ";
case Only1: return "ONLY1 ";
case PhysReg: return "PHYS-REG ";
case RegExcess: return "REG-EXCESS";
case RegCritical: return "REG-CRIT ";
case Stall: return "STALL ";
case Cluster: return "CLUSTER ";
case Weak: return "WEAK ";
case RegMax: return "REG-MAX ";
case ResourceReduce: return "RES-REDUCE";
case ResourceDemand: return "RES-DEMAND";
case TopDepthReduce: return "TOP-DEPTH ";
case TopPathReduce: return "TOP-PATH ";
case BotHeightReduce:return "BOT-HEIGHT";
case BotPathReduce: return "BOT-PATH ";
case NextDefUse: return "DEF-USE ";
case NodeOrder: return "ORDER ";
};
llvm_unreachable("Unknown reason!");
}
void GenericSchedulerBase::traceCandidate(const SchedCandidate &Cand) {
PressureChange P;
unsigned ResIdx = 0;
unsigned Latency = 0;
switch (Cand.Reason) {
default:
break;
case RegExcess:
P = Cand.RPDelta.Excess;
break;
case RegCritical:
P = Cand.RPDelta.CriticalMax;
break;
case RegMax:
P = Cand.RPDelta.CurrentMax;
break;
case ResourceReduce:
ResIdx = Cand.Policy.ReduceResIdx;
break;
case ResourceDemand:
ResIdx = Cand.Policy.DemandResIdx;
break;
case TopDepthReduce:
Latency = Cand.SU->getDepth();
break;
case TopPathReduce:
Latency = Cand.SU->getHeight();
break;
case BotHeightReduce:
Latency = Cand.SU->getHeight();
break;
case BotPathReduce:
Latency = Cand.SU->getDepth();
break;
}
dbgs() << " Cand SU(" << Cand.SU->NodeNum << ") " << getReasonStr(Cand.Reason);
if (P.isValid())
dbgs() << " " << TRI->getRegPressureSetName(P.getPSet())
<< ":" << P.getUnitInc() << " ";
else
dbgs() << " ";
if (ResIdx)
dbgs() << " " << SchedModel->getProcResource(ResIdx)->Name << " ";
else
dbgs() << " ";
if (Latency)
dbgs() << " " << Latency << " cycles ";
else
dbgs() << " ";
dbgs() << '\n';
}
#endif
namespace llvm {
bool tryLess(int TryVal, int CandVal,
GenericSchedulerBase::SchedCandidate &TryCand,
GenericSchedulerBase::SchedCandidate &Cand,
GenericSchedulerBase::CandReason Reason) { … }
bool tryGreater(int TryVal, int CandVal,
GenericSchedulerBase::SchedCandidate &TryCand,
GenericSchedulerBase::SchedCandidate &Cand,
GenericSchedulerBase::CandReason Reason) { … }
bool tryLatency(GenericSchedulerBase::SchedCandidate &TryCand,
GenericSchedulerBase::SchedCandidate &Cand,
SchedBoundary &Zone) { … }
}
static void tracePick(GenericSchedulerBase::CandReason Reason, bool IsTop) { … }
static void tracePick(const GenericSchedulerBase::SchedCandidate &Cand) { … }
void GenericScheduler::initialize(ScheduleDAGMI *dag) { … }
void GenericScheduler::initPolicy(MachineBasicBlock::iterator Begin,
MachineBasicBlock::iterator End,
unsigned NumRegionInstrs) { … }
void GenericScheduler::dumpPolicy() const { … }
void GenericScheduler::checkAcyclicLatency() { … }
void GenericScheduler::registerRoots() { … }
namespace llvm {
bool tryPressure(const PressureChange &TryP,
const PressureChange &CandP,
GenericSchedulerBase::SchedCandidate &TryCand,
GenericSchedulerBase::SchedCandidate &Cand,
GenericSchedulerBase::CandReason Reason,
const TargetRegisterInfo *TRI,
const MachineFunction &MF) { … }
unsigned getWeakLeft(const SUnit *SU, bool isTop) { … }
int biasPhysReg(const SUnit *SU, bool isTop) { … }
}
void GenericScheduler::initCandidate(SchedCandidate &Cand, SUnit *SU,
bool AtTop,
const RegPressureTracker &RPTracker,
RegPressureTracker &TempTracker) { … }
bool GenericScheduler::tryCandidate(SchedCandidate &Cand,
SchedCandidate &TryCand,
SchedBoundary *Zone) const { … }
void GenericScheduler::pickNodeFromQueue(SchedBoundary &Zone,
const CandPolicy &ZonePolicy,
const RegPressureTracker &RPTracker,
SchedCandidate &Cand) { … }
SUnit *GenericScheduler::pickNodeBidirectional(bool &IsTopNode) { … }
SUnit *GenericScheduler::pickNode(bool &IsTopNode) { … }
void GenericScheduler::reschedulePhysReg(SUnit *SU, bool isTop) { … }
void GenericScheduler::schedNode(SUnit *SU, bool IsTopNode) { … }
ScheduleDAGMILive *llvm::createGenericSchedLive(MachineSchedContext *C) { … }
static ScheduleDAGInstrs *createConvergingSched(MachineSchedContext *C) { … }
static MachineSchedRegistry
GenericSchedRegistry("converge", "Standard converging scheduler.",
createConvergingSched);
void PostGenericScheduler::initialize(ScheduleDAGMI *Dag) { … }
void PostGenericScheduler::initPolicy(MachineBasicBlock::iterator Begin,
MachineBasicBlock::iterator End,
unsigned NumRegionInstrs) { … }
void PostGenericScheduler::registerRoots() { … }
bool PostGenericScheduler::tryCandidate(SchedCandidate &Cand,
SchedCandidate &TryCand) { … }
void PostGenericScheduler::pickNodeFromQueue(SchedBoundary &Zone,
SchedCandidate &Cand) { … }
SUnit *PostGenericScheduler::pickNodeBidirectional(bool &IsTopNode) { … }
SUnit *PostGenericScheduler::pickNode(bool &IsTopNode) { … }
void PostGenericScheduler::schedNode(SUnit *SU, bool IsTopNode) { … }
ScheduleDAGMI *llvm::createGenericSchedPostRA(MachineSchedContext *C) { … }
namespace {
struct ILPOrder { … };
class ILPScheduler : public MachineSchedStrategy { … };
}
static ScheduleDAGInstrs *createILPMaxScheduler(MachineSchedContext *C) { … }
static ScheduleDAGInstrs *createILPMinScheduler(MachineSchedContext *C) { … }
static MachineSchedRegistry ILPMaxRegistry(
"ilpmax", "Schedule bottom-up for max ILP", createILPMaxScheduler);
static MachineSchedRegistry ILPMinRegistry(
"ilpmin", "Schedule bottom-up for min ILP", createILPMinScheduler);
#ifndef NDEBUG
namespace {
template<bool IsReverse>
struct SUnitOrder {
bool operator()(SUnit *A, SUnit *B) const {
if (IsReverse)
return A->NodeNum > B->NodeNum;
else
return A->NodeNum < B->NodeNum;
}
};
class InstructionShuffler : public MachineSchedStrategy {
bool IsAlternating;
bool IsTopDown;
PriorityQueue<SUnit*, std::vector<SUnit*>, SUnitOrder<false>>
TopQ;
PriorityQueue<SUnit*, std::vector<SUnit*>, SUnitOrder<true>>
BottomQ;
public:
InstructionShuffler(bool alternate, bool topdown)
: IsAlternating(alternate), IsTopDown(topdown) {}
void initialize(ScheduleDAGMI*) override {
TopQ.clear();
BottomQ.clear();
}
SUnit *pickNode(bool &IsTopNode) override {
SUnit *SU;
if (IsTopDown) {
do {
if (TopQ.empty()) return nullptr;
SU = TopQ.top();
TopQ.pop();
} while (SU->isScheduled);
IsTopNode = true;
} else {
do {
if (BottomQ.empty()) return nullptr;
SU = BottomQ.top();
BottomQ.pop();
} while (SU->isScheduled);
IsTopNode = false;
}
if (IsAlternating)
IsTopDown = !IsTopDown;
return SU;
}
void schedNode(SUnit *SU, bool IsTopNode) override {}
void releaseTopNode(SUnit *SU) override {
TopQ.push(SU);
}
void releaseBottomNode(SUnit *SU) override {
BottomQ.push(SU);
}
};
}
static ScheduleDAGInstrs *createInstructionShuffler(MachineSchedContext *C) {
bool Alternate = !ForceTopDown && !ForceBottomUp;
bool TopDown = !ForceBottomUp;
assert((TopDown || !ForceTopDown) &&
"-misched-topdown incompatible with -misched-bottomup");
return new ScheduleDAGMILive(
C, std::make_unique<InstructionShuffler>(Alternate, TopDown));
}
static MachineSchedRegistry ShufflerRegistry(
"shuffle", "Shuffle machine instructions alternating directions",
createInstructionShuffler);
#endif
#ifndef NDEBUG
namespace llvm {
template<> struct GraphTraits<
ScheduleDAGMI*> : public GraphTraits<ScheduleDAG*> {};
template<>
struct DOTGraphTraits<ScheduleDAGMI*> : public DefaultDOTGraphTraits {
DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
static std::string getGraphName(const ScheduleDAG *G) {
return std::string(G->MF.getName());
}
static bool renderGraphFromBottomUp() {
return true;
}
static bool isNodeHidden(const SUnit *Node, const ScheduleDAG *G) {
if (ViewMISchedCutoff == 0)
return false;
return (Node->Preds.size() > ViewMISchedCutoff
|| Node->Succs.size() > ViewMISchedCutoff);
}
static std::string getEdgeAttributes(const SUnit *Node,
SUnitIterator EI,
const ScheduleDAG *Graph) {
if (EI.isArtificialDep())
return "color=cyan,style=dashed";
if (EI.isCtrlDep())
return "color=blue,style=dashed";
return "";
}
static std::string getNodeLabel(const SUnit *SU, const ScheduleDAG *G) {
std::string Str;
raw_string_ostream SS(Str);
const ScheduleDAGMI *DAG = static_cast<const ScheduleDAGMI*>(G);
const SchedDFSResult *DFS = DAG->hasVRegLiveness() ?
static_cast<const ScheduleDAGMILive*>(G)->getDFSResult() : nullptr;
SS << "SU:" << SU->NodeNum;
if (DFS)
SS << " I:" << DFS->getNumInstrs(SU);
return Str;
}
static std::string getNodeDescription(const SUnit *SU, const ScheduleDAG *G) {
return G->getGraphNodeLabel(SU);
}
static std::string getNodeAttributes(const SUnit *N, const ScheduleDAG *G) {
std::string Str("shape=Mrecord");
const ScheduleDAGMI *DAG = static_cast<const ScheduleDAGMI*>(G);
const SchedDFSResult *DFS = DAG->hasVRegLiveness() ?
static_cast<const ScheduleDAGMILive*>(G)->getDFSResult() : nullptr;
if (DFS) {
Str += ",style=filled,fillcolor=\"#";
Str += DOT::getColorString(DFS->getSubtreeID(N));
Str += '"';
}
return Str;
}
};
}
#endif
void ScheduleDAGMI::viewGraph(const Twine &Name, const Twine &Title) { … }
void ScheduleDAGMI::viewGraph() { … }
static bool sortIntervals(const ResourceSegments::IntervalTy &A,
const ResourceSegments::IntervalTy &B) { … }
unsigned ResourceSegments::getFirstAvailableAt(
unsigned CurrCycle, unsigned AcquireAtCycle, unsigned ReleaseAtCycle,
std::function<ResourceSegments::IntervalTy(unsigned, unsigned, unsigned)>
IntervalBuilder) const { … }
void ResourceSegments::add(ResourceSegments::IntervalTy A,
const unsigned CutOff) { … }
bool ResourceSegments::intersects(ResourceSegments::IntervalTy A,
ResourceSegments::IntervalTy B) { … }
void ResourceSegments::sortAndMerge() { … }