From 65da09e5f66f340d0d0df2b990686f89a7c8ed98 Mon Sep 17 00:00:00 2001 From: paul-mchugh <33052852+paul-mchugh@users.noreply.github.com> Date: Tue, 15 Dec 2020 14:59:33 -0800 Subject: [PATCH] A53 ARM processor machine modeling (#137) Implemented A53 machine modeling and fixed ACO bugs related to having an issue rate > 1 --- include/opt-sched/Scheduler/machine_model.h | 18 ++-- lib/Scheduler/aco.cpp | 21 ++-- lib/Scheduler/machine_model.cpp | 4 + lib/Wrapper/OptSchedDDGWrapperBasic.cpp | 2 +- lib/Wrapper/OptSchedMachineWrapper.cpp | 112 ++++++++++++++++++-- lib/Wrapper/OptSchedMachineWrapper.h | 18 ++++ 6 files changed, 145 insertions(+), 30 deletions(-) diff --git a/include/opt-sched/Scheduler/machine_model.h b/include/opt-sched/Scheduler/machine_model.h index af5b4d17..5ff0cacb 100644 --- a/include/opt-sched/Scheduler/machine_model.h +++ b/include/opt-sched/Scheduler/machine_model.h @@ -74,6 +74,14 @@ struct InstTypeInfo { bool blksCycle; }; +// A description of a issue type/FU. +struct IssueTypeInfo { + // The name of the issue type. + string name; + // How many slots of this issue type the machine has per cycle. + int slotsCount; +}; + // A read-only description of a machine. class MachineModel { public: @@ -154,6 +162,8 @@ class MachineModel { } // Add a new instruction type. void AddInstType(InstTypeInfo &instTypeInfo); + // Add a new issue type. + void addIssueType(IssueTypeInfo &IssueTypeInfo); protected: // Creates an uninitialized machine model. For use by subclasses. @@ -167,14 +177,6 @@ class MachineModel { int count; }; - // A description of a register type. - struct IssueTypeInfo { - // The name of the issue type. - string name; - // How many slots of this issue type the machine has per cycle. - int slotsCount; - }; - // The name of the machine model. string mdlName_; // The machine's issue rate. I.e. the total number of issue slots for all diff --git a/lib/Scheduler/aco.cpp b/lib/Scheduler/aco.cpp index 8da13feb..7129b0c5 100644 --- a/lib/Scheduler/aco.cpp +++ b/lib/Scheduler/aco.cpp @@ -208,7 +208,7 @@ std::unique_ptr ACOScheduler::FindOneSchedule() { rgn_->InitForSchdulng(); SchedInstruction *waitFor = NULL; - InstCount waitTime = 0; + InstCount waitUntil = 0; llvm::SmallVector ready; while (!IsSchedComplete_()) { UpdtRdyLst_(crntCycleNum_, crntSlotNum_); @@ -259,7 +259,7 @@ std::unique_ptr ACOScheduler::FindOneSchedule() { Choice c; c.inst = fIns; c.heuristic = (double)heuristic / maxPriority + 1; - c.readyOn = fCycle; + c.readyOn = crntCycleNum_ + fCycle; ready.push_back(c); if (IsDbg && lastInst) LastHeu[std::make_pair(lastInst->GetNum(), fIns->GetNum())] = @@ -271,9 +271,9 @@ std::unique_ptr ACOScheduler::FindOneSchedule() { if (!ready.empty()) { Choice Sel = SelectInstruction(ready, lastInst); - waitTime = Sel.readyOn; + waitUntil = Sel.readyOn; inst = Sel.inst; - if (waitTime > 0 || !ChkInstLglty_(inst)) { + if (waitUntil > crntCycleNum_ || !ChkInstLglty_(inst)) { waitFor = inst; inst = NULL; } @@ -296,14 +296,11 @@ std::unique_ptr ACOScheduler::FindOneSchedule() { // 2)Schedule a stall if we are still waiting, Schedule the instruction we // are waiting for if possible, decrement waiting time - if (waitFor) { - if (waitTime <= 0) { - if (ChkInstLglty_(inst)) { - inst = waitFor; - waitFor = NULL; - } - } else - waitTime--; + if (waitFor && waitUntil <= crntCycleNum_) { + if (ChkInstLglty_(waitFor)) { + inst = waitFor; + waitFor = NULL; + } } // boilerplate, mostly copied from ListScheduler, try not to touch it diff --git a/lib/Scheduler/machine_model.cpp b/lib/Scheduler/machine_model.cpp index e143c9e2..418811c7 100644 --- a/lib/Scheduler/machine_model.cpp +++ b/lib/Scheduler/machine_model.cpp @@ -205,6 +205,10 @@ void MachineModel::AddInstType(InstTypeInfo &instTypeInfo) { instTypes_.push_back(std::move(instTypeInfo)); } +void MachineModel::addIssueType(IssueTypeInfo &IssueTypeInfo) { + issueTypes_.push_back(std::move(IssueTypeInfo)); +} + InstType MachineModel::getDefaultInstType() const { return GetInstTypeByName("Default"); } diff --git a/lib/Wrapper/OptSchedDDGWrapperBasic.cpp b/lib/Wrapper/OptSchedDDGWrapperBasic.cpp index e0c09071..1b60d5e6 100644 --- a/lib/Wrapper/OptSchedDDGWrapperBasic.cpp +++ b/lib/Wrapper/OptSchedDDGWrapperBasic.cpp @@ -478,7 +478,7 @@ void OptSchedDDGWrapperBasic::convertSUnit(const SUnit &SU) { // type. if (InstType == INVALID_INST_TYPE) { if (ShouldGenerateMM) - MM->getMMGen()->generateInstrType(MI); + InstType = MM->getMMGen()->generateInstrType(MI); else InstType = MM->getDefaultInstType(); } diff --git a/lib/Wrapper/OptSchedMachineWrapper.cpp b/lib/Wrapper/OptSchedMachineWrapper.cpp index b8142848..c22b62af 100644 --- a/lib/Wrapper/OptSchedMachineWrapper.cpp +++ b/lib/Wrapper/OptSchedMachineWrapper.cpp @@ -48,16 +48,25 @@ createCortexA7MMGenerator(const llvm::ScheduleDAGInstrs *dag, return make_unique(dag, mm); } +std::unique_ptr +createCortexA53MMGenerator(const llvm::ScheduleDAGInstrs *dag, + MachineModel *mm) { + return make_unique(dag, mm); +} + } // end anonymous namespace OptSchedMachineModel::OptSchedMachineModel(const char *configFile) : MachineModel(configFile), shouldGenerateMM(false), MMGen(nullptr) {} void OptSchedMachineModel::convertMachineModel( - const ScheduleDAGInstrs &dag, const RegisterClassInfo *regClassInfo) { - const TargetMachine &target = dag.TM; + const ScheduleDAGInstrs &Dag, const RegisterClassInfo *RegClassInfo) { + const TargetMachine &Target = Dag.TM; + const TargetSchedModel *LLVMSchedModel = Dag.getSchedModel(); + const TargetSubtargetInfo *SubtargetInfo = LLVMSchedModel->getSubtargetInfo(); + std::string ExactCPU = SubtargetInfo->getCPU().str(); - mdlName_ = target.getTarget().getName(); + mdlName_ = Target.getTarget().getName(); LLVM_DEBUG(dbgs() << "Machine model: " << mdlName_.c_str() << '\n'); @@ -67,10 +76,13 @@ void OptSchedMachineModel::convertMachineModel( if (shouldGenerateMM) { if (mdlName_ == "ARM-Cortex-A7") - MMGen = createCortexA7MMGenerator(&dag, this); + MMGen = createCortexA7MMGenerator(&Dag, this); + else if (ExactCPU == "cortex-a53") + MMGen = createCortexA53MMGenerator(&Dag, this); else - Logger::Error("Could not find machine model generator for target \"%s\"", - mdlName_.c_str()); + llvm::report_fatal_error( + "Could not find machine model generator for target " + mdlName_, + false); } InstTypeInfo instType; @@ -108,11 +120,11 @@ void OptSchedMachineModel::convertMachineModel( VGPR32.count = 24; registerTypes_.push_back(VGPR32); } else { - const auto *TRI = dag.TRI; + const auto *TRI = Dag.TRI; for (unsigned pSet = 0; pSet < TRI->getNumRegPressureSets(); ++pSet) { RegTypeInfo regType; regType.name = TRI->getRegPressureSetName(pSet); - int pressureLimit = regClassInfo->getRegPressureSetLimit(pSet); + int pressureLimit = RegClassInfo->getRegPressureSetLimit(pSet); // set registers with 0 limit to 1 to support flags and special cases if (pressureLimit > 0) regType.count = pressureLimit; @@ -121,6 +133,10 @@ void OptSchedMachineModel::convertMachineModel( registerTypes_.push_back(regType); } } + + // initialize other MM non-instruction specific info if appropriate + if (shouldGenerateMM && MMGen->generatesAllData()) + MMGen->generateProcessorData(&mdlName_, &issueRate_); } CortexA7MMGenerator::CortexA7MMGenerator(const llvm::ScheduleDAGInstrs *dag, @@ -199,6 +215,84 @@ InstType CortexA7MMGenerator::generateInstrType(const MachineInstr *instr) { // Add the new instruction type MM->AddInstType(InstTypeI); - return MM->GetInstTypeByName(InstTypeI.name); + return MM->GetInstTypeByName(instrName); + } +} + +void CortexA53MMGenerator::generateProcessorData(std::string *mdlName_, + int *issueRate_) { + const TargetSchedModel *LLVMSchedModel = DAG->getSchedModel(); + const TargetSubtargetInfo *SubtargetInfo = LLVMSchedModel->getSubtargetInfo(); + std::string ExactCPU = SubtargetInfo->getCPU().str(); + + *mdlName_ = ExactCPU; + *issueRate_ = LLVMSchedModel->getIssueWidth(); + + unsigned FUTypesCount = LLVMSchedModel->getNumProcResourceKinds(); + ResourceIdToIssueType.resize(FUTypesCount); + for (unsigned FUIdx = 1; FUIdx < FUTypesCount; FUIdx++) { + const MCProcResourceDesc *FUResource = + LLVMSchedModel->getProcResource(FUIdx); + ResourceIdToIssueType[FUIdx] = FUResource->Name; + IssueTypeInfo ITI{FUResource->Name, static_cast(FUResource->NumUnits)}; + MM->addIssueType(ITI); + } +} + +InstType +CortexA53MMGenerator::generateInstrType(const llvm::MachineInstr *instr) { + // Search in the machine model for an instType with this OpCode + const std::string InstrName = DAG->TII->getName(instr->getOpcode()); + const InstType InstrType = MM->GetInstTypeByName(InstrName); + + // If the machine model does not have instType with this OpCode name, + // generate a type for the instruction. + if (InstrType != INVALID_INST_TYPE) + return InstrType; + else { + const TargetSchedModel *LLVMSchedModel = DAG->getSchedModel(); + const MCSchedClassDesc *MCDesc = LLVMSchedModel->resolveSchedClass(instr); + + InstTypeInfo InstTypeI; + InstTypeI.name = InstrName; + // Most of the A53's instructions only use one FU (one uses 3 FUs and some + // use 0 FUs) we use the default issue type for instructions which use no FU + // If we were to see the 3 FU instruction then we assign it its first issue + // type (but I think the 3 FU inst is a type of branch isntruction that we + // never see) + const MCWriteProcResEntry *ResEntry = + LLVMSchedModel->getWriteProcResBegin(MCDesc); + if (ResEntry != LLVMSchedModel->getWriteProcResEnd(MCDesc)) { + std::string IssueTypeName = + ResourceIdToIssueType[ResEntry->ProcResourceIdx]; + InstTypeI.issuType = MM->GetIssueTypeByName(IssueTypeName.c_str()); + InstTypeI.pipelined = (ResEntry->Cycles == 1); + } else { + InstTypeI.issuType = MM->getDefaultIssueType(); + InstTypeI.pipelined = true; + } + InstTypeI.ltncy = 1; // This field is never used + InstTypeI.isCntxtDep = false; + InstTypeI.sprtd = true; + InstTypeI.blksCycle = false; + + Logger::Info( + "Adding new instruction type.\n" + "Name: %s\n" + "Is Context Dependent: %s\n" + "IssueType: %s (%d)\n" + "Latency: %d\n" + "Is Pipelined: %s\n" + "Supported: %s\n" + "Blocks Cycle: %s\n", + InstTypeI.name.c_str(), InstTypeI.isCntxtDep ? "True" : "False", + MM->GetIssueTypeNameByCode(InstTypeI.issuType), InstTypeI.issuType, + InstTypeI.ltncy, InstTypeI.pipelined ? "True" : "False", + InstTypeI.sprtd ? "True" : "False", + InstTypeI.blksCycle ? "True" : "False"); + + // Add the new instruction type + MM->AddInstType(InstTypeI); + return MM->GetInstTypeByName(InstrName); } } diff --git a/lib/Wrapper/OptSchedMachineWrapper.h b/lib/Wrapper/OptSchedMachineWrapper.h index d034e5df..927bf163 100644 --- a/lib/Wrapper/OptSchedMachineWrapper.h +++ b/lib/Wrapper/OptSchedMachineWrapper.h @@ -9,6 +9,7 @@ contained in those ini files. #define OPTSCHED_MACHINE_MODEL_WRAPPER_H #include "opt-sched/Scheduler/machine_model.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineScheduler.h" #include "llvm/CodeGen/RegisterClassInfo.h" @@ -49,6 +50,8 @@ class MachineModelGenerator { // Generate instruction scheduling type for all instructions in the current // DAG that do not already have assigned instruction types. virtual InstType generateInstrType(const llvm::MachineInstr *instr) = 0; + virtual bool generatesAllData() = 0; + virtual void generateProcessorData(std::string *mdlName_, int *issueRate_) {} virtual ~MachineModelGenerator() = default; }; @@ -62,6 +65,7 @@ class CortexA7MMGenerator : public MachineModelGenerator { // Generate instruction scheduling type for all instructions in the current // DAG by using LLVM itineraries. InstType generateInstrType(const llvm::MachineInstr *instr); + bool generatesAllData() { return false; } virtual ~CortexA7MMGenerator() = default; private: @@ -84,6 +88,20 @@ class CortexA7MMGenerator : public MachineModelGenerator { IssueType generateIssueType(const llvm::InstrStage *E) const; }; +class CortexA53MMGenerator : public MachineModelGenerator { +public: + CortexA53MMGenerator(const llvm::ScheduleDAGInstrs *dag, MachineModel *mm) + : DAG(dag), MM(mm) {} + InstType generateInstrType(const llvm::MachineInstr *instr); + bool generatesAllData() { return true; } + void generateProcessorData(std::string *mdlName_, int *issueRate_); + +private: + std::vector ResourceIdToIssueType; + const llvm::ScheduleDAGInstrs *DAG; + MachineModel *MM; +}; + } // end namespace opt_sched } // namespace llvm