diff --git a/include/llvm/Target/TargetSchedule.td b/include/llvm/Target/TargetSchedule.td index cf3d2505906..0da82fdd897 100644 --- a/include/llvm/Target/TargetSchedule.td +++ b/include/llvm/Target/TargetSchedule.td @@ -55,6 +55,15 @@ include "llvm/Target/TargetItinerary.td" class Instruction; // Forward def +// DAG operator that interprets the DAG args as Instruction defs. +def instrs; + +// DAG operator that interprets each DAG arg as a regex pattern for +// matching Instruction opcode names. +// The regex must match the beginning of the opcode (as in Python re.match). +// To avoid matching prefixes, append '$' to the pattern. +def instregex; + // Define the SchedMachineModel and provide basic properties for // coarse grained instruction cost model. Default values for the // properties are defined in MCSchedModel. A value of "-1" in the @@ -325,9 +334,9 @@ class SchedReadVariant variants> : SchedRead, // the subtarget to easily override specific operations. // // SchedModel ties this opcode mapping to a processor. -class InstRW rw, list instrs> { +class InstRW rw, dag instrlist> { list OperandReadWrites = rw; - list Instrs = instrs; + dag Instrs = instrlist; SchedMachineModel SchedModel = ?; } diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp index 90bc5b4e156..b9b1c293f04 100644 --- a/utils/TableGen/CodeGenSchedule.cpp +++ b/utils/TableGen/CodeGenSchedule.cpp @@ -18,6 +18,8 @@ #include "CodeGenTarget.h" #include "llvm/TableGen/Error.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Regex.h" +#include "llvm/ADT/STLExtras.h" using namespace llvm; @@ -34,11 +36,64 @@ static void dumpIdxVec(const SmallVectorImpl &V) { } #endif +// (instrs a, b, ...) Evaluate and union all arguments. Identical to AddOp. +struct InstrsOp : public SetTheory::Operator { + void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts) { + ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts); + } +}; + +// (instregex "OpcPat",...) Find all instructions matching an opcode pattern. +// +// TODO: Since this is a prefix match, perform a binary search over the +// instruction names using lower_bound. Note that the predefined instrs must be +// scanned linearly first. However, this is only safe if the regex pattern has +// no top-level bars. The DAG already has a list of patterns, so there's no +// reason to use top-level bars, but we need a way to verify they don't exist +// before implementing the optimization. +struct InstRegexOp : public SetTheory::Operator { + const CodeGenTarget &Target; + InstRegexOp(const CodeGenTarget &t): Target(t) {} + + void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts) { + SmallVector RegexList; + for (DagInit::const_arg_iterator + AI = Expr->arg_begin(), AE = Expr->arg_end(); AI != AE; ++AI) { + StringInit *SI = dynamic_cast(*AI); + if (!SI) + throw "instregex requires pattern string: " + Expr->getAsString(); + std::string pat = SI->getValue(); + // Implement a python-style prefix match. + if (pat[0] != '^') { + pat.insert(0, "^("); + pat.insert(pat.end(), ')'); + } + RegexList.push_back(new Regex(pat)); + } + for (CodeGenTarget::inst_iterator I = Target.inst_begin(), + E = Target.inst_end(); I != E; ++I) { + for (SmallVectorImpl::iterator + RI = RegexList.begin(), RE = RegexList.end(); RI != RE; ++RI) { + if ((*RI)->match((*I)->TheDef->getName())) + Elts.insert((*I)->TheDef); + } + } + DeleteContainerPointers(RegexList); + } +}; + /// CodeGenModels ctor interprets machine model records and populates maps. CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, const CodeGenTarget &TGT): Records(RK), Target(TGT), NumItineraryClasses(0) { + Sets.addFieldExpander("InstRW", "Instrs"); + + // Allow Set evaluation to recognize the dags used in InstRW records: + // (instrs Op1, Op1...) + Sets.addOperator("instrs", new InstrsOp); + Sets.addOperator("instregex", new InstRegexOp(Target)); + // Instantiate a CodeGenProcModel for each SchedMachineModel with the values // that are explicitly referenced in tablegen records. Resources associated // with each processor will be derived later. Populate ProcModelMap with the @@ -646,9 +701,11 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { // determined from ItinDef or SchedRW. SmallVector >, 4> ClassInstrs; // Sort Instrs into sets. - RecVec InstDefs = InstRWDef->getValueAsListOfDefs("Instrs"); - std::sort(InstDefs.begin(), InstDefs.end(), LessRecord()); - for (RecIter I = InstDefs.begin(), E = InstDefs.end(); I != E; ++I) { + const RecVec *InstDefs = Sets.expand(InstRWDef); + if (InstDefs->empty()) + throw TGError(InstRWDef->getLoc(), "No matching instruction opcodes"); + + for (RecIter I = InstDefs->begin(), E = InstDefs->end(); I != E; ++I) { unsigned SCIdx = 0; InstClassMapTy::const_iterator Pos = InstrClassMap.find(*I); if (Pos != InstrClassMap.end()) @@ -697,13 +754,22 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { SC.ProcIndices.push_back(0); // Map each Instr to this new class. // Note that InstDefs may be a smaller list than InstRWDef's "Instrs". + Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel"); + SmallSet RemappedClassIDs; for (ArrayRef::const_iterator II = InstDefs.begin(), IE = InstDefs.end(); II != IE; ++II) { unsigned OldSCIdx = InstrClassMap[*II]; - if (OldSCIdx) { - SC.InstRWs.insert(SC.InstRWs.end(), - SchedClasses[OldSCIdx].InstRWs.begin(), - SchedClasses[OldSCIdx].InstRWs.end()); + if (OldSCIdx && RemappedClassIDs.insert(OldSCIdx)) { + for (RecIter RI = SchedClasses[OldSCIdx].InstRWs.begin(), + RE = SchedClasses[OldSCIdx].InstRWs.end(); RI != RE; ++RI) { + if ((*RI)->getValueAsDef("SchedModel") == RWModelDef) { + throw TGError(InstRWDef->getLoc(), "Overlapping InstRW def " + + (*II)->getName() + " also matches " + + (*RI)->getValue("Instrs")->getValue()->getAsString()); + } + assert(*RI != InstRWDef && "SchedClass has duplicate InstRW def"); + SC.InstRWs.push_back(*RI); + } } InstrClassMap[*II] = SCIdx; } @@ -814,8 +880,8 @@ void CodeGenSchedModels::inferFromItinClass(Record *ItinClassDef, 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(); + const RecVec *InstDefs = Sets.expand(*RWI); + RecIter II = InstDefs->begin(), IE = InstDefs->end(); for (; II != IE; ++II) { if (InstrClassMap[*II] == SCIdx) break; diff --git a/utils/TableGen/CodeGenSchedule.h b/utils/TableGen/CodeGenSchedule.h index 211c05c8c64..cc3a10223b3 100644 --- a/utils/TableGen/CodeGenSchedule.h +++ b/utils/TableGen/CodeGenSchedule.h @@ -15,6 +15,7 @@ #ifndef CODEGEN_SCHEDULE_H #define CODEGEN_SCHEDULE_H +#include "SetTheory.h" #include "llvm/TableGen/Record.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/ADT/DenseMap.h" @@ -208,6 +209,9 @@ class CodeGenSchedModels { RecordKeeper &Records; const CodeGenTarget &Target; + // Map dag expressions to Instruction lists. + SetTheory Sets; + // List of unique processor models. std::vector ProcModels; diff --git a/utils/TableGen/SetTheory.cpp b/utils/TableGen/SetTheory.cpp index 46e6db173ea..bdca9a63bd2 100644 --- a/utils/TableGen/SetTheory.cpp +++ b/utils/TableGen/SetTheory.cpp @@ -294,7 +294,10 @@ const RecVec *SetTheory::expand(Record *Set) { // This is the first time we see Set. Find a suitable expander. try { const std::vector &SC = Set->getSuperClasses(); - for (unsigned i = 0, e = SC.size(); i != e; ++i) + for (unsigned i = 0, e = SC.size(); i != e; ++i) { + // Skip unnamed superclasses. + if (!dynamic_cast(SC[i]->getNameInit())) + continue; if (Expander *Exp = Expanders.lookup(SC[i]->getName())) { // This breaks recursive definitions. RecVec &EltVec = Expansions[Set]; @@ -303,6 +306,7 @@ const RecVec *SetTheory::expand(Record *Set) { EltVec.assign(Elts.begin(), Elts.end()); return &EltVec; } + } } catch (const std::string &Error) { throw TGError(Set->getLoc(), Error); }