diff options
Diffstat (limited to 'utils')
-rw-r--r-- | utils/FileCheck/FileCheck.cpp | 12 | ||||
-rw-r--r-- | utils/TableGen/CMakeLists.txt | 1 | ||||
-rw-r--r-- | utils/TableGen/CTagsEmitter.cpp | 99 | ||||
-rw-r--r-- | utils/TableGen/CodeGenDAGPatterns.cpp | 213 | ||||
-rw-r--r-- | utils/TableGen/CodeGenDAGPatterns.h | 8 | ||||
-rw-r--r-- | utils/TableGen/CodeGenRegisters.h | 4 | ||||
-rw-r--r-- | utils/TableGen/CodeGenSchedule.cpp | 280 | ||||
-rw-r--r-- | utils/TableGen/CodeGenSchedule.h | 67 | ||||
-rw-r--r-- | utils/TableGen/CodeGenTarget.cpp | 2 | ||||
-rw-r--r-- | utils/TableGen/CodeGenTarget.h | 6 | ||||
-rw-r--r-- | utils/TableGen/DAGISelMatcherGen.cpp | 53 | ||||
-rw-r--r-- | utils/TableGen/RegisterInfoEmitter.cpp | 2 | ||||
-rw-r--r-- | utils/TableGen/SubtargetEmitter.cpp | 184 | ||||
-rw-r--r-- | utils/TableGen/TableGen.cpp | 8 | ||||
-rw-r--r-- | utils/TableGen/TableGenBackends.h | 1 | ||||
-rw-r--r-- | utils/TableGen/X86RecognizableInstr.cpp | 17 | ||||
-rw-r--r-- | utils/TableGen/tdtags | 453 | ||||
-rw-r--r-- | utils/lit/lit/TestFormats.py | 3 | ||||
-rw-r--r-- | utils/lit/lit/TestRunner.py | 5 |
19 files changed, 1089 insertions, 329 deletions
diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index 563cab0d5d..b0ef67ac88 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -639,11 +639,11 @@ static bool ReadCheckFile(SourceMgr &SM, << ec.message() << '\n'; return true; } - MemoryBuffer *F = File.take(); // If we want to canonicalize whitespace, strip excess whitespace from the // buffer containing the CHECK lines. Remove DOS style line endings. - F = CanonicalizeInputFile(F, NoCanonicalizeWhiteSpace); + MemoryBuffer *F = + CanonicalizeInputFile(File.take(), NoCanonicalizeWhiteSpace); SM.AddNewSourceBuffer(F, SMLoc()); @@ -803,16 +803,16 @@ int main(int argc, char **argv) { << ec.message() << '\n'; return 2; } - MemoryBuffer *F = File.take(); - if (F->getBufferSize() == 0) { + if (File->getBufferSize() == 0) { errs() << "FileCheck error: '" << InputFilename << "' is empty.\n"; return 2; } - + // Remove duplicate spaces in the input file if requested. // Remove DOS style line endings. - F = CanonicalizeInputFile(F, NoCanonicalizeWhiteSpace); + MemoryBuffer *F = + CanonicalizeInputFile(File.take(), NoCanonicalizeWhiteSpace); SM.AddNewSourceBuffer(F, SMLoc()); diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt index d0f44be69a..3ee1974431 100644 --- a/utils/TableGen/CMakeLists.txt +++ b/utils/TableGen/CMakeLists.txt @@ -33,4 +33,5 @@ add_tablegen(llvm-tblgen LLVM X86DisassemblerTables.cpp X86ModRMFilters.cpp X86RecognizableInstr.cpp + CTagsEmitter.cpp ) diff --git a/utils/TableGen/CTagsEmitter.cpp b/utils/TableGen/CTagsEmitter.cpp new file mode 100644 index 0000000000..8bf777839b --- /dev/null +++ b/utils/TableGen/CTagsEmitter.cpp @@ -0,0 +1,99 @@ +//===- CTagsEmitter.cpp - Generate ctags-compatible index ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits an index of definitions in ctags(1) format. +// A helper script, utils/TableGen/tdtags, provides an easier-to-use +// interface; run 'tdtags -H' for documentation. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "ctags-emitter" + +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <algorithm> +#include <string> +#include <vector> +using namespace llvm; + +namespace llvm { extern SourceMgr SrcMgr; } + +namespace { + +class Tag { +private: + const std::string *Id; + SMLoc Loc; +public: + Tag(const std::string &Name, const SMLoc Location) + : Id(&Name), Loc(Location) {} + int operator<(const Tag &B) const { return *Id < *B.Id; } + void emit(raw_ostream &OS) const { + int BufferID = SrcMgr.FindBufferContainingLoc(Loc); + MemoryBuffer *CurMB = SrcMgr.getBufferInfo(BufferID).Buffer; + const char *BufferName = CurMB->getBufferIdentifier(); + std::pair<unsigned, unsigned> LineAndColumn = SrcMgr.getLineAndColumn(Loc); + OS << *Id << "\t" << BufferName << "\t" << LineAndColumn.first << "\n"; + } +}; + +class CTagsEmitter { +private: + RecordKeeper &Records; +public: + CTagsEmitter(RecordKeeper &R) : Records(R) {} + + void run(raw_ostream &OS); + +private: + static SMLoc locate(const Record *R); +}; + +} // End anonymous namespace. + +SMLoc CTagsEmitter::locate(const Record *R) { + ArrayRef<SMLoc> Locs = R->getLoc(); + if (Locs.empty()) { + SMLoc NullLoc; + return NullLoc; + } + return Locs.front(); +} + +void CTagsEmitter::run(raw_ostream &OS) { + const std::map<std::string, Record *> &Classes = Records.getClasses(); + const std::map<std::string, Record *> &Defs = Records.getDefs(); + std::vector<Tag> Tags; + // Collect tags. + Tags.reserve(Classes.size() + Defs.size()); + for (std::map<std::string, Record *>::const_iterator I = Classes.begin(), + E = Classes.end(); + I != E; ++I) + Tags.push_back(Tag(I->first, locate(I->second))); + for (std::map<std::string, Record *>::const_iterator I = Defs.begin(), + E = Defs.end(); + I != E; ++I) + Tags.push_back(Tag(I->first, locate(I->second))); + // Emit tags. + std::sort(Tags.begin(), Tags.end()); + OS << "!_TAG_FILE_FORMAT\t1\t/original ctags format/\n"; + OS << "!_TAG_FILE_SORTED\t1\t/0=unsorted, 1=sorted, 2=foldcase/\n"; + for (std::vector<Tag>::const_iterator I = Tags.begin(), E = Tags.end(); + I != E; ++I) + I->emit(OS); +} + +namespace llvm { + +void EmitCTags(RecordKeeper &RK, raw_ostream &OS) { CTagsEmitter(RK).run(OS); } + +} // End llvm namespace. diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp index 72fb77150c..8e5bb7760f 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -57,7 +57,7 @@ EEVT::TypeSet::TypeSet(MVT::SimpleValueType VT, TreePattern &TP) { } -EEVT::TypeSet::TypeSet(const std::vector<MVT::SimpleValueType> &VTList) { +EEVT::TypeSet::TypeSet(ArrayRef<MVT::SimpleValueType> VTList) { assert(!VTList.empty() && "empty list?"); TypeVec.append(VTList.begin(), VTList.end()); @@ -76,7 +76,7 @@ bool EEVT::TypeSet::FillWithPossibleTypes(TreePattern &TP, bool (*Pred)(MVT::SimpleValueType), const char *PredicateName) { assert(isCompletelyUnknown()); - const std::vector<MVT::SimpleValueType> &LegalTypes = + ArrayRef<MVT::SimpleValueType> LegalTypes = TP.getDAGPatterns().getTargetInfo().getLegalValueTypes(); if (TP.hasError()) @@ -956,6 +956,40 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, llvm_unreachable("Invalid ConstraintType!"); } +// Update the node type to match an instruction operand or result as specified +// in the ins or outs lists on the instruction definition. Return true if the +// type was actually changed. +bool TreePatternNode::UpdateNodeTypeFromInst(unsigned ResNo, + Record *Operand, + TreePattern &TP) { + // The 'unknown' operand indicates that types should be inferred from the + // context. + if (Operand->isSubClassOf("unknown_class")) + return false; + + // The Operand class specifies a type directly. + if (Operand->isSubClassOf("Operand")) + return UpdateNodeType(ResNo, getValueType(Operand->getValueAsDef("Type")), + TP); + + // PointerLikeRegClass has a type that is determined at runtime. + if (Operand->isSubClassOf("PointerLikeRegClass")) + return UpdateNodeType(ResNo, MVT::iPTR, TP); + + // Both RegisterClass and RegisterOperand operands derive their types from a + // register class def. + Record *RC = 0; + if (Operand->isSubClassOf("RegisterClass")) + RC = Operand; + else if (Operand->isSubClassOf("RegisterOperand")) + RC = Operand->getValueAsDef("RegClass"); + + assert(RC && "Unknown operand type"); + CodeGenTarget &Tgt = TP.getDAGPatterns().getTargetInfo(); + return UpdateNodeType(ResNo, Tgt.getRegisterClass(RC).getValueTypes(), TP); +} + + //===----------------------------------------------------------------------===// // SDNodeInfo implementation // @@ -1287,8 +1321,18 @@ TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) { /// type which should be applied to it. This will infer the type of register /// references from the register file information, for example. /// +/// When Unnamed is set, return the type of a DAG operand with no name, such as +/// the F8RC register class argument in: +/// +/// (COPY_TO_REGCLASS GPR:$src, F8RC) +/// +/// When Unnamed is false, return the type of a named DAG operand such as the +/// GPR:$src operand above. +/// static EEVT::TypeSet getImplicitType(Record *R, unsigned ResNo, - bool NotRegisters, TreePattern &TP) { + bool NotRegisters, + bool Unnamed, + TreePattern &TP) { // Check to see if this is a register operand. if (R->isSubClassOf("RegisterOperand")) { assert(ResNo == 0 && "Regoperand ref only has one result!"); @@ -1302,6 +1346,13 @@ static EEVT::TypeSet getImplicitType(Record *R, unsigned ResNo, // Check to see if this is a register or a register class. if (R->isSubClassOf("RegisterClass")) { assert(ResNo == 0 && "Regclass ref only has one result!"); + // An unnamed register class represents itself as an i32 immediate, for + // example on a COPY_TO_REGCLASS instruction. + if (Unnamed) + return EEVT::TypeSet(MVT::i32, TP); + + // In a named operand, the register class provides the possible set of + // types. if (NotRegisters) return EEVT::TypeSet(); // Unknown. const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo(); @@ -1327,9 +1378,27 @@ static EEVT::TypeSet getImplicitType(Record *R, unsigned ResNo, return EEVT::TypeSet(); } - if (R->isSubClassOf("ValueType") || R->isSubClassOf("CondCode")) { + if (R->isSubClassOf("ValueType")) { assert(ResNo == 0 && "This node only has one result!"); - // Using a VTSDNode or CondCodeSDNode. + // An unnamed VTSDNode represents itself as an MVT::Other immediate. + // + // (sext_inreg GPR:$src, i16) + // ~~~ + if (Unnamed) + return EEVT::TypeSet(MVT::Other, TP); + // With a name, the ValueType simply provides the type of the named + // variable. + // + // (sext_inreg i32:$src, i16) + // ~~~~~~~~ + if (NotRegisters) + return EEVT::TypeSet(); // Unknown. + return EEVT::TypeSet(getValueType(R), TP); + } + + if (R->isSubClassOf("CondCode")) { + assert(ResNo == 0 && "This node only has one result!"); + // Using a CondCodeSDNode. return EEVT::TypeSet(MVT::Other, TP); } @@ -1435,7 +1504,8 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { bool MadeChange = false; for (unsigned i = 0, e = Types.size(); i != e; ++i) MadeChange |= UpdateNodeType(i, getImplicitType(DI->getDef(), i, - NotRegisters, TP), TP); + NotRegisters, + !hasName(), TP), TP); return MadeChange; } @@ -1498,25 +1568,6 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { return MadeChange; } - if (getOperator()->getName() == "COPY_TO_REGCLASS") { - bool MadeChange = false; - MadeChange |= getChild(0)->ApplyTypeConstraints(TP, NotRegisters); - MadeChange |= getChild(1)->ApplyTypeConstraints(TP, NotRegisters); - - assert(getChild(0)->getNumTypes() == 1 && - getChild(1)->getNumTypes() == 1 && "Unhandled case"); - - // child #1 of COPY_TO_REGCLASS should be a register class. We don't care - // what type it gets, so if it didn't get a concrete type just give it the - // first viable type from the reg class. - if (!getChild(1)->hasTypeSet(0) && - !getChild(1)->getExtType(0).isCompletelyUnknown()) { - MVT::SimpleValueType RCVT = getChild(1)->getExtType(0).getTypeList()[0]; - MadeChange |= getChild(1)->UpdateNodeType(0, RCVT, TP); - } - return MadeChange; - } - if (const CodeGenIntrinsic *Int = getIntrinsicInfo(CDP)) { bool MadeChange = false; @@ -1575,26 +1626,8 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { // (outs) list of the instruction. // FIXME: Cap at one result so far. unsigned NumResultsToAdd = InstInfo.Operands.NumDefs ? 1 : 0; - for (unsigned ResNo = 0; ResNo != NumResultsToAdd; ++ResNo) { - Record *ResultNode = Inst.getResult(ResNo); - - if (ResultNode->isSubClassOf("PointerLikeRegClass")) { - MadeChange |= UpdateNodeType(ResNo, MVT::iPTR, TP); - } else if (ResultNode->isSubClassOf("RegisterOperand")) { - Record *RegClass = ResultNode->getValueAsDef("RegClass"); - const CodeGenRegisterClass &RC = - CDP.getTargetInfo().getRegisterClass(RegClass); - MadeChange |= UpdateNodeType(ResNo, RC.getValueTypes(), TP); - } else if (ResultNode->isSubClassOf("unknown_class")) { - // Nothing to do. - } else { - assert(ResultNode->isSubClassOf("RegisterClass") && - "Operands should be register classes!"); - const CodeGenRegisterClass &RC = - CDP.getTargetInfo().getRegisterClass(ResultNode); - MadeChange |= UpdateNodeType(ResNo, RC.getValueTypes(), TP); - } - } + for (unsigned ResNo = 0; ResNo != NumResultsToAdd; ++ResNo) + MadeChange |= UpdateNodeTypeFromInst(ResNo, Inst.getResult(ResNo), TP); // If the instruction has implicit defs, we apply the first one as a result. // FIXME: This sucks, it should apply all implicit defs. @@ -1636,30 +1669,44 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { return false; } - MVT::SimpleValueType VT; TreePatternNode *Child = getChild(ChildNo++); unsigned ChildResNo = 0; // Instructions always use res #0 of their op. - if (OperandNode->isSubClassOf("RegisterClass")) { - const CodeGenRegisterClass &RC = - CDP.getTargetInfo().getRegisterClass(OperandNode); - MadeChange |= Child->UpdateNodeType(ChildResNo, RC.getValueTypes(), TP); - } else if (OperandNode->isSubClassOf("RegisterOperand")) { - Record *RegClass = OperandNode->getValueAsDef("RegClass"); - const CodeGenRegisterClass &RC = - CDP.getTargetInfo().getRegisterClass(RegClass); - MadeChange |= Child->UpdateNodeType(ChildResNo, RC.getValueTypes(), TP); - } else if (OperandNode->isSubClassOf("Operand")) { - VT = getValueType(OperandNode->getValueAsDef("Type")); - MadeChange |= Child->UpdateNodeType(ChildResNo, VT, TP); - } else if (OperandNode->isSubClassOf("PointerLikeRegClass")) { - MadeChange |= Child->UpdateNodeType(ChildResNo, MVT::iPTR, TP); - } else if (OperandNode->isSubClassOf("unknown_class")) { - // Nothing to do. - } else - llvm_unreachable("Unknown operand type!"); + // If the operand has sub-operands, they may be provided by distinct + // child patterns, so attempt to match each sub-operand separately. + if (OperandNode->isSubClassOf("Operand")) { + DagInit *MIOpInfo = OperandNode->getValueAsDag("MIOperandInfo"); + if (unsigned NumArgs = MIOpInfo->getNumArgs()) { + // But don't do that if the whole operand is being provided by + // a single ComplexPattern. + const ComplexPattern *AM = Child->getComplexPatternInfo(CDP); + if (!AM || AM->getNumOperands() < NumArgs) { + // Match first sub-operand against the child we already have. + Record *SubRec = cast<DefInit>(MIOpInfo->getArg(0))->getDef(); + MadeChange |= + Child->UpdateNodeTypeFromInst(ChildResNo, SubRec, TP); + + // And the remaining sub-operands against subsequent children. + for (unsigned Arg = 1; Arg < NumArgs; ++Arg) { + if (ChildNo >= getNumChildren()) { + TP.error("Instruction '" + getOperator()->getName() + + "' expects more operands than were provided."); + return false; + } + Child = getChild(ChildNo++); + + SubRec = cast<DefInit>(MIOpInfo->getArg(Arg))->getDef(); + MadeChange |= + Child->UpdateNodeTypeFromInst(ChildResNo, SubRec, TP); + } + continue; + } + } + } - MadeChange |= Child->ApplyTypeConstraints(TP, NotRegisters); + // If we didn't match by pieces above, attempt to match the whole + // operand now. + MadeChange |= Child->UpdateNodeTypeFromInst(ChildResNo, OperandNode, TP); } if (ChildNo != getNumChildren()) { @@ -1668,6 +1715,8 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { return false; } + for (unsigned i = 0, e = getNumChildren(); i != e; ++i) + MadeChange |= getChild(i)->ApplyTypeConstraints(TP, NotRegisters); return MadeChange; } @@ -1817,6 +1866,16 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ return Res; } + // ?:$name or just $name. + if (TheInit == UnsetInit::get()) { + if (OpName.empty()) + error("'?' argument requires a name to match with operand list"); + TreePatternNode *Res = new TreePatternNode(TheInit, 1); + Args.push_back(OpName); + Res->setName(OpName); + return Res; + } + if (IntInit *II = dyn_cast<IntInit>(TheInit)) { if (!OpName.empty()) error("Constant int argument should not have a name!"); @@ -2383,6 +2442,7 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, I->error("set destination should be a register!"); if (Val->getDef()->isSubClassOf("RegisterClass") || + Val->getDef()->isSubClassOf("ValueType") || Val->getDef()->isSubClassOf("RegisterOperand") || Val->getDef()->isSubClassOf("PointerLikeRegClass")) { if (Dest->getName().empty()) @@ -2599,6 +2659,25 @@ getInstructionsInTree(TreePatternNode *Tree, SmallVectorImpl<Record*> &Instrs) { getInstructionsInTree(Tree->getChild(i), Instrs); } +/// Check the class of a pattern leaf node against the instruction operand it +/// represents. +static bool checkOperandClass(CGIOperandList::OperandInfo &OI, + Record *Leaf) { + if (OI.Rec == Leaf) + return true; + + // Allow direct value types to be used in instruction set patterns. + // The type will be checked later. + if (Leaf->isSubClassOf("ValueType")) + return true; + + // Patterns can also be ComplexPattern instances. + if (Leaf->isSubClassOf("ComplexPattern")) + return true; + + return false; +} + /// ParseInstructions - Parse all of the instructions, inlining and resolving /// any fragments involved. This populates the Instructions list with fully /// resolved instructions. @@ -2708,7 +2787,7 @@ void CodeGenDAGPatterns::ParseInstructions() { I->error("Operand $" + OpName + " should be a set destination: all " "outputs must occur before inputs in operand list!"); - if (CGI.Operands[i].Rec != R) + if (!checkOperandClass(CGI.Operands[i], R)) I->error("Operand $" + OpName + " class mismatch!"); // Remember the return type. @@ -2747,7 +2826,7 @@ void CodeGenDAGPatterns::ParseInstructions() { if (InVal->isLeaf() && isa<DefInit>(InVal->getLeafValue())) { Record *InRec = static_cast<DefInit*>(InVal->getLeafValue())->getDef(); - if (Op.Rec != InRec && !InRec->isSubClassOf("ComplexPattern")) + if (!checkOperandClass(Op, InRec)) I->error("Operand $" + OpName + "'s register class disagrees" " between the operand and pattern"); } diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h index 424f02f7ab..7c2fa36741 100644 --- a/utils/TableGen/CodeGenDAGPatterns.h +++ b/utils/TableGen/CodeGenDAGPatterns.h @@ -59,7 +59,7 @@ namespace EEVT { public: TypeSet() {} TypeSet(MVT::SimpleValueType VT, TreePattern &TP); - TypeSet(const std::vector<MVT::SimpleValueType> &VTList); + TypeSet(ArrayRef<MVT::SimpleValueType> VTList); bool isCompletelyUnknown() const { return TypeVec.empty(); } @@ -334,6 +334,7 @@ public: } ~TreePatternNode(); + bool hasName() const { return !Name.empty(); } const std::string &getName() const { return Name; } void setName(StringRef N) { Name.assign(N.begin(), N.end()); } @@ -463,6 +464,11 @@ public: // Higher level manipulation routines. return Types[ResNo].MergeInTypeInfo(EEVT::TypeSet(InTy, TP), TP); } + // Update node type with types inferred from an instruction operand or result + // def from the ins/outs lists. + // Return true if the type changed. + bool UpdateNodeTypeFromInst(unsigned ResNo, Record *Operand, TreePattern &TP); + /// ContainsUnresolvedType - Return true if this tree contains any /// unresolved types. bool ContainsUnresolvedType() const { diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h index a1921a412a..4f2cc28d49 100644 --- a/utils/TableGen/CodeGenRegisters.h +++ b/utils/TableGen/CodeGenRegisters.h @@ -261,7 +261,7 @@ namespace llvm { public: unsigned EnumValue; std::string Namespace; - std::vector<MVT::SimpleValueType> VTs; + SmallVector<MVT::SimpleValueType, 4> VTs; unsigned SpillSize; unsigned SpillAlignment; int CopyCost; @@ -274,7 +274,7 @@ namespace llvm { const std::string &getName() const { return Name; } std::string getQualifiedName() const; - const std::vector<MVT::SimpleValueType> &getValueTypes() const {return VTs;} + ArrayRef<MVT::SimpleValueType> getValueTypes() const {return VTs;} unsigned getNumValueTypes() const { return VTs.size(); } MVT::SimpleValueType getValueTypeNum(unsigned VTNum) const { diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp index 23b79fcddf..c02f0843d6 100644 --- a/utils/TableGen/CodeGenSchedule.cpp +++ b/utils/TableGen/CodeGenSchedule.cpp @@ -88,7 +88,7 @@ struct InstRegexOp : public SetTheory::Operator { /// CodeGenModels ctor interprets machine model records and populates maps. CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, const CodeGenTarget &TGT): - Records(RK), Target(TGT), NumItineraryClasses(0) { + Records(RK), Target(TGT) { Sets.addFieldExpander("InstRW", "Instrs"); @@ -217,7 +217,7 @@ void CodeGenSchedModels::collectSchedRW() { for (CodeGenTarget::inst_iterator I = Target.inst_begin(), E = Target.inst_end(); I != E; ++I) { Record *SchedDef = (*I)->TheDef; - if (!SchedDef->isSubClassOf("Sched")) + if (SchedDef->isValueUnset("SchedRW")) continue; RecVec RWs = SchedDef->getValueAsListOfDefs("SchedRW"); for (RecIter RWI = RWs.begin(), RWE = RWs.end(); RWI != RWE; ++RWI) { @@ -502,40 +502,25 @@ void CodeGenSchedModels::collectSchedClasses() { // NoItinerary is always the first class at Idx=0 SchedClasses.resize(1); - SchedClasses.back().Name = "NoItinerary"; + SchedClasses.back().Index = 0; + SchedClasses.back().Name = "NoInstrModel"; + SchedClasses.back().ItinClassDef = Records.getDef("NoItinerary"); SchedClasses.back().ProcIndices.push_back(0); - SchedClassIdxMap[SchedClasses.back().Name] = 0; - // Gather and sort all itinerary classes used by instruction descriptions. - RecVec ItinClassList; + // Create a SchedClass for each unique combination of itinerary class and + // SchedRW list. for (CodeGenTarget::inst_iterator I = Target.inst_begin(), E = Target.inst_end(); I != E; ++I) { Record *ItinDef = (*I)->TheDef->getValueAsDef("Itinerary"); - // Map a new SchedClass with no index. - if (!SchedClassIdxMap.count(ItinDef->getName())) { - SchedClassIdxMap[ItinDef->getName()] = 0; - ItinClassList.push_back(ItinDef); - } - } - // Assign each itinerary class unique number, skipping NoItinerary==0 - NumItineraryClasses = ItinClassList.size(); - std::sort(ItinClassList.begin(), ItinClassList.end(), LessRecord()); - for (unsigned i = 0, N = NumItineraryClasses; i < N; i++) { - Record *ItinDef = ItinClassList[i]; - SchedClassIdxMap[ItinDef->getName()] = SchedClasses.size(); - SchedClasses.push_back(CodeGenSchedClass(ItinDef)); - } - // Infer classes from SchedReadWrite resources listed for each - // instruction definition that inherits from class Sched. - for (CodeGenTarget::inst_iterator I = Target.inst_begin(), - E = Target.inst_end(); I != E; ++I) { - if (!(*I)->TheDef->isSubClassOf("Sched")) - continue; IdxVec Writes, Reads; - findRWs((*I)->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads); + if (!(*I)->TheDef->isValueUnset("SchedRW")) + findRWs((*I)->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads); + // ProcIdx == 0 indicates the class applies to all processors. IdxVec ProcIndices(1, 0); - addSchedClass(Writes, Reads, ProcIndices); + + unsigned SCIdx = addSchedClass(ItinDef, Writes, Reads, ProcIndices); + InstrClassMap[(*I)->TheDef] = SCIdx; } // Create classes for InstRW defs. RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW"); @@ -549,68 +534,70 @@ void CodeGenSchedModels::collectSchedClasses() { DEBUG(EnableDump = true); if (!EnableDump) return; + for (CodeGenTarget::inst_iterator I = Target.inst_begin(), E = Target.inst_end(); I != E; ++I) { - Record *SchedDef = (*I)->TheDef; + std::string InstName = (*I)->TheDef->getName(); - if (SchedDef->isSubClassOf("Sched")) { + unsigned SCIdx = InstrClassMap.lookup((*I)->TheDef); + if (!SCIdx) { + dbgs() << "No machine model for " << (*I)->TheDef->getName() << '\n'; + continue; + } + CodeGenSchedClass &SC = getSchedClass(SCIdx); + if (SC.ProcIndices[0] != 0) + PrintFatalError((*I)->TheDef->getLoc(), "Instruction's sched class " + "must not be subtarget specific."); + + IdxVec ProcIndices; + if (SC.ItinClassDef->getName() != "NoItinerary") { + ProcIndices.push_back(0); + dbgs() << "Itinerary for " << InstName << ": " + << SC.ItinClassDef->getName() << '\n'; + } + if (!SC.Writes.empty()) { + ProcIndices.push_back(0); + dbgs() << "SchedRW machine model for " << InstName; + for (IdxIter WI = SC.Writes.begin(), WE = SC.Writes.end(); WI != WE; ++WI) + dbgs() << " " << SchedWrites[*WI].Name; + for (IdxIter RI = SC.Reads.begin(), RE = SC.Reads.end(); RI != RE; ++RI) + dbgs() << " " << SchedReads[*RI].Name; + dbgs() << '\n'; + } + const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs; + for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); + RWI != RWE; ++RWI) { + const CodeGenProcModel &ProcModel = + getProcModel((*RWI)->getValueAsDef("SchedModel")); + ProcIndices.push_back(ProcModel.Index); + dbgs() << "InstRW on " << ProcModel.ModelName << " for " << InstName; IdxVec Writes; IdxVec Reads; - findRWs((*I)->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads); - dbgs() << "SchedRW machine model for " << InstName; + findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"), + Writes, Reads); for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) dbgs() << " " << SchedWrites[*WI].Name; for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI) dbgs() << " " << SchedReads[*RI].Name; dbgs() << '\n'; } - unsigned SCIdx = InstrClassMap.lookup((*I)->TheDef); - if (SCIdx) { - const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs; - for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); - RWI != RWE; ++RWI) { - const CodeGenProcModel &ProcModel = - getProcModel((*RWI)->getValueAsDef("SchedModel")); - dbgs() << "InstRW on " << ProcModel.ModelName << " for " << InstName; - IdxVec Writes; - IdxVec Reads; - findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"), - Writes, Reads); - for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) - dbgs() << " " << SchedWrites[*WI].Name; - for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI) - dbgs() << " " << SchedReads[*RI].Name; - dbgs() << '\n'; - } - continue; - } - if (!SchedDef->isSubClassOf("Sched") - && (SchedDef->getValueAsDef("Itinerary")->getName() == "NoItinerary")) { - dbgs() << "No machine model for " << (*I)->TheDef->getName() << '\n'; + for (std::vector<CodeGenProcModel>::iterator PI = ProcModels.begin(), + PE = ProcModels.end(); PI != PE; ++PI) { + if (!std::count(ProcIndices.begin(), ProcIndices.end(), PI->Index)) + dbgs() << "No machine model for " << (*I)->TheDef->getName() + << " on processor " << PI->ModelName << '\n'; } } } -unsigned CodeGenSchedModels::getSchedClassIdx( - const RecVec &RWDefs) const { - - IdxVec Writes, Reads; - findRWs(RWDefs, Writes, Reads); - return findSchedClassIdx(Writes, Reads); -} - /// Find an SchedClass that has been inferred from a per-operand list of /// SchedWrites and SchedReads. -unsigned CodeGenSchedModels::findSchedClassIdx(const IdxVec &Writes, +unsigned CodeGenSchedModels::findSchedClassIdx(Record *ItinClassDef, + const IdxVec &Writes, const IdxVec &Reads) const { for (SchedClassIter I = schedClassBegin(), E = schedClassEnd(); I != E; ++I) { - // Classes with InstRWs may have the same Writes/Reads as a class originally - // produced by a SchedRW definition. We need to be able to recover the - // original class index for processors that don't match any InstRWs. - if (I->ItinClassDef || !I->InstRWs.empty()) - continue; - - if (I->Writes == Writes && I->Reads == Reads) { + if (I->ItinClassDef == ItinClassDef + && I->Writes == Writes && I->Reads == Reads) { return I - schedClassBegin(); } } @@ -621,29 +608,17 @@ unsigned CodeGenSchedModels::findSchedClassIdx(const IdxVec &Writes, unsigned CodeGenSchedModels::getSchedClassIdx( const CodeGenInstruction &Inst) const { - unsigned SCIdx = InstrClassMap.lookup(Inst.TheDef); - if (SCIdx) - return SCIdx; - - // If this opcode isn't mapped by the subtarget fallback to the instruction - // definition's SchedRW or ItinDef values. - if (Inst.TheDef->isSubClassOf("Sched")) { - RecVec RWs = Inst.TheDef->getValueAsListOfDefs("SchedRW"); - return getSchedClassIdx(RWs); - } - Record *ItinDef = Inst.TheDef->getValueAsDef("Itinerary"); - assert(SchedClassIdxMap.count(ItinDef->getName()) && "missing ItinClass"); - unsigned Idx = SchedClassIdxMap.lookup(ItinDef->getName()); - assert(Idx <= NumItineraryClasses && "bad ItinClass index"); - return Idx; + return InstrClassMap.lookup(Inst.TheDef); } std::string CodeGenSchedModels::createSchedClassName( - const IdxVec &OperWrites, const IdxVec &OperReads) { + Record *ItinClassDef, const IdxVec &OperWrites, const IdxVec &OperReads) { std::string Name; + if (ItinClassDef && ItinClassDef->getName() != "NoItinerary") + Name = ItinClassDef->getName(); for (IdxIter WI = OperWrites.begin(), WE = OperWrites.end(); WI != WE; ++WI) { - if (WI != OperWrites.begin()) + if (!Name.empty()) Name += '_'; Name += SchedWrites[*WI].Name; } @@ -665,17 +640,18 @@ std::string CodeGenSchedModels::createSchedClassName(const RecVec &InstDefs) { return Name; } -/// Add an inferred sched class from a per-operand list of SchedWrites and -/// SchedReads. ProcIndices contains the set of IDs of processors that may -/// utilize this class. -unsigned CodeGenSchedModels::addSchedClass(const IdxVec &OperWrites, +/// Add an inferred sched class from an itinerary class and per-operand list of +/// SchedWrites and SchedReads. ProcIndices contains the set of IDs of +/// processors that may utilize this class. +unsigned CodeGenSchedModels::addSchedClass(Record *ItinClassDef, + const IdxVec &OperWrites, const IdxVec &OperReads, const IdxVec &ProcIndices) { assert(!ProcIndices.empty() && "expect at least one ProcIdx"); - unsigned Idx = findSchedClassIdx(OperWrites, OperReads); - if (Idx) { + unsigned Idx = findSchedClassIdx(ItinClassDef, OperWrites, OperReads); + if (Idx || SchedClasses[0].isKeyEqual(ItinClassDef, OperWrites, OperReads)) { IdxVec PI; std::set_union(SchedClasses[Idx].ProcIndices.begin(), SchedClasses[Idx].ProcIndices.end(), @@ -687,7 +663,9 @@ unsigned CodeGenSchedModels::addSchedClass(const IdxVec &OperWrites, Idx = SchedClasses.size(); SchedClasses.resize(Idx+1); CodeGenSchedClass &SC = SchedClasses.back(); - SC.Name = createSchedClassName(OperWrites, OperReads); + SC.Index = Idx; + SC.Name = createSchedClassName(ItinClassDef, OperWrites, OperReads); + SC.ItinClassDef = ItinClassDef; SC.Writes = OperWrites; SC.Reads = OperReads; SC.ProcIndices = ProcIndices; @@ -709,19 +687,10 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { PrintFatalError(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()) - SCIdx = Pos->second; - else { - // This instruction has not been mapped yet. Get the original class. All - // instructions in the same InstrRW class must be from the same original - // class because that is the fall-back class for other processors. - Record *ItinDef = (*I)->getValueAsDef("Itinerary"); - SCIdx = SchedClassIdxMap.lookup(ItinDef->getName()); - if (!SCIdx && (*I)->isSubClassOf("Sched")) - SCIdx = getSchedClassIdx((*I)->getValueAsListOfDefs("SchedRW")); - } + if (Pos == InstrClassMap.end()) + PrintFatalError((*I)->getLoc(), "No sched class for instruction."); + unsigned SCIdx = Pos->second; unsigned CIdx = 0, CEnd = ClassInstrs.size(); for (; CIdx != CEnd; ++CIdx) { if (ClassInstrs[CIdx].first == SCIdx) @@ -741,7 +710,7 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { ArrayRef<Record*> InstDefs = ClassInstrs[CIdx].second; // If the all instrs in the current class are accounted for, then leave // them mapped to their old class. - if (SchedClasses[OldSCIdx].InstRWs.size() == InstDefs.size()) { + if (OldSCIdx && SchedClasses[OldSCIdx].InstRWs.size() == InstDefs.size()) { assert(SchedClasses[OldSCIdx].ProcIndices[0] == 0 && "expected a generic SchedClass"); continue; @@ -749,6 +718,7 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { unsigned SCIdx = SchedClasses.size(); SchedClasses.resize(SCIdx+1); CodeGenSchedClass &SC = SchedClasses.back(); + SC.Index = SCIdx; SC.Name = createSchedClassName(InstDefs); // Preserve ItinDef and Writes/Reads for processors without an InstRW entry. SC.ItinClassDef = SchedClasses[OldSCIdx].ItinClassDef; @@ -780,32 +750,48 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { } } +// True if collectProcItins found anything. +bool CodeGenSchedModels::hasItineraries() const { + for (CodeGenSchedModels::ProcIter PI = procModelBegin(), PE = procModelEnd(); + PI != PE; ++PI) { + if (PI->hasItineraries()) + return true; + } + return false; +} + // Gather the processor itineraries. void CodeGenSchedModels::collectProcItins() { for (std::vector<CodeGenProcModel>::iterator PI = ProcModels.begin(), PE = ProcModels.end(); PI != PE; ++PI) { CodeGenProcModel &ProcModel = *PI; - RecVec ItinRecords = ProcModel.ItinsDef->getValueAsListOfDefs("IID"); - // Skip empty itinerary. - if (ItinRecords.empty()) + if (!ProcModel.hasItineraries()) continue; - ProcModel.ItinDefList.resize(NumItineraryClasses+1); + RecVec ItinRecords = ProcModel.ItinsDef->getValueAsListOfDefs("IID"); + assert(!ItinRecords.empty() && "ProcModel.hasItineraries is incorrect"); + + // Populate ItinDefList with Itinerary records. + ProcModel.ItinDefList.resize(NumInstrSchedClasses); // Insert each itinerary data record in the correct position within // the processor model's ItinDefList. for (unsigned i = 0, N = ItinRecords.size(); i < N; i++) { Record *ItinData = ItinRecords[i]; Record *ItinDef = ItinData->getValueAsDef("TheClass"); - if (!SchedClassIdxMap.count(ItinDef->getName())) { + bool FoundClass = false; + for (SchedClassIter SCI = schedClassBegin(), SCE = schedClassEnd(); + SCI != SCE; ++SCI) { + // Multiple SchedClasses may share an itinerary. Update all of them. + if (SCI->ItinClassDef == ItinDef) { + ProcModel.ItinDefList[SCI->Index] = ItinData; + FoundClass = true; + } + } + if (!FoundClass) { DEBUG(dbgs() << ProcModel.ItinsDef->getName() - << " has unused itinerary class " << ItinDef->getName() << '\n'); - continue; + << " missing class for itinerary " << ItinDef->getName() << '\n'); } - assert(SchedClassIdxMap.count(ItinDef->getName()) && "missing ItinClass"); - unsigned Idx = SchedClassIdxMap.lookup(ItinDef->getName()); - assert(Idx <= NumItineraryClasses && "bad ItinClass index"); - ProcModel.ItinDefList[Idx] = ItinData; } // Check for missing itinerary entries. assert(!ProcModel.ItinDefList[0] && "NoItinerary class can't have rec"); @@ -839,13 +825,17 @@ 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() { + DEBUG(dbgs() << NumInstrSchedClasses << " instr sched classes.\n"); + // Visit all existing classes and newly created classes. for (unsigned Idx = 0; Idx != SchedClasses.size(); ++Idx) { + assert(SchedClasses[Idx].Index == Idx && "bad SCIdx"); + if (SchedClasses[Idx].ItinClassDef) inferFromItinClass(SchedClasses[Idx].ItinClassDef, Idx); - else if (!SchedClasses[Idx].InstRWs.empty()) + if (!SchedClasses[Idx].InstRWs.empty()) inferFromInstRWs(Idx); - else { + if (!SchedClasses[Idx].Writes.empty()) { inferFromRW(SchedClasses[Idx].Writes, SchedClasses[Idx].Reads, Idx, SchedClasses[Idx].ProcIndices); } @@ -1042,11 +1032,13 @@ static bool hasVariant(ArrayRef<PredTransition> Transitions, // Populate IntersectingVariants with any variants or aliased sequences of the // given SchedRW whose processor indices and predicates are not mutually -// exclusive with the given transition, +// exclusive with the given transition. void PredTransitions::getIntersectingVariants( const CodeGenSchedRW &SchedRW, unsigned TransIdx, std::vector<TransVariant> &IntersectingVariants) { + bool GenericRW = false; + std::vector<TransVariant> Variants; if (SchedRW.HasVariants) { unsigned VarProcIdx = 0; @@ -1058,6 +1050,8 @@ void PredTransitions::getIntersectingVariants( const RecVec VarDefs = SchedRW.TheDef->getValueAsListOfDefs("Variants"); for (RecIter RI = VarDefs.begin(), RE = VarDefs.end(); RI != RE; ++RI) Variants.push_back(TransVariant(*RI, SchedRW.Index, VarProcIdx, 0)); + if (VarProcIdx == 0) + GenericRW = true; } for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end(); AI != AE; ++AI) { @@ -1081,6 +1075,8 @@ void PredTransitions::getIntersectingVariants( Variants.push_back( TransVariant(AliasRW.TheDef, SchedRW.Index, AliasProcIdx, 0)); } + if (AliasProcIdx == 0) + GenericRW = true; } for (unsigned VIdx = 0, VEnd = Variants.size(); VIdx != VEnd; ++VIdx) { TransVariant &Variant = Variants[VIdx]; @@ -1118,6 +1114,10 @@ void PredTransitions::getIntersectingVariants( TransVec.push_back(TransVec[TransIdx]); } } + if (GenericRW && IntersectingVariants.empty()) { + PrintFatalError(SchedRW.TheDef->getLoc(), "No variant of this type has " + "a matching predicate on any processor"); + } } // Push the Reads/Writes selected by this variant onto the PredTransition @@ -1215,10 +1215,6 @@ void PredTransitions::substituteVariantOperand( // This will push a copies of TransVec[TransIdx] on the back of TransVec. std::vector<TransVariant> IntersectingVariants; getIntersectingVariants(SchedRW, TransIdx, IntersectingVariants); - if (IntersectingVariants.empty()) - PrintFatalError(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<TransVariant>::const_iterator IVI = IntersectingVariants.begin(), @@ -1295,8 +1291,8 @@ static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions, IdxVec ProcIndices(I->ProcIndices.begin(), I->ProcIndices.end()); CodeGenSchedTransition SCTrans; SCTrans.ToClassIdx = - SchedModels.addSchedClass(OperWritesVariant, OperReadsVariant, - ProcIndices); + SchedModels.addSchedClass(/*ItinClassDef=*/0, OperWritesVariant, + OperReadsVariant, ProcIndices); SCTrans.ProcIndices = ProcIndices; // The final PredTerm is unique set of predicates guarding the transition. RecVec Preds; @@ -1318,7 +1314,7 @@ void CodeGenSchedModels::inferFromRW(const IdxVec &OperWrites, const IdxVec &OperReads, unsigned FromClassIdx, const IdxVec &ProcIndices) { - DEBUG(dbgs() << "INFER RW: "); + DEBUG(dbgs() << "INFER RW proc("; dumpIdxVec(ProcIndices); dbgs() << ") "); // Create a seed transition with an empty PredTerm and the expanded sequences // of SchedWrites for the current SchedClass. @@ -1542,6 +1538,20 @@ Record *CodeGenSchedModels::findProcResUnits(Record *ProcResKind, ProcUnitDef = *RI; } } + RecVec ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup"); + for (RecIter RI = ProcResGroups.begin(), RE = ProcResGroups.end(); + RI != RE; ++RI) { + + if (*RI == ProcResKind + && (*RI)->getValueAsDef("SchedModel") == PM.ModelDef) { + if (ProcUnitDef) { + PrintFatalError((*RI)->getLoc(), + "Multiple ProcessorResourceUnits associated with " + + ProcResKind->getName()); + } + ProcUnitDef = *RI; + } + } if (!ProcUnitDef) { PrintFatalError(ProcResKind->getLoc(), "No ProcessorResources associated with " @@ -1563,6 +1573,9 @@ void CodeGenSchedModels::addProcResource(Record *ProcResKind, return; PM.ProcResourceDefs.push_back(ProcResUnits); + if (ProcResUnits->isSubClassOf("ProcResGroup")) + return; + if (!ProcResUnits->getValueInit("Super")->isComplete()) return; @@ -1625,7 +1638,7 @@ void CodeGenSchedRW::dump() const { } void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const { - dbgs() << "SCHEDCLASS " << Name << '\n' + dbgs() << "SCHEDCLASS " << Index << ":" << Name << '\n' << " Writes: "; for (unsigned i = 0, N = Writes.size(); i < N; ++i) { SchedModels->getSchedWrite(Writes[i]).dump(); @@ -1643,6 +1656,13 @@ void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const { } } dbgs() << "\n ProcIdx: "; dumpIdxVec(ProcIndices); dbgs() << '\n'; + if (!Transitions.empty()) { + dbgs() << "\n Transitions for Proc "; + for (std::vector<CodeGenSchedTransition>::const_iterator + TI = Transitions.begin(), TE = Transitions.end(); TI != TE; ++TI) { + dumpIdxVec(TI->ProcIndices); + } + } } void PredTransitions::dump() const { diff --git a/utils/TableGen/CodeGenSchedule.h b/utils/TableGen/CodeGenSchedule.h index 78f115ecd8..e5b9118fb0 100644 --- a/utils/TableGen/CodeGenSchedule.h +++ b/utils/TableGen/CodeGenSchedule.h @@ -125,6 +125,7 @@ struct CodeGenSchedTransition { /// itinerary class. Each inherits the processor index from the ItinRW record /// that mapped the itinerary class to the variant Writes or Reads. struct CodeGenSchedClass { + unsigned Index; std::string Name; Record *ItinClassDef; @@ -141,12 +142,16 @@ struct CodeGenSchedClass { // off to join another inferred class. RecVec InstRWs; - CodeGenSchedClass(): ItinClassDef(0) {} - CodeGenSchedClass(Record *rec): ItinClassDef(rec) { - Name = rec->getName(); - ProcIndices.push_back(0); + CodeGenSchedClass(): Index(0), ItinClassDef(0) {} + + bool isKeyEqual(Record *IC, const IdxVec &W, const IdxVec &R) { + return ItinClassDef == IC && Writes == W && Reads == R; } + // Is this class generated from a variants if existing classes? Instructions + // are never mapped directly to inferred scheduling classes. + bool isInferred() const { return !ItinClassDef; } + #ifndef NDEBUG void dump(const CodeGenSchedModels *SchedModels) const; #endif @@ -189,11 +194,16 @@ struct CodeGenProcModel { // Per-operand machine model resources associated with this processor. RecVec ProcResourceDefs; + RecVec ProcResGroupDefs; CodeGenProcModel(unsigned Idx, const std::string &Name, Record *MDef, Record *IDef) : Index(Idx), ModelName(Name), ModelDef(MDef), ItinsDef(IDef) {} + bool hasItineraries() const { + return !ItinsDef->getValueAsListOfDefs("IID").empty(); + } + bool hasInstrSchedModel() const { return !WriteResDefs.empty() || !ItinRWDefs.empty(); } @@ -227,24 +237,11 @@ class CodeGenSchedModels { // List of unique SchedClasses. std::vector<CodeGenSchedClass> SchedClasses; - // Map SchedClass name to itinerary index. - // These are either explicit itinerary classes or classes implied by - // instruction definitions with SchedReadWrite lists. - StringMap<unsigned> SchedClassIdxMap; - - // SchedClass indices 1 up to and including NumItineraryClasses identify - // itinerary classes that are explicitly used for this target's instruction - // definitions. NoItinerary always has index 0 regardless of whether it is - // explicitly referenced. - // - // Any implied SchedClass has an index greater than NumItineraryClasses. - unsigned NumItineraryClasses; - // Any inferred SchedClass has an index greater than NumInstrSchedClassses. unsigned NumInstrSchedClasses; - // Map Instruction to SchedClass index. Only for Instructions mentioned in - // InstRW records. + // Map each instruction to its unique SchedClass index considering the + // combination of it's itinerary class, SchedRW list, and InstRW records. typedef DenseMap<Record*, unsigned> InstClassMapTy; InstClassMapTy InstrClassMap; @@ -280,6 +277,9 @@ public: ProcIter procModelBegin() const { return ProcModels.begin(); } ProcIter procModelEnd() const { return ProcModels.end(); } + // Return true if any processors have itineraries. + bool hasItineraries() const; + // Get a SchedWrite from its index. const CodeGenSchedRW &getSchedWrite(unsigned Idx) const { assert(Idx < SchedWrites.size() && "bad SchedWrite index"); @@ -311,16 +311,6 @@ public: // Return true if the given write record is referenced by a ReadAdvance. bool hasReadOfWrite(Record *WriteDef) const; - // Check if any instructions are assigned to an explicit itinerary class other - // than NoItinerary. - bool hasItineraryClasses() const { return NumItineraryClasses > 0; } - - // Return the number of itinerary classes in use by this target's instruction - // descriptions, not including "NoItinerary". - unsigned numItineraryClasses() const { - return NumItineraryClasses; - } - // Get a SchedClass from its index. CodeGenSchedClass &getSchedClass(unsigned Idx) { assert(Idx < SchedClasses.size() && "bad SchedClass index"); @@ -336,28 +326,26 @@ public: // for NoItinerary. unsigned getSchedClassIdx(const CodeGenInstruction &Inst) const; - unsigned getSchedClassIdx(const RecVec &RWDefs) const; - - unsigned getSchedClassIdxForItin(const Record *ItinDef) { - return SchedClassIdxMap[ItinDef->getName()]; - } - typedef std::vector<CodeGenSchedClass>::const_iterator SchedClassIter; SchedClassIter schedClassBegin() const { return SchedClasses.begin(); } SchedClassIter schedClassEnd() const { return SchedClasses.end(); } + 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(const IdxVec &OperWrites, const IdxVec &OperReads, - const IdxVec &ProcIndices); + unsigned addSchedClass(Record *ItinDef, const IdxVec &OperWrites, + const IdxVec &OperReads, const IdxVec &ProcIndices); unsigned findOrInsertRW(ArrayRef<unsigned> Seq, bool IsRead); - unsigned findSchedClassIdx(const IdxVec &Writes, const IdxVec &Reads) const; + unsigned findSchedClassIdx(Record *ItinClassDef, + const IdxVec &Writes, + const IdxVec &Reads) const; Record *findProcResUnits(Record *ProcResKind, const CodeGenProcModel &PM) const; @@ -375,7 +363,8 @@ private: void collectSchedClasses(); - std::string createSchedClassName(const IdxVec &OperWrites, + std::string createSchedClassName(Record *ItinClassDef, + const IdxVec &OperWrites, const IdxVec &OperReads); std::string createSchedClassName(const RecVec &InstDefs); void createInstRWClass(Record *InstRWDef); diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index dd3f6e29fd..8b292b9572 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -229,7 +229,7 @@ getRegisterVTs(Record *R) const { for (unsigned i = 0, e = RCs.size(); i != e; ++i) { const CodeGenRegisterClass &RC = *RCs[i]; if (RC.contains(Reg)) { - const std::vector<MVT::SimpleValueType> &InVTs = RC.getValueTypes(); + ArrayRef<MVT::SimpleValueType> InVTs = RC.getValueTypes(); Result.insert(Result.end(), InVTs.begin(), InVTs.end()); } } diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h index 4a1c6d8fcb..6271443029 100644 --- a/utils/TableGen/CodeGenTarget.h +++ b/utils/TableGen/CodeGenTarget.h @@ -68,7 +68,7 @@ class CodeGenTarget { mutable DenseMap<const Record*, CodeGenInstruction*> Instructions; mutable CodeGenRegBank *RegBank; mutable std::vector<Record*> RegAltNameIndices; - mutable std::vector<MVT::SimpleValueType> LegalValueTypes; + mutable SmallVector<MVT::SimpleValueType, 8> LegalValueTypes; void ReadRegAltNameIndices() const; void ReadInstructions() const; void ReadLegalValueTypes() const; @@ -129,7 +129,7 @@ public: /// specified physical register. std::vector<MVT::SimpleValueType> getRegisterVTs(Record *R) const; - const std::vector<MVT::SimpleValueType> &getLegalValueTypes() const { + ArrayRef<MVT::SimpleValueType> getLegalValueTypes() const { if (LegalValueTypes.empty()) ReadLegalValueTypes(); return LegalValueTypes; } @@ -137,7 +137,7 @@ public: /// isLegalValueType - Return true if the specified value type is natively /// supported by the target (i.e. there are registers that directly hold it). bool isLegalValueType(MVT::SimpleValueType VT) const { - const std::vector<MVT::SimpleValueType> &LegalVTs = getLegalValueTypes(); + ArrayRef<MVT::SimpleValueType> LegalVTs = getLegalValueTypes(); for (unsigned i = 0, e = LegalVTs.size(); i != e; ++i) if (LegalVTs[i] == VT) return true; return false; diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp index 38ffa30ec8..ed41631456 100644 --- a/utils/TableGen/DAGISelMatcherGen.cpp +++ b/utils/TableGen/DAGISelMatcherGen.cpp @@ -211,6 +211,12 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) { return AddMatcher(new CheckIntegerMatcher(II->getValue())); } + // An UnsetInit represents a named node without any constraints. + if (N->getLeafValue() == UnsetInit::get()) { + assert(N->hasName() && "Unnamed ? leaf"); + return; + } + DefInit *DI = dyn_cast<DefInit>(N->getLeafValue()); if (DI == 0) { errs() << "Unknown leaf kind: " << *N << "\n"; @@ -218,6 +224,17 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) { } Record *LeafRec = DI->getDef(); + + // A ValueType leaf node can represent a register when named, or itself when + // unnamed. + if (LeafRec->isSubClassOf("ValueType")) { + // A named ValueType leaf always matches: (add i32:$a, i32:$b). + if (N->hasName()) + return; + // An unnamed ValueType as in (sext_inreg GPR:$foo, i8). + return AddMatcher(new CheckValueTypeMatcher(LeafRec->getName())); + } + if (// Handle register references. Nothing to do here, they always match. LeafRec->isSubClassOf("RegisterClass") || LeafRec->isSubClassOf("RegisterOperand") || @@ -236,9 +253,6 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) { return; } - if (LeafRec->isSubClassOf("ValueType")) - return AddMatcher(new CheckValueTypeMatcher(LeafRec->getName())); - if (LeafRec->isSubClassOf("CondCode")) return AddMatcher(new CheckCondCodeMatcher(LeafRec->getName())); @@ -734,20 +748,33 @@ EmitResultInstructionAsOperand(const TreePatternNode *N, continue; } - const TreePatternNode *Child = N->getChild(ChildNo); - // Otherwise this is a normal operand or a predicate operand without // 'execute always'; emit it. - unsigned BeforeAddingNumOps = InstOps.size(); - EmitResultOperand(Child, InstOps); - assert(InstOps.size() > BeforeAddingNumOps && "Didn't add any operands"); - // If the operand is an instruction and it produced multiple results, just - // take the first one. - if (!Child->isLeaf() && Child->getOperator()->isSubClassOf("Instruction")) - InstOps.resize(BeforeAddingNumOps+1); + // For operands with multiple sub-operands we may need to emit + // multiple child patterns to cover them all. However, ComplexPattern + // children may themselves emit multiple MI operands. + unsigned NumSubOps = 1; + if (OperandNode->isSubClassOf("Operand")) { + DagInit *MIOpInfo = OperandNode->getValueAsDag("MIOperandInfo"); + if (unsigned NumArgs = MIOpInfo->getNumArgs()) + NumSubOps = NumArgs; + } - ++ChildNo; + unsigned FinalNumOps = InstOps.size() + NumSubOps; + while (InstOps.size() < FinalNumOps) { + const TreePatternNode *Child = N->getChild(ChildNo); + unsigned BeforeAddingNumOps = InstOps.size(); + EmitResultOperand(Child, InstOps); + assert(InstOps.size() > BeforeAddingNumOps && "Didn't add any operands"); + + // If the operand is an instruction and it produced multiple results, just + // take the first one. + if (!Child->isLeaf() && Child->getOperator()->isSubClassOf("Instruction")) + InstOps.resize(BeforeAddingNumOps+1); + + ++ChildNo; + } } // If this node has input glue or explicitly specified input physregs, we diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp index cf225117e1..1b5d90b8bd 100644 --- a/utils/TableGen/RegisterInfoEmitter.cpp +++ b/utils/TableGen/RegisterInfoEmitter.cpp @@ -1031,7 +1031,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, } // Build a shared array of value types. - SequenceToOffsetTable<std::vector<MVT::SimpleValueType> > VTSeqs; + SequenceToOffsetTable<SmallVector<MVT::SimpleValueType, 4> > VTSeqs; for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) VTSeqs.add(RegisterClasses[rc]->VTs); VTSeqs.layout(); diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index 93eef868ea..98892e1144 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -87,6 +87,8 @@ class SubtargetEmitter { const CodeGenProcModel &ProcModel); Record *FindReadAdvance(const CodeGenSchedRW &SchedRead, const CodeGenProcModel &ProcModel); + void ExpandProcResources(RecVec &PRVec, std::vector<int64_t> &Cycles, + const CodeGenProcModel &ProcModel); void GenSchedClassTables(const CodeGenProcModel &ProcModel, SchedClassTables &SchedTables); void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS); @@ -445,17 +447,15 @@ EmitStageAndOperandCycleData(raw_ostream &OS, // If this processor defines no itineraries, then leave the itinerary list // empty. std::vector<InstrItinerary> &ItinList = ProcItinLists.back(); - if (ProcModel.ItinDefList.empty()) + if (!ProcModel.hasItineraries()) continue; - // Reserve index==0 for NoItinerary. - ItinList.resize(SchedModels.numItineraryClasses()+1); - const std::string &Name = ProcModel.ItinsDef->getName(); - // For each itinerary data - for (unsigned SchedClassIdx = 0, - SchedClassEnd = ProcModel.ItinDefList.size(); + ItinList.resize(SchedModels.numInstrSchedClasses()); + assert(ProcModel.ItinDefList.size() == ItinList.size() && "bad Itins"); + + for (unsigned SchedClassIdx = 0, SchedClassEnd = ItinList.size(); SchedClassIdx < SchedClassEnd; ++SchedClassIdx) { // Next itinerary data @@ -631,13 +631,31 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) { Record *PRDef = ProcModel.ProcResourceDefs[i]; - // Find the SuperIdx - unsigned SuperIdx = 0; Record *SuperDef = 0; - if (PRDef->getValueInit("Super")->isComplete()) { - SuperDef = - SchedModels.findProcResUnits(PRDef->getValueAsDef("Super"), ProcModel); - SuperIdx = ProcModel.getProcResourceIdx(SuperDef); + unsigned SuperIdx = 0; + unsigned NumUnits = 0; + bool IsBuffered = true; + if (PRDef->isSubClassOf("ProcResGroup")) { + RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources"); + for (RecIter RUI = ResUnits.begin(), RUE = ResUnits.end(); + RUI != RUE; ++RUI) { + if (!NumUnits) + IsBuffered = (*RUI)->getValueAsBit("Buffered"); + else if(IsBuffered != (*RUI)->getValueAsBit("Buffered")) + PrintFatalError(PRDef->getLoc(), + "Mixing buffered and unbuffered resources."); + NumUnits += (*RUI)->getValueAsInt("NumUnits"); + } + } + else { + // Find the SuperIdx + if (PRDef->getValueInit("Super")->isComplete()) { + SuperDef = SchedModels.findProcResUnits( + PRDef->getValueAsDef("Super"), ProcModel); + SuperIdx = ProcModel.getProcResourceIdx(SuperDef); + } + NumUnits = PRDef->getValueAsInt("NumUnits"); + IsBuffered = PRDef->getValueAsBit("Buffered"); } // Emit the ProcResourceDesc if (i+1 == e) @@ -645,8 +663,8 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, OS << " {DBGFIELD(\"" << PRDef->getName() << "\") "; if (PRDef->getName().size() < 15) OS.indent(15 - PRDef->getName().size()); - OS << PRDef->getValueAsInt("NumUnits") << ", " << SuperIdx << ", " - << PRDef->getValueAsBit("Buffered") << "}" << Sep << " // #" << i+1; + OS << NumUnits << ", " << SuperIdx << ", " + << IsBuffered << "}" << Sep << " // #" << i+1; if (SuperDef) OS << ", Super=" << SuperDef->getName(); OS << "\n"; @@ -763,6 +781,51 @@ Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead, return ResDef; } +// Expand an explicit list of processor resources into a full list of implied +// resource groups that cover them. +// +// FIXME: Effectively consider a super-resource a group that include all of its +// subresources to allow mixing and matching super-resources and groups. +// +// FIXME: Warn if two overlapping groups don't have a common supergroup. +void SubtargetEmitter::ExpandProcResources(RecVec &PRVec, + std::vector<int64_t> &Cycles, + const CodeGenProcModel &ProcModel) { + // Default to 1 resource cycle. + Cycles.resize(PRVec.size(), 1); + for (unsigned i = 0, e = PRVec.size(); i != e; ++i) { + RecVec SubResources; + if (PRVec[i]->isSubClassOf("ProcResGroup")) { + SubResources = PRVec[i]->getValueAsListOfDefs("Resources"); + std::sort(SubResources.begin(), SubResources.end(), LessRecord()); + } + else { + SubResources.push_back(PRVec[i]); + } + for (RecIter PRI = ProcModel.ProcResourceDefs.begin(), + PRE = ProcModel.ProcResourceDefs.end(); + PRI != PRE; ++PRI) { + if (*PRI == PRVec[i] || !(*PRI)->isSubClassOf("ProcResGroup")) + continue; + RecVec SuperResources = (*PRI)->getValueAsListOfDefs("Resources"); + std::sort(SuperResources.begin(), SuperResources.end(), LessRecord()); + RecIter SubI = SubResources.begin(), SubE = SubResources.end(); + RecIter SuperI = SuperResources.begin(), SuperE = SuperResources.end(); + for ( ; SubI != SubE && SuperI != SuperE; ++SuperI) { + if (*SubI < *SuperI) + break; + else if (*SuperI < *SubI) + continue; + ++SubI; + } + if (SubI == SubE) { + PRVec.push_back(*PRI); + Cycles.push_back(Cycles[i]); + } + } + } +} + // Generate the SchedClass table for this processor and update global // tables. Must be called for each processor in order. void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, @@ -787,7 +850,22 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, SCDesc.ReadAdvanceIdx = 0; // A Variant SchedClass has no resources of its own. - if (!SCI->Transitions.empty()) { + bool HasVariants = false; + for (std::vector<CodeGenSchedTransition>::const_iterator + TI = SCI->Transitions.begin(), TE = SCI->Transitions.end(); + TI != TE; ++TI) { + if (TI->ProcIndices[0] == 0) { + HasVariants = true; + break; + } + IdxIter PIPos = std::find(TI->ProcIndices.begin(), + TI->ProcIndices.end(), ProcModel.Index); + if (PIPos != TI->ProcIndices.end()) { + HasVariants = true; + break; + } + } + if (HasVariants) { SCDesc.NumMicroOps = MCSchedClassDesc::VariantNumMicroOps; continue; } @@ -804,27 +882,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, } IdxVec Writes = SCI->Writes; IdxVec Reads = SCI->Reads; - if (SCI->ItinClassDef) { - assert(SCI->InstRWs.empty() && "ItinClass should not have InstRWs"); - // Check this processor's itinerary class resources. - for (RecIter II = ProcModel.ItinRWDefs.begin(), - IE = ProcModel.ItinRWDefs.end(); II != IE; ++II) { - RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses"); - if (std::find(Matched.begin(), Matched.end(), SCI->ItinClassDef) - != Matched.end()) { - SchedModels.findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), - Writes, Reads); - break; - } - } - if (Writes.empty()) { - DEBUG(dbgs() << ProcModel.ItinsDef->getName() - << " does not have resources for itinerary class " - << SCI->ItinClassDef->getName() << '\n'); - } - } - else if (!SCI->InstRWs.empty()) { - // This class may have a default ReadWrite list which can be overriden by + if (!SCI->InstRWs.empty()) { + // This class has a default ReadWrite list which can be overriden by // InstRW definitions. Record *RWDef = 0; for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end(); @@ -842,6 +901,23 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, Writes, Reads); } } + if (Writes.empty()) { + // Check this processor's itinerary class resources. + for (RecIter II = ProcModel.ItinRWDefs.begin(), + IE = ProcModel.ItinRWDefs.end(); II != IE; ++II) { + RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses"); + if (std::find(Matched.begin(), Matched.end(), SCI->ItinClassDef) + != Matched.end()) { + SchedModels.findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), + Writes, Reads); + break; + } + } + if (Writes.empty()) { + DEBUG(dbgs() << ProcModel.ModelName + << " does not have resources for class " << SCI->Name << '\n'); + } + } // Sum resources across all operand writes. std::vector<MCWriteProcResEntry> WriteProcResources; std::vector<MCWriteLatencyEntry> WriteLatencies; @@ -859,7 +935,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name); // If this Write is not referenced by a ReadAdvance, don't distinguish it // from other WriteLatency entries. - if (!SchedModels.hasReadOfWrite(SchedModels.getSchedWrite(WriteID).TheDef)) { + if (!SchedModels.hasReadOfWrite( + SchedModels.getSchedWrite(WriteID).TheDef)) { WriteID = 0; } WLEntry.WriteResourceID = WriteID; @@ -884,15 +961,15 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources"); std::vector<int64_t> Cycles = WriteRes->getValueAsListOfInts("ResourceCycles"); + + ExpandProcResources(PRVec, Cycles, ProcModel); + for (unsigned PRIdx = 0, PREnd = PRVec.size(); PRIdx != PREnd; ++PRIdx) { MCWriteProcResEntry WPREntry; WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]); assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx"); - if (Cycles.size() > PRIdx) - WPREntry.Cycles = Cycles[PRIdx]; - else - WPREntry.Cycles = 1; + WPREntry.Cycles = Cycles[PRIdx]; // If this resource is already used in this sequence, add the current // entry's cycles so that the same resource appears to be used // serially, rather than multiple parallel uses. This is important for @@ -1075,7 +1152,7 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, // The first class is always invalid. We no way to distinguish it except by // name and position. - assert(SchedModels.getSchedClass(0).Name == "NoItinerary" + assert(SchedModels.getSchedClass(0).Name == "NoInstrModel" && "invalid class not first"); OS << " {DBGFIELD(\"InvalidSchedClass\") " << MCSchedClassDesc::InvalidNumMicroOps @@ -1132,7 +1209,7 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { - SchedModels.schedClassBegin()) << ",\n"; else OS << " 0, 0, 0, 0, // No instruction-level machine model.\n"; - if (SchedModels.hasItineraryClasses()) + if (SchedModels.hasItineraries()) OS << " " << PI->ItinsDef->getName() << ");\n"; else OS << " 0); // No Itinerary\n"; @@ -1189,7 +1266,7 @@ void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { << "#define DBGFIELD(x)\n" << "#endif\n"; - if (SchedModels.hasItineraryClasses()) { + if (SchedModels.hasItineraries()) { std::vector<std::vector<InstrItinerary> > ProcItinLists; // Emit the stage data EmitStageAndOperandCycleData(OS, ProcItinLists); @@ -1230,7 +1307,7 @@ void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName, SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) { if (SCI->Transitions.empty()) continue; - VariantClasses.push_back(SCI - SchedModels.schedClassBegin()); + VariantClasses.push_back(SCI->Index); } if (!VariantClasses.empty()) { OS << " switch (SchedClass) {\n"; @@ -1277,13 +1354,8 @@ void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName, if (*PI == 0) break; } - unsigned SCIdx = 0; - if (SC.ItinClassDef) - SCIdx = SchedModels.getSchedClassIdxForItin(SC.ItinClassDef); - else - SCIdx = SchedModels.findSchedClassIdx(SC.Writes, SC.Reads); - if (SCIdx != *VCI) - OS << " return " << SCIdx << ";\n"; + if (SC.isInferred()) + OS << " return " << SC.Index << ";\n"; OS << " break;\n"; } OS << " };\n"; @@ -1389,7 +1461,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { << Target << "WriteProcResTable, " << Target << "WriteLatencyTable, " << Target << "ReadAdvanceTable, "; - if (SchedModels.hasItineraryClasses()) { + if (SchedModels.hasItineraries()) { OS << '\n'; OS.indent(22); OS << Target << "Stages, " << Target << "OperandCycles, " @@ -1446,7 +1518,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "extern const llvm::MCReadAdvanceEntry " << Target << "ReadAdvanceTable[];\n"; - if (SchedModels.hasItineraryClasses()) { + if (SchedModels.hasItineraries()) { OS << "extern const llvm::InstrStage " << Target << "Stages[];\n"; OS << "extern const unsigned " << Target << "OperandCycles[];\n"; OS << "extern const unsigned " << Target << "ForwardingPaths[];\n"; @@ -1470,7 +1542,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { << Target << "WriteLatencyTable, " << Target << "ReadAdvanceTable, "; OS << '\n'; OS.indent(22); - if (SchedModels.hasItineraryClasses()) { + if (SchedModels.hasItineraries()) { OS << Target << "Stages, " << Target << "OperandCycles, " << Target << "ForwardingPaths, "; diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index 510f2548cd..b5c3ca760d 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -40,7 +40,8 @@ enum ActionType { GenTgtIntrinsic, PrintEnums, PrintSets, - GenOptParserDefs + GenOptParserDefs, + GenCTags }; namespace { @@ -82,6 +83,8 @@ namespace { "Print expanded sets for testing DAG exprs"), clEnumValN(GenOptParserDefs, "gen-opt-parser-defs", "Generate option definitions"), + clEnumValN(GenCTags, "gen-ctags", + "Generate ctags-compatible index"), clEnumValEnd)); cl::opt<std::string> @@ -161,6 +164,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { } break; } + case GenCTags: + EmitCTags(Records, OS); + break; } return false; diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h index cc99092658..28b626e17e 100644 --- a/utils/TableGen/TableGenBackends.h +++ b/utils/TableGen/TableGenBackends.h @@ -75,5 +75,6 @@ void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS); void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS); void EmitMapTable(RecordKeeper &RK, raw_ostream &OS); void EmitOptParser(RecordKeeper &RK, raw_ostream &OS); +void EmitCTags(RecordKeeper &RK, raw_ostream &OS); } // End llvm namespace diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 8471faaaf6..61b9813b06 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -37,14 +37,15 @@ using namespace llvm; MAP(D1, 46) \ MAP(D4, 47) \ MAP(D5, 48) \ - MAP(D8, 49) \ - MAP(D9, 50) \ - MAP(DA, 51) \ - MAP(DB, 52) \ - MAP(DC, 53) \ - MAP(DD, 54) \ - MAP(DE, 55) \ - MAP(DF, 56) + MAP(D6, 49) \ + MAP(D8, 50) \ + MAP(D9, 51) \ + MAP(DA, 52) \ + MAP(DB, 53) \ + MAP(DC, 54) \ + MAP(DD, 55) \ + MAP(DE, 56) \ + MAP(DF, 57) // A clone of X86 since we can't depend on something that is generated. namespace X86Local { diff --git a/utils/TableGen/tdtags b/utils/TableGen/tdtags new file mode 100644 index 0000000000..5214485f4e --- /dev/null +++ b/utils/TableGen/tdtags @@ -0,0 +1,453 @@ +#!/bin/sh +#===-- tdtags - TableGen tags wrapper ---------------------------*- sh -*-===# +# vim:set sts=2 sw=2 et: +#===----------------------------------------------------------------------===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===----------------------------------------------------------------------===# +# +# This is a wrapper script to simplify generating ctags(1)-compatible index +# files for target .td files. Run tdtags -H for more documentation. +# +# For portability, this script is intended to conform to IEEE Std 1003.1-2008. +# +#===----------------------------------------------------------------------===# + +SELF=${0##*/} + +usage() { +cat <<END +Usage: $SELF [ <options> ] tdfile + or: $SELF [ <options> ] -x recipe [arg ...] +OPTIONS + -H Display further help. + -a Append the tags to an existing tags file. + -f <file> Write tags to the specified file (defaults to 'tags'). + -I <dir> Add the directory to the search path for tblgen include files. + -x <recipe> Generate tags file(s) for a common use case: + -q Suppress $TBLGEN error messages. + -v Be verbose; report progress. +END + usage_recipes +} + +usage_recipes() { +cat <<END + all - Generate an index in each directory that contains .td files + in the LLVM source tree. + here - Generate an index for all .td files in the current directory. + recurse - Generate an index in each directory that contains .td files + in and under the current directory. + target [<target> ...] + - Generate a tags file for each specified LLVM code generator + target, or if none are specified, all targets. +END +} + +help() { +cat <<END +NAME + $SELF - generate ctags(1)-compatible index files for tblgen .td source + +SYNOPSIS + $SELF [ options ] -x recipe [arg ...] + $SELF [ options ] [file ...] + +DESCRIPTION + With the '-x' option, $SELF produces one or more tags files for a + particular common use case. See the RECIPES section below for details. + + Without the '-x' option, $SELF provides a ctags(1)-like interface to + $TBLGEN. + +OPTIONS + -a Append newly generated tags to those already in an existing + tags file. Without ths option, any and all existing tags are + replaced. NOTE: When building a mixed tags file, using ${SELF} + for tblgen tags and ctags(1) for other languages, it is best + to run ${SELF} first without '-a', and ctags(1) second with '-a', + because ctags(1) handling is more capable. + -f <file> Use the name <file> for the tags file, rather than the default + "tags". If the <file> is "-", then the tag index is written to + standard output. + -H Display this document. + -I <dir> Add the directory <dir> to the search path for 'include' + statements in tblgen source. + -x Run a canned recipe, rather than operate on specified files. + When '-x' is present, the first non-option argument is the + name of a recipe, and any further arguments are arguments to + that recipe. With no arguments, lists the available recipes. + -q Suppress $TBLGEN error messages. Not all .td files are well- + formed outside a specific context, so recipes will sometimes + produce error messages for certain .td files. These errors + do not affect the indices produced for valid files. + -v Be verbose; report progress. + +RECIPES + $SELF -x all + Produce a tags file in every directory in the LLVM source tree + that contains any .td files. + $SELF -x here + Produce a tags file from .td files in the current directory. + $SELF -x recurse + Produce a tags file in every directory that contains any .td + files, in and under the current directory. + $SELF -x target [<target> ...] + Produce a tags file for each named code generator target, or + if none are named, for all code generator targets. +END +} + +# Temporary file management. +# +# Since SUS sh(1) has no arrays, this script makes extensive use of +# temporary files. The follow are 'global' and used to carry information +# across functions: +# $TMP:D Include directories. +# $TMP:I Included files. +# $TMP:T Top-level files, that are not included by another. +# $TMP:W Directories in which to generate tags (Worklist). +# For portability to OS X, names must not differ only in case. +# +TMP=${TMPDIR:-/tmp}/$SELF:$$ +trap "rm -f $TMP*" 0 +trap exit 1 2 13 15 +>$TMP:D + +td_dump() +{ + if [ $OPT_VERBOSE -gt 1 ] + then + printf '===== %s =====\n' "$1" + cat <"$1" + fi +} + +# Escape the arguments, taken as a whole. +e() { + printf '%s' "$*" | + sed -e "s/'/'\\\\''/g" -e "1s/^/'/" -e "\$s/\$/'/" +} + +# Determine whether the given directory contains at least one .td file. +dir_has_td() { + for i in $1/*.td + do + [ -f "$i" ] && return 0 + done + return 1 +} + +# Partition the supplied list of files, plus any files included from them, +# into two groups: +# $TMP:T Top-level files, that are not included by another. +# $TMP:I Included files. +# Add standard directories to the include paths in $TMP:D if this would +# benefit the any of the included files. +td_prep() { + >$TMP:E + >$TMP:J + for i in *.td + do + [ "x$i" = 'x*.td' ] && return 1 + if [ -f "$i" ] + then + printf '%s\n' "$i" >>$TMP:E + sed -n -e 's/include[[:space:]]"\(.*\)".*/\1/p' <"$i" >>$TMP:J + else + printf >&2 '%s: "%s" not found.\n' "$SELF" "$i" + exit 7 + fi + done + sort -u <$TMP:E >$TMP:X + sort -u <$TMP:J >$TMP:I + # A file that exists but is not included is toplevel. + comm -23 $TMP:X $TMP:I >$TMP:T + td_dump $TMP:T + td_dump $TMP:I + # Check include files. + while read i + do + [ -f "$i" ] && continue + while read d + do + [ -f "$d/$i" ] && break + done <$TMP:D + if [ -z "$d" ] + then + # See whether this include file can be found in a common location. + for d in $LLVM_SRC_ROOT/include \ + $LLVM_SRC_ROOT/tools/clang/include + do + if [ -f "$d/$i" ] + then + printf '%s\n' "$d" >>$TMP:D + break + fi + done + fi + done <$TMP:I + td_dump $TMP:D +} + +# Generate tags for the list of files in $TMP:T. +td_tag() { + # Collect include directories. + inc= + while read d + do + inc="${inc}${inc:+ }$(e "-I=$d")" + done <$TMP:D + + if [ $OPT_VERBOSE -ne 0 ] + then + printf >&2 'In "%s",\n' "$PWD" + fi + + # Generate tags for each file. + n=0 + while read i + do + if [ $OPT_VERBOSE -ne 0 ] + then + printf >&2 ' generating tags from "%s"\n' "$i" + fi + n=$((n + 1)) + t=$(printf '%s:A:%05u' "$TMP" $n) + eval $TBLGEN --gen-ctags $inc "$i" >$t 2>$TMP:F + [ $OPT_NOTBLGENERR -eq 1 ] || cat $TMP:F + done <$TMP:T + + # Add existing tags if requested. + if [ $OPT_APPEND -eq 1 -a -f "$OPT_TAGSFILE" ] + then + if [ $OPT_VERBOSE -ne 0 ] + then + printf >&2 ' and existing tags from "%s"\n' "$OPT_TAGSFILE" + fi + n=$((n + 1)) + t=$(printf '%s:A:%05u' "$TMP" $n) + sed -e '/^!_TAG_/d' <"$OPT_TAGSFILE" | sort -u >$t + fi + + # Merge tags. + if [ $n = 1 ] + then + mv -f "$t" $TMP:M + else + sort -m -u $TMP:A:* >$TMP:M + fi + + # Emit tags. + if [ x${OPT_TAGSFILE}x = x-x ] + then + cat $TMP:M + else + if [ $OPT_VERBOSE -ne 0 ] + then + printf >&2 ' into "%s".\n' "$OPT_TAGSFILE" + fi + mv -f $TMP:M "$OPT_TAGSFILE" + fi +} + +# Generate tags for the current directory. +td_here() { + td_prep + [ -s $TMP:T ] || return 1 + td_tag +} + +# Generate tags for the current directory, and report an error if there are +# no .td files present. +do_here() +{ + if ! td_here + then + printf >&2 '%s: Nothing to do here.\n' "$SELF" + exit 1 + fi +} + +# Generate tags for all .td files under the current directory. +do_recurse() +{ + td_find "$PWD" + td_dirs +} + +# Generate tags for all .td files in LLVM. +do_all() +{ + td_find "$LLVM_SRC_ROOT" + td_dirs +} + +# Generate tags for each directory in the worklist $TMP:W. +td_dirs() +{ + while read d + do + (cd "$d" && td_here) + done <$TMP:W +} + +# Find directories containing .td files within the specified directory, +# and record them in the worklist $TMP:W. +td_find() +{ + find -L "$1" -type f -name '*.td' | + sed -e 's:/[^/]*$::' | + sort -u >$TMP:W + td_dump $TMP:W +} + +# Generate tags for the specified code generator targets, or +# if there are no arguments, all targets. +do_targets() { + cd $LLVM_SRC_ROOT/lib/Target + if [ -z "$*" ] + then + td_find "$PWD" + else + # Check that every specified argument is a target directory; + # if not, list all target directories. + for d + do + if [ -d "$d" ] && dir_has_td "$d" + then + printf '%s/%s\n' "$PWD" "$d" + else + printf >&2 '%s: "%s" is not a target. Targets are:\n' "$SELF" "$d" + for d in * + do + [ -d "$d" ] || continue + dir_has_td "$d" && printf >&2 ' %s\n' "$d" + done + exit 2 + fi + done >$TMP:W + fi + td_dirs +} + +# Change to the directory at the top of the enclosing LLVM source tree, +# if possible. +llvm_src_root() { + while [ "$PWD" != / ] + do + # Use this directory if multiple notable subdirectories are present. + [ -d include/llvm -a -d lib/Target ] && return 0 + cd .. + done + return 1 +} + +# Ensure sort(1) behaves consistently. +LC_ALL=C +export LC_ALL + +# Globals. +TBLGEN=llvm-tblgen +LLVM_SRC_ROOT= + +# Command options. +OPT_TAGSFILE=tags +OPT_RECIPES=0 +OPT_APPEND=0 +OPT_VERBOSE=0 +OPT_NOTBLGENERR=0 + +while getopts 'af:hxqvHI:' opt +do + case $opt in + a) + OPT_APPEND=1 + ;; + f) + OPT_TAGSFILE="$OPTARG" + ;; + x) + OPT_RECIPES=1 + ;; + q) + OPT_NOTBLGENERR=1 + ;; + v) + OPT_VERBOSE=$((OPT_VERBOSE + 1)) + ;; + I) + printf '%s\n' "$OPTARG" >>$TMP:D + ;; + [hH]) + help + exit 0 + ;; + *) + usage >&2 + exit 4 + ;; + esac +done +shift $((OPTIND - 1)) + +# Handle the case where tdtags is a simple ctags(1)-like wrapper for tblgen. +if [ $OPT_RECIPES -eq 0 ] +then + if [ -z "$*" ] + then + help >&2 + exit 5 + fi + for i + do + printf '%s\n' "$i" + done >$TMP:T + td_tag + exit $? +fi + +# Find the directory at the top of the enclosing LLVM source tree. +if ! LLVM_SRC_ROOT=$(llvm_src_root && pwd) +then + printf >&2 '%s: Run from within the LLVM source tree.\n' "$SELF" + exit 3 +fi + +# Select canned actions. +RECIPE="$1" +case "$RECIPE" in +all) + shift + do_all + ;; +.|cwd|here) + shift + do_here + ;; +recurse) + shift + do_recurse + ;; +target) + shift + do_targets "$@" + ;; +*) + if [ -n "$RECIPE" ] + then + shift + printf >&2 '%s: Unknown recipe "-x %s". ' "$SELF" "$RECIPE" + fi + printf >&2 'Recipes:\n' + usage_recipes >&2 + printf >&2 'Run "%s -H" for help.\n' "$SELF" + exit 6 + ;; +esac + +exit $? diff --git a/utils/lit/lit/TestFormats.py b/utils/lit/lit/TestFormats.py index a272976ca0..26541f183b 100644 --- a/utils/lit/lit/TestFormats.py +++ b/utils/lit/lit/TestFormats.py @@ -97,6 +97,9 @@ class GoogleTest(object): if litConfig.useValgrind: cmd = litConfig.valgrindArgs + cmd + if litConfig.noExecute: + return Test.PASS, '' + out, err, exitCode = TestRunner.executeCommand( cmd, env=test.config.environment) diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index 07fb43f840..84176996a8 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -277,7 +277,10 @@ def executeScript(test, litConfig, tmpBase, commands, cwd): script += '.bat' # Write script file - f = open(script,'w') + mode = 'w' + if litConfig.isWindows and not isWin32CMDEXE: + mode += 'b' # Avoid CRLFs when writing bash scripts. + f = open(script, mode) if isWin32CMDEXE: f.write('\nif %ERRORLEVEL% NEQ 0 EXIT\n'.join(commands)) else: |