Allow subtarget selection of the default MachineScheduler and document the interface.

The global registry is used to allow command line override of the
scheduler selection, but does not work well as the normal selection
API. For example, the same LLVM process should be able to target
multiple targets or subtargets.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191071 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Andrew Trick
2013-09-20 05:14:41 +00:00
parent c87f9488b8
commit f45edcc381
6 changed files with 119 additions and 38 deletions

View File

@ -7,8 +7,48 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// //
// This file provides a MachineSchedRegistry for registering alternative machine // This file provides an interface for customizing the standard MachineScheduler
// schedulers. A Target may provide an alternative scheduler implementation by // pass. Note that the entire pass may be replaced as follows:
//
// <Target>TargetMachine::createPassConfig(PassManagerBase &PM) {
// PM.substitutePass(&MachineSchedulerID, &CustomSchedulerPassID);
// ...}
//
// The MachineScheduler pass is only responsible for choosing the regions to be
// scheduled. Targets can override the DAG builder and scheduler without
// replacing the pass as follows:
//
// ScheduleDAGInstrs *<Target>PassConfig::
// createMachineScheduler(MachineSchedContext *C) {
// return new CustomMachineScheduler(C);
// }
//
// The default scheduler, ScheduleDAGMI, builds the DAG and drives list
// scheduling while updating the instruction stream, register pressure, and live
// intervals. Most targets don't need to override the DAG builder and list
// schedulier, but subtargets that require custom scheduling heuristics may
// plugin an alternate MachineSchedStrategy. The strategy is responsible for
// selecting the highest priority node from the list:
//
// ScheduleDAGInstrs *<Target>PassConfig::
// createMachineScheduler(MachineSchedContext *C) {
// return new ScheduleDAGMI(C, CustomStrategy(C));
// }
//
// The DAG builder can also be customized in a sense by adding DAG mutations
// that will run after DAG building and before list scheduling. DAG mutations
// can adjust dependencies based on target-specific knowledge or add weak edges
// to aid heuristics:
//
// ScheduleDAGInstrs *<Target>PassConfig::
// createMachineScheduler(MachineSchedContext *C) {
// ScheduleDAGMI *DAG = new ScheduleDAGMI(C, CustomStrategy(C));
// DAG->addMutation(new CustomDependencies(DAG->TII, DAG->TRI));
// return DAG;
// }
//
// A target that supports alternative schedulers can use the
// MachineSchedRegistry to allow command line selection. This can be done by
// implementing the following boilerplate: // implementing the following boilerplate:
// //
// static ScheduleDAGInstrs *createCustomMachineSched(MachineSchedContext *C) { // static ScheduleDAGInstrs *createCustomMachineSched(MachineSchedContext *C) {
@ -18,9 +58,19 @@
// SchedCustomRegistry("custom", "Run my target's custom scheduler", // SchedCustomRegistry("custom", "Run my target's custom scheduler",
// createCustomMachineSched); // createCustomMachineSched);
// //
// Inside <Target>PassConfig: //
// enablePass(&MachineSchedulerID); // Finally, subtargets that don't need to implement custom heuristics but would
// MachineSchedRegistry::setDefault(createCustomMachineSched); // like to configure the GenericScheduler's policy for a given scheduler region,
// including scheduling direction and register pressure tracking policy, can do
// this:
//
// void <SubTarget>Subtarget::
// overrideSchedPolicy(MachineSchedPolicy &Policy,
// MachineInstr *begin,
// MachineInstr *end,
// unsigned NumRegionInstrs) const {
// Policy.<Flag> = true;
// }
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -85,15 +135,6 @@ public:
static MachineSchedRegistry *getList() { static MachineSchedRegistry *getList() {
return (MachineSchedRegistry *)Registry.getList(); return (MachineSchedRegistry *)Registry.getList();
} }
static ScheduleDAGCtor getDefault() {
return (ScheduleDAGCtor)Registry.getDefault();
}
static void setDefault(ScheduleDAGCtor C) {
Registry.setDefault((MachinePassCtor)C);
}
static void setDefault(StringRef Name) {
Registry.setDefault(Name);
}
static void setListener(MachinePassRegistryListener *L) { static void setListener(MachinePassRegistryListener *L) {
Registry.setListener(L); Registry.setListener(L);
} }

