Skip to content

Commit

Permalink
A53 ARM processor machine modeling (CSUS-LLVM#137)
Browse files Browse the repository at this point in the history
Implemented A53 machine modeling and fixed ACO bugs related to having an issue rate > 1
  • Loading branch information
paul-mchugh authored and jrbyrnes committed Feb 16, 2021
1 parent 1f77316 commit 65da09e
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 30 deletions.
18 changes: 10 additions & 8 deletions include/opt-sched/Scheduler/machine_model.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand Down
21 changes: 9 additions & 12 deletions lib/Scheduler/aco.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ std::unique_ptr<InstSchedule> ACOScheduler::FindOneSchedule() {
rgn_->InitForSchdulng();

SchedInstruction *waitFor = NULL;
InstCount waitTime = 0;
InstCount waitUntil = 0;
llvm::SmallVector<Choice, 0> ready;
while (!IsSchedComplete_()) {
UpdtRdyLst_(crntCycleNum_, crntSlotNum_);
Expand Down Expand Up @@ -259,7 +259,7 @@ std::unique_ptr<InstSchedule> 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())] =
Expand All @@ -271,9 +271,9 @@ std::unique_ptr<InstSchedule> 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;
}
Expand All @@ -296,14 +296,11 @@ std::unique_ptr<InstSchedule> 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
Expand Down
4 changes: 4 additions & 0 deletions lib/Scheduler/machine_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Wrapper/OptSchedDDGWrapperBasic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
112 changes: 103 additions & 9 deletions lib/Wrapper/OptSchedMachineWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,25 @@ createCortexA7MMGenerator(const llvm::ScheduleDAGInstrs *dag,
return make_unique<CortexA7MMGenerator>(dag, mm);
}

std::unique_ptr<MachineModelGenerator>
createCortexA53MMGenerator(const llvm::ScheduleDAGInstrs *dag,
MachineModel *mm) {
return make_unique<CortexA53MMGenerator>(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');

Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -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<int>(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);
}
}
18 changes: 18 additions & 0 deletions lib/Wrapper/OptSchedMachineWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
};

Expand All @@ -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:
Expand All @@ -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<std::string> ResourceIdToIssueType;
const llvm::ScheduleDAGInstrs *DAG;
MachineModel *MM;
};

} // end namespace opt_sched
} // namespace llvm

Expand Down

0 comments on commit 65da09e

Please sign in to comment.