mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-05 13:26:55 +00:00
Machine Model (-schedmodel only). Added SchedAliases.
Allow subtargets to tie SchedReadWrite types to processor specific sequences or variants. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@164451 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -101,6 +101,10 @@ class ProcResourceKind;
|
||||
// cycle that the instruction issues in-order, forcing an interlock
|
||||
// with subsequent instructions that require the same resource until
|
||||
// the number of ResourceCyles specified in WriteRes expire.
|
||||
//
|
||||
// SchedModel ties these units to a processor for any stand-alone defs
|
||||
// of this class. Instances of subclass ProcResource will be automatically
|
||||
// attached to a processor, so SchedModel is not needed.
|
||||
class ProcResourceUnits<ProcResourceKind kind, int num> {
|
||||
ProcResourceKind Kind = kind;
|
||||
int NumUnits = num;
|
||||
@@ -152,12 +156,17 @@ class SchedRead : SchedReadWrite;
|
||||
// If the final write in this sequence is a SchedWriteVariant marked
|
||||
// Variadic, then the list of prior writes are distributed across all
|
||||
// operands after resolving the predicate for the final write.
|
||||
//
|
||||
// SchedModel silences warnings but is ignored.
|
||||
class WriteSequence<list<SchedWrite> writes, int rep = 1> : SchedWrite {
|
||||
list<SchedWrite> Writes = writes;
|
||||
int Repeat = rep;
|
||||
SchedMachineModel SchedModel = ?;
|
||||
}
|
||||
|
||||
// Define values common to WriteRes and SchedWriteRes.
|
||||
//
|
||||
// SchedModel ties these resources to a processor.
|
||||
class ProcWriteResources<list<ProcResourceKind> resources> {
|
||||
list<ProcResourceKind> ProcResources = resources;
|
||||
list<int> ResourceCycles = [];
|
||||
@@ -217,12 +226,15 @@ class SchedWriteRes<list<ProcResourceKind> resources> : SchedWrite,
|
||||
ProcWriteResources<resources>;
|
||||
|
||||
// Define values common to ReadAdvance and SchedReadAdvance.
|
||||
//
|
||||
// SchedModel ties these resources to a processor.
|
||||
class ProcReadAdvance<int cycles, list<SchedWrite> writes = []> {
|
||||
int Cycles = cycles;
|
||||
list<SchedWrite> ValidWrites = writes;
|
||||
// Allow a processor to mark some scheduling classes as unsupported
|
||||
// for stronger verification.
|
||||
bit Unsupported = 0;
|
||||
SchedMachineModel SchedModel = ?;
|
||||
}
|
||||
|
||||
// A processor may define a ReadAdvance associated with a SchedRead
|
||||
@@ -237,7 +249,6 @@ class ProcReadAdvance<int cycles, list<SchedWrite> writes = []> {
|
||||
// to issue earlier relative to the writer.
|
||||
class ReadAdvance<SchedRead read, int cycles, list<SchedWrite> writes = []>
|
||||
: ProcReadAdvance<cycles, writes> {
|
||||
SchedMachineModel SchedModel = ?;
|
||||
SchedRead ReadType = read;
|
||||
}
|
||||
|
||||
@@ -261,6 +272,8 @@ class PredicateProlog<code c> {
|
||||
// particular MachineInstr. The code snippet is used as an
|
||||
// if-statement's expression. Available variables are MI, SchedModel,
|
||||
// and anything defined in a PredicateProlog.
|
||||
//
|
||||
// SchedModel silences warnings but is ignored.
|
||||
class SchedPredicate<code pred> {
|
||||
SchedMachineModel SchedModel = ?;
|
||||
code Predicate = pred;
|
||||
@@ -281,6 +294,7 @@ class SchedVar<SchedPredicate pred, list<SchedReadWrite> selected> {
|
||||
list<SchedReadWrite> Selected = selected;
|
||||
}
|
||||
|
||||
// SchedModel silences warnings but is ignored.
|
||||
class SchedVariant<list<SchedVar> variants> {
|
||||
list<SchedVar> Variants = variants;
|
||||
bit Variadic = 0;
|
||||
@@ -309,6 +323,8 @@ class SchedReadVariant<list<SchedVar> variants> : SchedRead,
|
||||
|
||||
// Map a set of opcodes to a list of SchedReadWrite types. This allows
|
||||
// the subtarget to easily override specific operations.
|
||||
//
|
||||
// SchedModel ties this opcode mapping to a processor.
|
||||
class InstRW<list<SchedReadWrite> rw, list<Instruction> instrs> {
|
||||
list<SchedReadWrite> OperandReadWrites = rw;
|
||||
list<Instruction> Instrs = instrs;
|
||||
@@ -318,8 +334,23 @@ class InstRW<list<SchedReadWrite> rw, list<Instruction> instrs> {
|
||||
// Map a set of itinerary classes to SchedReadWrite resources. This is
|
||||
// used to bootstrap a target (e.g. ARM) when itineraries already
|
||||
// exist and changing InstrInfo is undesirable.
|
||||
//
|
||||
// SchedModel ties this ItineraryClass mapping to a processor.
|
||||
class ItinRW<list<SchedReadWrite> rw, list<InstrItinClass> iic> {
|
||||
list<InstrItinClass> MatchedItinClasses = iic;
|
||||
list<SchedReadWrite> OperandReadWrites = rw;
|
||||
SchedMachineModel SchedModel = ?;
|
||||
}
|
||||
|
||||
// Alias a target-defined SchedReadWrite to a processor specific
|
||||
// SchedReadWrite. This allows a subtarget to easily map a
|
||||
// SchedReadWrite type onto a WriteSequence, SchedWriteVariant, or
|
||||
// SchedReadVariant.
|
||||
//
|
||||
// SchedModel will usually be provided by surrounding let statement
|
||||
// and ties this SchedAlias mapping to a processor.
|
||||
class SchedAlias<SchedReadWrite match, SchedReadWrite alias> {
|
||||
SchedReadWrite MatchRW = match;
|
||||
SchedReadWrite AliasRW = alias;
|
||||
SchedMachineModel SchedModel = ?;
|
||||
}
|
||||
|
@@ -61,7 +61,7 @@ CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK,
|
||||
collectSchedClasses();
|
||||
|
||||
// Find instruction itineraries for each processor. Sort and populate
|
||||
// CodeGenProcMode::ItinDefList. (Cycle-to-cycle itineraries). This requires
|
||||
// CodeGenProcModel::ItinDefList. (Cycle-to-cycle itineraries). This requires
|
||||
// all itinerary classes to be discovered.
|
||||
collectProcItins();
|
||||
|
||||
@@ -204,6 +204,25 @@ void CodeGenSchedModels::collectSchedRW() {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Find all ReadWrites referenced by SchedAlias. AliasDefs needs to be sorted
|
||||
// for the loop below that initializes Alias vectors.
|
||||
RecVec AliasDefs = Records.getAllDerivedDefinitions("SchedAlias");
|
||||
std::sort(AliasDefs.begin(), AliasDefs.end(), LessRecord());
|
||||
for (RecIter AI = AliasDefs.begin(), AE = AliasDefs.end(); AI != AE; ++AI) {
|
||||
Record *MatchDef = (*AI)->getValueAsDef("MatchRW");
|
||||
Record *AliasDef = (*AI)->getValueAsDef("AliasRW");
|
||||
if (MatchDef->isSubClassOf("SchedWrite")) {
|
||||
if (!AliasDef->isSubClassOf("SchedWrite"))
|
||||
throw TGError((*AI)->getLoc(), "SchedWrite Alias must be SchedWrite");
|
||||
scanSchedRW(AliasDef, SWDefs, RWSet);
|
||||
}
|
||||
else {
|
||||
assert(MatchDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite");
|
||||
if (!AliasDef->isSubClassOf("SchedRead"))
|
||||
throw TGError((*AI)->getLoc(), "SchedRead Alias must be SchedRead");
|
||||
scanSchedRW(AliasDef, SRDefs, RWSet);
|
||||
}
|
||||
}
|
||||
// Sort and add the SchedReadWrites directly referenced by instructions or
|
||||
// itinerary resources. Index reads and writes in separate domains.
|
||||
std::sort(SWDefs.begin(), SWDefs.end(), LessRecord());
|
||||
@@ -224,6 +243,16 @@ void CodeGenSchedModels::collectSchedRW() {
|
||||
findRWs(WI->TheDef->getValueAsListOfDefs("Writes"), WI->Sequence,
|
||||
/*IsRead=*/false);
|
||||
}
|
||||
// Initialize Aliases vectors.
|
||||
for (RecIter AI = AliasDefs.begin(), AE = AliasDefs.end(); AI != AE; ++AI) {
|
||||
Record *AliasDef = (*AI)->getValueAsDef("AliasRW");
|
||||
getSchedRW(AliasDef).IsAlias = true;
|
||||
Record *MatchDef = (*AI)->getValueAsDef("MatchRW");
|
||||
CodeGenSchedRW &RW = getSchedRW(MatchDef);
|
||||
if (RW.IsAlias)
|
||||
throw TGError((*AI)->getLoc(), "Cannot Alias an Alias");
|
||||
RW.Aliases.push_back(*AI);
|
||||
}
|
||||
DEBUG(
|
||||
for (unsigned WIdx = 0, WEnd = SchedWrites.size(); WIdx != WEnd; ++WIdx) {
|
||||
dbgs() << WIdx << ": ";
|
||||
@@ -412,7 +441,7 @@ void CodeGenSchedModels::collectSchedClasses() {
|
||||
IdxVec ProcIndices(1, 0);
|
||||
addSchedClass(Writes, Reads, ProcIndices);
|
||||
}
|
||||
// Create classes for InstReadWrite defs.
|
||||
// Create classes for InstRW defs.
|
||||
RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW");
|
||||
std::sort(InstRWDefs.begin(), InstRWDefs.end(), LessRecord());
|
||||
for (RecIter OI = InstRWDefs.begin(), OE = InstRWDefs.end(); OI != OE; ++OI)
|
||||
@@ -766,6 +795,17 @@ void CodeGenSchedModels::inferFromInstRWs(unsigned SCIdx) {
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Helper for substituteVariantOperand.
|
||||
struct TransVariant {
|
||||
Record *VariantDef;
|
||||
unsigned RWIdx; // Index of this variant's matched type.
|
||||
unsigned ProcIdx; // Processor model index or zero for any.
|
||||
unsigned TransVecIdx; // Index into PredTransitions::TransVec.
|
||||
|
||||
TransVariant(Record *def, unsigned rwi, unsigned pi, unsigned ti):
|
||||
VariantDef(def), RWIdx(rwi), ProcIdx(pi), TransVecIdx(ti) {}
|
||||
};
|
||||
|
||||
// Associate a predicate with the SchedReadWrite that it guards.
|
||||
// RWIdx is the index of the read/write variant.
|
||||
struct PredCheck {
|
||||
@@ -782,6 +822,7 @@ struct PredTransition {
|
||||
SmallVector<PredCheck, 4> PredTerm;
|
||||
SmallVector<SmallVector<unsigned,4>, 16> WriteSequences;
|
||||
SmallVector<SmallVector<unsigned,4>, 16> ReadSequences;
|
||||
SmallVector<unsigned, 4> ProcIndices;
|
||||
};
|
||||
|
||||
// Encapsulate a set of partially constructed transitions.
|
||||
@@ -805,8 +846,7 @@ public:
|
||||
|
||||
private:
|
||||
bool mutuallyExclusive(Record *PredDef, ArrayRef<PredCheck> Term);
|
||||
void pushVariant(unsigned SchedRW, Record *Variant, PredTransition &Trans,
|
||||
bool IsRead);
|
||||
void pushVariant(const TransVariant &VInfo, bool IsRead);
|
||||
};
|
||||
} // anonymous
|
||||
|
||||
@@ -838,16 +878,26 @@ bool PredTransitions::mutuallyExclusive(Record *PredDef,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Push the Reads/Writes selected by this variant onto the given PredTransition.
|
||||
void PredTransitions::pushVariant(unsigned RWIdx, Record *Variant,
|
||||
PredTransition &Trans, bool IsRead) {
|
||||
Trans.PredTerm.push_back(
|
||||
PredCheck(IsRead, RWIdx, Variant->getValueAsDef("Predicate")));
|
||||
RecVec SelectedDefs = Variant->getValueAsListOfDefs("Selected");
|
||||
// Push the Reads/Writes selected by this variant onto the PredTransition
|
||||
// specified by VInfo.
|
||||
void PredTransitions::
|
||||
pushVariant(const TransVariant &VInfo, bool IsRead) {
|
||||
|
||||
PredTransition &Trans = TransVec[VInfo.TransVecIdx];
|
||||
|
||||
Record *PredDef = VInfo.VariantDef->getValueAsDef("Predicate");
|
||||
Trans.PredTerm.push_back(PredCheck(IsRead, VInfo.RWIdx,PredDef));
|
||||
|
||||
// If this operand transition is reached through a processor-specific alias,
|
||||
// then the whole transition is specific to this processor.
|
||||
if (VInfo.ProcIdx != 0)
|
||||
Trans.ProcIndices.assign(1, VInfo.ProcIdx);
|
||||
|
||||
RecVec SelectedDefs = VInfo.VariantDef->getValueAsListOfDefs("Selected");
|
||||
IdxVec SelectedRWs;
|
||||
SchedModels.findRWs(SelectedDefs, SelectedRWs, IsRead);
|
||||
|
||||
const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(RWIdx, IsRead);
|
||||
const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(VInfo.RWIdx, IsRead);
|
||||
|
||||
SmallVectorImpl<SmallVector<unsigned,4> > &RWSequences = IsRead
|
||||
? Trans.ReadSequences : Trans.WriteSequences;
|
||||
@@ -889,9 +939,48 @@ void PredTransitions::pushVariant(unsigned RWIdx, Record *Variant,
|
||||
}
|
||||
}
|
||||
|
||||
static bool hasAliasedVariants(const CodeGenSchedRW &RW,
|
||||
CodeGenSchedModels &SchedModels) {
|
||||
if (RW.HasVariants)
|
||||
return true;
|
||||
|
||||
for (RecIter I = RW.Aliases.begin(), E = RW.Aliases.end(); I != E; ++I) {
|
||||
if (SchedModels.getSchedRW((*I)->getValueAsDef("AliasRW")).HasVariants)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool hasVariant(ArrayRef<PredTransition> Transitions,
|
||||
CodeGenSchedModels &SchedModels) {
|
||||
for (ArrayRef<PredTransition>::iterator
|
||||
PTI = Transitions.begin(), PTE = Transitions.end();
|
||||
PTI != PTE; ++PTI) {
|
||||
for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator
|
||||
WSI = PTI->WriteSequences.begin(), WSE = PTI->WriteSequences.end();
|
||||
WSI != WSE; ++WSI) {
|
||||
for (SmallVectorImpl<unsigned>::const_iterator
|
||||
WI = WSI->begin(), WE = WSI->end(); WI != WE; ++WI) {
|
||||
if (hasAliasedVariants(SchedModels.getSchedWrite(*WI), SchedModels))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator
|
||||
RSI = PTI->ReadSequences.begin(), RSE = PTI->ReadSequences.end();
|
||||
RSI != RSE; ++RSI) {
|
||||
for (SmallVectorImpl<unsigned>::const_iterator
|
||||
RI = RSI->begin(), RE = RSI->end(); RI != RE; ++RI) {
|
||||
if (hasAliasedVariants(SchedModels.getSchedRead(*RI), SchedModels))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// RWSeq is a sequence of all Reads or all Writes for the next read or write
|
||||
// operand. StartIdx is an index into TransVec where partial results
|
||||
// starts. RWSeq must be applied to all tranistions between StartIdx and the end
|
||||
// starts. RWSeq must be applied to all transitions between StartIdx and the end
|
||||
// of TransVec.
|
||||
void PredTransitions::substituteVariantOperand(
|
||||
const SmallVectorImpl<unsigned> &RWSeq, bool IsRead, unsigned StartIdx) {
|
||||
@@ -906,7 +995,7 @@ void PredTransitions::substituteVariantOperand(
|
||||
for (unsigned TransIdx = StartIdx, TransEnd = TransVec.size();
|
||||
TransIdx != TransEnd; ++TransIdx) {
|
||||
// In the common case, push RW onto the current operand's sequence.
|
||||
if (!SchedRW.HasVariants) {
|
||||
if (!hasAliasedVariants(SchedRW, SchedModels)) {
|
||||
if (IsRead)
|
||||
TransVec[TransIdx].ReadSequences.back().push_back(*RWI);
|
||||
else
|
||||
@@ -914,28 +1003,74 @@ void PredTransitions::substituteVariantOperand(
|
||||
continue;
|
||||
}
|
||||
// Distribute this partial PredTransition across intersecting variants.
|
||||
RecVec Variants = SchedRW.TheDef->getValueAsListOfDefs("Variants");
|
||||
std::vector<std::pair<Record*,unsigned> > IntersectingVariants;
|
||||
for (RecIter VI = Variants.begin(), VE = Variants.end(); VI != VE; ++VI) {
|
||||
Record *PredDef = (*VI)->getValueAsDef("Predicate");
|
||||
RecVec Variants;
|
||||
if (SchedRW.HasVariants)
|
||||
Variants = SchedRW.TheDef->getValueAsListOfDefs("Variants");
|
||||
IdxVec VarRWIds(Variants.size(), *RWI);
|
||||
IdxVec VarProcModels(Variants.size(), 0);
|
||||
for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end();
|
||||
AI != AE; ++AI) {
|
||||
unsigned AIdx;
|
||||
const CodeGenSchedRW &AliasRW =
|
||||
SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW"), AIdx);
|
||||
if (!AliasRW.HasVariants)
|
||||
continue;
|
||||
|
||||
RecVec AliasVars = AliasRW.TheDef->getValueAsListOfDefs("Variants");
|
||||
Variants.insert(Variants.end(), AliasVars.begin(), AliasVars.end());
|
||||
|
||||
VarRWIds.resize(Variants.size(), AIdx);
|
||||
|
||||
Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
|
||||
VarProcModels.resize(Variants.size(),
|
||||
SchedModels.getProcModel(ModelDef).Index);
|
||||
}
|
||||
std::vector<TransVariant> IntersectingVariants;
|
||||
for (unsigned VIdx = 0, VEnd = Variants.size(); VIdx != VEnd; ++VIdx) {
|
||||
Record *PredDef = Variants[VIdx]->getValueAsDef("Predicate");
|
||||
|
||||
// Don't expand variants if the processor models don't intersect.
|
||||
// A zero processor index means any processor.
|
||||
SmallVector<unsigned, 4> &ProcIndices = TransVec[TransIdx].ProcIndices;
|
||||
if (ProcIndices[0] != 0 && VarProcModels[VIdx] != 0) {
|
||||
unsigned Cnt = std::count(ProcIndices.begin(), ProcIndices.end(),
|
||||
VarProcModels[VIdx]);
|
||||
if (!Cnt)
|
||||
continue;
|
||||
if (Cnt > 1) {
|
||||
const CodeGenProcModel &PM =
|
||||
*(SchedModels.procModelBegin() + VarProcModels[VIdx]);
|
||||
throw TGError(Variants[VIdx]->getLoc(), "Multiple variants defined "
|
||||
"for processor " + PM.ModelName +
|
||||
" Ensure only one SchedAlias exists per RW.");
|
||||
}
|
||||
}
|
||||
if (mutuallyExclusive(PredDef, TransVec[TransIdx].PredTerm))
|
||||
continue;
|
||||
if (IntersectingVariants.empty())
|
||||
if (IntersectingVariants.empty()) {
|
||||
// The first variant builds on the existing transition.
|
||||
IntersectingVariants.push_back(std::make_pair(*VI, TransIdx));
|
||||
IntersectingVariants.push_back(
|
||||
TransVariant(Variants[VIdx], VarRWIds[VIdx], VarProcModels[VIdx],
|
||||
TransIdx));
|
||||
}
|
||||
else {
|
||||
// Push another copy of the current transition for more variants.
|
||||
IntersectingVariants.push_back(
|
||||
std::make_pair(*VI, TransVec.size()));
|
||||
TransVariant(Variants[VIdx], VarRWIds[VIdx], VarProcModels[VIdx],
|
||||
TransVec.size()));
|
||||
TransVec.push_back(TransVec[TransIdx]);
|
||||
}
|
||||
}
|
||||
if (IntersectingVariants.empty())
|
||||
throw TGError(SchedRW.TheDef->getLoc(), "No variant of this type has a "
|
||||
"matching predicate on any processor ");
|
||||
// Now expand each variant on top of its copy of the transition.
|
||||
for (std::vector<std::pair<Record*, unsigned> >::const_iterator
|
||||
for (std::vector<TransVariant>::const_iterator
|
||||
IVI = IntersectingVariants.begin(),
|
||||
IVE = IntersectingVariants.end();
|
||||
IVI != IVE; ++IVI)
|
||||
pushVariant(*RWI, IVI->first, TransVec[IVI->second], IsRead);
|
||||
IVI != IVE; ++IVI) {
|
||||
pushVariant(*IVI, IsRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -952,6 +1087,7 @@ void PredTransitions::substituteVariants(const PredTransition &Trans) {
|
||||
unsigned StartIdx = TransVec.size();
|
||||
TransVec.resize(TransVec.size() + 1);
|
||||
TransVec.back().PredTerm = Trans.PredTerm;
|
||||
TransVec.back().ProcIndices = Trans.ProcIndices;
|
||||
|
||||
// Visit each original write sequence.
|
||||
for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator
|
||||
@@ -977,37 +1113,9 @@ void PredTransitions::substituteVariants(const PredTransition &Trans) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool hasVariant(ArrayRef<PredTransition> Transitions,
|
||||
CodeGenSchedModels &SchedModels) {
|
||||
for (ArrayRef<PredTransition>::iterator
|
||||
PTI = Transitions.begin(), PTE = Transitions.end();
|
||||
PTI != PTE; ++PTI) {
|
||||
for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator
|
||||
WSI = PTI->WriteSequences.begin(), WSE = PTI->WriteSequences.end();
|
||||
WSI != WSE; ++WSI) {
|
||||
for (SmallVectorImpl<unsigned>::const_iterator
|
||||
WI = WSI->begin(), WE = WSI->end(); WI != WE; ++WI) {
|
||||
if (SchedModels.getSchedWrite(*WI).HasVariants)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator
|
||||
RSI = PTI->ReadSequences.begin(), RSE = PTI->ReadSequences.end();
|
||||
RSI != RSE; ++RSI) {
|
||||
for (SmallVectorImpl<unsigned>::const_iterator
|
||||
RI = RSI->begin(), RE = RSI->end(); RI != RE; ++RI) {
|
||||
if (SchedModels.getSchedRead(*RI).HasVariants)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a new SchedClass for each variant found by inferFromRW. Pass
|
||||
// ProcIndices by copy to avoid referencing anything from SchedClasses.
|
||||
static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions,
|
||||
unsigned FromClassIdx, IdxVec ProcIndices,
|
||||
unsigned FromClassIdx,
|
||||
CodeGenSchedModels &SchedModels) {
|
||||
// For each PredTransition, create a new CodeGenSchedTransition, which usually
|
||||
// requires creating a new SchedClass.
|
||||
@@ -1025,10 +1133,11 @@ static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions,
|
||||
for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator
|
||||
RSI = I->ReadSequences.begin(), RSE = I->ReadSequences.end();
|
||||
RSI != RSE; ++RSI) {
|
||||
// Create a new write representing the expanded sequence.
|
||||
// Create a new read representing the expanded sequence.
|
||||
OperReadsVariant.push_back(
|
||||
SchedModels.findOrInsertRW(*RSI, /*IsRead=*/true));
|
||||
}
|
||||
IdxVec ProcIndices(I->ProcIndices.begin(), I->ProcIndices.end());
|
||||
CodeGenSchedTransition SCTrans;
|
||||
SCTrans.ToClassIdx =
|
||||
SchedModels.addSchedClass(OperWritesVariant, OperReadsVariant,
|
||||
@@ -1047,18 +1156,22 @@ static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions,
|
||||
}
|
||||
}
|
||||
|
||||
/// Find each variant write that OperWrites or OperaReads refers to and create a
|
||||
/// new SchedClass for each variant.
|
||||
// Create new SchedClasses for the given ReadWrite list. If any of the
|
||||
// ReadWrites refers to a SchedVariant, create a new SchedClass for each variant
|
||||
// of the ReadWrite list, following Aliases if necessary.
|
||||
void CodeGenSchedModels::inferFromRW(const IdxVec &OperWrites,
|
||||
const IdxVec &OperReads,
|
||||
unsigned FromClassIdx,
|
||||
const IdxVec &ProcIndices) {
|
||||
DEBUG(dbgs() << "INFERRW Writes: ");
|
||||
DEBUG(dbgs() << "INFER RW: ");
|
||||
|
||||
// Create a seed transition with an empty PredTerm and the expanded sequences
|
||||
// of SchedWrites for the current SchedClass.
|
||||
std::vector<PredTransition> LastTransitions;
|
||||
LastTransitions.resize(1);
|
||||
LastTransitions.back().ProcIndices.append(ProcIndices.begin(),
|
||||
ProcIndices.end());
|
||||
|
||||
for (IdxIter I = OperWrites.begin(), E = OperWrites.end(); I != E; ++I) {
|
||||
IdxVec WriteSeq;
|
||||
expandRWSequence(*I, WriteSeq, /*IsRead=*/false);
|
||||
@@ -1100,7 +1213,7 @@ void CodeGenSchedModels::inferFromRW(const IdxVec &OperWrites,
|
||||
|
||||
// WARNING: We are about to mutate the SchedClasses vector. Do not refer to
|
||||
// OperWrites, OperReads, or ProcIndices after calling inferFromTransitions.
|
||||
inferFromTransitions(LastTransitions, FromClassIdx, ProcIndices, *this);
|
||||
inferFromTransitions(LastTransitions, FromClassIdx, *this);
|
||||
}
|
||||
|
||||
// Collect and sort WriteRes, ReadAdvance, and ProcResources.
|
||||
@@ -1200,6 +1313,15 @@ void CodeGenSchedModels::collectRWResources(const IdxVec &Writes,
|
||||
addWriteRes(SchedRW.TheDef, *PI);
|
||||
}
|
||||
}
|
||||
for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end();
|
||||
AI != AE; ++AI) {
|
||||
const CodeGenSchedRW &AliasRW =
|
||||
getSchedRW((*AI)->getValueAsDef("AliasRW"));
|
||||
if (AliasRW.TheDef && AliasRW.TheDef->isSubClassOf("SchedWriteRes")) {
|
||||
Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
|
||||
addWriteRes(AliasRW.TheDef, getProcModel(ModelDef).Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI) {
|
||||
const CodeGenSchedRW &SchedRW = getSchedRW(*RI, /*IsRead=*/true);
|
||||
@@ -1209,6 +1331,15 @@ void CodeGenSchedModels::collectRWResources(const IdxVec &Writes,
|
||||
addReadAdvance(SchedRW.TheDef, *PI);
|
||||
}
|
||||
}
|
||||
for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end();
|
||||
AI != AE; ++AI) {
|
||||
const CodeGenSchedRW &AliasRW =
|
||||
getSchedRW((*AI)->getValueAsDef("AliasRW"));
|
||||
if (AliasRW.TheDef && AliasRW.TheDef->isSubClassOf("SchedReadAdvance")) {
|
||||
Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
|
||||
addReadAdvance(AliasRW.TheDef, getProcModel(ModelDef).Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1265,6 +1396,8 @@ void CodeGenSchedModels::addProcResource(Record *ProcResKind,
|
||||
|
||||
// Add resources for a SchedWrite to this processor if they don't exist.
|
||||
void CodeGenSchedModels::addWriteRes(Record *ProcWriteResDef, unsigned PIdx) {
|
||||
assert(PIdx && "don't add resources to an invalid Processor model");
|
||||
|
||||
RecVec &WRDefs = ProcModels[PIdx].WriteResDefs;
|
||||
RecIter WRI = std::find(WRDefs.begin(), WRDefs.end(), ProcWriteResDef);
|
||||
if (WRI != WRDefs.end())
|
||||
|
@@ -45,14 +45,16 @@ void splitSchedReadWrites(const RecVec &RWDefs,
|
||||
struct CodeGenSchedRW {
|
||||
std::string Name;
|
||||
Record *TheDef;
|
||||
bool IsAlias;
|
||||
bool HasVariants;
|
||||
bool IsVariadic;
|
||||
bool IsSequence;
|
||||
IdxVec Sequence;
|
||||
RecVec Aliases;
|
||||
|
||||
CodeGenSchedRW(): TheDef(0), HasVariants(false), IsVariadic(false),
|
||||
IsSequence(false) {}
|
||||
CodeGenSchedRW(Record *Def): TheDef(Def), IsVariadic(false) {
|
||||
CodeGenSchedRW(): TheDef(0), IsAlias(false), HasVariants(false),
|
||||
IsVariadic(false), IsSequence(false) {}
|
||||
CodeGenSchedRW(Record *Def): TheDef(Def), IsAlias(false), IsVariadic(false) {
|
||||
Name = Def->getName();
|
||||
HasVariants = Def->isSubClassOf("SchedVariant");
|
||||
if (HasVariants)
|
||||
@@ -65,8 +67,8 @@ struct CodeGenSchedRW {
|
||||
}
|
||||
|
||||
CodeGenSchedRW(const IdxVec &Seq, const std::string &Name):
|
||||
Name(Name), TheDef(0), HasVariants(false), IsVariadic(false),
|
||||
IsSequence(true), Sequence(Seq) {
|
||||
Name(Name), TheDef(0), IsAlias(false), HasVariants(false),
|
||||
IsVariadic(false), IsSequence(true), Sequence(Seq) {
|
||||
assert(Sequence.size() > 1 && "implied sequence needs >1 RWs");
|
||||
}
|
||||
|
||||
@@ -75,6 +77,7 @@ struct CodeGenSchedRW {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -125,8 +128,10 @@ struct CodeGenSchedClass {
|
||||
|
||||
std::vector<CodeGenSchedTransition> Transitions;
|
||||
|
||||
// InstReadWrite records associated with this class. Any Instrs that the
|
||||
// definitions refer to that are not mapped to this class should be ignored.
|
||||
// InstRW records associated with this class. These records may refer to an
|
||||
// Instruction no longer mapped to this class by InstrClassMap. These
|
||||
// Instructions should be ignored by this class because they have been split
|
||||
// off to join another inferred class.
|
||||
RecVec InstRWs;
|
||||
|
||||
CodeGenSchedClass(): ItinClassDef(0) {}
|
||||
@@ -229,7 +234,7 @@ class CodeGenSchedModels {
|
||||
unsigned NumInstrSchedClasses;
|
||||
|
||||
// Map Instruction to SchedClass index. Only for Instructions mentioned in
|
||||
// OpReadWrites.
|
||||
// InstRW records.
|
||||
typedef DenseMap<Record*, unsigned> InstClassMapTy;
|
||||
InstClassMapTy InstrClassMap;
|
||||
|
||||
@@ -281,6 +286,16 @@ public:
|
||||
const CodeGenSchedRW &getSchedRW(unsigned Idx, bool IsRead) const {
|
||||
return IsRead ? getSchedRead(Idx) : getSchedWrite(Idx);
|
||||
}
|
||||
CodeGenSchedRW &getSchedRW(Record *Def, unsigned &Idx) {
|
||||
bool IsRead = Def->isSubClassOf("SchedRead");
|
||||
Idx = getSchedRWIdx(Def, IsRead);
|
||||
return const_cast<CodeGenSchedRW&>(
|
||||
IsRead ? getSchedRead(Idx) : getSchedWrite(Idx));
|
||||
}
|
||||
CodeGenSchedRW &getSchedRW(Record *Def) {
|
||||
unsigned Idx;
|
||||
return getSchedRW(Def, Idx);
|
||||
}
|
||||
|
||||
unsigned getSchedRWIdx(Record *Def, bool IsRead, unsigned After = 0) const;
|
||||
|
||||
|
@@ -81,9 +81,10 @@ class SubtargetEmitter {
|
||||
char Separator);
|
||||
void EmitProcessorResources(const CodeGenProcModel &ProcModel,
|
||||
raw_ostream &OS);
|
||||
Record *FindWriteResources(Record *WriteDef,
|
||||
Record *FindWriteResources(const CodeGenSchedRW &SchedWrite,
|
||||
const CodeGenProcModel &ProcModel);
|
||||
Record *FindReadAdvance(Record *ReadDef, const CodeGenProcModel &ProcModel);
|
||||
Record *FindReadAdvance(const CodeGenSchedRW &SchedRead,
|
||||
const CodeGenProcModel &ProcModel);
|
||||
void GenSchedClassTables(const CodeGenProcModel &ProcModel,
|
||||
SchedClassTables &SchedTables);
|
||||
void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS);
|
||||
@@ -654,48 +655,107 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel,
|
||||
// Find the WriteRes Record that defines processor resources for this
|
||||
// SchedWrite.
|
||||
Record *SubtargetEmitter::FindWriteResources(
|
||||
Record *WriteDef, const CodeGenProcModel &ProcModel) {
|
||||
const CodeGenSchedRW &SchedWrite, const CodeGenProcModel &ProcModel) {
|
||||
|
||||
// Check if the SchedWrite is already subtarget-specific and directly
|
||||
// specifies a set of processor resources.
|
||||
if (WriteDef->isSubClassOf("SchedWriteRes"))
|
||||
return WriteDef;
|
||||
if (SchedWrite.TheDef->isSubClassOf("SchedWriteRes"))
|
||||
return SchedWrite.TheDef;
|
||||
|
||||
// Check this processor's list of aliases for SchedWrite.
|
||||
Record *AliasDef = 0;
|
||||
for (RecIter AI = SchedWrite.Aliases.begin(), AE = SchedWrite.Aliases.end();
|
||||
AI != AE; ++AI) {
|
||||
const CodeGenSchedRW &AliasRW =
|
||||
SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW"));
|
||||
Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
|
||||
if (&SchedModels.getProcModel(ModelDef) != &ProcModel)
|
||||
continue;
|
||||
if (AliasDef)
|
||||
throw TGError(AliasRW.TheDef->getLoc(), "Multiple aliases "
|
||||
"defined for processor " + ProcModel.ModelName +
|
||||
" Ensure only one SchedAlias exists per RW.");
|
||||
AliasDef = AliasRW.TheDef;
|
||||
}
|
||||
if (AliasDef && AliasDef->isSubClassOf("SchedWriteRes"))
|
||||
return AliasDef;
|
||||
|
||||
// Check this processor's list of write resources.
|
||||
Record *ResDef = 0;
|
||||
for (RecIter WRI = ProcModel.WriteResDefs.begin(),
|
||||
WRE = ProcModel.WriteResDefs.end(); WRI != WRE; ++WRI) {
|
||||
if (!(*WRI)->isSubClassOf("WriteRes"))
|
||||
continue;
|
||||
if (WriteDef == (*WRI)->getValueAsDef("WriteType"))
|
||||
return *WRI;
|
||||
if (AliasDef == (*WRI)->getValueAsDef("WriteType")
|
||||
|| SchedWrite.TheDef == (*WRI)->getValueAsDef("WriteType")) {
|
||||
if (ResDef) {
|
||||
throw TGError((*WRI)->getLoc(), "Resources are defined for both "
|
||||
"SchedWrite and its alias on processor " +
|
||||
ProcModel.ModelName);
|
||||
}
|
||||
ResDef = *WRI;
|
||||
}
|
||||
}
|
||||
throw TGError(ProcModel.ModelDef->getLoc(),
|
||||
std::string("Processor does not define resources for ")
|
||||
+ WriteDef->getName());
|
||||
// TODO: If ProcModel has a base model (previous generation processor),
|
||||
// then call FindWriteResources recursively with that model here.
|
||||
if (!ResDef) {
|
||||
throw TGError(ProcModel.ModelDef->getLoc(),
|
||||
std::string("Processor does not define resources for ")
|
||||
+ SchedWrite.TheDef->getName());
|
||||
}
|
||||
return ResDef;
|
||||
}
|
||||
|
||||
/// Find the ReadAdvance record for the given SchedRead on this processor or
|
||||
/// return NULL.
|
||||
Record *SubtargetEmitter::FindReadAdvance(Record *ReadDef,
|
||||
Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead,
|
||||
const CodeGenProcModel &ProcModel) {
|
||||
// Check for SchedReads that directly specify a ReadAdvance.
|
||||
if (ReadDef->isSubClassOf("SchedReadAdvance"))
|
||||
return ReadDef;
|
||||
if (SchedRead.TheDef->isSubClassOf("SchedReadAdvance"))
|
||||
return SchedRead.TheDef;
|
||||
|
||||
// Check this processor's list of aliases for SchedRead.
|
||||
Record *AliasDef = 0;
|
||||
for (RecIter AI = SchedRead.Aliases.begin(), AE = SchedRead.Aliases.end();
|
||||
AI != AE; ++AI) {
|
||||
const CodeGenSchedRW &AliasRW =
|
||||
SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW"));
|
||||
Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
|
||||
if (&SchedModels.getProcModel(ModelDef) != &ProcModel)
|
||||
continue;
|
||||
if (AliasDef)
|
||||
throw TGError(AliasRW.TheDef->getLoc(), "Multiple aliases "
|
||||
"defined for processor " + ProcModel.ModelName +
|
||||
" Ensure only one SchedAlias exists per RW.");
|
||||
AliasDef = AliasRW.TheDef;
|
||||
}
|
||||
if (AliasDef && AliasDef->isSubClassOf("SchedReadAdvance"))
|
||||
return AliasDef;
|
||||
|
||||
// Check this processor's ReadAdvanceList.
|
||||
Record *ResDef = 0;
|
||||
for (RecIter RAI = ProcModel.ReadAdvanceDefs.begin(),
|
||||
RAE = ProcModel.ReadAdvanceDefs.end(); RAI != RAE; ++RAI) {
|
||||
if (!(*RAI)->isSubClassOf("ReadAdvance"))
|
||||
continue;
|
||||
if (ReadDef == (*RAI)->getValueAsDef("ReadType"))
|
||||
return *RAI;
|
||||
if (AliasDef == (*RAI)->getValueAsDef("ReadType")
|
||||
|| SchedRead.TheDef == (*RAI)->getValueAsDef("ReadType")) {
|
||||
if (ResDef) {
|
||||
throw TGError((*RAI)->getLoc(), "Resources are defined for both "
|
||||
"SchedRead and its alias on processor " +
|
||||
ProcModel.ModelName);
|
||||
}
|
||||
ResDef = *RAI;
|
||||
}
|
||||
}
|
||||
if (ReadDef->getName() != "ReadDefault") {
|
||||
// TODO: If ProcModel has a base model (previous generation processor),
|
||||
// then call FindReadAdvance recursively with that model here.
|
||||
if (!ResDef && SchedRead.TheDef->getName() != "ReadDefault") {
|
||||
throw TGError(ProcModel.ModelDef->getLoc(),
|
||||
std::string("Processor does not define resources for ")
|
||||
+ ReadDef->getName());
|
||||
+ SchedRead.TheDef->getName());
|
||||
}
|
||||
return NULL;
|
||||
return ResDef;
|
||||
}
|
||||
|
||||
// Generate the SchedClass table for this processor and update global
|
||||
@@ -797,8 +857,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
|
||||
for (IdxIter WSI = WriteSeq.begin(), WSE = WriteSeq.end();
|
||||
WSI != WSE; ++WSI) {
|
||||
|
||||
Record *WriteDef = SchedModels.getSchedWrite(*WSI).TheDef;
|
||||
Record *WriteRes = FindWriteResources(WriteDef, ProcModel);
|
||||
Record *WriteRes =
|
||||
FindWriteResources(SchedModels.getSchedWrite(*WSI), ProcModel);
|
||||
|
||||
// Mark the parent class as invalid for unsupported write types.
|
||||
if (WriteRes->getValueAsBit("Unsupported")) {
|
||||
@@ -832,8 +892,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
|
||||
// Entries must be sorted first by UseIdx then by WriteResourceID.
|
||||
for (unsigned UseIdx = 0, EndIdx = Reads.size();
|
||||
UseIdx != EndIdx; ++UseIdx) {
|
||||
Record *ReadDef = SchedModels.getSchedRead(Reads[UseIdx]).TheDef;
|
||||
Record *ReadAdvance = FindReadAdvance(ReadDef, ProcModel);
|
||||
Record *ReadAdvance =
|
||||
FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel);
|
||||
if (!ReadAdvance)
|
||||
continue;
|
||||
|
||||
|
Reference in New Issue
Block a user