View File

@ -23,8 +23,10 @@ namespace llvm {
class FunctionPass; class FunctionPass;
class MachineFunctionPass; class MachineFunctionPass;
struct MachineSchedContext;
class PassInfo; class PassInfo;
class PassManagerBase; class PassManagerBase;
class ScheduleDAGInstrs;
class TargetLoweringBase; class TargetLoweringBase;
class TargetLowering; class TargetLowering;
class TargetRegisterClass; class TargetRegisterClass;
@ -204,6 +206,20 @@ public:
/// Fully developed targets will not generally override this. /// Fully developed targets will not generally override this.
virtual void addMachinePasses(); virtual void addMachinePasses();
/// createTargetScheduler - Create an instance of ScheduleDAGInstrs to be run
/// within the standard MachineScheduler pass for this function and target at
/// the current optimization level.
///
/// This can also be used to plug a new MachineSchedStrategy into an instance
/// of the standard ScheduleDAGMI:
/// return new ScheduleDAGMI(C, new MyStrategy(C))
///
/// Return NULL to select the default (generic) machine scheduler.
virtual ScheduleDAGInstrs *
createMachineScheduler(MachineSchedContext *C) const {
return 0;
}
protected: protected:
// Helper to verify the analysis is really immutable. // Helper to verify the analysis is really immutable.
void setOpt(bool &Opt, bool Val); void setOpt(bool &Opt, bool Val);

View File

@ -101,6 +101,9 @@ public:
virtual void print(raw_ostream &O, const Module* = 0) const; virtual void print(raw_ostream &O, const Module* = 0) const;
static char ID; // Class identification, replacement for typeinfo static char ID; // Class identification, replacement for typeinfo
protected:
ScheduleDAGInstrs *createMachineScheduler();
}; };
} // namespace } // namespace
@ -202,6 +205,22 @@ nextIfDebug(MachineBasicBlock::iterator I,
&*nextIfDebug(MachineBasicBlock::const_iterator(I), End))); &*nextIfDebug(MachineBasicBlock::const_iterator(I), End)));
} }
/// Instantiate a ScheduleDAGInstrs that will be owned by the called.
ScheduleDAGInstrs *MachineScheduler::createMachineScheduler() {
// Select the scheduler, or set the default.
MachineSchedRegistry::ScheduleDAGCtor Ctor = MachineSchedOpt;
if (Ctor != useDefaultMachineSched)
return Ctor(this);
// Get the default scheduler set by the target for this function.
ScheduleDAGInstrs *Scheduler = PassConfig->createMachineScheduler(this);
if (Scheduler)
return Scheduler;
// Default to GenericScheduler.
return createGenericSched(this);
}
/// Top-level MachineScheduler pass driver. /// Top-level MachineScheduler pass driver.
/// ///
/// Visit blocks in function order. Divide each block into scheduling regions /// Visit blocks in function order. Divide each block into scheduling regions
@ -237,18 +256,9 @@ bool MachineScheduler::runOnMachineFunction(MachineFunction &mf) {
} }
RegClassInfo->runOnMachineFunction(*MF); RegClassInfo->runOnMachineFunction(*MF);
// Select the scheduler, or set the default. // Instantiate the selected scheduler for this target, function, and
MachineSchedRegistry::ScheduleDAGCtor Ctor = MachineSchedOpt; // optimization level.
if (Ctor == useDefaultMachineSched) { OwningPtr<ScheduleDAGInstrs> Scheduler(createMachineScheduler());
// Get the default scheduler set by the target.
Ctor = MachineSchedRegistry::getDefault();
if (!Ctor) {
Ctor = createGenericSched;
MachineSchedRegistry::setDefault(Ctor);
}
}
// Instantiate the selected scheduler.
OwningPtr<ScheduleDAGInstrs> Scheduler(Ctor(this));
// Visit all machine basic blocks. // Visit all machine basic blocks.
// //

