diff options
Diffstat (limited to 'llvm/utils/TableGen')
50 files changed, 2571 insertions, 1675 deletions
diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp index 3d63059dcb8b..9d304910ba4e 100644 --- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp +++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp @@ -612,7 +612,7 @@ struct MatchableInfo { /// operator< - Compare two matchables. bool operator<(const MatchableInfo &RHS) const { // The primary comparator is the instruction mnemonic. - if (int Cmp = Mnemonic.compare(RHS.Mnemonic)) + if (int Cmp = Mnemonic.compare_lower(RHS.Mnemonic)) return Cmp == -1; if (AsmOperands.size() != RHS.AsmOperands.size()) @@ -789,9 +789,8 @@ public: } bool hasOptionalOperands() const { - return find_if(Classes, [](const ClassInfo &Class) { - return Class.IsOptional; - }) != Classes.end(); + return any_of(Classes, + [](const ClassInfo &Class) { return Class.IsOptional; }); } }; @@ -1018,7 +1017,7 @@ void MatchableInfo::tokenizeAsmString(const AsmMatcherInfo &Info, case '$': { if (InTok) { - addAsmOperand(String.slice(Prev, i), false); + addAsmOperand(String.slice(Prev, i), IsIsolatedToken); InTok = false; IsIsolatedToken = false; } @@ -1113,9 +1112,7 @@ static std::string getEnumNameForToken(StringRef Str) { case '-': Res += "_MINUS_"; break; case '#': Res += "_HASH_"; break; default: - if ((*it >= 'A' && *it <= 'Z') || - (*it >= 'a' && *it <= 'z') || - (*it >= '0' && *it <= '9')) + if (isAlnum(*it)) Res += *it; else Res += "_" + utostr((unsigned) *it) + "_"; @@ -1980,7 +1977,7 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, } CvtOS << " unsigned OpIdx;\n"; CvtOS << " Inst.setOpcode(Opcode);\n"; - CvtOS << " for (const uint8_t *p = Converter; *p; p+= 2) {\n"; + CvtOS << " for (const uint8_t *p = Converter; *p; p += 2) {\n"; if (HasOptionalOperands) { CvtOS << " OpIdx = *(p + 1) - DefaultsOffset[*(p + 1)];\n"; } else { @@ -1990,14 +1987,14 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, CvtOS << " default: llvm_unreachable(\"invalid conversion entry!\");\n"; CvtOS << " case CVT_Reg:\n"; CvtOS << " static_cast<" << TargetOperandClass - << "&>(*Operands[OpIdx]).addRegOperands(Inst, 1);\n"; + << " &>(*Operands[OpIdx]).addRegOperands(Inst, 1);\n"; CvtOS << " break;\n"; CvtOS << " case CVT_Tied: {\n"; CvtOS << " assert(OpIdx < (size_t)(std::end(TiedAsmOperandTable) -\n"; - CvtOS << " std::begin(TiedAsmOperandTable)) &&\n"; + CvtOS << " std::begin(TiedAsmOperandTable)) &&\n"; CvtOS << " \"Tied operand not found\");\n"; CvtOS << " unsigned TiedResOpnd = TiedAsmOperandTable[OpIdx][0];\n"; - CvtOS << " if (TiedResOpnd != (uint8_t) -1)\n"; + CvtOS << " if (TiedResOpnd != (uint8_t)-1)\n"; CvtOS << " Inst.addOperand(Inst.getOperand(TiedResOpnd));\n"; CvtOS << " break;\n"; CvtOS << " }\n"; @@ -2012,7 +2009,7 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n" << " unsigned NumMCOperands = 0;\n" << " const uint8_t *Converter = ConversionTable[Kind];\n" - << " for (const uint8_t *p = Converter; *p; p+= 2) {\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" @@ -2129,12 +2126,12 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, << OpInfo.MINumOperands << ");\n" << " } else {\n" << " static_cast<" << TargetOperandClass - << "&>(*Operands[OpIdx])." << Op.Class->RenderMethod + << " &>(*Operands[OpIdx])." << Op.Class->RenderMethod << "(Inst, " << OpInfo.MINumOperands << ");\n" << " }\n"; } else { CvtOS << " static_cast<" << TargetOperandClass - << "&>(*Operands[OpIdx])." << Op.Class->RenderMethod + << " &>(*Operands[OpIdx])." << Op.Class->RenderMethod << "(Inst, " << OpInfo.MINumOperands << ");\n"; } CvtOS << " break;\n"; @@ -2390,9 +2387,9 @@ static void emitMatchClassEnumeration(CodeGenTarget &Target, static void emitOperandMatchErrorDiagStrings(AsmMatcherInfo &Info, raw_ostream &OS) { // If the target does not use DiagnosticString for any operands, don't emit // an unused function. - if (std::all_of( - Info.Classes.begin(), Info.Classes.end(), - [](const ClassInfo &CI) { return CI.DiagnosticString.empty(); })) + if (llvm::all_of(Info.Classes, [](const ClassInfo &CI) { + return CI.DiagnosticString.empty(); + })) return; OS << "static const char *getMatchKindDiag(" << Info.Target.getName() @@ -2448,7 +2445,7 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info, OS << "static unsigned validateOperandClass(MCParsedAsmOperand &GOp, " << "MatchClassKind Kind) {\n"; OS << " " << Info.Target.getName() << "Operand &Operand = (" - << Info.Target.getName() << "Operand&)GOp;\n"; + << Info.Target.getName() << "Operand &)GOp;\n"; // The InvalidMatchClass is not to match any operand. OS << " if (Kind == InvalidMatchClass)\n"; @@ -2811,7 +2808,7 @@ static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info, Record *AsmVariant = Target.getAsmParserVariant(VC); int AsmParserVariantNo = AsmVariant->getValueAsInt("Variant"); StringRef AsmParserVariantName = AsmVariant->getValueAsString("Name"); - OS << " case " << AsmParserVariantNo << ":\n"; + OS << " case " << AsmParserVariantNo << ":\n"; emitMnemonicAliasVariant(OS, Info, Aliases, /*Indent=*/2, AsmParserVariantName); OS << " break;\n"; @@ -2880,7 +2877,7 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, OS << " { "; // Store a pascal-style length byte in the mnemonic. - std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.str(); + std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.lower(); OS << StringTable.GetOrAddStringOffset(LenMnemonic, false) << " /* " << II.Mnemonic << " */, "; @@ -2978,7 +2975,7 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, "FeatureBitsets[it->RequiredFeaturesIdx];\n"; OS << " if (!ParseForAllFeatures && (AvailableFeatures & " "RequiredFeatures) != RequiredFeatures)\n"; - OS << " continue;\n\n"; + OS << " continue;\n\n"; // Emit check to ensure the operand number matches. OS << " // check if the operand in question has a custom parser.\n"; @@ -3011,10 +3008,10 @@ static void emitAsmTiedOperandConstraints(CodeGenTarget &Target, OS << " uint64_t &ErrorInfo) {\n"; OS << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n"; OS << " const uint8_t *Converter = ConversionTable[Kind];\n"; - OS << " for (const uint8_t *p = Converter; *p; p+= 2) {\n"; + OS << " for (const uint8_t *p = Converter; *p; p += 2) {\n"; OS << " switch (*p) {\n"; OS << " case CVT_Tied: {\n"; - OS << " unsigned OpIdx = *(p+1);\n"; + OS << " unsigned OpIdx = *(p + 1);\n"; OS << " assert(OpIdx < (size_t)(std::end(TiedAsmOperandTable) -\n"; OS << " std::begin(TiedAsmOperandTable)) &&\n"; OS << " \"Tied operand not found\");\n"; @@ -3086,7 +3083,7 @@ static void emitMnemonicSpellChecker(raw_ostream &OS, CodeGenTarget &Target, OS << "\n"; OS << " std::string Res = \", did you mean: \";\n"; OS << " unsigned i = 0;\n"; - OS << " for( ; i < Candidates.size() - 1; i++)\n"; + OS << " for (; i < Candidates.size() - 1; i++)\n"; OS << " Res += Candidates[i].str() + \", \";\n"; OS << " return Res + Candidates[i].str() + \"?\";\n"; } @@ -3094,6 +3091,67 @@ static void emitMnemonicSpellChecker(raw_ostream &OS, CodeGenTarget &Target, OS << "\n"; } +static void emitMnemonicChecker(raw_ostream &OS, + CodeGenTarget &Target, + unsigned VariantCount, + bool HasMnemonicFirst, + bool HasMnemonicAliases) { + OS << "static bool " << Target.getName() + << "CheckMnemonic(StringRef Mnemonic,\n"; + OS << " " + << "const FeatureBitset &AvailableFeatures,\n"; + OS << " " + << "unsigned VariantID) {\n"; + + if (!VariantCount) { + OS << " return false;\n"; + } else { + if (HasMnemonicAliases) { + OS << " // Process all MnemonicAliases to remap the mnemonic.\n"; + OS << " applyMnemonicAliases(Mnemonic, AvailableFeatures, VariantID);"; + OS << "\n\n"; + } + OS << " // Find the appropriate table for this asm variant.\n"; + OS << " const MatchEntry *Start, *End;\n"; + OS << " switch (VariantID) {\n"; + OS << " default: llvm_unreachable(\"invalid variant!\");\n"; + for (unsigned VC = 0; VC != VariantCount; ++VC) { + Record *AsmVariant = Target.getAsmParserVariant(VC); + int AsmVariantNo = AsmVariant->getValueAsInt("Variant"); + OS << " case " << AsmVariantNo << ": Start = std::begin(MatchTable" << VC + << "); End = std::end(MatchTable" << VC << "); break;\n"; + } + OS << " }\n\n"; + + OS << " // Search the table.\n"; + if (HasMnemonicFirst) { + OS << " auto MnemonicRange = " + "std::equal_range(Start, End, Mnemonic, LessOpcode());\n\n"; + } else { + OS << " auto MnemonicRange = std::make_pair(Start, End);\n"; + OS << " unsigned SIndex = Mnemonic.empty() ? 0 : 1;\n"; + OS << " if (!Mnemonic.empty())\n"; + OS << " MnemonicRange = " + << "std::equal_range(Start, End, Mnemonic.lower(), LessOpcode());\n\n"; + } + + OS << " if (MnemonicRange.first == MnemonicRange.second)\n"; + OS << " return false;\n\n"; + + OS << " for (const MatchEntry *it = MnemonicRange.first, " + << "*ie = MnemonicRange.second;\n"; + OS << " it != ie; ++it) {\n"; + OS << " const FeatureBitset &RequiredFeatures =\n"; + OS << " FeatureBitsets[it->RequiredFeaturesIdx];\n"; + OS << " if ((AvailableFeatures & RequiredFeatures) == "; + OS << "RequiredFeatures)\n"; + OS << " return true;\n"; + OS << " }\n"; + OS << " return false;\n"; + } + OS << "}\n"; + OS << "\n"; +} // Emit a function mapping match classes to strings, for debugging. static void emitMatchClassKindNames(std::forward_list<ClassInfo> &Infos, @@ -3194,7 +3252,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << "#undef GET_ASSEMBLER_HEADER\n"; OS << " // This should be included into the middle of the declaration of\n"; OS << " // your subclasses implementation of MCTargetAsmParser.\n"; - OS << " FeatureBitset ComputeAvailableFeatures(const FeatureBitset& FB) const;\n"; + OS << " FeatureBitset ComputeAvailableFeatures(const FeatureBitset &FB) const;\n"; if (HasOptionalOperands) { OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, " << "unsigned Opcode,\n" @@ -3324,7 +3382,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { HasDeprecation |= MI->HasDeprecation; // Store a pascal-style length byte in the mnemonic. - std::string LenMnemonic = char(MI->Mnemonic.size()) + MI->Mnemonic.str(); + std::string LenMnemonic = char(MI->Mnemonic.size()) + MI->Mnemonic.lower(); MaxMnemonicIndex = std::max(MaxMnemonicIndex, StringTable.GetOrAddStringOffset(LenMnemonic, false)); } @@ -3438,7 +3496,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { continue; // Store a pascal-style length byte in the mnemonic. - std::string LenMnemonic = char(MI->Mnemonic.size()) + MI->Mnemonic.str(); + std::string LenMnemonic = + char(MI->Mnemonic.size()) + MI->Mnemonic.lower(); OS << " { " << StringTable.GetOrAddStringOffset(LenMnemonic, false) << " /* " << MI->Mnemonic << " */, " << Target.getInstNamespace() << "::" @@ -3497,12 +3556,12 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " // Get the instruction mnemonic, which is the first token.\n"; if (HasMnemonicFirst) { OS << " StringRef Mnemonic = ((" << Target.getName() - << "Operand&)*Operands[0]).getToken();\n\n"; + << "Operand &)*Operands[0]).getToken();\n\n"; } else { OS << " StringRef Mnemonic;\n"; OS << " if (Operands[0]->isToken())\n"; OS << " Mnemonic = ((" << Target.getName() - << "Operand&)*Operands[0]).getToken();\n\n"; + << "Operand &)*Operands[0]).getToken();\n\n"; } if (HasMnemonicAliases) { @@ -3552,7 +3611,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { } OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"AsmMatcher: found \" <<\n" - << " std::distance(MnemonicRange.first, MnemonicRange.second) << \n" + << " std::distance(MnemonicRange.first, MnemonicRange.second) <<\n" << " \" encodings with mnemonic '\" << Mnemonic << \"'\\n\");\n\n"; OS << " // Return a more specific error code if no mnemonics match.\n"; @@ -3727,10 +3786,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " FeatureBitset NewMissingFeatures = RequiredFeatures & " "~AvailableFeatures;\n"; OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Missing target features:\";\n"; - OS << " for (unsigned I = 0, E = NewMissingFeatures.size(); I != E; ++I)\n"; - OS << " if (NewMissingFeatures[I])\n"; - OS << " dbgs() << ' ' << I;\n"; - OS << " dbgs() << \"\\n\");\n"; + OS << " for (unsigned I = 0, E = NewMissingFeatures.size(); I != E; ++I)\n"; + OS << " if (NewMissingFeatures[I])\n"; + OS << " dbgs() << ' ' << I;\n"; + OS << " dbgs() << \"\\n\");\n"; if (ReportMultipleNearMisses) { OS << " FeaturesNearMiss = NearMissInfo::getMissedFeature(NewMissingFeatures);\n"; } else { @@ -3865,7 +3924,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " getTargetOptions().MCNoDeprecatedWarn &&\n"; OS << " MII.getDeprecatedInfo(Inst, getSTI(), Info)) {\n"; OS << " SMLoc Loc = ((" << Target.getName() - << "Operand&)*Operands[0]).getStartLoc();\n"; + << "Operand &)*Operands[0]).getStartLoc();\n"; OS << " getParser().Warning(Loc, Info, None);\n"; OS << " }\n"; } @@ -3908,6 +3967,14 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { emitMnemonicSpellChecker(OS, Target, VariantCount); OS << "#endif // GET_MNEMONIC_SPELL_CHECKER\n\n"; + + OS << "\n#ifdef GET_MNEMONIC_CHECKER\n"; + OS << "#undef GET_MNEMONIC_CHECKER\n\n"; + + emitMnemonicChecker(OS, Target, VariantCount, + HasMnemonicFirst, HasMnemonicAliases); + + OS << "#endif // GET_MNEMONIC_CHECKER\n\n"; } namespace llvm { diff --git a/llvm/utils/TableGen/AsmWriterEmitter.cpp b/llvm/utils/TableGen/AsmWriterEmitter.cpp index d10ea71e97e3..92df204475b9 100644 --- a/llvm/utils/TableGen/AsmWriterEmitter.cpp +++ b/llvm/utils/TableGen/AsmWriterEmitter.cpp @@ -64,9 +64,15 @@ public: AsmWriterEmitter(RecordKeeper &R); void run(raw_ostream &o); - private: - void EmitPrintInstruction(raw_ostream &o); + void EmitGetMnemonic( + raw_ostream &o, + std::vector<std::vector<std::string>> &TableDrivenOperandPrinters, + unsigned &BitsLeft, unsigned &AsmStrBits); + void EmitPrintInstruction( + raw_ostream &o, + std::vector<std::vector<std::string>> &TableDrivenOperandPrinters, + unsigned &BitsLeft, unsigned &AsmStrBits); void EmitGetRegisterName(raw_ostream &o); void EmitPrintAliasInstruction(raw_ostream &O); @@ -212,12 +218,11 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, // Otherwise, scan to see if all of the other instructions in this command // set share the operand. - 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]; - })) + if (any_of(drop_begin(Idxs), [&](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 @@ -288,22 +293,19 @@ static void UnescapeAliasString(std::string &Str) { } } -/// EmitPrintInstruction - Generate the code for the "printInstruction" method -/// implementation. Destroys all instances of AsmWriterInst information, by -/// clearing the Instructions vector. -void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { +void AsmWriterEmitter::EmitGetMnemonic( + raw_ostream &O, + std::vector<std::vector<std::string>> &TableDrivenOperandPrinters, + unsigned &BitsLeft, unsigned &AsmStrBits) { Record *AsmWriter = Target.getAsmWriter(); StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget"); - O << "/// printInstruction - This method is automatically generated by " + O << "/// getMnemonic - This method is automatically generated by " "tablegen\n" "/// from the instruction set description.\n" - "void " - << Target.getName() << ClassName - << "::printInstruction(const MCInst *MI, uint64_t Address, " - << (PassSubtarget ? "const MCSubtargetInfo &STI, " : "") - << "raw_ostream &O) {\n"; + "std::pair<const char *, uint64_t> " + << Target.getName() << ClassName << "::getMnemonic(const MCInst *MI) {\n"; // Build an aggregate string, and build a table of offsets into it. SequenceToOffsetTable<std::string> StringTable; @@ -349,13 +351,11 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { } // Figure out how many bits we used for the string index. - unsigned AsmStrBits = Log2_32_Ceil(MaxStringIdx+2); + AsmStrBits = Log2_32_Ceil(MaxStringIdx + 2); // To reduce code size, we compactify common instructions into a few bits // in the opcode-indexed table. - unsigned BitsLeft = OpcodeInfoBits-AsmStrBits; - - std::vector<std::vector<std::string>> TableDrivenOperandPrinters; + BitsLeft = OpcodeInfoBits - AsmStrBits; while (true) { std::vector<std::string> UniqueOperandCommands; @@ -435,15 +435,47 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { ++Table; } - // Emit the initial tab character. - O << " O << \"\\t\";\n\n"; - O << " // Emit the opcode for the instruction.\n"; O << BitsString; + // Return mnemonic string and bits. + O << " return {AsmStrs+(Bits & " << (1 << AsmStrBits) - 1 + << ")-1, Bits};\n\n"; + + O << "}\n"; +} + +/// EmitPrintInstruction - Generate the code for the "printInstruction" method +/// implementation. Destroys all instances of AsmWriterInst information, by +/// clearing the Instructions vector. +void AsmWriterEmitter::EmitPrintInstruction( + raw_ostream &O, + std::vector<std::vector<std::string>> &TableDrivenOperandPrinters, + unsigned &BitsLeft, unsigned &AsmStrBits) { + const unsigned OpcodeInfoBits = 64; + Record *AsmWriter = Target.getAsmWriter(); + StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); + bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget"); + + O << "/// printInstruction - This method is automatically generated by " + "tablegen\n" + "/// from the instruction set description.\n" + "void " + << Target.getName() << ClassName + << "::printInstruction(const MCInst *MI, uint64_t Address, " + << (PassSubtarget ? "const MCSubtargetInfo &STI, " : "") + << "raw_ostream &O) {\n"; + + // Emit the initial tab character. + O << " O << \"\\t\";\n\n"; + // Emit the starting string. - O << " assert(Bits != 0 && \"Cannot print this instruction.\");\n" - << " O << AsmStrs+(Bits & " << (1 << AsmStrBits)-1 << ")-1;\n\n"; + O << " auto MnemonicInfo = getMnemonic(MI);\n\n"; + O << " O << MnemonicInfo.first;\n\n"; + + O << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32) + << "_t Bits = MnemonicInfo.second;\n" + << " assert(Bits != 0 && \"Cannot print this instruction.\");\n"; // Output the table driven operand information. BitsLeft = OpcodeInfoBits-AsmStrBits; @@ -489,10 +521,8 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { } // Okay, delete instructions with no operand info left. - auto I = llvm::remove_if(Instructions, - [](AsmWriterInst &Inst) { return Inst.Operands.empty(); }); - Instructions.erase(I, Instructions.end()); - + llvm::erase_if(Instructions, + [](AsmWriterInst &Inst) { return Inst.Operands.empty(); }); // Because this is a vector, we want to emit from the end. Reverse all of the // elements in the vector. @@ -683,9 +713,7 @@ public: ++Next; } else { // $name, just eat the usual suspects. - while (I != End && - ((*I >= 'a' && *I <= 'z') || (*I >= 'A' && *I <= 'Z') || - (*I >= '0' && *I <= '9') || *I == '_')) + while (I != End && (isAlnum(*I) || *I == '_')) ++I; Next = I; } @@ -1232,13 +1260,10 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { << " break;\n"; for (unsigned i = 0; i < MCOpPredicates.size(); ++i) { - Init *MCOpPred = MCOpPredicates[i]->getValueInit("MCOperandPredicate"); - if (CodeInit *SI = dyn_cast<CodeInit>(MCOpPred)) { - O << " case " << i + 1 << ": {\n" - << SI->getValue() << "\n" - << " }\n"; - } else - llvm_unreachable("Unexpected MCOperandPredicate field!"); + StringRef MCOpPred = MCOpPredicates[i]->getValueAsString("MCOperandPredicate"); + O << " case " << i + 1 << ": {\n" + << MCOpPred.data() << "\n" + << " }\n"; } O << " }\n" << "}\n\n"; @@ -1262,7 +1287,11 @@ AsmWriterEmitter::AsmWriterEmitter(RecordKeeper &R) : Records(R), Target(R) { } void AsmWriterEmitter::run(raw_ostream &O) { - EmitPrintInstruction(O); + std::vector<std::vector<std::string>> TableDrivenOperandPrinters; + unsigned BitsLeft = 0; + unsigned AsmStrBits = 0; + EmitGetMnemonic(O, TableDrivenOperandPrinters, BitsLeft, AsmStrBits); + EmitPrintInstruction(O, TableDrivenOperandPrinters, BitsLeft, AsmStrBits); EmitGetRegisterName(O); EmitPrintAliasInstruction(O); } diff --git a/llvm/utils/TableGen/AsmWriterInst.cpp b/llvm/utils/TableGen/AsmWriterInst.cpp index 24d29ffc28e5..cf24f79334ca 100644 --- a/llvm/utils/TableGen/AsmWriterInst.cpp +++ b/llvm/utils/TableGen/AsmWriterInst.cpp @@ -18,12 +18,7 @@ using namespace llvm; -static bool isIdentChar(char C) { - return (C >= 'a' && C <= 'z') || - (C >= 'A' && C <= 'Z') || - (C >= '0' && C <= '9') || - C == '_'; -} +static bool isIdentChar(char C) { return isAlnum(C) || C == '_'; } std::string AsmWriterOperand::getCode(bool PassSubtarget) const { if (OperandType == isLiteralTextOperand) { diff --git a/llvm/utils/TableGen/CallingConvEmitter.cpp b/llvm/utils/TableGen/CallingConvEmitter.cpp index a4e993f80ec9..9e997483d21d 100644 --- a/llvm/utils/TableGen/CallingConvEmitter.cpp +++ b/llvm/utils/TableGen/CallingConvEmitter.cpp @@ -38,6 +38,7 @@ void CallingConvEmitter::run(raw_ostream &O) { // Emit prototypes for all of the non-custom CC's so that they can forward ref // each other. + Records.startTimer("Emit prototypes"); for (Record *CC : CCs) { if (!CC->getValueAsBit("Custom")) { unsigned Pad = CC->getName().size(); @@ -56,6 +57,7 @@ void CallingConvEmitter::run(raw_ostream &O) { } // Emit each non-custom calling convention description in full. + Records.startTimer("Emit full descriptions"); for (Record *CC : CCs) { if (!CC->getValueAsBit("Custom")) EmitCallingConv(CC, O); @@ -85,7 +87,7 @@ void CallingConvEmitter::EmitCallingConv(Record *CC, raw_ostream &O) { EmitAction(CCActions->getElementAsRecord(i), 2, O); } - O << "\n return true; // CC didn't match.\n"; + O << "\n return true; // CC didn't match.\n"; O << "}\n"; } @@ -238,11 +240,11 @@ void CallingConvEmitter::EmitAction(Record *Action, O << IndentStr << "LocInfo = CCValAssign::FPExt;\n"; } else { O << IndentStr << "if (ArgFlags.isSExt())\n" - << IndentStr << IndentStr << "LocInfo = CCValAssign::SExt;\n" + << IndentStr << " LocInfo = CCValAssign::SExt;\n" << IndentStr << "else if (ArgFlags.isZExt())\n" - << IndentStr << IndentStr << "LocInfo = CCValAssign::ZExt;\n" + << IndentStr << " LocInfo = CCValAssign::ZExt;\n" << IndentStr << "else\n" - << IndentStr << IndentStr << "LocInfo = CCValAssign::AExt;\n"; + << IndentStr << " LocInfo = CCValAssign::AExt;\n"; } } else if (Action->isSubClassOf("CCPromoteToUpperBitsInType")) { Record *DestTy = Action->getValueAsDef("DestTy"); @@ -254,11 +256,11 @@ void CallingConvEmitter::EmitAction(Record *Action, "point"); } else { O << IndentStr << "if (ArgFlags.isSExt())\n" - << IndentStr << IndentStr << "LocInfo = CCValAssign::SExtUpper;\n" + << IndentStr << " LocInfo = CCValAssign::SExtUpper;\n" << IndentStr << "else if (ArgFlags.isZExt())\n" - << IndentStr << IndentStr << "LocInfo = CCValAssign::ZExtUpper;\n" + << IndentStr << " LocInfo = CCValAssign::ZExtUpper;\n" << IndentStr << "else\n" - << IndentStr << IndentStr << "LocInfo = CCValAssign::AExtUpper;\n"; + << IndentStr << " LocInfo = CCValAssign::AExtUpper;\n"; } } else if (Action->isSubClassOf("CCBitConvertToType")) { Record *DestTy = Action->getValueAsDef("DestTy"); @@ -282,7 +284,7 @@ void CallingConvEmitter::EmitAction(Record *Action, O << IndentStr << "if (" << Action->getValueAsString("FuncName") << "(ValNo, ValVT, " << "LocVT, LocInfo, ArgFlags, State))\n"; - O << IndentStr << IndentStr << "return false;\n"; + O << IndentStr << " return false;\n"; } else { errs() << *Action; PrintFatalError(Action->getLoc(), "Unknown CCAction!"); diff --git a/llvm/utils/TableGen/CodeEmitterGen.cpp b/llvm/utils/TableGen/CodeEmitterGen.cpp index 6338d44fb2a7..53bf953b13cf 100644 --- a/llvm/utils/TableGen/CodeEmitterGen.cpp +++ b/llvm/utils/TableGen/CodeEmitterGen.cpp @@ -311,7 +311,7 @@ std::string CodeEmitterGen::getInstructionCaseForEncoding(Record *R, Record *Enc for (const RecordVal &RV : EncodingDef->getValues()) { // Ignore fixed fields in the record, we're looking for values like: // bits<5> RST = { ?, ?, ?, ?, ? }; - if (RV.getPrefix() || RV.getValue()->isComplete()) + if (RV.isNonconcreteOK() || RV.getValue()->isComplete()) continue; AddCodeToMergeInOperand(R, BI, std::string(RV.getName()), NumberedOp, @@ -483,7 +483,7 @@ void CodeEmitterGen::run(raw_ostream &o) { << " Inst = Inst.zext(" << BitWidth << ");\n" << " if (Scratch.getBitWidth() != " << BitWidth << ")\n" << " Scratch = Scratch.zext(" << BitWidth << ");\n" - << " LoadIntFromMemory(Inst, (uint8_t*)&InstBits[opcode * " << NumWords + << " LoadIntFromMemory(Inst, (uint8_t *)&InstBits[opcode * " << NumWords << "], " << NumBytes << ");\n" << " APInt &Value = Inst;\n" << " APInt &op = Scratch;\n" @@ -643,9 +643,9 @@ void CodeEmitterGen::run(raw_ostream &o) { << " report_fatal_error(Msg.str());\n" << " }\n" << "#else\n" - << "// Silence unused variable warning on targets that don't use MCII for " + << " // Silence unused variable warning on targets that don't use MCII for " "other purposes (e.g. BPF).\n" - << "(void)MCII;\n" + << " (void)MCII;\n" << "#endif // NDEBUG\n"; o << "}\n"; o << "#endif\n"; diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp index 6fdc116721f3..1ca4a68eb155 100644 --- a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp @@ -507,9 +507,9 @@ bool TypeInfer::EnforceSmallerThan(TypeSetByHwMode &Small, // Always treat non-scalable MVTs as smaller than scalable MVTs for the // purposes of ordering. auto ASize = std::make_tuple(A.isScalableVector(), A.getScalarSizeInBits(), - A.getSizeInBits()); + A.getSizeInBits().getKnownMinSize()); auto BSize = std::make_tuple(B.isScalableVector(), B.getScalarSizeInBits(), - B.getSizeInBits()); + B.getSizeInBits().getKnownMinSize()); return ASize < BSize; }; auto SameKindLE = [](MVT A, MVT B) -> bool { @@ -520,8 +520,10 @@ bool TypeInfer::EnforceSmallerThan(TypeSetByHwMode &Small, std::make_tuple(B.isVector(), B.isScalableVector())) return false; - return std::make_tuple(A.getScalarSizeInBits(), A.getSizeInBits()) <= - std::make_tuple(B.getScalarSizeInBits(), B.getSizeInBits()); + return std::make_tuple(A.getScalarSizeInBits(), + A.getSizeInBits().getKnownMinSize()) <= + std::make_tuple(B.getScalarSizeInBits(), + B.getSizeInBits().getKnownMinSize()); }; for (unsigned M : Modes) { @@ -728,14 +730,14 @@ bool TypeInfer::EnforceSameSize(TypeSetByHwMode &A, TypeSetByHwMode &B) { if (B.empty()) Changed |= EnforceAny(B); - auto NoSize = [](const SmallSet<unsigned,2> &Sizes, MVT T) -> bool { + auto NoSize = [](const SmallSet<TypeSize, 2> &Sizes, MVT T) -> bool { return !Sizes.count(T.getSizeInBits()); }; for (unsigned M : union_modes(A, B)) { TypeSetByHwMode::SetType &AS = A.get(M); TypeSetByHwMode::SetType &BS = B.get(M); - SmallSet<unsigned,2> AN, BN; + SmallSet<TypeSize, 2> AN, BN; for (MVT T : AS) AN.insert(T.getSizeInBits()); @@ -871,7 +873,7 @@ bool TreePredicateFn::hasPredCode() const { } std::string TreePredicateFn::getPredCode() const { - std::string Code = ""; + std::string Code; if (!isLoad() && !isStore() && !isAtomic()) { Record *MemoryVT = getMemoryVT(); @@ -2388,7 +2390,7 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { MVT::SimpleValueType VT = P.second.SimpleTy; if (VT == MVT::iPTR || VT == MVT::iPTRAny) continue; - unsigned Size = MVT(VT).getSizeInBits(); + unsigned Size = MVT(VT).getFixedSizeInBits(); // Make sure that the value is representable for this type. if (Size >= 32) continue; @@ -3086,7 +3088,7 @@ CodeGenDAGPatterns::CodeGenDAGPatterns(RecordKeeper &R, VerifyInstructionFlags(); } -Record *CodeGenDAGPatterns::getSDNodeNamed(const std::string &Name) const { +Record *CodeGenDAGPatterns::getSDNodeNamed(StringRef Name) const { Record *N = Records.getDef(Name); if (!N || !N->isSubClassOf("SDNode")) PrintFatalError("Error getting SDNode '" + Name + "'!"); @@ -3589,6 +3591,9 @@ static bool hasNullFragReference(DagInit *DI) { if (Operator->getName() == "null_frag") return true; // If any of the arguments reference the null fragment, return true. for (unsigned i = 0, e = DI->getNumArgs(); i != e; ++i) { + if (auto Arg = dyn_cast<DefInit>(DI->getArg(i))) + if (Arg->getDef()->getName() == "null_frag") + return true; DagInit *Arg = dyn_cast<DagInit>(DI->getArg(i)); if (Arg && hasNullFragReference(Arg)) return true; @@ -3696,10 +3701,11 @@ void CodeGenDAGPatterns::parseInstructionPattern( for (unsigned i = 0; i != NumResults; ++i) { if (i == CGI.Operands.size()) { const std::string &OpName = - std::find_if(InstResults.begin(), InstResults.end(), - [](const std::pair<std::string, TreePatternNodePtr> &P) { - return P.second; - }) + llvm::find_if( + InstResults, + [](const std::pair<std::string, TreePatternNodePtr> &P) { + return P.second; + }) ->first; I.error("'" + OpName + "' set but does not appear in operand list!"); @@ -4288,7 +4294,7 @@ void CodeGenDAGPatterns::ExpandHwModeBasedTypes() { std::vector<Predicate> Preds = P.Predicates; const std::vector<Predicate> &MC = ModeChecks[Mode]; - Preds.insert(Preds.end(), MC.begin(), MC.end()); + llvm::append_range(Preds, MC); PatternsToMatch.emplace_back(P.getSrcRecord(), Preds, std::move(NewSrc), std::move(NewDst), P.getDstRegs(), P.getAddedComplexity(), Record::getNewUID(), diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.h b/llvm/utils/TableGen/CodeGenDAGPatterns.h index a3b84d76fde9..bc939fe9acc1 100644 --- a/llvm/utils/TableGen/CodeGenDAGPatterns.h +++ b/llvm/utils/TableGen/CodeGenDAGPatterns.h @@ -14,7 +14,6 @@ #ifndef LLVM_UTILS_TABLEGEN_CODEGENDAGPATTERNS_H #define LLVM_UTILS_TABLEGEN_CODEGENDAGPATTERNS_H -#include "CodeGenHwModes.h" #include "CodeGenIntrinsics.h" #include "CodeGenTarget.h" #include "SDNodeProperties.h" @@ -42,7 +41,6 @@ class SDNodeInfo; class TreePattern; class TreePatternNode; class CodeGenDAGPatterns; -class ComplexPattern; /// Shared pointer for TreePatternNode. using TreePatternNodePtr = std::shared_ptr<TreePatternNode>; @@ -190,7 +188,7 @@ private: struct TypeSetByHwMode : public InfoByHwMode<MachineValueTypeSet> { using SetType = MachineValueTypeSet; - std::vector<unsigned> AddrSpaces; + SmallVector<unsigned, 16> AddrSpaces; TypeSetByHwMode() = default; TypeSetByHwMode(const TypeSetByHwMode &VTS) = default; @@ -438,8 +436,6 @@ public: unsigned getScope() const { return Scope; } const std::string &getIdentifier() const { return Identifier; } - std::string getFullName() const; - bool operator==(const ScopedName &o) const; bool operator!=(const ScopedName &o) const; }; @@ -1180,7 +1176,7 @@ public: const CodeGenTarget &getTargetInfo() const { return Target; } const TypeSetByHwMode &getLegalTypes() const { return LegalVTS; } - Record *getSDNodeNamed(const std::string &Name) const; + Record *getSDNodeNamed(StringRef Name) const; const SDNodeInfo &getSDNodeInfo(Record *R) const { auto F = SDNodes.find(R); diff --git a/llvm/utils/TableGen/CodeGenInstruction.cpp b/llvm/utils/TableGen/CodeGenInstruction.cpp index 1df5902b081e..960fe08677f7 100644 --- a/llvm/utils/TableGen/CodeGenInstruction.cpp +++ b/llvm/utils/TableGen/CodeGenInstruction.cpp @@ -472,7 +472,7 @@ HasOneImplicitDefWithKnownVT(const CodeGenTarget &TargetInfo) const { /// include text from the specified variant, returning the new string. std::string CodeGenInstruction:: FlattenAsmStringVariants(StringRef Cur, unsigned Variant) { - std::string Res = ""; + std::string Res; for (;;) { // Find the start of the next variant string. diff --git a/llvm/utils/TableGen/CodeGenIntrinsics.h b/llvm/utils/TableGen/CodeGenIntrinsics.h index af59c1f3d833..c469f662a42d 100644 --- a/llvm/utils/TableGen/CodeGenIntrinsics.h +++ b/llvm/utils/TableGen/CodeGenIntrinsics.h @@ -148,6 +148,7 @@ struct CodeGenIntrinsic { enum ArgAttrKind { NoCapture, NoAlias, + NoUndef, Returned, ReadOnly, WriteOnly, @@ -176,6 +177,13 @@ struct CodeGenIntrinsic { return Properties & (1 << Prop); } + /// Goes through all IntrProperties that have IsDefault + /// value set and sets the property. + void setDefaultProperties(Record *R, std::vector<Record *> DefaultProperties); + + /// Helper function to set property \p Name to true; + void setProperty(Record *R); + /// Returns true if the parameter at \p ParamIdx is a pointer type. Returns /// false if the parameter is not a pointer, or \p ParamIdx is greater than /// the size of \p IS.ParamVTs. @@ -185,7 +193,7 @@ struct CodeGenIntrinsic { bool isParamImmArg(unsigned ParamIdx) const; - CodeGenIntrinsic(Record *R); + CodeGenIntrinsic(Record *R, std::vector<Record *> DefaultProperties); }; class CodeGenIntrinsicTable { diff --git a/llvm/utils/TableGen/CodeGenMapTable.cpp b/llvm/utils/TableGen/CodeGenMapTable.cpp index baca0768b26b..289a20a96f02 100644 --- a/llvm/utils/TableGen/CodeGenMapTable.cpp +++ b/llvm/utils/TableGen/CodeGenMapTable.cpp @@ -144,25 +144,15 @@ public: } } - std::string getName() const { - return Name; - } + const std::string &getName() const { return Name; } - std::string getFilterClass() { - return FilterClass; - } + const std::string &getFilterClass() const { return FilterClass; } - ListInit *getRowFields() const { - return RowFields; - } + ListInit *getRowFields() const { return RowFields; } - ListInit *getColFields() const { - return ColFields; - } + ListInit *getColFields() const { return ColFields; } - ListInit *getKeyCol() const { - return KeyCol; - } + ListInit *getKeyCol() const { return KeyCol; } const std::vector<ListInit*> &getValueCols() const { return ValueCols; @@ -200,7 +190,7 @@ private: public: MapTableEmitter(CodeGenTarget &Target, RecordKeeper &Records, Record *IMRec): Target(Target), InstrMapDesc(IMRec) { - const std::string FilterClass = InstrMapDesc.getFilterClass(); + const std::string &FilterClass = InstrMapDesc.getFilterClass(); InstrDefs = Records.getAllDerivedDefinitions(FilterClass); } @@ -384,7 +374,7 @@ unsigned MapTableEmitter::emitBinSearchTable(raw_ostream &OS) { for (unsigned i = 0; i < TotalNumInstr; i++) { Record *CurInstr = NumberedInstructions[i]->TheDef; std::vector<Record*> ColInstrs = MapTable[CurInstr]; - std::string OutStr(""); + std::string OutStr; unsigned RelExists = 0; if (!ColInstrs.empty()) { for (unsigned j = 0; j < NumCol; j++) { @@ -422,7 +412,7 @@ void MapTableEmitter::emitBinSearch(raw_ostream &OS, unsigned TableSize) { OS << " unsigned start = 0;\n"; OS << " unsigned end = " << TableSize << ";\n"; OS << " while (start < end) {\n"; - OS << " mid = start + (end - start)/2;\n"; + OS << " mid = start + (end - start) / 2;\n"; OS << " if (Opcode == " << InstrMapDesc.getName() << "Table[mid][0]) {\n"; OS << " break;\n"; OS << " }\n"; diff --git a/llvm/utils/TableGen/CodeGenRegisters.cpp b/llvm/utils/TableGen/CodeGenRegisters.cpp index 4584bc7cfae3..f9a7ba6bba80 100644 --- a/llvm/utils/TableGen/CodeGenRegisters.cpp +++ b/llvm/utils/TableGen/CodeGenRegisters.cpp @@ -196,7 +196,7 @@ void CodeGenRegister::buildObjectGraph(CodeGenRegBank &RegBank) { } } -const StringRef CodeGenRegister::getName() const { +StringRef CodeGenRegister::getName() const { assert(TheDef && "no def"); return TheDef->getName(); } @@ -496,11 +496,10 @@ void CodeGenRegister::computeSecondarySubRegs(CodeGenRegBank &RegBank) { assert(getSubRegIndex(SubReg) == SubRegIdx && "LeadingSuperRegs correct"); for (CodeGenRegister *SubReg : Cand->ExplicitSubRegs) { if (CodeGenSubRegIndex *SubRegIdx = getSubRegIndex(SubReg)) { - if (SubRegIdx->ConcatenationOf.empty()) { + if (SubRegIdx->ConcatenationOf.empty()) Parts.push_back(SubRegIdx); - } else - for (CodeGenSubRegIndex *SubIdx : SubRegIdx->ConcatenationOf) - Parts.push_back(SubIdx); + else + append_range(Parts, SubRegIdx->ConcatenationOf); } else { // Sub-register doesn't exist. Parts.clear(); @@ -743,6 +742,8 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R) TopoSigs(RegBank.getNumTopoSigs()), EnumValue(-1) { GeneratePressureSet = R->getValueAsBit("GeneratePressureSet"); std::vector<Record*> TypeList = R->getValueAsListOfDefs("RegTypes"); + if (TypeList.empty()) + PrintFatalError(R->getLoc(), "RegTypes list must not be empty!"); for (unsigned i = 0, e = TypeList.size(); i != e; ++i) { Record *Type = TypeList[i]; if (!Type->isSubClassOf("ValueType")) @@ -751,7 +752,6 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R) "' does not derive from the ValueType class!"); VTs.push_back(getValueTypeByHwMode(Type, RegBank.getHwModes())); } - assert(!VTs.empty() && "RegisterClass must contain at least one ValueType!"); // Allocation order 0 is the full set. AltOrders provides others. const SetTheory::RecVec *Elements = RegBank.getSets().expand(R); @@ -998,6 +998,8 @@ CodeGenRegisterClass::getMatchingSubClassWithSubRegs( const CodeGenRegisterClass *B) { // If there are multiple, identical register classes, prefer the original // register class. + if (A == B) + return false; if (A->getMembers().size() == B->getMembers().size()) return A == this; return A->getMembers().size() > B->getMembers().size(); @@ -1235,8 +1237,7 @@ CodeGenSubRegIndex *CodeGenRegBank::getSubRegIdx(Record *Def) { const CodeGenSubRegIndex * CodeGenRegBank::findSubRegIdx(const Record* Def) const { - auto I = Def2SubRegIdx.find(Def); - return (I == Def2SubRegIdx.end()) ? nullptr : I->second; + return Def2SubRegIdx.lookup(Def); } CodeGenRegister *CodeGenRegBank::getReg(Record *Def) { @@ -2008,7 +2009,7 @@ void CodeGenRegBank::computeRegUnitSets() { if (RCRegUnits.empty()) continue; - LLVM_DEBUG(dbgs() << "RC " << RC.getName() << " Units: \n"; + LLVM_DEBUG(dbgs() << "RC " << RC.getName() << " Units:\n"; for (auto U : RCRegUnits) printRegUnitName(U); dbgs() << "\n UnitSetIDs:"); diff --git a/llvm/utils/TableGen/CodeGenRegisters.h b/llvm/utils/TableGen/CodeGenRegisters.h index 2b200adef312..5228e6518fe5 100644 --- a/llvm/utils/TableGen/CodeGenRegisters.h +++ b/llvm/utils/TableGen/CodeGenRegisters.h @@ -163,7 +163,7 @@ namespace llvm { CodeGenRegister(Record *R, unsigned Enum); - const StringRef getName() const; + StringRef getName() const; // Extract more information from TheDef. This is used to build an object // graph after all CodeGenRegister objects have been created. @@ -353,7 +353,7 @@ namespace llvm { unsigned getNumValueTypes() const { return VTs.size(); } bool hasType(const ValueTypeByHwMode &VT) const { - return std::find(VTs.begin(), VTs.end(), VT) != VTs.end(); + return llvm::is_contained(VTs, VT); } const ValueTypeByHwMode &getValueTypeNum(unsigned VTNum) const { diff --git a/llvm/utils/TableGen/CodeGenSchedule.cpp b/llvm/utils/TableGen/CodeGenSchedule.cpp index 67583c736cd2..b20eb6eff422 100644 --- a/llvm/utils/TableGen/CodeGenSchedule.cpp +++ b/llvm/utils/TableGen/CodeGenSchedule.cpp @@ -86,7 +86,7 @@ struct InstRegexOp : public SetTheory::Operator { auto Pseudos = Instructions.slice(NumGeneric, NumPseudos); auto NonPseudos = Instructions.slice(NumGeneric + NumPseudos); - for (Init *Arg : make_range(Expr->arg_begin(), Expr->arg_end())) { + for (Init *Arg : Expr->getArgs()) { StringInit *SI = dyn_cast<StringInit>(Arg); if (!SI) PrintFatalError(Loc, "instregex requires pattern string: " + @@ -248,8 +248,7 @@ void CodeGenSchedModels::checkSTIPredicates() const { } PrintError(R->getLoc(), "STIPredicate " + Name + " multiply declared."); - PrintNote(It->second->getLoc(), "Previous declaration was here."); - PrintFatalError(R->getLoc(), "Invalid STIPredicateDecl found."); + PrintFatalNote(It->second->getLoc(), "Previous declaration was here."); } // Disallow InstructionEquivalenceClasses with an empty instruction list. @@ -284,7 +283,7 @@ static APInt constructOperandMask(ArrayRef<int64_t> Indices) { static void processSTIPredicate(STIPredicateFunction &Fn, - const DenseMap<Record *, unsigned> &ProcModelMap) { + const ProcModelMapTy &ProcModelMap) { DenseMap<const Record *, unsigned> Opcode2Index; using OpcodeMapPair = std::pair<const Record *, OpcodeInfo>; std::vector<OpcodeMapPair> OpcodeMappings; @@ -454,10 +453,8 @@ void CodeGenSchedModels::checkMCInstPredicates() const { PrintError(TIIPred->getLoc(), "TIIPredicate " + Name + " is multiply defined."); - PrintNote(It->second->getLoc(), - " Previous definition of " + Name + " was here."); - PrintFatalError(TIIPred->getLoc(), - "Found conflicting definitions of TIIPredicate."); + PrintFatalNote(It->second->getLoc(), + " Previous definition of " + Name + " was here."); } } @@ -953,9 +950,9 @@ void CodeGenSchedModels::collectSchedClasses() { } // If ProcIndices contains zero, the class applies to all processors. LLVM_DEBUG({ - if (!std::count(ProcIndices.begin(), ProcIndices.end(), 0)) { + if (!llvm::is_contained(ProcIndices, 0)) { for (const CodeGenProcModel &PM : ProcModels) { - if (!std::count(ProcIndices.begin(), ProcIndices.end(), PM.Index)) + if (!llvm::is_contained(ProcIndices, PM.Index)) dbgs() << "No machine model for " << Inst->TheDef->getName() << " on processor " << PM.ModelName << '\n'; } @@ -1083,13 +1080,14 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { if (RWD->getValueAsDef("SchedModel") == RWModelDef && RWModelDef->getValueAsBit("FullInstRWOverlapCheck")) { assert(!InstDefs.empty()); // Checked at function start. - PrintFatalError - (InstRWDef->getLoc(), - "Overlapping InstRW definition for \"" + - InstDefs.front()->getName() + - "\" also matches previous \"" + - RWD->getValue("Instrs")->getValue()->getAsString() + - "\"."); + PrintError( + InstRWDef->getLoc(), + "Overlapping InstRW definition for \"" + + InstDefs.front()->getName() + + "\" also matches previous \"" + + RWD->getValue("Instrs")->getValue()->getAsString() + + "\"."); + PrintFatalNote(RWD->getLoc(), "Previous match was here."); } } LLVM_DEBUG(dbgs() << "InstRW: Reuse SC " << OldSCIdx << ":" @@ -1118,13 +1116,13 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { for (Record *OldRWDef : SchedClasses[OldSCIdx].InstRWs) { if (OldRWDef->getValueAsDef("SchedModel") == RWModelDef) { assert(!InstDefs.empty()); // Checked at function start. - PrintFatalError - (InstRWDef->getLoc(), - "Overlapping InstRW definition for \"" + - InstDefs.front()->getName() + - "\" also matches previous \"" + - OldRWDef->getValue("Instrs")->getValue()->getAsString() + - "\"."); + PrintError( + InstRWDef->getLoc(), + "Overlapping InstRW definition for \"" + + InstDefs.front()->getName() + "\" also matches previous \"" + + OldRWDef->getValue("Instrs")->getValue()->getAsString() + + "\"."); + PrintFatalNote(OldRWDef->getLoc(), "Previous match was here."); } assert(OldRWDef != InstRWDef && "SchedClass has duplicate InstRW def"); @@ -1210,11 +1208,10 @@ 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); - } - } + for (CodeGenProcModel &ProcModel : ProcModels) + append_range( + ProcModel.UnsupportedFeaturesDefs, + ProcModel.ModelDef->getValueAsListOfDefs("UnsupportedFeatures")); } /// Infer new classes from existing classes. In the process, this may create new @@ -1250,7 +1247,7 @@ void CodeGenSchedModels::inferFromItinClass(Record *ItinClassDef, bool HasMatch = false; for (const Record *Rec : PM.ItinRWDefs) { RecVec Matched = Rec->getValueAsListOfDefs("MatchedItinClasses"); - if (!std::count(Matched.begin(), Matched.end(), ItinClassDef)) + if (!llvm::is_contained(Matched, ItinClassDef)) continue; if (HasMatch) PrintFatalError(Rec->getLoc(), "Duplicate itinerary class " @@ -1283,6 +1280,7 @@ void CodeGenSchedModels::inferFromInstRWs(unsigned SCIdx) { findRWs(Rec->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); unsigned PIdx = getProcModel(Rec->getValueAsDef("SchedModel")).Index; inferFromRW(Writes, Reads, SCIdx, PIdx); // May mutate SchedClasses. + SchedClasses[SCIdx].InstRWProcIndices.insert(PIdx); } } @@ -1315,7 +1313,13 @@ struct PredTransition { SmallVector<PredCheck, 4> PredTerm; SmallVector<SmallVector<unsigned,4>, 16> WriteSequences; SmallVector<SmallVector<unsigned,4>, 16> ReadSequences; - SmallVector<unsigned, 4> ProcIndices; + unsigned ProcIndex = 0; + + PredTransition() = default; + PredTransition(ArrayRef<PredCheck> PT, unsigned ProcId) { + PredTerm.assign(PT.begin(), PT.end()); + ProcIndex = ProcId; + } }; // Encapsulate a set of partially constructed transitions. @@ -1328,17 +1332,18 @@ public: PredTransitions(CodeGenSchedModels &sm): SchedModels(sm) {} - void substituteVariantOperand(const SmallVectorImpl<unsigned> &RWSeq, + bool substituteVariantOperand(const SmallVectorImpl<unsigned> &RWSeq, bool IsRead, unsigned StartIdx); - void substituteVariants(const PredTransition &Trans); + bool substituteVariants(const PredTransition &Trans); #ifndef NDEBUG void dump() const; #endif private: - bool mutuallyExclusive(Record *PredDef, ArrayRef<PredCheck> Term); + bool mutuallyExclusive(Record *PredDef, ArrayRef<Record *> Preds, + ArrayRef<PredCheck> Term); void getIntersectingVariants( const CodeGenSchedRW &SchedRW, unsigned TransIdx, std::vector<TransVariant> &IntersectingVariants); @@ -1357,6 +1362,7 @@ private: // are always checked in the order they are defined in the .td file. Later // conditions implicitly negate any prior condition. bool PredTransitions::mutuallyExclusive(Record *PredDef, + ArrayRef<Record *> Preds, ArrayRef<PredCheck> Term) { for (const PredCheck &PC: Term) { if (PC.Predicate == PredDef) @@ -1367,49 +1373,49 @@ bool PredTransitions::mutuallyExclusive(Record *PredDef, RecVec Variants = SchedRW.TheDef->getValueAsListOfDefs("Variants"); if (any_of(Variants, [PredDef](const Record *R) { return R->getValueAsDef("Predicate") == PredDef; - })) - return true; - } - return false; -} - -static bool hasAliasedVariants(const CodeGenSchedRW &RW, - CodeGenSchedModels &SchedModels) { - if (RW.HasVariants) - return true; - - for (Record *Alias : RW.Aliases) { - const CodeGenSchedRW &AliasRW = - SchedModels.getSchedRW(Alias->getValueAsDef("AliasRW")); - if (AliasRW.HasVariants) + })) { + // To check if PredDef is mutually exclusive with PC we also need to + // check that PC.Predicate is exclusive with all predicates from variant + // we're expanding. Consider following RW sequence with two variants + // (1 & 2), where A, B and C are predicates from corresponding SchedVars: + // + // 1:A/B - 2:C/B + // + // Here C is not mutually exclusive with variant (1), because A doesn't + // exist in variant (2). This means we have possible transitions from A + // to C and from A to B, and fully expanded sequence would look like: + // + // if (A & C) return ...; + // if (A & B) return ...; + // if (B) return ...; + // + // Now let's consider another sequence: + // + // 1:A/B - 2:A/B + // + // Here A in variant (2) is mutually exclusive with variant (1), because + // A also exists in (2). This means A->B transition is impossible and + // expanded sequence would look like: + // + // if (A) return ...; + // if (B) return ...; + if (!count(Preds, PC.Predicate)) + continue; return true; - if (AliasRW.IsSequence) { - IdxVec ExpandedRWs; - SchedModels.expandRWSequence(AliasRW.Index, ExpandedRWs, AliasRW.IsRead); - for (unsigned SI : ExpandedRWs) { - if (hasAliasedVariants(SchedModels.getSchedRW(SI, AliasRW.IsRead), - SchedModels)) - return true; - } } } return false; } -static bool hasVariant(ArrayRef<PredTransition> Transitions, - CodeGenSchedModels &SchedModels) { - for (const PredTransition &PTI : Transitions) { - for (const SmallVectorImpl<unsigned> &WSI : PTI.WriteSequences) - for (unsigned WI : WSI) - if (hasAliasedVariants(SchedModels.getSchedWrite(WI), SchedModels)) - return true; - - for (const SmallVectorImpl<unsigned> &RSI : PTI.ReadSequences) - for (unsigned RI : RSI) - if (hasAliasedVariants(SchedModels.getSchedRead(RI), SchedModels)) - return true; +static std::vector<Record *> getAllPredicates(ArrayRef<TransVariant> Variants, + unsigned ProcId) { + std::vector<Record *> Preds; + for (auto &Variant : Variants) { + if (!Variant.VarOrSeqDef->isSubClassOf("SchedVar")) + continue; + Preds.push_back(Variant.VarOrSeqDef->getValueAsDef("Predicate")); } - return false; + return Preds; } // Populate IntersectingVariants with any variants or aliased sequences of the @@ -1428,12 +1434,14 @@ void PredTransitions::getIntersectingVariants( Record *ModelDef = SchedRW.TheDef->getValueAsDef("SchedModel"); VarProcIdx = SchedModels.getProcModel(ModelDef).Index; } - // Push each variant. Assign TransVecIdx later. - const RecVec VarDefs = SchedRW.TheDef->getValueAsListOfDefs("Variants"); - for (Record *VarDef : VarDefs) - Variants.emplace_back(VarDef, SchedRW.Index, VarProcIdx, 0); - if (VarProcIdx == 0) - GenericRW = true; + if (VarProcIdx == 0 || VarProcIdx == TransVec[TransIdx].ProcIndex) { + // Push each variant. Assign TransVecIdx later. + const RecVec VarDefs = SchedRW.TheDef->getValueAsListOfDefs("Variants"); + for (Record *VarDef : VarDefs) + Variants.emplace_back(VarDef, SchedRW.Index, VarProcIdx, 0); + if (VarProcIdx == 0) + GenericRW = true; + } } for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end(); AI != AE; ++AI) { @@ -1445,6 +1453,17 @@ void PredTransitions::getIntersectingVariants( Record *ModelDef = (*AI)->getValueAsDef("SchedModel"); AliasProcIdx = SchedModels.getProcModel(ModelDef).Index; } + if (AliasProcIdx && AliasProcIdx != TransVec[TransIdx].ProcIndex) + continue; + if (!Variants.empty()) { + const CodeGenProcModel &PM = + *(SchedModels.procModelBegin() + AliasProcIdx); + PrintFatalError((*AI)->getLoc(), + "Multiple variants defined for processor " + + PM.ModelName + + " Ensure only one SchedAlias exists per RW."); + } + const CodeGenSchedRW &AliasRW = SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW")); @@ -1458,29 +1477,17 @@ void PredTransitions::getIntersectingVariants( if (AliasProcIdx == 0) GenericRW = true; } + std::vector<Record *> AllPreds = + getAllPredicates(Variants, TransVec[TransIdx].ProcIndex); for (TransVariant &Variant : Variants) { // Don't expand variants if the processor models don't intersect. // A zero processor index means any processor. - SmallVectorImpl<unsigned> &ProcIndices = TransVec[TransIdx].ProcIndices; - if (ProcIndices[0] && Variant.ProcIdx) { - unsigned Cnt = std::count(ProcIndices.begin(), ProcIndices.end(), - Variant.ProcIdx); - if (!Cnt) - continue; - if (Cnt > 1) { - const CodeGenProcModel &PM = - *(SchedModels.procModelBegin() + Variant.ProcIdx); - PrintFatalError(Variant.VarOrSeqDef->getLoc(), - "Multiple variants defined for processor " + - PM.ModelName + - " Ensure only one SchedAlias exists per RW."); - } - } if (Variant.VarOrSeqDef->isSubClassOf("SchedVar")) { Record *PredDef = Variant.VarOrSeqDef->getValueAsDef("Predicate"); - if (mutuallyExclusive(PredDef, TransVec[TransIdx].PredTerm)) + if (mutuallyExclusive(PredDef, AllPreds, TransVec[TransIdx].PredTerm)) continue; } + if (IntersectingVariants.empty()) { // The first variant builds on the existing transition. Variant.TransVecIdx = TransIdx; @@ -1507,9 +1514,6 @@ pushVariant(const TransVariant &VInfo, bool IsRead) { // If this operand transition is reached through a processor-specific alias, // then the whole transition is specific to this processor. - if (VInfo.ProcIdx != 0) - Trans.ProcIndices.assign(1, VInfo.ProcIdx); - IdxVec SelectedRWs; if (VInfo.VarOrSeqDef->isSubClassOf("SchedVar")) { Record *PredDef = VInfo.VarOrSeqDef->getValueAsDef("Predicate"); @@ -1530,6 +1534,7 @@ pushVariant(const TransVariant &VInfo, bool IsRead) { if (SchedRW.IsVariadic) { unsigned OperIdx = RWSequences.size()-1; // Make N-1 copies of this transition's last sequence. + RWSequences.reserve(RWSequences.size() + SelectedRWs.size() - 1); RWSequences.insert(RWSequences.end(), SelectedRWs.size() - 1, RWSequences[OperIdx]); // Push each of the N elements of the SelectedRWs onto a copy of the last @@ -1543,8 +1548,7 @@ pushVariant(const TransVariant &VInfo, bool IsRead) { ExpandedRWs.push_back(*RWI); else SchedModels.expandRWSequence(*RWI, ExpandedRWs, IsRead); - RWSequences[OperIdx].insert(RWSequences[OperIdx].end(), - ExpandedRWs.begin(), ExpandedRWs.end()); + llvm::append_range(RWSequences[OperIdx], ExpandedRWs); } assert(OperIdx == RWSequences.size() && "missed a sequence"); } @@ -1560,7 +1564,7 @@ pushVariant(const TransVariant &VInfo, bool IsRead) { else SchedModels.expandRWSequence(*RWI, ExpandedRWs, IsRead); } - Seq.insert(Seq.end(), ExpandedRWs.begin(), ExpandedRWs.end()); + llvm::append_range(Seq, ExpandedRWs); } } @@ -1568,9 +1572,9 @@ pushVariant(const TransVariant &VInfo, bool IsRead) { // operand. StartIdx is an index into TransVec where partial results // starts. RWSeq must be applied to all transitions between StartIdx and the end // of TransVec. -void PredTransitions::substituteVariantOperand( - const SmallVectorImpl<unsigned> &RWSeq, bool IsRead, unsigned StartIdx) { - +bool PredTransitions::substituteVariantOperand( + const SmallVectorImpl<unsigned> &RWSeq, bool IsRead, unsigned StartIdx) { + bool Subst = false; // Visit each original RW within the current sequence. for (SmallVectorImpl<unsigned>::const_iterator RWI = RWSeq.begin(), RWE = RWSeq.end(); RWI != RWE; ++RWI) { @@ -1580,27 +1584,25 @@ void PredTransitions::substituteVariantOperand( // revisited (TransEnd must be loop invariant). for (unsigned TransIdx = StartIdx, TransEnd = TransVec.size(); TransIdx != TransEnd; ++TransIdx) { - // In the common case, push RW onto the current operand's sequence. - if (!hasAliasedVariants(SchedRW, SchedModels)) { - if (IsRead) - TransVec[TransIdx].ReadSequences.back().push_back(*RWI); - else - TransVec[TransIdx].WriteSequences.back().push_back(*RWI); - continue; - } // Distribute this partial PredTransition across intersecting variants. // This will push a copies of TransVec[TransIdx] on the back of TransVec. std::vector<TransVariant> IntersectingVariants; getIntersectingVariants(SchedRW, TransIdx, IntersectingVariants); // Now expand each variant on top of its copy of the transition. - for (std::vector<TransVariant>::const_iterator - IVI = IntersectingVariants.begin(), - IVE = IntersectingVariants.end(); - IVI != IVE; ++IVI) { - pushVariant(*IVI, IsRead); + for (const TransVariant &IV : IntersectingVariants) + pushVariant(IV, IsRead); + if (IntersectingVariants.empty()) { + if (IsRead) + TransVec[TransIdx].ReadSequences.back().push_back(*RWI); + else + TransVec[TransIdx].WriteSequences.back().push_back(*RWI); + continue; + } else { + Subst = true; } } } + return Subst; } // For each variant of a Read/Write in Trans, substitute the sequence of @@ -1609,13 +1611,13 @@ void PredTransitions::substituteVariantOperand( // predicates should result in linear growth in the total number variants. // // This is one step in a breadth-first search of nested variants. -void PredTransitions::substituteVariants(const PredTransition &Trans) { +bool PredTransitions::substituteVariants(const PredTransition &Trans) { // Build up a set of partial results starting at the back of // PredTransitions. Remember the first new transition. unsigned StartIdx = TransVec.size(); - TransVec.emplace_back(); - TransVec.back().PredTerm = Trans.PredTerm; - TransVec.back().ProcIndices = Trans.ProcIndices; + bool Subst = false; + assert(Trans.ProcIndex != 0); + TransVec.emplace_back(Trans.PredTerm, Trans.ProcIndex); // Visit each original write sequence. for (SmallVectorImpl<SmallVector<unsigned,4>>::const_iterator @@ -1626,7 +1628,7 @@ void PredTransitions::substituteVariants(const PredTransition &Trans) { TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) { I->WriteSequences.emplace_back(); } - substituteVariantOperand(*WSI, /*IsRead=*/false, StartIdx); + Subst |= substituteVariantOperand(*WSI, /*IsRead=*/false, StartIdx); } // Visit each original read sequence. for (SmallVectorImpl<SmallVector<unsigned,4>>::const_iterator @@ -1637,10 +1639,37 @@ void PredTransitions::substituteVariants(const PredTransition &Trans) { TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) { I->ReadSequences.emplace_back(); } - substituteVariantOperand(*RSI, /*IsRead=*/true, StartIdx); + Subst |= substituteVariantOperand(*RSI, /*IsRead=*/true, StartIdx); } + return Subst; +} + +static void addSequences(CodeGenSchedModels &SchedModels, + const SmallVectorImpl<SmallVector<unsigned, 4>> &Seqs, + IdxVec &Result, bool IsRead) { + for (const auto &S : Seqs) + if (!S.empty()) + Result.push_back(SchedModels.findOrInsertRW(S, IsRead)); } +#ifndef NDEBUG +static void dumpRecVec(const RecVec &RV) { + for (const Record *R : RV) + dbgs() << R->getName() << ", "; +} +#endif + +static void dumpTransition(const CodeGenSchedModels &SchedModels, + const CodeGenSchedClass &FromSC, + const CodeGenSchedTransition &SCTrans, + const RecVec &Preds) { + LLVM_DEBUG(dbgs() << "Adding transition from " << FromSC.Name << "(" + << FromSC.Index << ") to " + << SchedModels.getSchedClass(SCTrans.ToClassIdx).Name << "(" + << SCTrans.ToClassIdx << ") on pred term: ("; + dumpRecVec(Preds); + dbgs() << ") on processor (" << SCTrans.ProcIndex << ")\n"); +} // Create a new SchedClass for each variant found by inferFromRW. Pass static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions, unsigned FromClassIdx, @@ -1649,21 +1678,25 @@ static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions, // requires creating a new SchedClass. for (ArrayRef<PredTransition>::iterator I = LastTransitions.begin(), E = LastTransitions.end(); I != E; ++I) { - IdxVec OperWritesVariant; - transform(I->WriteSequences, std::back_inserter(OperWritesVariant), - [&SchedModels](ArrayRef<unsigned> WS) { - return SchedModels.findOrInsertRW(WS, /*IsRead=*/false); - }); - IdxVec OperReadsVariant; - transform(I->ReadSequences, std::back_inserter(OperReadsVariant), - [&SchedModels](ArrayRef<unsigned> RS) { - return SchedModels.findOrInsertRW(RS, /*IsRead=*/true); - }); + // Variant expansion (substituteVariants) may create unconditional + // transitions. We don't need to build sched classes for them. + if (I->PredTerm.empty()) + continue; + IdxVec OperWritesVariant, OperReadsVariant; + addSequences(SchedModels, I->WriteSequences, OperWritesVariant, false); + addSequences(SchedModels, I->ReadSequences, OperReadsVariant, true); CodeGenSchedTransition SCTrans; + + // Transition should not contain processor indices already assigned to + // InstRWs in this scheduling class. + const CodeGenSchedClass &FromSC = SchedModels.getSchedClass(FromClassIdx); + if (FromSC.InstRWProcIndices.count(I->ProcIndex)) + continue; + SCTrans.ProcIndex = I->ProcIndex; SCTrans.ToClassIdx = - SchedModels.addSchedClass(/*ItinClassDef=*/nullptr, OperWritesVariant, - OperReadsVariant, I->ProcIndices); - SCTrans.ProcIndices.assign(I->ProcIndices.begin(), I->ProcIndices.end()); + SchedModels.addSchedClass(/*ItinClassDef=*/nullptr, OperWritesVariant, + OperReadsVariant, I->ProcIndex); + // The final PredTerm is unique set of predicates guarding the transition. RecVec Preds; transform(I->PredTerm, std::back_inserter(Preds), @@ -1671,12 +1704,36 @@ static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions, return P.Predicate; }); Preds.erase(std::unique(Preds.begin(), Preds.end()), Preds.end()); + dumpTransition(SchedModels, FromSC, SCTrans, Preds); SCTrans.PredTerm = std::move(Preds); SchedModels.getSchedClass(FromClassIdx) .Transitions.push_back(std::move(SCTrans)); } } +std::vector<unsigned> CodeGenSchedModels::getAllProcIndices() const { + std::vector<unsigned> ProcIdVec; + for (const auto &PM : ProcModelMap) + if (PM.second != 0) + ProcIdVec.push_back(PM.second); + // The order of the keys (Record pointers) of ProcModelMap are not stable. + // Sort to stabalize the values. + llvm::sort(ProcIdVec); + return ProcIdVec; +} + +static std::vector<PredTransition> +makePerProcessorTransitions(const PredTransition &Trans, + ArrayRef<unsigned> ProcIndices) { + std::vector<PredTransition> PerCpuTransVec; + for (unsigned ProcId : ProcIndices) { + assert(ProcId != 0); + PerCpuTransVec.push_back(Trans); + PerCpuTransVec.back().ProcIndex = ProcId; + } + return PerCpuTransVec; +} + // Create new SchedClasses for the given ReadWrite list. If any of the // ReadWrites refers to a SchedVariant, create a new SchedClass for each variant // of the ReadWrite list, following Aliases if necessary. @@ -1686,13 +1743,10 @@ void CodeGenSchedModels::inferFromRW(ArrayRef<unsigned> OperWrites, ArrayRef<unsigned> ProcIndices) { LLVM_DEBUG(dbgs() << "INFER RW proc("; dumpIdxVec(ProcIndices); dbgs() << ") "); - // Create a seed transition with an empty PredTerm and the expanded sequences // of SchedWrites for the current SchedClass. std::vector<PredTransition> LastTransitions; LastTransitions.emplace_back(); - LastTransitions.back().ProcIndices.append(ProcIndices.begin(), - ProcIndices.end()); for (unsigned WriteIdx : OperWrites) { IdxVec WriteSeq; @@ -1713,18 +1767,21 @@ void CodeGenSchedModels::inferFromRW(ArrayRef<unsigned> OperWrites, } LLVM_DEBUG(dbgs() << '\n'); + LastTransitions = makePerProcessorTransitions( + LastTransitions[0], llvm::is_contained(ProcIndices, 0) + ? ArrayRef<unsigned>(getAllProcIndices()) + : ProcIndices); // Collect all PredTransitions for individual operands. // Iterate until no variant writes remain. - while (hasVariant(LastTransitions, *this)) { + bool SubstitutedAny; + do { + SubstitutedAny = false; PredTransitions Transitions(*this); for (const PredTransition &Trans : LastTransitions) - Transitions.substituteVariants(Trans); + SubstitutedAny |= Transitions.substituteVariants(Trans); LLVM_DEBUG(Transitions.dump()); LastTransitions.swap(Transitions.TransVec); - } - // If the first transition has no variants, nothing to do. - if (LastTransitions[0].PredTerm.empty()) - return; + } while (SubstitutedAny); // WARNING: We are about to mutate the SchedClasses vector. Do not refer to // OperWrites, OperReads, or ProcIndices after calling inferFromTransitions. @@ -1767,8 +1824,7 @@ void CodeGenSchedModels::verifyProcResourceGroups(CodeGenProcModel &PM) { OtherUnits.begin(), OtherUnits.end()) != CheckUnits.end()) { // CheckUnits and OtherUnits overlap - OtherUnits.insert(OtherUnits.end(), CheckUnits.begin(), - CheckUnits.end()); + llvm::append_range(OtherUnits, CheckUnits); if (!hasSuperGroup(OtherUnits, PM)) { PrintFatalError((PM.ProcResourceDefs[i])->getLoc(), "proc resource group overlaps with " @@ -1990,7 +2046,7 @@ void CodeGenSchedModels::collectItinProcResources(Record *ItinClassDef) { for (RecIter II = PM.ItinRWDefs.begin(), IE = PM.ItinRWDefs.end(); II != IE; ++II) { RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses"); - if (!std::count(Matched.begin(), Matched.end(), ItinClassDef)) + if (!llvm::is_contained(Matched, ItinClassDef)) continue; if (HasMatch) PrintFatalError((*II)->getLoc(), "Duplicate itinerary class " @@ -2191,13 +2247,14 @@ void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const { dbgs().indent(10); } } - dbgs() << "\n ProcIdx: "; dumpIdxVec(ProcIndices); dbgs() << '\n'; + dbgs() << "\n ProcIdx: "; dumpIdxVec(ProcIndices); if (!Transitions.empty()) { dbgs() << "\n Transitions for Proc "; for (const CodeGenSchedTransition &Transition : Transitions) { - dumpIdxVec(Transition.ProcIndices); + dbgs() << Transition.ProcIndex << ", "; } } + dbgs() << '\n'; } void PredTransitions::dump() const { diff --git a/llvm/utils/TableGen/CodeGenSchedule.h b/llvm/utils/TableGen/CodeGenSchedule.h index c487d142d46c..9020447c940b 100644 --- a/llvm/utils/TableGen/CodeGenSchedule.h +++ b/llvm/utils/TableGen/CodeGenSchedule.h @@ -16,10 +16,12 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/SetTheory.h" +#include <map> namespace llvm { @@ -94,7 +96,7 @@ struct CodeGenSchedRW { /// Represent a transition between SchedClasses induced by SchedVariant. struct CodeGenSchedTransition { unsigned ToClassIdx; - IdxVec ProcIndices; + unsigned ProcIndex; RecVec PredTerm; }; @@ -139,6 +141,8 @@ struct CodeGenSchedClass { // Instructions should be ignored by this class because they have been split // off to join another inferred class. RecVec InstRWs; + // InstRWs processor indices. Filled in inferFromInstRWs + DenseSet<unsigned> InstRWProcIndices; CodeGenSchedClass(unsigned Index, std::string Name, Record *ItinClassDef) : Index(Index), Name(std::move(Name)), ItinClassDef(ItinClassDef) {} @@ -358,8 +362,7 @@ public: OpcodeGroup(OpcodeGroup &&Other) = default; void addOpcode(const Record *Opcode) { - assert(std::find(Opcodes.begin(), Opcodes.end(), Opcode) == Opcodes.end() && - "Opcode already in set!"); + assert(!llvm::is_contained(Opcodes, Opcode) && "Opcode already in set!"); Opcodes.push_back(Opcode); } @@ -407,6 +410,8 @@ public: ArrayRef<OpcodeGroup> getGroups() const { return Groups; } }; +using ProcModelMapTy = DenseMap<const Record *, unsigned>; + /// Top level container for machine model data. class CodeGenSchedModels { RecordKeeper &Records; @@ -419,7 +424,6 @@ class CodeGenSchedModels { std::vector<CodeGenProcModel> ProcModels; // Map Processor's MachineModel or ProcItin to a CodeGenProcModel index. - using ProcModelMapTy = DenseMap<Record*, unsigned>; ProcModelMapTy ProcModelMap; // Per-operand SchedReadWrite types. @@ -441,6 +445,7 @@ class CodeGenSchedModels { InstClassMapTy InstrClassMap; std::vector<STIPredicateFunction> STIPredicates; + std::vector<unsigned> getAllProcIndices() const; public: CodeGenSchedModels(RecordKeeper& RK, const CodeGenTarget &TGT); diff --git a/llvm/utils/TableGen/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp index 891a08ea590e..8f6d212df5ec 100644 --- a/llvm/utils/TableGen/CodeGenTarget.cpp +++ b/llvm/utils/TableGen/CodeGenTarget.cpp @@ -76,6 +76,7 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::f128: return "MVT::f128"; case MVT::ppcf128: return "MVT::ppcf128"; case MVT::x86mmx: return "MVT::x86mmx"; + case MVT::x86amx: return "MVT::x86amx"; case MVT::Glue: return "MVT::Glue"; case MVT::isVoid: return "MVT::isVoid"; case MVT::v1i1: return "MVT::v1i1"; @@ -86,6 +87,7 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::v32i1: return "MVT::v32i1"; case MVT::v64i1: return "MVT::v64i1"; case MVT::v128i1: return "MVT::v128i1"; + case MVT::v256i1: return "MVT::v256i1"; case MVT::v512i1: return "MVT::v512i1"; case MVT::v1024i1: return "MVT::v1024i1"; case MVT::v1i8: return "MVT::v1i8"; @@ -126,6 +128,9 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::v8i64: return "MVT::v8i64"; case MVT::v16i64: return "MVT::v16i64"; case MVT::v32i64: return "MVT::v32i64"; + case MVT::v64i64: return "MVT::v64i64"; + case MVT::v128i64: return "MVT::v128i64"; + case MVT::v256i64: return "MVT::v256i64"; case MVT::v1i128: return "MVT::v1i128"; case MVT::v2f16: return "MVT::v2f16"; case MVT::v3f16: return "MVT::v3f16"; @@ -163,6 +168,9 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::v8f64: return "MVT::v8f64"; case MVT::v16f64: return "MVT::v16f64"; case MVT::v32f64: return "MVT::v32f64"; + case MVT::v64f64: return "MVT::v64f64"; + case MVT::v128f64: return "MVT::v128f64"; + case MVT::v256f64: return "MVT::v256f64"; case MVT::nxv1i1: return "MVT::nxv1i1"; case MVT::nxv2i1: return "MVT::nxv2i1"; case MVT::nxv4i1: return "MVT::nxv4i1"; @@ -204,21 +212,22 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::nxv2bf16: return "MVT::nxv2bf16"; case MVT::nxv4bf16: return "MVT::nxv4bf16"; case MVT::nxv8bf16: return "MVT::nxv8bf16"; - case MVT::nxv1f32: return "MVT::nxv1f32"; - case MVT::nxv2f32: return "MVT::nxv2f32"; - case MVT::nxv4f32: return "MVT::nxv4f32"; - case MVT::nxv8f32: return "MVT::nxv8f32"; - case MVT::nxv16f32: return "MVT::nxv16f32"; - case MVT::nxv1f64: return "MVT::nxv1f64"; - case MVT::nxv2f64: return "MVT::nxv2f64"; - case MVT::nxv4f64: return "MVT::nxv4f64"; - case MVT::nxv8f64: return "MVT::nxv8f64"; - case MVT::token: return "MVT::token"; - case MVT::Metadata: return "MVT::Metadata"; - case MVT::iPTR: return "MVT::iPTR"; - case MVT::iPTRAny: return "MVT::iPTRAny"; - case MVT::Untyped: return "MVT::Untyped"; - case MVT::exnref: return "MVT::exnref"; + case MVT::nxv1f32: return "MVT::nxv1f32"; + case MVT::nxv2f32: return "MVT::nxv2f32"; + case MVT::nxv4f32: return "MVT::nxv4f32"; + case MVT::nxv8f32: return "MVT::nxv8f32"; + case MVT::nxv16f32: return "MVT::nxv16f32"; + case MVT::nxv1f64: return "MVT::nxv1f64"; + case MVT::nxv2f64: return "MVT::nxv2f64"; + case MVT::nxv4f64: return "MVT::nxv4f64"; + case MVT::nxv8f64: return "MVT::nxv8f64"; + case MVT::token: return "MVT::token"; + case MVT::Metadata: return "MVT::Metadata"; + case MVT::iPTR: return "MVT::iPTR"; + case MVT::iPTRAny: return "MVT::iPTRAny"; + case MVT::Untyped: return "MVT::Untyped"; + case MVT::funcref: return "MVT::funcref"; + case MVT::externref: return "MVT::externref"; default: llvm_unreachable("ILLEGAL VALUE TYPE!"); } } @@ -251,19 +260,27 @@ CodeGenTarget::CodeGenTarget(RecordKeeper &records) CodeGenTarget::~CodeGenTarget() { } -const StringRef CodeGenTarget::getName() const { - return TargetRec->getName(); -} +StringRef CodeGenTarget::getName() const { return TargetRec->getName(); } +/// getInstNamespace - Find and return the target machine's instruction +/// namespace. The namespace is cached because it is requested multiple times. StringRef CodeGenTarget::getInstNamespace() const { - 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") - return Inst->Namespace; + if (InstNamespace.empty()) { + for (const CodeGenInstruction *Inst : getInstructionsByEnumValue()) { + // We are not interested in the "TargetOpcode" namespace. + if (Inst->Namespace != "TargetOpcode") { + InstNamespace = Inst->Namespace; + break; + } + } } - return ""; + return InstNamespace; +} + +StringRef CodeGenTarget::getRegNamespace() const { + auto &RegClasses = RegBank->getRegClasses(); + return RegClasses.size() > 0 ? RegClasses.front().Namespace : ""; } Record *CodeGenTarget::getInstructionSet() const { @@ -324,7 +341,8 @@ CodeGenRegBank &CodeGenTarget::getRegBank() const { Optional<CodeGenRegisterClass *> CodeGenTarget::getSuperRegForSubReg(const ValueTypeByHwMode &ValueTy, CodeGenRegBank &RegBank, - const CodeGenSubRegIndex *SubIdx) const { + const CodeGenSubRegIndex *SubIdx, + bool MustBeAllocatable) const { std::vector<CodeGenRegisterClass *> Candidates; auto &RegClasses = RegBank.getRegClasses(); @@ -337,10 +355,11 @@ CodeGenTarget::getSuperRegForSubReg(const ValueTypeByHwMode &ValueTy, continue; // We have a class. Check if it supports this value type. - if (llvm::none_of(SubClassWithSubReg->VTs, - [&ValueTy](const ValueTypeByHwMode &ClassVT) { - return ClassVT == ValueTy; - })) + if (!llvm::is_contained(SubClassWithSubReg->VTs, ValueTy)) + continue; + + // If necessary, check that it is allocatable. + if (MustBeAllocatable && !SubClassWithSubReg->Allocatable) continue; // We have a register class which supports both the value type and @@ -376,11 +395,7 @@ void CodeGenTarget::ReadRegAltNameIndices() const { /// getRegisterByName - If there is a register with the specific AsmName, /// return it. const CodeGenRegister *CodeGenTarget::getRegisterByName(StringRef Name) const { - const StringMap<CodeGenRegister*> &Regs = getRegBank().getRegistersByName(); - StringMap<CodeGenRegister*>::const_iterator I = Regs.find(Name); - if (I == Regs.end()) - return nullptr; - return I->second; + return getRegBank().getRegistersByName().lookup(Name); } std::vector<ValueTypeByHwMode> CodeGenTarget::getRegisterVTs(Record *R) @@ -390,7 +405,7 @@ std::vector<ValueTypeByHwMode> CodeGenTarget::getRegisterVTs(Record *R) for (const auto &RC : getRegBank().getRegClasses()) { if (RC.contains(Reg)) { ArrayRef<ValueTypeByHwMode> InVTs = RC.getValueTypes(); - Result.insert(Result.end(), InVTs.begin(), InVTs.end()); + llvm::append_range(Result, InVTs); } } @@ -403,7 +418,7 @@ std::vector<ValueTypeByHwMode> CodeGenTarget::getRegisterVTs(Record *R) void CodeGenTarget::ReadLegalValueTypes() const { for (const auto &RC : getRegBank().getRegClasses()) - LegalValueTypes.insert(LegalValueTypes.end(), RC.VTs.begin(), RC.VTs.end()); + llvm::append_range(LegalValueTypes, RC.VTs); // Remove duplicates. llvm::sort(LegalValueTypes); @@ -419,8 +434,6 @@ CodeGenSchedModels &CodeGenTarget::getSchedModels() const { } void CodeGenTarget::ReadInstructions() const { - NamedRegionTimer T("Read Instructions", "Time spent reading instructions", - "CodeGenTarget", "CodeGenTarget", TimeRegions); std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction"); if (Insts.size() <= 2) PrintFatalError("No 'Instruction' subclasses defined!"); @@ -599,12 +612,19 @@ ComplexPattern::ComplexPattern(Record *R) { //===----------------------------------------------------------------------===// CodeGenIntrinsicTable::CodeGenIntrinsicTable(const RecordKeeper &RC) { - std::vector<Record*> Defs = RC.getAllDerivedDefinitions("Intrinsic"); + std::vector<Record *> IntrProperties = + RC.getAllDerivedDefinitions("IntrinsicProperty"); + std::vector<Record *> DefaultProperties; + for (Record *Rec : IntrProperties) + if (Rec->getValueAsBit("IsDefault")) + DefaultProperties.push_back(Rec); + + std::vector<Record *> Defs = RC.getAllDerivedDefinitions("Intrinsic"); Intrinsics.reserve(Defs.size()); for (unsigned I = 0, e = Defs.size(); I != e; ++I) - Intrinsics.push_back(CodeGenIntrinsic(Defs[I])); + Intrinsics.push_back(CodeGenIntrinsic(Defs[I], DefaultProperties)); llvm::sort(Intrinsics, [](const CodeGenIntrinsic &LHS, const CodeGenIntrinsic &RHS) { @@ -620,7 +640,8 @@ CodeGenIntrinsicTable::CodeGenIntrinsicTable(const RecordKeeper &RC) { Targets.back().Count = Intrinsics.size() - Targets.back().Offset; } -CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { +CodeGenIntrinsic::CodeGenIntrinsic(Record *R, + std::vector<Record *> DefaultProperties) { TheDef = R; std::string DefName = std::string(R->getName()); ArrayRef<SMLoc> DefLoc = R->getLoc(); @@ -773,70 +794,12 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { assert(Property->isSubClassOf("IntrinsicProperty") && "Expected a property!"); - if (Property->getName() == "IntrNoMem") - ModRef = NoMem; - else if (Property->getName() == "IntrReadMem") - 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) | MR_ArgMem); - else if (Property->getName() == "IntrInaccessibleMemOnly") - ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_InaccessibleMem); - else if (Property->getName() == "IntrInaccessibleMemOrArgMemOnly") - ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_ArgMem | - MR_InaccessibleMem); - else if (Property->getName() == "Commutative") - isCommutative = true; - else if (Property->getName() == "Throws") - canThrow = true; - else if (Property->getName() == "IntrNoDuplicate") - isNoDuplicate = true; - else if (Property->getName() == "IntrConvergent") - isConvergent = true; - else if (Property->getName() == "IntrNoReturn") - isNoReturn = true; - else if (Property->getName() == "IntrNoSync") - isNoSync = true; - else if (Property->getName() == "IntrNoFree") - isNoFree = true; - else if (Property->getName() == "IntrWillReturn") - isWillReturn = true; - else if (Property->getName() == "IntrCold") - isCold = true; - else if (Property->getName() == "IntrSpeculatable") - isSpeculatable = true; - else if (Property->getName() == "IntrHasSideEffects") - hasSideEffects = true; - else if (Property->isSubClassOf("NoCapture")) { - unsigned ArgNo = Property->getValueAsInt("ArgNo"); - ArgumentAttributes.emplace_back(ArgNo, NoCapture, 0); - } else if (Property->isSubClassOf("NoAlias")) { - unsigned ArgNo = Property->getValueAsInt("ArgNo"); - ArgumentAttributes.emplace_back(ArgNo, NoAlias, 0); - } else if (Property->isSubClassOf("Returned")) { - unsigned ArgNo = Property->getValueAsInt("ArgNo"); - ArgumentAttributes.emplace_back(ArgNo, Returned, 0); - } else if (Property->isSubClassOf("ReadOnly")) { - unsigned ArgNo = Property->getValueAsInt("ArgNo"); - ArgumentAttributes.emplace_back(ArgNo, ReadOnly, 0); - } else if (Property->isSubClassOf("WriteOnly")) { - unsigned ArgNo = Property->getValueAsInt("ArgNo"); - ArgumentAttributes.emplace_back(ArgNo, WriteOnly, 0); - } else if (Property->isSubClassOf("ReadNone")) { - unsigned ArgNo = Property->getValueAsInt("ArgNo"); - ArgumentAttributes.emplace_back(ArgNo, ReadNone, 0); - } else if (Property->isSubClassOf("ImmArg")) { - unsigned ArgNo = Property->getValueAsInt("ArgNo"); - ArgumentAttributes.emplace_back(ArgNo, ImmArg, 0); - } else if (Property->isSubClassOf("Align")) { - unsigned ArgNo = Property->getValueAsInt("ArgNo"); - uint64_t Align = Property->getValueAsInt("Align"); - ArgumentAttributes.emplace_back(ArgNo, Alignment, Align); - } else - llvm_unreachable("Unknown property!"); + setProperty(Property); } + // Set default properties to true. + setDefaultProperties(R, DefaultProperties); + // Also record the SDPatternOperator Properties. Properties = parseSDPatternOperatorProperties(R); @@ -844,6 +807,92 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { llvm::sort(ArgumentAttributes); } +void CodeGenIntrinsic::setDefaultProperties( + Record *R, std::vector<Record *> DefaultProperties) { + // opt-out of using default attributes. + if (R->getValueAsBit("DisableDefaultAttributes")) + return; + + for (Record *Rec : DefaultProperties) + setProperty(Rec); +} + +void CodeGenIntrinsic::setProperty(Record *R) { + if (R->getName() == "IntrNoMem") + ModRef = NoMem; + else if (R->getName() == "IntrReadMem") { + if (!(ModRef & MR_Ref)) + PrintFatalError(TheDef->getLoc(), + Twine("IntrReadMem cannot be used after IntrNoMem or " + "IntrWriteMem. Default is ReadWrite")); + ModRef = ModRefBehavior(ModRef & ~MR_Mod); + } else if (R->getName() == "IntrWriteMem") { + if (!(ModRef & MR_Mod)) + PrintFatalError(TheDef->getLoc(), + Twine("IntrWriteMem cannot be used after IntrNoMem or " + "IntrReadMem. Default is ReadWrite")); + ModRef = ModRefBehavior(ModRef & ~MR_Ref); + } else if (R->getName() == "IntrArgMemOnly") + ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_ArgMem); + else if (R->getName() == "IntrInaccessibleMemOnly") + ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_InaccessibleMem); + else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly") + ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_ArgMem | + MR_InaccessibleMem); + else if (R->getName() == "Commutative") + isCommutative = true; + else if (R->getName() == "Throws") + canThrow = true; + else if (R->getName() == "IntrNoDuplicate") + isNoDuplicate = true; + else if (R->getName() == "IntrConvergent") + isConvergent = true; + else if (R->getName() == "IntrNoReturn") + isNoReturn = true; + else if (R->getName() == "IntrNoSync") + isNoSync = true; + else if (R->getName() == "IntrNoFree") + isNoFree = true; + else if (R->getName() == "IntrWillReturn") + isWillReturn = !isNoReturn; + else if (R->getName() == "IntrCold") + isCold = true; + else if (R->getName() == "IntrSpeculatable") + isSpeculatable = true; + else if (R->getName() == "IntrHasSideEffects") + hasSideEffects = true; + else if (R->isSubClassOf("NoCapture")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + ArgumentAttributes.emplace_back(ArgNo, NoCapture, 0); + } else if (R->isSubClassOf("NoAlias")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + ArgumentAttributes.emplace_back(ArgNo, NoAlias, 0); + } else if (R->isSubClassOf("NoUndef")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + ArgumentAttributes.emplace_back(ArgNo, NoUndef, 0); + } else if (R->isSubClassOf("Returned")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + ArgumentAttributes.emplace_back(ArgNo, Returned, 0); + } else if (R->isSubClassOf("ReadOnly")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + ArgumentAttributes.emplace_back(ArgNo, ReadOnly, 0); + } else if (R->isSubClassOf("WriteOnly")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + ArgumentAttributes.emplace_back(ArgNo, WriteOnly, 0); + } else if (R->isSubClassOf("ReadNone")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + ArgumentAttributes.emplace_back(ArgNo, ReadNone, 0); + } else if (R->isSubClassOf("ImmArg")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + ArgumentAttributes.emplace_back(ArgNo, ImmArg, 0); + } else if (R->isSubClassOf("Align")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + uint64_t Align = R->getValueAsInt("Align"); + ArgumentAttributes.emplace_back(ArgNo, Alignment, Align); + } else + llvm_unreachable("Unknown property!"); +} + bool CodeGenIntrinsic::isParamAPointer(unsigned ParamIdx) const { if (ParamIdx >= IS.ParamVTs.size()) return false; diff --git a/llvm/utils/TableGen/CodeGenTarget.h b/llvm/utils/TableGen/CodeGenTarget.h index 6c89f34c50ec..9de9b512f74f 100644 --- a/llvm/utils/TableGen/CodeGenTarget.h +++ b/llvm/utils/TableGen/CodeGenTarget.h @@ -60,6 +60,7 @@ class CodeGenTarget { mutable std::unique_ptr<CodeGenSchedModels> SchedModels; + mutable StringRef InstNamespace; mutable std::vector<const CodeGenInstruction*> InstrsByEnum; mutable unsigned NumPseudoInstructions = 0; public: @@ -67,12 +68,15 @@ public: ~CodeGenTarget(); Record *getTargetRecord() const { return TargetRec; } - const StringRef getName() const; + StringRef getName() const; /// getInstNamespace - Return the target-specific instruction namespace. /// StringRef getInstNamespace() const; + /// getRegNamespace - Return the target-specific register namespace. + StringRef getRegNamespace() const; + /// getInstructionSet - Return the InstructionSet object. /// Record *getInstructionSet() const; @@ -107,7 +111,8 @@ public: /// covers \p SubIdx if it exists. Optional<CodeGenRegisterClass *> getSuperRegForSubReg(const ValueTypeByHwMode &Ty, CodeGenRegBank &RegBank, - const CodeGenSubRegIndex *SubIdx) const; + const CodeGenSubRegIndex *SubIdx, + bool MustBeAllocatable = false) const; /// getRegisterByName - If there is a register with the specific AsmName, /// return it. diff --git a/llvm/utils/TableGen/DAGISelEmitter.cpp b/llvm/utils/TableGen/DAGISelEmitter.cpp index d8e78ce55c7b..32ed0bf98743 100644 --- a/llvm/utils/TableGen/DAGISelEmitter.cpp +++ b/llvm/utils/TableGen/DAGISelEmitter.cpp @@ -23,9 +23,10 @@ namespace { /// DAGISelEmitter - The top-level class which coordinates construction /// and emission of the instruction selector. class DAGISelEmitter { + RecordKeeper &Records; // Just so we can get at the timing functions. CodeGenDAGPatterns CGP; public: - explicit DAGISelEmitter(RecordKeeper &R) : CGP(R) {} + explicit DAGISelEmitter(RecordKeeper &R) : Records(R), CGP(R) {} void run(raw_ostream &OS); }; } // End anonymous namespace @@ -150,6 +151,7 @@ void DAGISelEmitter::run(raw_ostream &OS) { }); // Add all the patterns to a temporary list so we can sort them. + Records.startTimer("Sort patterns"); std::vector<const PatternToMatch*> Patterns; for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(), E = CGP.ptm_end(); I != E; ++I) @@ -157,11 +159,10 @@ void DAGISelEmitter::run(raw_ostream &OS) { // We want to process the matches in order of minimal cost. Sort the patterns // so the least cost one is at the start. - std::stable_sort(Patterns.begin(), Patterns.end(), - PatternSortingPredicate(CGP)); - + llvm::stable_sort(Patterns, PatternSortingPredicate(CGP)); // Convert each variant of each pattern into a Matcher. + Records.startTimer("Convert to matchers"); std::vector<Matcher*> PatternMatchers; for (unsigned i = 0, e = Patterns.size(); i != e; ++i) { for (unsigned Variant = 0; ; ++Variant) { @@ -175,14 +176,19 @@ void DAGISelEmitter::run(raw_ostream &OS) { std::unique_ptr<Matcher> TheMatcher = std::make_unique<ScopeMatcher>(PatternMatchers); + Records.startTimer("Optimize matchers"); OptimizeMatcher(TheMatcher, CGP); + //Matcher->dump(); + + Records.startTimer("Emit matcher table"); EmitMatcherTable(TheMatcher.get(), CGP, OS); } namespace llvm { void EmitDAGISel(RecordKeeper &RK, raw_ostream &OS) { + RK.startTimer("Parse patterns"); DAGISelEmitter(RK).run(OS); } diff --git a/llvm/utils/TableGen/DAGISelMatcher.h b/llvm/utils/TableGen/DAGISelMatcher.h index 223513fc8d38..ff9a0cb335d1 100644 --- a/llvm/utils/TableGen/DAGISelMatcher.h +++ b/llvm/utils/TableGen/DAGISelMatcher.h @@ -31,7 +31,7 @@ Matcher *ConvertPatternToMatcher(const PatternToMatch &Pattern,unsigned Variant, const CodeGenDAGPatterns &CGP); void OptimizeMatcher(std::unique_ptr<Matcher> &Matcher, const CodeGenDAGPatterns &CGP); -void EmitMatcherTable(const Matcher *Matcher, const CodeGenDAGPatterns &CGP, +void EmitMatcherTable(Matcher *Matcher, const CodeGenDAGPatterns &CGP, raw_ostream &OS); @@ -41,6 +41,7 @@ class Matcher { // The next matcher node that is executed after this one. Null if this is the // last stage of a match. std::unique_ptr<Matcher> Next; + size_t Size; // Size in bytes of matcher and all its children (if any). virtual void anchor(); public: enum KindTy { @@ -85,7 +86,10 @@ public: EmitNode, // Create a DAG node EmitNodeXForm, // Run a SDNodeXForm CompleteMatch, // Finish a match and update the results. - MorphNodeTo // Build a node, finish a match and update results. + MorphNodeTo, // Build a node, finish a match and update results. + + // Highest enum value; watch out when adding more. + HighestKind = MorphNodeTo }; const KindTy Kind; @@ -94,6 +98,8 @@ protected: public: virtual ~Matcher() {} + unsigned getSize() const { return Size; } + void setSize(unsigned sz) { Size = sz; } KindTy getKind() const { return Kind; } Matcher *getNext() { return Next.get(); } @@ -700,7 +706,7 @@ public: const ComplexPattern &getPattern() const { return Pattern; } unsigned getMatchNumber() const { return MatchNumber; } - const std::string getName() const { return Name; } + std::string getName() const { return Name; } unsigned getFirstResult() const { return FirstResult; } static bool classof(const Matcher *N) { @@ -757,8 +763,8 @@ private: } }; -/// CheckImmAllOnesVMatcher - This check if the current node is an build vector -/// of all ones. +/// CheckImmAllOnesVMatcher - This checks if the current node is a build_vector +/// or splat_vector of all ones. class CheckImmAllOnesVMatcher : public Matcher { public: CheckImmAllOnesVMatcher() : Matcher(CheckImmAllOnesV) {} @@ -773,8 +779,8 @@ private: bool isContradictoryImpl(const Matcher *M) const override; }; -/// CheckImmAllZerosVMatcher - This check if the current node is an build vector -/// of all zeros. +/// CheckImmAllZerosVMatcher - This checks if the current node is a +/// build_vector or splat_vector of all zeros. class CheckImmAllZerosVMatcher : public Matcher { public: CheckImmAllZerosVMatcher() : Matcher(CheckImmAllZerosV) {} diff --git a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp index d9ec14aab8a8..03528a46aea7 100644 --- a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp +++ b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -23,6 +23,7 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" + using namespace llvm; enum { @@ -47,6 +48,8 @@ namespace { class MatcherTableEmitter { const CodeGenDAGPatterns &CGP; + SmallVector<unsigned, Matcher::HighestKind+1> OpcodeCounts; + DenseMap<TreePattern *, unsigned> NodePredicateMap; std::vector<TreePredicateFn> NodePredicates; std::vector<TreePredicateFn> NodePredicatesWithOperands; @@ -79,12 +82,15 @@ class MatcherTableEmitter { } public: - MatcherTableEmitter(const CodeGenDAGPatterns &cgp) - : CGP(cgp) {} + MatcherTableEmitter(const CodeGenDAGPatterns &cgp) : CGP(cgp) { + OpcodeCounts.assign(Matcher::HighestKind+1, 0); + } - unsigned EmitMatcherList(const Matcher *N, unsigned Indent, + unsigned EmitMatcherList(const Matcher *N, const unsigned Indent, unsigned StartIdx, raw_ostream &OS); + unsigned SizeMatcherList(Matcher *N, raw_ostream &OS); + void EmitPredicateFunctions(raw_ostream &OS); void EmitHistogram(const Matcher *N, raw_ostream &OS); @@ -95,7 +101,9 @@ private: void EmitNodePredicatesFunction(const std::vector<TreePredicateFn> &Preds, StringRef Decl, raw_ostream &OS); - unsigned EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, + unsigned SizeMatcher(Matcher *N, raw_ostream &OS); + + unsigned EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx, raw_ostream &OS); unsigned getNodePredicate(TreePredicateFn Pred) { @@ -165,7 +173,7 @@ static std::string GetPatFromTreePatternNode(const TreePatternNode *N) { return str; } -static unsigned GetVBRSize(unsigned Val) { +static size_t GetVBRSize(unsigned Val) { if (Val <= 127) return 1; unsigned NumBytes = 0; @@ -219,6 +227,78 @@ static std::string getIncludePath(const Record *R) { return str; } +/// This function traverses the matcher tree and sizes all the nodes +/// that are children of the three kinds of nodes that have them. +unsigned MatcherTableEmitter:: +SizeMatcherList(Matcher *N, raw_ostream &OS) { + unsigned Size = 0; + while (N) { + Size += SizeMatcher(N, OS); + N = N->getNext(); + } + return Size; +} + +/// This function sizes the children of the three kinds of nodes that +/// have them. It does so by using special cases for those three +/// nodes, but sharing the code in EmitMatcher() for the other kinds. +unsigned MatcherTableEmitter:: +SizeMatcher(Matcher *N, raw_ostream &OS) { + unsigned Idx = 0; + + ++OpcodeCounts[N->getKind()]; + switch (N->getKind()) { + // The Scope matcher has its kind, a series of child size + child, + // and a trailing zero. + case Matcher::Scope: { + ScopeMatcher *SM = cast<ScopeMatcher>(N); + assert(SM->getNext() == nullptr && "Scope matcher should not have next"); + unsigned Size = 1; // Count the kind. + for (unsigned i = 0, e = SM->getNumChildren(); i != e; ++i) { + const size_t ChildSize = SizeMatcherList(SM->getChild(i), OS); + assert(ChildSize != 0 && "Matcher cannot have child of size 0"); + SM->getChild(i)->setSize(ChildSize); + Size += GetVBRSize(ChildSize) + ChildSize; // Count VBR and child size. + } + ++Size; // Count the zero sentinel. + return Size; + } + + // SwitchOpcode and SwitchType have their kind, a series of child size + + // opcode/type + child, and a trailing zero. + case Matcher::SwitchOpcode: + case Matcher::SwitchType: { + unsigned Size = 1; // Count the kind. + unsigned NumCases; + if (const SwitchOpcodeMatcher *SOM = dyn_cast<SwitchOpcodeMatcher>(N)) + NumCases = SOM->getNumCases(); + else + NumCases = cast<SwitchTypeMatcher>(N)->getNumCases(); + for (unsigned i = 0, e = NumCases; i != e; ++i) { + Matcher *Child; + if (SwitchOpcodeMatcher *SOM = dyn_cast<SwitchOpcodeMatcher>(N)) { + Child = SOM->getCaseMatcher(i); + Size += 2; // Count the child's opcode. + } else { + Child = cast<SwitchTypeMatcher>(N)->getCaseMatcher(i); + ++Size; // Count the child's type. + } + const size_t ChildSize = SizeMatcherList(Child, OS); + assert(ChildSize != 0 && "Matcher cannot have child of size 0"); + Child->setSize(ChildSize); + Size += GetVBRSize(ChildSize) + ChildSize; // Count VBR and child size. + } + ++Size; // Count the zero sentinel. + return Size; + } + + default: + // Employ the matcher emitter to size other matchers. + return EmitMatcher(N, 0, Idx, OS); + } + llvm_unreachable("Unreachable"); +} + static void BeginEmitFunction(raw_ostream &OS, StringRef RetType, StringRef Decl, bool AddOverride) { OS << "#ifdef GET_DAGISEL_DECL\n"; @@ -250,7 +330,7 @@ void MatcherTableEmitter::EmitPatternMatchTable(raw_ostream &OS) { BeginEmitFunction(OS, "StringRef", "getPatternForIndex(unsigned Index)", true/*AddOverride*/); OS << "{\n"; - OS << "static const char * PATTERN_MATCH_TABLE[] = {\n"; + OS << "static const char *PATTERN_MATCH_TABLE[] = {\n"; for (const auto &It : VecPatterns) { OS << "\"" << It.first << "\",\n"; @@ -264,7 +344,7 @@ void MatcherTableEmitter::EmitPatternMatchTable(raw_ostream &OS) { BeginEmitFunction(OS, "StringRef", "getIncludePathForIndex(unsigned Index)", true/*AddOverride*/); OS << "{\n"; - OS << "static const char * INCLUDE_PATH_TABLE[] = {\n"; + OS << "static const char *INCLUDE_PATH_TABLE[] = {\n"; for (const auto &It : VecIncludeStrings) { OS << "\"" << It << "\",\n"; @@ -279,19 +359,16 @@ void MatcherTableEmitter::EmitPatternMatchTable(raw_ostream &OS) { /// EmitMatcher - Emit bytes for the specified matcher and return /// the number of bytes emitted. unsigned MatcherTableEmitter:: -EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, +EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx, raw_ostream &OS) { OS.indent(Indent); switch (N->getKind()) { case Matcher::Scope: { const ScopeMatcher *SM = cast<ScopeMatcher>(N); - assert(SM->getNext() == nullptr && "Shouldn't have next after scope"); - unsigned StartIdx = CurrentIdx; // Emit all of the children. - SmallString<128> TmpBuf; for (unsigned i = 0, e = SM->getNumChildren(); i != e; ++i) { if (i == 0) { OS << "OPC_Scope, "; @@ -304,34 +381,21 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, OS.indent(Indent); } - // We need to encode the child and the offset of the failure code before - // emitting either of them. Handle this by buffering the output into a - // string while we get the size. Unfortunately, the offset of the - // children depends on the VBR size of the child, so for large children we - // have to iterate a bit. - unsigned ChildSize = 0; - unsigned VBRSize = 0; - do { - VBRSize = GetVBRSize(ChildSize); - - TmpBuf.clear(); - raw_svector_ostream OS(TmpBuf); - ChildSize = EmitMatcherList(SM->getChild(i), Indent+1, - CurrentIdx+VBRSize, OS); - } while (GetVBRSize(ChildSize) != VBRSize); - - assert(ChildSize != 0 && "Should not have a zero-sized child!"); - - CurrentIdx += EmitVBRValue(ChildSize, OS); + size_t ChildSize = SM->getChild(i)->getSize(); + size_t VBRSize = GetVBRSize(ChildSize); + EmitVBRValue(ChildSize, OS); if (!OmitComments) { - OS << "/*->" << CurrentIdx+ChildSize << "*/"; - + OS << "/*->" << CurrentIdx + VBRSize + ChildSize << "*/"; if (i == 0) OS << " // " << SM->getNumChildren() << " children in Scope"; } + OS << '\n'; - OS << '\n' << TmpBuf; - CurrentIdx += ChildSize; + ChildSize = EmitMatcherList(SM->getChild(i), Indent+1, + CurrentIdx + VBRSize, OS); + assert(ChildSize == SM->getChild(i)->getSize() && + "Emitted child size does not match calculated size"); + CurrentIdx += VBRSize + ChildSize; } // Emit a zero as a sentinel indicating end of 'Scope'. @@ -450,7 +514,6 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, ++CurrentIdx; // For each case we emit the size, then the opcode, then the matcher. - SmallString<128> TmpBuf; for (unsigned i = 0, e = NumCases; i != e; ++i) { const Matcher *Child; unsigned IdxSize; @@ -462,24 +525,6 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, IdxSize = 1; // size of type in table is 1 byte. } - // We need to encode the opcode and the offset of the case code before - // emitting the case code. Handle this by buffering the output into a - // string while we get the size. Unfortunately, the offset of the - // children depends on the VBR size of the child, so for large children we - // have to iterate a bit. - unsigned ChildSize = 0; - unsigned VBRSize = 0; - do { - VBRSize = GetVBRSize(ChildSize); - - TmpBuf.clear(); - raw_svector_ostream OS(TmpBuf); - ChildSize = EmitMatcherList(Child, Indent+1, CurrentIdx+VBRSize+IdxSize, - OS); - } while (GetVBRSize(ChildSize) != VBRSize); - - assert(ChildSize != 0 && "Should not have a zero-sized child!"); - if (i != 0) { if (!OmitComments) OS << "/*" << format_decimal(CurrentIdx, IndexWidth) << "*/"; @@ -489,20 +534,19 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, "/*SwitchOpcode*/ " : "/*SwitchType*/ "); } - // Emit the VBR. - CurrentIdx += EmitVBRValue(ChildSize, OS); - + size_t ChildSize = Child->getSize(); + CurrentIdx += EmitVBRValue(ChildSize, OS) + IdxSize; if (const SwitchOpcodeMatcher *SOM = dyn_cast<SwitchOpcodeMatcher>(N)) OS << "TARGET_VAL(" << SOM->getCaseOpcode(i).getEnumName() << "),"; else OS << getEnumName(cast<SwitchTypeMatcher>(N)->getCaseType(i)) << ','; - - CurrentIdx += IdxSize; - if (!OmitComments) - OS << "// ->" << CurrentIdx+ChildSize; + OS << "// ->" << CurrentIdx + ChildSize; OS << '\n'; - OS << TmpBuf; + + ChildSize = EmitMatcherList(Child, Indent+1, CurrentIdx, OS); + assert(ChildSize == Child->getSize() && + "Emitted child size does not match calculated size"); CurrentIdx += ChildSize; } @@ -515,8 +559,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, " // EndSwitchOpcode" : " // EndSwitchType"); OS << '\n'; - ++CurrentIdx; - return CurrentIdx-StartIdx; + return CurrentIdx - StartIdx + 1; } case Matcher::CheckType: @@ -810,9 +853,10 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, llvm_unreachable("Unreachable"); } -/// EmitMatcherList - Emit the bytes for the specified matcher subtree. +/// This function traverses the matcher tree and emits all the nodes. +/// The nodes have already been sized. unsigned MatcherTableEmitter:: -EmitMatcherList(const Matcher *N, unsigned Indent, unsigned CurrentIdx, +EmitMatcherList(const Matcher *N, const unsigned Indent, unsigned CurrentIdx, raw_ostream &OS) { unsigned Size = 0; while (N) { @@ -841,12 +885,12 @@ void MatcherTableEmitter::EmitNodePredicatesFunction( OS << " default: llvm_unreachable(\"Invalid predicate in table?\");\n"; for (unsigned i = 0, e = Preds.size(); i != e; ++i) { // Emit the predicate code corresponding to this pattern. - TreePredicateFn PredFn = Preds[i]; + const TreePredicateFn PredFn = Preds[i]; assert(!PredFn.isAlwaysTrue() && "No code in this predicate"); - OS << " case " << i << ": { \n"; + OS << " case " << i << ": {\n"; for (auto *SimilarPred : - NodePredicatesByCodeToRun[PredFn.getCodeToRunOnSDNode()]) + NodePredicatesByCodeToRun[PredFn.getCodeToRunOnSDNode()]) OS << " // " << TreePredicateFn(SimilarPred).getFnName() <<'\n'; OS << PredFn.getCodeToRunOnSDNode() << "\n }\n"; @@ -887,7 +931,7 @@ void MatcherTableEmitter::EmitPredicateFunctions(raw_ostream &OS) { BeginEmitFunction(OS, "bool", "CheckComplexPattern(SDNode *Root, SDNode *Parent,\n" " SDValue N, unsigned PatternNo,\n" - " SmallVectorImpl<std::pair<SDValue, SDNode*>> &Result)", + " SmallVectorImpl<std::pair<SDValue, SDNode *>> &Result)", true/*AddOverride*/); OS << "{\n"; OS << " unsigned NextRes = Result.size();\n"; @@ -975,28 +1019,6 @@ void MatcherTableEmitter::EmitPredicateFunctions(raw_ostream &OS) { } } -static void BuildHistogram(const Matcher *M, std::vector<unsigned> &OpcodeFreq){ - for (; M != nullptr; M = M->getNext()) { - // Count this node. - if (unsigned(M->getKind()) >= OpcodeFreq.size()) - OpcodeFreq.resize(M->getKind()+1); - OpcodeFreq[M->getKind()]++; - - // Handle recursive nodes. - if (const ScopeMatcher *SM = dyn_cast<ScopeMatcher>(M)) { - for (unsigned i = 0, e = SM->getNumChildren(); i != e; ++i) - BuildHistogram(SM->getChild(i), OpcodeFreq); - } else if (const SwitchOpcodeMatcher *SOM = - dyn_cast<SwitchOpcodeMatcher>(M)) { - for (unsigned i = 0, e = SOM->getNumCases(); i != e; ++i) - BuildHistogram(SOM->getCaseMatcher(i), OpcodeFreq); - } else if (const SwitchTypeMatcher *STM = dyn_cast<SwitchTypeMatcher>(M)) { - for (unsigned i = 0, e = STM->getNumCases(); i != e; ++i) - BuildHistogram(STM->getCaseMatcher(i), OpcodeFreq); - } - } -} - static StringRef getOpcodeString(Matcher::KindTy Kind) { switch (Kind) { case Matcher::Scope: return "OPC_Scope"; break; @@ -1048,20 +1070,17 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M, if (OmitComments) return; - std::vector<unsigned> OpcodeFreq; - BuildHistogram(M, OpcodeFreq); - OS << " // Opcode Histogram:\n"; - for (unsigned i = 0, e = OpcodeFreq.size(); i != e; ++i) { + for (unsigned i = 0, e = OpcodeCounts.size(); i != e; ++i) { OS << " // #" << left_justify(getOpcodeString((Matcher::KindTy)i), HistOpcWidth) - << " = " << OpcodeFreq[i] << '\n'; + << " = " << OpcodeCounts[i] << '\n'; } OS << '\n'; } -void llvm::EmitMatcherTable(const Matcher *TheMatcher, +void llvm::EmitMatcherTable(Matcher *TheMatcher, const CodeGenDAGPatterns &CGP, raw_ostream &OS) { OS << "#if defined(GET_DAGISEL_DECL) && defined(GET_DAGISEL_BODY)\n"; @@ -1096,12 +1115,23 @@ void llvm::EmitMatcherTable(const Matcher *TheMatcher, BeginEmitFunction(OS, "void", "SelectCode(SDNode *N)", false/*AddOverride*/); MatcherTableEmitter MatcherEmitter(CGP); + // First we size all the children of the three kinds of matchers that have + // them. This is done by sharing the code in EmitMatcher(). but we don't + // want to emit anything, so we turn off comments and use a null stream. + bool SaveOmitComments = OmitComments; + OmitComments = true; + raw_null_ostream NullOS; + unsigned TotalSize = MatcherEmitter.SizeMatcherList(TheMatcher, NullOS); + OmitComments = SaveOmitComments; + + // Now that the matchers are sized, we can emit the code for them to the + // final stream. OS << "{\n"; OS << " // Some target values are emitted as 2 bytes, TARGET_VAL handles\n"; OS << " // this.\n"; OS << " #define TARGET_VAL(X) X & 255, unsigned(X) >> 8\n"; OS << " static const unsigned char MatcherTable[] = {\n"; - unsigned TotalSize = MatcherEmitter.EmitMatcherList(TheMatcher, 1, 0, OS); + TotalSize = MatcherEmitter.EmitMatcherList(TheMatcher, 1, 0, OS); OS << " 0\n }; // Total Array size is " << (TotalSize+1) << " bytes\n\n"; MatcherEmitter.EmitHistogram(TheMatcher, OS); diff --git a/llvm/utils/TableGen/DAGISelMatcherGen.cpp b/llvm/utils/TableGen/DAGISelMatcherGen.cpp index 123ea3374c74..f7415b87e1c0 100644 --- a/llvm/utils/TableGen/DAGISelMatcherGen.cpp +++ b/llvm/utils/TableGen/DAGISelMatcherGen.cpp @@ -282,7 +282,9 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) { // check to ensure that this gets folded into the normal top-level // OpcodeSwitch. if (N == Pattern.getSrcPattern()) { - const SDNodeInfo &NI = CGP.getSDNodeInfo(CGP.getSDNodeNamed("build_vector")); + MVT VT = N->getSimpleType(0); + StringRef Name = VT.isScalableVector() ? "splat_vector" : "build_vector"; + const SDNodeInfo &NI = CGP.getSDNodeInfo(CGP.getSDNodeNamed(Name)); AddMatcher(new CheckOpcodeMatcher(NI)); } return AddMatcher(new CheckImmAllOnesVMatcher()); @@ -292,7 +294,9 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) { // check to ensure that this gets folded into the normal top-level // OpcodeSwitch. if (N == Pattern.getSrcPattern()) { - const SDNodeInfo &NI = CGP.getSDNodeInfo(CGP.getSDNodeNamed("build_vector")); + MVT VT = N->getSimpleType(0); + StringRef Name = VT.isScalableVector() ? "splat_vector" : "build_vector"; + const SDNodeInfo &NI = CGP.getSDNodeInfo(CGP.getSDNodeNamed(Name)); AddMatcher(new CheckOpcodeMatcher(NI)); } return AddMatcher(new CheckImmAllZerosVMatcher()); @@ -744,7 +748,7 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N, } } - errs() << "unhandled leaf node: \n"; + errs() << "unhandled leaf node:\n"; N->dump(); } diff --git a/llvm/utils/TableGen/DFAEmitter.cpp b/llvm/utils/TableGen/DFAEmitter.cpp index 7391f6845a4b..781cb0636fa1 100644 --- a/llvm/utils/TableGen/DFAEmitter.cpp +++ b/llvm/utils/TableGen/DFAEmitter.cpp @@ -174,7 +174,7 @@ namespace { struct Action { Record *R = nullptr; unsigned I = 0; - std::string S = nullptr; + std::string S; Action() = default; Action(Record *R, unsigned I, std::string S) : R(R), I(I), S(S) {} @@ -346,8 +346,7 @@ Transition::Transition(Record *R, Automaton *Parent) { } else if (isa<IntRecTy>(SymbolV->getType())) { Actions.emplace_back(nullptr, R->getValueAsInt(A), ""); Types.emplace_back("unsigned"); - } else if (isa<StringRecTy>(SymbolV->getType()) || - isa<CodeRecTy>(SymbolV->getType())) { + } else if (isa<StringRecTy>(SymbolV->getType())) { Actions.emplace_back(nullptr, 0, std::string(R->getValueAsString(A))); Types.emplace_back("std::string"); } else { diff --git a/llvm/utils/TableGen/DFAPacketizerEmitter.cpp b/llvm/utils/TableGen/DFAPacketizerEmitter.cpp index bc4a084b3224..40d9385e5e9e 100644 --- a/llvm/utils/TableGen/DFAPacketizerEmitter.cpp +++ b/llvm/utils/TableGen/DFAPacketizerEmitter.cpp @@ -263,7 +263,7 @@ void DFAPacketizerEmitter::emitForItineraries( OS << " " << ProcModelStartIdx[Model] << ", // " << Model->ModelName << "\n"; } - OS << ScheduleClasses.size() << "\n};\n\n"; + OS << " " << ScheduleClasses.size() << "\n};\n\n"; // The type of a state in the nondeterministic automaton we're defining. using NfaStateTy = uint64_t; diff --git a/llvm/utils/TableGen/DirectiveEmitter.cpp b/llvm/utils/TableGen/DirectiveEmitter.cpp index 2061ff1fdd1a..c9daa9b24155 100644 --- a/llvm/utils/TableGen/DirectiveEmitter.cpp +++ b/llvm/utils/TableGen/DirectiveEmitter.cpp @@ -11,9 +11,9 @@ // //===----------------------------------------------------------------------===// +#include "llvm/TableGen/DirectiveEmitter.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" @@ -40,23 +40,15 @@ private: namespace llvm { -// Get Directive or Clause name formatted by replacing whitespaces with -// underscores. -std::string getFormattedName(StringRef Name) { - std::string N = Name.str(); - std::replace(N.begin(), N.end(), ' ', '_'); - return N; -} - // Generate enum class void GenerateEnumClass(const std::vector<Record *> &Records, raw_ostream &OS, - StringRef Enum, StringRef Prefix, StringRef CppNamespace, - bool MakeEnumAvailableInNamespace) { + StringRef Enum, StringRef Prefix, + const DirectiveLanguage &DirLang) { OS << "\n"; OS << "enum class " << Enum << " {\n"; for (const auto &R : Records) { - const auto Name = R->getValueAsString("name"); - OS << " " << Prefix << getFormattedName(Name) << ",\n"; + BaseRecord Rec{R}; + OS << " " << Prefix << Rec.getFormattedName() << ",\n"; } OS << "};\n"; OS << "\n"; @@ -68,44 +60,130 @@ void GenerateEnumClass(const std::vector<Record *> &Records, raw_ostream &OS, // At the same time we do not loose the strong type guarantees of the enum // class, that is we cannot pass an unsigned as Directive without an explicit // cast. - if (MakeEnumAvailableInNamespace) { + if (DirLang.hasMakeEnumAvailableInNamespace()) { OS << "\n"; for (const auto &R : Records) { - const auto FormattedName = getFormattedName(R->getValueAsString("name")); - OS << "constexpr auto " << Prefix << FormattedName << " = " - << "llvm::" << CppNamespace << "::" << Enum << "::" << Prefix - << FormattedName << ";\n"; + BaseRecord Rec{R}; + OS << "constexpr auto " << Prefix << Rec.getFormattedName() << " = " + << "llvm::" << DirLang.getCppNamespace() << "::" << Enum + << "::" << Prefix << Rec.getFormattedName() << ";\n"; } } } +// Generate enums for values that clauses can take. +// Also generate function declarations for get<Enum>Name(StringRef Str). +void GenerateEnumClauseVal(const std::vector<Record *> &Records, + raw_ostream &OS, const DirectiveLanguage &DirLang, + std::string &EnumHelperFuncs) { + for (const auto &R : Records) { + Clause C{R}; + const auto &ClauseVals = C.getClauseVals(); + if (ClauseVals.size() <= 0) + continue; + + const auto &EnumName = C.getEnumName(); + if (EnumName.size() == 0) { + PrintError("enumClauseValue field not set in Clause" + + C.getFormattedName() + "."); + return; + } + + OS << "\n"; + OS << "enum class " << EnumName << " {\n"; + for (const auto &CV : ClauseVals) { + ClauseVal CVal{CV}; + OS << " " << CV->getName() << "=" << CVal.getValue() << ",\n"; + } + OS << "};\n"; + + if (DirLang.hasMakeEnumAvailableInNamespace()) { + OS << "\n"; + for (const auto &CV : ClauseVals) { + OS << "constexpr auto " << CV->getName() << " = " + << "llvm::" << DirLang.getCppNamespace() << "::" << EnumName + << "::" << CV->getName() << ";\n"; + } + EnumHelperFuncs += (llvm::Twine(EnumName) + llvm::Twine(" get") + + llvm::Twine(EnumName) + llvm::Twine("(StringRef);\n")) + .str(); + + EnumHelperFuncs += + (llvm::Twine("llvm::StringRef get") + llvm::Twine(DirLang.getName()) + + llvm::Twine(EnumName) + llvm::Twine("Name(") + + llvm::Twine(EnumName) + llvm::Twine(");\n")) + .str(); + } + } +} + +bool HasDuplicateClauses(const std::vector<Record *> &Clauses, + const Directive &Directive, + llvm::StringSet<> &CrtClauses) { + bool HasError = false; + for (const auto &C : Clauses) { + VersionedClause VerClause{C}; + const auto insRes = CrtClauses.insert(VerClause.getClause().getName()); + if (!insRes.second) { + PrintError("Clause " + VerClause.getClause().getRecordName() + + " already defined on directive " + Directive.getRecordName()); + HasError = true; + } + } + return HasError; +} + +// Check for duplicate clauses in lists. Clauses cannot appear twice in the +// three allowed list. Also, since required implies allowed, clauses cannot +// appear in both the allowedClauses and requiredClauses lists. +bool HasDuplicateClausesInDirectives(const std::vector<Record *> &Directives) { + bool HasDuplicate = false; + for (const auto &D : Directives) { + Directive Dir{D}; + llvm::StringSet<> Clauses; + // Check for duplicates in the three allowed lists. + if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) || + HasDuplicateClauses(Dir.getAllowedOnceClauses(), Dir, Clauses) || + HasDuplicateClauses(Dir.getAllowedExclusiveClauses(), Dir, Clauses)) { + HasDuplicate = true; + } + // Check for duplicate between allowedClauses and required + Clauses.clear(); + if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) || + HasDuplicateClauses(Dir.getRequiredClauses(), Dir, Clauses)) { + HasDuplicate = true; + } + if (HasDuplicate) + PrintFatalError("One or more clauses are defined multiple times on" + " directive " + + Dir.getRecordName()); + } + + return HasDuplicate; +} + +// Check consitency of records. Return true if an error has been detected. +// Return false if the records are valid. +bool DirectiveLanguage::HasValidityErrors() const { + if (getDirectiveLanguages().size() != 1) { + PrintFatalError("A single definition of DirectiveLanguage is needed."); + return true; + } + + return HasDuplicateClausesInDirectives(getDirectives()); +} + // Generate the declaration section for the enumeration in the directive // language void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) { - - const auto &DirectiveLanguages = - Records.getAllDerivedDefinitions("DirectiveLanguage"); - - if (DirectiveLanguages.size() != 1) { - PrintError("A single definition of DirectiveLanguage is needed."); + const auto DirLang = DirectiveLanguage{Records}; + if (DirLang.HasValidityErrors()) return; - } - const auto &DirectiveLanguage = DirectiveLanguages[0]; - StringRef LanguageName = DirectiveLanguage->getValueAsString("name"); - StringRef DirectivePrefix = - DirectiveLanguage->getValueAsString("directivePrefix"); - StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix"); - StringRef CppNamespace = DirectiveLanguage->getValueAsString("cppNamespace"); - bool MakeEnumAvailableInNamespace = - DirectiveLanguage->getValueAsBit("makeEnumAvailableInNamespace"); - bool EnableBitmaskEnumInNamespace = - DirectiveLanguage->getValueAsBit("enableBitmaskEnumInNamespace"); - - OS << "#ifndef LLVM_" << LanguageName << "_INC\n"; - OS << "#define LLVM_" << LanguageName << "_INC\n"; - - if (EnableBitmaskEnumInNamespace) + OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n"; + OS << "#define LLVM_" << DirLang.getName() << "_INC\n"; + + if (DirLang.hasEnableBitmaskEnumInNamespace()) OS << "\n#include \"llvm/ADT/BitmaskEnum.h\"\n"; OS << "\n"; @@ -114,41 +192,48 @@ void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) { // Open namespaces defined in the directive language llvm::SmallVector<StringRef, 2> Namespaces; - llvm::SplitString(CppNamespace, Namespaces, "::"); + llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::"); for (auto Ns : Namespaces) OS << "namespace " << Ns << " {\n"; - if (EnableBitmaskEnumInNamespace) + if (DirLang.hasEnableBitmaskEnumInNamespace()) OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; // Emit Directive enumeration - const auto &Directives = Records.getAllDerivedDefinitions("Directive"); - GenerateEnumClass(Directives, OS, "Directive", DirectivePrefix, CppNamespace, - MakeEnumAvailableInNamespace); + GenerateEnumClass(DirLang.getDirectives(), OS, "Directive", + DirLang.getDirectivePrefix(), DirLang); // Emit Clause enumeration - const auto &Clauses = Records.getAllDerivedDefinitions("Clause"); - GenerateEnumClass(Clauses, OS, "Clause", ClausePrefix, CppNamespace, - MakeEnumAvailableInNamespace); + GenerateEnumClass(DirLang.getClauses(), OS, "Clause", + DirLang.getClausePrefix(), DirLang); + + // Emit ClauseVal enumeration + std::string EnumHelperFuncs; + GenerateEnumClauseVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs); // Generic function signatures OS << "\n"; OS << "// Enumeration helper functions\n"; - OS << "Directive get" << LanguageName + OS << "Directive get" << DirLang.getName() << "DirectiveKind(llvm::StringRef Str);\n"; OS << "\n"; - OS << "llvm::StringRef get" << LanguageName + OS << "llvm::StringRef get" << DirLang.getName() << "DirectiveName(Directive D);\n"; OS << "\n"; - OS << "Clause get" << LanguageName << "ClauseKind(llvm::StringRef Str);\n"; + OS << "Clause get" << DirLang.getName() + << "ClauseKind(llvm::StringRef Str);\n"; OS << "\n"; - OS << "llvm::StringRef get" << LanguageName << "ClauseName(Clause C);\n"; + OS << "llvm::StringRef get" << DirLang.getName() << "ClauseName(Clause C);\n"; OS << "\n"; OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p " << "Version.\n"; OS << "bool isAllowedClauseForDirective(Directive D, " << "Clause C, unsigned Version);\n"; OS << "\n"; + if (EnumHelperFuncs.length() > 0) { + OS << EnumHelperFuncs; + OS << "\n"; + } // Closing namespaces for (auto Ns : llvm::reverse(Namespaces)) @@ -156,138 +241,183 @@ void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) { OS << "} // namespace llvm\n"; - OS << "#endif // LLVM_" << LanguageName << "_INC\n"; + OS << "#endif // LLVM_" << DirLang.getName() << "_INC\n"; } // Generate function implementation for get<Enum>Name(StringRef Str) void GenerateGetName(const std::vector<Record *> &Records, raw_ostream &OS, - StringRef Enum, StringRef Prefix, StringRef LanguageName, - StringRef Namespace) { + StringRef Enum, const DirectiveLanguage &DirLang, + StringRef Prefix) { OS << "\n"; - OS << "llvm::StringRef llvm::" << Namespace << "::get" << LanguageName << Enum - << "Name(" << Enum << " Kind) {\n"; + OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get" + << DirLang.getName() << Enum << "Name(" << Enum << " Kind) {\n"; OS << " switch (Kind) {\n"; for (const auto &R : Records) { - const auto Name = R->getValueAsString("name"); - const auto AlternativeName = R->getValueAsString("alternativeName"); - OS << " case " << Prefix << getFormattedName(Name) << ":\n"; + BaseRecord Rec{R}; + OS << " case " << Prefix << Rec.getFormattedName() << ":\n"; OS << " return \""; - if (AlternativeName.empty()) - OS << Name; + if (Rec.getAlternativeName().empty()) + OS << Rec.getName(); else - OS << AlternativeName; + OS << Rec.getAlternativeName(); OS << "\";\n"; } OS << " }\n"; // switch - OS << " llvm_unreachable(\"Invalid " << LanguageName << " " << Enum + OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " " << Enum << " kind\");\n"; OS << "}\n"; } // Generate function implementation for get<Enum>Kind(StringRef Str) void GenerateGetKind(const std::vector<Record *> &Records, raw_ostream &OS, - StringRef Enum, StringRef Prefix, StringRef LanguageName, - StringRef Namespace, bool ImplicitAsUnknown) { + StringRef Enum, const DirectiveLanguage &DirLang, + StringRef Prefix, bool ImplicitAsUnknown) { - auto DefaultIt = std::find_if(Records.begin(), Records.end(), [](Record *R) { - return R->getValueAsBit("isDefault") == true; - }); + auto DefaultIt = llvm::find_if( + Records, [](Record *R) { return R->getValueAsBit("isDefault") == true; }); if (DefaultIt == Records.end()) { - PrintError("A least one " + Enum + " must be defined as default."); + PrintError("At least one " + Enum + " must be defined as default."); return; } - const auto FormattedDefaultName = - getFormattedName((*DefaultIt)->getValueAsString("name")); + BaseRecord DefaultRec{(*DefaultIt)}; OS << "\n"; - OS << Enum << " llvm::" << Namespace << "::get" << LanguageName << Enum - << "Kind(llvm::StringRef Str) {\n"; + OS << Enum << " llvm::" << DirLang.getCppNamespace() << "::get" + << DirLang.getName() << Enum << "Kind(llvm::StringRef Str) {\n"; OS << " return llvm::StringSwitch<" << Enum << ">(Str)\n"; for (const auto &R : Records) { - const auto Name = R->getValueAsString("name"); + BaseRecord Rec{R}; if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) { - OS << " .Case(\"" << Name << "\"," << Prefix << FormattedDefaultName - << ")\n"; + OS << " .Case(\"" << Rec.getName() << "\"," << Prefix + << DefaultRec.getFormattedName() << ")\n"; } else { - OS << " .Case(\"" << Name << "\"," << Prefix << getFormattedName(Name) - << ")\n"; + OS << " .Case(\"" << Rec.getName() << "\"," << Prefix + << Rec.getFormattedName() << ")\n"; } } - OS << " .Default(" << Prefix << FormattedDefaultName << ");\n"; + OS << " .Default(" << Prefix << DefaultRec.getFormattedName() << ");\n"; OS << "}\n"; } +// Generate function implementation for get<ClauseVal>Kind(StringRef Str) +void GenerateGetKindClauseVal(const DirectiveLanguage &DirLang, + raw_ostream &OS) { + for (const auto &R : DirLang.getClauses()) { + Clause C{R}; + const auto &ClauseVals = C.getClauseVals(); + if (ClauseVals.size() <= 0) + continue; + + auto DefaultIt = llvm::find_if(ClauseVals, [](Record *CV) { + return CV->getValueAsBit("isDefault") == true; + }); + + if (DefaultIt == ClauseVals.end()) { + PrintError("At least one val in Clause " + C.getFormattedName() + + " must be defined as default."); + return; + } + const auto DefaultName = (*DefaultIt)->getName(); + + const auto &EnumName = C.getEnumName(); + if (EnumName.size() == 0) { + PrintError("enumClauseValue field not set in Clause" + + C.getFormattedName() + "."); + return; + } + + OS << "\n"; + OS << EnumName << " llvm::" << DirLang.getCppNamespace() << "::get" + << EnumName << "(llvm::StringRef Str) {\n"; + OS << " return llvm::StringSwitch<" << EnumName << ">(Str)\n"; + for (const auto &CV : ClauseVals) { + ClauseVal CVal{CV}; + OS << " .Case(\"" << CVal.getFormattedName() << "\"," << CV->getName() + << ")\n"; + } + OS << " .Default(" << DefaultName << ");\n"; + OS << "}\n"; + + OS << "\n"; + OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get" + << DirLang.getName() << EnumName + << "Name(llvm::" << DirLang.getCppNamespace() << "::" << EnumName + << " x) {\n"; + OS << " switch (x) {\n"; + for (const auto &CV : ClauseVals) { + ClauseVal CVal{CV}; + OS << " case " << CV->getName() << ":\n"; + OS << " return \"" << CVal.getFormattedName() << "\";\n"; + } + OS << " }\n"; // switch + OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " " + << EnumName << " kind\");\n"; + OS << "}\n"; + } +} + void GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses, raw_ostream &OS, StringRef DirectiveName, - StringRef DirectivePrefix, - StringRef ClausePrefix, + const DirectiveLanguage &DirLang, llvm::StringSet<> &Cases) { for (const auto &C : Clauses) { - const auto MinVersion = C->getValueAsInt("minVersion"); - const auto MaxVersion = C->getValueAsInt("maxVersion"); - const auto SpecificClause = C->getValueAsDef("clause"); - const auto ClauseName = - getFormattedName(SpecificClause->getValueAsString("name")); - - if (Cases.find(ClauseName) == Cases.end()) { - Cases.insert(ClauseName); - OS << " case " << ClausePrefix << ClauseName << ":\n"; - OS << " return " << MinVersion << " <= Version && " << MaxVersion - << " >= Version;\n"; + VersionedClause VerClause{C}; + + const auto ClauseFormattedName = VerClause.getClause().getFormattedName(); + + if (Cases.find(ClauseFormattedName) == Cases.end()) { + Cases.insert(ClauseFormattedName); + OS << " case " << DirLang.getClausePrefix() << ClauseFormattedName + << ":\n"; + OS << " return " << VerClause.getMinVersion() + << " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n"; } } } // Generate the isAllowedClauseForDirective function implementation. -void GenerateIsAllowedClause(const std::vector<Record *> &Directives, - raw_ostream &OS, StringRef LanguageName, - StringRef DirectivePrefix, StringRef ClausePrefix, - StringRef CppNamespace) { +void GenerateIsAllowedClause(const DirectiveLanguage &DirLang, + raw_ostream &OS) { OS << "\n"; - OS << "bool llvm::" << CppNamespace << "::isAllowedClauseForDirective(" + OS << "bool llvm::" << DirLang.getCppNamespace() + << "::isAllowedClauseForDirective(" << "Directive D, Clause C, unsigned Version) {\n"; - OS << " assert(unsigned(D) <= llvm::" << CppNamespace + OS << " assert(unsigned(D) <= llvm::" << DirLang.getCppNamespace() << "::Directive_enumSize);\n"; - OS << " assert(unsigned(C) <= llvm::" << CppNamespace + OS << " assert(unsigned(C) <= llvm::" << DirLang.getCppNamespace() << "::Clause_enumSize);\n"; OS << " switch (D) {\n"; - for (const auto &D : Directives) { - - const auto DirectiveName = D->getValueAsString("name"); - const auto &AllowedClauses = D->getValueAsListOfDefs("allowedClauses"); - const auto &AllowedOnceClauses = - D->getValueAsListOfDefs("allowedOnceClauses"); - const auto &AllowedExclusiveClauses = - D->getValueAsListOfDefs("allowedExclusiveClauses"); - const auto &RequiredClauses = D->getValueAsListOfDefs("requiredClauses"); + for (const auto &D : DirLang.getDirectives()) { + Directive Dir{D}; - OS << " case " << DirectivePrefix << getFormattedName(DirectiveName) + OS << " case " << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ":\n"; - if (AllowedClauses.size() == 0 && AllowedOnceClauses.size() == 0 && - AllowedExclusiveClauses.size() == 0 && RequiredClauses.size() == 0) { + if (Dir.getAllowedClauses().size() == 0 && + Dir.getAllowedOnceClauses().size() == 0 && + Dir.getAllowedExclusiveClauses().size() == 0 && + Dir.getRequiredClauses().size() == 0) { OS << " return false;\n"; } else { OS << " switch (C) {\n"; llvm::StringSet<> Cases; - GenerateCaseForVersionedClauses(AllowedClauses, OS, DirectiveName, - DirectivePrefix, ClausePrefix, Cases); + GenerateCaseForVersionedClauses(Dir.getAllowedClauses(), OS, + Dir.getName(), DirLang, Cases); - GenerateCaseForVersionedClauses(AllowedOnceClauses, OS, DirectiveName, - DirectivePrefix, ClausePrefix, Cases); + GenerateCaseForVersionedClauses(Dir.getAllowedOnceClauses(), OS, + Dir.getName(), DirLang, Cases); - GenerateCaseForVersionedClauses(AllowedExclusiveClauses, OS, - DirectiveName, DirectivePrefix, - ClausePrefix, Cases); + GenerateCaseForVersionedClauses(Dir.getAllowedExclusiveClauses(), OS, + Dir.getName(), DirLang, Cases); - GenerateCaseForVersionedClauses(RequiredClauses, OS, DirectiveName, - DirectivePrefix, ClausePrefix, Cases); + GenerateCaseForVersionedClauses(Dir.getRequiredClauses(), OS, + Dir.getName(), DirLang, Cases); OS << " default:\n"; OS << " return false;\n"; @@ -297,37 +427,32 @@ void GenerateIsAllowedClause(const std::vector<Record *> &Directives, } OS << " }\n"; // End of directives switch - OS << " llvm_unreachable(\"Invalid " << LanguageName + OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " Directive kind\");\n"; OS << "}\n"; // End of function isAllowedClauseForDirective } // Generate a simple enum set with the give clauses. void GenerateClauseSet(const std::vector<Record *> &Clauses, raw_ostream &OS, - StringRef ClauseEnumSetClass, StringRef ClauseSetPrefix, - StringRef DirectiveName, StringRef DirectivePrefix, - StringRef ClausePrefix, StringRef CppNamespace) { + StringRef ClauseSetPrefix, Directive &Dir, + const DirectiveLanguage &DirLang) { OS << "\n"; - OS << " static " << ClauseEnumSetClass << " " << ClauseSetPrefix - << DirectivePrefix << getFormattedName(DirectiveName) << " {\n"; + OS << " static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix + << DirLang.getDirectivePrefix() << Dir.getFormattedName() << " {\n"; for (const auto &C : Clauses) { - const auto SpecificClause = C->getValueAsDef("clause"); - const auto ClauseName = SpecificClause->getValueAsString("name"); - OS << " llvm::" << CppNamespace << "::Clause::" << ClausePrefix - << getFormattedName(ClauseName) << ",\n"; + VersionedClause VerClause{C}; + OS << " llvm::" << DirLang.getCppNamespace() + << "::Clause::" << DirLang.getClausePrefix() + << VerClause.getClause().getFormattedName() << ",\n"; } OS << " };\n"; } // Generate an enum set for the 4 kinds of clauses linked to a directive. -void GenerateDirectiveClauseSets(const std::vector<Record *> &Directives, - raw_ostream &OS, StringRef LanguageName, - StringRef ClauseEnumSetClass, - StringRef DirectivePrefix, - StringRef ClausePrefix, - StringRef CppNamespace) { +void GenerateDirectiveClauseSets(const DirectiveLanguage &DirLang, + raw_ostream &OS) { IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS); @@ -336,35 +461,24 @@ void GenerateDirectiveClauseSets(const std::vector<Record *> &Directives, // Open namespaces defined in the directive language. llvm::SmallVector<StringRef, 2> Namespaces; - llvm::SplitString(CppNamespace, Namespaces, "::"); + llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::"); for (auto Ns : Namespaces) OS << "namespace " << Ns << " {\n"; - for (const auto &D : Directives) { - const auto DirectiveName = D->getValueAsString("name"); - - const auto &AllowedClauses = D->getValueAsListOfDefs("allowedClauses"); - const auto &AllowedOnceClauses = - D->getValueAsListOfDefs("allowedOnceClauses"); - const auto &AllowedExclusiveClauses = - D->getValueAsListOfDefs("allowedExclusiveClauses"); - const auto &RequiredClauses = D->getValueAsListOfDefs("requiredClauses"); + for (const auto &D : DirLang.getDirectives()) { + Directive Dir{D}; OS << "\n"; - OS << " // Sets for " << DirectiveName << "\n"; - - GenerateClauseSet(AllowedClauses, OS, ClauseEnumSetClass, "allowedClauses_", - DirectiveName, DirectivePrefix, ClausePrefix, - CppNamespace); - GenerateClauseSet(AllowedOnceClauses, OS, ClauseEnumSetClass, - "allowedOnceClauses_", DirectiveName, DirectivePrefix, - ClausePrefix, CppNamespace); - GenerateClauseSet(AllowedExclusiveClauses, OS, ClauseEnumSetClass, - "allowedExclusiveClauses_", DirectiveName, - DirectivePrefix, ClausePrefix, CppNamespace); - GenerateClauseSet(RequiredClauses, OS, ClauseEnumSetClass, - "requiredClauses_", DirectiveName, DirectivePrefix, - ClausePrefix, CppNamespace); + OS << " // Sets for " << Dir.getName() << "\n"; + + GenerateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir, + DirLang); + GenerateClauseSet(Dir.getAllowedOnceClauses(), OS, "allowedOnceClauses_", + Dir, DirLang); + GenerateClauseSet(Dir.getAllowedExclusiveClauses(), OS, + "allowedExclusiveClauses_", Dir, DirLang); + GenerateClauseSet(Dir.getRequiredClauses(), OS, "requiredClauses_", Dir, + DirLang); } // Closing namespaces @@ -377,118 +491,253 @@ void GenerateDirectiveClauseSets(const std::vector<Record *> &Directives, // Generate a map of directive (key) with DirectiveClauses struct as values. // The struct holds the 4 sets of enumeration for the 4 kinds of clauses // allowances (allowed, allowed once, allowed exclusive and required). -void GenerateDirectiveClauseMap(const std::vector<Record *> &Directives, - raw_ostream &OS, StringRef LanguageName, - StringRef ClauseEnumSetClass, - StringRef DirectivePrefix, - StringRef ClausePrefix, - StringRef CppNamespace) { +void GenerateDirectiveClauseMap(const DirectiveLanguage &DirLang, + raw_ostream &OS) { IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS); OS << "\n"; - OS << "struct " << LanguageName << "DirectiveClauses {\n"; - OS << " const " << ClauseEnumSetClass << " allowed;\n"; - OS << " const " << ClauseEnumSetClass << " allowedOnce;\n"; - OS << " const " << ClauseEnumSetClass << " allowedExclusive;\n"; - OS << " const " << ClauseEnumSetClass << " requiredOneOf;\n"; - OS << "};\n"; + OS << "{\n"; - OS << "\n"; - - OS << "std::unordered_map<llvm::" << CppNamespace << "::Directive, " - << LanguageName << "DirectiveClauses>\n"; - OS << " directiveClausesTable = {\n"; - - for (const auto &D : Directives) { - const auto FormattedDirectiveName = - getFormattedName(D->getValueAsString("name")); - OS << " {llvm::" << CppNamespace << "::Directive::" << DirectivePrefix - << FormattedDirectiveName << ",\n"; + for (const auto &D : DirLang.getDirectives()) { + Directive Dir{D}; + OS << " {llvm::" << DirLang.getCppNamespace() + << "::Directive::" << DirLang.getDirectivePrefix() + << Dir.getFormattedName() << ",\n"; OS << " {\n"; - OS << " llvm::" << CppNamespace << "::allowedClauses_" - << DirectivePrefix << FormattedDirectiveName << ",\n"; - OS << " llvm::" << CppNamespace << "::allowedOnceClauses_" - << DirectivePrefix << FormattedDirectiveName << ",\n"; - OS << " llvm::" << CppNamespace << "::allowedExclusiveClauses_" - << DirectivePrefix << FormattedDirectiveName << ",\n"; - OS << " llvm::" << CppNamespace << "::requiredClauses_" - << DirectivePrefix << FormattedDirectiveName << ",\n"; + OS << " llvm::" << DirLang.getCppNamespace() << "::allowedClauses_" + << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; + OS << " llvm::" << DirLang.getCppNamespace() << "::allowedOnceClauses_" + << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; + OS << " llvm::" << DirLang.getCppNamespace() + << "::allowedExclusiveClauses_" << DirLang.getDirectivePrefix() + << Dir.getFormattedName() << ",\n"; + OS << " llvm::" << DirLang.getCppNamespace() << "::requiredClauses_" + << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; OS << " }\n"; OS << " },\n"; } - OS << "};\n"; + OS << "}\n"; } -// Generate the implemenation section for the enumeration in the directive -// language -void EmitDirectivesFlangImpl(const std::vector<Record *> &Directives, - raw_ostream &OS, StringRef LanguageName, - StringRef ClauseEnumSetClass, - StringRef DirectivePrefix, StringRef ClausePrefix, - StringRef CppNamespace) { +// Generate classes entry for Flang clauses in the Flang parse-tree +// If the clause as a non-generic class, no entry is generated. +// If the clause does not hold a value, an EMPTY_CLASS is used. +// If the clause class is generic then a WRAPPER_CLASS is used. When the value +// is optional, the value class is wrapped into a std::optional. +void GenerateFlangClauseParserClass(const DirectiveLanguage &DirLang, + raw_ostream &OS) { - GenerateDirectiveClauseSets(Directives, OS, LanguageName, ClauseEnumSetClass, - DirectivePrefix, ClausePrefix, CppNamespace); + IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS); + + OS << "\n"; - GenerateDirectiveClauseMap(Directives, OS, LanguageName, ClauseEnumSetClass, - DirectivePrefix, ClausePrefix, CppNamespace); + for (const auto &C : DirLang.getClauses()) { + Clause Clause{C}; + if (!Clause.getFlangClass().empty()) { + OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", "; + if (Clause.isValueOptional() && Clause.isValueList()) { + OS << "std::optional<std::list<" << Clause.getFlangClass() << ">>"; + } else if (Clause.isValueOptional()) { + OS << "std::optional<" << Clause.getFlangClass() << ">"; + } else if (Clause.isValueList()) { + OS << "std::list<" << Clause.getFlangClass() << ">"; + } else { + OS << Clause.getFlangClass(); + } + } else { + OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName(); + } + OS << ");\n"; + } } -// Generate the implemenation section for the enumeration in the directive -// language. -void EmitDirectivesGen(RecordKeeper &Records, raw_ostream &OS) { +// Generate a list of the different clause classes for Flang. +void GenerateFlangClauseParserClassList(const DirectiveLanguage &DirLang, + raw_ostream &OS) { - const auto &DirectiveLanguages = - Records.getAllDerivedDefinitions("DirectiveLanguage"); + IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS); - if (DirectiveLanguages.size() != 1) { - PrintError("A single definition of DirectiveLanguage is needed."); - return; + OS << "\n"; + llvm::interleaveComma(DirLang.getClauses(), OS, [&](Record *C) { + Clause Clause{C}; + OS << Clause.getFormattedParserClassName() << "\n"; + }); +} + +// Generate dump node list for the clauses holding a generic class name. +void GenerateFlangClauseDump(const DirectiveLanguage &DirLang, + raw_ostream &OS) { + + IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS); + + OS << "\n"; + for (const auto &C : DirLang.getClauses()) { + Clause Clause{C}; + OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", " + << Clause.getFormattedParserClassName() << ")\n"; } +} - const auto &DirectiveLanguage = DirectiveLanguages[0]; - StringRef DirectivePrefix = - DirectiveLanguage->getValueAsString("directivePrefix"); - StringRef LanguageName = DirectiveLanguage->getValueAsString("name"); - StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix"); - StringRef CppNamespace = DirectiveLanguage->getValueAsString("cppNamespace"); - StringRef ClauseEnumSetClass = - DirectiveLanguage->getValueAsString("clauseEnumSetClass"); +// Generate Unparse functions for clauses classes in the Flang parse-tree +// If the clause is a non-generic class, no entry is generated. +void GenerateFlangClauseUnparse(const DirectiveLanguage &DirLang, + raw_ostream &OS) { - const auto &Directives = Records.getAllDerivedDefinitions("Directive"); + IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS); - EmitDirectivesFlangImpl(Directives, OS, LanguageName, ClauseEnumSetClass, - DirectivePrefix, ClausePrefix, CppNamespace); + OS << "\n"; + + for (const auto &C : DirLang.getClauses()) { + Clause Clause{C}; + if (!Clause.getFlangClass().empty()) { + if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) { + OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() + << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; + OS << " Word(\"" << Clause.getName().upper() << "\");\n"; + + OS << " Walk(\"(\", x.v, \")\");\n"; + OS << "}\n"; + } else if (Clause.isValueOptional()) { + OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() + << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; + OS << " Word(\"" << Clause.getName().upper() << "\");\n"; + OS << " Put(\"(\");\n"; + OS << " if (x.v.has_value())\n"; + if (Clause.isValueList()) + OS << " Walk(x.v, \",\");\n"; + else + OS << " Walk(x.v);\n"; + OS << " else\n"; + OS << " Put(\"" << Clause.getDefaultValue() << "\");\n"; + OS << " Put(\")\");\n"; + OS << "}\n"; + } else { + OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() + << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; + OS << " Word(\"" << Clause.getName().upper() << "\");\n"; + OS << " Put(\"(\");\n"; + if (Clause.isValueList()) + OS << " Walk(x.v, \",\");\n"; + else + OS << " Walk(x.v);\n"; + OS << " Put(\")\");\n"; + OS << "}\n"; + } + } else { + OS << "void Before(const " << DirLang.getFlangClauseBaseClass() + << "::" << Clause.getFormattedParserClassName() << " &) { Word(\"" + << Clause.getName().upper() << "\"); }\n"; + } + } } -// Generate the implemenation for the enumeration in the directive -// language. This code can be included in library. -void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) { +// Generate the implementation section for the enumeration in the directive +// language +void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang, + raw_ostream &OS) { - const auto &DirectiveLanguages = - Records.getAllDerivedDefinitions("DirectiveLanguage"); + GenerateDirectiveClauseSets(DirLang, OS); - if (DirectiveLanguages.size() != 1) { - PrintError("A single definition of DirectiveLanguage is needed."); - return; + GenerateDirectiveClauseMap(DirLang, OS); + + GenerateFlangClauseParserClass(DirLang, OS); + + GenerateFlangClauseParserClassList(DirLang, OS); + + GenerateFlangClauseDump(DirLang, OS); + + GenerateFlangClauseUnparse(DirLang, OS); +} + +void GenerateClauseClassMacro(const DirectiveLanguage &DirLang, + raw_ostream &OS) { + // Generate macros style information for legacy code in clang + IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS); + + OS << "\n"; + + OS << "#ifndef CLAUSE\n"; + OS << "#define CLAUSE(Enum, Str, Implicit)\n"; + OS << "#endif\n"; + OS << "#ifndef CLAUSE_CLASS\n"; + OS << "#define CLAUSE_CLASS(Enum, Str, Class)\n"; + OS << "#endif\n"; + OS << "#ifndef CLAUSE_NO_CLASS\n"; + OS << "#define CLAUSE_NO_CLASS(Enum, Str)\n"; + OS << "#endif\n"; + OS << "\n"; + OS << "#define __CLAUSE(Name, Class) \\\n"; + OS << " CLAUSE(" << DirLang.getClausePrefix() + << "##Name, #Name, /* Implicit */ false) \\\n"; + OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix() + << "##Name, #Name, Class)\n"; + OS << "#define __CLAUSE_NO_CLASS(Name) \\\n"; + OS << " CLAUSE(" << DirLang.getClausePrefix() + << "##Name, #Name, /* Implicit */ false) \\\n"; + OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, #Name)\n"; + OS << "#define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class) \\\n"; + OS << " CLAUSE(" << DirLang.getClausePrefix() + << "##Name, Str, /* Implicit */ true) \\\n"; + OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix() + << "##Name, Str, Class)\n"; + OS << "#define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str) \\\n"; + OS << " CLAUSE(" << DirLang.getClausePrefix() + << "##Name, Str, /* Implicit */ true) \\\n"; + OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, Str)\n"; + OS << "\n"; + + for (const auto &R : DirLang.getClauses()) { + Clause C{R}; + if (C.getClangClass().empty()) { // NO_CLASS + if (C.isImplicit()) { + OS << "__IMPLICIT_CLAUSE_NO_CLASS(" << C.getFormattedName() << ", \"" + << C.getFormattedName() << "\")\n"; + } else { + OS << "__CLAUSE_NO_CLASS(" << C.getFormattedName() << ")\n"; + } + } else { // CLASS + if (C.isImplicit()) { + OS << "__IMPLICIT_CLAUSE_CLASS(" << C.getFormattedName() << ", \"" + << C.getFormattedName() << "\", " << C.getClangClass() << ")\n"; + } else { + OS << "__CLAUSE(" << C.getFormattedName() << ", " << C.getClangClass() + << ")\n"; + } + } } - const auto &DirectiveLanguage = DirectiveLanguages[0]; - StringRef DirectivePrefix = - DirectiveLanguage->getValueAsString("directivePrefix"); - StringRef LanguageName = DirectiveLanguage->getValueAsString("name"); - StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix"); - StringRef CppNamespace = DirectiveLanguage->getValueAsString("cppNamespace"); - const auto &Directives = Records.getAllDerivedDefinitions("Directive"); - const auto &Clauses = Records.getAllDerivedDefinitions("Clause"); + OS << "\n"; + OS << "#undef __IMPLICIT_CLAUSE_NO_CLASS\n"; + OS << "#undef __IMPLICIT_CLAUSE_CLASS\n"; + OS << "#undef __CLAUSE\n"; + OS << "#undef CLAUSE_NO_CLASS\n"; + OS << "#undef CLAUSE_CLASS\n"; + OS << "#undef CLAUSE\n"; +} + +// Generate the implementation section for the enumeration in the directive +// language. +void EmitDirectivesGen(RecordKeeper &Records, raw_ostream &OS) { + const auto DirLang = DirectiveLanguage{Records}; + if (DirLang.HasValidityErrors()) + return; + + EmitDirectivesFlangImpl(DirLang, OS); - StringRef IncludeHeader = - DirectiveLanguage->getValueAsString("includeHeader"); + GenerateClauseClassMacro(DirLang, OS); +} - if (!IncludeHeader.empty()) - OS << "#include \"" << IncludeHeader << "\"\n\n"; +// Generate the implementation for the enumeration in the directive +// language. This code can be included in library. +void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) { + const auto DirLang = DirectiveLanguage{Records}; + if (DirLang.HasValidityErrors()) + return; + + if (!DirLang.getIncludeHeader().empty()) + OS << "#include \"" << DirLang.getIncludeHeader() << "\"\n\n"; OS << "#include \"llvm/ADT/StringRef.h\"\n"; OS << "#include \"llvm/ADT/StringSwitch.h\"\n"; @@ -496,29 +745,32 @@ void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) { OS << "\n"; OS << "using namespace llvm;\n"; llvm::SmallVector<StringRef, 2> Namespaces; - llvm::SplitString(CppNamespace, Namespaces, "::"); + llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::"); for (auto Ns : Namespaces) OS << "using namespace " << Ns << ";\n"; // getDirectiveKind(StringRef Str) - GenerateGetKind(Directives, OS, "Directive", DirectivePrefix, LanguageName, - CppNamespace, /*ImplicitAsUnknown=*/false); + GenerateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang, + DirLang.getDirectivePrefix(), /*ImplicitAsUnknown=*/false); // getDirectiveName(Directive Kind) - GenerateGetName(Directives, OS, "Directive", DirectivePrefix, LanguageName, - CppNamespace); + GenerateGetName(DirLang.getDirectives(), OS, "Directive", DirLang, + DirLang.getDirectivePrefix()); // getClauseKind(StringRef Str) - GenerateGetKind(Clauses, OS, "Clause", ClausePrefix, LanguageName, - CppNamespace, /*ImplicitAsUnknown=*/true); + GenerateGetKind(DirLang.getClauses(), OS, "Clause", DirLang, + DirLang.getClausePrefix(), + /*ImplicitAsUnknown=*/true); // getClauseName(Clause Kind) - GenerateGetName(Clauses, OS, "Clause", ClausePrefix, LanguageName, - CppNamespace); + GenerateGetName(DirLang.getClauses(), OS, "Clause", DirLang, + DirLang.getClausePrefix()); + + // get<ClauseVal>Kind(StringRef Str) + GenerateGetKindClauseVal(DirLang, OS); // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version) - GenerateIsAllowedClause(Directives, OS, LanguageName, DirectivePrefix, - ClausePrefix, CppNamespace); + GenerateIsAllowedClause(DirLang, OS); } } // namespace llvm diff --git a/llvm/utils/TableGen/ExegesisEmitter.cpp b/llvm/utils/TableGen/ExegesisEmitter.cpp index 8f784e4a4121..4e532c371691 100644 --- a/llvm/utils/TableGen/ExegesisEmitter.cpp +++ b/llvm/utils/TableGen/ExegesisEmitter.cpp @@ -144,7 +144,7 @@ void ExegesisEmitter::emitPfmCountersInfo(const Record &Def, void ExegesisEmitter::emitPfmCounters(raw_ostream &OS) const { // Emit the counter name table. - OS << "\nstatic const char* " << Target << "PfmCounterNames[] = {\n"; + OS << "\nstatic const char *" << Target << "PfmCounterNames[] = {\n"; for (const auto &NameAndIndex : PfmCounterNameTable) OS << " \"" << NameAndIndex.first << "\", // " << NameAndIndex.second << "\n"; diff --git a/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp b/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp index 88d210f7fd39..01b39df055ad 100644 --- a/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp +++ b/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp @@ -226,6 +226,8 @@ typedef std::vector<bit_value_t> insn_t; namespace { +static const uint64_t NO_FIXED_SEGMENTS_SENTINEL = -1ULL; + class FilterChooser; /// Filter - Filter works with FilterChooser to produce the decoding tree for @@ -279,7 +281,7 @@ protected: std::vector<EncodingIDAndOpcode> VariableInstructions; // Map of well-known segment value to its delegate. - std::map<unsigned, std::unique_ptr<const FilterChooser>> FilterChooserMap; + std::map<uint64_t, std::unique_ptr<const FilterChooser>> FilterChooserMap; // Number of instructions which fall under FilteredInstructions category. unsigned NumFiltered; @@ -305,7 +307,7 @@ public: const FilterChooser &getVariableFC() const { assert(NumFiltered == 1); assert(FilterChooserMap.size() == 1); - return *(FilterChooserMap.find((unsigned)-1)->second); + return *(FilterChooserMap.find(NO_FIXED_SEGMENTS_SENTINEL)->second); } // Divides the decoding task into sub tasks and delegates them to the @@ -602,10 +604,9 @@ void Filter::recurse() { // Delegates to an inferior filter chooser for further processing on this // group of instructions whose segment values are variable. - FilterChooserMap.insert( - std::make_pair(-1U, std::make_unique<FilterChooser>( - Owner->AllInstructions, VariableInstructions, - Owner->Operands, BitValueArray, *Owner))); + FilterChooserMap.insert(std::make_pair(NO_FIXED_SEGMENTS_SENTINEL, + std::make_unique<FilterChooser>(Owner->AllInstructions, + VariableInstructions, Owner->Operands, BitValueArray, *Owner))); } // No need to recurse for a singleton filtered instruction. @@ -674,7 +675,7 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const { for (auto &Filter : FilterChooserMap) { // Field value -1 implies a non-empty set of variable instructions. // See also recurse(). - if (Filter.first == (unsigned)-1) { + if (Filter.first == NO_FIXED_SEGMENTS_SENTINEL) { HasFallthrough = true; // Each scope should always have at least one filter value to check @@ -721,7 +722,7 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const { assert(TableInfo.FixupStack.size() > 1 && "fixup stack underflow!"); FixupScopeList::iterator Source = TableInfo.FixupStack.end() - 1; FixupScopeList::iterator Dest = Source - 1; - Dest->insert(Dest->end(), Source->begin(), Source->end()); + llvm::append_range(*Dest, *Source); TableInfo.FixupStack.pop_back(); // If there is no fallthrough, then the final filter should get fixed @@ -941,7 +942,7 @@ emitPredicateFunction(formatted_raw_ostream &OS, PredicateSet &Predicates, // The predicate function is just a big switch statement based on the // input predicate index. OS.indent(Indentation) << "static bool checkDecoderPredicate(unsigned Idx, " - << "const FeatureBitset& Bits) {\n"; + << "const FeatureBitset &Bits) {\n"; Indentation += 2; if (!Predicates.empty()) { OS.indent(Indentation) << "switch (Idx) {\n"; @@ -965,7 +966,7 @@ emitDecoderFunction(formatted_raw_ostream &OS, DecoderSet &Decoders, unsigned Indentation) const { // The decoder function is just a big switch statement based on the // input decoder index. - OS.indent(Indentation) << "template<typename InsnType>\n"; + OS.indent(Indentation) << "template <typename InsnType>\n"; OS.indent(Indentation) << "static DecodeStatus decodeToMCInst(DecodeStatus S," << " unsigned Idx, InsnType insn, MCInst &MI,\n"; OS.indent(Indentation) << " uint64_t " @@ -1192,7 +1193,7 @@ bool FilterChooser::emitPredicateMatch(raw_ostream &o, unsigned &Indentation, if (!Pred->getValue("AssemblerMatcherPredicate")) continue; - if (!dyn_cast<DagInit>(Pred->getValue("AssemblerCondDag")->getValue())) + if (!isa<DagInit>(Pred->getValue("AssemblerCondDag")->getValue())) continue; const DagInit *D = Pred->getValueAsDag("AssemblerCondDag"); @@ -1886,7 +1887,7 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, for (unsigned i = 0, e = Vals.size(); i != e; ++i) { // Ignore fixed fields in the record, we're looking for values like: // bits<5> RST = { ?, ?, ?, ?, ? }; - if (Vals[i].getPrefix() || Vals[i].getValue()->isComplete()) + if (Vals[i].isNonconcreteOK() || Vals[i].getValue()->isComplete()) continue; // Determine if Vals[i] actually contributes to the Inst encoding. @@ -2009,9 +2010,8 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, // For each operand, see if we can figure out where it is encoded. for (const auto &Op : InOutOperands) { if (!NumberedInsnOperands[std::string(Op.second)].empty()) { - InsnOperands.insert(InsnOperands.end(), - NumberedInsnOperands[std::string(Op.second)].begin(), - NumberedInsnOperands[std::string(Op.second)].end()); + llvm::append_range(InsnOperands, + NumberedInsnOperands[std::string(Op.second)]); continue; } if (!NumberedInsnOperands[TiedNames[std::string(Op.second)]].empty()) { @@ -2162,7 +2162,7 @@ static void emitFieldFromInstruction(formatted_raw_ostream &OS) { << "// * Support shift (<<, >>) with signed and unsigned integers on the " "RHS\n" << "// * Support put (<<) to raw_ostream&\n" - << "template<typename InsnType>\n" + << "template <typename InsnType>\n" << "#if defined(_MSC_VER) && !defined(__clang__)\n" << "__declspec(noinline)\n" << "#endif\n" @@ -2182,7 +2182,7 @@ static void emitFieldFromInstruction(formatted_raw_ostream &OS) { << " return (insn & fieldMask) >> startBit;\n" << "}\n" << "\n" - << "template<typename InsnType>\n" + << "template <typename InsnType>\n" << "static InsnType fieldFromInstruction(InsnType insn, unsigned " "startBit,\n" << " unsigned numBits, " @@ -2193,7 +2193,7 @@ static void emitFieldFromInstruction(formatted_raw_ostream &OS) { << " return (insn >> startBit) & fieldMask;\n" << "}\n" << "\n" - << "template<typename InsnType>\n" + << "template <typename InsnType>\n" << "static InsnType fieldFromInstruction(InsnType insn, unsigned " "startBit,\n" << " unsigned numBits) {\n" @@ -2205,14 +2205,14 @@ static void emitFieldFromInstruction(formatted_raw_ostream &OS) { // emitDecodeInstruction - Emit the templated helper function // decodeInstruction(). static void emitDecodeInstruction(formatted_raw_ostream &OS) { - OS << "template<typename InsnType>\n" + OS << "template <typename InsnType>\n" << "static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], " "MCInst &MI,\n" << " InsnType insn, uint64_t " "Address,\n" << " const void *DisAsm,\n" << " const MCSubtargetInfo &STI) {\n" - << " const FeatureBitset& Bits = STI.getFeatureBits();\n" + << " const FeatureBitset &Bits = STI.getFeatureBits();\n" << "\n" << " const uint8_t *Ptr = DecodeTable;\n" << " InsnType CurFieldValue = 0;\n" @@ -2374,7 +2374,7 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { << " if (Fail)\n" << " S = MCDisassembler::SoftFail;\n" << " LLVM_DEBUG(dbgs() << Loc << \": OPC_SoftFail: \" << (Fail ? " - "\"FAIL\\n\":\"PASS\\n\"));\n" + "\"FAIL\\n\" : \"PASS\\n\"));\n" << " break;\n" << " }\n" << " case MCD::OPC_Fail: {\n" @@ -2392,8 +2392,8 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { void FixedLenDecoderEmitter::run(raw_ostream &o) { formatted_raw_ostream OS(o); OS << "#include \"llvm/MC/MCInst.h\"\n"; - OS << "#include \"llvm/Support/Debug.h\"\n"; OS << "#include \"llvm/Support/DataTypes.h\"\n"; + OS << "#include \"llvm/Support/Debug.h\"\n"; OS << "#include \"llvm/Support/LEB128.h\"\n"; OS << "#include \"llvm/Support/raw_ostream.h\"\n"; OS << "#include <assert.h>\n"; diff --git a/llvm/utils/TableGen/GICombinerEmitter.cpp b/llvm/utils/TableGen/GICombinerEmitter.cpp index e2a670070ae7..ab00cff63998 100644 --- a/llvm/utils/TableGen/GICombinerEmitter.cpp +++ b/llvm/utils/TableGen/GICombinerEmitter.cpp @@ -150,7 +150,7 @@ protected: /// A block of arbitrary C++ to finish testing the match. /// FIXME: This is a temporary measure until we have actual pattern matching - const CodeInit *MatchingFixupCode = nullptr; + const StringInit *MatchingFixupCode = nullptr; /// The MatchData defined by the match stage and required by the apply stage. /// This allows the plumbing of arbitrary data from C++ predicates between the @@ -199,7 +199,7 @@ public: unsigned allocUID() { return UID++; } StringRef getName() const { return TheDef.getName(); } const Record &getDef() const { return TheDef; } - const CodeInit *getMatchingFixupCode() const { return MatchingFixupCode; } + const StringInit *getMatchingFixupCode() const { return MatchingFixupCode; } size_t getNumRoots() const { return Roots.size(); } GIMatchDag &getMatchDag() { return MatchDag; } @@ -346,8 +346,6 @@ void CombineRule::declareMatchData(StringRef PatternSymbol, StringRef Type, } bool CombineRule::parseDefs() { - NamedRegionTimer T("parseDefs", "Time spent parsing the defs", "Rule Parsing", - "Time spent on rule parsing", TimeRegions); DagInit *Defs = TheDef.getValueAsDag("Defs"); if (Defs->getOperatorAsDef(TheDef.getLoc())->getName() != "defs") { @@ -434,9 +432,9 @@ bool CombineRule::parseInstructionMatcher( } if (InstrOperand.isDef()) { - if (find_if(Roots, [&](const RootInfo &X) { + if (any_of(Roots, [&](const RootInfo &X) { return X.getPatternSymbol() == Name; - }) != Roots.end()) { + })) { N->setMatchRoot(); } } @@ -462,9 +460,9 @@ bool CombineRule::parseWipMatchOpcodeMatcher(const CodeGenTarget &Target, MatchDag.addInstrNode(makeDebugName(*this, Name), insertStrTab(Name), MatchDag.getContext().makeEmptyOperandList()); - if (find_if(Roots, [&](const RootInfo &X) { + if (any_of(Roots, [&](const RootInfo &X) { return ArgName && X.getPatternSymbol() == ArgName->getValue(); - }) != Roots.end()) { + })) { N->setMatchRoot(); } @@ -488,8 +486,6 @@ bool CombineRule::parseWipMatchOpcodeMatcher(const CodeGenTarget &Target, return false; } bool CombineRule::parseMatcher(const CodeGenTarget &Target) { - NamedRegionTimer T("parseMatcher", "Time spent parsing the matcher", - "Rule Parsing", "Time spent on rule parsing", TimeRegions); StringMap<std::vector<VarInfo>> NamedEdgeDefs; StringMap<std::vector<VarInfo>> NamedEdgeUses; DagInit *Matchers = TheDef.getValueAsDag("Match"); @@ -518,10 +514,10 @@ bool CombineRule::parseMatcher(const CodeGenTarget &Target) { // Parse arbitrary C++ code we have in lieu of supporting MIR matching - if (const CodeInit *CodeI = dyn_cast<CodeInit>(Matchers->getArg(I))) { + if (const StringInit *StringI = dyn_cast<StringInit>(Matchers->getArg(I))) { assert(!MatchingFixupCode && "Only one block of arbitrary code is currently permitted"); - MatchingFixupCode = CodeI; + MatchingFixupCode = StringI; MatchDag.setHasPostMatchPredicate(true); continue; } @@ -593,6 +589,7 @@ bool CombineRule::parseMatcher(const CodeGenTarget &Target) { } class GICombinerEmitter { + RecordKeeper &Records; StringRef Name; const CodeGenTarget &Target; Record *Combiner; @@ -618,7 +615,6 @@ public: /// response to the generated cl::opt. void emitNameMatcher(raw_ostream &OS) const; - void generateDeclarationsCodeForTree(raw_ostream &OS, const GIMatchTree &Tree) const; void generateCodeForTree(raw_ostream &OS, const GIMatchTree &Tree, StringRef Indent) const; }; @@ -626,7 +622,7 @@ public: GICombinerEmitter::GICombinerEmitter(RecordKeeper &RK, const CodeGenTarget &Target, StringRef Name, Record *Combiner) - : Name(Name), Target(Target), Combiner(Combiner) {} + : Records(RK), Name(Name), Target(Target), Combiner(Combiner) {} void GICombinerEmitter::emitNameMatcher(raw_ostream &OS) const { std::vector<std::pair<std::string, std::string>> Cases; @@ -762,7 +758,7 @@ void GICombinerEmitter::generateCodeForTree(raw_ostream &OS, DagInit *Applyer = RuleDef.getValueAsDag("Apply"); if (Applyer->getOperatorAsDef(RuleDef.getLoc())->getName() != "apply") { - PrintError(RuleDef.getLoc(), "Expected apply operator"); + PrintError(RuleDef.getLoc(), "Expected 'apply' operator in Apply DAG"); return; } @@ -803,16 +799,16 @@ void GICombinerEmitter::generateCodeForTree(raw_ostream &OS, OS << Indent << " && [&]() {\n" << Indent << " " << CodeExpander(Rule->getMatchingFixupCode()->getValue(), Expansions, - Rule->getMatchingFixupCode()->getLoc(), ShowExpansions) + RuleDef.getLoc(), ShowExpansions) << "\n" << Indent << " return true;\n" << Indent << " }()"; } OS << ") {\n" << Indent << " "; - if (const CodeInit *Code = dyn_cast<CodeInit>(Applyer->getArg(0))) { + if (const StringInit *Code = dyn_cast<StringInit>(Applyer->getArg(0))) { OS << CodeExpander(Code->getAsUnquotedString(), Expansions, - Code->getLoc(), ShowExpansions) + RuleDef.getLoc(), ShowExpansions) << "\n" << Indent << " return true;\n" << Indent << " }\n"; @@ -850,6 +846,7 @@ static void emitAdditionalHelperMethodArguments(raw_ostream &OS, } void GICombinerEmitter::run(raw_ostream &OS) { + Records.startTimer("Gather rules"); gatherRules(Rules, Combiner->getValueAsListOfDefs("Rules")); if (StopAfterParse) { MatchDagCtx.print(errs()); @@ -861,11 +858,8 @@ void GICombinerEmitter::run(raw_ostream &OS) { PrintFatalError(Combiner->getLoc(), "Failed to parse one or more rules"); LLVM_DEBUG(dbgs() << "Optimizing tree for " << Rules.size() << " rules\n"); std::unique_ptr<GIMatchTree> Tree; + Records.startTimer("Optimize combiner"); { - NamedRegionTimer T("Optimize", "Time spent optimizing the combiner", - "Code Generation", "Time spent generating code", - TimeRegions); - GIMatchTreeBuilder TreeBuilder(0); for (const auto &Rule : Rules) { bool HadARoot = false; @@ -887,9 +881,7 @@ void GICombinerEmitter::run(raw_ostream &OS) { return; } - NamedRegionTimer T("Emit", "Time spent emitting the combiner", - "Code Generation", "Time spent generating code", - TimeRegions); + Records.startTimer("Emit combiner"); OS << "#ifdef " << Name.upper() << "_GENCOMBINERHELPER_DEPS\n" << "#include \"llvm/ADT/SparseBitVector.h\"\n" << "namespace llvm {\n" @@ -906,7 +898,6 @@ void GICombinerEmitter::run(raw_ostream &OS) { << " bool isRuleDisabled(unsigned ID) const;\n" << " bool setRuleEnabled(StringRef RuleIdentifier);\n" << " bool setRuleDisabled(StringRef RuleIdentifier);\n" - << "\n" << "};\n" << "\n" << "class " << getClassName(); @@ -914,10 +905,10 @@ void GICombinerEmitter::run(raw_ostream &OS) { if (!StateClass.empty()) OS << " : public " << StateClass; OS << " {\n" - << " const " << getClassName() << "RuleConfig *RuleConfig;\n" + << " const " << getClassName() << "RuleConfig *RuleConfig;\n" << "\n" << "public:\n" - << " template<typename ... Args>" << getClassName() << "(const " + << " template <typename... Args>" << getClassName() << "(const " << getClassName() << "RuleConfig &RuleConfig, Args &&... args) : "; if (!StateClass.empty()) OS << StateClass << "(std::forward<Args>(args)...), "; @@ -947,9 +938,9 @@ void GICombinerEmitter::run(raw_ostream &OS) { << " if (First >= Last)\n" << " report_fatal_error(\"Beginning of range should be before " "end of range\");\n" - << " return {{ *First, *Last + 1 }};\n" + << " return {{*First, *Last + 1}};\n" << " } else if (RangePair.first == \"*\") {\n" - << " return {{ 0, " << Rules.size() << " }};\n" + << " return {{0, " << Rules.size() << "}};\n" << " } else {\n" << " const auto I = getRuleIdxForIdentifier(RangePair.first);\n" << " if (!I.hasValue())\n" @@ -963,7 +954,7 @@ void GICombinerEmitter::run(raw_ostream &OS) { OS << "bool " << getClassName() << "RuleConfig::setRule" << (Enabled ? "Enabled" : "Disabled") << "(StringRef RuleIdentifier) {\n" << " auto MaybeRange = getRuleRangeForIdentifier(RuleIdentifier);\n" - << " if(!MaybeRange.hasValue())\n" + << " if (!MaybeRange.hasValue())\n" << " return false;\n" << " for (auto I = MaybeRange->first; I < MaybeRange->second; ++I)\n" << " DisabledRules." << (Enabled ? "reset" : "set") << "(I);\n" @@ -1026,7 +1017,7 @@ void GICombinerEmitter::run(raw_ostream &OS) { << " MachineBasicBlock *MBB = MI.getParent();\n" << " MachineFunction *MF = MBB->getParent();\n" << " MachineRegisterInfo &MRI = MF->getRegInfo();\n" - << " SmallVector<MachineInstr *, 8> MIs = { &MI };\n\n" + << " SmallVector<MachineInstr *, 8> MIs = {&MI};\n\n" << " (void)MBB; (void)MF; (void)MRI; (void)RuleConfig;\n\n"; OS << " // Match data\n"; diff --git a/llvm/utils/TableGen/GlobalISel/CodeExpander.cpp b/llvm/utils/TableGen/GlobalISel/CodeExpander.cpp index d59a9b8e3b65..3ebb293f466e 100644 --- a/llvm/utils/TableGen/GlobalISel/CodeExpander.cpp +++ b/llvm/utils/TableGen/GlobalISel/CodeExpander.cpp @@ -58,21 +58,15 @@ void CodeExpander::emit(raw_ostream &OS) const { // Warn if we split because no terminator was found. StringRef EndVar = StartVar.drop_front(2 /* ${ */ + Var.size()); if (EndVar.empty()) { - size_t LocOffset = StartVar.data() - Code.data(); - PrintWarning( - Loc.size() > 0 && Loc[0].isValid() - ? SMLoc::getFromPointer(Loc[0].getPointer() + LocOffset) - : SMLoc(), - "Unterminated expansion"); + PrintWarning(Loc, "Unterminated expansion '${" + Var + "'"); + PrintNote("Code: [{" + Code + "}]"); } auto ValueI = Expansions.find(Var); if (ValueI == Expansions.end()) { - size_t LocOffset = StartVar.data() - Code.data(); - PrintError(Loc.size() > 0 && Loc[0].isValid() - ? SMLoc::getFromPointer(Loc[0].getPointer() + LocOffset) - : SMLoc(), - "Attempting to expand an undeclared variable " + Var); + PrintError(Loc, + "Attempt to expand an undeclared variable '" + Var + "'"); + PrintNote("Code: [{" + Code + "}]"); } if (ShowExpansions) OS << "/*$" << Var << "{*/"; @@ -82,11 +76,8 @@ void CodeExpander::emit(raw_ostream &OS) const { continue; } - size_t LocOffset = Current.data() - Code.data(); - PrintWarning(Loc.size() > 0 && Loc[0].isValid() - ? SMLoc::getFromPointer(Loc[0].getPointer() + LocOffset) - : SMLoc(), - "Assuming missing escape character"); + PrintWarning(Loc, "Assuming missing escape character: \\$"); + PrintNote("Code: [{" + Code + "}]"); OS << "$"; Current = Current.drop_front(1); } diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchDag.cpp b/llvm/utils/TableGen/GlobalISel/GIMatchDag.cpp index a3a9b7d8b037..7e037dd03b60 100644 --- a/llvm/utils/TableGen/GlobalISel/GIMatchDag.cpp +++ b/llvm/utils/TableGen/GlobalISel/GIMatchDag.cpp @@ -41,7 +41,7 @@ void GIMatchDag::writeDOTGraph(raw_ostream &OS, StringRef ID) const { SmallVector<std::pair<unsigned, StringRef>, 8> ToPrint; for (const auto &Assignment : N->user_assigned_operand_names()) ToPrint.emplace_back(Assignment.first, Assignment.second); - llvm::sort(ToPrint.begin(), ToPrint.end()); + llvm::sort(ToPrint); StringRef Separator = ""; for (const auto &Assignment : ToPrint) { OS << Separator << "$" << Assignment.second << "=getOperand(" diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchDagInstr.cpp b/llvm/utils/TableGen/GlobalISel/GIMatchDagInstr.cpp index 218b741be20c..ad9fbea8f881 100644 --- a/llvm/utils/TableGen/GlobalISel/GIMatchDagInstr.cpp +++ b/llvm/utils/TableGen/GlobalISel/GIMatchDagInstr.cpp @@ -27,7 +27,7 @@ void GIMatchDagInstr::print(raw_ostream &OS) const { SmallVector<std::pair<unsigned, StringRef>, 8> ToPrint; for (const auto &Assignment : UserAssignedNamesForOperands) ToPrint.emplace_back(Assignment.first, Assignment.second); - llvm::sort(ToPrint.begin(), ToPrint.end()); + llvm::sort(ToPrint); StringRef Separator = ""; for (const auto &Assignment : ToPrint) { OS << Separator << "$" << Assignment.second << "=getOperand(" diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp b/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp index 96dc4fc94893..d08a83333c30 100644 --- a/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp +++ b/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp @@ -121,8 +121,7 @@ void GIMatchTreeBuilderLeafInfo::declareInstr(const GIMatchDagInstr *Instr, unsi Info.bindOperandVariable(VarBinding.second, ID, VarBinding.first); // Clear the bit indicating we haven't visited this instr. - const auto &NodeI = std::find(MatchDag.instr_nodes_begin(), - MatchDag.instr_nodes_end(), Instr); + const auto &NodeI = find(MatchDag.instr_nodes(), Instr); assert(NodeI != MatchDag.instr_nodes_end() && "Instr isn't in this DAG"); unsigned InstrIdx = MatchDag.getInstrNodeIdx(NodeI); RemainingInstrNodes.reset(InstrIdx); @@ -266,11 +265,10 @@ void GIMatchTreeBuilder::runStep() { LLVM_DEBUG(dbgs() << "Leaf contains multiple rules, drop after the first " "fully tested rule\n"); auto FirstFullyTested = - std::find_if(Leaves.begin(), Leaves.end(), - [](const GIMatchTreeBuilderLeafInfo &X) { - return X.isFullyTraversed() && X.isFullyTested() && - !X.getMatchDag().hasPostMatchPredicate(); - }); + llvm::find_if(Leaves, [](const GIMatchTreeBuilderLeafInfo &X) { + return X.isFullyTraversed() && X.isFullyTested() && + !X.getMatchDag().hasPostMatchPredicate(); + }); if (FirstFullyTested != Leaves.end()) FirstFullyTested++; @@ -456,8 +454,7 @@ void GIMatchTreeOpcodePartitioner::repartition( // predicates for one instruction in the same DAG. That should be // impossible. assert(AllOpcodes && "Conflicting opcode predicates"); - for (const CodeGenInstruction *Expected : OpcodeP->getInstrs()) - OpcodesForThisPredicate.push_back(Expected); + append_range(OpcodesForThisPredicate, OpcodeP->getInstrs()); } for (const CodeGenInstruction *Expected : OpcodesForThisPredicate) { diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchTree.h b/llvm/utils/TableGen/GlobalISel/GIMatchTree.h index b86f6454589c..bf41a2e0e234 100644 --- a/llvm/utils/TableGen/GlobalISel/GIMatchTree.h +++ b/llvm/utils/TableGen/GlobalISel/GIMatchTree.h @@ -353,10 +353,7 @@ public: void declareOperand(unsigned InstrID, unsigned OpIdx); GIMatchTreeInstrInfo *getInstrInfo(unsigned ID) const { - auto I = InstrIDToInfo.find(ID); - if (I != InstrIDToInfo.end()) - return I->second; - return nullptr; + return InstrIDToInfo.lookup(ID); } void dump(raw_ostream &OS) const { diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp index 4e8dcc52fc20..0a6985a3eac2 100644 --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -187,17 +187,21 @@ class InstructionMatcher; static Optional<LLTCodeGen> MVTToLLT(MVT::SimpleValueType SVT) { MVT VT(SVT); - if (VT.isVector() && VT.getVectorNumElements() != 1) + if (VT.isScalableVector()) + return None; + + if (VT.isFixedLengthVector() && VT.getVectorNumElements() != 1) return LLTCodeGen( LLT::vector(VT.getVectorNumElements(), VT.getScalarSizeInBits())); if (VT.isInteger() || VT.isFloatingPoint()) return LLTCodeGen(LLT::scalar(VT.getSizeInBits())); + return None; } static std::string explainPredicates(const TreePatternNode *N) { - std::string Explanation = ""; + std::string Explanation; StringRef Separator = ""; for (const TreePredicateCall &Call : N->getPredicateCalls()) { const TreePredicateFn &P = Call.Fn; @@ -301,8 +305,8 @@ static Error failedImport(const Twine &Reason) { } static Error isTrivialOperatorNode(const TreePatternNode *N) { - std::string Explanation = ""; - std::string Separator = ""; + std::string Explanation; + std::string Separator; bool HasUnsupportedPredicate = false; for (const TreePredicateCall &Call : N->getPredicateCalls()) { @@ -389,6 +393,10 @@ getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset) { return Name; } +static std::string getScopedName(unsigned Scope, const std::string &Name) { + return ("pred:" + Twine(Scope) + ":" + Name).str(); +} + //===- MatchTable Helpers -------------------------------------------------===// class MatchTable; @@ -445,9 +453,8 @@ public: MatchTableRecord(Optional<unsigned> LabelID_, StringRef EmitStr, unsigned NumElements, unsigned Flags, int64_t RawValue = std::numeric_limits<int64_t>::min()) - : LabelID(LabelID_.hasValue() ? LabelID_.getValue() : ~0u), - EmitStr(EmitStr), NumElements(NumElements), Flags(Flags), - RawValue(RawValue) { + : LabelID(LabelID_.getValueOr(~0u)), EmitStr(EmitStr), + NumElements(NumElements), Flags(Flags), RawValue(RawValue) { assert((!LabelID_.hasValue() || LabelID != ~0u) && "This value is reserved for non-labels"); } @@ -852,6 +859,11 @@ protected: DefinedComplexPatternSubOperandMap; /// A map of Symbolic Names to ComplexPattern sub-operands. DefinedComplexPatternSubOperandMap ComplexSubOperands; + /// A map used to for multiple referenced error check of ComplexSubOperand. + /// ComplexSubOperand can't be referenced multiple from different operands, + /// however multiple references from same operand are allowed since that is + /// how 'same operand checks' are generated. + StringMap<std::string> ComplexSubOperandsParentName; uint64_t RuleID; static uint64_t NextRuleID; @@ -917,14 +929,25 @@ public: void definePhysRegOperand(Record *Reg, OperandMatcher &OM); Error defineComplexSubOperand(StringRef SymbolicName, Record *ComplexPattern, - unsigned RendererID, unsigned SubOperandID) { - if (ComplexSubOperands.count(SymbolicName)) - return failedImport( - "Complex suboperand referenced more than once (Operand: " + - SymbolicName + ")"); + unsigned RendererID, unsigned SubOperandID, + StringRef ParentSymbolicName) { + std::string ParentName(ParentSymbolicName); + if (ComplexSubOperands.count(SymbolicName)) { + const std::string &RecordedParentName = + ComplexSubOperandsParentName[SymbolicName]; + if (RecordedParentName != ParentName) + return failedImport("Error: Complex suboperand " + SymbolicName + + " referenced by different operands: " + + RecordedParentName + " and " + ParentName + "."); + // Complex suboperand referenced more than once from same the operand is + // used to generate 'same operand check'. Emitting of + // GIR_ComplexSubOperandRenderer for them is already handled. + return Error::success(); + } ComplexSubOperands[SymbolicName] = std::make_tuple(ComplexPattern, RendererID, SubOperandID); + ComplexSubOperandsParentName[SymbolicName] = ParentName; return Error::success(); } @@ -992,10 +1015,6 @@ protected: bool Optimized = false; public: - /// Construct a new predicate and add it to the matcher. - template <class Kind, class... Args> - Optional<Kind *> addPredicate(Args &&... args); - typename PredicatesTy::iterator predicates_begin() { return Predicates.begin(); } @@ -1089,6 +1108,7 @@ public: IPM_MemoryVsLLTSize, IPM_MemoryAddressSpace, IPM_MemoryAlignment, + IPM_VectorSplatImm, IPM_GenericPredicate, OPM_SameOperand, OPM_ComplexPattern, @@ -1101,6 +1121,7 @@ public: OPM_PointerToAny, OPM_RegBank, OPM_MBB, + OPM_RecordNamedOperand, }; protected: @@ -1270,10 +1291,15 @@ public: : OperandPredicateMatcher(OPM_PointerToAny, InsnVarID, OpIdx), SizeInBits(SizeInBits) {} - static bool classof(const OperandPredicateMatcher *P) { + static bool classof(const PredicateMatcher *P) { return P->getKind() == OPM_PointerToAny; } + bool isIdentical(const PredicateMatcher &B) const override { + return OperandPredicateMatcher::isIdentical(B) && + SizeInBits == cast<PointerToAnyOperandMatcher>(&B)->SizeInBits; + } + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { Table << MatchTable::Opcode("GIM_CheckPointerToAny") @@ -1284,6 +1310,40 @@ public: } }; +/// Generates code to record named operand in RecordedOperands list at StoreIdx. +/// Predicates with 'let PredicateCodeUsesOperands = 1' get RecordedOperands as +/// an argument to predicate's c++ code once all operands have been matched. +class RecordNamedOperandMatcher : public OperandPredicateMatcher { +protected: + unsigned StoreIdx; + std::string Name; + +public: + RecordNamedOperandMatcher(unsigned InsnVarID, unsigned OpIdx, + unsigned StoreIdx, StringRef Name) + : OperandPredicateMatcher(OPM_RecordNamedOperand, InsnVarID, OpIdx), + StoreIdx(StoreIdx), Name(Name) {} + + static bool classof(const PredicateMatcher *P) { + return P->getKind() == OPM_RecordNamedOperand; + } + + bool isIdentical(const PredicateMatcher &B) const override { + return OperandPredicateMatcher::isIdentical(B) && + StoreIdx == cast<RecordNamedOperandMatcher>(&B)->StoreIdx && + Name == cast<RecordNamedOperandMatcher>(&B)->Name; + } + + void emitPredicateOpcodes(MatchTable &Table, + RuleMatcher &Rule) const override { + Table << MatchTable::Opcode("GIM_RecordNamedOperand") + << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) + << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx) + << MatchTable::Comment("StoreIdx") << MatchTable::IntValue(StoreIdx) + << MatchTable::Comment("Name : " + Name) << MatchTable::LineBreak; + } +}; + /// Generates code to check that an operand is a particular target constant. class ComplexPatternOperandMatcher : public OperandPredicateMatcher { protected: @@ -1523,7 +1583,7 @@ public: AllocatedTemporariesBaseID(AllocatedTemporariesBaseID) {} bool hasSymbolicName() const { return !SymbolicName.empty(); } - const StringRef getSymbolicName() const { return SymbolicName; } + StringRef getSymbolicName() const { return SymbolicName; } void setSymbolicName(StringRef Name) { assert(SymbolicName.empty() && "Operand already has a symbolic name"); SymbolicName = std::string(Name); @@ -1670,10 +1730,23 @@ PredicateListMatcher<PredicateMatcher>::getNoPredicateComment() const { /// Generates code to check the opcode of an instruction. class InstructionOpcodeMatcher : public InstructionPredicateMatcher { protected: - const CodeGenInstruction *I; + // Allow matching one to several, similar opcodes that share properties. This + // is to handle patterns where one SelectionDAG operation maps to multiple + // GlobalISel ones (e.g. G_BUILD_VECTOR and G_BUILD_VECTOR_TRUNC). The first + // is treated as the canonical opcode. + SmallVector<const CodeGenInstruction *, 2> Insts; static DenseMap<const CodeGenInstruction *, unsigned> OpcodeValues; + + MatchTableRecord getInstValue(const CodeGenInstruction *I) const { + const auto VI = OpcodeValues.find(I); + if (VI != OpcodeValues.end()) + return MatchTable::NamedValue(I->Namespace, I->TheDef->getName(), + VI->second); + return MatchTable::NamedValue(I->Namespace, I->TheDef->getName()); + } + public: static void initOpcodeValuesMap(const CodeGenTarget &Target) { OpcodeValues.clear(); @@ -1683,8 +1756,13 @@ public: OpcodeValues[I] = OpcodeValue++; } - InstructionOpcodeMatcher(unsigned InsnVarID, const CodeGenInstruction *I) - : InstructionPredicateMatcher(IPM_Opcode, InsnVarID), I(I) {} + InstructionOpcodeMatcher(unsigned InsnVarID, + ArrayRef<const CodeGenInstruction *> I) + : InstructionPredicateMatcher(IPM_Opcode, InsnVarID), + Insts(I.begin(), I.end()) { + assert((Insts.size() == 1 || Insts.size() == 2) && + "unexpected number of opcode alternatives"); + } static bool classof(const PredicateMatcher *P) { return P->getKind() == IPM_Opcode; @@ -1692,22 +1770,36 @@ public: bool isIdentical(const PredicateMatcher &B) const override { return InstructionPredicateMatcher::isIdentical(B) && - I == cast<InstructionOpcodeMatcher>(&B)->I; + Insts == cast<InstructionOpcodeMatcher>(&B)->Insts; } + + bool hasValue() const override { + return Insts.size() == 1 && OpcodeValues.count(Insts[0]); + } + + // TODO: This is used for the SwitchMatcher optimization. We should be able to + // return a list of the opcodes to match. MatchTableRecord getValue() const override { + assert(Insts.size() == 1); + + const CodeGenInstruction *I = Insts[0]; const auto VI = OpcodeValues.find(I); if (VI != OpcodeValues.end()) return MatchTable::NamedValue(I->Namespace, I->TheDef->getName(), VI->second); return MatchTable::NamedValue(I->Namespace, I->TheDef->getName()); } - bool hasValue() const override { return OpcodeValues.count(I); } void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { - Table << MatchTable::Opcode("GIM_CheckOpcode") << MatchTable::Comment("MI") - << MatchTable::IntValue(InsnVarID) << getValue() - << MatchTable::LineBreak; + StringRef CheckType = Insts.size() == 1 ? + "GIM_CheckOpcode" : "GIM_CheckOpcodeIsEither"; + Table << MatchTable::Opcode(CheckType) << MatchTable::Comment("MI") + << MatchTable::IntValue(InsnVarID); + + for (const CodeGenInstruction *I : Insts) + Table << getInstValue(I); + Table << MatchTable::LineBreak; } /// Compare the priority of this object and B. @@ -1725,20 +1817,32 @@ public: // using instruction frequency information to improve compile time. if (const InstructionOpcodeMatcher *BO = dyn_cast<InstructionOpcodeMatcher>(&B)) - return I->TheDef->getName() < BO->I->TheDef->getName(); + return Insts[0]->TheDef->getName() < BO->Insts[0]->TheDef->getName(); return false; }; bool isConstantInstruction() const { - return I->TheDef->getName() == "G_CONSTANT"; + return Insts.size() == 1 && Insts[0]->TheDef->getName() == "G_CONSTANT"; } - StringRef getOpcode() const { return I->TheDef->getName(); } - bool isVariadicNumOperands() const { return I->Operands.isVariadic; } + // The first opcode is the canonical opcode, and later are alternatives. + StringRef getOpcode() const { + return Insts[0]->TheDef->getName(); + } + + ArrayRef<const CodeGenInstruction *> getAlternativeOpcodes() { + return Insts; + } + + bool isVariadicNumOperands() const { + // If one is variadic, they all should be. + return Insts[0]->Operands.isVariadic; + } StringRef getOperandType(unsigned OpIdx) const { - return I->Operands[OpIdx].OperandType; + // Types expected to be uniform for all alternatives. + return Insts[0]->Operands[OpIdx].OperandType; } }; @@ -2021,6 +2125,42 @@ public: } }; +// Matcher for immAllOnesV/immAllZerosV +class VectorSplatImmPredicateMatcher : public InstructionPredicateMatcher { +public: + enum SplatKind { + AllZeros, + AllOnes + }; + +private: + SplatKind Kind; + +public: + VectorSplatImmPredicateMatcher(unsigned InsnVarID, SplatKind K) + : InstructionPredicateMatcher(IPM_VectorSplatImm, InsnVarID), Kind(K) {} + + static bool classof(const PredicateMatcher *P) { + return P->getKind() == IPM_VectorSplatImm; + } + + bool isIdentical(const PredicateMatcher &B) const override { + return InstructionPredicateMatcher::isIdentical(B) && + Kind == static_cast<const VectorSplatImmPredicateMatcher &>(B).Kind; + } + + void emitPredicateOpcodes(MatchTable &Table, + RuleMatcher &Rule) const override { + if (Kind == AllOnes) + Table << MatchTable::Opcode("GIM_CheckIsBuildVectorAllOnes"); + else + Table << MatchTable::Opcode("GIM_CheckIsBuildVectorAllZeros"); + + Table << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID); + Table << MatchTable::LineBreak; + } +}; + /// Generates code to check an arbitrary C++ instruction predicate. class GenericInstructionPredicateMatcher : public InstructionPredicateMatcher { protected: @@ -2077,8 +2217,9 @@ protected: SmallVector<std::pair<Record *, unsigned>, 2> PhysRegInputs; public: - InstructionMatcher(RuleMatcher &Rule, StringRef SymbolicName) - : Rule(Rule), SymbolicName(SymbolicName) { + InstructionMatcher(RuleMatcher &Rule, StringRef SymbolicName, + bool NumOpsCheck = true) + : Rule(Rule), NumOperandsCheck(NumOpsCheck), SymbolicName(SymbolicName) { // We create a new instruction matcher. // Get a new ID for that instruction. InsnVarID = Rule.implicitlyDefineInsnVar(*this); @@ -2108,10 +2249,10 @@ public: } OperandMatcher &getOperand(unsigned OpIdx) { - auto I = std::find_if(Operands.begin(), Operands.end(), - [&OpIdx](const std::unique_ptr<OperandMatcher> &X) { - return X->getOpIdx() == OpIdx; - }); + auto I = llvm::find_if(Operands, + [&OpIdx](const std::unique_ptr<OperandMatcher> &X) { + return X->getOpIdx() == OpIdx; + }); if (I != Operands.end()) return **I; llvm_unreachable("Failed to lookup operand"); @@ -2267,9 +2408,10 @@ protected: public: InstructionOperandMatcher(unsigned InsnVarID, unsigned OpIdx, - RuleMatcher &Rule, StringRef SymbolicName) + RuleMatcher &Rule, StringRef SymbolicName, + bool NumOpsCheck = true) : OperandPredicateMatcher(OPM_Instruction, InsnVarID, OpIdx), - InsnMatcher(new InstructionMatcher(Rule, SymbolicName)) {} + InsnMatcher(new InstructionMatcher(Rule, SymbolicName, NumOpsCheck)) {} static bool classof(const PredicateMatcher *P) { return P->getKind() == OPM_Instruction; @@ -2395,7 +2537,7 @@ public: return R->getKind() == OR_Copy; } - const StringRef getSymbolicName() const { return SymbolicName; } + StringRef getSymbolicName() const { return SymbolicName; } void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName); @@ -2462,7 +2604,7 @@ public: return R->getKind() == OR_CopyOrAddZeroReg; } - const StringRef getSymbolicName() const { return SymbolicName; } + StringRef getSymbolicName() const { return SymbolicName; } void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName); @@ -2499,7 +2641,7 @@ public: return R->getKind() == OR_CopyConstantAsImm; } - const StringRef getSymbolicName() const { return SymbolicName; } + StringRef getSymbolicName() const { return SymbolicName; } void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName); @@ -2530,7 +2672,7 @@ public: return R->getKind() == OR_CopyFConstantAsFPImm; } - const StringRef getSymbolicName() const { return SymbolicName; } + StringRef getSymbolicName() const { return SymbolicName; } void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName); @@ -2564,7 +2706,7 @@ public: return R->getKind() == OR_CopySubReg; } - const StringRef getSymbolicName() const { return SymbolicName; } + StringRef getSymbolicName() const { return SymbolicName; } void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName); @@ -2587,12 +2729,13 @@ protected: unsigned InsnID; const Record *RegisterDef; bool IsDef; + const CodeGenTarget &Target; public: - AddRegisterRenderer(unsigned InsnID, const Record *RegisterDef, - bool IsDef = false) + AddRegisterRenderer(unsigned InsnID, const CodeGenTarget &Target, + const Record *RegisterDef, bool IsDef = false) : OperandRenderer(OR_Register), InsnID(InsnID), RegisterDef(RegisterDef), - IsDef(IsDef) {} + IsDef(IsDef), Target(Target) {} static bool classof(const OperandRenderer *R) { return R->getKind() == OR_Register; @@ -2600,13 +2743,17 @@ public: void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { Table << MatchTable::Opcode("GIR_AddRegister") - << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID) - << MatchTable::NamedValue( - (RegisterDef->getValue("Namespace") - ? RegisterDef->getValueAsString("Namespace") - : ""), - RegisterDef->getName()) - << MatchTable::Comment("AddRegisterRegFlags"); + << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID); + if (RegisterDef->getName() != "zero_reg") { + Table << MatchTable::NamedValue( + (RegisterDef->getValue("Namespace") + ? RegisterDef->getValueAsString("Namespace") + : ""), + RegisterDef->getName()); + } else { + Table << MatchTable::NamedValue(Target.getRegNamespace(), "NoRegister"); + } + Table << MatchTable::Comment("AddRegisterRegFlags"); // TODO: This is encoded as a 64-bit element, but only 16 or 32-bits are // really needed for a physical register reference. We can pack the @@ -2628,12 +2775,14 @@ protected: unsigned TempRegID; const CodeGenSubRegIndex *SubRegIdx; bool IsDef; + bool IsDead; public: TempRegRenderer(unsigned InsnID, unsigned TempRegID, bool IsDef = false, - const CodeGenSubRegIndex *SubReg = nullptr) + const CodeGenSubRegIndex *SubReg = nullptr, + bool IsDead = false) : OperandRenderer(OR_Register), InsnID(InsnID), TempRegID(TempRegID), - SubRegIdx(SubReg), IsDef(IsDef) {} + SubRegIdx(SubReg), IsDef(IsDef), IsDead(IsDead) {} static bool classof(const OperandRenderer *R) { return R->getKind() == OR_TempRegister; @@ -2650,9 +2799,13 @@ public: << MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID) << MatchTable::Comment("TempRegFlags"); - if (IsDef) - Table << MatchTable::NamedValue("RegState::Define"); - else + if (IsDef) { + SmallString<32> RegFlags; + RegFlags += "RegState::Define"; + if (IsDead) + RegFlags += "|RegState::Dead"; + Table << MatchTable::NamedValue(RegFlags); + } else Table << MatchTable::IntValue(0); if (SubRegIdx) @@ -3365,6 +3518,16 @@ private: // Rule coverage information. Optional<CodeGenCoverage> RuleCoverage; + /// Variables used to help with collecting of named operands for predicates + /// with 'let PredicateCodeUsesOperands = 1'. WaitingForNamedOperands is set + /// to the number of named operands that predicate expects. Store locations in + /// StoreIdxForName correspond to the order in which operand names appear in + /// predicate's argument list. + /// When we visit named leaf operand and WaitingForNamedOperands is not zero, + /// add matcher that will record operand and decrease counter. + unsigned WaitingForNamedOperands = 0; + StringMap<unsigned> StoreIdxForName; + void gatherOpcodeValues(); void gatherTypeIDValues(); void gatherNodeEquivs(); @@ -3394,7 +3557,11 @@ private: Expected<action_iterator> createInstructionRenderer(action_iterator InsertPt, RuleMatcher &M, const TreePatternNode *Dst); - void importExplicitDefRenderers(BuildMIAction &DstMIBuilder); + + Expected<action_iterator> + importExplicitDefRenderers(action_iterator InsertPt, RuleMatcher &M, + BuildMIAction &DstMIBuilder, + const TreePatternNode *Dst); Expected<action_iterator> importExplicitUseRenderers(action_iterator InsertPt, RuleMatcher &M, @@ -3413,7 +3580,8 @@ private: void emitCxxPredicateFns(raw_ostream &OS, StringRef CodeFieldName, StringRef TypeIdentifier, StringRef ArgType, - StringRef ArgName, StringRef AdditionalDeclarations, + StringRef ArgName, StringRef AdditionalArgs, + StringRef AdditionalDeclarations, std::function<bool(const Record *R)> Filter); void emitImmPredicateFns(raw_ostream &OS, StringRef TypeIdentifier, StringRef ArgType, @@ -3455,6 +3623,12 @@ private: Optional<const CodeGenRegisterClass *> inferRegClassFromPattern(TreePatternNode *N); + // Add builtin predicates. + Expected<InstructionMatcher &> + addBuiltinPredicates(const Record *SrcGIEquivOrNull, + const TreePredicateFn &Predicate, + InstructionMatcher &InsnMatcher, bool &HasAddedMatcher); + public: /// Takes a sequence of \p Rules and group them based on the predicates /// they share. \p MatcherStorage is used as a memory container @@ -3562,6 +3736,147 @@ GlobalISelEmitter::importRulePredicates(RuleMatcher &M, return Error::success(); } +Expected<InstructionMatcher &> GlobalISelEmitter::addBuiltinPredicates( + const Record *SrcGIEquivOrNull, const TreePredicateFn &Predicate, + InstructionMatcher &InsnMatcher, bool &HasAddedMatcher) { + if (Predicate.isLoad() || Predicate.isStore() || Predicate.isAtomic()) { + if (const ListInit *AddrSpaces = Predicate.getAddressSpaces()) { + SmallVector<unsigned, 4> ParsedAddrSpaces; + + for (Init *Val : AddrSpaces->getValues()) { + IntInit *IntVal = dyn_cast<IntInit>(Val); + if (!IntVal) + return failedImport("Address space is not an integer"); + ParsedAddrSpaces.push_back(IntVal->getValue()); + } + + if (!ParsedAddrSpaces.empty()) { + InsnMatcher.addPredicate<MemoryAddressSpacePredicateMatcher>( + 0, ParsedAddrSpaces); + } + } + + int64_t MinAlign = Predicate.getMinAlignment(); + if (MinAlign > 0) + InsnMatcher.addPredicate<MemoryAlignmentPredicateMatcher>(0, MinAlign); + } + + // G_LOAD is used for both non-extending and any-extending loads. + if (Predicate.isLoad() && Predicate.isNonExtLoad()) { + InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>( + 0, MemoryVsLLTSizePredicateMatcher::EqualTo, 0); + return InsnMatcher; + } + if (Predicate.isLoad() && Predicate.isAnyExtLoad()) { + InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>( + 0, MemoryVsLLTSizePredicateMatcher::LessThan, 0); + return InsnMatcher; + } + + if (Predicate.isStore()) { + if (Predicate.isTruncStore()) { + // FIXME: If MemoryVT is set, we end up with 2 checks for the MMO size. + InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>( + 0, MemoryVsLLTSizePredicateMatcher::LessThan, 0); + return InsnMatcher; + } + if (Predicate.isNonTruncStore()) { + // We need to check the sizes match here otherwise we could incorrectly + // match truncating stores with non-truncating ones. + InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>( + 0, MemoryVsLLTSizePredicateMatcher::EqualTo, 0); + } + } + + // No check required. We already did it by swapping the opcode. + if (!SrcGIEquivOrNull->isValueUnset("IfSignExtend") && + Predicate.isSignExtLoad()) + return InsnMatcher; + + // No check required. We already did it by swapping the opcode. + if (!SrcGIEquivOrNull->isValueUnset("IfZeroExtend") && + Predicate.isZeroExtLoad()) + return InsnMatcher; + + // No check required. G_STORE by itself is a non-extending store. + if (Predicate.isNonTruncStore()) + return InsnMatcher; + + if (Predicate.isLoad() || Predicate.isStore() || Predicate.isAtomic()) { + if (Predicate.getMemoryVT() != nullptr) { + Optional<LLTCodeGen> MemTyOrNone = + MVTToLLT(getValueType(Predicate.getMemoryVT())); + + if (!MemTyOrNone) + return failedImport("MemVT could not be converted to LLT"); + + // MMO's work in bytes so we must take care of unusual types like i1 + // don't round down. + unsigned MemSizeInBits = + llvm::alignTo(MemTyOrNone->get().getSizeInBits(), 8); + + InsnMatcher.addPredicate<MemorySizePredicateMatcher>(0, + MemSizeInBits / 8); + return InsnMatcher; + } + } + + if (Predicate.isLoad() || Predicate.isStore()) { + // No check required. A G_LOAD/G_STORE is an unindexed load. + if (Predicate.isUnindexed()) + return InsnMatcher; + } + + if (Predicate.isAtomic()) { + if (Predicate.isAtomicOrderingMonotonic()) { + InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("Monotonic"); + return InsnMatcher; + } + if (Predicate.isAtomicOrderingAcquire()) { + InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("Acquire"); + return InsnMatcher; + } + if (Predicate.isAtomicOrderingRelease()) { + InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("Release"); + return InsnMatcher; + } + if (Predicate.isAtomicOrderingAcquireRelease()) { + InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>( + "AcquireRelease"); + return InsnMatcher; + } + if (Predicate.isAtomicOrderingSequentiallyConsistent()) { + InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>( + "SequentiallyConsistent"); + return InsnMatcher; + } + } + + if (Predicate.isAtomicOrderingAcquireOrStronger()) { + InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>( + "Acquire", AtomicOrderingMMOPredicateMatcher::AO_OrStronger); + return InsnMatcher; + } + if (Predicate.isAtomicOrderingWeakerThanAcquire()) { + InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>( + "Acquire", AtomicOrderingMMOPredicateMatcher::AO_WeakerThan); + return InsnMatcher; + } + + if (Predicate.isAtomicOrderingReleaseOrStronger()) { + InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>( + "Release", AtomicOrderingMMOPredicateMatcher::AO_OrStronger); + return InsnMatcher; + } + if (Predicate.isAtomicOrderingWeakerThanRelease()) { + InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>( + "Release", AtomicOrderingMMOPredicateMatcher::AO_WeakerThan); + return InsnMatcher; + } + HasAddedMatcher = false; + return InsnMatcher; +} + Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher( RuleMatcher &Rule, InstructionMatcher &InsnMatcher, const TreePatternNode *Src, unsigned &TempOpIdx) { @@ -3603,6 +3918,7 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher( for (const TreePredicateCall &Call : Src->getPredicateCalls()) { const TreePredicateFn &Predicate = Call.Fn; + bool HasAddedBuiltinMatcher = true; if (Predicate.isAlwaysTrue()) continue; @@ -3611,154 +3927,35 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher( continue; } - // An address space check is needed in all contexts if there is one. - if (Predicate.isLoad() || Predicate.isStore() || Predicate.isAtomic()) { - if (const ListInit *AddrSpaces = Predicate.getAddressSpaces()) { - SmallVector<unsigned, 4> ParsedAddrSpaces; - - for (Init *Val : AddrSpaces->getValues()) { - IntInit *IntVal = dyn_cast<IntInit>(Val); - if (!IntVal) - return failedImport("Address space is not an integer"); - ParsedAddrSpaces.push_back(IntVal->getValue()); - } - - if (!ParsedAddrSpaces.empty()) { - InsnMatcher.addPredicate<MemoryAddressSpacePredicateMatcher>( - 0, ParsedAddrSpaces); - } - } - - int64_t MinAlign = Predicate.getMinAlignment(); - if (MinAlign > 0) - InsnMatcher.addPredicate<MemoryAlignmentPredicateMatcher>(0, MinAlign); - } - - // G_LOAD is used for both non-extending and any-extending loads. - if (Predicate.isLoad() && Predicate.isNonExtLoad()) { - InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>( - 0, MemoryVsLLTSizePredicateMatcher::EqualTo, 0); - continue; - } - if (Predicate.isLoad() && Predicate.isAnyExtLoad()) { - InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>( - 0, MemoryVsLLTSizePredicateMatcher::LessThan, 0); - continue; - } - - if (Predicate.isStore()) { - if (Predicate.isTruncStore()) { - // FIXME: If MemoryVT is set, we end up with 2 checks for the MMO size. - InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>( - 0, MemoryVsLLTSizePredicateMatcher::LessThan, 0); - continue; - } - if (Predicate.isNonTruncStore()) { - // We need to check the sizes match here otherwise we could incorrectly - // match truncating stores with non-truncating ones. - InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>( - 0, MemoryVsLLTSizePredicateMatcher::EqualTo, 0); - } - } - - // No check required. We already did it by swapping the opcode. - if (!SrcGIEquivOrNull->isValueUnset("IfSignExtend") && - Predicate.isSignExtLoad()) - continue; - - // No check required. We already did it by swapping the opcode. - if (!SrcGIEquivOrNull->isValueUnset("IfZeroExtend") && - Predicate.isZeroExtLoad()) - continue; - - // No check required. G_STORE by itself is a non-extending store. - if (Predicate.isNonTruncStore()) - continue; - - if (Predicate.isLoad() || Predicate.isStore() || Predicate.isAtomic()) { - if (Predicate.getMemoryVT() != nullptr) { - Optional<LLTCodeGen> MemTyOrNone = - MVTToLLT(getValueType(Predicate.getMemoryVT())); - - if (!MemTyOrNone) - return failedImport("MemVT could not be converted to LLT"); - - // MMO's work in bytes so we must take care of unusual types like i1 - // don't round down. - unsigned MemSizeInBits = - llvm::alignTo(MemTyOrNone->get().getSizeInBits(), 8); - - InsnMatcher.addPredicate<MemorySizePredicateMatcher>( - 0, MemSizeInBits / 8); - continue; - } - } - - if (Predicate.isLoad() || Predicate.isStore()) { - // No check required. A G_LOAD/G_STORE is an unindexed load. - if (Predicate.isUnindexed()) - continue; - } - - if (Predicate.isAtomic()) { - if (Predicate.isAtomicOrderingMonotonic()) { - InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>( - "Monotonic"); - continue; - } - if (Predicate.isAtomicOrderingAcquire()) { - InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("Acquire"); - continue; - } - if (Predicate.isAtomicOrderingRelease()) { - InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("Release"); - continue; - } - if (Predicate.isAtomicOrderingAcquireRelease()) { - InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>( - "AcquireRelease"); - continue; - } - if (Predicate.isAtomicOrderingSequentiallyConsistent()) { - InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>( - "SequentiallyConsistent"); - continue; - } - - if (Predicate.isAtomicOrderingAcquireOrStronger()) { - InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>( - "Acquire", AtomicOrderingMMOPredicateMatcher::AO_OrStronger); - continue; - } - if (Predicate.isAtomicOrderingWeakerThanAcquire()) { - InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>( - "Acquire", AtomicOrderingMMOPredicateMatcher::AO_WeakerThan); - continue; - } - - if (Predicate.isAtomicOrderingReleaseOrStronger()) { - InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>( - "Release", AtomicOrderingMMOPredicateMatcher::AO_OrStronger); - continue; - } - if (Predicate.isAtomicOrderingWeakerThanRelease()) { - InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>( - "Release", AtomicOrderingMMOPredicateMatcher::AO_WeakerThan); - continue; - } - } + auto InsnMatcherOrError = addBuiltinPredicates( + SrcGIEquivOrNull, Predicate, InsnMatcher, HasAddedBuiltinMatcher); + if (auto Error = InsnMatcherOrError.takeError()) + return std::move(Error); if (Predicate.hasGISelPredicateCode()) { + if (Predicate.usesOperands()) { + assert(WaitingForNamedOperands == 0 && + "previous predicate didn't find all operands or " + "nested predicate that uses operands"); + TreePattern *TP = Predicate.getOrigPatFragRecord(); + WaitingForNamedOperands = TP->getNumArgs(); + for (unsigned i = 0; i < WaitingForNamedOperands; ++i) + StoreIdxForName[getScopedName(Call.Scope, TP->getArgName(i))] = i; + } InsnMatcher.addPredicate<GenericInstructionPredicateMatcher>(Predicate); continue; } - - return failedImport("Src pattern child has predicate (" + - explainPredicates(Src) + ")"); + if (!HasAddedBuiltinMatcher) { + return failedImport("Src pattern child has predicate (" + + explainPredicates(Src) + ")"); + } } + + bool IsAtomic = false; if (SrcGIEquivOrNull && SrcGIEquivOrNull->getValueAsBit("CheckMMOIsNonAtomic")) InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("NotAtomic"); else if (SrcGIEquivOrNull && SrcGIEquivOrNull->getValueAsBit("CheckMMOIsAtomic")) { + IsAtomic = true; InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>( "Unordered", AtomicOrderingMMOPredicateMatcher::AO_OrStronger); } @@ -3812,6 +4009,27 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher( } } + // Hack around an unfortunate mistake in how atomic store (and really + // atomicrmw in general) operands were ordered. A ISD::STORE used the order + // <stored value>, <pointer> order. ISD::ATOMIC_STORE used the opposite, + // <pointer>, <stored value>. In GlobalISel there's just the one store + // opcode, so we need to swap the operands here to get the right type check. + if (IsAtomic && SrcGIOrNull->TheDef->getName() == "G_STORE") { + assert(NumChildren == 2 && "wrong operands for atomic store"); + + TreePatternNode *PtrChild = Src->getChild(0); + TreePatternNode *ValueChild = Src->getChild(1); + + if (auto Error = importChildMatcher(Rule, InsnMatcher, PtrChild, true, + false, 1, TempOpIdx)) + return std::move(Error); + + if (auto Error = importChildMatcher(Rule, InsnMatcher, ValueChild, false, + false, 0, TempOpIdx)) + return std::move(Error); + return InsnMatcher; + } + // Match the used operands (i.e. the children of the operator). bool IsIntrinsic = SrcGIOrNull->TheDef->getName() == "G_INTRINSIC" || @@ -3902,12 +4120,22 @@ Error GlobalISelEmitter::importChildMatcher( bool OperandIsImmArg, unsigned OpIdx, unsigned &TempOpIdx) { Record *PhysReg = nullptr; - StringRef SrcChildName = getSrcChildName(SrcChild, PhysReg); + std::string SrcChildName = std::string(getSrcChildName(SrcChild, PhysReg)); + if (!SrcChild->isLeaf() && + SrcChild->getOperator()->isSubClassOf("ComplexPattern")) { + // The "name" of a non-leaf complex pattern (MY_PAT $op1, $op2) is + // "MY_PAT:op1:op2" and the ones with same "name" represent same operand. + std::string PatternName = std::string(SrcChild->getOperator()->getName()); + for (unsigned i = 0; i < SrcChild->getNumChildren(); ++i) { + PatternName += ":"; + PatternName += SrcChild->getChild(i)->getName(); + } + SrcChildName = PatternName; + } OperandMatcher &OM = - PhysReg - ? InsnMatcher.addPhysRegInput(PhysReg, OpIdx, TempOpIdx) - : InsnMatcher.addOperand(OpIdx, std::string(SrcChildName), TempOpIdx); + PhysReg ? InsnMatcher.addPhysRegInput(PhysReg, OpIdx, TempOpIdx) + : InsnMatcher.addOperand(OpIdx, SrcChildName, TempOpIdx); if (OM.isSameAsAnotherOperand()) return Error::success(); @@ -3954,9 +4182,9 @@ Error GlobalISelEmitter::importChildMatcher( for (unsigned i = 0, e = SrcChild->getNumChildren(); i != e; ++i) { auto *SubOperand = SrcChild->getChild(i); if (!SubOperand->getName().empty()) { - if (auto Error = Rule.defineComplexSubOperand(SubOperand->getName(), - SrcChild->getOperator(), - RendererID, i)) + if (auto Error = Rule.defineComplexSubOperand( + SubOperand->getName(), SrcChild->getOperator(), RendererID, i, + SrcChildName)) return Error; } } @@ -4002,6 +4230,13 @@ Error GlobalISelEmitter::importChildMatcher( if (auto *ChildDefInit = dyn_cast<DefInit>(SrcChild->getLeafValue())) { auto *ChildRec = ChildDefInit->getDef(); + if (WaitingForNamedOperands) { + auto PA = SrcChild->getNamesAsPredicateArg().begin(); + std::string Name = getScopedName(PA->getScope(), PA->getIdentifier()); + OM.addPredicate<RecordNamedOperandMatcher>(StoreIdxForName[Name], Name); + --WaitingForNamedOperands; + } + // Check for register classes. if (ChildRec->isSubClassOf("RegisterClass") || ChildRec->isSubClassOf("RegisterOperand")) { @@ -4044,6 +4279,40 @@ Error GlobalISelEmitter::importChildMatcher( if (ChildRec->getName() == "srcvalue") return Error::success(); + const bool ImmAllOnesV = ChildRec->getName() == "immAllOnesV"; + if (ImmAllOnesV || ChildRec->getName() == "immAllZerosV") { + auto MaybeInsnOperand = OM.addPredicate<InstructionOperandMatcher>( + InsnMatcher.getRuleMatcher(), SrcChild->getName(), false); + InstructionOperandMatcher &InsnOperand = **MaybeInsnOperand; + + ValueTypeByHwMode VTy = ChildTypes.front().getValueTypeByHwMode(); + + const CodeGenInstruction &BuildVector + = Target.getInstruction(RK.getDef("G_BUILD_VECTOR")); + const CodeGenInstruction &BuildVectorTrunc + = Target.getInstruction(RK.getDef("G_BUILD_VECTOR_TRUNC")); + + // Treat G_BUILD_VECTOR as the canonical opcode, and G_BUILD_VECTOR_TRUNC + // as an alternative. + InsnOperand.getInsnMatcher().addPredicate<InstructionOpcodeMatcher>( + makeArrayRef({&BuildVector, &BuildVectorTrunc})); + + // TODO: Handle both G_BUILD_VECTOR and G_BUILD_VECTOR_TRUNC We could + // theoretically not emit any opcode check, but getOpcodeMatcher currently + // has to succeed. + OperandMatcher &OM = + InsnOperand.getInsnMatcher().addOperand(0, "", TempOpIdx); + if (auto Error = + OM.addTypeCheckPredicate(VTy, false /* OperandIsAPointer */)) + return failedImport(toString(std::move(Error)) + + " for result of Src pattern operator"); + + InsnOperand.getInsnMatcher().addPredicate<VectorSplatImmPredicateMatcher>( + ImmAllOnesV ? VectorSplatImmPredicateMatcher::AllOnes + : VectorSplatImmPredicateMatcher::AllZeros); + return Error::success(); + } + return failedImport( "Src pattern child def is an unsupported tablegen class"); } @@ -4155,7 +4424,7 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer( return failedImport("Dst operand has an unsupported type"); if (ChildRec->isSubClassOf("Register")) { - DstMIBuilder.addRenderer<AddRegisterRenderer>(ChildRec); + DstMIBuilder.addRenderer<AddRegisterRenderer>(Target, ChildRec); return InsertPt; } @@ -4215,12 +4484,15 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer( &Target.getInstruction(RK.getDef("COPY"))); BuildMIAction &CopyToPhysRegMIBuilder = *static_cast<BuildMIAction *>(InsertPt->get()); - CopyToPhysRegMIBuilder.addRenderer<AddRegisterRenderer>(PhysInput.first, + CopyToPhysRegMIBuilder.addRenderer<AddRegisterRenderer>(Target, + PhysInput.first, true); CopyToPhysRegMIBuilder.addRenderer<CopyPhysRegRenderer>(PhysInput.first); } - importExplicitDefRenderers(DstMIBuilder); + if (auto Error = importExplicitDefRenderers(InsertPt, M, DstMIBuilder, Dst) + .takeError()) + return std::move(Error); if (auto Error = importExplicitUseRenderers(InsertPt, M, DstMIBuilder, Dst) .takeError()) @@ -4372,13 +4644,39 @@ Expected<action_iterator> GlobalISelEmitter::createInstructionRenderer( DstI); } -void GlobalISelEmitter::importExplicitDefRenderers( - BuildMIAction &DstMIBuilder) { +Expected<action_iterator> GlobalISelEmitter::importExplicitDefRenderers( + action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder, + const TreePatternNode *Dst) { const CodeGenInstruction *DstI = DstMIBuilder.getCGI(); - for (unsigned I = 0; I < DstI->Operands.NumDefs; ++I) { - const CGIOperandList::OperandInfo &DstIOperand = DstI->Operands[I]; - DstMIBuilder.addRenderer<CopyRenderer>(DstIOperand.Name); + const unsigned NumDefs = DstI->Operands.NumDefs; + if (NumDefs == 0) + return InsertPt; + + DstMIBuilder.addRenderer<CopyRenderer>(DstI->Operands[0].Name); + + // Some instructions have multiple defs, but are missing a type entry + // (e.g. s_cc_out operands). + if (Dst->getExtTypes().size() < NumDefs) + return failedImport("unhandled discarded def"); + + // Patterns only handle a single result, so any result after the first is an + // implicitly dead def. + for (unsigned I = 1; I < NumDefs; ++I) { + const TypeSetByHwMode &ExtTy = Dst->getExtType(I); + if (!ExtTy.isMachineValueType()) + return failedImport("unsupported typeset"); + + auto OpTy = MVTToLLT(ExtTy.getMachineValueType().SimpleTy); + if (!OpTy) + return failedImport("unsupported type"); + + unsigned TempRegID = M.allocateTempRegID(); + InsertPt = + M.insertAction<MakeTempRegisterAction>(InsertPt, *OpTy, TempRegID); + DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID, true, nullptr, true); } + + return InsertPt; } Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers( @@ -4392,6 +4690,8 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers( // EXTRACT_SUBREG needs to use a subregister COPY. if (Name == "EXTRACT_SUBREG") { + if (!Dst->getChild(1)->isLeaf()) + return failedImport("EXTRACT_SUBREG child #1 is not a leaf"); DefInit *SubRegInit = dyn_cast<DefInit>(Dst->getChild(1)->getLeafValue()); if (!SubRegInit) return failedImport("EXTRACT_SUBREG child #1 is not a subreg index"); @@ -4578,7 +4878,7 @@ Error GlobalISelEmitter::importDefaultOperandRenderers( IDMIBuilder.addRenderer<TempRegRenderer>(TempRegID); DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID); } else { - DstMIBuilder.addRenderer<AddRegisterRenderer>(Def); + DstMIBuilder.addRenderer<AddRegisterRenderer>(Target, Def); } continue; } @@ -4653,6 +4953,17 @@ GlobalISelEmitter::inferRegClassFromPattern(TreePatternNode *N) { return None; return getRegClassFromLeaf(RCChild); } + if (InstName == "INSERT_SUBREG") { + TreePatternNode *Child0 = N->getChild(0); + assert(Child0->getNumTypes() == 1 && "Unexpected number of types!"); + const TypeSetByHwMode &VTy = Child0->getExtType(0); + return inferSuperRegisterClassForNode(VTy, Child0, N->getChild(2)); + } + if (InstName == "EXTRACT_SUBREG") { + assert(N->getNumTypes() == 1 && "Unexpected number of types!"); + const TypeSetByHwMode &VTy = N->getExtType(0); + return inferSuperRegisterClass(VTy, N->getChild(1)); + } // Handle destination record types that we can safely infer a register class // from. @@ -4689,7 +5000,8 @@ GlobalISelEmitter::inferSuperRegisterClass(const TypeSetByHwMode &Ty, // Use the information we found above to find a minimal register class which // supports the subregister and type we want. auto RC = - Target.getSuperRegForSubReg(Ty.getValueTypeByHwMode(), CGRegs, SubIdx); + Target.getSuperRegForSubReg(Ty.getValueTypeByHwMode(), CGRegs, SubIdx, + /* MustBeAllocatable */ true); if (!RC) return None; return *RC; @@ -4777,9 +5089,9 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { if (Dst->isLeaf()) { Record *RCDef = getInitValueAsRegClass(Dst->getLeafValue()); - - const CodeGenRegisterClass &RC = Target.getRegisterClass(RCDef); if (RCDef) { + const CodeGenRegisterClass &RC = Target.getRegisterClass(RCDef); + // We need to replace the def and all its uses with the specified // operand. However, we must also insert COPY's wherever needed. // For now, emit a copy and let the register allocator clean up. @@ -4814,8 +5126,8 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { auto &DstI = Target.getInstruction(DstOp); StringRef DstIName = DstI.TheDef->getName(); - if (DstI.Operands.NumDefs != Src->getExtTypes().size()) - return failedImport("Src pattern results and dst MI defs are different (" + + if (DstI.Operands.NumDefs < Src->getExtTypes().size()) + return failedImport("Src pattern result has more defs than dst MI (" + to_string(Src->getExtTypes().size()) + " def(s) vs " + to_string(DstI.Operands.NumDefs) + " def(s))"); @@ -5035,7 +5347,8 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { // trouble than it's worth. void GlobalISelEmitter::emitCxxPredicateFns( raw_ostream &OS, StringRef CodeFieldName, StringRef TypeIdentifier, - StringRef ArgType, StringRef ArgName, StringRef AdditionalDeclarations, + StringRef ArgType, StringRef ArgName, StringRef AdditionalArgs, + StringRef AdditionalDeclarations, std::function<bool(const Record *R)> Filter) { std::vector<const Record *> MatchedRecords; const auto &Defs = RK.getAllDerivedDefinitions("PatFrag"); @@ -5060,7 +5373,7 @@ void GlobalISelEmitter::emitCxxPredicateFns( OS << "bool " << Target.getName() << "InstructionSelector::test" << ArgName << "Predicate_" << TypeIdentifier << "(unsigned PredicateID, " << ArgType << " " - << ArgName << ") const {\n" + << ArgName << AdditionalArgs <<") const {\n" << AdditionalDeclarations; if (!AdditionalDeclarations.empty()) OS << "\n"; @@ -5086,12 +5399,13 @@ void GlobalISelEmitter::emitImmPredicateFns( raw_ostream &OS, StringRef TypeIdentifier, StringRef ArgType, std::function<bool(const Record *R)> Filter) { return emitCxxPredicateFns(OS, "ImmediateCode", TypeIdentifier, ArgType, - "Imm", "", Filter); + "Imm", "", "", Filter); } void GlobalISelEmitter::emitMIPredicateFns(raw_ostream &OS) { return emitCxxPredicateFns( OS, "GISelPredicateCode", "MI", "const MachineInstr &", "MI", + ", const std::array<const MachineOperand *, 3> &Operands", " const MachineFunction &MF = *MI.getParent()->getParent();\n" " const MachineRegisterInfo &MRI = MF.getRegInfo();\n" " (void)MRI;", @@ -5117,8 +5431,7 @@ std::vector<Matcher *> GlobalISelEmitter::optimizeRules( // added rules out of it and make sure to re-create the group to properly // re-initialize it: if (CurrentGroup->size() < 2) - for (Matcher *M : CurrentGroup->matchers()) - OptRules.push_back(M); + append_range(OptRules, CurrentGroup->matchers()); else { CurrentGroup->finalize(); OptRules.push_back(CurrentGroup.get()); @@ -5167,15 +5480,13 @@ GlobalISelEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules, OpcodeOrder[Opcode] = CurrentOrdering++; } - std::stable_sort(InputRules.begin(), InputRules.end(), - [&OpcodeOrder](const Matcher *A, const Matcher *B) { - auto *L = static_cast<const RuleMatcher *>(A); - auto *R = static_cast<const RuleMatcher *>(B); - return std::make_tuple(OpcodeOrder[L->getOpcode()], - L->getNumOperands()) < - std::make_tuple(OpcodeOrder[R->getOpcode()], - R->getNumOperands()); - }); + llvm::stable_sort(InputRules, [&OpcodeOrder](const Matcher *A, + const Matcher *B) { + auto *L = static_cast<const RuleMatcher *>(A); + auto *R = static_cast<const RuleMatcher *>(B); + return std::make_tuple(OpcodeOrder[L->getOpcode()], L->getNumOperands()) < + std::make_tuple(OpcodeOrder[R->getOpcode()], R->getNumOperands()); + }); for (Matcher *Rule : InputRules) Rule->optimize(); @@ -5308,7 +5619,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) { << " typedef void(" << Target.getName() << "InstructionSelector::*CustomRendererFn)(MachineInstrBuilder &, const " - "MachineInstr&, int) " + "MachineInstr &, int) " "const;\n" << " const ISelInfoTy<PredicateBitset, ComplexMatcherMemFn, " "CustomRendererFn> " @@ -5324,7 +5635,8 @@ void GlobalISelEmitter::run(raw_ostream &OS) { << " bool testImmPredicate_APFloat(unsigned PredicateID, const APFloat " "&Imm) const override;\n" << " const int64_t *getMatchTable() const override;\n" - << " bool testMIPredicate_MI(unsigned PredicateID, const MachineInstr &MI) " + << " bool testMIPredicate_MI(unsigned PredicateID, const MachineInstr &MI" + ", const std::array<const MachineOperand *, 3> &Operands) " "const override;\n" << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n"; @@ -5360,7 +5672,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) { OS << "void " << Target.getName() << "InstructionSelector" "::setupGeneratedPerFunctionState(MachineFunction &MF) {\n" " AvailableFunctionFeatures = computeAvailableFunctionFeatures(" - "(const " << Target.getName() << "Subtarget*)&MF.getSubtarget(), &MF);\n" + "(const " << Target.getName() << "Subtarget *)&MF.getSubtarget(), &MF);\n" "}\n"; if (Target.getName() == "X86" || Target.getName() == "AArch64") { @@ -5378,8 +5690,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) { // Emit a table containing the LLT objects needed by the matcher and an enum // for the matcher to reference them with. std::vector<LLTCodeGen> TypeObjects; - for (const auto &Ty : KnownTypes) - TypeObjects.push_back(Ty); + append_range(TypeObjects, KnownTypes); llvm::sort(TypeObjects); OS << "// LLT Objects.\n" << "enum {\n"; @@ -5481,7 +5792,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) { << "enum {\n" << " GICR_Invalid,\n"; for (const auto &Record : CustomRendererFns) - OS << " GICR_" << Record->getValueAsString("RendererFn") << ", \n"; + OS << " GICR_" << Record->getValueAsString("RendererFn") << ",\n"; OS << "};\n"; OS << Target.getName() << "InstructionSelector::CustomRendererFn\n" @@ -5774,11 +6085,10 @@ void SwitchMatcher::finalize() { if (empty()) return; - std::stable_sort(Matchers.begin(), Matchers.end(), - [](const Matcher *L, const Matcher *R) { - return L->getFirstCondition().getValue() < - R->getFirstCondition().getValue(); - }); + llvm::stable_sort(Matchers, [](const Matcher *L, const Matcher *R) { + return L->getFirstCondition().getValue() < + R->getFirstCondition().getValue(); + }); Condition = Matchers[0]->popFirstCondition(); for (unsigned I = 1, E = Values.size(); I < E; ++I) Matchers[I]->popFirstCondition(); diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp index f3141735a995..9ff385faec56 100644 --- a/llvm/utils/TableGen/InstrInfoEmitter.cpp +++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -182,11 +182,10 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) { if (Constraint.isNone()) Res += "0"; else if (Constraint.isEarlyClobber()) - Res += "(1 << MCOI::EARLY_CLOBBER)"; + Res += "MCOI_EARLY_CLOBBER"; else { assert(Constraint.isTied()); - Res += "((" + utostr(Constraint.getTiedOperand()) + - " << 16) | (1 << MCOI::TIED_TO))"; + Res += "MCOI_TIED_TO(" + utostr(Constraint.getTiedOperand()) + ")"; } Result.push_back(Res); @@ -280,7 +279,7 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS, for (const auto &Op : Operands) OS << " " << Op.first << " = " << Op.second << ",\n"; - OS << "OPERAND_LAST"; + OS << " OPERAND_LAST"; OS << "\n};\n"; OS << "} // end namespace OpName\n"; OS << "} // end namespace " << Namespace << "\n"; @@ -316,7 +315,7 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS, OS << " return OperandMap[" << TableIndex++ << "][NamedIdx];\n"; } - OS << " default: return -1;\n"; + OS << " default: return -1;\n"; OS << " }\n"; } else { // There are no operands, so no need to emit anything @@ -371,7 +370,7 @@ void InstrInfoEmitter::emitOperandTypeMappings( OS << "namespace " << Namespace << " {\n"; OS << "LLVM_READONLY\n"; OS << "static int getOperandType(uint16_t Opcode, uint16_t OpIdx) {\n"; - // TODO: Factor out instructions with same operands to compress the tables. + // TODO: Factor out duplicate operand lists to compress the tables. if (!NumberedInstructions.empty()) { std::vector<int> OperandOffsets; std::vector<Record *> OperandRecords; @@ -385,7 +384,7 @@ void InstrInfoEmitter::emitOperandTypeMappings( OperandRecords.push_back(Op.Rec); ++CurrentOffset; } else { - for (Init *Arg : make_range(MIOI->arg_begin(), MIOI->arg_end())) { + for (Init *Arg : MIOI->getArgs()) { OperandRecords.push_back(cast<DefInit>(Arg)->getDef()); ++CurrentOffset; } @@ -393,16 +392,26 @@ void InstrInfoEmitter::emitOperandTypeMappings( } } - // Emit the table of offsets for the opcode lookup. - OS << " const int Offsets[] = {\n"; + // Emit the table of offsets (indexes) into the operand type table. + // Size the unsigned integer offset to save space. + assert(OperandRecords.size() <= UINT32_MAX && + "Too many operands for offset table"); + OS << ((OperandRecords.size() <= UINT16_MAX) ? " const uint16_t" + : " const uint32_t"); + OS << " Offsets[] = {\n"; for (int I = 0, E = OperandOffsets.size(); I != E; ++I) OS << " " << OperandOffsets[I] << ",\n"; OS << " };\n"; // Add an entry for the end so that we don't need to special case it below. OperandOffsets.push_back(OperandRecords.size()); + // Emit the actual operand types in a flat table. - OS << " const int OpcodeOperandTypes[] = {\n "; + // Size the signed integer operand type to save space. + assert(EnumVal <= INT16_MAX && + "Too many operand types for operand types table"); + OS << ((EnumVal <= INT8_MAX) ? " const int8_t" : " const int16_t"); + OS << " OpcodeOperandTypes[] = {\n "; for (int I = 0, E = OperandRecords.size(), CurOffset = 1; I != E; ++I) { // We print each Opcode's operands in its own row. if (I == OperandOffsets[CurOffset]) { @@ -532,6 +541,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) { unsigned ListNumber = 0; // Emit all of the instruction's implicit uses and defs. + Records.startTimer("Emit uses/defs"); for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) { Record *Inst = II->TheDef; std::vector<Record*> Uses = Inst->getValueAsListOfDefs("Uses"); @@ -549,10 +559,12 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OperandInfoMapTy OperandInfoIDs; // Emit all of the operand info records. + Records.startTimer("Emit operand info"); EmitOperandInfo(OS, OperandInfoIDs); // Emit all of the MCInstrDesc records in their ENUM ordering. // + Records.startTimer("Emit InstrDesc records"); OS << "\nextern const MCInstrDesc " << TargetName << "Insts[] = {\n"; ArrayRef<const CodeGenInstruction*> NumberedInstructions = Target.getInstructionsByEnumValue(); @@ -568,6 +580,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "};\n\n"; // Emit the array of instruction names. + Records.startTimer("Emit instruction names"); InstrNames.layout(); InstrNames.emitStringLiteralDef(OS, Twine("extern const char ") + TargetName + "InstrNameData[]"); @@ -628,6 +641,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) { } // MCInstrInfo initialization routine. + Records.startTimer("Emit initialization routine"); OS << "static inline void Init" << TargetName << "MCInstrInfo(MCInstrInfo *II) {\n"; OS << " II->InitMCInstrInfo(" << TargetName << "Insts, " << TargetName @@ -706,10 +720,13 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "#endif // GET_INSTRINFO_CTOR_DTOR\n\n"; + Records.startTimer("Emit operand name mappings"); emitOperandNameMappings(OS, Target, NumberedInstructions); + Records.startTimer("Emit operand type mappings"); emitOperandTypeMappings(OS, Target, NumberedInstructions); + Records.startTimer("Emit helper methods"); emitMCIIHelperMethods(OS, TargetName); } @@ -862,7 +879,9 @@ void InstrInfoEmitter::emitEnums(raw_ostream &OS) { namespace llvm { void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS) { + RK.startTimer("Analyze DAG patterns"); InstrInfoEmitter(RK).run(OS); + RK.startTimer("Emit map table"); EmitMapTable(RK, OS); } diff --git a/llvm/utils/TableGen/IntrinsicEmitter.cpp b/llvm/utils/TableGen/IntrinsicEmitter.cpp index 7e4191494149..4be0d90a45d2 100644 --- a/llvm/utils/TableGen/IntrinsicEmitter.cpp +++ b/llvm/utils/TableGen/IntrinsicEmitter.cpp @@ -246,13 +246,16 @@ enum IIT_Info { IIT_SUBDIVIDE4_ARG = 45, IIT_VEC_OF_BITCASTS_TO_INT = 46, IIT_V128 = 47, - IIT_BF16 = 48 + IIT_BF16 = 48, + IIT_STRUCT9 = 49, + IIT_V256 = 50, + IIT_AMX = 51 }; static void EncodeFixedValueType(MVT::SimpleValueType VT, std::vector<unsigned char> &Sig) { if (MVT(VT).isInteger()) { - unsigned BitWidth = MVT(VT).getSizeInBits(); + unsigned BitWidth = MVT(VT).getFixedSizeInBits(); switch (BitWidth) { default: PrintFatalError("unhandled integer type width in intrinsic!"); case 1: return Sig.push_back(IIT_I1); @@ -274,6 +277,7 @@ static void EncodeFixedValueType(MVT::SimpleValueType VT, case MVT::token: return Sig.push_back(IIT_TOKEN); case MVT::Metadata: return Sig.push_back(IIT_METADATA); case MVT::x86mmx: return Sig.push_back(IIT_MMX); + case MVT::x86amx: return Sig.push_back(IIT_AMX); // MVT::OtherVT is used to mean the empty struct type here. case MVT::Other: return Sig.push_back(IIT_EMPTYSTRUCT); // MVT::isVoid is used to represent varargs here. @@ -384,6 +388,7 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes, case 32: Sig.push_back(IIT_V32); break; case 64: Sig.push_back(IIT_V64); break; case 128: Sig.push_back(IIT_V128); break; + case 256: Sig.push_back(IIT_V256); break; case 512: Sig.push_back(IIT_V512); break; case 1024: Sig.push_back(IIT_V1024); break; } @@ -469,6 +474,7 @@ static void ComputeFixedEncoding(const CodeGenIntrinsic &Int, case 6: TypeSig.push_back(IIT_STRUCT6); break; case 7: TypeSig.push_back(IIT_STRUCT7); break; case 8: TypeSig.push_back(IIT_STRUCT8); break; + case 9: TypeSig.push_back(IIT_STRUCT9); break; default: llvm_unreachable("Unhandled case in struct"); } @@ -687,6 +693,12 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints, OS << "Attribute::NoAlias"; addComma = true; break; + case CodeGenIntrinsic::NoUndef: + if (addComma) + OS << ","; + OS << "Attribute::NoUndef"; + addComma = true; + break; case CodeGenIntrinsic::Returned: if (addComma) OS << ","; diff --git a/llvm/utils/TableGen/OptParserEmitter.cpp b/llvm/utils/TableGen/OptParserEmitter.cpp index 251533a8d154..8e6c05885e5b 100644 --- a/llvm/utils/TableGen/OptParserEmitter.cpp +++ b/llvm/utils/TableGen/OptParserEmitter.cpp @@ -20,7 +20,7 @@ using namespace llvm; -static const std::string getOptionName(const Record &R) { +static std::string getOptionName(const Record &R) { // Use the record name unless EnumName is defined. if (isa<UnsetInit>(R.getValueInit("EnumName"))) return std::string(R.getName()); @@ -35,19 +35,20 @@ static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) { return OS; } -static const std::string getOptionSpelling(const Record &R, - size_t &PrefixLength) { +static std::string getOptionSpelling(const Record &R, size_t &PrefixLength) { std::vector<StringRef> Prefixes = R.getValueAsListOfStrings("Prefixes"); StringRef Name = R.getValueAsString("Name"); + if (Prefixes.empty()) { PrefixLength = 0; return Name.str(); } + PrefixLength = Prefixes[0].size(); return (Twine(Prefixes[0]) + Twine(Name)).str(); } -static const std::string getOptionSpelling(const Record &R) { +static std::string getOptionSpelling(const Record &R) { size_t PrefixLength; return getOptionSpelling(R, PrefixLength); } @@ -59,75 +60,29 @@ static void emitNameUsingSpelling(raw_ostream &OS, const Record &R) { OS << "[" << PrefixLength << "]"; } -class MarshallingKindInfo { +class MarshallingInfo { public: + static constexpr const char *MacroName = "OPTION_WITH_MARSHALLING"; const Record &R; - const char *MacroName; bool ShouldAlwaysEmit; + StringRef MacroPrefix; StringRef KeyPath; StringRef DefaultValue; StringRef NormalizedValuesScope; - - void emit(raw_ostream &OS) const { - write_cstring(OS, StringRef(getOptionSpelling(R))); - OS << ", "; - OS << ShouldAlwaysEmit; - OS << ", "; - OS << KeyPath; - OS << ", "; - emitScopedNormalizedValue(OS, DefaultValue); - OS << ", "; - emitSpecific(OS); - } - - virtual Optional<StringRef> emitValueTable(raw_ostream &OS) const { - return None; - } - - virtual ~MarshallingKindInfo() = default; - - static std::unique_ptr<MarshallingKindInfo> create(const Record &R); - -protected: - void emitScopedNormalizedValue(raw_ostream &OS, - StringRef NormalizedValue) const { - if (!NormalizedValuesScope.empty()) - OS << NormalizedValuesScope << "::"; - OS << NormalizedValue; - } - - virtual void emitSpecific(raw_ostream &OS) const = 0; - MarshallingKindInfo(const Record &R, const char *MacroName) - : R(R), MacroName(MacroName) {} -}; - -class MarshallingFlagInfo final : public MarshallingKindInfo { -public: - bool IsPositive; - - void emitSpecific(raw_ostream &OS) const override { OS << IsPositive; } - - static std::unique_ptr<MarshallingKindInfo> create(const Record &R) { - std::unique_ptr<MarshallingFlagInfo> Ret(new MarshallingFlagInfo(R)); - Ret->IsPositive = R.getValueAsBit("IsPositive"); - return Ret; - } - -private: - MarshallingFlagInfo(const Record &R) - : MarshallingKindInfo(R, "OPTION_WITH_MARSHALLING_FLAG") {} -}; - -class MarshallingStringInfo final : public MarshallingKindInfo { -public: - StringRef NormalizerRetTy; + StringRef ImpliedCheck; + StringRef ImpliedValue; + StringRef ShouldParse; StringRef Normalizer; StringRef Denormalizer; + StringRef ValueMerger; + StringRef ValueExtractor; int TableIndex = -1; std::vector<StringRef> Values; std::vector<StringRef> NormalizedValues; std::string ValueTableName; + static size_t NextTableIndex; + static constexpr const char *ValueTablePreamble = R"( struct SimpleEnumValue { const char *Name; @@ -143,17 +98,39 @@ struct SimpleEnumValueTable { static constexpr const char *ValueTablesDecl = "static const SimpleEnumValueTable SimpleEnumValueTables[] = "; - void emitSpecific(raw_ostream &OS) const override { - emitScopedNormalizedValue(OS, NormalizerRetTy); + MarshallingInfo(const Record &R) : R(R) {} + + std::string getMacroName() const { + return (MacroPrefix + MarshallingInfo::MacroName).str(); + } + + void emit(raw_ostream &OS) const { + write_cstring(OS, StringRef(getOptionSpelling(R))); + OS << ", "; + OS << ShouldParse; + OS << ", "; + OS << ShouldAlwaysEmit; + OS << ", "; + OS << KeyPath; + OS << ", "; + emitScopedNormalizedValue(OS, DefaultValue); + OS << ", "; + OS << ImpliedCheck; + OS << ", "; + emitScopedNormalizedValue(OS, ImpliedValue); OS << ", "; OS << Normalizer; OS << ", "; OS << Denormalizer; OS << ", "; + OS << ValueMerger; + OS << ", "; + OS << ValueExtractor; + OS << ", "; OS << TableIndex; } - Optional<StringRef> emitValueTable(raw_ostream &OS) const override { + Optional<StringRef> emitValueTable(raw_ostream &OS) const { if (TableIndex == -1) return {}; OS << "static const SimpleEnumValue " << ValueTableName << "[] = {\n"; @@ -169,73 +146,66 @@ struct SimpleEnumValueTable { return StringRef(ValueTableName); } - static std::unique_ptr<MarshallingKindInfo> create(const Record &R) { - assert(!isa<UnsetInit>(R.getValueInit("NormalizerRetTy")) && - "String options must have a type"); - - std::unique_ptr<MarshallingStringInfo> Ret(new MarshallingStringInfo(R)); - Ret->NormalizerRetTy = R.getValueAsString("NormalizerRetTy"); - - Ret->Normalizer = R.getValueAsString("Normalizer"); - Ret->Denormalizer = R.getValueAsString("Denormalizer"); - - if (!isa<UnsetInit>(R.getValueInit("NormalizedValues"))) { - assert(!isa<UnsetInit>(R.getValueInit("Values")) && - "Cannot provide normalized values for value-less options"); - Ret->TableIndex = NextTableIndex++; - Ret->NormalizedValues = R.getValueAsListOfStrings("NormalizedValues"); - Ret->Values.reserve(Ret->NormalizedValues.size()); - Ret->ValueTableName = getOptionName(R) + "ValueTable"; - - StringRef ValuesStr = R.getValueAsString("Values"); - for (;;) { - size_t Idx = ValuesStr.find(','); - if (Idx == StringRef::npos) - break; - if (Idx > 0) - Ret->Values.push_back(ValuesStr.slice(0, Idx)); - ValuesStr = ValuesStr.slice(Idx + 1, StringRef::npos); - } - if (!ValuesStr.empty()) - Ret->Values.push_back(ValuesStr); - - assert(Ret->Values.size() == Ret->NormalizedValues.size() && - "The number of normalized values doesn't match the number of " - "values"); - } - - return Ret; - } - private: - MarshallingStringInfo(const Record &R) - : MarshallingKindInfo(R, "OPTION_WITH_MARSHALLING_STRING") {} - - static size_t NextTableIndex; + void emitScopedNormalizedValue(raw_ostream &OS, + StringRef NormalizedValue) const { + if (!NormalizedValuesScope.empty()) + OS << NormalizedValuesScope << "::"; + OS << NormalizedValue; + } }; -size_t MarshallingStringInfo::NextTableIndex = 0; +size_t MarshallingInfo::NextTableIndex = 0; -std::unique_ptr<MarshallingKindInfo> -MarshallingKindInfo::create(const Record &R) { +static MarshallingInfo createMarshallingInfo(const Record &R) { assert(!isa<UnsetInit>(R.getValueInit("KeyPath")) && !isa<UnsetInit>(R.getValueInit("DefaultValue")) && - "Must provide at least a key-path and a default value for emitting " - "marshalling information"); - - std::unique_ptr<MarshallingKindInfo> Ret = nullptr; - StringRef MarshallingKindStr = R.getValueAsString("MarshallingKind"); - - if (MarshallingKindStr == "flag") - Ret = MarshallingFlagInfo::create(R); - else if (MarshallingKindStr == "string") - Ret = MarshallingStringInfo::create(R); - - Ret->ShouldAlwaysEmit = R.getValueAsBit("ShouldAlwaysEmit"); - Ret->KeyPath = R.getValueAsString("KeyPath"); - Ret->DefaultValue = R.getValueAsString("DefaultValue"); - if (!isa<UnsetInit>(R.getValueInit("NormalizedValuesScope"))) - Ret->NormalizedValuesScope = R.getValueAsString("NormalizedValuesScope"); + !isa<UnsetInit>(R.getValueInit("ValueMerger")) && + "MarshallingInfo must have a provide a keypath, default value and a " + "value merger"); + + MarshallingInfo Ret(R); + + Ret.ShouldAlwaysEmit = R.getValueAsBit("ShouldAlwaysEmit"); + Ret.MacroPrefix = R.getValueAsString("MacroPrefix"); + Ret.KeyPath = R.getValueAsString("KeyPath"); + Ret.DefaultValue = R.getValueAsString("DefaultValue"); + Ret.NormalizedValuesScope = R.getValueAsString("NormalizedValuesScope"); + Ret.ImpliedCheck = R.getValueAsString("ImpliedCheck"); + Ret.ImpliedValue = + R.getValueAsOptionalString("ImpliedValue").getValueOr(Ret.DefaultValue); + + Ret.ShouldParse = R.getValueAsString("ShouldParse"); + Ret.Normalizer = R.getValueAsString("Normalizer"); + Ret.Denormalizer = R.getValueAsString("Denormalizer"); + Ret.ValueMerger = R.getValueAsString("ValueMerger"); + Ret.ValueExtractor = R.getValueAsString("ValueExtractor"); + + if (!isa<UnsetInit>(R.getValueInit("NormalizedValues"))) { + assert(!isa<UnsetInit>(R.getValueInit("Values")) && + "Cannot provide normalized values for value-less options"); + Ret.TableIndex = MarshallingInfo::NextTableIndex++; + Ret.NormalizedValues = R.getValueAsListOfStrings("NormalizedValues"); + Ret.Values.reserve(Ret.NormalizedValues.size()); + Ret.ValueTableName = getOptionName(R) + "ValueTable"; + + StringRef ValuesStr = R.getValueAsString("Values"); + for (;;) { + size_t Idx = ValuesStr.find(','); + if (Idx == StringRef::npos) + break; + if (Idx > 0) + Ret.Values.push_back(ValuesStr.slice(0, Idx)); + ValuesStr = ValuesStr.slice(Idx + 1, StringRef::npos); + } + if (!ValuesStr.empty()) + Ret.Values.push_back(ValuesStr); + + assert(Ret.Values.size() == Ret.NormalizedValues.size() && + "The number of normalized values doesn't match the number of " + "values"); + } + return Ret; } @@ -258,13 +228,12 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { PrefixesT Prefixes; Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0")); unsigned CurPrefix = 0; - for (unsigned i = 0, e = Opts.size(); i != e; ++i) { - const Record &R = *Opts[i]; - std::vector<StringRef> prf = R.getValueAsListOfStrings("Prefixes"); - PrefixKeyT prfkey(prf.begin(), prf.end()); + for (const Record &R : llvm::make_pointee_range(Opts)) { + std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes"); + PrefixKeyT PrefixKey(RPrefixes.begin(), RPrefixes.end()); unsigned NewPrefix = CurPrefix + 1; - if (Prefixes.insert(std::make_pair(prfkey, (Twine("prefix_") + - Twine(NewPrefix)).str())).second) + std::string Prefix = (Twine("prefix_") + Twine(NewPrefix)).str(); + if (Prefixes.insert(std::make_pair(PrefixKey, Prefix)).second) CurPrefix = NewPrefix; } @@ -274,19 +243,16 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { OS << "// Prefixes\n\n"; OS << "#ifdef PREFIX\n"; OS << "#define COMMA ,\n"; - for (PrefixesT::const_iterator I = Prefixes.begin(), E = Prefixes.end(); - I != E; ++I) { + for (const auto &Prefix : Prefixes) { OS << "PREFIX("; // Prefix name. - OS << I->second; + OS << Prefix.second; // Prefix values. OS << ", {"; - for (PrefixKeyT::const_iterator PI = I->first.begin(), - PE = I->first.end(); PI != PE; ++PI) { - OS << "\"" << *PI << "\" COMMA "; - } + for (StringRef PrefixKey : Prefix.first) + OS << "\"" << PrefixKey << "\" COMMA "; OS << "nullptr})\n"; } OS << "#undef COMMA\n"; @@ -295,9 +261,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { OS << "/////////\n"; OS << "// Groups\n\n"; OS << "#ifdef OPTION\n"; - for (unsigned i = 0, e = Groups.size(); i != e; ++i) { - const Record &R = *Groups[i]; - + for (const Record &R : llvm::make_pointee_range(Groups)) { // Start a single option entry. OS << "OPTION("; @@ -344,8 +308,8 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { auto WriteOptRecordFields = [&](raw_ostream &OS, const Record &R) { // The option prefix; - std::vector<StringRef> prf = R.getValueAsListOfStrings("Prefixes"); - OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", "; + std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes"); + OS << Prefixes[PrefixKeyT(RPrefixes.begin(), RPrefixes.end())] << ", "; // The option string. emitNameUsingSpelling(OS, R); @@ -382,8 +346,8 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { OS << "nullptr"; } else { OS << "\""; - for (size_t i = 0, e = AliasArgs.size(); i != e; ++i) - OS << AliasArgs[i] << "\\0"; + for (StringRef AliasArg : AliasArgs) + OS << AliasArg << "\\0"; OS << "\""; } @@ -427,39 +391,63 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { OS << "nullptr"; }; - std::vector<std::unique_ptr<MarshallingKindInfo>> OptsWithMarshalling; - for (unsigned I = 0, E = Opts.size(); I != E; ++I) { - const Record &R = *Opts[I]; + auto IsMarshallingOption = [](const Record &R) { + return !isa<UnsetInit>(R.getValueInit("KeyPath")) && + !R.getValueAsString("KeyPath").empty(); + }; + std::vector<const Record *> OptsWithMarshalling; + for (const Record &R : llvm::make_pointee_range(Opts)) { // Start a single option entry. OS << "OPTION("; WriteOptRecordFields(OS, R); OS << ")\n"; - if (!isa<UnsetInit>(R.getValueInit("MarshallingKind"))) - OptsWithMarshalling.push_back(MarshallingKindInfo::create(R)); + if (IsMarshallingOption(R)) + OptsWithMarshalling.push_back(&R); } OS << "#endif // OPTION\n"; - for (const auto &KindInfo : OptsWithMarshalling) { - OS << "#ifdef " << KindInfo->MacroName << "\n"; - OS << KindInfo->MacroName << "("; - WriteOptRecordFields(OS, KindInfo->R); + auto CmpMarshallingOpts = [](const Record *const *A, const Record *const *B) { + unsigned AID = (*A)->getID(); + unsigned BID = (*B)->getID(); + + if (AID < BID) + return -1; + if (AID > BID) + return 1; + return 0; + }; + // The RecordKeeper stores records (options) in lexicographical order, and we + // have reordered the options again when generating prefix groups. We need to + // restore the original definition order of options with marshalling to honor + // the topology of the dependency graph implied by `DefaultAnyOf`. + array_pod_sort(OptsWithMarshalling.begin(), OptsWithMarshalling.end(), + CmpMarshallingOpts); + + std::vector<MarshallingInfo> MarshallingInfos; + for (const auto *R : OptsWithMarshalling) + MarshallingInfos.push_back(createMarshallingInfo(*R)); + + for (const auto &MI : MarshallingInfos) { + OS << "#ifdef " << MI.getMacroName() << "\n"; + OS << MI.getMacroName() << "("; + WriteOptRecordFields(OS, MI.R); OS << ", "; - KindInfo->emit(OS); + MI.emit(OS); OS << ")\n"; - OS << "#endif // " << KindInfo->MacroName << "\n"; + OS << "#endif // " << MI.getMacroName() << "\n"; } OS << "\n"; OS << "#ifdef SIMPLE_ENUM_VALUE_TABLE"; OS << "\n"; - OS << MarshallingStringInfo::ValueTablePreamble; + OS << MarshallingInfo::ValueTablePreamble; std::vector<StringRef> ValueTableNames; - for (const auto &KindInfo : OptsWithMarshalling) - if (auto MaybeValueTableName = KindInfo->emitValueTable(OS)) + for (const auto &MI : MarshallingInfos) + if (auto MaybeValueTableName = MI.emitValueTable(OS)) ValueTableNames.push_back(*MaybeValueTableName); - OS << MarshallingStringInfo::ValueTablesDecl << "{"; + OS << MarshallingInfo::ValueTablesDecl << "{"; for (auto ValueTableName : ValueTableNames) OS << "{" << ValueTableName << ", sizeof(" << ValueTableName << ") / sizeof(SimpleEnumValue)" @@ -475,8 +463,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { OS << "#ifdef OPTTABLE_ARG_INIT\n"; OS << "//////////\n"; OS << "// Option Values\n\n"; - for (unsigned I = 0, E = Opts.size(); I != E; ++I) { - const Record &R = *Opts[I]; + for (const Record &R : llvm::make_pointee_range(Opts)) { if (isa<UnsetInit>(R.getValueInit("ValuesCode"))) continue; OS << "{\n"; diff --git a/llvm/utils/TableGen/PredicateExpander.cpp b/llvm/utils/TableGen/PredicateExpander.cpp index 9f7f40db2626..a76640f6d11f 100644 --- a/llvm/utils/TableGen/PredicateExpander.cpp +++ b/llvm/utils/TableGen/PredicateExpander.cpp @@ -198,6 +198,18 @@ void PredicateExpander::expandCheckIsImmOperand(raw_ostream &OS, int OpIndex) { << "getOperand(" << OpIndex << ").isImm() "; } +void PredicateExpander::expandCheckFunctionPredicateWithTII( + raw_ostream &OS, StringRef MCInstFn, StringRef MachineInstrFn, + StringRef TIIPtr) { + if (!shouldExpandForMC()) { + OS << (TIIPtr.empty() ? "TII" : TIIPtr) << "->" << MachineInstrFn; + OS << (isByRef() ? "(MI)" : "(*MI)"); + return; + } + + OS << MCInstFn << (isByRef() ? "(MI" : "(*MI") << ", MCII)"; +} + void PredicateExpander::expandCheckFunctionPredicate(raw_ostream &OS, StringRef MCInstFn, StringRef MachineInstrFn) { @@ -358,10 +370,18 @@ void PredicateExpander::expandPredicate(raw_ostream &OS, const Record *Rec) { return expandPredicateSequence(OS, Rec->getValueAsListOfDefs("Predicates"), /* AllOf */ false); - if (Rec->isSubClassOf("CheckFunctionPredicate")) + if (Rec->isSubClassOf("CheckFunctionPredicate")) { return expandCheckFunctionPredicate( OS, Rec->getValueAsString("MCInstFnName"), Rec->getValueAsString("MachineInstrFnName")); + } + + if (Rec->isSubClassOf("CheckFunctionPredicateWithTII")) { + return expandCheckFunctionPredicateWithTII( + OS, Rec->getValueAsString("MCInstFnName"), + Rec->getValueAsString("MachineInstrFnName"), + Rec->getValueAsString("TIIPtrName")); + } if (Rec->isSubClassOf("CheckNonPortable")) return expandCheckNonPortable(OS, Rec->getValueAsString("CodeBlock")); diff --git a/llvm/utils/TableGen/PredicateExpander.h b/llvm/utils/TableGen/PredicateExpander.h index 115a81cf123b..29cca92d902c 100644 --- a/llvm/utils/TableGen/PredicateExpander.h +++ b/llvm/utils/TableGen/PredicateExpander.h @@ -79,6 +79,9 @@ public: void expandCheckInvalidRegOperand(raw_ostream &OS, int OpIndex); void expandCheckFunctionPredicate(raw_ostream &OS, StringRef MCInstFn, StringRef MachineInstrFn); + void expandCheckFunctionPredicateWithTII(raw_ostream &OS, StringRef MCInstFn, + StringRef MachineInstrFn, + StringRef TIIPtr); void expandCheckNonPortable(raw_ostream &OS, StringRef CodeBlock); void expandPredicate(raw_ostream &OS, const Record *Rec); void expandReturnStatement(raw_ostream &OS, const Record *Rec); diff --git a/llvm/utils/TableGen/PseudoLoweringEmitter.cpp b/llvm/utils/TableGen/PseudoLoweringEmitter.cpp index 3a80d8e5d1c4..e05409db67d0 100644 --- a/llvm/utils/TableGen/PseudoLoweringEmitter.cpp +++ b/llvm/utils/TableGen/PseudoLoweringEmitter.cpp @@ -89,11 +89,15 @@ addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Insn, // problem. // FIXME: We probably shouldn't ever get a non-zero BaseIdx here. assert(BaseIdx == 0 && "Named subargument in pseudo expansion?!"); - if (DI->getDef() != Insn.Operands[BaseIdx + i].Rec) - PrintFatalError(Rec->getLoc(), - "Pseudo operand type '" + DI->getDef()->getName() + - "' does not match expansion operand type '" + - Insn.Operands[BaseIdx + i].Rec->getName() + "'"); + // FIXME: Are the message operand types backward? + if (DI->getDef() != Insn.Operands[BaseIdx + i].Rec) { + PrintError(Rec, "In pseudo instruction '" + Rec->getName() + + "', operand type '" + DI->getDef()->getName() + + "' does not match expansion operand type '" + + Insn.Operands[BaseIdx + i].Rec->getName() + "'"); + PrintFatalNote(DI->getDef(), + "Value was assigned at the following location:"); + } // Source operand maps to destination operand. The Data element // will be filled in later, just set the Kind for now. Do it // for each corresponding MachineInstr operand, not just the first. @@ -128,23 +132,38 @@ void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) { LLVM_DEBUG(dbgs() << " Result: " << *Dag << "\n"); DefInit *OpDef = dyn_cast<DefInit>(Dag->getOperator()); - if (!OpDef) - PrintFatalError(Rec->getLoc(), Rec->getName() + - " has unexpected operator type!"); + if (!OpDef) { + PrintError(Rec, "In pseudo instruction '" + Rec->getName() + + "', result operator is not a record"); + PrintFatalNote(Rec->getValue("ResultInst"), + "Result was assigned at the following location:"); + } Record *Operator = OpDef->getDef(); - if (!Operator->isSubClassOf("Instruction")) - PrintFatalError(Rec->getLoc(), "Pseudo result '" + Operator->getName() + - "' is not an instruction!"); + if (!Operator->isSubClassOf("Instruction")) { + PrintError(Rec, "In pseudo instruction '" + Rec->getName() + + "', result operator '" + Operator->getName() + + "' is not an instruction"); + PrintFatalNote(Rec->getValue("ResultInst"), + "Result was assigned at the following location:"); + } CodeGenInstruction Insn(Operator); - if (Insn.isCodeGenOnly || Insn.isPseudo) - PrintFatalError(Rec->getLoc(), "Pseudo result '" + Operator->getName() + - "' cannot be another pseudo instruction!"); + if (Insn.isCodeGenOnly || Insn.isPseudo) { + PrintError(Rec, "In pseudo instruction '" + Rec->getName() + + "', result operator '" + Operator->getName() + + "' cannot be a pseudo instruction"); + PrintFatalNote(Rec->getValue("ResultInst"), + "Result was assigned at the following location:"); + } - if (Insn.Operands.size() != Dag->getNumArgs()) - PrintFatalError(Rec->getLoc(), "Pseudo result '" + Operator->getName() + - "' operand count mismatch"); + if (Insn.Operands.size() != Dag->getNumArgs()) { + PrintError(Rec, "In pseudo instruction '" + Rec->getName() + + "', result operator '" + Operator->getName() + + "' has the wrong number of operands"); + PrintFatalNote(Rec->getValue("ResultInst"), + "Result was assigned at the following location:"); + } unsigned NumMIOperands = 0; for (unsigned i = 0, e = Insn.Operands.size(); i != e; ++i) @@ -177,10 +196,13 @@ void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) { continue; StringMap<unsigned>::iterator SourceOp = SourceOperands.find(Dag->getArgNameStr(i)); - if (SourceOp == SourceOperands.end()) - PrintFatalError(Rec->getLoc(), - "Pseudo output operand '" + Dag->getArgNameStr(i) + - "' has no matching source operand."); + if (SourceOp == SourceOperands.end()) { + PrintError(Rec, "In pseudo instruction '" + Rec->getName() + + "', output operand '" + Dag->getArgNameStr(i) + + "' has no matching source operand"); + PrintFatalNote(Rec->getValue("ResultInst"), + "Value was assigned at the following location:"); + } // Map the source operand to the destination operand index for each // MachineInstr operand. for (unsigned I = 0, E = Insn.Operands[i].MINumOperands; I != E; ++I) @@ -204,15 +226,15 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) { if (!Expansions.empty()) { o << " switch (MI->getOpcode()) {\n" - << " default: return false;\n"; + << " default: return false;\n"; for (auto &Expansion : Expansions) { CodeGenInstruction &Source = Expansion.Source; CodeGenInstruction &Dest = Expansion.Dest; - o << " case " << Source.Namespace << "::" + o << " case " << Source.Namespace << "::" << Source.TheDef->getName() << ": {\n" - << " MCInst TmpInst;\n" - << " MCOperand MCOp;\n" - << " TmpInst.setOpcode(" << Dest.Namespace << "::" + << " MCInst TmpInst;\n" + << " MCOperand MCOp;\n" + << " TmpInst.setOpcode(" << Dest.Namespace << "::" << Dest.TheDef->getName() << ");\n"; // Copy the operands from the source instruction. @@ -221,23 +243,23 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) { // expansion DAG. unsigned MIOpNo = 0; for (const auto &DestOperand : Dest.Operands) { - o << " // Operand: " << DestOperand.Name << "\n"; + o << " // Operand: " << DestOperand.Name << "\n"; for (unsigned i = 0, e = DestOperand.MINumOperands; i != e; ++i) { switch (Expansion.OperandMap[MIOpNo + i].Kind) { case OpData::Operand: - o << " lowerOperand(MI->getOperand(" + o << " lowerOperand(MI->getOperand(" << Source.Operands[Expansion.OperandMap[MIOpNo].Data .Operand].MIOperandNo + i << "), MCOp);\n" - << " TmpInst.addOperand(MCOp);\n"; + << " TmpInst.addOperand(MCOp);\n"; break; case OpData::Imm: - o << " TmpInst.addOperand(MCOperand::createImm(" + o << " TmpInst.addOperand(MCOperand::createImm(" << Expansion.OperandMap[MIOpNo + i].Data.Imm << "));\n"; break; case OpData::Reg: { Record *Reg = Expansion.OperandMap[MIOpNo + i].Data.Reg; - o << " TmpInst.addOperand(MCOperand::createReg("; + o << " TmpInst.addOperand(MCOperand::createReg("; // "zero_reg" is special. if (Reg->getName() == "zero_reg") o << "0"; @@ -253,15 +275,15 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) { } if (Dest.Operands.isVariadic) { MIOpNo = Source.Operands.size() + 1; - o << " // variable_ops\n"; - o << " for (unsigned i = " << MIOpNo + o << " // variable_ops\n"; + o << " for (unsigned i = " << MIOpNo << ", e = MI->getNumOperands(); i != e; ++i)\n" - << " if (lowerOperand(MI->getOperand(i), MCOp))\n" - << " TmpInst.addOperand(MCOp);\n"; + << " if (lowerOperand(MI->getOperand(i), MCOp))\n" + << " TmpInst.addOperand(MCOp);\n"; } - o << " EmitToStreamer(OutStreamer, TmpInst);\n" - << " break;\n" - << " }\n"; + o << " EmitToStreamer(OutStreamer, TmpInst);\n" + << " break;\n" + << " }\n"; } o << " }\n return true;"; } else @@ -271,24 +293,18 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) { } void PseudoLoweringEmitter::run(raw_ostream &o) { - Record *ExpansionClass = Records.getClass("PseudoInstExpansion"); - Record *InstructionClass = Records.getClass("Instruction"); - assert(ExpansionClass && "PseudoInstExpansion class definition missing!"); - assert(InstructionClass && "Instruction class definition missing!"); - - std::vector<Record*> Insts; - for (const auto &D : Records.getDefs()) { - if (D.second->isSubClassOf(ExpansionClass) && - D.second->isSubClassOf(InstructionClass)) - Insts.push_back(D.second.get()); - } + StringRef Classes[] = {"PseudoInstExpansion", "Instruction"}; + std::vector<Record *> Insts = + Records.getAllDerivedDefinitions(makeArrayRef(Classes)); // Process the pseudo expansion definitions, validating them as we do so. + Records.startTimer("Process definitions"); for (unsigned i = 0, e = Insts.size(); i != e; ++i) evaluateExpansion(Insts[i]); // Generate expansion code to lower the pseudo to an MCInst of the real // instruction. + Records.startTimer("Emit expansion code"); emitLoweringEmitter(o); } diff --git a/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp b/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp index f298e639bf7f..183c8f9494db 100644 --- a/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp +++ b/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp @@ -37,11 +37,11 @@ // compressing/uncompressing MCInst instructions, plus // some helper functions: // -// bool compressInst(MCInst& OutInst, const MCInst &MI, +// bool compressInst(MCInst &OutInst, const MCInst &MI, // const MCSubtargetInfo &STI, // MCContext &Context); // -// bool uncompressInst(MCInst& OutInst, const MCInst &MI, +// bool uncompressInst(MCInst &OutInst, const MCInst &MI, // const MCRegisterInfo &MRI, // const MCSubtargetInfo &STI); // @@ -101,11 +101,12 @@ class RISCVCompressInstEmitter { IndexedMap<OpData> DestOperandMap; // Maps operands in the Dest Instruction // to the corresponding Source instruction operand. + bool IsCompressOnly; CompressPat(CodeGenInstruction &S, CodeGenInstruction &D, std::vector<Record *> RF, IndexedMap<OpData> &SourceMap, - IndexedMap<OpData> &DestMap) + IndexedMap<OpData> &DestMap, bool IsCompressOnly) : Source(S), Dest(D), PatReqFeatures(RF), SourceOperandMap(SourceMap), - DestOperandMap(DestMap) {} + DestOperandMap(DestMap), IsCompressOnly(IsCompressOnly) {} }; enum EmitterType { Compress, Uncompress, CheckCompress }; RecordKeeper &Records; @@ -138,13 +139,12 @@ public: } // End anonymous namespace. bool RISCVCompressInstEmitter::validateRegister(Record *Reg, Record *RegClass) { - assert(Reg->isSubClassOf("Register") && "Reg record should be a Register\n"); - assert(RegClass->isSubClassOf("RegisterClass") && "RegClass record should be" - " a RegisterClass\n"); + assert(Reg->isSubClassOf("Register") && "Reg record should be a Register"); + assert(RegClass->isSubClassOf("RegisterClass") && + "RegClass record should be a RegisterClass"); const CodeGenRegisterClass &RC = Target.getRegisterClass(RegClass); const CodeGenRegister *R = Target.getRegisterByName(Reg->getName().lower()); - assert((R != nullptr) && - ("Register" + Reg->getName().str() + " not defined!!\n").c_str()); + assert((R != nullptr) && "Register not defined!!"); return RC.contains(R); } @@ -237,9 +237,9 @@ void RISCVCompressInstEmitter::addDagOperandMapping( if (Inst.Operands[i].Rec->isSubClassOf("RegisterClass")) PrintFatalError( Rec->getLoc(), - ("Error in Dag '" + Dag->getAsString() + "' Found immediate: '" + - II->getAsString() + - "' but corresponding instruction operand expected a register!")); + "Error in Dag '" + Dag->getAsString() + "' Found immediate: '" + + II->getAsString() + + "' but corresponding instruction operand expected a register!"); // No pattern validation check possible for values of fixed immediate. OperandMap[i].Kind = OpData::Imm; OperandMap[i].Data.Imm = II->getValue(); @@ -285,11 +285,7 @@ static bool verifyDagOpCount(CodeGenInstruction &Inst, DagInit *Dag, } static bool validateArgsTypes(Init *Arg1, Init *Arg2) { - DefInit *Type1 = dyn_cast<DefInit>(Arg1); - DefInit *Type2 = dyn_cast<DefInit>(Arg2); - assert(Type1 && ("Arg1 type not found\n")); - assert(Type2 && ("Arg2 type not found\n")); - return Type1->getDef() == Type2->getDef(); + return cast<DefInit>(Arg1)->getDef() == cast<DefInit>(Arg2)->getDef(); } // Creates a mapping between the operand name in the Dag (e.g. $rs1) and @@ -471,7 +467,8 @@ void RISCVCompressInstEmitter::evaluateCompressPat(Record *Rec) { }); CompressPatterns.push_back(CompressPat(SourceInst, DestInst, PatReqFeatures, - SourceOperandMap, DestOperandMap)); + SourceOperandMap, DestOperandMap, + Rec->getValueAsBit("isCompressOnly"))); } static void @@ -514,50 +511,41 @@ getReqFeatures(std::set<std::pair<bool, StringRef>> &FeaturesSet, static unsigned getPredicates(DenseMap<const Record *, unsigned> &PredicateMap, std::vector<const Record *> &Predicates, Record *Rec, StringRef Name) { - unsigned Entry = PredicateMap[Rec]; + unsigned &Entry = PredicateMap[Rec]; if (Entry) return Entry; if (!Rec->isValueUnset(Name)) { Predicates.push_back(Rec); Entry = Predicates.size(); - PredicateMap[Rec] = Entry; return Entry; } PrintFatalError(Rec->getLoc(), "No " + Name + - " predicate on this operand at all: '" + Rec->getName().str() + "'"); + " predicate on this operand at all: '" + + Rec->getName() + "'"); return 0; } -static void printPredicates(std::vector<const Record *> &Predicates, +static void printPredicates(const std::vector<const Record *> &Predicates, StringRef Name, raw_ostream &o) { for (unsigned i = 0; i < Predicates.size(); ++i) { - Init *Pred = Predicates[i]->getValueInit(Name); - if (CodeInit *SI = dyn_cast<CodeInit>(Pred)) - o << " case " << i + 1 << ": {\n" - << " // " << Predicates[i]->getName().str() << "\n" - << " " << SI->getValue() << "\n" - << " }\n"; - else - llvm_unreachable("Unexpected predicate field!"); + StringRef Pred = Predicates[i]->getValueAsString(Name); + o << " case " << i + 1 << ": {\n" + << " // " << Predicates[i]->getName() << "\n" + << " " << Pred << "\n" + << " }\n"; } } -static std::string mergeCondAndCode(raw_string_ostream &CondStream, - raw_string_ostream &CodeStream) { - std::string S; - raw_string_ostream CombinedStream(S); - CombinedStream.indent(4) - << "if (" - << CondStream.str().substr( - 6, CondStream.str().length() - - 10) // remove first indentation and last '&&'. - << ") {\n"; - CombinedStream << CodeStream.str(); +static void mergeCondAndCode(raw_ostream &CombinedStream, StringRef CondStr, + StringRef CodeStr) { + // Remove first indentation and last '&&'. + CondStr = CondStr.drop_front(6).drop_back(4); + CombinedStream.indent(4) << "if (" << CondStr << ") {\n"; + CombinedStream << CodeStr; CombinedStream.indent(4) << " return true;\n"; CombinedStream.indent(4) << "} // if\n"; - return CombinedStream.str(); } void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, @@ -568,23 +556,20 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, "'PassSubtarget' is false. SubTargetInfo object is needed " "for target features.\n"); - std::string Namespace = std::string(Target.getName()); + StringRef Namespace = Target.getName(); // Sort entries in CompressPatterns to handle instructions that can have more // than one candidate for compression\uncompression, e.g ADD can be // transformed to a C_ADD or a C_MV. When emitting 'uncompress()' function the // source and destination are flipped and the sort key needs to change // accordingly. - llvm::stable_sort(CompressPatterns, - [EType](const CompressPat &LHS, const CompressPat &RHS) { - if (EType == EmitterType::Compress || - EType == EmitterType::CheckCompress) - return (LHS.Source.TheDef->getName().str() < - RHS.Source.TheDef->getName().str()); - else - return (LHS.Dest.TheDef->getName().str() < - RHS.Dest.TheDef->getName().str()); - }); + llvm::stable_sort(CompressPatterns, [EType](const CompressPat &LHS, + const CompressPat &RHS) { + if (EType == EmitterType::Compress || EType == EmitterType::CheckCompress) + return (LHS.Source.TheDef->getName() < RHS.Source.TheDef->getName()); + else + return (LHS.Dest.TheDef->getName() < RHS.Dest.TheDef->getName()); + }); // A list of MCOperandPredicates for all operands in use, and the reverse map. std::vector<const Record *> MCOpPredicates; @@ -610,17 +595,17 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, << "#undef GEN_CHECK_COMPRESS_INSTR\n\n"; if (EType == EmitterType::Compress) { - FuncH << "static bool compressInst(MCInst& OutInst,\n"; + FuncH << "static bool compressInst(MCInst &OutInst,\n"; FuncH.indent(25) << "const MCInst &MI,\n"; FuncH.indent(25) << "const MCSubtargetInfo &STI,\n"; FuncH.indent(25) << "MCContext &Context) {\n"; } else if (EType == EmitterType::Uncompress){ - FuncH << "static bool uncompressInst(MCInst& OutInst,\n"; + FuncH << "static bool uncompressInst(MCInst &OutInst,\n"; FuncH.indent(27) << "const MCInst &MI,\n"; FuncH.indent(27) << "const MCRegisterInfo &MRI,\n"; FuncH.indent(27) << "const MCSubtargetInfo &STI) {\n"; } else if (EType == EmitterType::CheckCompress) { - FuncH << "static bool isCompressibleInst(const MachineInstr& MI,\n"; + FuncH << "static bool isCompressibleInst(const MachineInstr &MI,\n"; FuncH.indent(27) << "const RISCVSubtarget *Subtarget,\n"; FuncH.indent(27) << "const MCRegisterInfo &MRI,\n"; FuncH.indent(27) << "const MCSubtargetInfo &STI) {\n"; @@ -638,10 +623,10 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, return; } - std::string CaseString(""); + std::string CaseString; raw_string_ostream CaseStream(CaseString); - std::string PrevOp(""); - std::string CurOp(""); + StringRef PrevOp; + StringRef CurOp; CaseStream << " switch (MI.getOpcode()) {\n"; CaseStream << " default: return false;\n"; @@ -651,6 +636,9 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, EType == EmitterType::Compress || EType == EmitterType::Uncompress; for (auto &CompressPat : CompressPatterns) { + if (EType == EmitterType::Uncompress && CompressPat.IsCompressOnly) + continue; + std::string CondString; std::string CodeString; raw_string_ostream CondStream(CondString); @@ -664,10 +652,10 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, IndexedMap<OpData> &DestOperandMap = CompressOrCheck ? CompressPat.DestOperandMap : CompressPat.SourceOperandMap; - CurOp = Source.TheDef->getName().str(); + CurOp = Source.TheDef->getName(); // Check current and previous opcode to decide to continue or end a case. if (CurOp != PrevOp) { - if (PrevOp != "") + if (!PrevOp.empty()) CaseStream.indent(6) << "break;\n } // case " + PrevOp + "\n"; CaseStream.indent(4) << "case " + Namespace + "::" + CurOp + ": {\n"; } @@ -688,9 +676,9 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, // Emit checks for all required features. for (auto &Op : FeaturesSet) { StringRef Not = Op.first ? "!" : ""; - CondStream.indent(6) - << Not << ("STI.getFeatureBits()[" + Namespace + "::" + Op.second + "]").str() + - " &&\n"; + CondStream.indent(6) << Not << "STI.getFeatureBits()[" << Namespace + << "::" << Op.second << "]" + << " &&\n"; } // Emit checks for all required feature groups. @@ -699,8 +687,8 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, for (auto &Op : Set) { bool isLast = &Op == &*Set.rbegin(); StringRef Not = Op.first ? "!" : ""; - CondStream << Not << ("STI.getFeatureBits()[" + Namespace + "::" + Op.second + - "]").str(); + CondStream << Not << "STI.getFeatureBits()[" << Namespace + << "::" << Op.second << "]"; if (!isLast) CondStream << " || "; } @@ -713,10 +701,8 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, if (SourceOperandMap[OpNo].TiedOpIdx != -1) { if (Source.Operands[OpNo].Rec->isSubClassOf("RegisterClass")) CondStream.indent(6) - << "(MI.getOperand(" - << std::to_string(OpNo) + ").getReg() == MI.getOperand(" - << std::to_string(SourceOperandMap[OpNo].TiedOpIdx) - << ").getReg()) &&\n"; + << "(MI.getOperand(" << OpNo << ").getReg() == MI.getOperand(" + << SourceOperandMap[OpNo].TiedOpIdx << ").getReg()) &&\n"; else PrintFatalError("Unexpected tied operand types!\n"); } @@ -727,27 +713,26 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, break; case OpData::Imm: CondStream.indent(6) - << "(MI.getOperand(" + std::to_string(OpNo) + ").isImm()) &&\n" + - " (MI.getOperand(" + std::to_string(OpNo) + - ").getImm() == " + - std::to_string(SourceOperandMap[OpNo].Data.Imm) + ") &&\n"; + << "(MI.getOperand(" << OpNo << ").isImm()) &&\n" + << " (MI.getOperand(" << OpNo + << ").getImm() == " << SourceOperandMap[OpNo].Data.Imm << ") &&\n"; break; case OpData::Reg: { Record *Reg = SourceOperandMap[OpNo].Data.Reg; - CondStream.indent(6) << "(MI.getOperand(" + std::to_string(OpNo) + - ").getReg() == " + Namespace + - "::" + Reg->getName().str() + ") &&\n"; + CondStream.indent(6) + << "(MI.getOperand(" << OpNo << ").getReg() == " << Namespace + << "::" << Reg->getName() << ") &&\n"; break; } } } - CodeStream.indent(6) << "// " + Dest.AsmString + "\n"; + CodeStream.indent(6) << "// " << Dest.AsmString << "\n"; if (CompressOrUncompress) - CodeStream.indent(6) << "OutInst.setOpcode(" + Namespace + - "::" + Dest.TheDef->getName().str() + ");\n"; + CodeStream.indent(6) << "OutInst.setOpcode(" << Namespace + << "::" << Dest.TheDef->getName() << ");\n"; OpNo = 0; for (const auto &DestOperand : Dest.Operands) { - CodeStream.indent(6) << "// Operand: " + DestOperand.Name + "\n"; + CodeStream.indent(6) << "// Operand: " << DestOperand.Name << "\n"; switch (DestOperandMap[OpNo].Kind) { case OpData::Operand: { unsigned OpIdx = DestOperandMap[OpNo].Data.Operand; @@ -759,68 +744,67 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, // Don't check register class if this is a tied operand, it was done // for the operand its tied to. if (DestOperand.getTiedRegister() == -1) - CondStream.indent(6) - << "(MRI.getRegClass(" + Namespace + - "::" + DestOperand.Rec->getName().str() + - "RegClassID).contains(" + "MI.getOperand(" + - std::to_string(OpIdx) + ").getReg())) &&\n"; + CondStream.indent(6) << "(MRI.getRegClass(" << Namespace + << "::" << DestOperand.Rec->getName() + << "RegClassID).contains(MI.getOperand(" + << OpIdx << ").getReg())) &&\n"; if (CompressOrUncompress) - CodeStream.indent(6) << "OutInst.addOperand(MI.getOperand(" + - std::to_string(OpIdx) + "));\n"; + CodeStream.indent(6) + << "OutInst.addOperand(MI.getOperand(" << OpIdx << "));\n"; } else { // Handling immediate operands. if (CompressOrUncompress) { - unsigned Entry = getPredicates(MCOpPredicateMap, MCOpPredicates, - DestOperand.Rec, StringRef("MCOperandPredicate")); - CondStream.indent(6) << Namespace + "ValidateMCOperand(" + - "MI.getOperand(" + std::to_string(OpIdx) + - "), STI, " + std::to_string(Entry) + - ") &&\n"; + unsigned Entry = + getPredicates(MCOpPredicateMap, MCOpPredicates, DestOperand.Rec, + "MCOperandPredicate"); + CondStream.indent(6) + << Namespace << "ValidateMCOperand(" + << "MI.getOperand(" << OpIdx << "), STI, " << Entry << ") &&\n"; } else { - unsigned Entry = getPredicates(ImmLeafPredicateMap, ImmLeafPredicates, - DestOperand.Rec, StringRef("ImmediateCode")); - CondStream.indent(6) << "MI.getOperand(" + std::to_string(OpIdx) + - ").isImm() && \n"; - CondStream.indent(6) << Namespace + "ValidateMachineOperand(" + - "MI.getOperand(" + std::to_string(OpIdx) + - "), Subtarget, " + std::to_string(Entry) + - ") &&\n"; + unsigned Entry = + getPredicates(ImmLeafPredicateMap, ImmLeafPredicates, + DestOperand.Rec, "ImmediateCode"); + CondStream.indent(6) + << "MI.getOperand(" << OpIdx << ").isImm() &&\n"; + CondStream.indent(6) << Namespace << "ValidateMachineOperand(" + << "MI.getOperand(" << OpIdx + << "), Subtarget, " << Entry << ") &&\n"; } if (CompressOrUncompress) - CodeStream.indent(6) << "OutInst.addOperand(MI.getOperand(" + - std::to_string(OpIdx) + "));\n"; + CodeStream.indent(6) + << "OutInst.addOperand(MI.getOperand(" << OpIdx << "));\n"; } break; } case OpData::Imm: { if (CompressOrUncompress) { unsigned Entry = getPredicates(MCOpPredicateMap, MCOpPredicates, - DestOperand.Rec, StringRef("MCOperandPredicate")); + DestOperand.Rec, "MCOperandPredicate"); CondStream.indent(6) - << Namespace + "ValidateMCOperand(" + "MCOperand::createImm(" + - std::to_string(DestOperandMap[OpNo].Data.Imm) + "), STI, " + - std::to_string(Entry) + ") &&\n"; + << Namespace << "ValidateMCOperand(" + << "MCOperand::createImm(" << DestOperandMap[OpNo].Data.Imm + << "), STI, " << Entry << ") &&\n"; } else { unsigned Entry = getPredicates(ImmLeafPredicateMap, ImmLeafPredicates, - DestOperand.Rec, StringRef("ImmediateCode")); + DestOperand.Rec, "ImmediateCode"); CondStream.indent(6) - << Namespace + "ValidateMachineOperand(" + "MachineOperand::CreateImm(" + - std::to_string(DestOperandMap[OpNo].Data.Imm) + "), SubTarget, " + - std::to_string(Entry) + ") &&\n"; + << Namespace + << "ValidateMachineOperand(MachineOperand::CreateImm(" + << DestOperandMap[OpNo].Data.Imm << "), SubTarget, " << Entry + << ") &&\n"; } if (CompressOrUncompress) - CodeStream.indent(6) - << "OutInst.addOperand(MCOperand::createImm(" + - std::to_string(DestOperandMap[OpNo].Data.Imm) + "));\n"; + CodeStream.indent(6) << "OutInst.addOperand(MCOperand::createImm(" + << DestOperandMap[OpNo].Data.Imm << "));\n"; } break; case OpData::Reg: { if (CompressOrUncompress) { // Fixed register has been validated at pattern validation time. Record *Reg = DestOperandMap[OpNo].Data.Reg; - CodeStream.indent(6) << "OutInst.addOperand(MCOperand::createReg(" + - Namespace + "::" + Reg->getName().str() + - "));\n"; + CodeStream.indent(6) + << "OutInst.addOperand(MCOperand::createReg(" << Namespace + << "::" << Reg->getName() << "));\n"; } } break; } @@ -828,12 +812,12 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, } if (CompressOrUncompress) CodeStream.indent(6) << "OutInst.setLoc(MI.getLoc());\n"; - CaseStream << mergeCondAndCode(CondStream, CodeStream); + mergeCondAndCode(CaseStream, CondStream.str(), CodeStream.str()); PrevOp = CurOp; } Func << CaseStream.str() << "\n"; // Close brace for the last case. - Func.indent(4) << "} // case " + CurOp + "\n"; + Func.indent(4) << "} // case " << CurOp << "\n"; Func.indent(2) << "} // switch\n"; Func.indent(2) << "return false;\n}\n"; @@ -858,7 +842,7 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, << "ValidateMachineOperand(const MachineOperand &MO,\n" << " const RISCVSubtarget *Subtarget,\n" << " unsigned PredicateIndex) {\n" - << " int64_t Imm = MO.getImm(); \n" + << " int64_t Imm = MO.getImm();\n" << " switch (PredicateIndex) {\n" << " default:\n" << " llvm_unreachable(\"Unknown ImmLeaf Predicate kind\");\n" @@ -884,13 +868,7 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, } void RISCVCompressInstEmitter::run(raw_ostream &o) { - Record *CompressClass = Records.getClass("CompressPat"); - assert(CompressClass && "Compress class definition missing!"); - std::vector<Record *> Insts; - for (const auto &D : Records.getDefs()) { - if (D.second->isSubClassOf(CompressClass)) - Insts.push_back(D.second.get()); - } + std::vector<Record *> Insts = Records.getAllDerivedDefinitions("CompressPat"); // Process the CompressPat definitions, validating them as we do so. for (unsigned i = 0, e = Insts.size(); i != e; ++i) diff --git a/llvm/utils/TableGen/RegisterBankEmitter.cpp b/llvm/utils/TableGen/RegisterBankEmitter.cpp index 586f857b1fb0..0725657150f8 100644 --- a/llvm/utils/TableGen/RegisterBankEmitter.cpp +++ b/llvm/utils/TableGen/RegisterBankEmitter.cpp @@ -71,10 +71,7 @@ public: /// Add a register class to the bank without duplicates. void addRegisterClass(const CodeGenRegisterClass *RC) { - if (std::find_if(RCs.begin(), RCs.end(), - [&RC](const CodeGenRegisterClass *X) { - return X == RC; - }) != RCs.end()) + if (llvm::is_contained(RCs, RC)) return; // FIXME? We really want the register size rather than the spill size @@ -131,9 +128,12 @@ void RegisterBankEmitter::emitHeader(raw_ostream &OS, // <Target>RegisterBankInfo.h OS << "namespace llvm {\n" << "namespace " << TargetName << " {\n" - << "enum {\n"; + << "enum : unsigned {\n"; + + OS << " InvalidRegBankID = ~0u,\n"; + unsigned ID = 0; for (const auto &Bank : Banks) - OS << " " << Bank.getEnumeratorName() << ",\n"; + OS << " " << Bank.getEnumeratorName() << " = " << ID++ << ",\n"; OS << " NumRegisterBanks,\n" << "};\n" << "} // end namespace " << TargetName << "\n" @@ -168,7 +168,7 @@ void RegisterBankEmitter::emitBaseClassDefinition( /// to the class. static void visitRegisterBankClasses( const CodeGenRegBank &RegisterClassHierarchy, - const CodeGenRegisterClass *RC, const Twine Kind, + const CodeGenRegisterClass *RC, const Twine &Kind, std::function<void(const CodeGenRegisterClass *, StringRef)> VisitFn, SmallPtrSetImpl<const CodeGenRegisterClass *> &VisitedRCs) { @@ -182,7 +182,7 @@ static void visitRegisterBankClasses( for (const auto &PossibleSubclass : RegisterClassHierarchy.getRegClasses()) { std::string TmpKind = - (Twine(Kind) + " (" + PossibleSubclass.getName() + ")").str(); + (Kind + " (" + PossibleSubclass.getName() + ")").str(); // Visit each subclass of an explicitly named class. if (RC != &PossibleSubclass && RC->hasSubClass(&PossibleSubclass)) @@ -279,6 +279,7 @@ void RegisterBankEmitter::run(raw_ostream &OS) { StringRef TargetName = Target.getName(); const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank(); + Records.startTimer("Analyze records"); std::vector<RegisterBank> Banks; for (const auto &V : Records.getAllDerivedDefinitions("RegisterBank")) { SmallPtrSet<const CodeGenRegisterClass *, 8> VisitedRCs; @@ -300,6 +301,7 @@ void RegisterBankEmitter::run(raw_ostream &OS) { } // Warn about ambiguous MIR caused by register bank/class name clashes. + Records.startTimer("Warn ambiguous"); for (const auto &Class : RegisterClassHierarchy.getRegClasses()) { for (const auto &Bank : Banks) { if (Bank.getName().lower() == StringRef(Class.getName()).lower()) { @@ -312,6 +314,7 @@ void RegisterBankEmitter::run(raw_ostream &OS) { } } + Records.startTimer("Emit output"); emitSourceFileHeader("Register Bank Source Fragments", OS); OS << "#ifdef GET_REGBANK_DECLARATIONS\n" << "#undef GET_REGBANK_DECLARATIONS\n"; diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp index a615587efdee..dce7594dec2f 100644 --- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp +++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp @@ -127,7 +127,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, OS << " " << Reg.getName() << " = " << Reg.EnumValue << ",\n"; assert(Registers.size() == Registers.back().EnumValue && "Register enum value mismatch!"); - OS << " NUM_TARGET_REGS \t// " << Registers.size()+1 << "\n"; + OS << " NUM_TARGET_REGS // " << Registers.size()+1 << "\n"; OS << "};\n"; if (!Namespace.empty()) OS << "} // end namespace " << Namespace << "\n"; @@ -146,7 +146,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, for (const auto &RC : RegisterClasses) OS << " " << RC.getName() << "RegClassID" << " = " << RC.EnumValue << ",\n"; - OS << "\n };\n"; + OS << "\n};\n"; if (!Namespace.empty()) OS << "} // end namespace " << Namespace << "\n\n"; } @@ -323,7 +323,7 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, OS << "/// Get the dimensions of register pressure impacted by this " << "register class.\n" << "/// Returns a -1 terminated array of pressure set IDs\n" - << "const int* " << ClassName << "::\n" + << "const int *" << ClassName << "::\n" << "getRegClassPressureSets(const TargetRegisterClass *RC) const {\n"; OS << " static const " << getMinimalTypeForRange(PSetsSeqs.size() - 1, 32) << " RCSetStartTable[] = {\n "; @@ -337,7 +337,7 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, OS << "/// Get the dimensions of register pressure impacted by this " << "register unit.\n" << "/// Returns a -1 terminated array of pressure set IDs\n" - << "const int* " << ClassName << "::\n" + << "const int *" << ClassName << "::\n" << "getRegUnitPressureSets(unsigned RegUnit) const {\n" << " assert(RegUnit < " << RegBank.getNumNativeRegUnits() << " && \"invalid register unit\");\n"; @@ -356,11 +356,10 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, using DwarfRegNumsMapPair = std::pair<Record*, std::vector<int64_t>>; using DwarfRegNumsVecTy = std::vector<DwarfRegNumsMapPair>; -void finalizeDwarfRegNumsKeys(DwarfRegNumsVecTy &DwarfRegNums) { +static void finalizeDwarfRegNumsKeys(DwarfRegNumsVecTy &DwarfRegNums) { // Sort and unique to get a map-like vector. We want the last assignment to // match previous behaviour. - std::stable_sort(DwarfRegNums.begin(), DwarfRegNums.end(), - on_first<LessRecordRegister>()); + llvm::stable_sort(DwarfRegNums, on_first<LessRecordRegister>()); // Warn about duplicate assignments. const Record *LastSeenReg = nullptr; for (const auto &X : DwarfRegNums) { @@ -462,18 +461,16 @@ void RegisterInfoEmitter::EmitRegMappingTables( DefInit *DI = cast<DefInit>(V->getValue()); Record *Alias = DI->getDef(); - const auto &AliasIter = - std::lower_bound(DwarfRegNums.begin(), DwarfRegNums.end(), Alias, - [](const DwarfRegNumsMapPair &A, const Record *B) { - return LessRecordRegister()(A.first, B); - }); + const auto &AliasIter = llvm::lower_bound( + DwarfRegNums, Alias, [](const DwarfRegNumsMapPair &A, const Record *B) { + return LessRecordRegister()(A.first, B); + }); assert(AliasIter != DwarfRegNums.end() && AliasIter->first == Alias && "Expected Alias to be present in map"); - const auto &RegIter = - std::lower_bound(DwarfRegNums.begin(), DwarfRegNums.end(), Reg, - [](const DwarfRegNumsMapPair &A, const Record *B) { - return LessRecordRegister()(A.first, B); - }); + const auto &RegIter = llvm::lower_bound( + DwarfRegNums, Reg, [](const DwarfRegNumsMapPair &A, const Record *B) { + return LessRecordRegister()(A.first, B); + }); assert(RegIter != DwarfRegNums.end() && RegIter->first == Reg && "Expected Reg to be present in map"); RegIter->second = AliasIter->second; @@ -960,7 +957,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, const auto &RUMasks = Reg.getRegUnitLaneMasks(); MaskVec &LaneMaskVec = RegUnitLaneMasks[i]; assert(LaneMaskVec.empty()); - LaneMaskVec.insert(LaneMaskVec.begin(), RUMasks.begin(), RUMasks.end()); + llvm::append_range(LaneMaskVec, RUMasks); // Terminator mask should not be used inside of the list. #ifndef NDEBUG for (LaneBitmask M : LaneMaskVec) { @@ -1167,7 +1164,7 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target, << " LaneBitmask reverseComposeSubRegIndexLaneMaskImpl" << "(unsigned, LaneBitmask) const override;\n" << " const TargetRegisterClass *getSubClassWithSubReg" - << "(const TargetRegisterClass*, unsigned) const override;\n"; + << "(const TargetRegisterClass *, unsigned) const override;\n"; } OS << " const RegClassWeight &getRegClassWeight(" << "const TargetRegisterClass *RC) const override;\n" @@ -1288,7 +1285,8 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, OS << CGH.getMode(M).Name; OS << ")\n"; for (const auto &RC : RegisterClasses) { - assert(RC.EnumValue == EV++ && "Unexpected order of register classes"); + assert(RC.EnumValue == EV && "Unexpected order of register classes"); + ++EV; (void)EV; const RegSizeInfo &RI = RC.RSI.get(M); OS << " { " << RI.RegSize << ", " << RI.SpillSize << ", " @@ -1435,7 +1433,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, } OS << "\nnamespace {\n"; - OS << " const TargetRegisterClass* const RegisterClasses[] = {\n"; + OS << " const TargetRegisterClass *const RegisterClasses[] = {\n"; for (const auto &RC : RegisterClasses) OS << " &" << RC.getQualifiedName() << "RegClass,\n"; OS << " };\n"; @@ -1615,9 +1613,16 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, void RegisterInfoEmitter::run(raw_ostream &OS) { CodeGenRegBank &RegBank = Target.getRegBank(); + Records.startTimer("Print enums"); runEnums(OS, Target, RegBank); + + Records.startTimer("Print MC registers"); runMCDesc(OS, Target, RegBank); + + Records.startTimer("Print header fragment"); runTargetHeader(OS, Target, RegBank); + + Records.startTimer("Print target registers"); runTargetDesc(OS, Target, RegBank); if (RegisterInfoDebug) diff --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp index 326cb4e54edc..912d43b2caa1 100644 --- a/llvm/utils/TableGen/SearchableTableEmitter.cpp +++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp @@ -12,6 +12,8 @@ // //===----------------------------------------------------------------------===// +#include "CodeGenIntrinsics.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Format.h" @@ -19,7 +21,6 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" -#include "CodeGenIntrinsics.h" #include <algorithm> #include <set> #include <string> @@ -53,6 +54,7 @@ struct GenericEnum { struct GenericField { std::string Name; RecTy *RecType = nullptr; + bool IsCode = false; bool IsIntrinsic = false; bool IsInstruction = false; GenericEnum *Enum = nullptr; @@ -62,12 +64,14 @@ struct GenericField { struct SearchIndex { std::string Name; + SMLoc Loc; // Source location of PrimaryKey or Key field definition. SmallVector<GenericField, 1> Fields; bool EarlyOut = false; }; struct GenericTable { std::string Name; + ArrayRef<SMLoc> Locs; // Source locations from the Record instance. std::string PreprocessorGuard; std::string CppTypeName; SmallVector<GenericField, 2> Fields; @@ -106,15 +110,17 @@ private: TypeInArgument, }; - std::string primaryRepresentation(const GenericField &Field, Init *I) { - if (StringInit *SI = dyn_cast<StringInit>(I)) - return SI->getAsString(); - else if (BitsInit *BI = dyn_cast<BitsInit>(I)) + std::string primaryRepresentation(SMLoc Loc, const GenericField &Field, + Init *I) { + if (StringInit *SI = dyn_cast<StringInit>(I)) { + if (Field.IsCode || SI->hasCodeFormat()) + return std::string(SI->getValue()); + else + 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 std::string(CI->getValue()); else if (Field.IsIntrinsic) return "Intrinsic::" + getIntrinsic(I).EnumName; else if (Field.IsInstruction) @@ -122,11 +128,12 @@ private: else if (Field.Enum) { auto *Entry = Field.Enum->EntryMap[cast<DefInit>(I)->getDef()]; if (!Entry) - PrintFatalError(Twine("Entry for field '") + Field.Name + "' is null"); + PrintFatalError(Loc, + Twine("Entry for field '") + Field.Name + "' is null"); return std::string(Entry->first); } - PrintFatalError(Twine("invalid field type for field '") + Field.Name + - "', expected: string, bits, bit or code"); + PrintFatalError(Loc, Twine("invalid field type for field '") + Field.Name + + "'; expected: bit, bits, string, or code"); } bool isIntrinsic(Init *I) { @@ -138,17 +145,16 @@ private: CodeGenIntrinsic &getIntrinsic(Init *I) { std::unique_ptr<CodeGenIntrinsic> &Intr = Intrinsics[I]; if (!Intr) - Intr = std::make_unique<CodeGenIntrinsic>(cast<DefInit>(I)->getDef()); + Intr = std::make_unique<CodeGenIntrinsic>(cast<DefInit>(I)->getDef(), + std::vector<Record *>()); return *Intr; } bool compareBy(Record *LHS, Record *RHS, const SearchIndex &Index); - bool isIntegral(Init *I) { - return isa<BitsInit>(I) || isa<CodeInit>(I) || isIntrinsic(I); - } - - std::string searchableFieldType(const GenericField &Field, TypeContext Ctx) { + std::string searchableFieldType(const GenericTable &Table, + const SearchIndex &Index, + const GenericField &Field, TypeContext Ctx) { if (isa<StringRecTy>(Field.RecType)) { if (Ctx == TypeInStaticStruct) return "const char *"; @@ -165,12 +171,16 @@ private: return "uint32_t"; if (NumBits <= 64) return "uint64_t"; - PrintFatalError(Twine("bitfield '") + Field.Name + - "' too large to search"); + PrintFatalError(Index.Loc, Twine("In table '") + Table.Name + + "' lookup method '" + Index.Name + + "', key field '" + Field.Name + + "' of type bits is too large"); } else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction) return "unsigned"; - PrintFatalError(Twine("Field '") + Field.Name + "' has unknown type '" + - Field.RecType->getAsString() + "' to search by"); + PrintFatalError(Index.Loc, + Twine("In table '") + Table.Name + "' lookup method '" + + Index.Name + "', key field '" + Field.Name + + "' has invalid type: " + Field.RecType->getAsString()); } void emitGenericTable(const GenericTable &Table, raw_ostream &OS); @@ -183,7 +193,7 @@ private: bool parseFieldType(GenericField &Field, Init *II); std::unique_ptr<SearchIndex> - parseSearchIndex(GenericTable &Table, StringRef Name, + parseSearchIndex(GenericTable &Table, const RecordVal *RecVal, StringRef Name, const std::vector<StringRef> &Key, bool EarlyOut); void collectEnumEntries(GenericEnum &Enum, StringRef NameField, StringRef ValueField, @@ -258,8 +268,8 @@ bool SearchableTableEmitter::compareBy(Record *LHS, Record *RHS, if (LHSv > RHSv) return false; } else { - std::string LHSs = primaryRepresentation(Field, LHSI); - std::string RHSs = primaryRepresentation(Field, RHSI); + std::string LHSs = primaryRepresentation(Index.Loc, Field, LHSI); + std::string RHSs = primaryRepresentation(Index.Loc, Field, RHSI); if (isa<StringRecTy>(Field.RecType)) { LHSs = StringRef(LHSs).upper(); @@ -314,7 +324,8 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table, } else { OS << " struct IndexType {\n"; for (const auto &Field : Index.Fields) { - OS << " " << searchableFieldType(Field, TypeInStaticStruct) << " " + OS << " " + << searchableFieldType(Table, Index, Field, TypeInStaticStruct) << " " << Field.Name << ";\n"; } OS << " unsigned _index;\n"; @@ -327,11 +338,10 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table, for (unsigned i = 0; i < Table.Entries.size(); ++i) Entries.emplace_back(Table.Entries[i], i); - std::stable_sort(Entries.begin(), Entries.end(), - [&](const std::pair<Record *, unsigned> &LHS, - const std::pair<Record *, unsigned> &RHS) { - return compareBy(LHS.first, RHS.first, Index); - }); + llvm::stable_sort(Entries, [&](const std::pair<Record *, unsigned> &LHS, + const std::pair<Record *, unsigned> &RHS) { + return compareBy(LHS.first, RHS.first, Index); + }); IndexRowsStorage.reserve(Entries.size()); for (const auto &Entry : Entries) { @@ -344,8 +354,8 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table, OS << ", "; NeedComma = true; - std::string Repr = - primaryRepresentation(Field, Entry.first->getValueInit(Field.Name)); + std::string Repr = primaryRepresentation( + Index.Loc, Field, Entry.first->getValueInit(Field.Name)); if (isa<StringRecTy>(Field.RecType)) Repr = StringRef(Repr).upper(); OS << Repr; @@ -388,10 +398,10 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table, if (Index.EarlyOut) { const GenericField &Field = Index.Fields[0]; - std::string FirstRepr = - primaryRepresentation(Field, IndexRows[0]->getValueInit(Field.Name)); + std::string FirstRepr = primaryRepresentation( + Index.Loc, Field, IndexRows[0]->getValueInit(Field.Name)); std::string LastRepr = primaryRepresentation( - Field, IndexRows.back()->getValueInit(Field.Name)); + Index.Loc, Field, IndexRows.back()->getValueInit(Field.Name)); OS << " if ((" << Field.Name << " < " << FirstRepr << ") ||\n"; OS << " (" << Field.Name << " > " << LastRepr << "))\n"; OS << " return nullptr;\n\n"; @@ -399,11 +409,11 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table, OS << " struct KeyType {\n"; for (const auto &Field : Index.Fields) { - OS << " " << searchableFieldType(Field, TypeInTempStruct) << " " - << Field.Name << ";\n"; + OS << " " << searchableFieldType(Table, Index, Field, TypeInTempStruct) + << " " << Field.Name << ";\n"; } OS << " };\n"; - OS << " KeyType Key = { "; + OS << " KeyType Key = {"; bool NeedComma = false; for (const auto &Field : Index.Fields) { if (NeedComma) @@ -414,12 +424,14 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table, if (isa<StringRecTy>(Field.RecType)) { OS << ".upper()"; if (IsPrimary) - PrintFatalError(Twine("Use a secondary index for case-insensitive " - "comparison of field '") + - Field.Name + "' in table '" + Table.Name + "'"); + PrintFatalError(Index.Loc, + Twine("In table '") + Table.Name + + "', use a secondary lookup method for " + "case-insensitive comparison of field '" + + Field.Name + "'"); } } - OS << " };\n"; + OS << "};\n"; OS << " auto Table = makeArrayRef(" << IndexName << ");\n"; OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n"; @@ -476,7 +488,8 @@ void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table, OS << ", "; NeedComma = true; - OS << searchableFieldType(Field, TypeInArgument) << " " << Field.Name; + OS << searchableFieldType(Table, Index, Field, TypeInArgument) << " " + << Field.Name; } OS << ")"; } @@ -511,7 +524,8 @@ void SearchableTableEmitter::emitGenericTable(const GenericTable &Table, OS << ", "; NeedComma = true; - OS << primaryRepresentation(Field, Entry->getValueInit(Field.Name)); + OS << primaryRepresentation(Table.Locs[0], Field, + Entry->getValueInit(Field.Name)); } OS << " }, // " << i << "\n"; @@ -528,40 +542,49 @@ void SearchableTableEmitter::emitGenericTable(const GenericTable &Table, OS << "#endif\n\n"; } -bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *II) { - if (auto DI = dyn_cast<DefInit>(II)) { - Record *TypeRec = DI->getDef(); - if (TypeRec->isSubClassOf("GenericEnum")) { - Field.Enum = EnumMap[TypeRec]; - Field.RecType = RecordRecTy::get(Field.Enum->Class); +bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *TypeOf) { + if (auto Type = dyn_cast<StringInit>(TypeOf)) { + if (Type->getValue() == "code") { + Field.IsCode = true; return true; + } else { + if (Record *TypeRec = Records.getDef(Type->getValue())) { + if (TypeRec->isSubClassOf("GenericEnum")) { + Field.Enum = EnumMap[TypeRec]; + Field.RecType = RecordRecTy::get(Field.Enum->Class); + return true; + } + } } } return false; } -std::unique_ptr<SearchIndex> -SearchableTableEmitter::parseSearchIndex(GenericTable &Table, StringRef Name, - const std::vector<StringRef> &Key, - bool EarlyOut) { +std::unique_ptr<SearchIndex> SearchableTableEmitter::parseSearchIndex( + GenericTable &Table, const RecordVal *KeyRecVal, StringRef Name, + const std::vector<StringRef> &Key, bool EarlyOut) { auto Index = std::make_unique<SearchIndex>(); Index->Name = std::string(Name); + Index->Loc = KeyRecVal->getLoc(); Index->EarlyOut = EarlyOut; for (const auto &FieldName : Key) { const GenericField *Field = Table.getFieldByName(FieldName); if (!Field) - PrintFatalError(Twine("Search index '") + Name + - "' refers to non-existing field '" + FieldName + - "' in table '" + Table.Name + "'"); + PrintFatalError( + KeyRecVal, + Twine("In table '") + Table.Name + + "', 'PrimaryKey' or 'Key' refers to nonexistent field '" + + FieldName + "'"); + Index->Fields.push_back(*Field); } if (EarlyOut && isa<StringRecTy>(Index->Fields[0].RecType)) { PrintFatalError( - "Early-out is not supported for string types (in search index '" + - Twine(Name) + "'"); + KeyRecVal, Twine("In lookup method '") + Name + "', early-out is not " + + "supported for a first key field of type string"); } return Index; @@ -586,11 +609,11 @@ void SearchableTableEmitter::collectEnumEntries( } if (ValueField.empty()) { - std::stable_sort(Enum.Entries.begin(), Enum.Entries.end(), - [](const std::unique_ptr<GenericEnum::Entry> &LHS, - const std::unique_ptr<GenericEnum::Entry> &RHS) { - return LHS->first < RHS->first; - }); + llvm::stable_sort(Enum.Entries, + [](const std::unique_ptr<GenericEnum::Entry> &LHS, + const std::unique_ptr<GenericEnum::Entry> &RHS) { + return LHS->first < RHS->first; + }); for (size_t i = 0; i < Enum.Entries.size(); ++i) Enum.Entries[i]->second = i; @@ -600,31 +623,33 @@ void SearchableTableEmitter::collectEnumEntries( void SearchableTableEmitter::collectTableEntries( GenericTable &Table, const std::vector<Record *> &Items) { if (Items.empty()) - PrintWarning(Twine("Table '") + Table.Name + "' has no items"); + PrintFatalError(Table.Locs, + Twine("Table '") + Table.Name + "' has no entries"); for (auto EntryRec : Items) { for (auto &Field : Table.Fields) { auto TI = dyn_cast<TypedInit>(EntryRec->getValueInit(Field.Name)); if (!TI || !TI->isComplete()) { - PrintFatalError(EntryRec->getLoc(), - Twine("Record '") + EntryRec->getName() + - "' in table '" + Table.Name + - "' is missing field '" + Field.Name + "'"); + PrintFatalError(EntryRec, Twine("Record '") + EntryRec->getName() + + "' for table '" + Table.Name + + "' is missing field '" + Field.Name + + "'"); } if (!Field.RecType) { Field.RecType = TI->getType(); } else { RecTy *Ty = resolveTypes(Field.RecType, TI->getType()); if (!Ty) - PrintFatalError(Twine("Field '") + Field.Name + "' of table '" + - Table.Name + "' has incompatible type: " + - Field.RecType->getAsString() + " vs. " + - TI->getType()->getAsString()); + PrintFatalError(EntryRec->getValue(Field.Name), + Twine("Field '") + Field.Name + "' of table '" + + Table.Name + "' entry has incompatible type: " + + TI->getType()->getAsString() + " vs. " + + Field.RecType->getAsString()); Field.RecType = Ty; } } - Table.Entries.push_back(EntryRec); + Table.Entries.push_back(EntryRec); // Add record to table's record list. } Record *IntrinsicClass = Records.getClass("Intrinsic"); @@ -665,8 +690,9 @@ void SearchableTableEmitter::run(raw_ostream &OS) { StringRef FilterClass = EnumRec->getValueAsString("FilterClass"); Enum->Class = Records.getClass(FilterClass); if (!Enum->Class) - PrintFatalError(EnumRec->getLoc(), Twine("Enum FilterClass '") + - FilterClass + "' does not exist"); + PrintFatalError(EnumRec->getValue("FilterClass"), + Twine("Enum FilterClass '") + FilterClass + + "' does not exist"); collectEnumEntries(*Enum, NameField, ValueField, Records.getAllDerivedDefinitions(FilterClass)); @@ -677,36 +703,44 @@ void SearchableTableEmitter::run(raw_ostream &OS) { for (auto TableRec : Records.getAllDerivedDefinitions("GenericTable")) { auto Table = std::make_unique<GenericTable>(); Table->Name = std::string(TableRec->getName()); + Table->Locs = TableRec->getLoc(); Table->PreprocessorGuard = std::string(TableRec->getName()); Table->CppTypeName = std::string(TableRec->getValueAsString("CppTypeName")); std::vector<StringRef> Fields = TableRec->getValueAsListOfStrings("Fields"); for (const auto &FieldName : Fields) { - Table->Fields.emplace_back(FieldName); - - if (auto TypeOfVal = TableRec->getValue(("TypeOf_" + FieldName).str())) { - if (!parseFieldType(Table->Fields.back(), TypeOfVal->getValue())) { - PrintFatalError(TableRec->getLoc(), - Twine("Table '") + Table->Name + - "' has bad 'TypeOf_" + FieldName + - "': " + TypeOfVal->getValue()->getAsString()); + Table->Fields.emplace_back(FieldName); // Construct a GenericField. + + if (auto TypeOfRecordVal = TableRec->getValue(("TypeOf_" + FieldName).str())) { + if (!parseFieldType(Table->Fields.back(), TypeOfRecordVal->getValue())) { + PrintError(TypeOfRecordVal, + Twine("Table '") + Table->Name + + "' has invalid 'TypeOf_" + FieldName + + "': " + TypeOfRecordVal->getValue()->getAsString()); + PrintFatalNote("The 'TypeOf_xxx' field must be a string naming a " + "GenericEnum record, or \"code\""); } } } - collectTableEntries(*Table, Records.getAllDerivedDefinitions( - TableRec->getValueAsString("FilterClass"))); + StringRef FilterClass = TableRec->getValueAsString("FilterClass"); + if (!Records.getClass(FilterClass)) + PrintFatalError(TableRec->getValue("FilterClass"), + Twine("Table FilterClass '") + + FilterClass + "' does not exist"); + + collectTableEntries(*Table, Records.getAllDerivedDefinitions(FilterClass)); if (!TableRec->isValueUnset("PrimaryKey")) { Table->PrimaryKey = - parseSearchIndex(*Table, TableRec->getValueAsString("PrimaryKeyName"), + parseSearchIndex(*Table, TableRec->getValue("PrimaryKey"), + TableRec->getValueAsString("PrimaryKeyName"), TableRec->getValueAsListOfStrings("PrimaryKey"), TableRec->getValueAsBit("PrimaryKeyEarlyOut")); - std::stable_sort(Table->Entries.begin(), Table->Entries.end(), - [&](Record *LHS, Record *RHS) { - return compareBy(LHS, RHS, *Table->PrimaryKey); - }); + llvm::stable_sort(Table->Entries, [&](Record *LHS, Record *RHS) { + return compareBy(LHS, RHS, *Table->PrimaryKey); + }); } TableMap.insert(std::make_pair(TableRec, Table.get())); @@ -717,15 +751,16 @@ void SearchableTableEmitter::run(raw_ostream &OS) { Record *TableRec = IndexRec->getValueAsDef("Table"); auto It = TableMap.find(TableRec); if (It == TableMap.end()) - PrintFatalError(IndexRec->getLoc(), + PrintFatalError(IndexRec->getValue("Table"), Twine("SearchIndex '") + IndexRec->getName() + - "' refers to non-existing table '" + + "' refers to nonexistent table '" + TableRec->getName()); GenericTable &Table = *It->second; - Table.Indices.push_back(parseSearchIndex( - Table, IndexRec->getName(), IndexRec->getValueAsListOfStrings("Key"), - IndexRec->getValueAsBit("EarlyOut"))); + Table.Indices.push_back( + parseSearchIndex(Table, IndexRec->getValue("Key"), IndexRec->getName(), + IndexRec->getValueAsListOfStrings("Key"), + IndexRec->getValueAsBit("EarlyOut"))); } // Translate legacy tables. @@ -756,6 +791,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) { auto Table = std::make_unique<GenericTable>(); Table->Name = (Twine(Class->getName()) + "sList").str(); + Table->Locs = Class->getLoc(); Table->PreprocessorGuard = Class->getName().upper(); Table->CppTypeName = std::string(Class->getName()); @@ -778,7 +814,8 @@ void SearchableTableEmitter::run(raw_ostream &OS) { Class->getValueAsListOfStrings("SearchableFields")) { std::string Name = (Twine("lookup") + Table->CppTypeName + "By" + Field).str(); - Table->Indices.push_back(parseSearchIndex(*Table, Name, {Field}, false)); + Table->Indices.push_back(parseSearchIndex(*Table, Class->getValue(Field), + Name, {Field}, false)); } Tables.emplace_back(std::move(Table)); diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp index 68ee839c43ba..7d2b4b929df3 100644 --- a/llvm/utils/TableGen/SubtargetEmitter.cpp +++ b/llvm/utils/TableGen/SubtargetEmitter.cpp @@ -114,7 +114,6 @@ class SubtargetEmitter { SchedClassTables &SchedTables); void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS); void EmitProcessorModels(raw_ostream &OS); - void EmitProcessorLookup(raw_ostream &OS); void EmitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS); void emitSchedModelHelpersImpl(raw_ostream &OS, bool OnlyExpandMCInstPredicates = false); @@ -267,12 +266,15 @@ SubtargetEmitter::CPUKeyValues(raw_ostream &OS, for (Record *Processor : ProcessorList) { StringRef Name = Processor->getValueAsString("Name"); RecVec FeatureList = Processor->getValueAsListOfDefs("Features"); + RecVec TuneFeatureList = Processor->getValueAsListOfDefs("TuneFeatures"); // Emit as { "cpu", "description", 0, { f1 , f2 , ... fn } }, OS << " { " << "\"" << Name << "\", "; printFeatureMask(OS, FeatureList, FeatureMap); + OS << ", "; + printFeatureMask(OS, TuneFeatureList, FeatureMap); // Emit the scheduler model pointer. const std::string &ProcModelName = @@ -728,10 +730,8 @@ void SubtargetEmitter::EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel, unsigned QueueID = 0; if (ProcModel.LoadQueue) { const Record *Queue = ProcModel.LoadQueue->getValueAsDef("QueueDescriptor"); - QueueID = - 1 + std::distance(ProcModel.ProcResourceDefs.begin(), - std::find(ProcModel.ProcResourceDefs.begin(), - ProcModel.ProcResourceDefs.end(), Queue)); + QueueID = 1 + std::distance(ProcModel.ProcResourceDefs.begin(), + find(ProcModel.ProcResourceDefs, Queue)); } OS << " " << QueueID << ", // Resource Descriptor for the Load Queue\n"; @@ -739,10 +739,8 @@ void SubtargetEmitter::EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel, if (ProcModel.StoreQueue) { const Record *Queue = ProcModel.StoreQueue->getValueAsDef("QueueDescriptor"); - QueueID = - 1 + std::distance(ProcModel.ProcResourceDefs.begin(), - std::find(ProcModel.ProcResourceDefs.begin(), - ProcModel.ProcResourceDefs.end(), Queue)); + QueueID = 1 + std::distance(ProcModel.ProcResourceDefs.begin(), + find(ProcModel.ProcResourceDefs, Queue)); } OS << " " << QueueID << ", // Resource Descriptor for the Store Queue\n"; } @@ -1005,8 +1003,7 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, bool HasVariants = false; for (const CodeGenSchedTransition &CGT : make_range(SC.Transitions.begin(), SC.Transitions.end())) { - if (CGT.ProcIndices[0] == 0 || - is_contained(CGT.ProcIndices, ProcModel.Index)) { + if (CGT.ProcIndex == ProcModel.Index) { HasVariants = true; break; } @@ -1219,11 +1216,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, } else { SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size(); - SchedTables.WriteLatencies.insert(SchedTables.WriteLatencies.end(), - WriteLatencies.begin(), - WriteLatencies.end()); - SchedTables.WriterNames.insert(SchedTables.WriterNames.end(), - WriterNames.begin(), WriterNames.end()); + llvm::append_range(SchedTables.WriteLatencies, WriteLatencies); + llvm::append_range(SchedTables.WriterNames, WriterNames); } // ReadAdvanceEntries must remain in operand order. SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size(); @@ -1235,8 +1229,7 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin(); else { SCDesc.ReadAdvanceIdx = SchedTables.ReadAdvanceEntries.size(); - SchedTables.ReadAdvanceEntries.insert(RAPos, ReadAdvanceEntries.begin(), - ReadAdvanceEntries.end()); + llvm::append_range(SchedTables.ReadAdvanceEntries, ReadAdvanceEntries); } } } @@ -1443,20 +1436,20 @@ static void emitPredicateProlog(const RecordKeeper &Records, raw_ostream &OS) { OS << Buffer; } +static bool isTruePredicate(const Record *Rec) { + return Rec->isSubClassOf("MCSchedPredicate") && + Rec->getValueAsDef("Pred")->isSubClassOf("MCTrue"); +} + static void emitPredicates(const CodeGenSchedTransition &T, const CodeGenSchedClass &SC, PredicateExpander &PE, raw_ostream &OS) { std::string Buffer; raw_string_ostream SS(Buffer); - auto IsTruePredicate = [](const Record *Rec) { - return Rec->isSubClassOf("MCSchedPredicate") && - Rec->getValueAsDef("Pred")->isSubClassOf("MCTrue"); - }; - // If not all predicates are MCTrue, then we need an if-stmt. unsigned NumNonTruePreds = - T.PredTerm.size() - count_if(T.PredTerm, IsTruePredicate); + T.PredTerm.size() - count_if(T.PredTerm, isTruePredicate); SS.indent(PE.getIndentLevel() * 2); @@ -1468,7 +1461,7 @@ static void emitPredicates(const CodeGenSchedTransition &T, for (const Record *Rec : T.PredTerm) { // Skip predicates that evaluate to "true". - if (IsTruePredicate(Rec)) + if (isTruePredicate(Rec)) continue; if (FirstNonTruePredicate) { @@ -1504,7 +1497,8 @@ static void emitPredicates(const CodeGenSchedTransition &T, // Used by method `SubtargetEmitter::emitSchedModelHelpersImpl()` to generate // epilogue code for the auto-generated helper. -void emitSchedModelHelperEpilogue(raw_ostream &OS, bool ShouldReturnZero) { +static void emitSchedModelHelperEpilogue(raw_ostream &OS, + bool ShouldReturnZero) { if (ShouldReturnZero) { OS << " // Don't know how to resolve this scheduling class.\n" << " return 0;\n"; @@ -1514,15 +1508,15 @@ void emitSchedModelHelperEpilogue(raw_ostream &OS, bool ShouldReturnZero) { OS << " report_fatal_error(\"Expected a variant SchedClass\");\n"; } -bool hasMCSchedPredicates(const CodeGenSchedTransition &T) { +static bool hasMCSchedPredicates(const CodeGenSchedTransition &T) { return all_of(T.PredTerm, [](const Record *Rec) { return Rec->isSubClassOf("MCSchedPredicate"); }); } -void collectVariantClasses(const CodeGenSchedModels &SchedModels, - IdxVec &VariantClasses, - bool OnlyExpandMCInstPredicates) { +static void collectVariantClasses(const CodeGenSchedModels &SchedModels, + IdxVec &VariantClasses, + bool OnlyExpandMCInstPredicates) { for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) { // Ignore non-variant scheduling classes. if (SC.Transitions.empty()) @@ -1541,19 +1535,24 @@ void collectVariantClasses(const CodeGenSchedModels &SchedModels, } } -void collectProcessorIndices(const CodeGenSchedClass &SC, IdxVec &ProcIndices) { +static void collectProcessorIndices(const CodeGenSchedClass &SC, + IdxVec &ProcIndices) { // A variant scheduling class may define transitions for multiple // processors. This function identifies wich processors are associated with // transition rules specified by variant class `SC`. for (const CodeGenSchedTransition &T : SC.Transitions) { IdxVec PI; - std::set_union(T.ProcIndices.begin(), T.ProcIndices.end(), - ProcIndices.begin(), ProcIndices.end(), - std::back_inserter(PI)); + std::set_union(&T.ProcIndex, &T.ProcIndex + 1, ProcIndices.begin(), + ProcIndices.end(), std::back_inserter(PI)); ProcIndices.swap(PI); } } +static bool isAlwaysTrue(const CodeGenSchedTransition &T) { + return llvm::all_of(T.PredTerm, + [](const Record *R) { return isTruePredicate(R); }); +} + void SubtargetEmitter::emitSchedModelHelpersImpl( raw_ostream &OS, bool OnlyExpandMCInstPredicates) { IdxVec VariantClasses; @@ -1596,8 +1595,9 @@ void SubtargetEmitter::emitSchedModelHelpersImpl( } // Now emit transitions associated with processor PI. + const CodeGenSchedTransition *FinalT = nullptr; for (const CodeGenSchedTransition &T : SC.Transitions) { - if (PI != 0 && !count(T.ProcIndices, PI)) + if (PI != 0 && T.ProcIndex != PI) continue; // Emit only transitions based on MCSchedPredicate, if it's the case. @@ -1610,9 +1610,17 @@ void SubtargetEmitter::emitSchedModelHelpersImpl( if (OnlyExpandMCInstPredicates && !hasMCSchedPredicates(T)) continue; + // If transition is folded to 'return X' it should be the last one. + if (isAlwaysTrue(T)) { + FinalT = &T; + continue; + } PE.setIndentLevel(3); emitPredicates(T, SchedModels.getSchedClass(T.ToClassIdx), PE, OS); } + if (FinalT) + emitPredicates(*FinalT, SchedModels.getSchedClass(FinalT->ToClassIdx), + PE, OS); OS << " }\n"; @@ -1646,9 +1654,9 @@ void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName, OS << "unsigned " << ClassName << "\n::resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI," - << " unsigned CPUID) const {\n" + << " const MCInstrInfo *MCII, unsigned CPUID) const {\n" << " return " << Target << "_MC" - << "::resolveVariantSchedClassImpl(SchedClass, MI, CPUID);\n" + << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n" << "} // " << ClassName << "::resolveVariantSchedClass\n\n"; STIPredicateExpander PE(Target); @@ -1692,17 +1700,19 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS, << "// subtarget options.\n" << "void llvm::"; OS << Target; - OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef FS) {\n" + OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, " + << "StringRef FS) {\n" << " LLVM_DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n" - << " LLVM_DEBUG(dbgs() << \"\\nCPU:\" << CPU << \"\\n\\n\");\n"; + << " LLVM_DEBUG(dbgs() << \"\\nCPU:\" << CPU);\n" + << " LLVM_DEBUG(dbgs() << \"\\nTuneCPU:\" << TuneCPU << \"\\n\\n\");\n"; if (Features.empty()) { OS << "}\n"; return; } - OS << " InitMCProcessorInfo(CPU, FS);\n" - << " const FeatureBitset& Bits = getFeatureBits();\n"; + OS << " InitMCProcessorInfo(CPU, TuneCPU, FS);\n" + << " const FeatureBitset &Bits = getFeatureBits();\n"; for (Record *R : Features) { // Next record @@ -1727,26 +1737,28 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS, void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) { OS << "namespace " << Target << "_MC {\n" << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,\n" - << " const MCInst *MI, unsigned CPUID) {\n"; + << " const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID) {\n"; emitSchedModelHelpersImpl(OS, /* OnlyExpandMCPredicates */ true); OS << "}\n"; OS << "} // end namespace " << Target << "_MC\n\n"; OS << "struct " << Target << "GenMCSubtargetInfo : public MCSubtargetInfo {\n"; - OS << " " << Target << "GenMCSubtargetInfo(const Triple &TT, \n" - << " StringRef CPU, StringRef FS, ArrayRef<SubtargetFeatureKV> PF,\n" + OS << " " << Target << "GenMCSubtargetInfo(const Triple &TT,\n" + << " StringRef CPU, StringRef TuneCPU, StringRef FS,\n" + << " ArrayRef<SubtargetFeatureKV> PF,\n" << " ArrayRef<SubtargetSubTypeKV> PD,\n" << " const MCWriteProcResEntry *WPR,\n" << " const MCWriteLatencyEntry *WL,\n" << " const MCReadAdvanceEntry *RA, const InstrStage *IS,\n" << " const unsigned *OC, const unsigned *FP) :\n" - << " MCSubtargetInfo(TT, CPU, FS, PF, PD,\n" + << " MCSubtargetInfo(TT, CPU, TuneCPU, FS, PF, PD,\n" << " WPR, WL, RA, IS, OC, FP) { }\n\n" << " unsigned resolveVariantSchedClass(unsigned SchedClass,\n" - << " const MCInst *MI, unsigned CPUID) const override {\n" + << " const MCInst *MI, const MCInstrInfo *MCII,\n" + << " unsigned CPUID) const override {\n" << " return " << Target << "_MC" - << "::resolveVariantSchedClassImpl(SchedClass, MI, CPUID); \n"; + << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n"; OS << " }\n"; if (TGT.getHwModes().getNumModeIds() > 1) OS << " unsigned getHwMode() const override;\n"; @@ -1817,8 +1829,9 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "\nstatic inline MCSubtargetInfo *create" << Target << "MCSubtargetInfoImpl(" - << "const Triple &TT, StringRef CPU, StringRef FS) {\n"; - OS << " return new " << Target << "GenMCSubtargetInfo(TT, CPU, FS, "; + << "const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS) {\n"; + OS << " return new " << Target + << "GenMCSubtargetInfo(TT, CPU, TuneCPU, FS, "; if (NumFeatures) OS << Target << "FeatureKV, "; else @@ -1862,17 +1875,18 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "class DFAPacketizer;\n"; OS << "namespace " << Target << "_MC {\n" << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass," - << " const MCInst *MI, unsigned CPUID);\n" + << " const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID);\n" << "} // end namespace " << Target << "_MC\n\n"; OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n" << " explicit " << ClassName << "(const Triple &TT, StringRef CPU, " - << "StringRef FS);\n" + << "StringRef TuneCPU, StringRef FS);\n" << "public:\n" << " unsigned resolveSchedClass(unsigned SchedClass, " << " const MachineInstr *DefMI," << " const TargetSchedModel *SchedModel) const override;\n" << " unsigned resolveVariantSchedClass(unsigned SchedClass," - << " const MCInst *MI, unsigned CPUID) const override;\n" + << " const MCInst *MI, const MCInstrInfo *MCII," + << " unsigned CPUID) const override;\n" << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)" << " const;\n"; if (TGT.getHwModes().getNumModeIds() > 1) @@ -1909,8 +1923,8 @@ void SubtargetEmitter::run(raw_ostream &OS) { } OS << ClassName << "::" << ClassName << "(const Triple &TT, StringRef CPU, " - << "StringRef FS)\n" - << " : TargetSubtargetInfo(TT, CPU, FS, "; + << "StringRef TuneCPU, StringRef FS)\n" + << " : TargetSubtargetInfo(TT, CPU, TuneCPU, FS, "; if (NumFeatures) OS << "makeArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), "; else diff --git a/llvm/utils/TableGen/SubtargetFeatureInfo.cpp b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp index 3821f4757464..105ed82c9d02 100644 --- a/llvm/utils/TableGen/SubtargetFeatureInfo.cpp +++ b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp @@ -7,11 +7,10 @@ //===----------------------------------------------------------------------===// #include "SubtargetFeatureInfo.h" - #include "Types.h" #include "llvm/Config/llvm-config.h" +#include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" - #include <map> using namespace llvm; @@ -113,7 +112,7 @@ void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures( StringRef TargetName, StringRef ClassName, StringRef FuncName, SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) { OS << "FeatureBitset " << TargetName << ClassName << "::\n" - << FuncName << "(const FeatureBitset& FB) const {\n"; + << FuncName << "(const FeatureBitset &FB) const {\n"; OS << " FeatureBitset Features;\n"; for (const auto &SF : SubtargetFeatures) { const SubtargetFeatureInfo &SFI = SF.second; diff --git a/llvm/utils/TableGen/SubtargetFeatureInfo.h b/llvm/utils/TableGen/SubtargetFeatureInfo.h index d72f8b93461f..8c8a4487934c 100644 --- a/llvm/utils/TableGen/SubtargetFeatureInfo.h +++ b/llvm/utils/TableGen/SubtargetFeatureInfo.h @@ -9,17 +9,12 @@ #ifndef LLVM_UTIL_TABLEGEN_SUBTARGETFEATUREINFO_H #define LLVM_UTIL_TABLEGEN_SUBTARGETFEATUREINFO_H -#include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" - #include <map> #include <string> #include <vector> namespace llvm { -class Record; -class RecordKeeper; - struct SubtargetFeatureInfo; using SubtargetFeatureInfoMap = std::map<Record *, SubtargetFeatureInfo, LessRecordByID>; diff --git a/llvm/utils/TableGen/TableGen.cpp b/llvm/utils/TableGen/TableGen.cpp index 8015a58471ca..6d851da34731 100644 --- a/llvm/utils/TableGen/TableGen.cpp +++ b/llvm/utils/TableGen/TableGen.cpp @@ -12,9 +12,7 @@ #include "TableGenBackends.h" // Declares all backends. #include "llvm/Support/CommandLine.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" +#include "llvm/Support/InitLLVM.h" #include "llvm/TableGen/Main.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/SetTheory.h" @@ -23,6 +21,8 @@ using namespace llvm; enum ActionType { PrintRecords, + PrintDetailedRecords, + NullBackend, DumpJSON, GenEmitter, GenRegisterInfo, @@ -60,9 +60,6 @@ enum ActionType { }; namespace llvm { -/// Storage for TimeRegionsOpt as a global so that backends aren't required to -/// include CommandLine.h -bool TimeRegions = false; cl::opt<bool> EmitLongStrLiterals( "long-string-literals", cl::desc("when emitting large string tables, prefer string literals over " @@ -77,6 +74,10 @@ cl::opt<ActionType> Action( cl::values( clEnumValN(PrintRecords, "print-records", "Print all records to stdout (default)"), + clEnumValN(PrintDetailedRecords, "print-detailed-records", + "Print full details of all records to stdout"), + clEnumValN(NullBackend, "null-backend", + "Do nothing after parsing (useful for timing)"), clEnumValN(DumpJSON, "dump-json", "Dump all records as machine-readable JSON"), clEnumValN(GenEmitter, "gen-emitter", "Generate machine code emitter"), @@ -144,15 +145,15 @@ cl::opt<std::string> Class("class", cl::desc("Print Enum list for this class"), cl::value_desc("class name"), cl::cat(PrintEnumsCat)); -cl::opt<bool, true> - TimeRegionsOpt("time-regions", - cl::desc("Time regions of tablegens execution"), - cl::location(TimeRegions)); - bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { switch (Action) { case PrintRecords: - OS << Records; // No argument, dump all contents + OS << Records; // No argument, dump all contents + break; + case PrintDetailedRecords: + EmitDetailedRecords(Records, OS); + break; + case NullBackend: // No backend at all. break; case DumpJSON: EmitJSON(Records, OS); @@ -278,12 +279,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { } int main(int argc, char **argv) { - sys::PrintStackTraceOnErrorSignal(argv[0]); - PrettyStackTraceProgram X(argc, argv); + InitLLVM X(argc, argv); cl::ParseCommandLineOptions(argc, argv); - llvm_shutdown_obj Y; - return TableGenMain(argv[0], &LLVMTableGenMain); } diff --git a/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp b/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp index 54aa5a8164f2..7518b262e6e9 100644 --- a/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp +++ b/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp @@ -39,9 +39,15 @@ void emitWebAssemblyDisassemblerTables( ->getValue()); if (Opc == 0xFFFFFFFF) continue; // No opcode defined. - assert(Opc <= 0xFFFF); - auto Prefix = Opc >> 8; - Opc = Opc & 0xFF; + assert(Opc <= 0xFFFFFF); + unsigned Prefix; + if (Opc <= 0xFFFF) { + Prefix = Opc >> 8; + Opc = Opc & 0xFF; + } else { + Prefix = Opc >> 16; + Opc = Opc & 0xFFFF; + } auto &CGIP = OpcodeTable[Prefix][Opc]; // All wasm instructions have a StackBased field of type string, we only // want the instructions for which this is "true". @@ -133,8 +139,7 @@ void emitWebAssemblyDisassemblerTables( } // Store operands if no prior occurrence. if (OperandStart == OperandTable.size()) { - OperandTable.insert(OperandTable.end(), CurOperandList.begin(), - CurOperandList.end()); + llvm::append_range(OperandTable, CurOperandList); } OS << OperandStart; } else { diff --git a/llvm/utils/TableGen/X86DisassemblerTables.cpp b/llvm/utils/TableGen/X86DisassemblerTables.cpp index 76e4fd9a13ee..331664f875b7 100644 --- a/llvm/utils/TableGen/X86DisassemblerTables.cpp +++ b/llvm/utils/TableGen/X86DisassemblerTables.cpp @@ -763,7 +763,7 @@ void DisassemblerTables::emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2, } if (index == 256) { // If all 256 entries are MODRM_ONEENTRY, omit output. - assert(MODRM_ONEENTRY == 0); + static_assert(MODRM_ONEENTRY == 0, ""); --i2; o2 << "},\n"; } else { diff --git a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp index 8026c324cd40..85d926215113 100644 --- a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp +++ b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp @@ -127,6 +127,15 @@ class X86FoldTablesEmitter { OS << "0 },\n"; } + + bool operator<(const X86FoldTableEntry &RHS) const { + bool LHSpseudo = RegInst->TheDef->getValueAsBit("isPseudo"); + bool RHSpseudo = RHS.RegInst->TheDef->getValueAsBit("isPseudo"); + if (LHSpseudo != RHSpseudo) + return LHSpseudo; + + return RegInst->TheDef->getName() < RHS.RegInst->TheDef->getName(); + } }; typedef std::vector<X86FoldTableEntry> FoldTable; @@ -225,14 +234,8 @@ static inline unsigned int getRegOperandSize(const Record *RegRec) { } // Return the size of the memory operand -static inline unsigned int -getMemOperandSize(const Record *MemRec, const bool IntrinsicSensitive = false) { +static inline unsigned getMemOperandSize(const Record *MemRec) { if (MemRec->isSubClassOf("Operand")) { - // Intrinsic memory instructions use ssmem/sdmem. - if (IntrinsicSensitive && - (MemRec->getName() == "sdmem" || MemRec->getName() == "ssmem")) - return 128; - StringRef Name = MemRec->getValueAsDef("ParserMatchClass")->getValueAsString("Name"); if (Name == "Mem8") @@ -568,8 +571,6 @@ void X86FoldTablesEmitter::updateTables(const CodeGenInstruction *RegInstr, getRegOperandSize(RegOpRec) == getMemOperandSize(MemOpRec)) addEntryWithFlags(Table0, RegInstr, MemInstr, S, 0); } - - return; } void X86FoldTablesEmitter::run(formatted_raw_ostream &OS) { @@ -653,6 +654,14 @@ void X86FoldTablesEmitter::run(formatted_raw_ostream &OS) { &(Target.getInstruction(MemInstIter)), Entry.Strategy); } + // Sort the tables before printing. + llvm::sort(Table2Addr); + llvm::sort(Table0); + llvm::sort(Table1); + llvm::sort(Table2); + llvm::sort(Table3); + llvm::sort(Table4); + // Print all tables. printTable(Table2Addr, "Table2Addr", OS); printTable(Table0, "Table0", OS); diff --git a/llvm/utils/TableGen/X86RecognizableInstr.cpp b/llvm/utils/TableGen/X86RecognizableInstr.cpp index 84f6d5210d74..e4b7c05cfb88 100644 --- a/llvm/utils/TableGen/X86RecognizableInstr.cpp +++ b/llvm/utils/TableGen/X86RecognizableInstr.cpp @@ -54,7 +54,7 @@ static uint8_t byteFromBitsInit(BitsInit &init) { /// @param rec - The record from which to extract the value. /// @param name - The name of the field in the record. /// @return - The field, as translated by byteFromBitsInit(). -static uint8_t byteFromRec(const Record* rec, const std::string &name) { +static uint8_t byteFromRec(const Record* rec, StringRef name) { BitsInit* bits = rec->getValueAsBitsInit(name); return byteFromBitsInit(*bits); } @@ -874,6 +874,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s, TYPE("i16imm", TYPE_IMM) TYPE("i16i8imm", TYPE_IMM) TYPE("GR16", TYPE_R16) + TYPE("GR16orGR32orGR64", TYPE_R16) TYPE("i32mem", TYPE_M) TYPE("i32imm", TYPE_IMM) TYPE("i32i8imm", TYPE_IMM) @@ -1035,6 +1036,7 @@ RecognizableInstr::rmRegisterEncodingFromString(const std::string &s, ENCODING("RST", ENCODING_FP) ENCODING("RSTi", ENCODING_FP) ENCODING("GR16", ENCODING_RM) + ENCODING("GR16orGR32orGR64",ENCODING_RM) ENCODING("GR32", ENCODING_RM) ENCODING("GR32orGR64", ENCODING_RM) ENCODING("GR64", ENCODING_RM) @@ -1072,6 +1074,7 @@ OperandEncoding RecognizableInstr::roRegisterEncodingFromString(const std::string &s, uint8_t OpSize) { ENCODING("GR16", ENCODING_REG) + ENCODING("GR16orGR32orGR64",ENCODING_REG) ENCODING("GR32", ENCODING_REG) ENCODING("GR32orGR64", ENCODING_REG) ENCODING("GR64", ENCODING_REG) |
