mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-05 13:26:55 +00:00
Porting Hexagon MI Scheduler to the new API.
Change current Hexagon MI scheduler to use new converging scheduler. Integrates DFA resource model into it. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@163137 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
423
lib/Target/Hexagon/HexagonMachineScheduler.h
Normal file
423
lib/Target/Hexagon/HexagonMachineScheduler.h
Normal file
@@ -0,0 +1,423 @@
|
||||
//===-- HexagonMachineScheduler.h - Custom Hexagon MI scheduler. ----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Custom Hexagon MI scheduler.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef HEXAGONASMPRINTER_H
|
||||
#define HEXAGONASMPRINTER_H
|
||||
|
||||
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
|
||||
#include "llvm/CodeGen/MachineScheduler.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/CodeGen/RegisterClassInfo.h"
|
||||
#include "llvm/CodeGen/RegisterPressure.h"
|
||||
#include "llvm/CodeGen/ResourcePriorityQueue.h"
|
||||
#include "llvm/CodeGen/ScheduleDAGInstrs.h"
|
||||
#include "llvm/CodeGen/ScheduleHazardRecognizer.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/PriorityQueue.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MachineSchedStrategy - Interface to a machine scheduling algorithm.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace llvm {
|
||||
class VLIWMachineScheduler;
|
||||
|
||||
/// MachineSchedStrategy - Interface used by VLIWMachineScheduler to drive the selected
|
||||
/// scheduling algorithm.
|
||||
///
|
||||
/// If this works well and targets wish to reuse VLIWMachineScheduler, we may expose it
|
||||
/// in ScheduleDAGInstrs.h
|
||||
class MachineSchedStrategy {
|
||||
public:
|
||||
virtual ~MachineSchedStrategy() {}
|
||||
|
||||
/// Initialize the strategy after building the DAG for a new region.
|
||||
virtual void initialize(VLIWMachineScheduler *DAG) = 0;
|
||||
|
||||
/// Pick the next node to schedule, or return NULL. Set IsTopNode to true to
|
||||
/// schedule the node at the top of the unscheduled region. Otherwise it will
|
||||
/// be scheduled at the bottom.
|
||||
virtual SUnit *pickNode(bool &IsTopNode) = 0;
|
||||
|
||||
/// Notify MachineSchedStrategy that VLIWMachineScheduler has scheduled a node.
|
||||
virtual void schedNode(SUnit *SU, bool IsTopNode) = 0;
|
||||
|
||||
/// When all predecessor dependencies have been resolved, free this node for
|
||||
/// top-down scheduling.
|
||||
virtual void releaseTopNode(SUnit *SU) = 0;
|
||||
/// When all successor dependencies have been resolved, free this node for
|
||||
/// bottom-up scheduling.
|
||||
virtual void releaseBottomNode(SUnit *SU) = 0;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ConvergingVLIWScheduler - Implementation of the standard MachineSchedStrategy.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// 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.
|
||||
class ReadyQueue {
|
||||
unsigned ID;
|
||||
std::string Name;
|
||||
std::vector<SUnit*> Queue;
|
||||
|
||||
public:
|
||||
ReadyQueue(unsigned id, const Twine &name): ID(id), Name(name.str()) {}
|
||||
|
||||
unsigned getID() const { return ID; }
|
||||
|
||||
StringRef getName() const { return Name; }
|
||||
|
||||
// SU is in this queue if it's NodeQueueID is a superset of this ID.
|
||||
bool isInQueue(SUnit *SU) const { return (SU->NodeQueueId & ID); }
|
||||
|
||||
bool empty() const { return Queue.empty(); }
|
||||
|
||||
unsigned size() const { return Queue.size(); }
|
||||
|
||||
typedef std::vector<SUnit*>::iterator iterator;
|
||||
|
||||
iterator begin() { return Queue.begin(); }
|
||||
|
||||
iterator end() { return Queue.end(); }
|
||||
|
||||
iterator find(SUnit *SU) {
|
||||
return std::find(Queue.begin(), Queue.end(), SU);
|
||||
}
|
||||
|
||||
void push(SUnit *SU) {
|
||||
Queue.push_back(SU);
|
||||
SU->NodeQueueId |= ID;
|
||||
}
|
||||
|
||||
void remove(iterator I) {
|
||||
(*I)->NodeQueueId &= ~ID;
|
||||
*I = Queue.back();
|
||||
Queue.pop_back();
|
||||
}
|
||||
|
||||
void dump() {
|
||||
dbgs() << Name << ": ";
|
||||
for (unsigned i = 0, e = Queue.size(); i < e; ++i)
|
||||
dbgs() << Queue[i]->NodeNum << " ";
|
||||
dbgs() << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
/// ConvergingVLIWScheduler shrinks the unscheduled zone using heuristics to balance
|
||||
/// the schedule.
|
||||
class ConvergingVLIWScheduler : public MachineSchedStrategy {
|
||||
|
||||
/// Store the state used by ConvergingVLIWScheduler heuristics, required for the
|
||||
/// lifetime of one invocation of pickNode().
|
||||
struct SchedCandidate {
|
||||
// The best SUnit candidate.
|
||||
SUnit *SU;
|
||||
|
||||
// Register pressure values for the best candidate.
|
||||
RegPressureDelta RPDelta;
|
||||
|
||||
// Best scheduling cost.
|
||||
int SCost;
|
||||
|
||||
SchedCandidate(): SU(NULL), SCost(0) {}
|
||||
};
|
||||
/// Represent the type of SchedCandidate found within a single queue.
|
||||
enum CandResult {
|
||||
NoCand, NodeOrder, SingleExcess, SingleCritical, SingleMax, MultiPressure,
|
||||
BestCost};
|
||||
|
||||
/// Each Scheduling boundary is associated with ready queues. It tracks the
|
||||
/// current cycle in whichever direction at has moved, and maintains the state
|
||||
/// of "hazards" and other interlocks at the current cycle.
|
||||
struct SchedBoundary {
|
||||
VLIWMachineScheduler *DAG;
|
||||
|
||||
ReadyQueue Available;
|
||||
ReadyQueue Pending;
|
||||
bool CheckPending;
|
||||
|
||||
ScheduleHazardRecognizer *HazardRec;
|
||||
|
||||
unsigned CurrCycle;
|
||||
unsigned IssueCount;
|
||||
|
||||
/// MinReadyCycle - Cycle of the soonest available instruction.
|
||||
unsigned MinReadyCycle;
|
||||
|
||||
// Remember the greatest min operand latency.
|
||||
unsigned MaxMinLatency;
|
||||
|
||||
/// Pending queues extend the ready queues with the same ID and the
|
||||
/// PendingFlag set.
|
||||
SchedBoundary(unsigned ID, const Twine &Name):
|
||||
DAG(0), Available(ID, Name+".A"),
|
||||
Pending(ID << ConvergingVLIWScheduler::LogMaxQID, Name+".P"),
|
||||
CheckPending(false), HazardRec(0), CurrCycle(0), IssueCount(0),
|
||||
MinReadyCycle(UINT_MAX), MaxMinLatency(0) {}
|
||||
|
||||
~SchedBoundary() { delete HazardRec; }
|
||||
|
||||
bool isTop() const {
|
||||
return Available.getID() == ConvergingVLIWScheduler::TopQID;
|
||||
}
|
||||
|
||||
bool checkHazard(SUnit *SU);
|
||||
|
||||
void releaseNode(SUnit *SU, unsigned ReadyCycle);
|
||||
|
||||
void bumpCycle();
|
||||
|
||||
void bumpNode(SUnit *SU);
|
||||
|
||||
void releasePending();
|
||||
|
||||
void removeReady(SUnit *SU);
|
||||
|
||||
SUnit *pickOnlyChoice();
|
||||
};
|
||||
|
||||
VLIWMachineScheduler *DAG;
|
||||
const TargetRegisterInfo *TRI;
|
||||
|
||||
// State of the top and bottom scheduled instruction boundaries.
|
||||
SchedBoundary Top;
|
||||
SchedBoundary Bot;
|
||||
|
||||
public:
|
||||
/// SUnit::NodeQueueId: 0 (none), 1 (top), 2 (bot), 3 (both)
|
||||
enum {
|
||||
TopQID = 1,
|
||||
BotQID = 2,
|
||||
LogMaxQID = 2
|
||||
};
|
||||
|
||||
ConvergingVLIWScheduler():
|
||||
DAG(0), TRI(0), Top(TopQID, "TopQ"), Bot(BotQID, "BotQ") {}
|
||||
|
||||
virtual void initialize(VLIWMachineScheduler *dag);
|
||||
|
||||
virtual SUnit *pickNode(bool &IsTopNode);
|
||||
|
||||
virtual void schedNode(SUnit *SU, bool IsTopNode);
|
||||
|
||||
virtual void releaseTopNode(SUnit *SU);
|
||||
|
||||
virtual void releaseBottomNode(SUnit *SU);
|
||||
|
||||
protected:
|
||||
SUnit *pickNodeBidrectional(bool &IsTopNode);
|
||||
|
||||
int SchedulingCost(ReadyQueue &Q,
|
||||
SUnit *SU, SchedCandidate &Candidate,
|
||||
RegPressureDelta &Delta, bool verbose);
|
||||
|
||||
CandResult pickNodeFromQueue(ReadyQueue &Q,
|
||||
const RegPressureTracker &RPTracker,
|
||||
SchedCandidate &Candidate);
|
||||
#ifndef NDEBUG
|
||||
void traceCandidate(const char *Label, const ReadyQueue &Q, SUnit *SU,
|
||||
PressureElement P = PressureElement());
|
||||
#endif
|
||||
};
|
||||
|
||||
class VLIWResourceModel {
|
||||
/// ResourcesModel - Represents VLIW state.
|
||||
/// Not limited to VLIW targets per say, but assumes
|
||||
/// definition of DFA by a target.
|
||||
DFAPacketizer *ResourcesModel;
|
||||
|
||||
const InstrItineraryData *InstrItins;
|
||||
|
||||
/// Local packet/bundle model. Purely
|
||||
/// internal to the MI schedulre at the time.
|
||||
std::vector<SUnit*> Packet;
|
||||
|
||||
/// Total packets created.
|
||||
unsigned TotalPackets;
|
||||
|
||||
public:
|
||||
VLIWResourceModel(MachineSchedContext *C, const InstrItineraryData *IID) :
|
||||
InstrItins(IID), TotalPackets(0) {
|
||||
const TargetMachine &TM = C->MF->getTarget();
|
||||
ResourcesModel = TM.getInstrInfo()->CreateTargetScheduleState(&TM,NULL);
|
||||
|
||||
// This hard requirement could be relaxed, but for now do not let it proceed.
|
||||
assert(ResourcesModel && "Unimplemented CreateTargetScheduleState.");
|
||||
|
||||
Packet.resize(InstrItins->SchedModel->IssueWidth);
|
||||
Packet.clear();
|
||||
ResourcesModel->clearResources();
|
||||
}
|
||||
|
||||
~VLIWResourceModel() {
|
||||
delete ResourcesModel;
|
||||
}
|
||||
|
||||
void resetPacketState() {
|
||||
Packet.clear();
|
||||
}
|
||||
|
||||
void resetDFA() {
|
||||
ResourcesModel->clearResources();
|
||||
}
|
||||
|
||||
bool isResourceAvailable(SUnit *SU);
|
||||
void reserveResources(SUnit *SU);
|
||||
unsigned getTotalPackets() const { return TotalPackets; }
|
||||
};
|
||||
|
||||
class VLIWMachineScheduler : public ScheduleDAGInstrs {
|
||||
/// AA - AliasAnalysis for making memory reference queries.
|
||||
AliasAnalysis *AA;
|
||||
|
||||
RegisterClassInfo *RegClassInfo;
|
||||
MachineSchedStrategy *SchedImpl;
|
||||
|
||||
/// state separatly for top/bottom sectioins.
|
||||
VLIWResourceModel *TopResourceModel;
|
||||
VLIWResourceModel *BotResourceModel;
|
||||
|
||||
MachineBasicBlock::iterator LiveRegionEnd;
|
||||
|
||||
/// Register pressure in this region computed by buildSchedGraph.
|
||||
IntervalPressure RegPressure;
|
||||
RegPressureTracker RPTracker;
|
||||
|
||||
/// List of pressure sets that exceed the target's pressure limit before
|
||||
/// scheduling, listed in increasing set ID order. Each pressure set is paired
|
||||
/// with its max pressure in the currently scheduled regions.
|
||||
std::vector<PressureElement> RegionCriticalPSets;
|
||||
|
||||
/// The top of the unscheduled zone.
|
||||
MachineBasicBlock::iterator CurrentTop;
|
||||
IntervalPressure TopPressure;
|
||||
RegPressureTracker TopRPTracker;
|
||||
|
||||
/// The bottom of the unscheduled zone.
|
||||
MachineBasicBlock::iterator CurrentBottom;
|
||||
IntervalPressure BotPressure;
|
||||
RegPressureTracker BotRPTracker;
|
||||
|
||||
#ifndef NDEBUG
|
||||
/// The number of instructions scheduled so far. Used to cut off the
|
||||
/// scheduler at the point determined by misched-cutoff.
|
||||
unsigned NumInstrsScheduled;
|
||||
#endif
|
||||
|
||||
/// Total packets in the region.
|
||||
unsigned TotalPackets;
|
||||
|
||||
const MachineLoopInfo *MLI;
|
||||
public:
|
||||
VLIWMachineScheduler(MachineSchedContext *C, MachineSchedStrategy *S):
|
||||
ScheduleDAGInstrs(*C->MF, *C->MLI, *C->MDT, /*IsPostRA=*/false, C->LIS),
|
||||
AA(C->AA), RegClassInfo(C->RegClassInfo), SchedImpl(S),
|
||||
RPTracker(RegPressure), CurrentTop(), TopRPTracker(TopPressure),
|
||||
CurrentBottom(), BotRPTracker(BotPressure), MLI(C->MLI) {
|
||||
|
||||
TopResourceModel = new VLIWResourceModel(C, InstrItins);
|
||||
BotResourceModel = new VLIWResourceModel(C, InstrItins);
|
||||
|
||||
#ifndef NDEBUG
|
||||
NumInstrsScheduled = 0;
|
||||
#endif
|
||||
TotalPackets = 0;
|
||||
}
|
||||
|
||||
virtual ~VLIWMachineScheduler() {
|
||||
delete SchedImpl;
|
||||
delete TopResourceModel;
|
||||
delete BotResourceModel;
|
||||
}
|
||||
|
||||
MachineBasicBlock::iterator top() const { return CurrentTop; }
|
||||
MachineBasicBlock::iterator bottom() const { return CurrentBottom; }
|
||||
|
||||
/// Implement the ScheduleDAGInstrs interface for handling the next scheduling
|
||||
/// region. This covers all instructions in a block, while schedule() may only
|
||||
/// cover a subset.
|
||||
void enterRegion(MachineBasicBlock *bb,
|
||||
MachineBasicBlock::iterator begin,
|
||||
MachineBasicBlock::iterator end,
|
||||
unsigned endcount);
|
||||
|
||||
/// Schedule - This is called back from ScheduleDAGInstrs::Run() when it's
|
||||
/// time to do some work.
|
||||
void schedule();
|
||||
|
||||
unsigned CurCycle;
|
||||
|
||||
/// Get current register pressure for the top scheduled instructions.
|
||||
const IntervalPressure &getTopPressure() const { return TopPressure; }
|
||||
const RegPressureTracker &getTopRPTracker() const { return TopRPTracker; }
|
||||
|
||||
/// Get current register pressure for the bottom scheduled instructions.
|
||||
const IntervalPressure &getBotPressure() const { return BotPressure; }
|
||||
const RegPressureTracker &getBotRPTracker() const { return BotRPTracker; }
|
||||
|
||||
/// Get register pressure for the entire scheduling region before scheduling.
|
||||
const IntervalPressure &getRegPressure() const { return RegPressure; }
|
||||
|
||||
const std::vector<PressureElement> &getRegionCriticalPSets() const {
|
||||
return RegionCriticalPSets;
|
||||
}
|
||||
|
||||
VLIWResourceModel *getTopResourceModel() { return TopResourceModel; };
|
||||
VLIWResourceModel *getBotResourceModel() { return BotResourceModel; };
|
||||
|
||||
/// getIssueWidth - Return the max instructions per scheduling group.
|
||||
unsigned getIssueWidth() const {
|
||||
return (InstrItins && InstrItins->SchedModel)
|
||||
? InstrItins->SchedModel->IssueWidth : 1;
|
||||
}
|
||||
|
||||
/// getNumMicroOps - Return the number of issue slots required for this MI.
|
||||
unsigned getNumMicroOps(MachineInstr *MI) const {
|
||||
if (!InstrItins) return 1;
|
||||
int UOps = InstrItins->getNumMicroOps(MI->getDesc().getSchedClass());
|
||||
return (UOps >= 0) ? UOps : TII->getNumMicroOps(InstrItins, MI);
|
||||
}
|
||||
|
||||
private:
|
||||
void scheduleNodeTopDown(SUnit *SU);
|
||||
void listScheduleTopDown();
|
||||
|
||||
void initRegPressure();
|
||||
void updateScheduledPressure(std::vector<unsigned> NewMaxPressure);
|
||||
|
||||
void moveInstruction(MachineInstr *MI, MachineBasicBlock::iterator InsertPos);
|
||||
bool checkSchedLimit();
|
||||
|
||||
void releaseRoots();
|
||||
|
||||
void releaseSucc(SUnit *SU, SDep *SuccEdge);
|
||||
void releaseSuccessors(SUnit *SU);
|
||||
void releasePred(SUnit *SU, SDep *PredEdge);
|
||||
void releasePredecessors(SUnit *SU);
|
||||
|
||||
void placeDebugValues();
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user