View File

@ -102,17 +102,25 @@ class HexagonPassConfig : public TargetPassConfig {
public: public:
HexagonPassConfig(HexagonTargetMachine *TM, PassManagerBase &PM) HexagonPassConfig(HexagonTargetMachine *TM, PassManagerBase &PM)
: TargetPassConfig(TM, PM) { : TargetPassConfig(TM, PM) {
// Enable MI scheduler. // FIXME: Rather than calling enablePass(&MachineSchedulerID) below, define
if (!DisableHexagonMISched) { // HexagonSubtarget::enableMachineScheduler() { return true; }.
// That will bypass the SelectionDAG VLIW scheduler, which is probably just
// hurting compile time and will be removed eventually anyway.
if (DisableHexagonMISched)
disablePass(&MachineSchedulerID);
else
enablePass(&MachineSchedulerID); enablePass(&MachineSchedulerID);
MachineSchedRegistry::setDefault(createVLIWMachineSched);
}
} }
HexagonTargetMachine &getHexagonTargetMachine() const { HexagonTargetMachine &getHexagonTargetMachine() const {
return getTM<HexagonTargetMachine>(); return getTM<HexagonTargetMachine>();
} }
virtual ScheduleDAGInstrs *
createMachineScheduler(MachineSchedContext *C) const {
return createVLIWMachineSched(C);
}
virtual bool addInstSelector(); virtual bool addInstSelector();
virtual bool addPreRegAlloc(); virtual bool addPreRegAlloc();
virtual bool addPostRegAlloc(); virtual bool addPostRegAlloc();

View File

@ -64,6 +64,10 @@ public:
bool hasHWFP64() const; bool hasHWFP64() const;
bool hasCaymanISA() const; bool hasCaymanISA() const;
virtual bool enableMachineScheduler() const {
return getGeneration() <= NORTHERN_ISLANDS;
}
// Helper functions to simplify if statements // Helper functions to simplify if statements
bool isTargetELF() const; bool isTargetELF() const;
std::string getDataLayout() const; std::string getDataLayout() const;

View File

@ -80,17 +80,20 @@ namespace {
class AMDGPUPassConfig : public TargetPassConfig { class AMDGPUPassConfig : public TargetPassConfig {
public: public:
AMDGPUPassConfig(AMDGPUTargetMachine *TM, PassManagerBase &PM) AMDGPUPassConfig(AMDGPUTargetMachine *TM, PassManagerBase &PM)
: TargetPassConfig(TM, PM) { : TargetPassConfig(TM, PM) {}
const AMDGPUSubtarget &ST = TM->getSubtarget<AMDGPUSubtarget>();
if (ST.getGeneration() <= AMDGPUSubtarget::NORTHERN_ISLANDS) {
enablePass(&MachineSchedulerID);
MachineSchedRegistry::setDefault(createR600MachineScheduler);
}
}
AMDGPUTargetMachine &getAMDGPUTargetMachine() const { AMDGPUTargetMachine &getAMDGPUTargetMachine() const {
return getTM<AMDGPUTargetMachine>(); return getTM<AMDGPUTargetMachine>();
} }
virtual ScheduleDAGInstrs *
createMachineScheduler(MachineSchedContext *C) const {
const AMDGPUSubtarget &ST = TM->getSubtarget<AMDGPUSubtarget>();
if (ST.getGeneration() <= AMDGPUSubtarget::NORTHERN_ISLANDS)
return createR600MachineScheduler(C);
return 0;
}
virtual bool addPreISel(); virtual bool addPreISel();
virtual bool addInstSelector(); virtual bool addInstSelector();
virtual bool addPreRegAlloc(); virtual bool addPreRegAlloc();
@ -186,4 +189,3 @@ bool AMDGPUPassConfig::addPreEmitPass() {
return false; return false;
} }