TableGen subtarget parser. Handle new machine model.

Infer SchedClasses from variants defined by the target or subtarget.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@163952 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Andrew Trick 2012-09-15 00:19:59 +00:00
parent 48605c3406
commit 5e613c260b
2 changed files with 512 additions and 0 deletions

View File

@ -27,6 +27,11 @@ static void dumpIdxVec(const IdxVec &V) {
dbgs() << V[i] << ", ";
}
}
static void dumpIdxVec(const SmallVectorImpl<unsigned> &V) {
for (unsigned i = 0, e = V.size(); i < e; ++i) {
dbgs() << V[i] << ", ";
}
}
#endif
/// CodeGenModels ctor interprets machine model records and populates maps.
@ -63,6 +68,12 @@ CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK,
// Find ItinRW records for each processor and itinerary class.
// (For per-operand resources mapped to itinerary classes).
collectProcItinRW();
// Infer new SchedClasses from SchedVariant.
inferSchedClasses();
DEBUG(for (unsigned i = 0; i < SchedClasses.size(); ++i)
SchedClasses[i].dump(this));
}
/// Gather all processor models.
@ -289,6 +300,57 @@ void CodeGenSchedModels::findRWs(const RecVec &RWDefs, IdxVec &RWs,
}
}
void CodeGenSchedModels::expandRWSequence(unsigned RWIdx, IdxVec &RWSeq,
bool IsRead) const {
const CodeGenSchedRW &SchedRW = getSchedRW(RWIdx, IsRead);
if (!SchedRW.IsSequence) {
RWSeq.push_back(RWIdx);
return;
}
int Repeat =
SchedRW.TheDef ? SchedRW.TheDef->getValueAsInt("Repeat") : 1;
for (int i = 0; i < Repeat; ++i) {
for (IdxIter I = SchedRW.Sequence.begin(), E = SchedRW.Sequence.end();
I != E; ++I) {
expandRWSequence(*I, RWSeq, IsRead);
}
}
}
// Find the existing SchedWrite that models this sequence of writes.
unsigned CodeGenSchedModels::findRWForSequence(const IdxVec &Seq,
bool IsRead) {
std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites;
for (std::vector<CodeGenSchedRW>::iterator I = RWVec.begin(), E = RWVec.end();
I != E; ++I) {
if (I->Sequence == Seq)
return I - RWVec.begin();
}
// Index zero reserved for invalid RW.
return 0;
}
/// Add this ReadWrite if it doesn't already exist.
unsigned CodeGenSchedModels::findOrInsertRW(ArrayRef<unsigned> Seq,
bool IsRead) {
assert(!Seq.empty() && "cannot insert empty sequence");
if (Seq.size() == 1)
return Seq.back();
unsigned Idx = findRWForSequence(Seq, IsRead);
if (Idx)
return Idx;
CodeGenSchedRW SchedRW(Seq, genRWName(Seq, IsRead));
if (IsRead) {
SchedReads.push_back(SchedRW);
return SchedReads.size() - 1;
}
SchedWrites.push_back(SchedRW);
return SchedWrites.size() - 1;
}
/// Visit all the instruction definitions for this target to gather and
/// enumerate the itinerary classes. These are the explicitly specified
/// SchedClasses. More SchedClasses may be inferred.
@ -619,6 +681,409 @@ void CodeGenSchedModels::collectProcItinRW() {
}
}
/// Infer new classes from existing classes. In the process, this may create new
/// SchedWrites from sequences of existing SchedWrites.
void CodeGenSchedModels::inferSchedClasses() {
// Visit all existing classes and newly created classes.
for (unsigned Idx = 0; Idx != SchedClasses.size(); ++Idx) {
if (SchedClasses[Idx].ItinClassDef)
inferFromItinClass(SchedClasses[Idx].ItinClassDef, Idx);
else if (!SchedClasses[Idx].InstRWs.empty())
inferFromInstRWs(Idx);
else {
inferFromRW(SchedClasses[Idx].Writes, SchedClasses[Idx].Reads,
Idx, SchedClasses[Idx].ProcIndices);
}
assert(SchedClasses.size() < (NumInstrSchedClasses*6) &&
"too many SchedVariants");
}
}
/// Infer classes from per-processor itinerary resources.
void CodeGenSchedModels::inferFromItinClass(Record *ItinClassDef,
unsigned FromClassIdx) {
for (unsigned PIdx = 0, PEnd = ProcModels.size(); PIdx != PEnd; ++PIdx) {
const CodeGenProcModel &PM = ProcModels[PIdx];
// For all ItinRW entries.
bool HasMatch = false;
for (RecIter II = PM.ItinRWDefs.begin(), IE = PM.ItinRWDefs.end();
II != IE; ++II) {
RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses");
if (!std::count(Matched.begin(), Matched.end(), ItinClassDef))
continue;
if (HasMatch)
throw TGError((*II)->getLoc(), "Duplicate itinerary class "
+ ItinClassDef->getName()
+ " in ItinResources for " + PM.ModelName);
HasMatch = true;
IdxVec Writes, Reads;
findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads);
IdxVec ProcIndices(1, PIdx);
inferFromRW(Writes, Reads, FromClassIdx, ProcIndices);
}
}
}
/// Infer classes from per-processor InstReadWrite definitions.
void CodeGenSchedModels::inferFromInstRWs(unsigned SCIdx) {
const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs;
for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); RWI != RWE; ++RWI) {
RecVec Instrs = (*RWI)->getValueAsListOfDefs("Instrs");
RecIter II = Instrs.begin(), IE = Instrs.end();
for (; II != IE; ++II) {
if (InstrClassMap[*II] == SCIdx)
break;
}
// If this class no longer has any instructions mapped to it, it has become
// irrelevant.
if (II == IE)
continue;
IdxVec Writes, Reads;
findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads);
unsigned PIdx = getProcModel((*RWI)->getValueAsDef("SchedModel")).Index;
IdxVec ProcIndices(1, PIdx);
inferFromRW(Writes, Reads, SCIdx, ProcIndices);
}
}
namespace {
// Associate a predicate with the SchedReadWrite that it guards.
// RWIdx is the index of the read/write variant.
struct PredCheck {
bool IsRead;
unsigned RWIdx;
Record *Predicate;
PredCheck(bool r, unsigned w, Record *p): IsRead(r), RWIdx(w), Predicate(p) {}
};
// A Predicate transition is a list of RW sequences guarded by a PredTerm.
struct PredTransition {
// A predicate term is a conjunction of PredChecks.
SmallVector<PredCheck, 4> PredTerm;
SmallVector<SmallVector<unsigned,4>, 16> WriteSequences;
SmallVector<SmallVector<unsigned,4>, 16> ReadSequences;
};
// Encapsulate a set of partially constructed transitions.
// The results are built by repeated calls to substituteVariants.
class PredTransitions {
CodeGenSchedModels &SchedModels;
public:
std::vector<PredTransition> TransVec;
PredTransitions(CodeGenSchedModels &sm): SchedModels(sm) {}
void substituteVariantOperand(const SmallVectorImpl<unsigned> &RWSeq,
bool IsRead, unsigned StartIdx);
void substituteVariants(const PredTransition &Trans);
#ifndef NDEBUG
void dump() const;
#endif
private:
bool mutuallyExclusive(Record *PredDef, ArrayRef<PredCheck> Term);
void pushVariant(unsigned SchedRW, Record *Variant, PredTransition &Trans,
bool IsRead);
};
} // anonymous
// Return true if this predicate is mutually exclusive with a PredTerm. This
// degenerates into checking if the predicate is mutually exclusive with any
// predicate in the Term's conjunction.
//
// All predicates associated with a given SchedRW are considered mutually
// exclusive. This should work even if the conditions expressed by the
// predicates are not exclusive because the predicates for a given SchedWrite
// are always checked in the order they are defined in the .td file. Later
// conditions implicitly negate any prior condition.
bool PredTransitions::mutuallyExclusive(Record *PredDef,
ArrayRef<PredCheck> Term) {
for (ArrayRef<PredCheck>::iterator I = Term.begin(), E = Term.end();
I != E; ++I) {
if (I->Predicate == PredDef)
return false;
const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(I->RWIdx, I->IsRead);
assert(SchedRW.HasVariants && "PredCheck must refer to a SchedVariant");
RecVec Variants = SchedRW.TheDef->getValueAsListOfDefs("Variants");
for (RecIter VI = Variants.begin(), VE = Variants.end(); VI != VE; ++VI) {
if ((*VI)->getValueAsDef("Predicate") == PredDef)
return true;
}
}
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");
IdxVec SelectedRWs;
SchedModels.findRWs(SelectedDefs, SelectedRWs, IsRead);
const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(RWIdx, IsRead);
SmallVectorImpl<SmallVector<unsigned,4> > &RWSequences = IsRead
? Trans.ReadSequences : Trans.WriteSequences;
if (SchedRW.IsVariadic) {
unsigned OperIdx = RWSequences.size()-1;
// Make N-1 copies of this transition's last sequence.
for (unsigned i = 1, e = SelectedRWs.size(); i != e; ++i) {
RWSequences.push_back(RWSequences[OperIdx]);
}
// Push each of the N elements of the SelectedRWs onto a copy of the last
// sequence (split the current operand into N operands).
// Note that write sequences should be expanded within this loop--the entire
// sequence belongs to a single operand.
for (IdxIter RWI = SelectedRWs.begin(), RWE = SelectedRWs.end();
RWI != RWE; ++RWI, ++OperIdx) {
IdxVec ExpandedRWs;
if (IsRead)
ExpandedRWs.push_back(*RWI);
else
SchedModels.expandRWSequence(*RWI, ExpandedRWs, IsRead);
RWSequences[OperIdx].insert(RWSequences[OperIdx].end(),
ExpandedRWs.begin(), ExpandedRWs.end());
}
assert(OperIdx == RWSequences.size() && "missed a sequence");
}
else {
// Push this transition's expanded sequence onto this transition's last
// sequence (add to the current operand's sequence).
SmallVectorImpl<unsigned> &Seq = RWSequences.back();
IdxVec ExpandedRWs;
for (IdxIter RWI = SelectedRWs.begin(), RWE = SelectedRWs.end();
RWI != RWE; ++RWI) {
if (IsRead)
ExpandedRWs.push_back(*RWI);
else
SchedModels.expandRWSequence(*RWI, ExpandedRWs, IsRead);
}
Seq.insert(Seq.end(), ExpandedRWs.begin(), ExpandedRWs.end());
}
}
// 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
// of TransVec.
void PredTransitions::substituteVariantOperand(
const SmallVectorImpl<unsigned> &RWSeq, bool IsRead, unsigned StartIdx) {
// Visit each original RW within the current sequence.
for (SmallVectorImpl<unsigned>::const_iterator
RWI = RWSeq.begin(), RWE = RWSeq.end(); RWI != RWE; ++RWI) {
const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(*RWI, IsRead);
// Push this RW on all partial PredTransitions or distribute variants.
// New PredTransitions may be pushed within this loop which should not be
// revisited (TransEnd must be loop invariant).
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 (IsRead)
TransVec[TransIdx].ReadSequences.back().push_back(*RWI);
else
TransVec[TransIdx].WriteSequences.back().push_back(*RWI);
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");
if (mutuallyExclusive(PredDef, TransVec[TransIdx].PredTerm))
continue;
if (IntersectingVariants.empty())
// The first variant builds on the existing transition.
IntersectingVariants.push_back(std::make_pair(*VI, TransIdx));
else {
// Push another copy of the current transition for more variants.
IntersectingVariants.push_back(
std::make_pair(*VI, TransVec.size()));
TransVec.push_back(TransVec[TransIdx]);
}
}
// Now expand each variant on top of its copy of the transition.
for (std::vector<std::pair<Record*, unsigned> >::const_iterator
IVI = IntersectingVariants.begin(),
IVE = IntersectingVariants.end();
IVI != IVE; ++IVI)
pushVariant(*RWI, IVI->first, TransVec[IVI->second], IsRead);
}
}
}
// For each variant of a Read/Write in Trans, substitute the sequence of
// Read/Writes guarded by the variant. This is exponential in the number of
// variant Read/Writes, but in practice detection of mutually exclusive
// predicates should result in linear growth in the total number variants.
//
// This is one step in a breadth-first search of nested variants.
void PredTransitions::substituteVariants(const PredTransition &Trans) {
// Build up a set of partial results starting at the back of
// PredTransitions. Remember the first new transition.
unsigned StartIdx = TransVec.size();
TransVec.resize(TransVec.size() + 1);
TransVec.back().PredTerm = Trans.PredTerm;
// Visit each original write sequence.
for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator
WSI = Trans.WriteSequences.begin(), WSE = Trans.WriteSequences.end();
WSI != WSE; ++WSI) {
// Push a new (empty) write sequence onto all partial Transitions.
for (std::vector<PredTransition>::iterator I =
TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) {
I->WriteSequences.resize(I->WriteSequences.size() + 1);
}
substituteVariantOperand(*WSI, /*IsRead=*/false, StartIdx);
}
// Visit each original read sequence.
for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator
RSI = Trans.ReadSequences.begin(), RSE = Trans.ReadSequences.end();
RSI != RSE; ++RSI) {
// Push a new (empty) read sequence onto all partial Transitions.
for (std::vector<PredTransition>::iterator I =
TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) {
I->ReadSequences.resize(I->ReadSequences.size() + 1);
}
substituteVariantOperand(*RSI, /*IsRead=*/true, StartIdx);
}
}
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,
CodeGenSchedModels &SchedModels) {
// For each PredTransition, create a new CodeGenSchedTransition, which usually
// requires creating a new SchedClass.
for (ArrayRef<PredTransition>::iterator
I = LastTransitions.begin(), E = LastTransitions.end(); I != E; ++I) {
IdxVec OperWritesVariant;
for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator
WSI = I->WriteSequences.begin(), WSE = I->WriteSequences.end();
WSI != WSE; ++WSI) {
// Create a new write representing the expanded sequence.
OperWritesVariant.push_back(
SchedModels.findOrInsertRW(*WSI, /*IsRead=*/false));
}
IdxVec OperReadsVariant;
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.
OperReadsVariant.push_back(
SchedModels.findOrInsertRW(*RSI, /*IsRead=*/true));
}
CodeGenSchedTransition SCTrans;
SCTrans.ToClassIdx =
SchedModels.addSchedClass(OperWritesVariant, OperReadsVariant,
ProcIndices);
SCTrans.ProcIndices = ProcIndices;
// The final PredTerm is unique set of predicates guarding the transition.
RecVec Preds;
for (SmallVectorImpl<PredCheck>::const_iterator
PI = I->PredTerm.begin(), PE = I->PredTerm.end(); PI != PE; ++PI) {
Preds.push_back(PI->Predicate);
}
RecIter PredsEnd = std::unique(Preds.begin(), Preds.end());
Preds.resize(PredsEnd - Preds.begin());
SCTrans.PredTerm = Preds;
SchedModels.getSchedClass(FromClassIdx).Transitions.push_back(SCTrans);
}
}
/// Find each variant write that OperWrites or OperaReads refers to and create a
/// new SchedClass for each variant.
void CodeGenSchedModels::inferFromRW(const IdxVec &OperWrites,
const IdxVec &OperReads,
unsigned FromClassIdx,
const IdxVec &ProcIndices) {
DEBUG(dbgs() << "INFERRW Writes: ");
// 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);
for (IdxIter I = OperWrites.begin(), E = OperWrites.end(); I != E; ++I) {
IdxVec WriteSeq;
expandRWSequence(*I, WriteSeq, /*IsRead=*/false);
unsigned Idx = LastTransitions[0].WriteSequences.size();
LastTransitions[0].WriteSequences.resize(Idx + 1);
SmallVectorImpl<unsigned> &Seq = LastTransitions[0].WriteSequences[Idx];
for (IdxIter WI = WriteSeq.begin(), WE = WriteSeq.end(); WI != WE; ++WI)
Seq.push_back(*WI);
DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") ");
}
DEBUG(dbgs() << " Reads: ");
for (IdxIter I = OperReads.begin(), E = OperReads.end(); I != E; ++I) {
IdxVec ReadSeq;
expandRWSequence(*I, ReadSeq, /*IsRead=*/true);
unsigned Idx = LastTransitions[0].ReadSequences.size();
LastTransitions[0].ReadSequences.resize(Idx + 1);
SmallVectorImpl<unsigned> &Seq = LastTransitions[0].ReadSequences[Idx];
for (IdxIter RI = ReadSeq.begin(), RE = ReadSeq.end(); RI != RE; ++RI)
Seq.push_back(*RI);
DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") ");
}
DEBUG(dbgs() << '\n');
// Collect all PredTransitions for individual operands.
// Iterate until no variant writes remain.
while (hasVariant(LastTransitions, *this)) {
PredTransitions Transitions(*this);
for (std::vector<PredTransition>::const_iterator
I = LastTransitions.begin(), E = LastTransitions.end();
I != E; ++I) {
Transitions.substituteVariants(*I);
}
DEBUG(Transitions.dump());
LastTransitions.swap(Transitions.TransVec);
}
// If the first transition has no variants, nothing to do.
if (LastTransitions[0].PredTerm.empty())
return;
// 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);
}
#ifndef NDEBUG
void CodeGenProcModel::dump() const {
dbgs() << Index << ": " << ModelName << " "
@ -655,4 +1120,34 @@ void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const {
}
dbgs() << "\n ProcIdx: "; dumpIdxVec(ProcIndices); dbgs() << '\n';
}
void PredTransitions::dump() const {
dbgs() << "Expanded Variants:\n";
for (std::vector<PredTransition>::const_iterator
TI = TransVec.begin(), TE = TransVec.end(); TI != TE; ++TI) {
dbgs() << "{";
for (SmallVectorImpl<PredCheck>::const_iterator
PCI = TI->PredTerm.begin(), PCE = TI->PredTerm.end();
PCI != PCE; ++PCI) {
if (PCI != TI->PredTerm.begin())
dbgs() << ", ";
dbgs() << SchedModels.getSchedRW(PCI->RWIdx, PCI->IsRead).Name
<< ":" << PCI->Predicate->getName();
}
dbgs() << "},\n => {";
for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator
WSI = TI->WriteSequences.begin(), WSE = TI->WriteSequences.end();
WSI != WSE; ++WSI) {
dbgs() << "(";
for (SmallVectorImpl<unsigned>::const_iterator
WI = WSI->begin(), WE = WSI->end(); WI != WE; ++WI) {
if (WI != WSI->begin())
dbgs() << ", ";
dbgs() << SchedModels.getSchedWrite(*WI).Name;
}
dbgs() << "),";
}
dbgs() << "}\n";
}
}
#endif // NDEBUG

View File

@ -83,6 +83,13 @@ struct CodeGenSchedRW {
#endif
};
/// Represent a transition between SchedClasses induced by SchedWriteVariant.
struct CodeGenSchedTransition {
unsigned ToClassIdx;
IdxVec ProcIndices;
RecVec PredTerm;
};
/// Scheduling class.
///
/// Each instruction description will be mapped to a scheduling class. There are
@ -116,6 +123,8 @@ struct CodeGenSchedClass {
// Sorted list of ProcIdx, where ProcIdx==0 implies any processor.
IdxVec ProcIndices;
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.
RecVec InstRWs;
@ -308,6 +317,7 @@ public:
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;
unsigned addSchedClass(const IdxVec &OperWrites, const IdxVec &OperReads,
const IdxVec &ProcIndices);
@ -337,6 +347,13 @@ private:
void collectProcItins();
void collectProcItinRW();
void inferSchedClasses();
void inferFromRW(const IdxVec &OperWrites, const IdxVec &OperReads,
unsigned FromClassIdx, const IdxVec &ProcIndices);
void inferFromItinClass(Record *ItinClassDef, unsigned FromClassIdx);
void inferFromInstRWs(unsigned SCIdx);
};
} // namespace llvm