//===- MachineScheduler.h - MachineInstr Scheduling Pass --------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file provides an interface for customizing the standard MachineScheduler // 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, ScheduleDAGMILive, 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 // scheduler, 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 ScheduleDAGMILive(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 = createGenericSchedLive(C); // DAG->addMutation(new CustomDAGMutation(...)); // 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: // // static ScheduleDAGInstrs *createCustomMachineSched(MachineSchedContext *C) { // return new CustomMachineScheduler(C); // } // static MachineSchedRegistry // SchedCustomRegistry("custom", "Run my target's custom scheduler", // createCustomMachineSched); // // // Finally, subtargets that don't need to implement custom heuristics but would // 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, // unsigned NumRegionInstrs) const { // Policy.<Flag> = true; // } // //===----------------------------------------------------------------------===// #ifndef LLVM_CODEGEN_MACHINESCHEDULER_H #define LLVM_CODEGEN_MACHINESCHEDULER_H #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachinePassRegistry.h" #include "llvm/CodeGen/RegisterPressure.h" #include "llvm/CodeGen/ScheduleDAG.h" #include "llvm/CodeGen/ScheduleDAGInstrs.h" #include "llvm/CodeGen/ScheduleDAGMutation.h" #include "llvm/CodeGen/TargetSchedule.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include <algorithm> #include <cassert> #include <llvm/Support/raw_ostream.h> #include <memory> #include <string> #include <vector> namespace llvm { extern cl::opt<bool> ForceTopDown; extern cl::opt<bool> ForceBottomUp; extern cl::opt<bool> VerifyScheduling; #ifndef NDEBUG extern cl::opt<bool> ViewMISchedDAGs; extern cl::opt<bool> PrintDAGs; #else extern const bool ViewMISchedDAGs; extern const bool PrintDAGs; #endif class AAResults; class LiveIntervals; class MachineDominatorTree; class MachineFunction; class MachineInstr; class MachineLoopInfo; class RegisterClassInfo; class SchedDFSResult; class ScheduleHazardRecognizer; class TargetInstrInfo; class TargetPassConfig; class TargetRegisterInfo; /// MachineSchedContext provides enough context from the MachineScheduler pass /// for the target to instantiate a scheduler. struct MachineSchedContext { … }; /// MachineSchedRegistry provides a selection of available machine instruction /// schedulers. class MachineSchedRegistry : public MachinePassRegistryNode< ScheduleDAGInstrs *(*)(MachineSchedContext *)> { … }; class ScheduleDAGMI; /// Define a generic scheduling policy for targets that don't provide their own /// MachineSchedStrategy. This can be overriden for each scheduling region /// before building the DAG. struct MachineSchedPolicy { … }; /// MachineSchedStrategy - Interface to the scheduling algorithm used by /// ScheduleDAGMI. /// /// Initialization sequence: /// initPolicy -> shouldTrackPressure -> initialize(DAG) -> registerRoots class MachineSchedStrategy { … }; /// ScheduleDAGMI is an implementation of ScheduleDAGInstrs that simply /// schedules machine instructions according to the given MachineSchedStrategy /// without much extra book-keeping. This is the common functionality between /// PreRA and PostRA MachineScheduler. class ScheduleDAGMI : public ScheduleDAGInstrs { … }; /// ScheduleDAGMILive is an implementation of ScheduleDAGInstrs that schedules /// machine instructions while updating LiveIntervals and tracking regpressure. class ScheduleDAGMILive : public ScheduleDAGMI { … }; //===----------------------------------------------------------------------===// /// /// Helpers for implementing custom MachineSchedStrategy classes. These take /// care of the book-keeping associated with list scheduling heuristics. /// //===----------------------------------------------------------------------===// /// ReadyQueue encapsulates vector of "ready" SUnits with basic convenience /// methods for pushing and removing nodes. ReadyQueue's are uniquely identified /// by an ID. SUnit::NodeQueueId is a mask of the ReadyQueues the SUnit is in. /// /// This is a convenience class that may be used by implementations of /// MachineSchedStrategy. class ReadyQueue { … }; /// Summarize the unscheduled region. struct SchedRemainder { … }; /// ResourceSegments are a collection of intervals closed on the /// left and opened on the right: /// /// list{ [a1, b1), [a2, b2), ..., [a_N, b_N) } /// /// The collection has the following properties: /// /// 1. The list is ordered: a_i < b_i and b_i < a_(i+1) /// /// 2. The intervals in the collection do not intersect each other. /// /// A \ref ResourceSegments instance represents the cycle /// reservation history of the instance of and individual resource. class ResourceSegments { … }; /// Each Scheduling boundary is associated with ready queues. It tracks the /// current cycle in the direction of movement, and maintains the state /// of "hazards" and other interlocks at the current cycle. class SchedBoundary { … }; /// Base class for GenericScheduler. This class maintains information about /// scheduling candidates based on TargetSchedModel making it easy to implement /// heuristics for either preRA or postRA scheduling. class GenericSchedulerBase : public MachineSchedStrategy { … }; // Utility functions used by heuristics in tryCandidate(). 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); 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); /// GenericScheduler shrinks the unscheduled zone using heuristics to balance /// the schedule. class GenericScheduler : public GenericSchedulerBase { … }; /// PostGenericScheduler - Interface to the scheduling algorithm used by /// ScheduleDAGMI. /// /// Callbacks from ScheduleDAGMI: /// initPolicy -> initialize(DAG) -> registerRoots -> pickNode ... class PostGenericScheduler : public GenericSchedulerBase { … }; /// Create the standard converging machine scheduler. This will be used as the /// default scheduler if the target does not set a default. /// Adds default DAG mutations. ScheduleDAGMILive *createGenericSchedLive(MachineSchedContext *C); /// Create a generic scheduler with no vreg liveness or DAG mutation passes. ScheduleDAGMI *createGenericSchedPostRA(MachineSchedContext *C); /// If ReorderWhileClustering is set to true, no attempt will be made to /// reduce reordering due to store clustering. std::unique_ptr<ScheduleDAGMutation> createLoadClusterDAGMutation(const TargetInstrInfo *TII, const TargetRegisterInfo *TRI, bool ReorderWhileClustering = false); /// If ReorderWhileClustering is set to true, no attempt will be made to /// reduce reordering due to store clustering. std::unique_ptr<ScheduleDAGMutation> createStoreClusterDAGMutation(const TargetInstrInfo *TII, const TargetRegisterInfo *TRI, bool ReorderWhileClustering = false); std::unique_ptr<ScheduleDAGMutation> createCopyConstrainDAGMutation(const TargetInstrInfo *TII, const TargetRegisterInfo *TRI); } // end namespace llvm #endif // LLVM_CODEGEN_MACHINESCHEDULER_H