#ifndef LLVM_UTILS_TABLEGEN_CODEGENSCHEDULE_H
#define LLVM_UTILS_TABLEGEN_CODEGENSCHEDULE_H
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/SetTheory.h"
namespace llvm {
class CodeGenTarget;
class CodeGenSchedModels;
class CodeGenInstruction;
using RecVec = std::vector<Record*>;
using RecIter = std::vector<Record*>::const_iterator;
using IdxVec = std::vector<unsigned>;
using IdxIter = std::vector<unsigned>::const_iterator;
struct CodeGenSchedRW {
unsigned Index;
std::string Name;
Record *TheDef;
bool IsRead;
bool IsAlias;
bool HasVariants;
bool IsVariadic;
bool IsSequence;
IdxVec Sequence;
RecVec Aliases;
CodeGenSchedRW()
: Index(0), TheDef(nullptr), IsRead(false), IsAlias(false),
HasVariants(false), IsVariadic(false), IsSequence(false) {}
CodeGenSchedRW(unsigned Idx, Record *Def)
: Index(Idx), TheDef(Def), IsAlias(false), IsVariadic(false) {
Name = std::string(Def->getName());
IsRead = Def->isSubClassOf("SchedRead");
HasVariants = Def->isSubClassOf("SchedVariant");
if (HasVariants)
IsVariadic = Def->getValueAsBit("Variadic");
IsSequence = Def->isSubClassOf("WriteSequence");
}
CodeGenSchedRW(unsigned Idx, bool Read, ArrayRef<unsigned> Seq,
const std::string &Name)
: Index(Idx), Name(Name), TheDef(nullptr), IsRead(Read), IsAlias(false),
HasVariants(false), IsVariadic(false), IsSequence(true), Sequence(Seq) {
assert(Sequence.size() > 1 && "implied sequence needs >1 RWs");
}
bool isValid() const {
assert((!HasVariants || TheDef) && "Variant write needs record def");
assert((!IsVariadic || HasVariants) && "Variadic write needs variants");
assert((!IsSequence || !HasVariants) && "Sequence can't have variant");
assert((!IsSequence || !Sequence.empty()) && "Sequence should be nonempty");
assert((!IsAlias || Aliases.empty()) && "Alias cannot have aliases");
return TheDef || !Sequence.empty();
}
#ifndef NDEBUG
void dump() const;
#endif
};
struct CodeGenSchedTransition {
unsigned ToClassIdx;
unsigned ProcIndex;
RecVec PredTerm;
};
struct CodeGenSchedClass {
unsigned Index;
std::string Name;
Record *ItinClassDef;
IdxVec Writes;
IdxVec Reads;
IdxVec ProcIndices;
std::vector<CodeGenSchedTransition> Transitions;
RecVec InstRWs;
DenseSet<unsigned> InstRWProcIndices;
CodeGenSchedClass(unsigned Index, std::string Name, Record *ItinClassDef)
: Index(Index), Name(std::move(Name)), ItinClassDef(ItinClassDef) {}
bool isKeyEqual(Record *IC, ArrayRef<unsigned> W,
ArrayRef<unsigned> R) const {
return ItinClassDef == IC && makeArrayRef(Writes) == W &&
makeArrayRef(Reads) == R;
}
bool isInferred() const { return !ItinClassDef; }
#ifndef NDEBUG
void dump(const CodeGenSchedModels *SchedModels) const;
#endif
};
struct CodeGenRegisterCost {
Record *RCDef;
unsigned Cost;
bool AllowMoveElimination;
CodeGenRegisterCost(Record *RC, unsigned RegisterCost, bool AllowMoveElim = false)
: RCDef(RC), Cost(RegisterCost), AllowMoveElimination(AllowMoveElim) {}
CodeGenRegisterCost(const CodeGenRegisterCost &) = default;
CodeGenRegisterCost &operator=(const CodeGenRegisterCost &) = delete;
};
struct CodeGenRegisterFile {
std::string Name;
Record *RegisterFileDef;
unsigned MaxMovesEliminatedPerCycle;
bool AllowZeroMoveEliminationOnly;
unsigned NumPhysRegs;
std::vector<CodeGenRegisterCost> Costs;
CodeGenRegisterFile(StringRef name, Record *def, unsigned MaxMoveElimPerCy = 0,
bool AllowZeroMoveElimOnly = false)
: Name(name), RegisterFileDef(def),
MaxMovesEliminatedPerCycle(MaxMoveElimPerCy),
AllowZeroMoveEliminationOnly(AllowZeroMoveElimOnly),
NumPhysRegs(0) {}
bool hasDefaultCosts() const { return Costs.empty(); }
};
struct CodeGenProcModel {
unsigned Index;
std::string ModelName;
Record *ModelDef;
Record *ItinsDef;
RecVec ItinDefList;
RecVec ItinRWDefs;
RecVec UnsupportedFeaturesDefs;
RecVec WriteResDefs;
RecVec ReadAdvanceDefs;
RecVec ProcResourceDefs;
std::vector<CodeGenRegisterFile> RegisterFiles;
Record *RetireControlUnit;
Record *LoadQueue;
Record *StoreQueue;
CodeGenProcModel(unsigned Idx, std::string Name, Record *MDef,
Record *IDef) :
Index(Idx), ModelName(std::move(Name)), ModelDef(MDef), ItinsDef(IDef),
RetireControlUnit(nullptr), LoadQueue(nullptr), StoreQueue(nullptr) {}
bool hasItineraries() const {
return !ItinsDef->getValueAsListOfDefs("IID").empty();
}
bool hasInstrSchedModel() const {
return !WriteResDefs.empty() || !ItinRWDefs.empty();
}
bool hasExtraProcessorInfo() const {
return RetireControlUnit || LoadQueue || StoreQueue ||
!RegisterFiles.empty();
}
unsigned getProcResourceIdx(Record *PRDef) const;
bool isUnsupported(const CodeGenInstruction &Inst) const;
#ifndef NDEBUG
void dump() const;
#endif
};
struct PredicateInfo {
llvm::APInt ProcModelMask; llvm::APInt OperandMask; const Record *Predicate; PredicateInfo(llvm::APInt CpuMask, llvm::APInt Operands, const Record *Pred)
: ProcModelMask(CpuMask), OperandMask(Operands), Predicate(Pred) {}
bool operator==(const PredicateInfo &Other) const {
return ProcModelMask == Other.ProcModelMask &&
OperandMask == Other.OperandMask && Predicate == Other.Predicate;
}
};
class OpcodeInfo {
std::vector<PredicateInfo> Predicates;
OpcodeInfo(const OpcodeInfo &Other) = delete;
OpcodeInfo &operator=(const OpcodeInfo &Other) = delete;
public:
OpcodeInfo() = default;
OpcodeInfo &operator=(OpcodeInfo &&Other) = default;
OpcodeInfo(OpcodeInfo &&Other) = default;
ArrayRef<PredicateInfo> getPredicates() const { return Predicates; }
void addPredicateForProcModel(const llvm::APInt &CpuMask,
const llvm::APInt &OperandMask,
const Record *Predicate);
};
class OpcodeGroup {
OpcodeInfo Info;
std::vector<const Record *> Opcodes;
OpcodeGroup(const OpcodeGroup &Other) = delete;
OpcodeGroup &operator=(const OpcodeGroup &Other) = delete;
public:
OpcodeGroup(OpcodeInfo &&OpInfo) : Info(std::move(OpInfo)) {}
OpcodeGroup(OpcodeGroup &&Other) = default;
void addOpcode(const Record *Opcode) {
assert(!llvm::is_contained(Opcodes, Opcode) && "Opcode already in set!");
Opcodes.push_back(Opcode);
}
ArrayRef<const Record *> getOpcodes() const { return Opcodes; }
const OpcodeInfo &getOpcodeInfo() const { return Info; }
};
class STIPredicateFunction {
const Record *FunctionDeclaration;
std::vector<const Record *> Definitions;
std::vector<OpcodeGroup> Groups;
STIPredicateFunction(const STIPredicateFunction &Other) = delete;
STIPredicateFunction &operator=(const STIPredicateFunction &Other) = delete;
public:
STIPredicateFunction(const Record *Rec) : FunctionDeclaration(Rec) {}
STIPredicateFunction(STIPredicateFunction &&Other) = default;
bool isCompatibleWith(const STIPredicateFunction &Other) const {
return FunctionDeclaration == Other.FunctionDeclaration;
}
void addDefinition(const Record *Def) { Definitions.push_back(Def); }
void addOpcode(const Record *OpcodeRec, OpcodeInfo &&Info) {
if (Groups.empty() ||
Groups.back().getOpcodeInfo().getPredicates() != Info.getPredicates())
Groups.emplace_back(std::move(Info));
Groups.back().addOpcode(OpcodeRec);
}
StringRef getName() const {
return FunctionDeclaration->getValueAsString("Name");
}
const Record *getDefaultReturnPredicate() const {
return FunctionDeclaration->getValueAsDef("DefaultReturnValue");
}
const Record *getDeclaration() const { return FunctionDeclaration; }
ArrayRef<const Record *> getDefinitions() const { return Definitions; }
ArrayRef<OpcodeGroup> getGroups() const { return Groups; }
};
using ProcModelMapTy = DenseMap<const Record *, unsigned>;
class CodeGenSchedModels {
RecordKeeper &Records;
const CodeGenTarget &Target;
SetTheory Sets;
std::vector<CodeGenProcModel> ProcModels;
ProcModelMapTy ProcModelMap;
std::vector<CodeGenSchedRW> SchedWrites;
std::vector<CodeGenSchedRW> SchedReads;
std::vector<CodeGenSchedClass> SchedClasses;
unsigned NumInstrSchedClasses;
RecVec ProcResourceDefs;
RecVec ProcResGroups;
using InstClassMapTy = DenseMap<Record*, unsigned>;
InstClassMapTy InstrClassMap;
std::vector<STIPredicateFunction> STIPredicates;
std::vector<unsigned> getAllProcIndices() const;
public:
CodeGenSchedModels(RecordKeeper& RK, const CodeGenTarget &TGT);
using class_iterator = std::vector<CodeGenSchedClass>::iterator;
using const_class_iterator = std::vector<CodeGenSchedClass>::const_iterator;
class_iterator classes_begin() { return SchedClasses.begin(); }
const_class_iterator classes_begin() const { return SchedClasses.begin(); }
class_iterator classes_end() { return SchedClasses.end(); }
const_class_iterator classes_end() const { return SchedClasses.end(); }
iterator_range<class_iterator> classes() {
return make_range(classes_begin(), classes_end());
}
iterator_range<const_class_iterator> classes() const {
return make_range(classes_begin(), classes_end());
}
iterator_range<class_iterator> explicit_classes() {
return make_range(classes_begin(), classes_begin() + NumInstrSchedClasses);
}
iterator_range<const_class_iterator> explicit_classes() const {
return make_range(classes_begin(), classes_begin() + NumInstrSchedClasses);
}
Record *getModelOrItinDef(Record *ProcDef) const {
Record *ModelDef = ProcDef->getValueAsDef("SchedModel");
Record *ItinsDef = ProcDef->getValueAsDef("ProcItin");
if (!ItinsDef->getValueAsListOfDefs("IID").empty()) {
assert(ModelDef->getValueAsBit("NoModel")
&& "Itineraries must be defined within SchedMachineModel");
return ItinsDef;
}
return ModelDef;
}
const CodeGenProcModel &getModelForProc(Record *ProcDef) const {
Record *ModelDef = getModelOrItinDef(ProcDef);
ProcModelMapTy::const_iterator I = ProcModelMap.find(ModelDef);
assert(I != ProcModelMap.end() && "missing machine model");
return ProcModels[I->second];
}
CodeGenProcModel &getProcModel(Record *ModelDef) {
ProcModelMapTy::const_iterator I = ProcModelMap.find(ModelDef);
assert(I != ProcModelMap.end() && "missing machine model");
return ProcModels[I->second];
}
const CodeGenProcModel &getProcModel(Record *ModelDef) const {
return const_cast<CodeGenSchedModels*>(this)->getProcModel(ModelDef);
}
using ProcIter = std::vector<CodeGenProcModel>::const_iterator;
ProcIter procModelBegin() const { return ProcModels.begin(); }
ProcIter procModelEnd() const { return ProcModels.end(); }
ArrayRef<CodeGenProcModel> procModels() const { return ProcModels; }
bool hasItineraries() const;
const CodeGenSchedRW &getSchedWrite(unsigned Idx) const {
assert(Idx < SchedWrites.size() && "bad SchedWrite index");
assert(SchedWrites[Idx].isValid() && "invalid SchedWrite");
return SchedWrites[Idx];
}
const CodeGenSchedRW &getSchedRead(unsigned Idx) const {
assert(Idx < SchedReads.size() && "bad SchedRead index");
assert(SchedReads[Idx].isValid() && "invalid SchedRead");
return SchedReads[Idx];
}
const CodeGenSchedRW &getSchedRW(unsigned Idx, bool IsRead) const {
return IsRead ? getSchedRead(Idx) : getSchedWrite(Idx);
}
CodeGenSchedRW &getSchedRW(Record *Def) {
bool IsRead = Def->isSubClassOf("SchedRead");
unsigned Idx = getSchedRWIdx(Def, IsRead);
return const_cast<CodeGenSchedRW&>(
IsRead ? getSchedRead(Idx) : getSchedWrite(Idx));
}
const CodeGenSchedRW &getSchedRW(Record *Def) const {
return const_cast<CodeGenSchedModels&>(*this).getSchedRW(Def);
}
unsigned getSchedRWIdx(const Record *Def, bool IsRead) const;
bool hasReadOfWrite(Record *WriteDef) const;
CodeGenSchedClass &getSchedClass(unsigned Idx) {
assert(Idx < SchedClasses.size() && "bad SchedClass index");
return SchedClasses[Idx];
}
const CodeGenSchedClass &getSchedClass(unsigned Idx) const {
assert(Idx < SchedClasses.size() && "bad SchedClass index");
return SchedClasses[Idx];
}
unsigned getSchedClassIdx(const CodeGenInstruction &Inst) const;
using SchedClassIter = std::vector<CodeGenSchedClass>::const_iterator;
SchedClassIter schedClassBegin() const { return SchedClasses.begin(); }
SchedClassIter schedClassEnd() const { return SchedClasses.end(); }
ArrayRef<CodeGenSchedClass> schedClasses() const { return SchedClasses; }
unsigned numInstrSchedClasses() const { return NumInstrSchedClasses; }
void findRWs(const RecVec &RWDefs, IdxVec &Writes, IdxVec &Reads) const;
void findRWs(const RecVec &RWDefs, IdxVec &RWs, bool IsRead) const;
void expandRWSequence(unsigned RWIdx, IdxVec &RWSeq, bool IsRead) const;
void expandRWSeqForProc(unsigned RWIdx, IdxVec &RWSeq, bool IsRead,
const CodeGenProcModel &ProcModel) const;
unsigned addSchedClass(Record *ItinDef, ArrayRef<unsigned> OperWrites,
ArrayRef<unsigned> OperReads,
ArrayRef<unsigned> ProcIndices);
unsigned findOrInsertRW(ArrayRef<unsigned> Seq, bool IsRead);
Record *findProcResUnits(Record *ProcResKind, const CodeGenProcModel &PM,
ArrayRef<SMLoc> Loc) const;
ArrayRef<STIPredicateFunction> getSTIPredicates() const {
return STIPredicates;
}
private:
void collectProcModels();
void addProcModel(Record *ProcDef);
void collectSchedRW();
std::string genRWName(ArrayRef<unsigned> Seq, bool IsRead);
unsigned findRWForSequence(ArrayRef<unsigned> Seq, bool IsRead);
void collectSchedClasses();
void collectRetireControlUnits();
void collectRegisterFiles();
void collectOptionalProcessorInfo();
std::string createSchedClassName(Record *ItinClassDef,
ArrayRef<unsigned> OperWrites,
ArrayRef<unsigned> OperReads);
std::string createSchedClassName(const RecVec &InstDefs);
void createInstRWClass(Record *InstRWDef);
void collectProcItins();
void collectProcItinRW();
void collectProcUnsupportedFeatures();
void inferSchedClasses();
void checkMCInstPredicates() const;
void checkSTIPredicates() const;
void collectSTIPredicates();
void collectLoadStoreQueueInfo();
void checkCompleteness();
void inferFromRW(ArrayRef<unsigned> OperWrites, ArrayRef<unsigned> OperReads,
unsigned FromClassIdx, ArrayRef<unsigned> ProcIndices);
void inferFromItinClass(Record *ItinClassDef, unsigned FromClassIdx);
void inferFromInstRWs(unsigned SCIdx);
bool hasSuperGroup(RecVec &SubUnits, CodeGenProcModel &PM);
void verifyProcResourceGroups(CodeGenProcModel &PM);
void collectProcResources();
void collectItinProcResources(Record *ItinClassDef);
void collectRWResources(unsigned RWIdx, bool IsRead,
ArrayRef<unsigned> ProcIndices);
void collectRWResources(ArrayRef<unsigned> Writes, ArrayRef<unsigned> Reads,
ArrayRef<unsigned> ProcIndices);
void addProcResource(Record *ProcResourceKind, CodeGenProcModel &PM,
ArrayRef<SMLoc> Loc);
void addWriteRes(Record *ProcWriteResDef, unsigned PIdx);
void addReadAdvance(Record *ProcReadAdvanceDef, unsigned PIdx);
};
}
#endif