diff options
Diffstat (limited to 'utils/TableGen')
41 files changed, 1663 insertions, 1307 deletions
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 6e9a9484dc88..76228e0b6581 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -112,10 +112,10 @@ #include "llvm/TableGen/TableGenBackend.h" #include <cassert> #include <cctype> +#include <forward_list> #include <map> #include <set> -#include <sstream> -#include <forward_list> + using namespace llvm; #define DEBUG_TYPE "asm-matcher-emitter" @@ -199,6 +199,14 @@ struct ClassInfo { /// For custom match classes: the diagnostic kind for when the predicate fails. std::string DiagnosticType; + + /// Is this operand optional and not always required. + bool IsOptional; + + /// DefaultMethod - The name of the method that returns the default operand + /// for optional operand + std::string DefaultMethod; + public: /// isRegisterClass() - Check if this is a register class. bool isRegisterClass() const { @@ -263,34 +271,79 @@ public: return false; } - /// operator< - Compare two classes. - // FIXME: This ordering seems to be broken. For example: - // u64 < i64, i64 < s8, s8 < u64, forming a cycle - // u64 is a subset of i64 - // i64 and s8 are not subsets of each other, so are ordered by name - // s8 and u64 are not subsets of each other, so are ordered by name + int getTreeDepth() const { + int Depth = 0; + const ClassInfo *Root = this; + while (!Root->SuperClasses.empty()) { + Depth++; + Root = Root->SuperClasses.front(); + } + return Depth; + } + + const ClassInfo *findRoot() const { + const ClassInfo *Root = this; + while (!Root->SuperClasses.empty()) + Root = Root->SuperClasses.front(); + return Root; + } + + /// Compare two classes. This does not produce a total ordering, but does + /// guarantee that subclasses are sorted before their parents, and that the + /// ordering is transitive. bool operator<(const ClassInfo &RHS) const { if (this == &RHS) return false; - // Unrelated classes can be ordered by kind. - if (!isRelatedTo(RHS)) - return Kind < RHS.Kind; - - switch (Kind) { - case Invalid: - llvm_unreachable("Invalid kind!"); - - default: - // This class precedes the RHS if it is a proper subset of the RHS. - if (isSubsetOf(RHS)) + // First, enforce the ordering between the three different types of class. + // Tokens sort before registers, which sort before user classes. + if (Kind == Token) { + if (RHS.Kind != Token) return true; - if (RHS.isSubsetOf(*this)) + assert(RHS.Kind == Token); + } else if (isRegisterClass()) { + if (RHS.Kind == Token) return false; + else if (RHS.isUserClass()) + return true; + assert(RHS.isRegisterClass()); + } else if (isUserClass()) { + if (!RHS.isUserClass()) + return false; + assert(RHS.isUserClass()); + } else { + llvm_unreachable("Unknown ClassInfoKind"); + } - // Otherwise, order by name to ensure we have a total ordering. - return ValueName < RHS.ValueName; + if (Kind == Token || isUserClass()) { + // Related tokens and user classes get sorted by depth in the inheritence + // tree (so that subclasses are before their parents). + if (isRelatedTo(RHS)) { + if (getTreeDepth() > RHS.getTreeDepth()) + return true; + if (getTreeDepth() < RHS.getTreeDepth()) + return false; + } else { + // Unrelated tokens and user classes are ordered by the name of their + // root nodes, so that there is a consistent ordering between + // unconnected trees. + return findRoot()->ValueName < RHS.findRoot()->ValueName; + } + } else if (isRegisterClass()) { + // For register sets, sort by number of registers. This guarantees that + // a set will always sort before all of it's strict supersets. + if (Registers.size() != RHS.Registers.size()) + return Registers.size() < RHS.Registers.size(); + } else { + llvm_unreachable("Unknown ClassInfoKind"); } + + // FIXME: We should be able to just return false here, as we only need a + // partial order (we use stable sorts, so this is deterministic) and the + // name of a class shouldn't be significant. However, some of the backends + // accidentally rely on this behaviour, so it will have to stay like this + // until they are fixed. + return ValueName < RHS.ValueName; } }; @@ -526,8 +579,8 @@ struct MatchableInfo { /// operator< - Compare two matchables. bool operator<(const MatchableInfo &RHS) const { // The primary comparator is the instruction mnemonic. - if (Mnemonic != RHS.Mnemonic) - return Mnemonic < RHS.Mnemonic; + if (int Cmp = Mnemonic.compare(RHS.Mnemonic)) + return Cmp == -1; if (AsmOperands.size() != RHS.AsmOperands.size()) return AsmOperands.size() < RHS.AsmOperands.size(); @@ -637,7 +690,6 @@ struct OperandMatchEntry { } }; - class AsmMatcherInfo { public: /// Tracked Records @@ -720,9 +772,15 @@ public: RecordKeeper &getRecords() const { return Records; } + + bool hasOptionalOperands() const { + return std::find_if(Classes.begin(), Classes.end(), + [](const ClassInfo& Class){ return Class.IsOptional; }) + != Classes.end(); + } }; -} // End anonymous namespace +} // end anonymous namespace void MatchableInfo::dump() const { errs() << TheDef->getName() << " -- " << "flattened:\"" << AsmString <<"\"\n"; @@ -833,7 +891,6 @@ extractSingletonRegisterForAsmOperand(MatchableInfo::AsmOperand &Op, // If there is no register prefix (i.e. "%" in "%eax"), then this may // be some random non-register token, just ignore it. - return; } void MatchableInfo::initialize(const AsmMatcherInfo &Info, @@ -1071,6 +1128,8 @@ ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) { Entry->RenderMethod = "<invalid>"; Entry->ParserMethod = ""; Entry->DiagnosticType = ""; + Entry->IsOptional = false; + Entry->DefaultMethod = "<invalid>"; } return Entry; @@ -1111,7 +1170,6 @@ AsmMatcherInfo::getOperandClass(Record *Rec, int SubOpIdx) { PrintFatalError(Rec->getLoc(), "register class has no class info!"); } - if (Rec->isSubClassOf("RegisterClass")) { if (ClassInfo *CI = RegisterClassClasses[Rec]) return CI; @@ -1206,6 +1264,8 @@ buildRegisterClasses(SmallPtrSetImpl<Record*> &SingletonRegisters) { CI->Registers = RS; // FIXME: diagnostic type. CI->DiagnosticType = ""; + CI->IsOptional = false; + CI->DefaultMethod = ""; // unused RegisterSetClasses.insert(std::make_pair(RS, CI)); ++Index; } @@ -1320,6 +1380,19 @@ void AsmMatcherInfo::buildOperandClasses() { if (StringInit *SI = dyn_cast<StringInit>(DiagnosticType)) CI->DiagnosticType = SI->getValue(); + Init *IsOptional = Rec->getValueInit("IsOptional"); + if (BitInit *BI = dyn_cast<BitInit>(IsOptional)) + CI->IsOptional = BI->getValue(); + + // Get or construct the default method name. + Init *DMName = Rec->getValueInit("DefaultMethod"); + if (StringInit *SI = dyn_cast<StringInit>(DMName)) { + CI->DefaultMethod = SI->getValue(); + } else { + assert(isa<UnsetInit>(DMName) && "Unexpected DefaultMethod field!"); + CI->DefaultMethod = "default" + CI->ClassName + "Operands"; + } + ++Index; } } @@ -1400,7 +1473,7 @@ void AsmMatcherInfo::buildInfo() { AsmVariant->getValueAsString("BreakCharacters"); Variant.AsmVariantNo = AsmVariant->getValueAsInt("Variant"); - for (const CodeGenInstruction *CGI : Target.instructions()) { + for (const CodeGenInstruction *CGI : Target.getInstructionsByEnumValue()) { // If the tblgen -match-prefix option is specified (for tblgen hackers), // filter the set of instructions we consider. @@ -1539,6 +1612,16 @@ void AsmMatcherInfo::buildInfo() { // Reorder classes so that classes precede super classes. Classes.sort(); + +#ifndef NDEBUG + // Verify that the table is now sorted + for (auto I = Classes.begin(), E = Classes.end(); I != E; ++I) { + for (auto J = I; J != E; ++J) { + assert(!(*J < *I)); + assert(I == J || !J->isSubsetOf(*I)); + } + } +#endif // NDEBUG } /// buildInstructionOperandReference - The specified operand is a reference to a @@ -1744,10 +1827,10 @@ static unsigned getConverterOperandID(const std::string &Name, return ID; } - static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, std::vector<std::unique_ptr<MatchableInfo>> &Infos, - bool HasMnemonicFirst, raw_ostream &OS) { + bool HasMnemonicFirst, bool HasOptionalOperands, + raw_ostream &OS) { SmallSetVector<std::string, 16> OperandConversionKinds; SmallSetVector<std::string, 16> InstructionConversionKinds; std::vector<std::vector<uint8_t> > ConversionTable; @@ -1762,24 +1845,40 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, std::string ConvertFnBody; raw_string_ostream CvtOS(ConvertFnBody); // Start the unified conversion function. - CvtOS << "void " << Target.getName() << ClassName << "::\n" - << "convertToMCInst(unsigned Kind, MCInst &Inst, " - << "unsigned Opcode,\n" - << " const OperandVector" - << " &Operands) {\n" - << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n" - << " const uint8_t *Converter = ConversionTable[Kind];\n" - << " Inst.setOpcode(Opcode);\n" - << " for (const uint8_t *p = Converter; *p; p+= 2) {\n" - << " switch (*p) {\n" - << " default: llvm_unreachable(\"invalid conversion entry!\");\n" - << " case CVT_Reg:\n" - << " static_cast<" << TargetOperandClass - << "&>(*Operands[*(p + 1)]).addRegOperands(Inst, 1);\n" - << " break;\n" - << " case CVT_Tied:\n" - << " Inst.addOperand(Inst.getOperand(*(p + 1)));\n" - << " break;\n"; + if (HasOptionalOperands) { + CvtOS << "void " << Target.getName() << ClassName << "::\n" + << "convertToMCInst(unsigned Kind, MCInst &Inst, " + << "unsigned Opcode,\n" + << " const OperandVector &Operands,\n" + << " const SmallBitVector &OptionalOperandsMask) {\n"; + } else { + CvtOS << "void " << Target.getName() << ClassName << "::\n" + << "convertToMCInst(unsigned Kind, MCInst &Inst, " + << "unsigned Opcode,\n" + << " const OperandVector &Operands) {\n"; + } + CvtOS << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n"; + CvtOS << " const uint8_t *Converter = ConversionTable[Kind];\n"; + if (HasOptionalOperands) { + CvtOS << " unsigned NumDefaults = 0;\n"; + } + CvtOS << " unsigned OpIdx;\n"; + CvtOS << " Inst.setOpcode(Opcode);\n"; + CvtOS << " for (const uint8_t *p = Converter; *p; p+= 2) {\n"; + if (HasOptionalOperands) { + CvtOS << " OpIdx = *(p + 1) - NumDefaults;\n"; + } else { + CvtOS << " OpIdx = *(p + 1);\n"; + } + CvtOS << " switch (*p) {\n"; + CvtOS << " default: llvm_unreachable(\"invalid conversion entry!\");\n"; + CvtOS << " case CVT_Reg:\n"; + CvtOS << " static_cast<" << TargetOperandClass + << "&>(*Operands[OpIdx]).addRegOperands(Inst, 1);\n"; + CvtOS << " break;\n"; + CvtOS << " case CVT_Tied:\n"; + CvtOS << " Inst.addOperand(Inst.getOperand(OpIdx));\n"; + CvtOS << " break;\n"; std::string OperandFnBody; raw_string_ostream OpOS(OperandFnBody); @@ -1873,6 +1972,11 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, // the index of its entry in the vector). std::string Name = "CVT_" + (Op.Class->isRegisterClass() ? "Reg" : Op.Class->RenderMethod); + if (Op.Class->IsOptional) { + // For optional operands we must also care about DefaultMethod + assert(HasOptionalOperands); + Name += "_" + Op.Class->DefaultMethod; + } Name = getEnumNameForToken(Name); bool IsNewConverter = false; @@ -1888,11 +1992,27 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, // This is a new operand kind. Add a handler for it to the // converter driver. - CvtOS << " case " << Name << ":\n" - << " static_cast<" << TargetOperandClass - << "&>(*Operands[*(p + 1)])." << Op.Class->RenderMethod - << "(Inst, " << OpInfo.MINumOperands << ");\n" - << " break;\n"; + CvtOS << " case " << Name << ":\n"; + if (Op.Class->IsOptional) { + // If optional operand is not present in actual instruction then we + // should call its DefaultMethod before RenderMethod + assert(HasOptionalOperands); + CvtOS << " if (OptionalOperandsMask[*(p + 1) - 1]) {\n" + << " " << Op.Class->DefaultMethod << "()" + << "->" << Op.Class->RenderMethod << "(Inst, " + << OpInfo.MINumOperands << ");\n" + << " ++NumDefaults;\n" + << " } else {\n" + << " static_cast<" << TargetOperandClass + << "&>(*Operands[OpIdx])." << Op.Class->RenderMethod + << "(Inst, " << OpInfo.MINumOperands << ");\n" + << " }\n"; + } else { + CvtOS << " static_cast<" << TargetOperandClass + << "&>(*Operands[OpIdx])." << Op.Class->RenderMethod + << "(Inst, " << OpInfo.MINumOperands << ");\n"; + } + CvtOS << " break;\n"; // Add a handler for the operand number lookup. OpOS << " case " << Name << ":\n" @@ -2015,7 +2135,6 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, OS << " CVT_NUM_SIGNATURES\n"; OS << "};\n\n"; - OS << "} // end anonymous namespace\n\n"; // Output the conversion table. @@ -2051,6 +2170,7 @@ static void emitMatchClassEnumeration(CodeGenTarget &Target, << "/// instruction matching.\n"; OS << "enum MatchClassKind {\n"; OS << " InvalidMatchClass = 0,\n"; + OS << " OptionalMatchClass = 1,\n"; for (const auto &CI : Infos) { OS << " " << CI.Name << ", // "; if (CI.Kind == ClassInfo::Token) { @@ -2091,19 +2211,23 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info, // Check the user classes. We don't care what order since we're only // actually matching against one of them. + OS << " switch (Kind) {\n" + " default: break;\n"; for (const auto &CI : Info.Classes) { if (!CI.isUserClass()) continue; OS << " // '" << CI.ClassName << "' class\n"; - OS << " if (Kind == " << CI.Name << ") {\n"; + OS << " case " << CI.Name << ":\n"; OS << " if (Operand." << CI.PredicateMethod << "())\n"; OS << " return MCTargetAsmParser::Match_Success;\n"; if (!CI.DiagnosticType.empty()) OS << " return " << Info.Target.getName() << "AsmParser::Match_" << CI.DiagnosticType << ";\n"; - OS << " }\n\n"; + else + OS << " break;\n"; } + OS << " } // end switch (Kind)\n\n"; // Check for register operands, including sub-classes. OS << " if (Operand.isReg()) {\n"; @@ -2137,6 +2261,8 @@ static void emitIsSubclass(CodeGenTarget &Target, bool EmittedSwitch = false; for (const auto &A : Infos) { std::vector<StringRef> SuperClasses; + if (A.IsOptional) + SuperClasses.push_back("OptionalMatchClass"); for (const auto &B : Infos) { if (&A != &B && A.isSubsetOf(B)) SuperClasses.push_back(B.Name); @@ -2225,6 +2351,37 @@ static void emitMatchRegisterName(CodeGenTarget &Target, Record *AsmParser, OS << "}\n\n"; } +/// Emit the function to match a string to the target +/// specific register enum. +static void emitMatchRegisterAltName(CodeGenTarget &Target, Record *AsmParser, + raw_ostream &OS) { + // Construct the match list. + std::vector<StringMatcher::StringPair> Matches; + const auto &Regs = Target.getRegBank().getRegisters(); + for (const CodeGenRegister &Reg : Regs) { + + auto AltNames = Reg.TheDef->getValueAsListOfStrings("AltNames"); + + for (auto AltName : AltNames) { + AltName = StringRef(AltName).trim(); + + // don't handle empty alternative names + if (AltName.empty()) + continue; + + Matches.emplace_back(AltName, + "return " + utostr(Reg.EnumValue) + ";"); + } + } + + OS << "static unsigned MatchRegisterAltName(StringRef Name) {\n"; + + StringMatcher("Name", Matches, OS).Emit(); + + OS << " return 0;\n"; + OS << "}\n\n"; +} + static const char *getMinimalTypeForRange(uint64_t Range) { assert(Range <= 0xFFFFFFFFFFFFFFFFULL && "Enum too large"); if (Range > 0xFFFFFFFFULL) @@ -2665,6 +2822,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { const std::unique_ptr<MatchableInfo> &b){ return *a < *b;}); +#ifndef NDEBUG + // Verify that the table is now sorted + for (auto I = Info.Matchables.begin(), E = Info.Matchables.end(); I != E; + ++I) { + for (auto J = I; J != E; ++J) { + assert(!(**J < **I)); + } + } +#endif // NDEBUG + DEBUG_WITH_TYPE("instruction_info", { for (const auto &MI : Info.Matchables) MI->dump(); @@ -2698,6 +2865,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { Info.buildOperandMatchInfo(); bool HasMnemonicFirst = AsmParser->getValueAsBit("HasMnemonicFirst"); + bool HasOptionalOperands = Info.hasOptionalOperands(); // Write the output. @@ -2707,10 +2875,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " // This should be included into the middle of the declaration of\n"; OS << " // your subclasses implementation of MCTargetAsmParser.\n"; OS << " uint64_t ComputeAvailableFeatures(const FeatureBitset& FB) const;\n"; - OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, " - << "unsigned Opcode,\n" - << " const OperandVector " - << "&Operands);\n"; + if (HasOptionalOperands) { + OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, " + << "unsigned Opcode,\n" + << " const OperandVector &Operands,\n" + << " const SmallBitVector &OptionalOperandsMask);\n"; + } else { + OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, " + << "unsigned Opcode,\n" + << " const OperandVector &Operands);\n"; + } OS << " void convertToMapAndConstraints(unsigned Kind,\n "; OS << " const OperandVector &Operands) override;\n"; if (HasMnemonicFirst) @@ -2744,7 +2918,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { emitOperandDiagnosticTypes(Info, OS); OS << "#endif // GET_OPERAND_DIAGNOSTIC_TYPES\n\n"; - OS << "\n#ifdef GET_REGISTER_MATCHER\n"; OS << "#undef GET_REGISTER_MATCHER\n\n"; @@ -2756,6 +2929,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { if (AsmParser->getValueAsBit("ShouldEmitMatchRegisterName")) emitMatchRegisterName(Target, AsmParser, OS); + if (AsmParser->getValueAsBit("ShouldEmitMatchRegisterAltName")) + emitMatchRegisterAltName(Target, AsmParser, OS); + OS << "#endif // GET_REGISTER_MATCHER\n\n"; OS << "\n#ifdef GET_SUBTARGET_FEATURE_NAME\n"; @@ -2775,7 +2951,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // Generate the convertToMCInst function to convert operands into an MCInst. // Also, generate the convertToMapAndConstraints function for MS-style inline // assembly. The latter doesn't actually generate a MCInst. - emitConvertFuncs(Target, ClassName, Info.Matchables, HasMnemonicFirst, OS); + emitConvertFuncs(Target, ClassName, Info.Matchables, HasMnemonicFirst, + HasOptionalOperands, OS); // Emit the enumeration for classes which participate in matching. emitMatchClassEnumeration(Target, Info.Classes, OS); @@ -2792,7 +2969,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // Emit the available features compute function. emitComputeAvailableFeatures(Info, OS); - StringToOffsetTable StringTable; size_t MaxNumOperands = 0; @@ -2958,6 +3134,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " bool HadMatchOtherThanPredicate = false;\n"; OS << " unsigned RetCode = Match_InvalidOperand;\n"; OS << " uint64_t MissingFeatures = ~0ULL;\n"; + if (HasOptionalOperands) { + OS << " SmallBitVector OptionalOperandsMask(" << MaxNumOperands << ");\n"; + } OS << " // Set ErrorInfo to the operand that mismatches if it is\n"; OS << " // wrong for all instances of the instruction.\n"; OS << " ErrorInfo = ~0ULL;\n"; @@ -3002,36 +3181,55 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // Emit check that the subclasses match. OS << " bool OperandsValid = true;\n"; - OS << " for (unsigned i = " << (HasMnemonicFirst ? "0" : "SIndex") - << "; i != " << MaxNumOperands << "; ++i) {\n"; - OS << " auto Formal = static_cast<MatchClassKind>(it->Classes[i]);\n"; - OS << " if (i" << (HasMnemonicFirst ? "+1" : "") - << " >= Operands.size()) {\n"; - OS << " OperandsValid = (Formal == " <<"InvalidMatchClass);\n"; - OS << " if (!OperandsValid) ErrorInfo = i" - << (HasMnemonicFirst ? "+1" : "") << ";\n"; + if (HasOptionalOperands) { + OS << " OptionalOperandsMask.reset(0, " << MaxNumOperands << ");\n"; + } + OS << " for (unsigned FormalIdx = " << (HasMnemonicFirst ? "0" : "SIndex") + << ", ActualIdx = " << (HasMnemonicFirst ? "1" : "SIndex") + << "; FormalIdx != " << MaxNumOperands << "; ++FormalIdx) {\n"; + OS << " auto Formal = " + << "static_cast<MatchClassKind>(it->Classes[FormalIdx]);\n"; + OS << " if (ActualIdx >= Operands.size()) {\n"; + OS << " OperandsValid = (Formal == " <<"InvalidMatchClass) || " + "isSubclass(Formal, OptionalMatchClass);\n"; + OS << " if (!OperandsValid) ErrorInfo = ActualIdx;\n"; + if (HasOptionalOperands) { + OS << " OptionalOperandsMask.set(FormalIdx, " << MaxNumOperands + << ");\n"; + } OS << " break;\n"; OS << " }\n"; - OS << " MCParsedAsmOperand &Actual = *Operands[i" - << (HasMnemonicFirst ? "+1" : "") << "];\n"; + OS << " MCParsedAsmOperand &Actual = *Operands[ActualIdx];\n"; OS << " unsigned Diag = validateOperandClass(Actual, Formal);\n"; - OS << " if (Diag == Match_Success)\n"; + OS << " if (Diag == Match_Success) {\n"; + OS << " ++ActualIdx;\n"; OS << " continue;\n"; + OS << " }\n"; OS << " // If the generic handler indicates an invalid operand\n"; OS << " // failure, check for a special case.\n"; OS << " if (Diag == Match_InvalidOperand) {\n"; OS << " Diag = validateTargetOperandClass(Actual, Formal);\n"; - OS << " if (Diag == Match_Success)\n"; + OS << " if (Diag == Match_Success) {\n"; + OS << " ++ActualIdx;\n"; OS << " continue;\n"; + OS << " }\n"; + OS << " }\n"; + OS << " // If current formal operand wasn't matched and it is optional\n" + << " // then try to match next formal operand\n"; + OS << " if (Diag == Match_InvalidOperand " + << "&& isSubclass(Formal, OptionalMatchClass)) {\n"; + if (HasOptionalOperands) { + OS << " OptionalOperandsMask.set(FormalIdx);\n"; + } + OS << " continue;\n"; OS << " }\n"; OS << " // If this operand is broken for all of the instances of this\n"; OS << " // mnemonic, keep track of it so we can report loc info.\n"; OS << " // If we already had a match that only failed due to a\n"; OS << " // target predicate, that diagnostic is preferred.\n"; OS << " if (!HadMatchOtherThanPredicate &&\n"; - OS << " (it == MnemonicRange.first || ErrorInfo <= i" - << (HasMnemonicFirst ? "+1" : "") << ")) {\n"; - OS << " ErrorInfo = i" << (HasMnemonicFirst ? "+1" : "") << ";\n"; + OS << " (it == MnemonicRange.first || ErrorInfo <= ActualIdx)) {\n"; + OS << " ErrorInfo = ActualIdx;\n"; OS << " // InvalidOperand is the default. Prefer specificity.\n"; OS << " if (Diag != Match_InvalidOperand)\n"; OS << " RetCode = Diag;\n"; @@ -3063,7 +3261,12 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " }\n\n"; OS << " // We have selected a definite instruction, convert the parsed\n" << " // operands into the appropriate MCInst.\n"; - OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\n"; + if (HasOptionalOperands) { + OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands,\n" + << " OptionalOperandsMask);\n"; + } else { + OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\n"; + } OS << "\n"; // Verify the instruction with the target-specific match predicate function. @@ -3118,4 +3321,4 @@ void EmitAsmMatcher(RecordKeeper &RK, raw_ostream &OS) { AsmMatcherEmitter(RK).run(OS); } -} // End llvm namespace +} // end namespace llvm diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp index cf7cbd962865..fc2138f7e8ea 100644 --- a/utils/TableGen/AsmWriterEmitter.cpp +++ b/utils/TableGen/AsmWriterEmitter.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This tablegen backend is emits an assembly printer for the current target. +// This tablegen backend emits an assembly printer for the current target. // Note that this is currently fairly skeletal, but will grow over time. // //===----------------------------------------------------------------------===// @@ -27,6 +27,7 @@ #include <algorithm> #include <cassert> #include <map> +#include <utility> #include <vector> using namespace llvm; @@ -36,10 +37,8 @@ namespace { class AsmWriterEmitter { RecordKeeper &Records; CodeGenTarget Target; - std::map<const CodeGenInstruction*, AsmWriterInst*> CGIAWIMap; - const std::vector<const CodeGenInstruction*> *NumberedInstructions; + ArrayRef<const CodeGenInstruction *> NumberedInstructions; std::vector<AsmWriterInst> Instructions; - std::vector<std::string> PrintMethods; public: AsmWriterEmitter(RecordKeeper &R); @@ -50,21 +49,16 @@ private: void EmitGetRegisterName(raw_ostream &o); void EmitPrintAliasInstruction(raw_ostream &O); - AsmWriterInst *getAsmWriterInstByID(unsigned ID) const { - assert(ID < NumberedInstructions->size()); - std::map<const CodeGenInstruction*, AsmWriterInst*>::const_iterator I = - CGIAWIMap.find(NumberedInstructions->at(ID)); - assert(I != CGIAWIMap.end() && "Didn't find inst!"); - return I->second; - } void FindUniqueOperandCommands(std::vector<std::string> &UOC, - std::vector<unsigned> &InstIdxs, - std::vector<unsigned> &InstOpsUsed) const; + std::vector<std::vector<unsigned>> &InstIdxs, + std::vector<unsigned> &InstOpsUsed, + bool PassSubtarget) const; }; } // end anonymous namespace static void PrintCases(std::vector<std::pair<std::string, - AsmWriterOperand> > &OpsToPrint, raw_ostream &O) { + AsmWriterOperand> > &OpsToPrint, raw_ostream &O, + bool PassSubtarget) { O << " case " << OpsToPrint.back().first << ":"; AsmWriterOperand TheOp = OpsToPrint.back().second; OpsToPrint.pop_back(); @@ -78,7 +72,7 @@ static void PrintCases(std::vector<std::pair<std::string, } // Finally, emit the code. - O << "\n " << TheOp.getCode(); + O << "\n " << TheOp.getCode(PassSubtarget); O << "\n break;\n"; } @@ -86,7 +80,7 @@ static void PrintCases(std::vector<std::pair<std::string, /// EmitInstructions - Emit the last instruction in the vector and any other /// instructions that are suitably similar to it. static void EmitInstructions(std::vector<AsmWriterInst> &Insts, - raw_ostream &O) { + raw_ostream &O, bool PassSubtarget) { AsmWriterInst FirstInst = Insts.back(); Insts.pop_back(); @@ -115,7 +109,7 @@ static void EmitInstructions(std::vector<AsmWriterInst> &Insts, for (unsigned i = 0, e = FirstInst.Operands.size(); i != e; ++i) { if (i != DifferingOperand) { // If the operand is the same for all instructions, just print it. - O << " " << FirstInst.Operands[i].getCode(); + O << " " << FirstInst.Operands[i].getCode(PassSubtarget); } else { // If this is the operand that varies between all of the instructions, // emit a switch for just this operand now. @@ -133,7 +127,7 @@ static void EmitInstructions(std::vector<AsmWriterInst> &Insts, } std::reverse(OpsToPrint.begin(), OpsToPrint.end()); while (!OpsToPrint.empty()) - PrintCases(OpsToPrint, O); + PrintCases(OpsToPrint, O, PassSubtarget); O << " }"; } O << "\n"; @@ -143,9 +137,9 @@ static void EmitInstructions(std::vector<AsmWriterInst> &Insts, void AsmWriterEmitter:: FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, - std::vector<unsigned> &InstIdxs, - std::vector<unsigned> &InstOpsUsed) const { - InstIdxs.assign(NumberedInstructions->size(), ~0U); + std::vector<std::vector<unsigned>> &InstIdxs, + std::vector<unsigned> &InstOpsUsed, + bool PassSubtarget) const { // This vector parallels UniqueOperandCommands, keeping track of which // instructions each case are used for. It is a comma separated string of @@ -154,31 +148,27 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, InstrsForCase.resize(UniqueOperandCommands.size()); InstOpsUsed.assign(UniqueOperandCommands.size(), 0); - for (unsigned i = 0, e = NumberedInstructions->size(); i != e; ++i) { - const AsmWriterInst *Inst = getAsmWriterInstByID(i); - if (!Inst) - continue; // PHI, INLINEASM, CFI_INSTRUCTION, etc. - - if (Inst->Operands.empty()) + for (size_t i = 0, e = Instructions.size(); i != e; ++i) { + const AsmWriterInst &Inst = Instructions[i]; + if (Inst.Operands.empty()) continue; // Instruction already done. - std::string Command = " " + Inst->Operands[0].getCode() + "\n"; + std::string Command = " "+Inst.Operands[0].getCode(PassSubtarget)+"\n"; // Check to see if we already have 'Command' in UniqueOperandCommands. // If not, add it. - bool FoundIt = false; - for (unsigned idx = 0, e = UniqueOperandCommands.size(); idx != e; ++idx) - if (UniqueOperandCommands[idx] == Command) { - InstIdxs[i] = idx; - InstrsForCase[idx] += ", "; - InstrsForCase[idx] += Inst->CGI->TheDef->getName(); - FoundIt = true; - break; - } - if (!FoundIt) { - InstIdxs[i] = UniqueOperandCommands.size(); + auto I = std::find(UniqueOperandCommands.begin(), + UniqueOperandCommands.end(), Command); + if (I != UniqueOperandCommands.end()) { + size_t idx = I - UniqueOperandCommands.begin(); + InstrsForCase[idx] += ", "; + InstrsForCase[idx] += Inst.CGI->TheDef->getName(); + InstIdxs[idx].push_back(i); + } else { UniqueOperandCommands.push_back(std::move(Command)); - InstrsForCase.push_back(Inst->CGI->TheDef->getName()); + InstrsForCase.push_back(Inst.CGI->TheDef->getName()); + InstIdxs.emplace_back(); + InstIdxs.back().push_back(i); // This command matches one operand so far. InstOpsUsed.push_back(1); @@ -188,45 +178,33 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, // For each entry of UniqueOperandCommands, there is a set of instructions // that uses it. If the next command of all instructions in the set are // identical, fold it into the command. - for (unsigned CommandIdx = 0, e = UniqueOperandCommands.size(); + for (size_t CommandIdx = 0, e = UniqueOperandCommands.size(); CommandIdx != e; ++CommandIdx) { - for (unsigned Op = 1; ; ++Op) { - // Scan for the first instruction in the set. - std::vector<unsigned>::iterator NIT = - std::find(InstIdxs.begin(), InstIdxs.end(), CommandIdx); - if (NIT == InstIdxs.end()) break; // No commonality. + const auto &Idxs = InstIdxs[CommandIdx]; + for (unsigned Op = 1; ; ++Op) { + // Find the first instruction in the set. + const AsmWriterInst &FirstInst = Instructions[Idxs.front()]; // If this instruction has no more operands, we isn't anything to merge // into this command. - const AsmWriterInst *FirstInst = - getAsmWriterInstByID(NIT-InstIdxs.begin()); - if (!FirstInst || FirstInst->Operands.size() == Op) + if (FirstInst.Operands.size() == Op) break; // Otherwise, scan to see if all of the other instructions in this command // set share the operand. - bool AllSame = true; - - for (NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx); - NIT != InstIdxs.end(); - NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx)) { - // Okay, found another instruction in this command set. If the operand - // matches, we're ok, otherwise bail out. - const AsmWriterInst *OtherInst = - getAsmWriterInstByID(NIT-InstIdxs.begin()); - - if (!OtherInst || OtherInst->Operands.size() == Op || - OtherInst->Operands[Op] != FirstInst->Operands[Op]) { - AllSame = false; - break; - } - } - if (!AllSame) break; + if (std::any_of(Idxs.begin()+1, Idxs.end(), + [&](unsigned Idx) { + const AsmWriterInst &OtherInst = Instructions[Idx]; + return OtherInst.Operands.size() == Op || + OtherInst.Operands[Op] != FirstInst.Operands[Op]; + })) + break; // Okay, everything in this command set has the same next operand. Add it // to UniqueOperandCommands and remember that it was consumed. - std::string Command = " " + FirstInst->Operands[Op].getCode() + "\n"; + std::string Command = " " + + FirstInst.Operands[Op].getCode(PassSubtarget) + "\n"; UniqueOperandCommands[CommandIdx] += Command; InstOpsUsed[CommandIdx]++; @@ -277,7 +255,7 @@ static void UnescapeString(std::string &Str) { void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { Record *AsmWriter = Target.getAsmWriter(); std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); - unsigned PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget"); + bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget"); O << "/// printInstruction - This method is automatically generated by tablegen\n" @@ -292,18 +270,16 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { /// OpcodeInfo - This encodes the index of the string to use for the first /// chunk of the output as well as indices used for operand printing. - std::vector<uint64_t> OpcodeInfo; + std::vector<uint64_t> OpcodeInfo(NumberedInstructions.size()); const unsigned OpcodeInfoBits = 64; // Add all strings to the string table upfront so it can generate an optimized // representation. - for (const CodeGenInstruction *Inst : *NumberedInstructions) { - AsmWriterInst *AWI = CGIAWIMap[Inst]; - if (AWI && - AWI->Operands[0].OperandType == + for (AsmWriterInst &AWI : Instructions) { + if (AWI.Operands[0].OperandType == AsmWriterOperand::isLiteralTextOperand && - !AWI->Operands[0].Str.empty()) { - std::string Str = AWI->Operands[0].Str; + !AWI.Operands[0].Str.empty()) { + std::string Str = AWI.Operands[0].Str; UnescapeString(Str); StringTable.add(Str); } @@ -312,29 +288,24 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { StringTable.layout(); unsigned MaxStringIdx = 0; - for (const CodeGenInstruction *Inst : *NumberedInstructions) { - AsmWriterInst *AWI = CGIAWIMap[Inst]; + for (AsmWriterInst &AWI : Instructions) { unsigned Idx; - if (!AWI) { - // Something not handled by the asmwriter printer. - Idx = ~0U; - } else if (AWI->Operands[0].OperandType != - AsmWriterOperand::isLiteralTextOperand || - AWI->Operands[0].Str.empty()) { + if (AWI.Operands[0].OperandType != AsmWriterOperand::isLiteralTextOperand || + AWI.Operands[0].Str.empty()) { // Something handled by the asmwriter printer, but with no leading string. Idx = StringTable.get(""); } else { - std::string Str = AWI->Operands[0].Str; + std::string Str = AWI.Operands[0].Str; UnescapeString(Str); Idx = StringTable.get(Str); MaxStringIdx = std::max(MaxStringIdx, Idx); // Nuke the string from the operand list. It is now handled! - AWI->Operands.erase(AWI->Operands.begin()); + AWI.Operands.erase(AWI.Operands.begin()); } // Bias offset by one since we want 0 as a sentinel. - OpcodeInfo.push_back(Idx+1); + OpcodeInfo[AWI.CGIIndex] = Idx+1; } // Figure out how many bits we used for the string index. @@ -348,10 +319,10 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { while (1) { std::vector<std::string> UniqueOperandCommands; - std::vector<unsigned> InstIdxs; + std::vector<std::vector<unsigned>> InstIdxs; std::vector<unsigned> NumInstOpsHandled; FindUniqueOperandCommands(UniqueOperandCommands, InstIdxs, - NumInstOpsHandled); + NumInstOpsHandled, PassSubtarget); // If we ran out of operands to print, we're done. if (UniqueOperandCommands.empty()) break; @@ -368,23 +339,22 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { } // Otherwise, we can include this in the initial lookup table. Add it in. - for (unsigned i = 0, e = InstIdxs.size(); i != e; ++i) - if (InstIdxs[i] != ~0U) { - OpcodeInfo[i] |= (uint64_t)InstIdxs[i] << (OpcodeInfoBits-BitsLeft); - } - BitsLeft -= NumBits; - - // Remove the info about this operand. - for (unsigned i = 0, e = NumberedInstructions->size(); i != e; ++i) { - if (AsmWriterInst *Inst = getAsmWriterInstByID(i)) - if (!Inst->Operands.empty()) { - unsigned NumOps = NumInstOpsHandled[InstIdxs[i]]; - assert(NumOps <= Inst->Operands.size() && + for (size_t i = 0, e = InstIdxs.size(); i != e; ++i) { + unsigned NumOps = NumInstOpsHandled[i]; + for (unsigned Idx : InstIdxs[i]) { + OpcodeInfo[Instructions[Idx].CGIIndex] |= + (uint64_t)i << (OpcodeInfoBits-BitsLeft); + // Remove the info about this operand from the instruction. + AsmWriterInst &Inst = Instructions[Idx]; + if (!Inst.Operands.empty()) { + assert(NumOps <= Inst.Operands.size() && "Can't remove this many ops!"); - Inst->Operands.erase(Inst->Operands.begin(), - Inst->Operands.begin()+NumOps); + Inst.Operands.erase(Inst.Operands.begin(), + Inst.Operands.begin()+NumOps); } + } } + BitsLeft -= NumBits; // Remember the handlers for this set of operands. TableDrivenOperandPrinters.push_back(std::move(UniqueOperandCommands)); @@ -411,9 +381,9 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { uint64_t Mask = (1ULL << TableSize) - 1; O << " static const uint" << TableSize << "_t OpInfo" << Table << "[] = {\n"; - for (unsigned i = 0, e = NumberedInstructions->size(); i != e; ++i) { + for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { O << " " << ((OpcodeInfo[i] >> Shift) & Mask) << "U,\t// " - << NumberedInstructions->at(i)->TheDef->getName() << "\n"; + << NumberedInstructions[i]->TheDef->getName() << "\n"; } O << " };\n\n"; // Emit string to combine the individual table lookups. @@ -502,7 +472,7 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { O << " switch (MI->getOpcode()) {\n"; O << " default: llvm_unreachable(\"Unexpected opcode.\");\n"; while (!Instructions.empty()) - EmitInstructions(Instructions, O); + EmitInstructions(Instructions, O, PassSubtarget); O << " }\n"; } @@ -578,7 +548,7 @@ void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) { Record *AsmWriter = Target.getAsmWriter(); std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); const auto &Registers = Target.getRegBank().getRegisters(); - std::vector<Record*> AltNameIndices = Target.getRegAltNameIndices(); + const std::vector<Record*> &AltNameIndices = Target.getRegAltNameIndices(); bool hasAltNames = AltNameIndices.size() > 1; std::string Namespace = Registers.front().TheDef->getValueAsString("Namespace"); @@ -606,7 +576,7 @@ void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) { O << " switch(AltIdx) {\n" << " default: llvm_unreachable(\"Invalid register alt name index!\");\n"; for (const Record *R : AltNameIndices) { - std::string AltName(R->getName()); + const std::string &AltName = R->getName(); std::string Prefix = !Namespace.empty() ? Namespace + "::" : ""; O << " case " << Prefix << AltName << ":\n" << " assert(*(AsmStrs" << AltName << "+RegAsmOffset" @@ -631,12 +601,12 @@ namespace { class IAPrinter { std::vector<std::string> Conds; std::map<StringRef, std::pair<int, int>> OpMap; - SmallVector<Record*, 4> ReqFeatures; std::string Result; std::string AsmString; public: - IAPrinter(std::string R, std::string AS) : Result(R), AsmString(AS) {} + IAPrinter(std::string R, std::string AS) + : Result(std::move(R)), AsmString(std::move(AS)) {} void addCond(const std::string &C) { Conds.push_back(C); } @@ -677,7 +647,7 @@ public: } void print(raw_ostream &O) { - if (Conds.empty() && ReqFeatures.empty()) { + if (Conds.empty()) { O.indent(6) << "return true;\n"; return; } @@ -784,7 +754,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { // Emit the method that prints the alias instruction. std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); unsigned Variant = AsmWriter->getValueAsInt("Variant"); - unsigned PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget"); + bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget"); std::vector<Record*> AllInstAliases = Records.getAllDerivedDefinitions("InstAlias"); @@ -808,6 +778,8 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { // before it can be matched to the mnemonic. std::map<std::string, std::vector<IAPrinter>> IAPrinterMap; + std::vector<std::string> PrintMethods; + // A list of MCOperandPredicates for all operands in use, and the reverse map std::vector<const Record*> MCOpPredicates; DenseMap<const Record*, unsigned> MCOpPredicateMap; @@ -825,6 +797,18 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { IAPrinter IAP(CGA.Result->getAsString(), CGA.AsmString); + std::string Namespace = Target.getName(); + std::vector<Record *> ReqFeatures; + if (PassSubtarget) { + // We only consider ReqFeatures predicates if PassSubtarget + std::vector<Record *> RF = + CGA.TheDef->getValueAsListOfDefs("Predicates"); + std::copy_if(RF.begin(), RF.end(), std::back_inserter(ReqFeatures), + [](Record *R) { + return R->getValueAsBit("AssemblerMatcherPredicate"); + }); + } + unsigned NumMIOps = 0; for (auto &Operand : CGA.ResultOperands) NumMIOps += Operand.getMINumOperands(); @@ -929,6 +913,27 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { } if (CantHandle) continue; + + for (auto I = ReqFeatures.cbegin(); I != ReqFeatures.cend(); I++) { + Record *R = *I; + std::string AsmCondString = R->getValueAsString("AssemblerCondString"); + + // AsmCondString has syntax [!]F(,[!]F)* + SmallVector<StringRef, 4> Ops; + SplitString(AsmCondString, Ops, ","); + assert(!Ops.empty() && "AssemblerCondString cannot be empty"); + + for (auto &Op : Ops) { + assert(!Op.empty() && "Empty operator"); + if (Op[0] == '!') + Cond = "!STI.getFeatureBits()[" + Namespace + "::" + + Op.substr(1).str() + "]"; + else + Cond = "STI.getFeatureBits()[" + Namespace + "::" + Op.str() + "]"; + IAP.addCond(Cond); + } + } + IAPrinterMap[Aliases.first].push_back(std::move(IAP)); } } @@ -1002,13 +1007,14 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { // Code that prints the alias, replacing the operands with the ones from the // MCInst. O << " unsigned I = 0;\n"; - O << " while (AsmString[I] != ' ' && AsmString[I] != '\t' &&\n"; - O << " AsmString[I] != '\\0')\n"; + O << " while (AsmString[I] != ' ' && AsmString[I] != '\\t' &&\n"; + O << " AsmString[I] != '$' && AsmString[I] != '\\0')\n"; O << " ++I;\n"; O << " OS << '\\t' << StringRef(AsmString, I);\n"; O << " if (AsmString[I] != '\\0') {\n"; - O << " OS << '\\t';\n"; + O << " if (AsmString[I] == ' ' || AsmString[I] == '\\t')"; + O << " OS << '\\t';\n"; O << " do {\n"; O << " if (AsmString[I] == '$') {\n"; O << " ++I;\n"; @@ -1072,7 +1078,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { for (unsigned i = 0; i < MCOpPredicates.size(); ++i) { Init *MCOpPred = MCOpPredicates[i]->getValueInit("MCOperandPredicate"); - if (StringInit *SI = dyn_cast<StringInit>(MCOpPred)) { + if (CodeInit *SI = dyn_cast<CodeInit>(MCOpPred)) { O << " case " << i + 1 << ": {\n" << SI->getValue() << "\n" << " }\n"; @@ -1089,19 +1095,15 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { AsmWriterEmitter::AsmWriterEmitter(RecordKeeper &R) : Records(R), Target(R) { Record *AsmWriter = Target.getAsmWriter(); unsigned Variant = AsmWriter->getValueAsInt("Variant"); - unsigned PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget"); - for (const CodeGenInstruction *I : Target.instructions()) - if (!I->AsmString.empty() && I->TheDef->getName() != "PHI") - Instructions.emplace_back(*I, Variant, PassSubtarget); // Get the instruction numbering. - NumberedInstructions = &Target.getInstructionsByEnumValue(); + NumberedInstructions = Target.getInstructionsByEnumValue(); - // Compute the CodeGenInstruction -> AsmWriterInst mapping. Note that not - // all machine instructions are necessarily being printed, so there may be - // target instructions not in this map. - for (AsmWriterInst &AWI : Instructions) - CGIAWIMap.insert(std::make_pair(AWI.CGI, &AWI)); + for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { + const CodeGenInstruction *I = NumberedInstructions[i]; + if (!I->AsmString.empty() && I->TheDef->getName() != "PHI") + Instructions.emplace_back(*I, i, Variant); + } } void AsmWriterEmitter::run(raw_ostream &O) { diff --git a/utils/TableGen/AsmWriterInst.cpp b/utils/TableGen/AsmWriterInst.cpp index 5b09765a2756..2c19e5d663d6 100644 --- a/utils/TableGen/AsmWriterInst.cpp +++ b/utils/TableGen/AsmWriterInst.cpp @@ -26,7 +26,7 @@ static bool isIdentChar(char C) { C == '_'; } -std::string AsmWriterOperand::getCode() const { +std::string AsmWriterOperand::getCode(bool PassSubtarget) const { if (OperandType == isLiteralTextOperand) { if (Str.size() == 1) return "O << '" + Str + "';"; @@ -50,9 +50,9 @@ std::string AsmWriterOperand::getCode() const { /// ParseAsmString - Parse the specified Instruction's AsmString into this /// AsmWriterInst. /// -AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant, - unsigned PassSubtarget) { - this->CGI = &CGI; +AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex, + unsigned Variant) + : CGI(&CGI), CGIIndex(CGIIndex) { // NOTE: Any extensions to this code need to be mirrored in the // AsmPrinter::printInlineAsm code that executes as compile time (assuming @@ -120,8 +120,7 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant, while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) ++VarEnd; - std::string VarName(AsmString.begin()+DollarPos+1, - AsmString.begin()+VarEnd); + StringRef VarName(AsmString.data()+DollarPos+1, VarEnd-DollarPos-1); // Modifier - Support ${foo:modifier} syntax, where "modifier" is passed // into printOperand. Also support ${:feature}, which is passed into @@ -143,7 +142,7 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant, PrintFatalError("Reached end of string before terminating curly brace in '" + CGI.TheDef->getName() + "'"); - unsigned ModifierStart = VarEnd; + std::string::size_type ModifierStart = VarEnd; while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) ++VarEnd; Modifier = std::string(AsmString.begin()+ModifierStart, @@ -163,16 +162,14 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant, if (VarName.empty()) { // Just a modifier, pass this into PrintSpecial. - Operands.emplace_back("PrintSpecial", ~0U, ~0U, Modifier, - PassSubtarget); + Operands.emplace_back("PrintSpecial", ~0U, Modifier); } else { // Otherwise, normal operand. unsigned OpNo = CGI.Operands.getOperandNamed(VarName); CGIOperandList::OperandInfo OpInfo = CGI.Operands[OpNo]; unsigned MIOp = OpInfo.MIOperandNo; - Operands.emplace_back(OpInfo.PrinterMethodName, OpNo, MIOp, Modifier, - PassSubtarget); + Operands.emplace_back(OpInfo.PrinterMethodName, MIOp, Modifier); } LastEmitted = VarEnd; } diff --git a/utils/TableGen/AsmWriterInst.h b/utils/TableGen/AsmWriterInst.h index a597e6ba1a55..708f23cb5b0e 100644 --- a/utils/TableGen/AsmWriterInst.h +++ b/utils/TableGen/AsmWriterInst.h @@ -35,29 +35,20 @@ namespace llvm { isLiteralStatementOperand } OperandType; + /// MiOpNo - For isMachineInstrOperand, this is the operand number of the + /// machine instruction. + unsigned MIOpNo; + /// Str - For isLiteralTextOperand, this IS the literal text. For /// isMachineInstrOperand, this is the PrinterMethodName for the operand.. /// For isLiteralStatementOperand, this is the code to insert verbatim /// into the asm writer. std::string Str; - /// CGIOpNo - For isMachineInstrOperand, this is the index of the operand in - /// the CodeGenInstruction. - unsigned CGIOpNo; - - /// MiOpNo - For isMachineInstrOperand, this is the operand number of the - /// machine instruction. - unsigned MIOpNo; - /// MiModifier - For isMachineInstrOperand, this is the modifier string for /// an operand, specified with syntax like ${opname:modifier}. std::string MiModifier; - // PassSubtarget - Pass MCSubtargetInfo to the print method if this is - // equal to 1. - // FIXME: Remove after all ports are updated. - unsigned PassSubtarget; - // To make VS STL happy AsmWriterOperand(OpType op = isLiteralTextOperand):OperandType(op) {} @@ -66,13 +57,10 @@ namespace llvm { : OperandType(op), Str(LitStr) {} AsmWriterOperand(const std::string &Printer, - unsigned _CGIOpNo, unsigned _MIOpNo, const std::string &Modifier, - unsigned PassSubtarget, OpType op = isMachineInstrOperand) - : OperandType(op), Str(Printer), CGIOpNo(_CGIOpNo), MIOpNo(_MIOpNo), - MiModifier(Modifier), PassSubtarget(PassSubtarget) {} + : OperandType(op), MIOpNo(_MIOpNo), Str(Printer), MiModifier(Modifier) {} bool operator!=(const AsmWriterOperand &Other) const { if (OperandType != Other.OperandType || Str != Other.Str) return true; @@ -85,16 +73,17 @@ namespace llvm { } /// getCode - Return the code that prints this operand. - std::string getCode() const; + std::string getCode(bool PassSubtarget) const; }; class AsmWriterInst { public: std::vector<AsmWriterOperand> Operands; const CodeGenInstruction *CGI; + unsigned CGIIndex; - AsmWriterInst(const CodeGenInstruction &CGI, - unsigned Variant, unsigned PassSubtarget); + AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex, + unsigned Variant); /// MatchesAllButOneOp - If this instruction is exactly identical to the /// specified instruction except for one differing operand, return the diff --git a/utils/TableGen/Attributes.cpp b/utils/TableGen/Attributes.cpp index 7b001bf14de5..58dbe5767ada 100644 --- a/utils/TableGen/Attributes.cpp +++ b/utils/TableGen/Attributes.cpp @@ -27,6 +27,7 @@ public: private: void emitTargetIndependentEnums(raw_ostream &OS); + void emitConversionFn(raw_ostream &OS); void emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr); void printEnumAttrClasses(raw_ostream &OS, @@ -52,6 +53,27 @@ void Attributes::emitTargetIndependentEnums(raw_ostream &OS) { OS << "#endif\n"; } +void Attributes::emitConversionFn(raw_ostream &OS) { + OS << "#ifdef GET_ATTR_KIND_FROM_NAME\n"; + OS << "#undef GET_ATTR_KIND_FROM_NAME\n"; + + std::vector<Record*> Attrs = + Records.getAllDerivedDefinitions("EnumAttr"); + + OS << "static Attribute::AttrKind getAttrKindFromName(StringRef AttrName) {\n"; + OS << " return StringSwitch<Attribute::AttrKind>(AttrName)\n"; + + for (auto A : Attrs) { + OS << " .Case(\"" << A->getValueAsString("AttrString"); + OS << "\", Attribute::" << A->getName() << ")\n"; + } + + OS << " .Default(Attribute::None);\n"; + OS << "}\n\n"; + + OS << "#endif\n"; +} + void Attributes::emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr) { OS << "#ifdef GET_ATTR_COMPAT_FUNC\n"; OS << "#undef GET_ATTR_COMPAT_FUNC\n"; @@ -144,6 +166,7 @@ void Attributes::printStrBoolAttrClasses(raw_ostream &OS, void Attributes::emit(raw_ostream &OS) { emitTargetIndependentEnums(OS); + emitConversionFn(OS); emitFnAttrCompatCheck(OS, false); } diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt index eef1540424dd..e8fe30f5ac70 100644 --- a/utils/TableGen/CMakeLists.txt +++ b/utils/TableGen/CMakeLists.txt @@ -27,6 +27,7 @@ add_tablegen(llvm-tblgen LLVM OptParserEmitter.cpp PseudoLoweringEmitter.cpp RegisterInfoEmitter.cpp + SearchableTableEmitter.cpp SubtargetEmitter.cpp TableGen.cpp X86DisassemblerTables.cpp diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp index 46fcdf5e96ff..400913e32745 100644 --- a/utils/TableGen/CodeEmitterGen.cpp +++ b/utils/TableGen/CodeEmitterGen.cpp @@ -15,7 +15,6 @@ #include "CodeGenTarget.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" @@ -227,7 +226,7 @@ void CodeEmitterGen::run(raw_ostream &o) { // For little-endian instruction bit encodings, reverse the bit order Target.reverseBitsForLittleEndianEncoding(); - const std::vector<const CodeGenInstruction*> &NumberedInstructions = + ArrayRef<const CodeGenInstruction*> NumberedInstructions = Target.getInstructionsByEnumValue(); // Emit function declaration @@ -238,11 +237,7 @@ void CodeEmitterGen::run(raw_ostream &o) { // Emit instruction base values o << " static const uint64_t InstBits[] = {\n"; - for (std::vector<const CodeGenInstruction*>::const_iterator - IN = NumberedInstructions.begin(), - EN = NumberedInstructions.end(); - IN != EN; ++IN) { - const CodeGenInstruction *CGI = *IN; + for (const CodeGenInstruction *CGI : NumberedInstructions) { Record *R = CGI->TheDef; if (R->getValueAsString("Namespace") == "TargetOpcode" || diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp index 3ebe51e05121..307a95373c9d 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -2392,8 +2392,8 @@ void TreePattern::dump() const { print(errs()); } CodeGenDAGPatterns::CodeGenDAGPatterns(RecordKeeper &R) : Records(R), Target(R) { - Intrinsics = LoadIntrinsics(Records, false); - TgtIntrinsics = LoadIntrinsics(Records, true); + Intrinsics = CodeGenIntrinsicTable(Records, false); + TgtIntrinsics = CodeGenIntrinsicTable(Records, true); ParseNodeInfo(); ParseNodeTransforms(); ParseComplexPatterns(); @@ -2816,14 +2816,14 @@ public: if (const CodeGenIntrinsic *IntInfo = N->getIntrinsicInfo(CDP)) { // If this is an intrinsic, analyze it. - if (IntInfo->ModRef >= CodeGenIntrinsic::ReadArgMem) + if (IntInfo->ModRef & CodeGenIntrinsic::MR_Ref) mayLoad = true;// These may load memory. - if (IntInfo->ModRef >= CodeGenIntrinsic::ReadWriteArgMem) + if (IntInfo->ModRef & CodeGenIntrinsic::MR_Mod) mayStore = true;// Intrinsics that can write to memory are 'mayStore'. if (IntInfo->ModRef >= CodeGenIntrinsic::ReadWriteMem) - // WriteMem intrinsics can have other strange effects. + // ReadWriteMem intrinsics can have other strange effects. hasSideEffects = true; } } @@ -2974,9 +2974,16 @@ const DAGInstruction &CodeGenDAGPatterns::parseInstructionPattern( // fill in the InstResults map. for (unsigned j = 0, e = I->getNumTrees(); j != e; ++j) { TreePatternNode *Pat = I->getTree(j); - if (Pat->getNumTypes() != 0) + if (Pat->getNumTypes() != 0) { + std::string Types; + for (unsigned k = 0, ke = Pat->getNumTypes(); k != ke; ++k) { + if (k > 0) + Types += ", "; + Types += Pat->getExtType(k).getName(); + } I->error("Top-level forms in instruction pattern should have" - " void types"); + " void types, has types " + Types); + } // Find inputs and outputs, and verify the structure of the uses/defs. FindPatternInputsAndOutputs(I, Pat, InstInputs, InstResults, @@ -3249,7 +3256,7 @@ void CodeGenDAGPatterns::AddPatternToMatch(TreePattern *Pattern, void CodeGenDAGPatterns::InferInstructionFlags() { - const std::vector<const CodeGenInstruction*> &Instructions = + ArrayRef<const CodeGenInstruction*> Instructions = Target.getInstructionsByEnumValue(); // First try to infer flags from the primary instruction pattern, if any. diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h index 76c9cefea50f..819c4b8492cb 100644 --- a/utils/TableGen/CodeGenDAGPatterns.h +++ b/utils/TableGen/CodeGenDAGPatterns.h @@ -716,8 +716,8 @@ public: class CodeGenDAGPatterns { RecordKeeper &Records; CodeGenTarget Target; - std::vector<CodeGenIntrinsic> Intrinsics; - std::vector<CodeGenIntrinsic> TgtIntrinsics; + CodeGenIntrinsicTable Intrinsics; + CodeGenIntrinsicTable TgtIntrinsics; std::map<Record*, SDNodeInfo, LessRecordByID> SDNodes; std::map<Record*, std::pair<Record*, std::string>, LessRecordByID> SDNodeXForms; diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp index 366e8ec7fac1..ec802363030e 100644 --- a/utils/TableGen/CodeGenInstruction.cpp +++ b/utils/TableGen/CodeGenInstruction.cpp @@ -49,7 +49,9 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) { unsigned MIOperandNo = 0; std::set<std::string> OperandNames; - for (unsigned i = 0, e = InDI->getNumArgs()+OutDI->getNumArgs(); i != e; ++i){ + unsigned e = InDI->getNumArgs() + OutDI->getNumArgs(); + OperandList.reserve(e); + for (unsigned i = 0; i != e; ++i){ Init *ArgInit; std::string ArgName; if (i < NumDefs) { @@ -322,6 +324,7 @@ CodeGenInstruction::CodeGenInstruction(Record *R) isExtractSubreg = R->getValueAsBit("isExtractSubreg"); isInsertSubreg = R->getValueAsBit("isInsertSubreg"); isConvergent = R->getValueAsBit("isConvergent"); + hasNoSchedulingInfo = R->getValueAsBit("hasNoSchedulingInfo"); bool Unset; mayLoad = R->getValueAsBitOrUnset("mayLoad", Unset); diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h index 8f01abd5403c..8e5a03d7b743 100644 --- a/utils/TableGen/CodeGenInstruction.h +++ b/utils/TableGen/CodeGenInstruction.h @@ -14,7 +14,6 @@ #ifndef LLVM_UTILS_TABLEGEN_CODEGENINSTRUCTION_H #define LLVM_UTILS_TABLEGEN_CODEGENINSTRUCTION_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/MachineValueType.h" #include "llvm/Support/SMLoc.h" @@ -23,10 +22,10 @@ #include <vector> namespace llvm { +template <typename T> class ArrayRef; class Record; class DagInit; class CodeGenTarget; - class StringRef; class CGIOperandList { public: @@ -257,6 +256,7 @@ namespace llvm { bool isExtractSubreg : 1; bool isInsertSubreg : 1; bool isConvergent : 1; + bool hasNoSchedulingInfo : 1; std::string DeprecatedReason; bool HasComplexDeprecationPredicate; @@ -316,7 +316,8 @@ namespace llvm { K_Reg } Kind; - ResultOperand(std::string N, Record *r) : Name(N), R(r), Kind(K_Record) {} + ResultOperand(std::string N, Record *r) + : Name(std::move(N)), R(r), Kind(K_Record) {} ResultOperand(int64_t I) : Imm(I), Kind(K_Imm) {} ResultOperand(Record *r) : R(r), Kind(K_Reg) {} diff --git a/utils/TableGen/CodeGenIntrinsics.h b/utils/TableGen/CodeGenIntrinsics.h index 7bdb7e1bc537..ea3ec67d62ed 100644 --- a/utils/TableGen/CodeGenIntrinsics.h +++ b/utils/TableGen/CodeGenIntrinsics.h @@ -19,85 +19,122 @@ #include <vector> namespace llvm { - class Record; - class RecordKeeper; - class CodeGenTarget; - - struct CodeGenIntrinsic { - Record *TheDef; // The actual record defining this intrinsic. - std::string Name; // The name of the LLVM function "llvm.bswap.i32" - std::string EnumName; // The name of the enum "bswap_i32" - std::string GCCBuiltinName;// Name of the corresponding GCC builtin, or "". - std::string MSBuiltinName; // Name of the corresponding MS builtin, or "". - std::string TargetPrefix; // Target prefix, e.g. "ppc" for t-s intrinsics. - - /// IntrinsicSignature - This structure holds the return values and - /// parameter values of an intrinsic. If the number of return values is > 1, - /// then the intrinsic implicitly returns a first-class aggregate. The - /// numbering of the types starts at 0 with the first return value and - /// continues from there through the parameter list. This is useful for - /// "matching" types. - struct IntrinsicSignature { - /// RetVTs - The MVT::SimpleValueType for each return type. Note that this - /// list is only populated when in the context of a target .td file. When - /// building Intrinsics.td, this isn't available, because we don't know - /// the target pointer size. - std::vector<MVT::SimpleValueType> RetVTs; - - /// RetTypeDefs - The records for each return type. - std::vector<Record*> RetTypeDefs; - - /// ParamVTs - The MVT::SimpleValueType for each parameter type. Note that - /// this list is only populated when in the context of a target .td file. - /// When building Intrinsics.td, this isn't available, because we don't - /// know the target pointer size. - std::vector<MVT::SimpleValueType> ParamVTs; - - /// ParamTypeDefs - The records for each parameter type. - std::vector<Record*> ParamTypeDefs; - }; - - IntrinsicSignature IS; - - // Memory mod/ref behavior of this intrinsic. - enum ModRefKind { - NoMem, ReadArgMem, ReadMem, ReadWriteArgMem, ReadWriteMem - }; - ModRefKind ModRef; - - /// This is set to true if the intrinsic is overloaded by its argument - /// types. - bool isOverloaded; - - /// isCommutative - True if the intrinsic is commutative. - bool isCommutative; - - /// canThrow - True if the intrinsic can throw. - bool canThrow; - - /// isNoDuplicate - True if the intrinsic is marked as noduplicate. - bool isNoDuplicate; - - /// isNoReturn - True if the intrinsic is no-return. - bool isNoReturn; - - /// isConvergent - True if the intrinsic is marked as convergent. - bool isConvergent; - - enum ArgAttribute { - NoCapture, - ReadOnly, - ReadNone - }; - std::vector<std::pair<unsigned, ArgAttribute> > ArgumentAttributes; - - CodeGenIntrinsic(Record *R); +class Record; +class RecordKeeper; +class CodeGenTarget; + +struct CodeGenIntrinsic { + Record *TheDef; // The actual record defining this intrinsic. + std::string Name; // The name of the LLVM function "llvm.bswap.i32" + std::string EnumName; // The name of the enum "bswap_i32" + std::string GCCBuiltinName; // Name of the corresponding GCC builtin, or "". + std::string MSBuiltinName; // Name of the corresponding MS builtin, or "". + std::string TargetPrefix; // Target prefix, e.g. "ppc" for t-s intrinsics. + + /// This structure holds the return values and parameter values of an + /// intrinsic. If the number of return values is > 1, then the intrinsic + /// implicitly returns a first-class aggregate. The numbering of the types + /// starts at 0 with the first return value and continues from there through + /// the parameter list. This is useful for "matching" types. + struct IntrinsicSignature { + /// The MVT::SimpleValueType for each return type. Note that this list is + /// only populated when in the context of a target .td file. When building + /// Intrinsics.td, this isn't available, because we don't know the target + /// pointer size. + std::vector<MVT::SimpleValueType> RetVTs; + + /// The records for each return type. + std::vector<Record *> RetTypeDefs; + + /// The MVT::SimpleValueType for each parameter type. Note that this list is + /// only populated when in the context of a target .td file. When building + /// Intrinsics.td, this isn't available, because we don't know the target + /// pointer size. + std::vector<MVT::SimpleValueType> ParamVTs; + + /// The records for each parameter type. + std::vector<Record *> ParamTypeDefs; }; - /// LoadIntrinsics - Read all of the intrinsics defined in the specified - /// .td file. - std::vector<CodeGenIntrinsic> LoadIntrinsics(const RecordKeeper &RC, - bool TargetOnly); + IntrinsicSignature IS; + + /// Bit flags describing the type (ref/mod) and location of memory + /// accesses that may be performed by the intrinsics. Analogous to + /// \c FunctionModRefBehaviour. + enum ModRefBits { + /// The intrinsic may access memory anywhere, i.e. it is not restricted + /// to access through pointer arguments. + MR_Anywhere = 1, + + /// The intrinsic may read memory. + MR_Ref = 2, + + /// The intrinsic may write memory. + MR_Mod = 4, + + /// The intrinsic may both read and write memory. + MR_ModRef = MR_Ref | MR_Mod, + }; + + /// Memory mod/ref behavior of this intrinsic, corresponding to intrinsic + /// properties (IntrReadMem, IntrArgMemOnly, etc.). + enum ModRefBehavior { + NoMem = 0, + ReadArgMem = MR_Ref, + ReadMem = MR_Ref | MR_Anywhere, + WriteArgMem = MR_Mod, + WriteMem = MR_Mod | MR_Anywhere, + ReadWriteArgMem = MR_ModRef, + ReadWriteMem = MR_ModRef | MR_Anywhere, + }; + ModRefBehavior ModRef; + + /// This is set to true if the intrinsic is overloaded by its argument + /// types. + bool isOverloaded; + + /// True if the intrinsic is commutative. + bool isCommutative; + + /// True if the intrinsic can throw. + bool canThrow; + + /// True if the intrinsic is marked as noduplicate. + bool isNoDuplicate; + + /// True if the intrinsic is no-return. + bool isNoReturn; + + /// True if the intrinsic is marked as convergent. + bool isConvergent; + + enum ArgAttribute { NoCapture, Returned, ReadOnly, WriteOnly, ReadNone }; + std::vector<std::pair<unsigned, ArgAttribute>> ArgumentAttributes; + + CodeGenIntrinsic(Record *R); +}; + +class CodeGenIntrinsicTable { + std::vector<CodeGenIntrinsic> Intrinsics; + +public: + struct TargetSet { + std::string Name; + size_t Offset; + size_t Count; + }; + std::vector<TargetSet> Targets; + + explicit CodeGenIntrinsicTable(const RecordKeeper &RC, bool TargetOnly); + CodeGenIntrinsicTable() = default; + + bool empty() const { return Intrinsics.empty(); } + size_t size() const { return Intrinsics.size(); } + CodeGenIntrinsic &operator[](size_t Pos) { return Intrinsics[Pos]; } + const CodeGenIntrinsic &operator[](size_t Pos) const { + return Intrinsics[Pos]; + } +}; } #endif diff --git a/utils/TableGen/CodeGenMapTable.cpp b/utils/TableGen/CodeGenMapTable.cpp index f66dd082709b..527f530da479 100644 --- a/utils/TableGen/CodeGenMapTable.cpp +++ b/utils/TableGen/CodeGenMapTable.cpp @@ -337,10 +337,20 @@ Record *MapTableEmitter::getInstrForColumn(Record *KeyInstr, } if (MatchFound) { - if (MatchInstr) // Already had a match + if (MatchInstr) { + // Already had a match // Error if multiple matches are found for a column. + std::string KeyValueStr; + for (Init *Value : KeyValue) { + if (!KeyValueStr.empty()) + KeyValueStr += ", "; + KeyValueStr += Value->getAsString(); + } + PrintFatalError("Multiple matches found for `" + KeyInstr->getName() + - "', for the relation `" + InstrMapDesc.getName()); + "', for the relation `" + InstrMapDesc.getName() + "', row fields [" + + KeyValueStr + "], column `" + CurValueCol->getAsString() + "'"); + } MatchInstr = CurInstr; } } @@ -355,7 +365,7 @@ Record *MapTableEmitter::getInstrForColumn(Record *KeyInstr, unsigned MapTableEmitter::emitBinSearchTable(raw_ostream &OS) { - const std::vector<const CodeGenInstruction*> &NumberedInstructions = + ArrayRef<const CodeGenInstruction*> NumberedInstructions = Target.getInstructionsByEnumValue(); std::string TargetName = Target.getName(); const std::vector<ListInit*> &ValueCols = InstrMapDesc.getValueCols(); @@ -499,8 +509,7 @@ static void emitEnums(raw_ostream &OS, RecordKeeper &Records) { // Iterate over all InstrMapping records and create a map between column // fields and their possible values across all records. - for (unsigned i = 0, e = InstrMapVec.size(); i < e; i++) { - Record *CurMap = InstrMapVec[i]; + for (Record *CurMap : InstrMapVec) { ListInit *ColFields; ColFields = CurMap->getValueAsListInit("ColFields"); ListInit *List = CurMap->getValueAsListInit("ValueCols"); @@ -524,10 +533,8 @@ static void emitEnums(raw_ostream &OS, RecordKeeper &Records) { } } - for (std::map<std::string, std::vector<Init*> >::iterator - II = ColFieldValueMap.begin(), IE = ColFieldValueMap.end(); - II != IE; II++) { - std::vector<Init*> FieldValues = (*II).second; + for (auto &Entry : ColFieldValueMap) { + std::vector<Init*> FieldValues = Entry.second; // Delete duplicate entries from ColFieldValueMap for (unsigned i = 0; i < FieldValues.size() - 1; i++) { @@ -540,9 +547,9 @@ static void emitEnums(raw_ostream &OS, RecordKeeper &Records) { } // Emit enumerated values for the column fields. - OS << "enum " << (*II).first << " {\n"; + OS << "enum " << Entry.first << " {\n"; for (unsigned i = 0, endFV = FieldValues.size(); i < endFV; i++) { - OS << "\t" << (*II).first << "_" << FieldValues[i]->getAsUnquotedString(); + OS << "\t" << Entry.first << "_" << FieldValues[i]->getAsUnquotedString(); if (i != endFV - 1) OS << ",\n"; else @@ -577,8 +584,8 @@ void EmitMapTable(RecordKeeper &Records, raw_ostream &OS) { // Iterate over all instruction mapping records and construct relationship // maps based on the information specified there. // - for (unsigned i = 0, e = InstrMapVec.size(); i < e; i++) { - MapTableEmitter IMap(Target, Records, InstrMapVec[i]); + for (Record *CurMap : InstrMapVec) { + MapTableEmitter IMap(Target, Records, CurMap); // Build RowInstrMap to group instructions based on their values for // RowFields. In the process, also collect key instructions into diff --git a/utils/TableGen/CodeGenRegisters.cpp b/utils/TableGen/CodeGenRegisters.cpp index ca316e96a21a..626144fbe855 100644 --- a/utils/TableGen/CodeGenRegisters.cpp +++ b/utils/TableGen/CodeGenRegisters.cpp @@ -587,10 +587,9 @@ struct TupleExpander : SetTheory::Expander { Elts.insert(NewReg); // Copy Proto super-classes. - ArrayRef<Record *> Supers = Proto->getSuperClasses(); - ArrayRef<SMRange> Ranges = Proto->getSuperClassRanges(); - for (unsigned i = 0, e = Supers.size(); i != e; ++i) - NewReg->addSuperClass(Supers[i], Ranges[i]); + ArrayRef<std::pair<Record *, SMRange>> Supers = Proto->getSuperClasses(); + for (const auto &SuperPair : Supers) + NewReg->addSuperClass(SuperPair.first, SuperPair.second); // Copy Proto fields. for (unsigned i = 0, e = Proto->getValues().size(); i != e; ++i) { @@ -1193,45 +1192,57 @@ void CodeGenRegBank::computeSubRegLaneMasks() { for (const auto &Idx : SubRegIndices) { const auto &Composites = Idx.getComposites(); auto &LaneTransforms = Idx.CompositionLaneMaskTransform; - // Go through all leaf subregisters and find the ones that compose with Idx. - // These make out all possible valid bits in the lane mask we want to - // transform. Looking only at the leafs ensure that only a single bit in - // the mask is set. - unsigned NextBit = 0; - for (auto &Idx2 : SubRegIndices) { - // Skip non-leaf subregisters. - if (!Idx2.getComposites().empty()) - continue; - // Replicate the behaviour from the lane mask generation loop above. - unsigned SrcBit = NextBit; - unsigned SrcMask = 1u << SrcBit; - if (NextBit < 31) - ++NextBit; - assert(Idx2.LaneMask == SrcMask); - - // Get the composed subregister if there is any. - auto C = Composites.find(&Idx2); - if (C == Composites.end()) - continue; - const CodeGenSubRegIndex *Composite = C->second; - // The Composed subreg should be a leaf subreg too - assert(Composite->getComposites().empty()); - - // Create Mask+Rotate operation and merge with existing ops if possible. - unsigned DstBit = Log2_32(Composite->LaneMask); - int Shift = DstBit - SrcBit; - uint8_t RotateLeft = Shift >= 0 ? (uint8_t)Shift : 32+Shift; - for (auto &I : LaneTransforms) { - if (I.RotateLeft == RotateLeft) { - I.Mask |= SrcMask; - SrcMask = 0; + + if (Composites.empty()) { + // Moving from a class with no subregisters we just had a single lane: + // The subregister must be a leaf subregister and only occupies 1 bit. + // Move the bit from the class without subregisters into that position. + unsigned DstBit = Log2_32(Idx.LaneMask); + assert(Idx.LaneMask == 1u << DstBit && "Must be a leaf subregister"); + MaskRolPair MaskRol = { 1, (uint8_t)DstBit }; + LaneTransforms.push_back(MaskRol); + } else { + // Go through all leaf subregisters and find the ones that compose with + // Idx. These make out all possible valid bits in the lane mask we want to + // transform. Looking only at the leafs ensure that only a single bit in + // the mask is set. + unsigned NextBit = 0; + for (auto &Idx2 : SubRegIndices) { + // Skip non-leaf subregisters. + if (!Idx2.getComposites().empty()) + continue; + // Replicate the behaviour from the lane mask generation loop above. + unsigned SrcBit = NextBit; + unsigned SrcMask = 1u << SrcBit; + if (NextBit < 31) + ++NextBit; + assert(Idx2.LaneMask == SrcMask); + + // Get the composed subregister if there is any. + auto C = Composites.find(&Idx2); + if (C == Composites.end()) + continue; + const CodeGenSubRegIndex *Composite = C->second; + // The Composed subreg should be a leaf subreg too + assert(Composite->getComposites().empty()); + + // Create Mask+Rotate operation and merge with existing ops if possible. + unsigned DstBit = Log2_32(Composite->LaneMask); + int Shift = DstBit - SrcBit; + uint8_t RotateLeft = Shift >= 0 ? (uint8_t)Shift : 32+Shift; + for (auto &I : LaneTransforms) { + if (I.RotateLeft == RotateLeft) { + I.Mask |= SrcMask; + SrcMask = 0; + } + } + if (SrcMask != 0) { + MaskRolPair MaskRol = { SrcMask, RotateLeft }; + LaneTransforms.push_back(MaskRol); } - } - if (SrcMask != 0) { - MaskRolPair MaskRol = { SrcMask, RotateLeft }; - LaneTransforms.push_back(MaskRol); } } + // Optimize if the transformation consists of one step only: Set mask to // 0xffffffff (including some irrelevant invalid bits) so that it should // merge with more entries later while compressing the table. @@ -1268,10 +1279,10 @@ void CodeGenRegBank::computeSubRegLaneMasks() { LaneMask |= SubRegIndex.LaneMask; } - // For classes without any subregisters set LaneMask to ~0u instead of 0. + // For classes without any subregisters set LaneMask to 1 instead of 0. // This makes it easier for client code to handle classes uniformly. if (LaneMask == 0) - LaneMask = ~0u; + LaneMask = 1; RegClass.LaneMask = LaneMask; } @@ -1818,11 +1829,14 @@ void CodeGenRegBank::computeDerivedInfo() { computeRegUnitLaneMasks(); - // Compute register class HasDisjunctSubRegs flag. + // Compute register class HasDisjunctSubRegs/CoveredBySubRegs flag. for (CodeGenRegisterClass &RC : RegClasses) { RC.HasDisjunctSubRegs = false; - for (const CodeGenRegister *Reg : RC.getMembers()) + RC.CoveredBySubRegs = true; + for (const CodeGenRegister *Reg : RC.getMembers()) { RC.HasDisjunctSubRegs |= Reg->HasDisjunctSubRegs; + RC.CoveredBySubRegs &= Reg->CoveredBySubRegs; + } } // Get the weight of each set. diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h index dc441436537d..b8d47aa4ff82 100644 --- a/utils/TableGen/CodeGenRegisters.h +++ b/utils/TableGen/CodeGenRegisters.h @@ -19,22 +19,21 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SetVector.h" #include "llvm/ADT/SparseBitVector.h" #include "llvm/CodeGen/MachineValueType.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/SetTheory.h" #include <cstdlib> +#include <deque> #include <list> #include <map> -#include <set> #include <string> #include <vector> -#include <deque> namespace llvm { class CodeGenRegBank; + template <typename T, typename Vector, typename Set> class SetVector; /// Used to encode a step in a register lane mask transformation. /// Mask the bits specified in Mask, then rotate them Rol bits to the left @@ -311,6 +310,7 @@ namespace llvm { unsigned LaneMask; /// True if there are at least 2 subregisters which do not interfere. bool HasDisjunctSubRegs; + bool CoveredBySubRegs; // Return the Record that defined this class, or NULL if the class was // created by TableGen. diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp index c98f62345342..d1b141e3160f 100644 --- a/utils/TableGen/CodeGenSchedule.cpp +++ b/utils/TableGen/CodeGenSchedule.cpp @@ -68,7 +68,7 @@ struct InstRegexOp : public SetTheory::Operator { } RegexList.push_back(Regex(pat)); } - for (const CodeGenInstruction *Inst : Target.instructions()) { + for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { for (auto &R : RegexList) { if (R.match(Inst->TheDef->getName())) Elts.insert(Inst->TheDef); @@ -120,12 +120,18 @@ CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, // (For per-operand resources mapped to itinerary classes). collectProcItinRW(); + // Find UnsupportedFeatures records for each processor. + // (For per-operand resources mapped to itinerary classes). + collectProcUnsupportedFeatures(); + // Infer new SchedClasses from SchedVariant. inferSchedClasses(); // Populate each CodeGenProcModel's WriteResDefs, ReadAdvanceDefs, and // ProcResourceDefs. collectProcResources(); + + checkCompleteness(); } /// Gather all processor models. @@ -204,7 +210,7 @@ void CodeGenSchedModels::collectSchedRW() { // Find all SchedReadWrites referenced by instruction defs. RecVec SWDefs, SRDefs; - for (const CodeGenInstruction *Inst : Target.instructions()) { + for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { Record *SchedDef = Inst->TheDef; if (SchedDef->isValueUnset("SchedRW")) continue; @@ -498,7 +504,7 @@ void CodeGenSchedModels::collectSchedClasses() { // Create a SchedClass for each unique combination of itinerary class and // SchedRW list. - for (const CodeGenInstruction *Inst : Target.instructions()) { + for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { Record *ItinDef = Inst->TheDef->getValueAsDef("Itinerary"); IdxVec Writes, Reads; if (!Inst->TheDef->isValueUnset("SchedRW")) @@ -523,11 +529,12 @@ void CodeGenSchedModels::collectSchedClasses() { if (!EnableDump) return; - for (const CodeGenInstruction *Inst : Target.instructions()) { + for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { std::string InstName = Inst->TheDef->getName(); unsigned SCIdx = InstrClassMap.lookup(Inst->TheDef); if (!SCIdx) { - dbgs() << "No machine model for " << Inst->TheDef->getName() << '\n'; + if (!Inst->hasNoSchedulingInfo) + dbgs() << "No machine model for " << Inst->TheDef->getName() << '\n'; continue; } CodeGenSchedClass &SC = getSchedClass(SCIdx); @@ -826,6 +833,15 @@ void CodeGenSchedModels::collectProcItinRW() { } } +// Gather the unsupported features for processor models. +void CodeGenSchedModels::collectProcUnsupportedFeatures() { + for (CodeGenProcModel &ProcModel : ProcModels) { + for (Record *Pred : ProcModel.ModelDef->getValueAsListOfDefs("UnsupportedFeatures")) { + ProcModel.UnsupportedFeaturesDefs.push_back(Pred); + } + } +} + /// Infer new classes from existing classes. In the process, this may create new /// SchedWrites from sequences of existing SchedWrites. void CodeGenSchedModels::inferSchedClasses() { @@ -1426,6 +1442,9 @@ void CodeGenSchedModels::verifyProcResourceGroups(CodeGenProcModel &PM) { // Collect and sort WriteRes, ReadAdvance, and ProcResources. void CodeGenSchedModels::collectProcResources() { + ProcResourceDefs = Records.getAllDerivedDefinitions("ProcResourceUnits"); + ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup"); + // Add any subtarget-specific SchedReadWrites that are directly associated // with processor resources. Refer to the parent SchedClass's ProcIndices to // determine which processors they apply to. @@ -1520,6 +1539,63 @@ void CodeGenSchedModels::collectProcResources() { dbgs() << '\n'); verifyProcResourceGroups(PM); } + + ProcResourceDefs.clear(); + ProcResGroups.clear(); +} + +void CodeGenSchedModels::checkCompleteness() { + bool Complete = true; + bool HadCompleteModel = false; + for (const CodeGenProcModel &ProcModel : procModels()) { + if (!ProcModel.ModelDef->getValueAsBit("CompleteModel")) + continue; + for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { + if (Inst->hasNoSchedulingInfo) + continue; + if (ProcModel.isUnsupported(*Inst)) + continue; + unsigned SCIdx = getSchedClassIdx(*Inst); + if (!SCIdx) { + if (Inst->TheDef->isValueUnset("SchedRW") && !HadCompleteModel) { + PrintError("No schedule information for instruction '" + + Inst->TheDef->getName() + "'"); + Complete = false; + } + continue; + } + + const CodeGenSchedClass &SC = getSchedClass(SCIdx); + if (!SC.Writes.empty()) + continue; + if (SC.ItinClassDef != nullptr) + continue; + + const RecVec &InstRWs = SC.InstRWs; + auto I = std::find_if(InstRWs.begin(), InstRWs.end(), + [&ProcModel] (const Record *R) { + return R->getValueAsDef("SchedModel") == + ProcModel.ModelDef; + }); + if (I == InstRWs.end()) { + PrintError("'" + ProcModel.ModelName + "' lacks information for '" + + Inst->TheDef->getName() + "'"); + Complete = false; + } + } + HadCompleteModel = true; + } + if (!Complete) { + errs() << "\n\nIncomplete schedule models found.\n" + << "- Consider setting 'CompleteModel = 0' while developing new models.\n" + << "- Pseudo instructions can be marked with 'hasNoSchedulingInfo = 1'.\n" + << "- Instructions should usually have Sched<[...]> as a superclass, " + "you may temporarily use an empty list.\n" + << "- Instructions related to unsupported features can be excluded with " + "list<Predicate> UnsupportedFeatures = [HasA,..,HasY]; in the " + "processor model.\n\n"; + PrintFatalError("Incomplete schedule model"); + } } // Collect itinerary class resources for each processor. @@ -1600,8 +1676,8 @@ Record *CodeGenSchedModels::findProcResUnits(Record *ProcResKind, return ProcResKind; Record *ProcUnitDef = nullptr; - RecVec ProcResourceDefs = - Records.getAllDerivedDefinitions("ProcResourceUnits"); + assert(!ProcResourceDefs.empty()); + assert(!ProcResGroups.empty()); for (RecIter RI = ProcResourceDefs.begin(), RE = ProcResourceDefs.end(); RI != RE; ++RI) { @@ -1616,7 +1692,6 @@ Record *CodeGenSchedModels::findProcResUnits(Record *ProcResKind, ProcUnitDef = *RI; } } - RecVec ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup"); for (RecIter RI = ProcResGroups.begin(), RE = ProcResGroups.end(); RI != RE; ++RI) { @@ -1699,6 +1774,16 @@ unsigned CodeGenProcModel::getProcResourceIdx(Record *PRDef) const { return 1 + (PRPos - ProcResourceDefs.begin()); } +bool CodeGenProcModel::isUnsupported(const CodeGenInstruction &Inst) const { + for (const Record *TheDef : UnsupportedFeaturesDefs) { + for (const Record *PredDef : Inst.TheDef->getValueAsListOfDefs("Predicates")) { + if (TheDef->getName() == PredDef->getName()) + return true; + } + } + return false; +} + #ifndef NDEBUG void CodeGenProcModel::dump() const { dbgs() << Index << ": " << ModelName << " " diff --git a/utils/TableGen/CodeGenSchedule.h b/utils/TableGen/CodeGenSchedule.h index f5c50c992a92..755ffd25b0cb 100644 --- a/utils/TableGen/CodeGenSchedule.h +++ b/utils/TableGen/CodeGenSchedule.h @@ -189,6 +189,10 @@ struct CodeGenProcModel { // This list is empty if no ItinRW refers to this Processor. RecVec ItinRWDefs; + // List of unsupported feature. + // This list is empty if the Processor has no UnsupportedFeatures. + RecVec UnsupportedFeaturesDefs; + // All read/write resources associated with this processor. RecVec WriteResDefs; RecVec ReadAdvanceDefs; @@ -211,6 +215,8 @@ struct CodeGenProcModel { unsigned getProcResourceIdx(Record *PRDef) const; + bool isUnsupported(const CodeGenInstruction &Inst) const; + #ifndef NDEBUG void dump() const; #endif @@ -241,6 +247,9 @@ class CodeGenSchedModels { // Any inferred SchedClass has an index greater than NumInstrSchedClassses. unsigned NumInstrSchedClasses; + RecVec ProcResourceDefs; + RecVec ProcResGroups; + // 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; @@ -300,6 +309,7 @@ public: typedef std::vector<CodeGenProcModel>::const_iterator ProcIter; ProcIter procModelBegin() const { return ProcModels.begin(); } ProcIter procModelEnd() const { return ProcModels.end(); } + ArrayRef<CodeGenProcModel> procModels() const { return ProcModels; } // Return true if any processors have itineraries. bool hasItineraries() const; @@ -353,6 +363,7 @@ public: typedef std::vector<CodeGenSchedClass>::const_iterator SchedClassIter; SchedClassIter schedClassBegin() const { return SchedClasses.begin(); } SchedClassIter schedClassEnd() const { return SchedClasses.end(); } + ArrayRef<CodeGenSchedClass> schedClasses() const { return SchedClasses; } unsigned numInstrSchedClasses() const { return NumInstrSchedClasses; } @@ -397,8 +408,12 @@ private: void collectProcItinRW(); + void collectProcUnsupportedFeatures(); + void inferSchedClasses(); + void checkCompleteness(); + void inferFromRW(ArrayRef<unsigned> OperWrites, ArrayRef<unsigned> OperReads, unsigned FromClassIdx, ArrayRef<unsigned> ProcIndices); void inferFromItinClass(Record *ItinClassDef, unsigned FromClassIdx); diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index aaad4225ace8..245b9eeeed85 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -39,7 +39,7 @@ MVT::SimpleValueType llvm::getValueType(Record *Rec) { return (MVT::SimpleValueType)Rec->getValueAsInt("Value"); } -std::string llvm::getName(MVT::SimpleValueType T) { +StringRef llvm::getName(MVT::SimpleValueType T) { switch (T) { case MVT::Other: return "UNKNOWN"; case MVT::iPTR: return "TLI.getPointerTy()"; @@ -48,7 +48,7 @@ std::string llvm::getName(MVT::SimpleValueType T) { } } -std::string llvm::getEnumName(MVT::SimpleValueType T) { +StringRef llvm::getEnumName(MVT::SimpleValueType T) { switch (T) { case MVT::Other: return "MVT::Other"; case MVT::i1: return "MVT::i1"; @@ -162,7 +162,7 @@ const std::string &CodeGenTarget::getName() const { } std::string CodeGenTarget::getInstNamespace() const { - for (const CodeGenInstruction *Inst : instructions()) { + for (const CodeGenInstruction *Inst : getInstructionsByEnumValue()) { // Make sure not to pick up "TargetOpcode" by accidentally getting // the namespace off the PHI instruction or something. if (Inst->Namespace != "TargetOpcode") @@ -300,14 +300,9 @@ GetInstByName(const char *Name, /// \brief Return all of the instructions defined by the target, ordered by /// their enum value. void CodeGenTarget::ComputeInstrsByEnum() const { - // The ordering here must match the ordering in TargetOpcodes.h. static const char *const FixedInstrs[] = { - "PHI", "INLINEASM", "CFI_INSTRUCTION", "EH_LABEL", - "GC_LABEL", "KILL", "EXTRACT_SUBREG", "INSERT_SUBREG", - "IMPLICIT_DEF", "SUBREG_TO_REG", "COPY_TO_REGCLASS", "DBG_VALUE", - "REG_SEQUENCE", "COPY", "BUNDLE", "LIFETIME_START", - "LIFETIME_END", "STACKMAP", "PATCHPOINT", "LOAD_STACK_GUARD", - "STATEPOINT", "LOCAL_ESCAPE", "FAULTING_LOAD_OP", +#define HANDLE_TARGET_OPCODE(OPC, NUM) #OPC, +#include "llvm/Target/TargetOpcodes.def" nullptr}; const auto &Insts = getInstructions(); for (const char *const *p = FixedInstrs; *p; ++p) { @@ -357,9 +352,9 @@ void CodeGenTarget::reverseBitsForLittleEndianEncoding() { BitsInit *BI = R->getValueAsBitsInit("Inst"); unsigned numBits = BI->getNumBits(); - + SmallVector<Init *, 16> NewBits(numBits); - + for (unsigned bit = 0, end = numBits / 2; bit != end; ++bit) { unsigned bitSwapIdx = numBits - bit - 1; Init *OrigBit = BI->getBit(bit); @@ -431,18 +426,29 @@ ComplexPattern::ComplexPattern(Record *R) { // CodeGenIntrinsic Implementation //===----------------------------------------------------------------------===// -std::vector<CodeGenIntrinsic> llvm::LoadIntrinsics(const RecordKeeper &RC, - bool TargetOnly) { - std::vector<Record*> I = RC.getAllDerivedDefinitions("Intrinsic"); +CodeGenIntrinsicTable::CodeGenIntrinsicTable(const RecordKeeper &RC, + bool TargetOnly) { + std::vector<Record*> Defs = RC.getAllDerivedDefinitions("Intrinsic"); - std::vector<CodeGenIntrinsic> Result; + Intrinsics.reserve(Defs.size()); - for (unsigned i = 0, e = I.size(); i != e; ++i) { - bool isTarget = I[i]->getValueAsBit("isTarget"); + for (unsigned I = 0, e = Defs.size(); I != e; ++I) { + bool isTarget = Defs[I]->getValueAsBit("isTarget"); if (isTarget == TargetOnly) - Result.push_back(CodeGenIntrinsic(I[i])); + Intrinsics.push_back(CodeGenIntrinsic(Defs[I])); } - return Result; + std::sort(Intrinsics.begin(), Intrinsics.end(), + [](const CodeGenIntrinsic &LHS, const CodeGenIntrinsic &RHS) { + return std::tie(LHS.TargetPrefix, LHS.Name) < + std::tie(RHS.TargetPrefix, RHS.Name); + }); + Targets.push_back({"", 0, 0}); + for (size_t I = 0, E = Intrinsics.size(); I < E; ++I) + if (Intrinsics[I].TargetPrefix != Targets.back().Name) { + Targets.back().Count = I - Targets.back().Offset; + Targets.push_back({Intrinsics[I].TargetPrefix, I, 0}); + } + Targets.back().Count = Intrinsics.size() - Targets.back().Offset; } CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { @@ -565,7 +571,7 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { } // Parse the intrinsic properties. - ListInit *PropList = R->getValueAsListInit("Properties"); + ListInit *PropList = R->getValueAsListInit("IntrProperties"); for (unsigned i = 0, e = PropList->size(); i != e; ++i) { Record *Property = PropList->getElementAsRecord(i); assert(Property->isSubClassOf("IntrinsicProperty") && @@ -573,12 +579,12 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { if (Property->getName() == "IntrNoMem") ModRef = NoMem; - else if (Property->getName() == "IntrReadArgMem") - ModRef = ReadArgMem; else if (Property->getName() == "IntrReadMem") - ModRef = ReadMem; - else if (Property->getName() == "IntrReadWriteArgMem") - ModRef = ReadWriteArgMem; + ModRef = ModRefBehavior(ModRef & ~MR_Mod); + else if (Property->getName() == "IntrWriteMem") + ModRef = ModRefBehavior(ModRef & ~MR_Ref); + else if (Property->getName() == "IntrArgMemOnly") + ModRef = ModRefBehavior(ModRef & ~MR_Anywhere); else if (Property->getName() == "Commutative") isCommutative = true; else if (Property->getName() == "Throws") @@ -592,9 +598,15 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { else if (Property->isSubClassOf("NoCapture")) { unsigned ArgNo = Property->getValueAsInt("ArgNo"); ArgumentAttributes.push_back(std::make_pair(ArgNo, NoCapture)); + } else if (Property->isSubClassOf("Returned")) { + unsigned ArgNo = Property->getValueAsInt("ArgNo"); + ArgumentAttributes.push_back(std::make_pair(ArgNo, Returned)); } else if (Property->isSubClassOf("ReadOnly")) { unsigned ArgNo = Property->getValueAsInt("ArgNo"); ArgumentAttributes.push_back(std::make_pair(ArgNo, ReadOnly)); + } else if (Property->isSubClassOf("WriteOnly")) { + unsigned ArgNo = Property->getValueAsInt("ArgNo"); + ArgumentAttributes.push_back(std::make_pair(ArgNo, WriteOnly)); } else if (Property->isSubClassOf("ReadNone")) { unsigned ArgNo = Property->getValueAsInt("ArgNo"); ArgumentAttributes.push_back(std::make_pair(ArgNo, ReadNone)); diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h index cf4a0bbe5bd9..85a8c1b18878 100644 --- a/utils/TableGen/CodeGenTarget.h +++ b/utils/TableGen/CodeGenTarget.h @@ -52,8 +52,8 @@ enum SDNP { /// record corresponds to. MVT::SimpleValueType getValueType(Record *Rec); -std::string getName(MVT::SimpleValueType T); -std::string getEnumName(MVT::SimpleValueType T); +StringRef getName(MVT::SimpleValueType T); +StringRef getEnumName(MVT::SimpleValueType T); /// getQualifiedName - Return the name of the specified record, with a /// namespace qualifier if the record contains one. @@ -139,9 +139,7 @@ public: /// supported by the target (i.e. there are registers that directly hold it). bool isLegalValueType(MVT::SimpleValueType VT) const { ArrayRef<MVT::SimpleValueType> LegalVTs = getLegalValueTypes(); - for (unsigned i = 0, e = LegalVTs.size(); i != e; ++i) - if (LegalVTs[i] == VT) return true; - return false; + return std::find(LegalVTs.begin(), LegalVTs.end(), VT) != LegalVTs.end(); } CodeGenSchedModels &getSchedModels() const; @@ -163,18 +161,15 @@ public: /// getInstructionsByEnumValue - Return all of the instructions defined by the /// target, ordered by their enum value. - const std::vector<const CodeGenInstruction*> & + ArrayRef<const CodeGenInstruction *> getInstructionsByEnumValue() const { if (InstrsByEnum.empty()) ComputeInstrsByEnum(); return InstrsByEnum; } - typedef std::vector<const CodeGenInstruction*>::const_iterator inst_iterator; + typedef ArrayRef<const CodeGenInstruction *>::const_iterator inst_iterator; inst_iterator inst_begin() const{return getInstructionsByEnumValue().begin();} inst_iterator inst_end() const { return getInstructionsByEnumValue().end(); } - iterator_range<inst_iterator> instructions() const { - return make_range(inst_begin(), inst_end()); - } /// isLittleEndianEncoding - are instruction bit patterns defined as [0..n]? diff --git a/utils/TableGen/DAGISelMatcher.cpp b/utils/TableGen/DAGISelMatcher.cpp index 9c4079906a38..6ac3958e0f43 100644 --- a/utils/TableGen/DAGISelMatcher.cpp +++ b/utils/TableGen/DAGISelMatcher.cpp @@ -225,12 +225,14 @@ void CheckFoldableChainNodeMatcher::printImpl(raw_ostream &OS, } void EmitIntegerMatcher::printImpl(raw_ostream &OS, unsigned indent) const { - OS.indent(indent) << "EmitInteger " << Val << " VT=" << VT << '\n'; + OS.indent(indent) << "EmitInteger " << Val << " VT=" << getEnumName(VT) + << '\n'; } void EmitStringIntegerMatcher:: printImpl(raw_ostream &OS, unsigned indent) const { - OS.indent(indent) << "EmitStringInteger " << Val << " VT=" << VT << '\n'; + OS.indent(indent) << "EmitStringInteger " << Val << " VT=" << getEnumName(VT) + << '\n'; } void EmitRegisterMatcher::printImpl(raw_ostream &OS, unsigned indent) const { @@ -239,7 +241,7 @@ void EmitRegisterMatcher::printImpl(raw_ostream &OS, unsigned indent) const { OS << Reg->getName(); else OS << "zero_reg"; - OS << " VT=" << VT << '\n'; + OS << " VT=" << getEnumName(VT) << '\n'; } void EmitConvertToTargetMatcher:: @@ -275,54 +277,12 @@ void EmitNodeMatcherCommon::printImpl(raw_ostream &OS, unsigned indent) const { OS << ")\n"; } -void MarkGlueResultsMatcher::printImpl(raw_ostream &OS, unsigned indent) const { - OS.indent(indent) << "MarkGlueResults <todo: args>\n"; -} - void CompleteMatchMatcher::printImpl(raw_ostream &OS, unsigned indent) const { OS.indent(indent) << "CompleteMatch <todo args>\n"; OS.indent(indent) << "Src = " << *Pattern.getSrcPattern() << "\n"; OS.indent(indent) << "Dst = " << *Pattern.getDstPattern() << "\n"; } -// getHashImpl Implementation. - -unsigned CheckPatternPredicateMatcher::getHashImpl() const { - return HashString(Predicate); -} - -unsigned CheckPredicateMatcher::getHashImpl() const { - return HashString(getPredicate().getFnName()); -} - -unsigned CheckOpcodeMatcher::getHashImpl() const { - return HashString(Opcode.getEnumName()); -} - -unsigned CheckCondCodeMatcher::getHashImpl() const { - return HashString(CondCodeName); -} - -unsigned CheckValueTypeMatcher::getHashImpl() const { - return HashString(TypeName); -} - -unsigned EmitStringIntegerMatcher::getHashImpl() const { - return HashString(Val) ^ VT; -} - -template<typename It> -static unsigned HashUnsigneds(It I, It E) { - unsigned Result = 0; - for (; I != E; ++I) - Result = (Result<<3) ^ *I; - return Result; -} - -unsigned EmitMergeInputChainsMatcher::getHashImpl() const { - return HashUnsigneds(ChainNodes.begin(), ChainNodes.end()); -} - bool CheckOpcodeMatcher::isEqualImpl(const Matcher *M) const { // Note: pointer equality isn't enough here, we have to check the enum names // to ensure that the nodes are for the same opcode. @@ -339,24 +299,10 @@ bool EmitNodeMatcherCommon::isEqualImpl(const Matcher *m) const { M->NumFixedArityOperands == NumFixedArityOperands; } -unsigned EmitNodeMatcherCommon::getHashImpl() const { - return (HashString(OpcodeName) << 4) | Operands.size(); -} - - void EmitNodeMatcher::anchor() { } void MorphNodeToMatcher::anchor() { } -unsigned MarkGlueResultsMatcher::getHashImpl() const { - return HashUnsigneds(GlueResultNodes.begin(), GlueResultNodes.end()); -} - -unsigned CompleteMatchMatcher::getHashImpl() const { - return HashUnsigneds(Results.begin(), Results.end()) ^ - ((unsigned)(intptr_t)&Pattern << 8); -} - // isContradictoryImpl Implementations. static bool TypesAreContradictory(MVT::SimpleValueType T1, diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h index a8a6ba5c32e1..6bda9ca5f96f 100644 --- a/utils/TableGen/DAGISelMatcher.h +++ b/utils/TableGen/DAGISelMatcher.h @@ -82,7 +82,6 @@ public: EmitCopyToReg, // Emit a copytoreg into a physreg. EmitNode, // Create a DAG node EmitNodeXForm, // Run a SDNodeXForm - MarkGlueResults, // Indicate which interior nodes have glue results. CompleteMatch, // Finish a match and update the results. MorphNodeTo // Build a node, finish a match and update results. }; @@ -107,17 +106,6 @@ public: return isEqualImpl(M); } - unsigned getHash() const { - // Clear the high bit so we don't conflict with tombstones etc. - return ((getHashImpl() << 4) ^ getKind()) & (~0U>>1); - } - - /// isSafeToReorderWithPatternPredicate - Return true if it is safe to sink a - /// PatternPredicate node past this one. - virtual bool isSafeToReorderWithPatternPredicate() const { - return false; - } - /// isSimplePredicateNode - Return true if this is a simple predicate that /// operates on the node or its children without potential side effects or a /// change of the current node. @@ -181,7 +169,6 @@ public: protected: virtual void printImpl(raw_ostream &OS, unsigned indent) const = 0; virtual bool isEqualImpl(const Matcher *M) const = 0; - virtual unsigned getHashImpl() const = 0; virtual bool isContradictoryImpl(const Matcher *M) const { return false; } }; @@ -228,7 +215,6 @@ public: private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return false; } - unsigned getHashImpl() const override { return 12312; } }; /// RecordMatcher - Save the current node in the operand list. @@ -251,11 +237,9 @@ public: return N->getKind() == RecordNode; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return true; } - unsigned getHashImpl() const override { return 0; } }; /// RecordChildMatcher - Save a numbered child of the current node, or fail @@ -285,14 +269,11 @@ public: return N->getKind() == RecordChild; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast<RecordChildMatcher>(M)->getChildNo() == getChildNo(); } - unsigned getHashImpl() const override { return getChildNo(); } }; /// RecordMemRefMatcher - Save the current node's memref. @@ -304,12 +285,9 @@ public: return N->getKind() == RecordMemRef; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return true; } - unsigned getHashImpl() const override { return 0; } }; @@ -323,12 +301,9 @@ public: return N->getKind() == CaptureGlueInput; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return true; } - unsigned getHashImpl() const override { return 0; } }; /// MoveChildMatcher - This tells the interpreter to move into the @@ -344,14 +319,11 @@ public: return N->getKind() == MoveChild; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast<MoveChildMatcher>(M)->getChildNo() == getChildNo(); } - unsigned getHashImpl() const override { return getChildNo(); } }; /// MoveParentMatcher - This tells the interpreter to move to the parent @@ -364,12 +336,9 @@ public: return N->getKind() == MoveParent; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return true; } - unsigned getHashImpl() const override { return 0; } }; /// CheckSameMatcher - This checks to see if this node is exactly the same @@ -387,14 +356,11 @@ public: return N->getKind() == CheckSame; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast<CheckSameMatcher>(M)->getMatchNumber() == getMatchNumber(); } - unsigned getHashImpl() const override { return getMatchNumber(); } }; /// CheckChildSameMatcher - This checks to see if child node is exactly the same @@ -414,15 +380,12 @@ public: return N->getKind() == CheckChildSame; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast<CheckChildSameMatcher>(M)->ChildNo == ChildNo && cast<CheckChildSameMatcher>(M)->MatchNumber == MatchNumber; } - unsigned getHashImpl() const override { return (MatchNumber << 2) | ChildNo; } }; /// CheckPatternPredicateMatcher - This checks the target-specific predicate @@ -440,14 +403,11 @@ public: return N->getKind() == CheckPatternPredicate; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast<CheckPatternPredicateMatcher>(M)->getPredicate() == Predicate; } - unsigned getHashImpl() const override; }; /// CheckPredicateMatcher - This checks the target-specific predicate to @@ -463,15 +423,11 @@ public: return N->getKind() == CheckPredicate; } - // TODO: Ok? - //virtual bool isSafeToReorderWithPatternPredicate() const { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast<CheckPredicateMatcher>(M)->Pred == Pred; } - unsigned getHashImpl() const override; }; @@ -489,12 +445,9 @@ public: return N->getKind() == CheckOpcode; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override; - unsigned getHashImpl() const override; bool isContradictoryImpl(const Matcher *M) const override; }; @@ -522,7 +475,6 @@ public: private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return false; } - unsigned getHashImpl() const override { return 4123; } }; /// CheckTypeMatcher - This checks to see if the current node has the @@ -541,14 +493,11 @@ public: return N->getKind() == CheckType; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast<CheckTypeMatcher>(M)->Type == Type; } - unsigned getHashImpl() const override { return Type; } bool isContradictoryImpl(const Matcher *M) const override; }; @@ -576,7 +525,6 @@ public: private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return false; } - unsigned getHashImpl() const override { return 4123; } }; @@ -596,15 +544,12 @@ public: return N->getKind() == CheckChildType; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast<CheckChildTypeMatcher>(M)->ChildNo == ChildNo && cast<CheckChildTypeMatcher>(M)->Type == Type; } - unsigned getHashImpl() const override { return (Type << 3) | ChildNo; } bool isContradictoryImpl(const Matcher *M) const override; }; @@ -623,14 +568,11 @@ public: return N->getKind() == CheckInteger; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast<CheckIntegerMatcher>(M)->Value == Value; } - unsigned getHashImpl() const override { return Value; } bool isContradictoryImpl(const Matcher *M) const override; }; @@ -650,15 +592,12 @@ public: return N->getKind() == CheckChildInteger; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast<CheckChildIntegerMatcher>(M)->ChildNo == ChildNo && cast<CheckChildIntegerMatcher>(M)->Value == Value; } - unsigned getHashImpl() const override { return (Value << 3) | ChildNo; } bool isContradictoryImpl(const Matcher *M) const override; }; @@ -676,14 +615,11 @@ public: return N->getKind() == CheckCondCode; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast<CheckCondCodeMatcher>(M)->CondCodeName == CondCodeName; } - unsigned getHashImpl() const override; }; /// CheckValueTypeMatcher - This checks to see if the current node is a @@ -700,14 +636,11 @@ public: return N->getKind() == CheckValueType; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast<CheckValueTypeMatcher>(M)->TypeName == TypeName; } - unsigned getHashImpl() const override; bool isContradictoryImpl(const Matcher *M) const override; }; @@ -744,18 +677,12 @@ public: return N->getKind() == CheckComplexPat; } - // Not safe to move a pattern predicate past a complex pattern. - bool isSafeToReorderWithPatternPredicate() const override { return false; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return &cast<CheckComplexPatMatcher>(M)->Pattern == &Pattern && cast<CheckComplexPatMatcher>(M)->MatchNumber == MatchNumber; } - unsigned getHashImpl() const override { - return (unsigned)(intptr_t)&Pattern ^ MatchNumber; - } }; /// CheckAndImmMatcher - This checks to see if the current node is an 'and' @@ -772,14 +699,11 @@ public: return N->getKind() == CheckAndImm; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast<CheckAndImmMatcher>(M)->Value == Value; } - unsigned getHashImpl() const override { return Value; } }; /// CheckOrImmMatcher - This checks to see if the current node is an 'and' @@ -796,14 +720,11 @@ public: return N->getKind() == CheckOrImm; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast<CheckOrImmMatcher>(M)->Value == Value; } - unsigned getHashImpl() const override { return Value; } }; /// CheckFoldableChainNodeMatcher - This checks to see if the current node @@ -817,12 +738,9 @@ public: return N->getKind() == CheckFoldableChainNode; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return true; } - unsigned getHashImpl() const override { return 0; } }; /// EmitIntegerMatcher - This creates a new TargetConstant. @@ -846,7 +764,6 @@ private: return cast<EmitIntegerMatcher>(M)->Val == Val && cast<EmitIntegerMatcher>(M)->VT == VT; } - unsigned getHashImpl() const override { return (Val << 4) | VT; } }; /// EmitStringIntegerMatcher - A target constant whose value is represented @@ -871,7 +788,6 @@ private: return cast<EmitStringIntegerMatcher>(M)->Val == Val && cast<EmitStringIntegerMatcher>(M)->VT == VT; } - unsigned getHashImpl() const override; }; /// EmitRegisterMatcher - This creates a new TargetConstant. @@ -897,9 +813,6 @@ private: return cast<EmitRegisterMatcher>(M)->Reg == Reg && cast<EmitRegisterMatcher>(M)->VT == VT; } - unsigned getHashImpl() const override { - return ((unsigned)(intptr_t)Reg) << 4 | VT; - } }; /// EmitConvertToTargetMatcher - Emit an operation that reads a specified @@ -922,7 +835,6 @@ private: bool isEqualImpl(const Matcher *M) const override { return cast<EmitConvertToTargetMatcher>(M)->Slot == Slot; } - unsigned getHashImpl() const override { return Slot; } }; /// EmitMergeInputChainsMatcher - Emit a node that merges a list of input @@ -951,7 +863,6 @@ private: bool isEqualImpl(const Matcher *M) const override { return cast<EmitMergeInputChainsMatcher>(M)->ChainNodes == ChainNodes; } - unsigned getHashImpl() const override; }; /// EmitCopyToRegMatcher - Emit a CopyToReg node from a value to a physreg, @@ -977,9 +888,6 @@ private: return cast<EmitCopyToRegMatcher>(M)->SrcSlot == SrcSlot && cast<EmitCopyToRegMatcher>(M)->DestPhysReg == DestPhysReg; } - unsigned getHashImpl() const override { - return SrcSlot ^ ((unsigned)(intptr_t)DestPhysReg << 4); - } }; @@ -1006,9 +914,6 @@ private: return cast<EmitNodeXFormMatcher>(M)->Slot == Slot && cast<EmitNodeXFormMatcher>(M)->NodeXForm == NodeXForm; } - unsigned getHashImpl() const override { - return Slot ^ ((unsigned)(intptr_t)NodeXForm << 4); - } }; /// EmitNodeMatcherCommon - Common class shared between EmitNode and @@ -1066,7 +971,6 @@ public: private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override; - unsigned getHashImpl() const override; }; /// EmitNodeMatcher - This signals a successful match and generates a node. @@ -1116,34 +1020,6 @@ public: } }; -/// MarkGlueResultsMatcher - This node indicates which non-root nodes in the -/// pattern produce glue. This allows CompleteMatchMatcher to update them -/// with the output glue of the resultant code. -class MarkGlueResultsMatcher : public Matcher { - SmallVector<unsigned, 3> GlueResultNodes; -public: - MarkGlueResultsMatcher(ArrayRef<unsigned> nodes) - : Matcher(MarkGlueResults), GlueResultNodes(nodes.begin(), nodes.end()) {} - - unsigned getNumNodes() const { return GlueResultNodes.size(); } - - unsigned getNode(unsigned i) const { - assert(i < GlueResultNodes.size()); - return GlueResultNodes[i]; - } - - static inline bool classof(const Matcher *N) { - return N->getKind() == MarkGlueResults; - } - -private: - void printImpl(raw_ostream &OS, unsigned indent) const override; - bool isEqualImpl(const Matcher *M) const override { - return cast<MarkGlueResultsMatcher>(M)->GlueResultNodes == GlueResultNodes; - } - unsigned getHashImpl() const override; -}; - /// CompleteMatchMatcher - Complete a match by replacing the results of the /// pattern with the newly generated nodes. This also prints a comment /// indicating the source and dest patterns. @@ -1170,7 +1046,6 @@ private: return cast<CompleteMatchMatcher>(M)->Results == Results && &cast<CompleteMatchMatcher>(M)->Pattern == &Pattern; } - unsigned getHashImpl() const override; }; } // end namespace llvm diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp index 26f53dca6361..d30fc5131cba 100644 --- a/utils/TableGen/DAGISelMatcherEmitter.cpp +++ b/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -247,9 +247,16 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, OS << "OPC_CaptureGlueInput,\n"; return 1; - case Matcher::MoveChild: - OS << "OPC_MoveChild, " << cast<MoveChildMatcher>(N)->getChildNo() << ",\n"; - return 2; + case Matcher::MoveChild: { + const auto *MCM = cast<MoveChildMatcher>(N); + + OS << "OPC_MoveChild"; + // Handle the specialized forms. + if (MCM->getChildNo() >= 8) + OS << ", "; + OS << MCM->getChildNo() << ",\n"; + return (MCM->getChildNo() >= 8) ? 2 : 1; + } case Matcher::MoveParent: OS << "OPC_MoveParent,\n"; @@ -500,8 +507,8 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, const EmitMergeInputChainsMatcher *MN = cast<EmitMergeInputChainsMatcher>(N); - // Handle the specialized forms OPC_EmitMergeInputChains1_0 and 1_1. - if (MN->getNumNodes() == 1 && MN->getNode(0) < 2) { + // Handle the specialized forms OPC_EmitMergeInputChains1_0, 1_1, and 1_2. + if (MN->getNumNodes() == 1 && MN->getNode(0) < 3) { OS << "OPC_EmitMergeInputChains1_" << MN->getNode(0) << ",\n"; return 1; } @@ -532,6 +539,10 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, case Matcher::MorphNodeTo: { const EmitNodeMatcherCommon *EN = cast<EmitNodeMatcherCommon>(N); OS << (isa<EmitNodeMatcher>(EN) ? "OPC_EmitNode" : "OPC_MorphNodeTo"); + bool CompressVTs = EN->getNumVTs() < 3; + if (CompressVTs) + OS << EN->getNumVTs(); + OS << ", TARGET_VAL(" << EN->getOpcodeName() << "), 0"; if (EN->hasChain()) OS << "|OPFL_Chain"; @@ -542,10 +553,13 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, OS << "|OPFL_Variadic" << EN->getNumFixedArityOperands(); OS << ",\n"; - OS.PadToColumn(Indent*2+4) << EN->getNumVTs(); - if (!OmitComments) - OS << "/*#VTs*/"; - OS << ", "; + OS.PadToColumn(Indent*2+4); + if (!CompressVTs) { + OS << EN->getNumVTs(); + if (!OmitComments) + OS << "/*#VTs*/"; + OS << ", "; + } for (unsigned i = 0, e = EN->getNumVTs(); i != e; ++i) OS << getEnumName(EN->getVT(i)) << ", "; @@ -579,16 +593,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, } else OS << '\n'; - return 6+EN->getNumVTs()+NumOperandBytes; - } - case Matcher::MarkGlueResults: { - const MarkGlueResultsMatcher *CFR = cast<MarkGlueResultsMatcher>(N); - OS << "OPC_MarkGlueResults, " << CFR->getNumNodes() << ", "; - unsigned NumOperandBytes = 0; - for (unsigned i = 0, e = CFR->getNumNodes(); i != e; ++i) - NumOperandBytes += EmitVBRValue(CFR->getNode(i), OS); - OS << '\n'; - return 2+NumOperandBytes; + return 5 + !CompressVTs + EN->getNumVTs() + NumOperandBytes; } case Matcher::CompleteMatch: { const CompleteMatchMatcher *CM = cast<CompleteMatchMatcher>(N); @@ -807,7 +812,6 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M, case Matcher::EmitNode: OS << "OPC_EmitNode"; break; case Matcher::MorphNodeTo: OS << "OPC_MorphNodeTo"; break; case Matcher::EmitNodeXForm: OS << "OPC_EmitNodeXForm"; break; - case Matcher::MarkGlueResults: OS << "OPC_MarkGlueResults"; break; case Matcher::CompleteMatch: OS << "OPC_CompleteMatch"; break; } @@ -837,8 +841,9 @@ void llvm::EmitMatcherTable(const Matcher *TheMatcher, MatcherEmitter.EmitHistogram(TheMatcher, OS); OS << " #undef TARGET_VAL\n"; - OS << " return SelectCodeCommon(N, MatcherTable,sizeof(MatcherTable));\n}\n"; - OS << '\n'; + OS << " SelectCodeCommon(N, MatcherTable,sizeof(MatcherTable));\n"; + OS << " return nullptr;\n"; + OS << "}\n"; // Next up, emit the function for node and pattern predicates: MatcherEmitter.EmitPredicateFunctions(OS); diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp index 9663b71d6620..4110e9725b5a 100644 --- a/utils/TableGen/DAGISelMatcherGen.cpp +++ b/utils/TableGen/DAGISelMatcherGen.cpp @@ -10,7 +10,6 @@ #include "DAGISelMatcher.h" #include "CodeGenDAGPatterns.h" #include "CodeGenRegisters.h" -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/TableGen/Error.h" @@ -76,10 +75,6 @@ namespace { /// array of all of the recorded input nodes that have chains. SmallVector<unsigned, 2> MatchedChainNodes; - /// MatchedGlueResultNodes - This maintains the position in the recorded - /// nodes array of all of the recorded input nodes that have glue results. - SmallVector<unsigned, 2> MatchedGlueResultNodes; - /// MatchedComplexPatterns - This maintains a list of all of the /// ComplexPatterns that we need to check. The second element of each pair /// is the recorded operand number of the input node. @@ -121,7 +116,7 @@ namespace { /// If this is the first time a node with unique identifier Name has been /// seen, record it. Otherwise, emit a check to make sure this is the same /// node. Returns true if this is the first encounter. - bool recordUniqueNode(std::string Name); + bool recordUniqueNode(const std::string &Name); // Result Code Generation. unsigned getNamedArgumentSlot(StringRef Name) { @@ -426,8 +421,6 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N, AddMatcher(new RecordMatcher("'" + N->getOperator()->getName() + "' glue output node", NextRecordedOperandNo)); - // Remember all of the nodes with output glue our pattern will match. - MatchedGlueResultNodes.push_back(NextRecordedOperandNo++); } // If this node is known to have an input glue or if it *might* have an input @@ -445,7 +438,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N, } } -bool MatcherGen::recordUniqueNode(std::string Name) { +bool MatcherGen::recordUniqueNode(const std::string &Name) { unsigned &VarMapEntry = VariableMap[Name]; if (VarMapEntry == 0) { // If it is a named node, we must emit a 'Record' opcode. @@ -989,11 +982,6 @@ void MatcherGen::EmitResultCode() { assert(Ops.size() >= NumSrcResults && "Didn't provide enough results"); Ops.resize(NumSrcResults); - // If the matched pattern covers nodes which define a glue result, emit a node - // that tells the matcher about them so that it can update their results. - if (!MatchedGlueResultNodes.empty()) - AddMatcher(new MarkGlueResultsMatcher(MatchedGlueResultNodes)); - AddMatcher(new CompleteMatchMatcher(Ops, Pattern)); } diff --git a/utils/TableGen/DAGISelMatcherOpt.cpp b/utils/TableGen/DAGISelMatcherOpt.cpp index c9ee371e3e2f..ad385fac0438 100644 --- a/utils/TableGen/DAGISelMatcherOpt.cpp +++ b/utils/TableGen/DAGISelMatcherOpt.cpp @@ -13,7 +13,6 @@ #include "DAGISelMatcher.h" #include "CodeGenDAGPatterns.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -79,24 +78,6 @@ static void ContractNodes(std::unique_ptr<Matcher> &MatcherPtr, return ContractNodes(MatcherPtr, CGP); } - // Turn EmitNode->MarkFlagResults->CompleteMatch into - // MarkFlagResults->EmitNode->CompleteMatch when we can to encourage - // MorphNodeTo formation. This is safe because MarkFlagResults never refers - // to the root of the pattern. - if (isa<EmitNodeMatcher>(N) && isa<MarkGlueResultsMatcher>(N->getNext()) && - isa<CompleteMatchMatcher>(N->getNext()->getNext())) { - // Unlink the two nodes from the list. - Matcher *EmitNode = MatcherPtr.release(); - Matcher *MFR = EmitNode->takeNext(); - Matcher *Tail = MFR->takeNext(); - - // Relink them. - MatcherPtr.reset(MFR); - MFR->setNext(EmitNode); - EmitNode->setNext(Tail); - return ContractNodes(MatcherPtr, CGP); - } - // Turn EmitNode->CompleteMatch into MorphNodeTo if we can. if (EmitNodeMatcher *EN = dyn_cast<EmitNodeMatcher>(N)) if (CompleteMatchMatcher *CM = @@ -177,59 +158,6 @@ static void ContractNodes(std::unique_ptr<Matcher> &MatcherPtr, } } -/// SinkPatternPredicates - Pattern predicates can be checked at any level of -/// the matching tree. The generator dumps them at the top level of the pattern -/// though, which prevents factoring from being able to see past them. This -/// optimization sinks them as far down into the pattern as possible. -/// -/// Conceptually, we'd like to sink these predicates all the way to the last -/// matcher predicate in the series. However, it turns out that some -/// ComplexPatterns have side effects on the graph, so we really don't want to -/// run a complex pattern if the pattern predicate will fail. For this -/// reason, we refuse to sink the pattern predicate past a ComplexPattern. -/// -static void SinkPatternPredicates(std::unique_ptr<Matcher> &MatcherPtr) { - // Recursively scan for a PatternPredicate. - // If we reached the end of the chain, we're done. - Matcher *N = MatcherPtr.get(); - if (!N) return; - - // Walk down all members of a scope node. - if (ScopeMatcher *Scope = dyn_cast<ScopeMatcher>(N)) { - for (unsigned i = 0, e = Scope->getNumChildren(); i != e; ++i) { - std::unique_ptr<Matcher> Child(Scope->takeChild(i)); - SinkPatternPredicates(Child); - Scope->resetChild(i, Child.release()); - } - return; - } - - // If this node isn't a CheckPatternPredicateMatcher we keep scanning until - // we find one. - CheckPatternPredicateMatcher *CPPM =dyn_cast<CheckPatternPredicateMatcher>(N); - if (!CPPM) - return SinkPatternPredicates(N->getNextPtr()); - - // Ok, we found one, lets try to sink it. Check if we can sink it past the - // next node in the chain. If not, we won't be able to change anything and - // might as well bail. - if (!CPPM->getNext()->isSafeToReorderWithPatternPredicate()) - return; - - // Okay, we know we can sink it past at least one node. Unlink it from the - // chain and scan for the new insertion point. - MatcherPtr.release(); // Don't delete CPPM. - MatcherPtr.reset(CPPM->takeNext()); - - N = MatcherPtr.get(); - while (N->getNext()->isSafeToReorderWithPatternPredicate()) - N = N->getNext(); - - // At this point, we want to insert CPPM after N. - CPPM->setNext(N->takeNext()); - N->setNext(CPPM); -} - /// FindNodeWithKind - Scan a series of matchers looking for a matcher with a /// specified kind. Return null if we didn't find one otherwise return the /// matcher. @@ -264,8 +192,7 @@ static void FactorNodes(std::unique_ptr<Matcher> &MatcherPtr) { return FactorNodes(N->getNextPtr()); // Okay, pull together the children of the scope node into a vector so we can - // inspect it more easily. While we're at it, bucket them up by the hash - // code of their first predicate. + // inspect it more easily. SmallVector<Matcher*, 32> OptionsToMatch; for (unsigned i = 0, e = Scope->getNumChildren(); i != e; ++i) { @@ -456,7 +383,8 @@ static void FactorNodes(std::unique_ptr<Matcher> &MatcherPtr) { CheckOpcodeMatcher *COM = cast<CheckOpcodeMatcher>(NewOptionsToMatch[i]); assert(Opcodes.insert(COM->getOpcode().getEnumName()).second && "Duplicate opcodes not factored?"); - Cases.push_back(std::make_pair(&COM->getOpcode(), COM->getNext())); + Cases.push_back(std::make_pair(&COM->getOpcode(), COM->takeNext())); + delete COM; } MatcherPtr.reset(new SwitchOpcodeMatcher(Cases)); @@ -486,7 +414,9 @@ static void FactorNodes(std::unique_ptr<Matcher> &MatcherPtr) { } Matcher *Entries[2] = { PrevMatcher, MatcherWithoutCTM }; - Cases[Entry-1].second = new ScopeMatcher(Entries); + std::unique_ptr<Matcher> Case(new ScopeMatcher(Entries)); + FactorNodes(Case); + Cases[Entry-1].second = Case.release(); continue; } @@ -515,6 +445,5 @@ void llvm::OptimizeMatcher(std::unique_ptr<Matcher> &MatcherPtr, const CodeGenDAGPatterns &CGP) { ContractNodes(MatcherPtr, CGP); - SinkPatternPredicates(MatcherPtr); FactorNodes(MatcherPtr); } diff --git a/utils/TableGen/DFAPacketizerEmitter.cpp b/utils/TableGen/DFAPacketizerEmitter.cpp index 77afff7ab5c2..e31caaf3c98c 100644 --- a/utils/TableGen/DFAPacketizerEmitter.cpp +++ b/utils/TableGen/DFAPacketizerEmitter.cpp @@ -1,4 +1,4 @@ -//===- DFAPacketizerEmitter.cpp - Packetization DFA for a VLIW machine-----===// +//===- DFAPacketizerEmitter.cpp - Packetization DFA for a VLIW machine ----===// // // The LLVM Compiler Infrastructure // @@ -24,10 +24,10 @@ #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" #include "llvm/Support/Debug.h" -#include <list> #include <map> #include <string> #include <queue> + using namespace llvm; // -------------------------------------------------------------------- @@ -73,7 +73,8 @@ namespace { InsnInput = addDFAFuncUnits(InsnInput, U); return InsnInput; } -} +} // end anonymous namespace + // -------------------------------------------------------------------- #ifndef NDEBUG @@ -149,7 +150,7 @@ public: void run(raw_ostream &OS); }; -} // End anonymous namespace. +} // end anonymous namespace // // @@ -234,7 +235,7 @@ class State { // bool hasTransition(std::vector<unsigned> InsnClass) const; }; -} // End anonymous namespace. +} // end anonymous namespace // // class DFA: deterministic finite automaton for processor resource tracking. @@ -262,7 +263,7 @@ public: int numInsnClasses = 0, int maxResources = 0, int numCombos = 0, int maxStages = 0); }; -} // End anonymous namespace. +} // end anonymous namespace #ifndef NDEBUG // To enable debugging, run llvm-tblgen with: "-debug-only dfa-emitter". @@ -305,7 +306,7 @@ void dbgsIndent(unsigned indent) { DEBUG(dbgs() << " "); } } -#endif +#endif // NDEBUG // // Constructors and destructors for State and DFA @@ -454,7 +455,6 @@ void State::AddInsnClassStages(std::vector<unsigned> &InsnClass, } } - // // canMaybeAddInsnClass - Quickly verifies if an instruction of type InsnClass // may be a valid transition from this state i.e., can an instruction of type @@ -505,7 +505,6 @@ bool State::canMaybeAddInsnClass(std::vector<unsigned> &InsnClass, return false; } - const State &DFA::newState() { auto IterPair = states.insert(State()); assert(IterPair.second && "State already exists"); @@ -518,7 +517,6 @@ DFAPacketizerEmitter::DFAPacketizerEmitter(RecordKeeper &R): TargetName(CodeGenTarget(R).getName()), allInsnClasses(), Records(R) {} - // // writeTableAndAPI - Print out a table representing the DFA and the // associated API to create a DFA packetizer. @@ -626,7 +624,6 @@ void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName, OS << "};\n"; OS << "} // namespace\n"; - // // Emit DFA Packetizer tables if the target is a VLIW machine. // @@ -640,7 +637,6 @@ void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName, OS << "} // End llvm namespace \n"; } - // // collectAllFuncUnits - Construct a map of function unit names to bits. // @@ -713,7 +709,7 @@ int DFAPacketizerEmitter::collectAllComboFuncs( Record *ComboFunc = FuncData->getValueAsDef("TheComboFunc"); const std::vector<Record*> &FuncList = FuncData->getValueAsListOfDefs("FuncList"); - std::string ComboFuncName = ComboFunc->getName(); + const std::string &ComboFuncName = ComboFunc->getName(); unsigned ComboBit = FUNameToBitsMap[ComboFuncName]; unsigned ComboResources = ComboBit; DEBUG(dbgs() << " combo: " << ComboFuncName @@ -735,7 +731,6 @@ int DFAPacketizerEmitter::collectAllComboFuncs( return numCombos; } - // // collectOneInsnClass - Populate allInsnClasses with one instruction class // @@ -940,7 +935,7 @@ void DFAPacketizerEmitter::run(raw_ostream &OS) { // if (!current->hasTransition(InsnClass) && current->canMaybeAddInsnClass(InsnClass, ComboBitToBitsMap)) { - const State *NewState = NULL; + const State *NewState = nullptr; current->AddInsnClass(InsnClass, ComboBitToBitsMap, NewStateResources); if (NewStateResources.size() == 0) { DEBUG(dbgs() << " Skipped - no new states generated\n"); @@ -994,4 +989,4 @@ void EmitDFAPacketizer(RecordKeeper &RK, raw_ostream &OS) { DFAPacketizerEmitter(RK).run(OS); } -} // End llvm namespace +} // end namespaec llvm diff --git a/utils/TableGen/DisassemblerEmitter.cpp b/utils/TableGen/DisassemblerEmitter.cpp index e8595271bcce..44815b05f274 100644 --- a/utils/TableGen/DisassemblerEmitter.cpp +++ b/utils/TableGen/DisassemblerEmitter.cpp @@ -96,12 +96,11 @@ using namespace llvm::X86Disassembler; namespace llvm { extern void EmitFixedLenDecoder(RecordKeeper &RK, raw_ostream &OS, - std::string PredicateNamespace, - std::string GPrefix, - std::string GPostfix, - std::string ROK, - std::string RFail, - std::string L); + const std::string &PredicateNamespace, + const std::string &GPrefix, + const std::string &GPostfix, + const std::string &ROK, + const std::string &RFail, const std::string &L); void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) { CodeGenTarget Target(Records); @@ -111,7 +110,7 @@ void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) { if (Target.getName() == "X86") { DisassemblerTables Tables; - const std::vector<const CodeGenInstruction*> &numberedInstructions = + ArrayRef<const CodeGenInstruction*> numberedInstructions = Target.getInstructionsByEnumValue(); for (unsigned i = 0, e = numberedInstructions.size(); i != e; ++i) diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp index 748c92347783..debb12c4f511 100644 --- a/utils/TableGen/FastISelEmitter.cpp +++ b/utils/TableGen/FastISelEmitter.cpp @@ -18,13 +18,13 @@ //===----------------------------------------------------------------------===// #include "CodeGenDAGPatterns.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" +#include <utility> using namespace llvm; @@ -417,9 +417,7 @@ static std::string getLegalCName(std::string OpName) { return OpName; } -FastISelMap::FastISelMap(std::string instns) - : InstNS(instns) { -} +FastISelMap::FastISelMap(std::string instns) : InstNS(std::move(instns)) {} static std::string PhyRegForNode(TreePatternNode *Op, const CodeGenTarget &Target) { diff --git a/utils/TableGen/FixedLenDecoderEmitter.cpp b/utils/TableGen/FixedLenDecoderEmitter.cpp index 8ca4a1bf5404..0506400b90f6 100644 --- a/utils/TableGen/FixedLenDecoderEmitter.cpp +++ b/utils/TableGen/FixedLenDecoderEmitter.cpp @@ -28,6 +28,7 @@ #include "llvm/TableGen/Record.h" #include <map> #include <string> +#include <utility> #include <vector> using namespace llvm; @@ -47,7 +48,7 @@ struct OperandInfo { bool HasCompleteDecoder; OperandInfo(std::string D, bool HCD) - : Decoder(D), HasCompleteDecoder(HCD) { } + : Decoder(std::move(D)), HasCompleteDecoder(HCD) {} void addField(unsigned Base, unsigned Width, unsigned Offset) { Fields.push_back(EncodingField(Base, Width, Offset)); @@ -78,22 +79,21 @@ struct DecoderTableInfo { namespace { class FixedLenDecoderEmitter { - const std::vector<const CodeGenInstruction*> *NumberedInstructions; + ArrayRef<const CodeGenInstruction *> NumberedInstructions; public: // Defaults preserved here for documentation, even though they aren't // strictly necessary given the way that this is currently being called. - FixedLenDecoderEmitter(RecordKeeper &R, - std::string PredicateNamespace, - std::string GPrefix = "if (", + FixedLenDecoderEmitter(RecordKeeper &R, std::string PredicateNamespace, + std::string GPrefix = "if (", std::string GPostfix = " == MCDisassembler::Fail)", - std::string ROK = "MCDisassembler::Success", - std::string RFail = "MCDisassembler::Fail", - std::string L = "") : - Target(R), - PredicateNamespace(PredicateNamespace), - GuardPrefix(GPrefix), GuardPostfix(GPostfix), - ReturnOK(ROK), ReturnFail(RFail), Locals(L) {} + std::string ROK = "MCDisassembler::Success", + std::string RFail = "MCDisassembler::Fail", + std::string L = "") + : Target(R), PredicateNamespace(std::move(PredicateNamespace)), + GuardPrefix(std::move(GPrefix)), GuardPostfix(std::move(GPostfix)), + ReturnOK(std::move(ROK)), ReturnFail(std::move(RFail)), + Locals(std::move(L)) {} // Emit the decoder state machine table. void emitTable(formatted_raw_ostream &o, DecoderTable &Table, @@ -306,7 +306,7 @@ protected: friend class Filter; // Vector of codegen instructions to choose our filter. - const std::vector<const CodeGenInstruction*> &AllInstructions; + ArrayRef<const CodeGenInstruction *> AllInstructions; // Vector of uid's for this filter chooser to work on. const std::vector<unsigned> &Opcodes; @@ -337,7 +337,7 @@ protected: void operator=(const FilterChooser &) = delete; public: - FilterChooser(const std::vector<const CodeGenInstruction*> &Insts, + FilterChooser(ArrayRef<const CodeGenInstruction *> Insts, const std::vector<unsigned> &IDs, const std::map<unsigned, std::vector<OperandInfo> > &Ops, unsigned BW, @@ -348,7 +348,7 @@ public: doFilter(); } - FilterChooser(const std::vector<const CodeGenInstruction*> &Insts, + FilterChooser(ArrayRef<const CodeGenInstruction *> Insts, const std::vector<unsigned> &IDs, const std::map<unsigned, std::vector<OperandInfo> > &Ops, const std::vector<bit_value_t> &ParentFilterBitValues, @@ -410,9 +410,6 @@ protected: return Filters[BestIndex]; } - // Called from Filter::recurse() when singleton exists. For debug purpose. - void SingletonExists(unsigned Opc) const; - bool PositionFiltered(unsigned i) const { return ValueSet(FilterBitValues[i]); } @@ -559,7 +556,6 @@ void Filter::recurse() { // No need to recurse for a singleton filtered instruction. // See also Filter::emit*(). if (getNumFiltered() == 1) { - //Owner->SingletonExists(LastOpcFiltered); assert(FilterChooserMap.size() == 1); return; } @@ -732,15 +728,15 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS, OS.indent(Indentation) << "MCD::OPC_FilterValue, "; // The filter value is ULEB128 encoded. while (*I >= 128) - OS << utostr(*I++) << ", "; - OS << utostr(*I++) << ", "; + OS << (unsigned)*I++ << ", "; + OS << (unsigned)*I++ << ", "; // 16-bit numtoskip value. uint8_t Byte = *I++; uint32_t NumToSkip = Byte; - OS << utostr(Byte) << ", "; + OS << (unsigned)Byte << ", "; Byte = *I++; - OS << utostr(Byte) << ", "; + OS << (unsigned)Byte << ", "; NumToSkip |= Byte << 8; OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; break; @@ -753,14 +749,14 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS, << Len << ", ";// << Val << ", " << NumToSkip << ",\n"; // ULEB128 encoded field value. for (; *I >= 128; ++I) - OS << utostr(*I) << ", "; - OS << utostr(*I++) << ", "; + OS << (unsigned)*I << ", "; + OS << (unsigned)*I++ << ", "; // 16-bit numtoskip value. uint8_t Byte = *I++; uint32_t NumToSkip = Byte; - OS << utostr(Byte) << ", "; + OS << (unsigned)Byte << ", "; Byte = *I++; - OS << utostr(Byte) << ", "; + OS << (unsigned)Byte << ", "; NumToSkip |= Byte << 8; OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; break; @@ -769,15 +765,15 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS, ++I; OS.indent(Indentation) << "MCD::OPC_CheckPredicate, "; for (; *I >= 128; ++I) - OS << utostr(*I) << ", "; - OS << utostr(*I++) << ", "; + OS << (unsigned)*I << ", "; + OS << (unsigned)*I++ << ", "; // 16-bit numtoskip value. uint8_t Byte = *I++; uint32_t NumToSkip = Byte; - OS << utostr(Byte) << ", "; + OS << (unsigned)Byte << ", "; Byte = *I++; - OS << utostr(Byte) << ", "; + OS << (unsigned)Byte << ", "; NumToSkip |= Byte << 8; OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; break; @@ -796,17 +792,17 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS, OS.indent(Indentation) << "MCD::OPC_" << (IsTry ? "Try" : "") << "Decode, "; for (p = Buffer; *p >= 128; ++p) - OS << utostr(*p) << ", "; - OS << utostr(*p) << ", "; + OS << (unsigned)*p << ", "; + OS << (unsigned)*p << ", "; // Decoder index. for (; *I >= 128; ++I) - OS << utostr(*I) << ", "; - OS << utostr(*I++) << ", "; + OS << (unsigned)*I << ", "; + OS << (unsigned)*I++ << ", "; if (!IsTry) { OS << "// Opcode: " - << NumberedInstructions->at(Opc)->TheDef->getName() << "\n"; + << NumberedInstructions[Opc]->TheDef->getName() << "\n"; break; } @@ -815,13 +811,13 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS, // 16-bit numtoskip value. uint8_t Byte = *I++; uint32_t NumToSkip = Byte; - OS << utostr(Byte) << ", "; + OS << (unsigned)Byte << ", "; Byte = *I++; - OS << utostr(Byte) << ", "; + OS << (unsigned)Byte << ", "; NumToSkip |= Byte << 8; OS << "// Opcode: " - << NumberedInstructions->at(Opc)->TheDef->getName() + << NumberedInstructions[Opc]->TheDef->getName() << ", skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; break; } @@ -832,22 +828,28 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS, uint64_t Value = 0; unsigned Shift = 0; do { - OS << ", " << utostr(*I); + OS << ", " << (unsigned)*I; Value += (*I & 0x7f) << Shift; Shift += 7; } while (*I++ >= 128); - if (Value > 127) - OS << " /* 0x" << utohexstr(Value) << " */"; + if (Value > 127) { + OS << " /* 0x"; + OS.write_hex(Value); + OS << " */"; + } // Negative mask Value = 0; Shift = 0; do { - OS << ", " << utostr(*I); + OS << ", " << (unsigned)*I; Value += (*I & 0x7f) << Shift; Shift += 7; } while (*I++ >= 128); - if (Value > 127) - OS << " /* 0x" << utohexstr(Value) << " */"; + if (Value > 127) { + OS << " /* 0x"; + OS.write_hex(Value); + OS << " */"; + } OS << ",\n"; break; } @@ -971,30 +973,6 @@ void FilterChooser::dumpStack(raw_ostream &o, const char *prefix) const { } } -// Called from Filter::recurse() when singleton exists. For debug purpose. -void FilterChooser::SingletonExists(unsigned Opc) const { - insn_t Insn0; - insnWithID(Insn0, Opc); - - errs() << "Singleton exists: " << nameWithID(Opc) - << " with its decoding dominating "; - for (unsigned i = 0; i < Opcodes.size(); ++i) { - if (Opcodes[i] == Opc) continue; - errs() << nameWithID(Opcodes[i]) << ' '; - } - errs() << '\n'; - - dumpStack(errs(), "\t\t"); - for (unsigned i = 0; i < Opcodes.size(); ++i) { - const std::string &Name = nameWithID(Opcodes[i]); - - errs() << '\t' << Name << " "; - dumpBits(errs(), - getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst")); - errs() << '\n'; - } -} - // Calculates the island(s) needed to decode the instruction. // This returns a list of undecoded bits of an instructions, for example, // Inst{20} = 1 && Inst{3-0} == 0b1111 represents two islands of yet-to-be @@ -2250,13 +2228,13 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) { Target.reverseBitsForLittleEndianEncoding(); // Parameterize the decoders based on namespace and instruction width. - NumberedInstructions = &Target.getInstructionsByEnumValue(); + NumberedInstructions = Target.getInstructionsByEnumValue(); std::map<std::pair<std::string, unsigned>, std::vector<unsigned> > OpcMap; std::map<unsigned, std::vector<OperandInfo> > Operands; - for (unsigned i = 0; i < NumberedInstructions->size(); ++i) { - const CodeGenInstruction *Inst = NumberedInstructions->at(i); + for (unsigned i = 0; i < NumberedInstructions.size(); ++i) { + const CodeGenInstruction *Inst = NumberedInstructions[i]; const Record *Def = Inst->TheDef; unsigned Size = Def->getValueAsInt("Size"); if (Def->getValueAsString("Namespace") == "TargetOpcode" || @@ -2277,7 +2255,7 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) { DecoderTableInfo TableInfo; for (const auto &Opc : OpcMap) { // Emit the decoder for this namespace+width combination. - FilterChooser FC(*NumberedInstructions, Opc.second, Operands, + FilterChooser FC(NumberedInstructions, Opc.second, Operands, 8*Opc.first.second, this); // The decode table is cleared for each top level decoder function. The @@ -2318,12 +2296,10 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) { namespace llvm { void EmitFixedLenDecoder(RecordKeeper &RK, raw_ostream &OS, - std::string PredicateNamespace, - std::string GPrefix, - std::string GPostfix, - std::string ROK, - std::string RFail, - std::string L) { + const std::string &PredicateNamespace, + const std::string &GPrefix, + const std::string &GPostfix, const std::string &ROK, + const std::string &RFail, const std::string &L) { FixedLenDecoderEmitter(RK, PredicateNamespace, GPrefix, GPostfix, ROK, RFail, L).run(OS); } diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index a6583399fa20..02461cc0508d 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -59,12 +59,12 @@ private: raw_ostream &OS); void emitOperandTypesEnum(raw_ostream &OS, const CodeGenTarget &Target); void initOperandMapData( - const std::vector<const CodeGenInstruction *> &NumberedInstructions, + ArrayRef<const CodeGenInstruction *> NumberedInstructions, const std::string &Namespace, std::map<std::string, unsigned> &Operands, OpNameMapTy &OperandMap); void emitOperandNameMappings(raw_ostream &OS, const CodeGenTarget &Target, - const std::vector<const CodeGenInstruction*> &NumberedInstructions); + ArrayRef<const CodeGenInstruction*> NumberedInstructions); // Operand information. void EmitOperandInfo(raw_ostream &OS, OperandInfoMapTy &OperandInfoIDs); @@ -75,8 +75,8 @@ private: static void PrintDefList(const std::vector<Record*> &Uses, unsigned Num, raw_ostream &OS) { OS << "static const MCPhysReg ImplicitList" << Num << "[] = { "; - for (unsigned i = 0, e = Uses.size(); i != e; ++i) - OS << getQualifiedName(Uses[i]) << ", "; + for (Record *U : Uses) + OS << getQualifiedName(U) << ", "; OS << "0 };\n"; } @@ -177,7 +177,7 @@ void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS, OS << "\n"; const CodeGenTarget &Target = CDP.getTargetInfo(); - for (const CodeGenInstruction *Inst : Target.instructions()) { + for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { std::vector<std::string> OperandInfo = GetOperandInfo(*Inst); unsigned &N = OperandInfoIDs[OperandInfo]; if (N != 0) continue; @@ -198,7 +198,7 @@ void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS, /// each instructions. This is used to generate the OperandMap table as /// well as the getNamedOperandIdx() function. void InstrInfoEmitter::initOperandMapData( - const std::vector<const CodeGenInstruction *> &NumberedInstructions, + ArrayRef<const CodeGenInstruction *> NumberedInstructions, const std::string &Namespace, std::map<std::string, unsigned> &Operands, OpNameMapTy &OperandMap) { @@ -234,7 +234,7 @@ void InstrInfoEmitter::initOperandMapData( /// OpName enum void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS, const CodeGenTarget &Target, - const std::vector<const CodeGenInstruction*> &NumberedInstructions) { + ArrayRef<const CodeGenInstruction*> NumberedInstructions) { const std::string &Namespace = Target.getInstNamespace(); std::string OpNameNS = "OpName"; @@ -249,7 +249,7 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS, OS << "#undef GET_INSTRINFO_OPERAND_ENUM\n"; OS << "namespace llvm {\n"; OS << "namespace " << Namespace << " {\n"; - OS << "namespace " << OpNameNS << " { \n"; + OS << "namespace " << OpNameNS << " {\n"; OS << "enum {\n"; for (const auto &Op : Operands) OS << " " << Op.first << " = " << Op.second << ",\n"; @@ -259,7 +259,7 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS, OS << "} // end namespace OpName\n"; OS << "} // end namespace " << Namespace << "\n"; OS << "} // end namespace llvm\n"; - OS << "#endif //GET_INSTRINFO_OPERAND_ENUM\n"; + OS << "#endif //GET_INSTRINFO_OPERAND_ENUM\n\n"; OS << "#ifdef GET_INSTRINFO_NAMED_OPS\n"; OS << "#undef GET_INSTRINFO_NAMED_OPS\n"; @@ -299,7 +299,7 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS, OS << "}\n"; OS << "} // end namespace " << Namespace << "\n"; OS << "} // end namespace llvm\n"; - OS << "#endif //GET_INSTRINFO_NAMED_OPS\n"; + OS << "#endif //GET_INSTRINFO_NAMED_OPS\n\n"; } @@ -312,11 +312,11 @@ void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS, const std::string &Namespace = Target.getInstNamespace(); std::vector<Record *> Operands = Records.getAllDerivedDefinitions("Operand"); - OS << "\n#ifdef GET_INSTRINFO_OPERAND_TYPES_ENUM\n"; + OS << "#ifdef GET_INSTRINFO_OPERAND_TYPES_ENUM\n"; OS << "#undef GET_INSTRINFO_OPERAND_TYPES_ENUM\n"; OS << "namespace llvm {\n"; OS << "namespace " << Namespace << " {\n"; - OS << "namespace OpTypes { \n"; + OS << "namespace OpTypes {\n"; OS << "enum OperandType {\n"; unsigned EnumVal = 0; @@ -330,7 +330,7 @@ void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS, OS << "} // end namespace OpTypes\n"; OS << "} // end namespace " << Namespace << "\n"; OS << "} // end namespace llvm\n"; - OS << "#endif // GET_INSTRINFO_OPERAND_TYPES_ENUM\n"; + OS << "#endif // GET_INSTRINFO_OPERAND_TYPES_ENUM\n\n"; } //===----------------------------------------------------------------------===// @@ -339,12 +339,10 @@ void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS, // run - Emit the main instruction description records for the target... void InstrInfoEmitter::run(raw_ostream &OS) { - emitSourceFileHeader("Target Instruction Enum Values", OS); + emitSourceFileHeader("Target Instruction Enum Values and Descriptors", OS); emitEnums(OS); - emitSourceFileHeader("Target Instruction Descriptors", OS); - - OS << "\n#ifdef GET_INSTRINFO_MC_DESC\n"; + OS << "#ifdef GET_INSTRINFO_MC_DESC\n"; OS << "#undef GET_INSTRINFO_MC_DESC\n"; OS << "namespace llvm {\n\n"; @@ -358,7 +356,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) { unsigned ListNumber = 0; // Emit all of the instruction's implicit uses and defs. - for (const CodeGenInstruction *II : Target.instructions()) { + for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) { Record *Inst = II->TheDef; std::vector<Record*> Uses = Inst->getValueAsListOfDefs("Uses"); if (!Uses.empty()) { @@ -380,7 +378,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) { // Emit all of the MCInstrDesc records in their ENUM ordering. // OS << "\nextern const MCInstrDesc " << TargetName << "Insts[] = {\n"; - const std::vector<const CodeGenInstruction*> &NumberedInstructions = + ArrayRef<const CodeGenInstruction*> NumberedInstructions = Target.getInstructionsByEnumValue(); SequenceToOffsetTable<std::string> InstrNames; @@ -418,26 +416,26 @@ void InstrInfoEmitter::run(raw_ostream &OS) { << TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, " << NumberedInstructions.size() << ");\n}\n\n"; - OS << "} // end llvm namespace \n"; + OS << "} // end llvm namespace\n"; OS << "#endif // GET_INSTRINFO_MC_DESC\n\n"; // Create a TargetInstrInfo subclass to hide the MC layer initialization. - OS << "\n#ifdef GET_INSTRINFO_HEADER\n"; + OS << "#ifdef GET_INSTRINFO_HEADER\n"; OS << "#undef GET_INSTRINFO_HEADER\n"; std::string ClassName = TargetName + "GenInstrInfo"; OS << "namespace llvm {\n"; OS << "struct " << ClassName << " : public TargetInstrInfo {\n" << " explicit " << ClassName - << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1, int CatchRetOpcode = -1);\n" + << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1, int CatchRetOpcode = -1, int ReturnOpcode = -1);\n" << " ~" << ClassName << "() override {}\n" << "};\n"; - OS << "} // end llvm namespace \n"; + OS << "} // end llvm namespace\n"; OS << "#endif // GET_INSTRINFO_HEADER\n\n"; - OS << "\n#ifdef GET_INSTRINFO_CTOR_DTOR\n"; + OS << "#ifdef GET_INSTRINFO_CTOR_DTOR\n"; OS << "#undef GET_INSTRINFO_CTOR_DTOR\n"; OS << "namespace llvm {\n"; @@ -445,12 +443,12 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "extern const unsigned " << TargetName << "InstrNameIndices[];\n"; OS << "extern const char " << TargetName << "InstrNameData[];\n"; OS << ClassName << "::" << ClassName - << "(int CFSetupOpcode, int CFDestroyOpcode, int CatchRetOpcode)\n" - << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode) {\n" + << "(int CFSetupOpcode, int CFDestroyOpcode, int CatchRetOpcode, int ReturnOpcode)\n" + << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode, ReturnOpcode) {\n" << " InitMCInstrInfo(" << TargetName << "Insts, " << TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, " << NumberedInstructions.size() << ");\n}\n"; - OS << "} // end llvm namespace \n"; + OS << "} // end llvm namespace\n"; OS << "#endif // GET_INSTRINFO_CTOR_DTOR\n\n"; @@ -564,7 +562,7 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, // emitEnums - Print out enum values for all of the instructions. void InstrInfoEmitter::emitEnums(raw_ostream &OS) { - OS << "\n#ifdef GET_INSTRINFO_ENUM\n"; + OS << "#ifdef GET_INSTRINFO_ENUM\n"; OS << "#undef GET_INSTRINFO_ENUM\n"; OS << "namespace llvm {\n\n"; @@ -577,26 +575,23 @@ void InstrInfoEmitter::emitEnums(raw_ostream &OS) { if (Namespace.empty()) PrintFatalError("No instructions defined!"); - const std::vector<const CodeGenInstruction*> &NumberedInstructions = - Target.getInstructionsByEnumValue(); - OS << "namespace " << Namespace << " {\n"; OS << " enum {\n"; unsigned Num = 0; - for (const CodeGenInstruction *Inst : NumberedInstructions) + for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) OS << " " << Inst->TheDef->getName() << "\t= " << Num++ << ",\n"; - OS << " INSTRUCTION_LIST_END = " << NumberedInstructions.size() << "\n"; + OS << " INSTRUCTION_LIST_END = " << Num << "\n"; OS << " };\n\n"; OS << "namespace Sched {\n"; OS << " enum {\n"; Num = 0; for (const auto &Class : SchedModels.explicit_classes()) OS << " " << Class.Name << "\t= " << Num++ << ",\n"; - OS << " SCHED_LIST_END = " << SchedModels.numInstrSchedClasses() << "\n"; + OS << " SCHED_LIST_END = " << Num << "\n"; OS << " };\n"; OS << "} // end Sched namespace\n"; OS << "} // end " << Namespace << " namespace\n"; - OS << "} // end llvm namespace \n"; + OS << "} // end llvm namespace\n"; OS << "#endif // GET_INSTRINFO_ENUM\n\n"; } diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp index 42a6a152f55e..a676159e494b 100644 --- a/utils/TableGen/IntrinsicEmitter.cpp +++ b/utils/TableGen/IntrinsicEmitter.cpp @@ -20,6 +20,7 @@ #include "llvm/TableGen/Record.h" #include "llvm/TableGen/StringMatcher.h" #include "llvm/TableGen/TableGenBackend.h" +#include "llvm/TableGen/StringToOffsetTable.h" #include <algorithm> using namespace llvm; @@ -37,23 +38,16 @@ public: void EmitPrefix(raw_ostream &OS); - void EmitEnumInfo(const std::vector<CodeGenIntrinsic> &Ints, - raw_ostream &OS); - - void EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints, - raw_ostream &OS); - void EmitIntrinsicToNameTable(const std::vector<CodeGenIntrinsic> &Ints, + void EmitEnumInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); + void EmitTargetInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); + void EmitIntrinsicToNameTable(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); - void EmitIntrinsicToOverloadTable(const std::vector<CodeGenIntrinsic> &Ints, - raw_ostream &OS); - void EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints, - raw_ostream &OS); - void EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, - raw_ostream &OS); - void EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints, + void EmitIntrinsicToOverloadTable(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); - void EmitIntrinsicToMSBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints, - raw_ostream &OS); + void EmitGenerator(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); + void EmitAttributes(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); + void EmitIntrinsicToBuiltinMap(const CodeGenIntrinsicTable &Ints, bool IsGCC, + raw_ostream &OS); void EmitSuffix(raw_ostream &OS); }; } // End anonymous namespace @@ -65,7 +59,7 @@ public: void IntrinsicEmitter::run(raw_ostream &OS) { emitSourceFileHeader("Intrinsic Function Source Fragment", OS); - std::vector<CodeGenIntrinsic> Ints = LoadIntrinsics(Records, TargetOnly); + CodeGenIntrinsicTable Ints(Records, TargetOnly); if (TargetOnly && !Ints.empty()) TargetPrefix = Ints[0].TargetPrefix; @@ -75,26 +69,29 @@ void IntrinsicEmitter::run(raw_ostream &OS) { // Emit the enum information. EmitEnumInfo(Ints, OS); + // Emit the target metadata. + EmitTargetInfo(Ints, OS); + // Emit the intrinsic ID -> name table. EmitIntrinsicToNameTable(Ints, OS); // Emit the intrinsic ID -> overload table. EmitIntrinsicToOverloadTable(Ints, OS); - // Emit the function name recognizer. - EmitFnNameRecognizer(Ints, OS); - // Emit the intrinsic declaration generator. EmitGenerator(Ints, OS); // Emit the intrinsic parameter attributes. EmitAttributes(Ints, OS); - // Emit code to translate GCC builtins into LLVM intrinsics. - EmitIntrinsicToGCCBuiltinMap(Ints, OS); + // Individual targets don't need GCC builtin name mappings. + if (!TargetOnly) { + // Emit code to translate GCC builtins into LLVM intrinsics. + EmitIntrinsicToBuiltinMap(Ints, true, OS); - // Emit code to translate MS builtins into LLVM intrinsics. - EmitIntrinsicToMSBuiltinMap(Ints, OS); + // Emit code to translate MS builtins into LLVM intrinsics. + EmitIntrinsicToBuiltinMap(Ints, false, OS); + } EmitSuffix(OS); } @@ -117,7 +114,7 @@ void IntrinsicEmitter::EmitSuffix(raw_ostream &OS) { "#endif\n\n"; } -void IntrinsicEmitter::EmitEnumInfo(const std::vector<CodeGenIntrinsic> &Ints, +void IntrinsicEmitter::EmitEnumInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS) { OS << "// Enum values for Intrinsics.h\n"; OS << "#ifdef GET_INTRINSIC_ENUM_VALUES\n"; @@ -131,64 +128,25 @@ void IntrinsicEmitter::EmitEnumInfo(const std::vector<CodeGenIntrinsic> &Ints, OS << "#endif\n\n"; } -void IntrinsicEmitter:: -EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints, - raw_ostream &OS) { - // Build a 'first character of function name' -> intrinsic # mapping. - std::map<char, std::vector<unsigned> > IntMapping; - for (unsigned i = 0, e = Ints.size(); i != e; ++i) - IntMapping[Ints[i].Name[5]].push_back(i); - - OS << "// Function name -> enum value recognizer code.\n"; - OS << "#ifdef GET_FUNCTION_RECOGNIZER\n"; - OS << " StringRef NameR(Name+6, Len-6); // Skip over 'llvm.'\n"; - OS << " switch (Name[5]) { // Dispatch on first letter.\n"; - OS << " default: break;\n"; - // Emit the intrinsic matching stuff by first letter. - for (std::map<char, std::vector<unsigned> >::iterator I = IntMapping.begin(), - E = IntMapping.end(); I != E; ++I) { - OS << " case '" << I->first << "':\n"; - std::vector<unsigned> &IntList = I->second; - - // Sort in reverse order of intrinsic name so "abc.def" appears after - // "abd.def.ghi" in the overridden name matcher - std::sort(IntList.begin(), IntList.end(), [&](unsigned i, unsigned j) { - return Ints[i].Name > Ints[j].Name; - }); - - // Emit all the overloaded intrinsics first, build a table of the - // non-overloaded ones. - std::vector<StringMatcher::StringPair> MatchTable; - - for (unsigned i = 0, e = IntList.size(); i != e; ++i) { - unsigned IntNo = IntList[i]; - std::string Result = "return " + TargetPrefix + "Intrinsic::" + - Ints[IntNo].EnumName + ";"; - - if (!Ints[IntNo].isOverloaded) { - MatchTable.push_back(std::make_pair(Ints[IntNo].Name.substr(6),Result)); - continue; - } - - // For overloaded intrinsics, only the prefix needs to match - std::string TheStr = Ints[IntNo].Name.substr(6); - TheStr += '.'; // Require "bswap." instead of bswap. - OS << " if (NameR.startswith(\"" << TheStr << "\")) " - << Result << '\n'; - } - - // Emit the matcher logic for the fixed length strings. - StringMatcher("NameR", MatchTable, OS).Emit(1); - OS << " break; // end of '" << I->first << "' case.\n"; - } - - OS << " }\n"; +void IntrinsicEmitter::EmitTargetInfo(const CodeGenIntrinsicTable &Ints, + raw_ostream &OS) { + OS << "// Target mapping\n"; + OS << "#ifdef GET_INTRINSIC_TARGET_DATA\n"; + OS << "struct IntrinsicTargetInfo {\n" + << " StringRef Name;\n" + << " size_t Offset;\n" + << " size_t Count;\n" + << "};\n"; + OS << "static const IntrinsicTargetInfo TargetInfos[] = {\n"; + for (auto Target : Ints.Targets) + OS << " {\"" << Target.Name << "\", " << Target.Offset << ", " + << Target.Count << "},\n"; + OS << "};\n"; OS << "#endif\n\n"; } -void IntrinsicEmitter:: -EmitIntrinsicToNameTable(const std::vector<CodeGenIntrinsic> &Ints, - raw_ostream &OS) { +void IntrinsicEmitter::EmitIntrinsicToNameTable( + const CodeGenIntrinsicTable &Ints, raw_ostream &OS) { OS << "// Intrinsic ID to name table\n"; OS << "#ifdef GET_INTRINSIC_NAME_TABLE\n"; OS << " // Note that entry #0 is the invalid intrinsic!\n"; @@ -197,9 +155,8 @@ EmitIntrinsicToNameTable(const std::vector<CodeGenIntrinsic> &Ints, OS << "#endif\n\n"; } -void IntrinsicEmitter:: -EmitIntrinsicToOverloadTable(const std::vector<CodeGenIntrinsic> &Ints, - raw_ostream &OS) { +void IntrinsicEmitter::EmitIntrinsicToOverloadTable( + const CodeGenIntrinsicTable &Ints, raw_ostream &OS) { OS << "// Intrinsic ID to overload bitset\n"; OS << "#ifdef GET_INTRINSIC_OVERLOAD_TABLE\n"; OS << "static const uint8_t OTable[] = {\n"; @@ -421,7 +378,7 @@ static void printIITEntry(raw_ostream &OS, unsigned char X) { OS << (unsigned)X; } -void IntrinsicEmitter::EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints, +void IntrinsicEmitter::EmitGenerator(const CodeGenIntrinsicTable &Ints, raw_ostream &OS) { // If we can compute a 32-bit fixed encoding for this intrinsic, do so and // capture it in this vector, otherwise store a ~0U. @@ -520,8 +477,8 @@ struct AttributeComparator { return R->isConvergent; // Try to order by readonly/readnone attribute. - CodeGenIntrinsic::ModRefKind LK = L->ModRef; - CodeGenIntrinsic::ModRefKind RK = R->ModRef; + CodeGenIntrinsic::ModRefBehavior LK = L->ModRef; + CodeGenIntrinsic::ModRefBehavior RK = R->ModRef; if (LK != RK) return (LK > RK); // Order by argument attributes. @@ -532,8 +489,8 @@ struct AttributeComparator { } // End anonymous namespace /// EmitAttributes - This emits the Intrinsic::getAttributes method. -void IntrinsicEmitter:: -EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) { +void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints, + raw_ostream &OS) { OS << "// Add parameter attributes that are not common to all intrinsics.\n"; OS << "#ifdef GET_INTRINSIC_ATTRIBUTES\n"; if (TargetOnly) @@ -606,12 +563,24 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) { OS << "Attribute::NoCapture"; addComma = true; break; + case CodeGenIntrinsic::Returned: + if (addComma) + OS << ","; + OS << "Attribute::Returned"; + addComma = true; + break; case CodeGenIntrinsic::ReadOnly: if (addComma) OS << ","; OS << "Attribute::ReadOnly"; addComma = true; break; + case CodeGenIntrinsic::WriteOnly: + if (addComma) + OS << ","; + OS << "Attribute::WriteOnly"; + addComma = true; + break; case CodeGenIntrinsic::ReadNone: if (addComma) OS << ","; @@ -674,6 +643,17 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) { OS << ","; OS << "Attribute::ReadOnly"; break; + case CodeGenIntrinsic::WriteArgMem: + if (addComma) + OS << ","; + OS << "Attribute::WriteOnly,"; + OS << "Attribute::ArgMemOnly"; + break; + case CodeGenIntrinsic::WriteMem: + if (addComma) + OS << ","; + OS << "Attribute::WriteOnly"; + break; case CodeGenIntrinsic::ReadWriteArgMem: if (addComma) OS << ","; @@ -704,56 +684,57 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) { OS << "#endif // GET_INTRINSIC_ATTRIBUTES\n\n"; } -/// EmitTargetBuiltins - All of the builtins in the specified map are for the -/// same target, and we already checked it. -static void EmitTargetBuiltins(const std::map<std::string, std::string> &BIM, - const std::string &TargetPrefix, - raw_ostream &OS) { - - std::vector<StringMatcher::StringPair> Results; - - for (std::map<std::string, std::string>::const_iterator I = BIM.begin(), - E = BIM.end(); I != E; ++I) { - std::string ResultCode = - "return " + TargetPrefix + "Intrinsic::" + I->second + ";"; - Results.emplace_back(I->first, ResultCode); - } - - StringMatcher("BuiltinName", Results, OS).Emit(); -} - - -void IntrinsicEmitter:: -EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints, - raw_ostream &OS) { - typedef std::map<std::string, std::map<std::string, std::string> > BIMTy; +void IntrinsicEmitter::EmitIntrinsicToBuiltinMap( + const CodeGenIntrinsicTable &Ints, bool IsGCC, raw_ostream &OS) { + StringRef CompilerName = (IsGCC ? "GCC" : "MS"); + typedef std::map<std::string, std::map<std::string, std::string>> BIMTy; BIMTy BuiltinMap; + StringToOffsetTable Table; for (unsigned i = 0, e = Ints.size(); i != e; ++i) { - if (!Ints[i].GCCBuiltinName.empty()) { + const std::string &BuiltinName = + IsGCC ? Ints[i].GCCBuiltinName : Ints[i].MSBuiltinName; + if (!BuiltinName.empty()) { // Get the map for this target prefix. - std::map<std::string, std::string> &BIM =BuiltinMap[Ints[i].TargetPrefix]; + std::map<std::string, std::string> &BIM = + BuiltinMap[Ints[i].TargetPrefix]; - if (!BIM.insert(std::make_pair(Ints[i].GCCBuiltinName, - Ints[i].EnumName)).second) + if (!BIM.insert(std::make_pair(BuiltinName, Ints[i].EnumName)).second) PrintFatalError("Intrinsic '" + Ints[i].TheDef->getName() + - "': duplicate GCC builtin name!"); + "': duplicate " + CompilerName + " builtin name!"); + Table.GetOrAddStringOffset(BuiltinName); } } - OS << "// Get the LLVM intrinsic that corresponds to a GCC builtin.\n"; - OS << "// This is used by the C front-end. The GCC builtin name is passed\n"; + OS << "// Get the LLVM intrinsic that corresponds to a builtin.\n"; + OS << "// This is used by the C front-end. The builtin name is passed\n"; OS << "// in as BuiltinName, and a target prefix (e.g. 'ppc') is passed\n"; OS << "// in as TargetPrefix. The result is assigned to 'IntrinsicID'.\n"; - OS << "#ifdef GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN\n"; + OS << "#ifdef GET_LLVM_INTRINSIC_FOR_" << CompilerName << "_BUILTIN\n"; if (TargetOnly) { OS << "static " << TargetPrefix << "Intrinsic::ID " - << "getIntrinsicForGCCBuiltin(const char " + << "getIntrinsicFor" << CompilerName << "Builtin(const char " << "*TargetPrefixStr, const char *BuiltinNameStr) {\n"; } else { - OS << "Intrinsic::ID Intrinsic::getIntrinsicForGCCBuiltin(const char " + OS << "Intrinsic::ID Intrinsic::getIntrinsicFor" << CompilerName + << "Builtin(const char " << "*TargetPrefixStr, const char *BuiltinNameStr) {\n"; } + OS << " static const char BuiltinNames[] = {\n"; + Table.EmitCharArray(OS); + OS << " };\n\n"; + + OS << " struct BuiltinEntry {\n"; + OS << " Intrinsic::ID IntrinID;\n"; + OS << " unsigned StrTabOffset;\n"; + OS << " const char *getName() const {\n"; + OS << " return &BuiltinNames[StrTabOffset];\n"; + OS << " }\n"; + OS << " bool operator<(const char *RHS) const {\n"; + OS << " return strcmp(getName(), RHS) < 0;\n"; + OS << " }\n"; + OS << " };\n"; + OS << " StringRef BuiltinName(BuiltinNameStr);\n"; OS << " StringRef TargetPrefix(TargetPrefixStr);\n\n"; @@ -768,7 +749,18 @@ EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints, OS << "{\n"; // Emit the comparisons for this target prefix. - EmitTargetBuiltins(I->second, TargetPrefix, OS); + OS << " static const BuiltinEntry " << I->first << "Names[] = {\n"; + for (const auto &P : I->second) { + OS << " {Intrinsic::" << P.second << ", " + << Table.GetOrAddStringOffset(P.first) << "}, // " << P.first << "\n"; + } + OS << " };\n"; + OS << " auto I = std::lower_bound(std::begin(" << I->first << "Names),\n"; + OS << " std::end(" << I->first << "Names),\n"; + OS << " BuiltinNameStr);\n"; + OS << " if (I != std::end(" << I->first << "Names) &&\n"; + OS << " strcmp(I->getName(), BuiltinNameStr) == 0)\n"; + OS << " return I->IntrinID;\n"; OS << " }\n"; } OS << " return "; @@ -779,55 +771,6 @@ EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints, OS << "#endif\n\n"; } -void IntrinsicEmitter:: -EmitIntrinsicToMSBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints, - raw_ostream &OS) { - std::map<std::string, std::map<std::string, std::string>> TargetBuiltins; - - for (const auto &Intrinsic : Ints) { - if (Intrinsic.MSBuiltinName.empty()) - continue; - - auto &Builtins = TargetBuiltins[Intrinsic.TargetPrefix]; - if (!Builtins.insert(std::make_pair(Intrinsic.MSBuiltinName, - Intrinsic.EnumName)).second) - PrintFatalError("Intrinsic '" + Intrinsic.TheDef->getName() + "': " - "duplicate MS builtin name!"); - } - - OS << "// Get the LLVM intrinsic that corresponds to a MS builtin.\n" - "// This is used by the C front-end. The MS builtin name is passed\n" - "// in as a BuiltinName, and a target prefix (e.g. 'arm') is passed\n" - "// in as a TargetPrefix. The result is assigned to 'IntrinsicID'.\n" - "#ifdef GET_LLVM_INTRINSIC_FOR_MS_BUILTIN\n"; - - OS << (TargetOnly ? "static " + TargetPrefix : "") << "Intrinsic::ID " - << (TargetOnly ? "" : "Intrinsic::") - << "getIntrinsicForMSBuiltin(const char *TP, const char *BN) {\n"; - OS << " StringRef BuiltinName(BN);\n" - " StringRef TargetPrefix(TP);\n" - "\n"; - - for (const auto &Builtins : TargetBuiltins) { - OS << " "; - if (Builtins.first.empty()) - OS << "/* Target Independent Builtins */ "; - else - OS << "if (TargetPrefix == \"" << Builtins.first << "\") "; - OS << "{\n"; - EmitTargetBuiltins(Builtins.second, TargetPrefix, OS); - OS << "}"; - } - - OS << " return "; - if (!TargetPrefix.empty()) - OS << "(" << TargetPrefix << "Intrinsic::ID)"; - OS << "Intrinsic::not_intrinsic;\n"; - OS << "}\n"; - - OS << "#endif\n\n"; -} - void llvm::EmitIntrinsics(RecordKeeper &RK, raw_ostream &OS, bool TargetOnly) { IntrinsicEmitter(RK, TargetOnly).run(OS); } diff --git a/utils/TableGen/Makefile b/utils/TableGen/Makefile deleted file mode 100644 index 9bfd94b7576b..000000000000 --- a/utils/TableGen/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -##===- utils/TableGen/Makefile -----------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../.. -TOOLNAME = llvm-tblgen -USEDLIBS = LLVMTableGen.a LLVMSupport.a - -# This tool has no plugins, optimize startup time. -TOOL_NO_EXPORTS = 1 - -include $(LEVEL)/Makefile.common - diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp index b727df75626f..9bb988f30f18 100644 --- a/utils/TableGen/RegisterInfoEmitter.cpp +++ b/utils/TableGen/RegisterInfoEmitter.cpp @@ -16,22 +16,38 @@ #include "CodeGenRegisters.h" #include "CodeGenTarget.h" #include "SequenceToOffsetTable.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SparseBitVector.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" +#include "llvm/CodeGen/MachineValueType.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" +#include "llvm/TableGen/SetTheory.h" #include "llvm/TableGen/TableGenBackend.h" #include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <deque> +#include <iterator> #include <set> +#include <string> #include <vector> + using namespace llvm; namespace { + class RegisterInfoEmitter { RecordKeeper &Records; + public: RegisterInfoEmitter(RecordKeeper &R) : Records(R) {} @@ -65,7 +81,8 @@ private: void emitComposeSubRegIndexLaneMask(raw_ostream &OS, CodeGenRegBank &RegBank, const std::string &ClassName); }; -} // End anonymous namespace + +} // end anonymous namespace // runEnums - Print out enum values for all of the registers. void RegisterInfoEmitter::runEnums(raw_ostream &OS, @@ -81,7 +98,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, emitSourceFileHeader("Target Register Enum Values", OS); OS << "\n#ifdef GET_REGINFO_ENUM\n"; - OS << "#undef GET_REGINFO_ENUM\n"; + OS << "#undef GET_REGINFO_ENUM\n\n"; OS << "namespace llvm {\n\n"; @@ -100,7 +117,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, OS << " NUM_TARGET_REGS \t// " << Registers.size()+1 << "\n"; OS << "};\n"; if (!Namespace.empty()) - OS << "}\n"; + OS << "} // end namespace " << Namespace << "\n"; const auto &RegisterClasses = Bank.getRegClasses(); if (!RegisterClasses.empty()) { @@ -109,7 +126,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, assert(RegisterClasses.size() <= 0xffff && "Too many register classes to fit in tables"); - OS << "\n// Register classes\n"; + OS << "\n// Register classes\n\n"; if (!Namespace.empty()) OS << "namespace " << Namespace << " {\n"; OS << "enum {\n"; @@ -118,14 +135,14 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, << " = " << RC.EnumValue << ",\n"; OS << "\n };\n"; if (!Namespace.empty()) - OS << "}\n"; + OS << "} // end namespace " << Namespace << "\n\n"; } const std::vector<Record*> &RegAltNameIndices = Target.getRegAltNameIndices(); // If the only definition is the default NoRegAltName, we don't need to // emit anything. if (RegAltNameIndices.size() > 1) { - OS << "\n// Register alternate name indices\n"; + OS << "\n// Register alternate name indices\n\n"; if (!Namespace.empty()) OS << "namespace " << Namespace << " {\n"; OS << "enum {\n"; @@ -134,12 +151,12 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, OS << " NUM_TARGET_REG_ALT_NAMES = " << RegAltNameIndices.size() << "\n"; OS << "};\n"; if (!Namespace.empty()) - OS << "}\n"; + OS << "} // end namespace " << Namespace << "\n\n"; } auto &SubRegIndices = Bank.getSubRegIndices(); if (!SubRegIndices.empty()) { - OS << "\n// Subregister indices\n"; + OS << "\n// Subregister indices\n\n"; std::string Namespace = SubRegIndices.front().getNamespace(); if (!Namespace.empty()) OS << "namespace " << Namespace << " {\n"; @@ -149,10 +166,10 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, OS << " " << Idx.getName() << ",\t// " << ++i << "\n"; OS << " NUM_TARGET_SUBREGS\n};\n"; if (!Namespace.empty()) - OS << "}\n"; + OS << "} // end namespace " << Namespace << "\n\n"; } - OS << "} // End llvm namespace\n"; + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_REGINFO_ENUM\n\n"; } @@ -728,15 +745,11 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS, SubReg2SequenceIndexMap.push_back(Found); } - OS << "unsigned " << ClName - << "::composeSubRegIndexLaneMaskImpl(unsigned IdxA, unsigned LaneMask)" - " const {\n"; - OS << " struct MaskRolOp {\n" " unsigned Mask;\n" " uint8_t RotateLeft;\n" " };\n" - " static const MaskRolOp Seqs[] = {\n"; + " static const MaskRolOp LaneMaskComposeSequences[] = {\n"; unsigned Idx = 0; for (size_t s = 0, se = Sequences.size(); s != se; ++s) { OS << " "; @@ -756,24 +769,43 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS, for (size_t i = 0, e = SubRegIndices.size(); i != e; ++i) { OS << " "; unsigned Idx = SubReg2SequenceIndexMap[i]; - OS << format("&Seqs[%u]", Idx); + OS << format("&LaneMaskComposeSequences[%u]", Idx); if (i+1 != e) OS << ","; OS << " // to " << SubRegIndices[i].getName() << "\n"; } OS << " };\n\n"; - OS << " --IdxA; assert(IdxA < " << SubRegIndices.size() + OS << "LaneBitmask " << ClName + << "::composeSubRegIndexLaneMaskImpl(unsigned IdxA, LaneBitmask LaneMask)" + " const {\n" + " --IdxA; assert(IdxA < " << SubRegIndices.size() << " && \"Subregister index out of bounds\");\n" - " unsigned Result = 0;\n" + " LaneBitmask Result = 0;\n" " for (const MaskRolOp *Ops = CompositeSequences[IdxA]; Ops->Mask != 0; ++Ops)" " {\n" - " unsigned Masked = LaneMask & Ops->Mask;\n" + " LaneBitmask Masked = LaneMask & Ops->Mask;\n" " Result |= (Masked << Ops->RotateLeft) & 0xFFFFFFFF;\n" " Result |= (Masked >> ((32 - Ops->RotateLeft) & 0x1F));\n" " }\n" " return Result;\n" - "}\n"; + "}\n\n"; + + OS << "LaneBitmask " << ClName + << "::reverseComposeSubRegIndexLaneMaskImpl(unsigned IdxA, " + " LaneBitmask LaneMask) const {\n" + " LaneMask &= getSubRegIndexLaneMask(IdxA);\n" + " --IdxA; assert(IdxA < " << SubRegIndices.size() + << " && \"Subregister index out of bounds\");\n" + " LaneBitmask Result = 0;\n" + " for (const MaskRolOp *Ops = CompositeSequences[IdxA]; Ops->Mask != 0; ++Ops)" + " {\n" + " LaneBitmask Rotated = (LaneMask >> Ops->RotateLeft) |\n" + " ((LaneMask << ((32 - Ops->RotateLeft) & 0x1F)) & 0xFFFFFFFF);\n" + " Result |= Rotated & Ops->Mask;\n" + " }\n" + " return Result;\n" + "}\n\n"; } // @@ -785,7 +817,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, emitSourceFileHeader("MC Register Information", OS); OS << "\n#ifdef GET_REGINFO_MC_DESC\n"; - OS << "#undef GET_REGINFO_MC_DESC\n"; + OS << "#undef GET_REGINFO_MC_DESC\n\n"; const auto &Regs = RegBank.getRegisters(); @@ -958,7 +990,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, ArrayRef<Record*> Order = RC.getOrder(); // Give the register class a legal C name if it's anonymous. - std::string Name = RC.getName(); + const std::string &Name = RC.getName(); RegClassStrings.add(Name); @@ -984,7 +1016,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, OS << "\n };\n\n"; } - OS << "}\n\n"; + OS << "} // end anonymous namespace\n\n"; RegClassStrings.layout(); OS << "extern const char " << TargetName << "RegClassStrings[] = {\n"; @@ -1008,7 +1040,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, << RC.SpillSize/8 << ", " << RC.SpillAlignment/8 << ", " << RC.CopyCost << ", " - << RC.Allocatable << " },\n"; + << ( RC.Allocatable ? "true" : "false" ) << " },\n"; } OS << "};\n\n"; @@ -1051,7 +1083,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, OS << "}\n\n"; - OS << "} // End llvm namespace\n"; + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_REGINFO_MC_DESC\n\n"; } @@ -1061,7 +1093,7 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target, emitSourceFileHeader("Register Information Header Fragment", OS); OS << "\n#ifdef GET_REGINFO_HEADER\n"; - OS << "#undef GET_REGINFO_HEADER\n"; + OS << "#undef GET_REGINFO_HEADER\n\n"; const std::string &TargetName = Target.getName(); std::string ClassName = TargetName + "GenRegisterInfo"; @@ -1078,8 +1110,10 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target, if (!RegBank.getSubRegIndices().empty()) { OS << " unsigned composeSubRegIndicesImpl" << "(unsigned, unsigned) const override;\n" - << " unsigned composeSubRegIndexLaneMaskImpl" - << "(unsigned, unsigned) const override;\n" + << " LaneBitmask composeSubRegIndexLaneMaskImpl" + << "(unsigned, LaneBitmask) const override;\n" + << " LaneBitmask reverseComposeSubRegIndexLaneMaskImpl" + << "(unsigned, LaneBitmask) const override;\n" << " const TargetRegisterClass *getSubClassWithSubReg" << "(const TargetRegisterClass*, unsigned) const override;\n"; } @@ -1113,9 +1147,9 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target, // Output the extern for the instance. OS << " extern const TargetRegisterClass " << Name << "RegClass;\n"; } - OS << "} // end of namespace " << TargetName << "\n\n"; + OS << "} // end namespace " << RegisterClasses.front().Namespace << "\n\n"; } - OS << "} // End llvm namespace\n"; + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_REGINFO_HEADER\n\n"; } @@ -1128,7 +1162,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, emitSourceFileHeader("Target Register and Register Classes Information", OS); OS << "\n#ifdef GET_REGINFO_TARGET_DESC\n"; - OS << "#undef GET_REGINFO_TARGET_DESC\n"; + OS << "#undef GET_REGINFO_TARGET_DESC\n\n"; OS << "namespace llvm {\n\n"; @@ -1294,7 +1328,9 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, << format("0x%08x,\n ", RC.LaneMask) << (unsigned)RC.AllocationPriority << ",\n " << (RC.HasDisjunctSubRegs?"true":"false") - << ", /* HasDisjunctSubRegs */\n "; + << ", /* HasDisjunctSubRegs */\n " + << (RC.CoveredBySubRegs?"true":"false") + << ", /* CoveredBySubRegs */\n "; if (RC.getSuperClasses().empty()) OS << "NullRegClasses,\n "; else @@ -1306,7 +1342,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, OS << " };\n\n"; } - OS << "}\n"; + OS << "} // end namespace " << RegisterClasses.front().Namespace << "\n"; } OS << "\nnamespace {\n"; @@ -1314,19 +1350,20 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, for (const auto &RC : RegisterClasses) OS << " &" << RC.getQualifiedName() << "RegClass,\n"; OS << " };\n"; - OS << "}\n"; // End of anonymous namespace... + OS << "} // end anonymous namespace\n"; // Emit extra information about registers. const std::string &TargetName = Target.getName(); OS << "\nstatic const TargetRegisterInfoDesc " << TargetName << "RegInfoDesc[] = { // Extra Descriptors\n"; - OS << " { 0, 0 },\n"; + OS << " { 0, false },\n"; const auto &Regs = RegBank.getRegisters(); for (const auto &Reg : Regs) { OS << " { "; OS << Reg.CostPerUse << ", " - << int(AllocatableRegs.count(Reg.TheDef)) << " },\n"; + << ( AllocatableRegs.count(Reg.TheDef) != 0 ? "true" : "false" ) + << " },\n"; } OS << "};\n"; // End of register descriptors... @@ -1414,7 +1451,6 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, OS << "}\n\n"; - // Emit CalleeSavedRegs information. std::vector<Record*> CSRSets = Records.getAllDerivedDefinitions("CalleeSavedRegs"); @@ -1482,7 +1518,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, << " MF.getSubtarget().getFrameLowering());\n" << "}\n\n"; - OS << "} // End llvm namespace\n"; + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_REGINFO_TARGET_DESC\n\n"; } @@ -1503,4 +1539,4 @@ void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS) { RegisterInfoEmitter(RK).run(OS); } -} // End llvm namespace +} // end namespace llvm diff --git a/utils/TableGen/SearchableTableEmitter.cpp b/utils/TableGen/SearchableTableEmitter.cpp new file mode 100644 index 000000000000..8c1b8804d174 --- /dev/null +++ b/utils/TableGen/SearchableTableEmitter.cpp @@ -0,0 +1,320 @@ +//===- SearchableTableEmitter.cpp - Generate efficiently searchable tables -==// +// +// 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 a generic array initialized by specified fields, +// together with companion index tables and lookup functions (binary search, +// currently). +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include <algorithm> +#include <sstream> +#include <string> +#include <vector> +using namespace llvm; + +#define DEBUG_TYPE "searchable-table-emitter" + +namespace { + +class SearchableTableEmitter { + RecordKeeper &Records; + +public: + SearchableTableEmitter(RecordKeeper &R) : Records(R) {} + + void run(raw_ostream &OS); + +private: + typedef std::pair<Init *, int> SearchTableEntry; + + int getAsInt(BitsInit *B) { + return cast<IntInit>(B->convertInitializerTo(IntRecTy::get()))->getValue(); + } + int getInt(Record *R, StringRef Field) { + return getAsInt(R->getValueAsBitsInit(Field)); + } + + std::string primaryRepresentation(Init *I) { + if (StringInit *SI = dyn_cast<StringInit>(I)) + return SI->getAsString(); + else if (BitsInit *BI = dyn_cast<BitsInit>(I)) + return "0x" + utohexstr(getAsInt(BI)); + else if (BitInit *BI = dyn_cast<BitInit>(I)) + return BI->getValue() ? "true" : "false"; + else if (CodeInit *CI = dyn_cast<CodeInit>(I)) { + return CI->getValue(); + } + PrintFatalError(SMLoc(), + "invalid field type, expected: string, bits, bit or code"); + } + + std::string searchRepresentation(Init *I) { + std::string PrimaryRep = primaryRepresentation(I); + if (!isa<StringInit>(I)) + return PrimaryRep; + return StringRef(PrimaryRep).upper(); + } + + std::string searchableFieldType(Init *I) { + if (isa<StringInit>(I)) + return "const char *"; + else if (BitsInit *BI = dyn_cast<BitsInit>(I)) { + unsigned NumBits = BI->getNumBits(); + if (NumBits <= 8) + NumBits = 8; + else if (NumBits <= 16) + NumBits = 16; + else if (NumBits <= 32) + NumBits = 32; + else if (NumBits <= 64) + NumBits = 64; + else + PrintFatalError(SMLoc(), "bitfield too large to search"); + return "uint" + utostr(NumBits) + "_t"; + } + PrintFatalError(SMLoc(), "Unknown type to search by"); + } + + void emitMapping(Record *MappingDesc, raw_ostream &OS); + void emitMappingEnum(std::vector<Record *> &Items, Record *InstanceClass, + raw_ostream &OS); + void + emitPrimaryTable(StringRef Name, std::vector<std::string> &FieldNames, + std::vector<std::string> &SearchFieldNames, + std::vector<std::vector<SearchTableEntry>> &SearchTables, + std::vector<Record *> &Items, raw_ostream &OS); + void emitSearchTable(StringRef Name, StringRef Field, + std::vector<SearchTableEntry> &SearchTable, + raw_ostream &OS); + void emitLookupDeclaration(StringRef Name, StringRef Field, Init *I, + raw_ostream &OS); + void emitLookupFunction(StringRef Name, StringRef Field, Init *I, + raw_ostream &OS); +}; + +} // End anonymous namespace. + +/// Emit an enum providing symbolic access to some preferred field from +/// C++. +void SearchableTableEmitter::emitMappingEnum(std::vector<Record *> &Items, + Record *InstanceClass, + raw_ostream &OS) { + std::string EnumNameField = InstanceClass->getValueAsString("EnumNameField"); + std::string EnumValueField; + if (!InstanceClass->isValueUnset("EnumValueField")) + EnumValueField = InstanceClass->getValueAsString("EnumValueField"); + + OS << "enum " << InstanceClass->getName() << "Values {\n"; + for (auto Item : Items) { + OS << " " << Item->getValueAsString(EnumNameField); + if (EnumValueField != StringRef()) + OS << " = " << getInt(Item, EnumValueField); + OS << ",\n"; + } + OS << "};\n\n"; +} + +void SearchableTableEmitter::emitPrimaryTable( + StringRef Name, std::vector<std::string> &FieldNames, + std::vector<std::string> &SearchFieldNames, + std::vector<std::vector<SearchTableEntry>> &SearchTables, + std::vector<Record *> &Items, raw_ostream &OS) { + OS << "const " << Name << " " << Name << "sList[] = {\n"; + + for (auto Item : Items) { + OS << " { "; + for (unsigned i = 0; i < FieldNames.size(); ++i) { + OS << primaryRepresentation(Item->getValueInit(FieldNames[i])); + if (i != FieldNames.size() - 1) + OS << ", "; + } + OS << "},\n"; + } + OS << "};\n\n"; +} + +void SearchableTableEmitter::emitSearchTable( + StringRef Name, StringRef Field, std::vector<SearchTableEntry> &SearchTable, + raw_ostream &OS) { + OS << "const std::pair<" << searchableFieldType(SearchTable[0].first) + << ", int> " << Name << "sBy" << Field << "[] = {\n"; + + if (isa<BitsInit>(SearchTable[0].first)) { + std::stable_sort(SearchTable.begin(), SearchTable.end(), + [this](const SearchTableEntry &LHS, + const SearchTableEntry &RHS) { + return getAsInt(cast<BitsInit>(LHS.first)) < + getAsInt(cast<BitsInit>(RHS.first)); + }); + } else { + std::stable_sort(SearchTable.begin(), SearchTable.end(), + [this](const SearchTableEntry &LHS, + const SearchTableEntry &RHS) { + return searchRepresentation(LHS.first) < + searchRepresentation(RHS.first); + }); + } + + for (auto Entry : SearchTable) { + OS << " { " << searchRepresentation(Entry.first) << ", " << Entry.second + << " },\n"; + } + OS << "};\n\n"; +} + +void SearchableTableEmitter::emitLookupFunction(StringRef Name, StringRef Field, + Init *I, raw_ostream &OS) { + bool IsIntegral = isa<BitsInit>(I); + std::string FieldType = searchableFieldType(I); + std::string PairType = "std::pair<" + FieldType + ", int>"; + + // const SysRegs *lookupSysRegByName(const char *Name) { + OS << "const " << Name << " *" + << "lookup" << Name << "By" << Field; + OS << "(" << (IsIntegral ? FieldType : "StringRef") << " " << Field + << ") {\n"; + + if (IsIntegral) { + OS << " auto CanonicalVal = " << Field << ";\n"; + OS << " " << PairType << " Val = {CanonicalVal, 0};\n"; + } else { + // Make sure the result is null terminated because it's going via "char *". + OS << " std::string CanonicalVal = " << Field << ".upper();\n"; + OS << " " << PairType << " Val = {CanonicalVal.data(), 0};\n"; + } + + OS << " ArrayRef<" << PairType << "> Table(" << Name << "sBy" << Field + << ");\n"; + OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Val"; + + if (IsIntegral) + OS << ");\n"; + else { + OS << ",\n "; + OS << "[](const " << PairType << " &LHS, const " << PairType + << " &RHS) {\n"; + OS << " return StringRef(LHS.first) < StringRef(RHS.first);\n"; + OS << " });\n\n"; + } + + OS << " if (Idx == Table.end() || CanonicalVal != Idx->first)\n"; + OS << " return nullptr;\n"; + + OS << " return &" << Name << "sList[Idx->second];\n"; + OS << "}\n\n"; +} + +void SearchableTableEmitter::emitLookupDeclaration(StringRef Name, + StringRef Field, Init *I, + raw_ostream &OS) { + bool IsIntegral = isa<BitsInit>(I); + std::string FieldType = searchableFieldType(I); + OS << "const " << Name << " *" + << "lookup" << Name << "By" << Field; + OS << "(" << (IsIntegral ? FieldType : "StringRef") << " " << Field + << ");\n\n"; +} + +void SearchableTableEmitter::emitMapping(Record *InstanceClass, + raw_ostream &OS) { + const std::string &TableName = InstanceClass->getName(); + std::vector<Record *> Items = Records.getAllDerivedDefinitions(TableName); + + // Gather all the records we're going to need for this particular mapping. + std::vector<std::vector<SearchTableEntry>> SearchTables; + std::vector<std::string> SearchFieldNames; + + std::vector<std::string> FieldNames; + for (const RecordVal &Field : InstanceClass->getValues()) { + std::string FieldName = Field.getName(); + + // Skip uninteresting fields: either built-in, special to us, or injected + // template parameters (if they contain a ':'). + if (FieldName.find(':') != std::string::npos || FieldName == "NAME" || + FieldName == "SearchableFields" || FieldName == "EnumNameField" || + FieldName == "EnumValueField") + continue; + + FieldNames.push_back(FieldName); + } + + for (auto *Field : *InstanceClass->getValueAsListInit("SearchableFields")) { + SearchTables.emplace_back(); + SearchFieldNames.push_back(Field->getAsUnquotedString()); + } + + int Idx = 0; + for (Record *Item : Items) { + for (unsigned i = 0; i < SearchFieldNames.size(); ++i) { + Init *SearchVal = Item->getValueInit(SearchFieldNames[i]); + SearchTables[i].emplace_back(SearchVal, Idx); + } + ++Idx; + } + + OS << "#ifdef GET_" << StringRef(TableName).upper() << "_DECL\n"; + OS << "#undef GET_" << StringRef(TableName).upper() << "_DECL\n"; + + // Next emit the enum containing the top-level names for use in C++ code if + // requested + if (!InstanceClass->isValueUnset("EnumNameField")) { + emitMappingEnum(Items, InstanceClass, OS); + } + + // And the declarations for the functions that will perform lookup. + for (unsigned i = 0; i < SearchFieldNames.size(); ++i) + emitLookupDeclaration(TableName, SearchFieldNames[i], + SearchTables[i][0].first, OS); + + OS << "#endif\n\n"; + + OS << "#ifdef GET_" << StringRef(TableName).upper() << "_IMPL\n"; + OS << "#undef GET_" << StringRef(TableName).upper() << "_IMPL\n"; + + // The primary data table contains all the fields defined for this map. + emitPrimaryTable(TableName, FieldNames, SearchFieldNames, SearchTables, Items, + OS); + + // Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary + // search can be performed by "Thing". + for (unsigned i = 0; i < SearchTables.size(); ++i) { + emitSearchTable(TableName, SearchFieldNames[i], SearchTables[i], OS); + emitLookupFunction(TableName, SearchFieldNames[i], SearchTables[i][0].first, + OS); + } + + OS << "#endif\n"; +} + +void SearchableTableEmitter::run(raw_ostream &OS) { + // Tables are defined to be the direct descendents of "SearchableEntry". + Record *SearchableTable = Records.getClass("SearchableTable"); + for (auto &NameRec : Records.getClasses()) { + Record *Class = NameRec.second.get(); + if (Class->getSuperClasses().size() != 1 || + !Class->isSubClassOf(SearchableTable)) + continue; + emitMapping(Class, OS); + } +} + +namespace llvm { + +void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS) { + SearchableTableEmitter(RK).run(OS); +} + +} // End llvm namespace. diff --git a/utils/TableGen/SequenceToOffsetTable.h b/utils/TableGen/SequenceToOffsetTable.h index 66506ea0638f..e026b1c9fbf0 100644 --- a/utils/TableGen/SequenceToOffsetTable.h +++ b/utils/TableGen/SequenceToOffsetTable.h @@ -22,7 +22,6 @@ #include <cctype> #include <functional> #include <map> -#include <vector> namespace llvm { diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index d056de003e18..228882177bdf 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -13,16 +13,20 @@ #include "CodeGenTarget.h" #include "CodeGenSchedule.h" -#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/MC/MCInstrItineraries.h" +#include "llvm/MC/MCSchedule.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" #include <algorithm> +#include <cassert> +#include <cstdint> #include <map> #include <string> #include <vector> @@ -32,6 +36,7 @@ using namespace llvm; #define DEBUG_TYPE "subtarget-emitter" namespace { + class SubtargetEmitter { // Each processor has a SchedClassDesc table with an entry for each SchedClass. // The SchedClassDesc table indexes into a global write resource table, write @@ -64,7 +69,7 @@ class SubtargetEmitter { CodeGenSchedModels &SchedModels; std::string Target; - void Enumeration(raw_ostream &OS, const char *ClassName); + void Enumeration(raw_ostream &OS); unsigned FeatureKeyValues(raw_ostream &OS); unsigned CPUKeyValues(raw_ostream &OS); void FormItineraryStageString(const std::string &Names, @@ -96,7 +101,7 @@ class SubtargetEmitter { void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS); void EmitProcessorModels(raw_ostream &OS); void EmitProcessorLookup(raw_ostream &OS); - void EmitSchedModelHelpers(std::string ClassName, raw_ostream &OS); + void EmitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS); void EmitSchedModel(raw_ostream &OS); void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures, unsigned NumProcs); @@ -107,15 +112,16 @@ public: void run(raw_ostream &o); }; + } // end anonymous namespace // // Enumeration - Emit the specified class as an enumeration. // -void SubtargetEmitter::Enumeration(raw_ostream &OS, - const char *ClassName) { +void SubtargetEmitter::Enumeration(raw_ostream &OS) { // Get all records of class and sort - std::vector<Record*> DefList = Records.getAllDerivedDefinitions(ClassName); + std::vector<Record*> DefList = + Records.getAllDerivedDefinitions("SubtargetFeature"); std::sort(DefList.begin(), DefList.end(), LessRecord()); unsigned N = DefList.size(); @@ -126,8 +132,8 @@ void SubtargetEmitter::Enumeration(raw_ostream &OS, OS << "namespace " << Target << " {\n"; - // Open enumeration. Use a 64-bit underlying type. - OS << "enum : uint64_t {\n"; + // Open enumeration. + OS << "enum {\n"; // For each record for (unsigned i = 0; i < N;) { @@ -142,7 +148,8 @@ void SubtargetEmitter::Enumeration(raw_ostream &OS, } // Close enumeration and namespace - OS << "};\n}\n"; + OS << "};\n"; + OS << "} // end namespace " << Target << "\n"; } // @@ -357,17 +364,16 @@ EmitStageAndOperandCycleData(raw_ostream &OS, SmallPtrSet<Record*, 8> ItinsDefSet; // Emit functional units for all the itineraries. - for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), - PE = SchedModels.procModelEnd(); PI != PE; ++PI) { + for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) { - if (!ItinsDefSet.insert(PI->ItinsDef).second) + if (!ItinsDefSet.insert(ProcModel.ItinsDef).second) continue; - std::vector<Record*> FUs = PI->ItinsDef->getValueAsListOfDefs("FU"); + std::vector<Record*> FUs = ProcModel.ItinsDef->getValueAsListOfDefs("FU"); if (FUs.empty()) continue; - const std::string &Name = PI->ItinsDef->getName(); + const std::string &Name = ProcModel.ItinsDef->getName(); OS << "\n// Functional units for \"" << Name << "\"\n" << "namespace " << Name << "FU {\n"; @@ -375,9 +381,9 @@ EmitStageAndOperandCycleData(raw_ostream &OS, OS << " const unsigned " << FUs[j]->getName() << " = 1 << " << j << ";\n"; - OS << "}\n"; + OS << "} // end namespace " << Name << "FU\n"; - std::vector<Record*> BPs = PI->ItinsDef->getValueAsListOfDefs("BP"); + std::vector<Record*> BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP"); if (!BPs.empty()) { OS << "\n// Pipeline forwarding pathes for itineraries \"" << Name << "\"\n" << "namespace " << Name << "Bypass {\n"; @@ -387,7 +393,7 @@ EmitStageAndOperandCycleData(raw_ostream &OS, OS << " const unsigned " << BPs[j]->getName() << " = 1 << " << j << ";\n"; - OS << "}\n"; + OS << "} // end namespace " << Name << "Bypass\n"; } } @@ -411,10 +417,7 @@ EmitStageAndOperandCycleData(raw_ostream &OS, // object with computed offsets to the ProcItinLists result. unsigned StageCount = 1, OperandCycleCount = 1; std::map<std::string, unsigned> ItinStageMap, ItinOperandMap; - for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), - PE = SchedModels.procModelEnd(); PI != PE; ++PI) { - const CodeGenProcModel &ProcModel = *PI; - + for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) { // Add process itinerary to the list. ProcItinLists.resize(ProcItinLists.size()+1); @@ -612,9 +615,8 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, int BufferSize = PRDef->getValueAsInt("BufferSize"); if (PRDef->isSubClassOf("ProcResGroup")) { RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources"); - for (RecIter RUI = ResUnits.begin(), RUE = ResUnits.end(); - RUI != RUE; ++RUI) { - NumUnits += (*RUI)->getValueAsInt("NumUnits"); + for (Record *RU : ResUnits) { + NumUnits += RU->getValueAsInt("NumUnits"); } } else { @@ -652,10 +654,9 @@ Record *SubtargetEmitter::FindWriteResources( return SchedWrite.TheDef; Record *AliasDef = nullptr; - for (RecIter AI = SchedWrite.Aliases.begin(), AE = SchedWrite.Aliases.end(); - AI != AE; ++AI) { + for (Record *A : SchedWrite.Aliases) { const CodeGenSchedRW &AliasRW = - SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW")); + SchedModels.getSchedRW(A->getValueAsDef("AliasRW")); if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) { Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); if (&SchedModels.getProcModel(ModelDef) != &ProcModel) @@ -672,18 +673,17 @@ Record *SubtargetEmitter::FindWriteResources( // Check this processor's list of write resources. Record *ResDef = nullptr; - for (RecIter WRI = ProcModel.WriteResDefs.begin(), - WRE = ProcModel.WriteResDefs.end(); WRI != WRE; ++WRI) { - if (!(*WRI)->isSubClassOf("WriteRes")) + for (Record *WR : ProcModel.WriteResDefs) { + if (!WR->isSubClassOf("WriteRes")) continue; - if (AliasDef == (*WRI)->getValueAsDef("WriteType") - || SchedWrite.TheDef == (*WRI)->getValueAsDef("WriteType")) { + if (AliasDef == WR->getValueAsDef("WriteType") + || SchedWrite.TheDef == WR->getValueAsDef("WriteType")) { if (ResDef) { - PrintFatalError((*WRI)->getLoc(), "Resources are defined for both " + PrintFatalError(WR->getLoc(), "Resources are defined for both " "SchedWrite and its alias on processor " + ProcModel.ModelName); } - ResDef = *WRI; + ResDef = WR; } } // TODO: If ProcModel has a base model (previous generation processor), @@ -706,10 +706,9 @@ Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead, // Check this processor's list of aliases for SchedRead. Record *AliasDef = nullptr; - for (RecIter AI = SchedRead.Aliases.begin(), AE = SchedRead.Aliases.end(); - AI != AE; ++AI) { + for (Record *A : SchedRead.Aliases) { const CodeGenSchedRW &AliasRW = - SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW")); + SchedModels.getSchedRW(A->getValueAsDef("AliasRW")); if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) { Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); if (&SchedModels.getProcModel(ModelDef) != &ProcModel) @@ -726,18 +725,17 @@ Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead, // Check this processor's ReadAdvanceList. Record *ResDef = nullptr; - for (RecIter RAI = ProcModel.ReadAdvanceDefs.begin(), - RAE = ProcModel.ReadAdvanceDefs.end(); RAI != RAE; ++RAI) { - if (!(*RAI)->isSubClassOf("ReadAdvance")) + for (Record *RA : ProcModel.ReadAdvanceDefs) { + if (!RA->isSubClassOf("ReadAdvance")) continue; - if (AliasDef == (*RAI)->getValueAsDef("ReadType") - || SchedRead.TheDef == (*RAI)->getValueAsDef("ReadType")) { + if (AliasDef == RA->getValueAsDef("ReadType") + || SchedRead.TheDef == RA->getValueAsDef("ReadType")) { if (ResDef) { - PrintFatalError((*RAI)->getLoc(), "Resources are defined for both " + PrintFatalError(RA->getLoc(), "Resources are defined for both " "SchedRead and its alias on processor " + ProcModel.ModelName); } - ResDef = *RAI; + ResDef = RA; } } // TODO: If ProcModel has a base model (previous generation processor), @@ -779,12 +777,10 @@ void SubtargetEmitter::ExpandProcResources(RecVec &PRVec, SubDef = SuperDef; } } - for (RecIter PRI = PM.ProcResourceDefs.begin(), - PRE = PM.ProcResourceDefs.end(); - PRI != PRE; ++PRI) { - if (*PRI == PRDef || !(*PRI)->isSubClassOf("ProcResGroup")) + for (Record *PR : PM.ProcResourceDefs) { + if (PR == PRDef || !PR->isSubClassOf("ProcResGroup")) continue; - RecVec SuperResources = (*PRI)->getValueAsListOfDefs("Resources"); + RecVec SuperResources = PR->getValueAsListOfDefs("Resources"); RecIter SubI = SubResources.begin(), SubE = SubResources.end(); for( ; SubI != SubE; ++SubI) { if (std::find(SuperResources.begin(), SuperResources.end(), *SubI) @@ -793,7 +789,7 @@ void SubtargetEmitter::ExpandProcResources(RecVec &PRVec, } } if (SubI == SubE) { - PRVec.push_back(*PRI); + PRVec.push_back(PR); Cycles.push_back(Cycles[i]); } } @@ -809,9 +805,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, return; std::vector<MCSchedClassDesc> &SCTab = SchedTables.ProcSchedClasses.back(); - for (CodeGenSchedModels::SchedClassIter SCI = SchedModels.schedClassBegin(), - SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) { - DEBUG(SCI->dump(&SchedModels)); + for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) { + DEBUG(SC.dump(&SchedModels)); SCTab.resize(SCTab.size() + 1); MCSchedClassDesc &SCDesc = SCTab.back(); @@ -826,7 +821,7 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, // A Variant SchedClass has no resources of its own. bool HasVariants = false; for (std::vector<CodeGenSchedTransition>::const_iterator - TI = SCI->Transitions.begin(), TE = SCI->Transitions.end(); + TI = SC.Transitions.begin(), TE = SC.Transitions.end(); TI != TE; ++TI) { if (TI->ProcIndices[0] == 0) { HasVariants = true; @@ -847,24 +842,23 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, // Determine if the SchedClass is actually reachable on this processor. If // not don't try to locate the processor resources, it will fail. // If ProcIndices contains 0, this class applies to all processors. - assert(!SCI->ProcIndices.empty() && "expect at least one procidx"); - if (SCI->ProcIndices[0] != 0) { - IdxIter PIPos = std::find(SCI->ProcIndices.begin(), - SCI->ProcIndices.end(), ProcModel.Index); - if (PIPos == SCI->ProcIndices.end()) + assert(!SC.ProcIndices.empty() && "expect at least one procidx"); + if (SC.ProcIndices[0] != 0) { + IdxIter PIPos = std::find(SC.ProcIndices.begin(), + SC.ProcIndices.end(), ProcModel.Index); + if (PIPos == SC.ProcIndices.end()) continue; } - IdxVec Writes = SCI->Writes; - IdxVec Reads = SCI->Reads; - if (!SCI->InstRWs.empty()) { + IdxVec Writes = SC.Writes; + IdxVec Reads = SC.Reads; + if (!SC.InstRWs.empty()) { // This class has a default ReadWrite list which can be overriden by // InstRW definitions. Record *RWDef = nullptr; - for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end(); - RWI != RWE; ++RWI) { - Record *RWModelDef = (*RWI)->getValueAsDef("SchedModel"); + for (Record *RW : SC.InstRWs) { + Record *RWModelDef = RW->getValueAsDef("SchedModel"); if (&ProcModel == &SchedModels.getProcModel(RWModelDef)) { - RWDef = *RWI; + RWDef = RW; break; } } @@ -877,19 +871,18 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, } 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) + for (Record *I : ProcModel.ItinRWDefs) { + RecVec Matched = I->getValueAsListOfDefs("MatchedItinClasses"); + if (std::find(Matched.begin(), Matched.end(), SC.ItinClassDef) != Matched.end()) { - SchedModels.findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), + SchedModels.findRWs(I->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); break; } } if (Writes.empty()) { DEBUG(dbgs() << ProcModel.ModelName - << " does not have resources for class " << SCI->Name << '\n'); + << " does not have resources for class " << SC.Name << '\n'); } } // Sum resources across all operand writes. @@ -897,9 +890,9 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, std::vector<MCWriteLatencyEntry> WriteLatencies; std::vector<std::string> WriterNames; std::vector<MCReadAdvanceEntry> ReadAdvanceEntries; - for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) { + for (unsigned W : Writes) { IdxVec WriteSeq; - SchedModels.expandRWSeqForProc(*WI, WriteSeq, /*IsRead=*/false, + SchedModels.expandRWSeqForProc(W, WriteSeq, /*IsRead=*/false, ProcModel); // For each operand, create a latency entry. @@ -915,11 +908,10 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, } WLEntry.WriteResourceID = WriteID; - for (IdxIter WSI = WriteSeq.begin(), WSE = WriteSeq.end(); - WSI != WSE; ++WSI) { + for (unsigned WS : WriteSeq) { Record *WriteRes = - FindWriteResources(SchedModels.getSchedWrite(*WSI), ProcModel); + FindWriteResources(SchedModels.getSchedWrite(WS), ProcModel); // Mark the parent class as invalid for unsupported write types. if (WriteRes->getValueAsBit("Unsupported")) { @@ -981,16 +973,15 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, if (ValidWrites.empty()) WriteIDs.push_back(0); else { - for (RecIter VWI = ValidWrites.begin(), VWE = ValidWrites.end(); - VWI != VWE; ++VWI) { - WriteIDs.push_back(SchedModels.getSchedRWIdx(*VWI, /*IsRead=*/false)); + for (Record *VW : ValidWrites) { + WriteIDs.push_back(SchedModels.getSchedRWIdx(VW, /*IsRead=*/false)); } } std::sort(WriteIDs.begin(), WriteIDs.end()); - for(IdxIter WI = WriteIDs.begin(), WE = WriteIDs.end(); WI != WE; ++WI) { + for(unsigned W : WriteIDs) { MCReadAdvanceEntry RAEntry; RAEntry.UseIdx = UseIdx; - RAEntry.WriteResourceID = *WI; + RAEntry.WriteResourceID = W; RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles"); ReadAdvanceEntries.push_back(RAEntry); } @@ -1130,7 +1121,7 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, && "invalid class not first"); OS << " {DBGFIELD(\"InvalidSchedClass\") " << MCSchedClassDesc::InvalidNumMicroOps - << ", 0, 0, 0, 0, 0, 0, 0, 0},\n"; + << ", false, false, 0, 0, 0, 0, 0, 0},\n"; for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) { MCSchedClassDesc &MCDesc = SCTab[SCIdx]; @@ -1139,7 +1130,8 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, if (SchedClass.Name.size() < 18) OS.indent(18 - SchedClass.Name.size()); OS << MCDesc.NumMicroOps - << ", " << MCDesc.BeginGroup << ", " << MCDesc.EndGroup + << ", " << ( MCDesc.BeginGroup ? "true" : "false" ) + << ", " << ( MCDesc.EndGroup ? "true" : "false" ) << ", " << format("%2d", MCDesc.WriteProcResIdx) << ", " << MCDesc.NumWriteProcResEntries << ", " << format("%2d", MCDesc.WriteLatencyIdx) @@ -1156,45 +1148,48 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { // For each processor model. - for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), - PE = SchedModels.procModelEnd(); PI != PE; ++PI) { + for (const CodeGenProcModel &PM : SchedModels.procModels()) { // Emit processor resource table. - if (PI->hasInstrSchedModel()) - EmitProcessorResources(*PI, OS); - else if(!PI->ProcResourceDefs.empty()) - PrintFatalError(PI->ModelDef->getLoc(), "SchedMachineModel defines " + if (PM.hasInstrSchedModel()) + EmitProcessorResources(PM, OS); + else if(!PM.ProcResourceDefs.empty()) + PrintFatalError(PM.ModelDef->getLoc(), "SchedMachineModel defines " "ProcResources without defining WriteRes SchedWriteRes"); // Begin processor itinerary properties OS << "\n"; - OS << "static const llvm::MCSchedModel " << PI->ModelName << " = {\n"; - EmitProcessorProp(OS, PI->ModelDef, "IssueWidth", ','); - EmitProcessorProp(OS, PI->ModelDef, "MicroOpBufferSize", ','); - EmitProcessorProp(OS, PI->ModelDef, "LoopMicroOpBufferSize", ','); - EmitProcessorProp(OS, PI->ModelDef, "LoadLatency", ','); - EmitProcessorProp(OS, PI->ModelDef, "HighLatency", ','); - EmitProcessorProp(OS, PI->ModelDef, "MispredictPenalty", ','); - - OS << " " << (bool)(PI->ModelDef ? - PI->ModelDef->getValueAsBit("PostRAScheduler") : 0) - << ", // " << "PostRAScheduler\n"; - - OS << " " << (bool)(PI->ModelDef ? - PI->ModelDef->getValueAsBit("CompleteModel") : 0) - << ", // " << "CompleteModel\n"; - - OS << " " << PI->Index << ", // Processor ID\n"; - if (PI->hasInstrSchedModel()) - OS << " " << PI->ModelName << "ProcResources" << ",\n" - << " " << PI->ModelName << "SchedClasses" << ",\n" - << " " << PI->ProcResourceDefs.size()+1 << ",\n" + OS << "static const llvm::MCSchedModel " << PM.ModelName << " = {\n"; + EmitProcessorProp(OS, PM.ModelDef, "IssueWidth", ','); + EmitProcessorProp(OS, PM.ModelDef, "MicroOpBufferSize", ','); + EmitProcessorProp(OS, PM.ModelDef, "LoopMicroOpBufferSize", ','); + EmitProcessorProp(OS, PM.ModelDef, "LoadLatency", ','); + EmitProcessorProp(OS, PM.ModelDef, "HighLatency", ','); + EmitProcessorProp(OS, PM.ModelDef, "MispredictPenalty", ','); + + bool PostRAScheduler = + (PM.ModelDef ? PM.ModelDef->getValueAsBit("PostRAScheduler") : false); + + OS << " " << (PostRAScheduler ? "true" : "false") << ", // " + << "PostRAScheduler\n"; + + bool CompleteModel = + (PM.ModelDef ? PM.ModelDef->getValueAsBit("CompleteModel") : false); + + OS << " " << (CompleteModel ? "true" : "false") << ", // " + << "CompleteModel\n"; + + OS << " " << PM.Index << ", // Processor ID\n"; + if (PM.hasInstrSchedModel()) + OS << " " << PM.ModelName << "ProcResources" << ",\n" + << " " << PM.ModelName << "SchedClasses" << ",\n" + << " " << PM.ProcResourceDefs.size()+1 << ",\n" << " " << (SchedModels.schedClassEnd() - SchedModels.schedClassBegin()) << ",\n"; else OS << " nullptr, nullptr, 0, 0," << " // No instruction-level machine model.\n"; - if (PI->hasItineraries()) - OS << " " << PI->ItinsDef->getName() << "};\n"; + if (PM.hasItineraries()) + OS << " " << PM.ItinsDef->getName() << "};\n"; else OS << " nullptr}; // No Itinerary\n"; } @@ -1260,9 +1255,8 @@ void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { << "// Data tables for the new per-operand machine model.\n"; SchedClassTables SchedTables; - for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), - PE = SchedModels.procModelEnd(); PI != PE; ++PI) { - GenSchedClassTables(*PI, SchedTables); + for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) { + GenSchedClassTables(ProcModel, SchedTables); } EmitSchedClassTables(SchedTables, OS); @@ -1274,7 +1268,7 @@ void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { OS << "#undef DBGFIELD"; } -void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName, +void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS) { OS << "unsigned " << ClassName << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI," @@ -1282,60 +1276,52 @@ void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName, std::vector<Record*> Prologs = Records.getAllDerivedDefinitions("PredicateProlog"); std::sort(Prologs.begin(), Prologs.end(), LessRecord()); - for (std::vector<Record*>::const_iterator - PI = Prologs.begin(), PE = Prologs.end(); PI != PE; ++PI) { - OS << (*PI)->getValueAsString("Code") << '\n'; + for (Record *P : Prologs) { + OS << P->getValueAsString("Code") << '\n'; } IdxVec VariantClasses; - for (CodeGenSchedModels::SchedClassIter SCI = SchedModels.schedClassBegin(), - SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) { - if (SCI->Transitions.empty()) + for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) { + if (SC.Transitions.empty()) continue; - VariantClasses.push_back(SCI->Index); + VariantClasses.push_back(SC.Index); } if (!VariantClasses.empty()) { OS << " switch (SchedClass) {\n"; - for (IdxIter VCI = VariantClasses.begin(), VCE = VariantClasses.end(); - VCI != VCE; ++VCI) { - const CodeGenSchedClass &SC = SchedModels.getSchedClass(*VCI); - OS << " case " << *VCI << ": // " << SC.Name << '\n'; + for (unsigned VC : VariantClasses) { + const CodeGenSchedClass &SC = SchedModels.getSchedClass(VC); + OS << " case " << VC << ": // " << SC.Name << '\n'; IdxVec ProcIndices; - for (std::vector<CodeGenSchedTransition>::const_iterator - TI = SC.Transitions.begin(), TE = SC.Transitions.end(); - TI != TE; ++TI) { + for (const CodeGenSchedTransition &T : SC.Transitions) { IdxVec PI; - std::set_union(TI->ProcIndices.begin(), TI->ProcIndices.end(), + std::set_union(T.ProcIndices.begin(), T.ProcIndices.end(), ProcIndices.begin(), ProcIndices.end(), std::back_inserter(PI)); ProcIndices.swap(PI); } - for (IdxIter PI = ProcIndices.begin(), PE = ProcIndices.end(); - PI != PE; ++PI) { + for (unsigned PI : ProcIndices) { OS << " "; - if (*PI != 0) - OS << "if (SchedModel->getProcessorID() == " << *PI << ") "; - OS << "{ // " << (SchedModels.procModelBegin() + *PI)->ModelName + if (PI != 0) + OS << "if (SchedModel->getProcessorID() == " << PI << ") "; + OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName << '\n'; - for (std::vector<CodeGenSchedTransition>::const_iterator - TI = SC.Transitions.begin(), TE = SC.Transitions.end(); - TI != TE; ++TI) { - if (*PI != 0 && !std::count(TI->ProcIndices.begin(), - TI->ProcIndices.end(), *PI)) { + for (const CodeGenSchedTransition &T : SC.Transitions) { + if (PI != 0 && !std::count(T.ProcIndices.begin(), + T.ProcIndices.end(), PI)) { continue; } OS << " if ("; - for (RecIter RI = TI->PredTerm.begin(), RE = TI->PredTerm.end(); + for (RecIter RI = T.PredTerm.begin(), RE = T.PredTerm.end(); RI != RE; ++RI) { - if (RI != TI->PredTerm.begin()) + if (RI != T.PredTerm.begin()) OS << "\n && "; OS << "(" << (*RI)->getValueAsString("Predicate") << ")"; } OS << ")\n" - << " return " << TI->ToClassIdx << "; // " - << SchedModels.getSchedClass(TI->ToClassIdx).Name << '\n'; + << " return " << T.ToClassIdx << "; // " + << SchedModels.getSchedClass(T.ToClassIdx).Name << '\n'; } OS << " }\n"; - if (*PI == 0) + if (PI == 0) break; } if (SC.isInferred()) @@ -1375,9 +1361,8 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS, OS << " InitMCProcessorInfo(CPU, FS);\n" << " const FeatureBitset& Bits = getFeatureBits();\n"; - for (unsigned i = 0; i < Features.size(); i++) { + for (Record *R : Features) { // Next record - Record *R = Features[i]; const std::string &Instance = R->getName(); const std::string &Value = R->getValueAsString("Value"); const std::string &Attribute = R->getValueAsString("Attribute"); @@ -1403,15 +1388,15 @@ void SubtargetEmitter::run(raw_ostream &OS) { emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS); OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n"; - OS << "#undef GET_SUBTARGETINFO_ENUM\n"; + OS << "#undef GET_SUBTARGETINFO_ENUM\n\n"; OS << "namespace llvm {\n"; - Enumeration(OS, "SubtargetFeature"); - OS << "} // end llvm namespace\n"; + Enumeration(OS); + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n"; OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n"; - OS << "#undef GET_SUBTARGETINFO_MC_DESC\n"; + OS << "#undef GET_SUBTARGETINFO_MC_DESC\n\n"; OS << "namespace llvm {\n"; #if 0 @@ -1424,7 +1409,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { EmitSchedModel(OS); OS << "\n"; #if 0 - OS << "}\n"; + OS << "} // end anonymous namespace\n\n"; #endif // MCInstrInfo initialization routine. @@ -1454,22 +1439,22 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "0, 0, 0"; OS << ");\n}\n\n"; - OS << "} // end llvm namespace\n"; + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n"; OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n"; - OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n"; + OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n\n"; OS << "#include \"llvm/Support/Debug.h\"\n"; - OS << "#include \"llvm/Support/raw_ostream.h\"\n"; + OS << "#include \"llvm/Support/raw_ostream.h\"\n\n"; ParseFeaturesFunction(OS, NumFeatures, NumProcs); OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n"; // Create a TargetSubtargetInfo subclass to hide the MC layer initialization. OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n"; - OS << "#undef GET_SUBTARGETINFO_HEADER\n"; + OS << "#undef GET_SUBTARGETINFO_HEADER\n\n"; std::string ClassName = Target + "GenSubtargetInfo"; OS << "namespace llvm {\n"; @@ -1484,14 +1469,14 @@ void SubtargetEmitter::run(raw_ostream &OS) { << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)" << " const;\n" << "};\n"; - OS << "} // end llvm namespace\n"; + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n"; OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n"; - OS << "#undef GET_SUBTARGETINFO_CTOR\n"; + OS << "#undef GET_SUBTARGETINFO_CTOR\n\n"; - OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n"; + OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n"; OS << "namespace llvm {\n"; OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n"; OS << "extern const llvm::SubtargetFeatureKV " << Target << "SubTypeKV[];\n"; @@ -1536,7 +1521,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { EmitSchedModelHelpers(ClassName, OS); - OS << "} // end llvm namespace\n"; + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n"; } @@ -1548,4 +1533,4 @@ void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) { SubtargetEmitter(RK, CGTarget).run(OS); } -} // end llvm namespace +} // end namespace llvm diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index bcc594d69a1d..24dbe5d3a280 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -43,7 +43,8 @@ enum ActionType { PrintSets, GenOptParserDefs, GenCTags, - GenAttributes + GenAttributes, + GenSearchableTables, }; namespace { @@ -89,6 +90,8 @@ namespace { "Generate ctags-compatible index"), clEnumValN(GenAttributes, "gen-attrs", "Generate attributes"), + clEnumValN(GenSearchableTables, "gen-searchable-tables", + "Generate generic binary-searchable table"), clEnumValEnd)); cl::opt<std::string> @@ -172,6 +175,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenAttributes: EmitAttributes(Records, OS); break; + case GenSearchableTables: + EmitSearchableTables(Records, OS); + break; } return false; @@ -179,7 +185,7 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { } int main(int argc, char **argv) { - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h index d9dd3d157697..51e017fe6594 100644 --- a/utils/TableGen/TableGenBackends.h +++ b/utils/TableGen/TableGenBackends.h @@ -79,6 +79,7 @@ void EmitMapTable(RecordKeeper &RK, raw_ostream &OS); void EmitOptParser(RecordKeeper &RK, raw_ostream &OS); void EmitCTags(RecordKeeper &RK, raw_ostream &OS); void EmitAttributes(RecordKeeper &RK, raw_ostream &OS); +void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS); } // End llvm namespace diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp index ad36dc427a56..5b710e446150 100644 --- a/utils/TableGen/X86DisassemblerTables.cpp +++ b/utils/TableGen/X86DisassemblerTables.cpp @@ -285,7 +285,7 @@ static inline bool inheritsFrom(InstructionContext child, return false; case IC_EVEX_L_W_K: case IC_EVEX_L_W_B: - case IC_EVEX_L_W_K_B: + case IC_EVEX_L_W_K_B: case IC_EVEX_L_W_XS_K: case IC_EVEX_L_W_XS_B: case IC_EVEX_L_W_XS_K_B: diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 8a5ae12f67fb..ca937d09726d 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -225,7 +225,6 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables, CD8_Scale = byteFromRec(Rec, "CD8_Scale"); Name = Rec->getName(); - AsmString = Rec->getValueAsString("AsmString"); Operands = &insn.Operands.OperandList; @@ -477,7 +476,7 @@ void RecognizableInstr::adjustOperandEncoding(OperandEncoding &encoding) { void RecognizableInstr::handleOperand(bool optional, unsigned &operandIndex, unsigned &physicalOperandIndex, - unsigned &numPhysicalOperands, + unsigned numPhysicalOperands, const unsigned *operandMapping, OperandEncoding (*encodingFromString) (const std::string&, @@ -562,6 +561,7 @@ void RecognizableInstr::emitInstructionSpecifier() { // physicalOperandIndex should always be < numPhysicalOperands unsigned physicalOperandIndex = 0; +#ifndef NDEBUG // Given the set of prefix bits, how many additional operands does the // instruction have? unsigned additionalOperands = 0; @@ -569,6 +569,7 @@ void RecognizableInstr::emitInstructionSpecifier() { ++additionalOperands; if (HasEVEX_K) ++additionalOperands; +#endif switch (Form) { default: llvm_unreachable("Unhandled form"); @@ -584,11 +585,9 @@ void RecognizableInstr::emitInstructionSpecifier() { return; case X86Local::RawFrm: // Operand 1 (optional) is an address or immediate. - // Operand 2 (optional) is an immediate. - assert(numPhysicalOperands <= 2 && + assert(numPhysicalOperands <= 1 && "Unexpected number of operands for RawFrm"); HANDLE_OPTIONAL(relocation) - HANDLE_OPTIONAL(immediate) break; case X86Local::RawFrmMemOffs: // Operand 1 is an address. @@ -800,8 +799,8 @@ void RecognizableInstr::emitInstructionSpecifier() { case X86Local::MRM_F1: case X86Local::MRM_F2: case X86Local::MRM_F3: case X86Local::MRM_F4: case X86Local::MRM_F5: case X86Local::MRM_F6: case X86Local::MRM_F7: case X86Local::MRM_F9: case X86Local::MRM_FA: - case X86Local::MRM_FB: case X86Local::MRM_FC: case X86Local::MRM_FD: - case X86Local::MRM_FE: case X86Local::MRM_FF: + case X86Local::MRM_FB: case X86Local::MRM_FC: case X86Local::MRM_FD: + case X86Local::MRM_FE: case X86Local::MRM_FF: // Ignored. break; } @@ -1024,19 +1023,19 @@ OperandType RecognizableInstr::typeFromString(const std::string &s, TYPE("VK32WM", TYPE_VK32) TYPE("VK64", TYPE_VK64) TYPE("VK64WM", TYPE_VK64) - TYPE("GR16_NOAX", TYPE_Rv) TYPE("GR32_NOAX", TYPE_Rv) - TYPE("GR64_NOAX", TYPE_R64) - TYPE("vx32mem", TYPE_M32) - TYPE("vx32xmem", TYPE_M32) - TYPE("vy32mem", TYPE_M32) - TYPE("vy32xmem", TYPE_M32) - TYPE("vz32mem", TYPE_M32) TYPE("vx64mem", TYPE_M64) + TYPE("vx128mem", TYPE_M128) + TYPE("vx256mem", TYPE_M256) + TYPE("vy128mem", TYPE_M128) + TYPE("vy256mem", TYPE_M256) TYPE("vx64xmem", TYPE_M64) - TYPE("vy64mem", TYPE_M64) - TYPE("vy64xmem", TYPE_M64) - TYPE("vz64mem", TYPE_M64) + TYPE("vx128xmem", TYPE_M128) + TYPE("vx256xmem", TYPE_M256) + TYPE("vy128xmem", TYPE_M128) + TYPE("vy256xmem", TYPE_M256) + TYPE("vy512mem", TYPE_M512) + TYPE("vz512mem", TYPE_M512) TYPE("BNDR", TYPE_BNDR) errs() << "Unhandled type string " << s << "\n"; llvm_unreachable("Unhandled type string"); @@ -1220,16 +1219,18 @@ RecognizableInstr::memoryEncodingFromString(const std::string &s, ENCODING("opaque48mem", ENCODING_RM) ENCODING("opaque80mem", ENCODING_RM) ENCODING("opaque512mem", ENCODING_RM) - ENCODING("vx32mem", ENCODING_RM) - ENCODING("vx32xmem", ENCODING_RM) - ENCODING("vy32mem", ENCODING_RM) - ENCODING("vy32xmem", ENCODING_RM) - ENCODING("vz32mem", ENCODING_RM) ENCODING("vx64mem", ENCODING_RM) + ENCODING("vx128mem", ENCODING_RM) + ENCODING("vx256mem", ENCODING_RM) + ENCODING("vy128mem", ENCODING_RM) + ENCODING("vy256mem", ENCODING_RM) ENCODING("vx64xmem", ENCODING_RM) - ENCODING("vy64mem", ENCODING_RM) - ENCODING("vy64xmem", ENCODING_RM) - ENCODING("vz64mem", ENCODING_RM) + ENCODING("vx128xmem", ENCODING_RM) + ENCODING("vx256xmem", ENCODING_RM) + ENCODING("vy128xmem", ENCODING_RM) + ENCODING("vy256xmem", ENCODING_RM) + ENCODING("vy512mem", ENCODING_RM) + ENCODING("vz512mem", ENCODING_RM) errs() << "Unhandled memory encoding " << s << "\n"; llvm_unreachable("Unhandled memory encoding"); } @@ -1288,9 +1289,7 @@ RecognizableInstr::opcodeModifierEncodingFromString(const std::string &s, ENCODING("GR64", ENCODING_RO) ENCODING("GR16", ENCODING_Rv) ENCODING("GR8", ENCODING_RB) - ENCODING("GR16_NOAX", ENCODING_Rv) ENCODING("GR32_NOAX", ENCODING_Rv) - ENCODING("GR64_NOAX", ENCODING_RO) errs() << "Unhandled opcode modifier encoding " << s << "\n"; llvm_unreachable("Unhandled opcode modifier encoding"); } diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h index 28e10535508d..f6f50065f704 100644 --- a/utils/TableGen/X86RecognizableInstr.h +++ b/utils/TableGen/X86RecognizableInstr.h @@ -19,7 +19,6 @@ #include "CodeGenTarget.h" #include "X86DisassemblerTables.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/Support/DataTypes.h" #include "llvm/TableGen/Record.h" @@ -87,8 +86,6 @@ private: /// The instruction name as listed in the tables std::string Name; - /// The AT&T AsmString for the instruction - std::string AsmString; /// Indicates whether the instruction should be emitted into the decode /// tables; regardless, it will be emitted into the instruction info table @@ -179,7 +176,7 @@ private: void handleOperand(bool optional, unsigned &operandIndex, unsigned &physicalOperandIndex, - unsigned &numPhysicalOperands, + unsigned numPhysicalOperands, const unsigned *operandMapping, OperandEncoding (*encodingFromString) (const std::string&, diff --git a/utils/TableGen/module.modulemap b/utils/TableGen/module.modulemap deleted file mode 100644 index 8871bbfd4a2f..000000000000 --- a/utils/TableGen/module.modulemap +++ /dev/null @@ -1,4 +0,0 @@ -module TableGen { - umbrella "." - module * { export * } -} |