diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
commit | cfca06d7963fa0909f90483b42a6d7d194d01e08 (patch) | |
tree | 209fb2a2d68f8f277793fc8df46c753d31bc853b /llvm/utils/TableGen | |
parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) |
Vendor import of llvm-project master 2e10b7a39b9, the last commit beforevendor/llvm-project/llvmorg-11-init-20887-g2e10b7a39b9vendor/llvm-project/master
the llvmorg-12-init tag, from which release/11.x was branched.
Notes
Notes:
svn path=/vendor/llvm-project/master/; revision=363578
svn path=/vendor/llvm-project/llvmorg-11-init-20887-g2e10b7a39b9/; revision=363579; tag=vendor/llvm-project/llvmorg-11-init-20887-g2e10b7a39b9
Diffstat (limited to 'llvm/utils/TableGen')
52 files changed, 2139 insertions, 698 deletions
diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp index ccf0959389ba..3d63059dcb8b 100644 --- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp +++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp @@ -1085,7 +1085,7 @@ bool MatchableInfo::validate(StringRef CommentDelimiter, bool IsAlias) const { // Verify that any operand is only mentioned once. // We reject aliases and ignore instructions for now. if (!IsAlias && TheDef->getValueAsString("AsmMatchConverter").empty() && - Tok[0] == '$' && !OperandNames.insert(Tok).second) { + Tok[0] == '$' && !OperandNames.insert(std::string(Tok)).second) { LLVM_DEBUG({ errs() << "warning: '" << TheDef->getName() << "': " << "ignoring instruction with tied operand '" @@ -1126,7 +1126,7 @@ static std::string getEnumNameForToken(StringRef Str) { } ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) { - ClassInfo *&Entry = TokenClasses[Token]; + ClassInfo *&Entry = TokenClasses[std::string(Token)]; if (!Entry) { Classes.emplace_front(); @@ -1134,7 +1134,7 @@ ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) { Entry->Kind = ClassInfo::Token; Entry->ClassName = "Token"; Entry->Name = "MCK_" + getEnumNameForToken(Token); - Entry->ValueName = Token; + Entry->ValueName = std::string(Token); Entry->PredicateMethod = "<invalid>"; Entry->RenderMethod = "<invalid>"; Entry->ParserMethod = ""; @@ -1310,11 +1310,11 @@ buildRegisterClasses(SmallPtrSetImpl<Record*> &SingletonRegisters) { Init *DiagnosticType = Def->getValueInit("DiagnosticType"); if (StringInit *SI = dyn_cast<StringInit>(DiagnosticType)) - CI->DiagnosticType = SI->getValue(); + CI->DiagnosticType = std::string(SI->getValue()); Init *DiagnosticString = Def->getValueInit("DiagnosticString"); if (StringInit *SI = dyn_cast<StringInit>(DiagnosticString)) - CI->DiagnosticString = SI->getValue(); + CI->DiagnosticString = std::string(SI->getValue()); // If we have a diagnostic string but the diagnostic type is not specified // explicitly, create an anonymous diagnostic type. @@ -1335,9 +1335,9 @@ buildRegisterClasses(SmallPtrSetImpl<Record*> &SingletonRegisters) { assert(CI && "Missing singleton register class info!"); if (CI->ValueName.empty()) { - CI->ClassName = Rec->getName(); + CI->ClassName = std::string(Rec->getName()); CI->Name = "MCK_" + Rec->getName().str(); - CI->ValueName = Rec->getName(); + CI->ValueName = std::string(Rec->getName()); } else CI->ValueName = CI->ValueName + "," + Rec->getName().str(); } @@ -1372,14 +1372,14 @@ void AsmMatcherInfo::buildOperandClasses() { else CI->SuperClasses.push_back(SC); } - CI->ClassName = Rec->getValueAsString("Name"); + CI->ClassName = std::string(Rec->getValueAsString("Name")); CI->Name = "MCK_" + CI->ClassName; - CI->ValueName = Rec->getName(); + CI->ValueName = std::string(Rec->getName()); // Get or construct the predicate method name. Init *PMName = Rec->getValueInit("PredicateMethod"); if (StringInit *SI = dyn_cast<StringInit>(PMName)) { - CI->PredicateMethod = SI->getValue(); + CI->PredicateMethod = std::string(SI->getValue()); } else { assert(isa<UnsetInit>(PMName) && "Unexpected PredicateMethod field!"); CI->PredicateMethod = "is" + CI->ClassName; @@ -1388,7 +1388,7 @@ void AsmMatcherInfo::buildOperandClasses() { // Get or construct the render method name. Init *RMName = Rec->getValueInit("RenderMethod"); if (StringInit *SI = dyn_cast<StringInit>(RMName)) { - CI->RenderMethod = SI->getValue(); + CI->RenderMethod = std::string(SI->getValue()); } else { assert(isa<UnsetInit>(RMName) && "Unexpected RenderMethod field!"); CI->RenderMethod = "add" + CI->ClassName + "Operands"; @@ -1397,15 +1397,15 @@ void AsmMatcherInfo::buildOperandClasses() { // Get the parse method name or leave it as empty. Init *PRMName = Rec->getValueInit("ParserMethod"); if (StringInit *SI = dyn_cast<StringInit>(PRMName)) - CI->ParserMethod = SI->getValue(); + CI->ParserMethod = std::string(SI->getValue()); // Get the diagnostic type and string or leave them as empty. Init *DiagnosticType = Rec->getValueInit("DiagnosticType"); if (StringInit *SI = dyn_cast<StringInit>(DiagnosticType)) - CI->DiagnosticType = SI->getValue(); + CI->DiagnosticType = std::string(SI->getValue()); Init *DiagnosticString = Rec->getValueInit("DiagnosticString"); if (StringInit *SI = dyn_cast<StringInit>(DiagnosticString)) - CI->DiagnosticString = SI->getValue(); + CI->DiagnosticString = std::string(SI->getValue()); // If we have a DiagnosticString, we need a DiagnosticType for use within // the matcher. if (!CI->DiagnosticString.empty() && CI->DiagnosticType.empty()) @@ -1418,7 +1418,7 @@ void AsmMatcherInfo::buildOperandClasses() { // Get or construct the default method name. Init *DMName = Rec->getValueInit("DefaultMethod"); if (StringInit *SI = dyn_cast<StringInit>(DMName)) { - CI->DefaultMethod = SI->getValue(); + CI->DefaultMethod = std::string(SI->getValue()); } else { assert(isa<UnsetInit>(DMName) && "Unexpected DefaultMethod field!"); CI->DefaultMethod = "default" + CI->ClassName + "Operands"; @@ -2601,7 +2601,7 @@ static void emitMatchRegisterName(CodeGenTarget &Target, Record *AsmParser, if (Reg.TheDef->getValueAsString("AsmName").empty()) continue; - Matches.emplace_back(Reg.TheDef->getValueAsString("AsmName"), + Matches.emplace_back(std::string(Reg.TheDef->getValueAsString("AsmName")), "return " + utostr(Reg.EnumValue) + ";"); } @@ -2633,7 +2633,7 @@ static void emitMatchRegisterAltName(CodeGenTarget &Target, Record *AsmParser, if (AltName.empty()) continue; - Matches.emplace_back(AltName, + Matches.emplace_back(std::string(AltName), "return " + utostr(Reg.EnumValue) + ";"); } } @@ -2729,7 +2729,8 @@ static void emitMnemonicAliasVariant(raw_ostream &OS,const AsmMatcherInfo &Info, StringRef AsmVariantName = R->getValueAsString("AsmVariantName"); if (AsmVariantName != AsmParserVariantName) continue; - AliasesFromMnemonic[R->getValueAsString("FromMnemonic")].push_back(R); + AliasesFromMnemonic[std::string(R->getValueAsString("FromMnemonic"))] + .push_back(R); } if (AliasesFromMnemonic.empty()) return; @@ -3001,7 +3002,7 @@ static void emitAsmTiedOperandConstraints(CodeGenTarget &Target, AsmMatcherInfo &Info, raw_ostream &OS) { std::string AsmParserName = - Info.AsmParser->getValueAsString("AsmParserClassName"); + std::string(Info.AsmParser->getValueAsString("AsmParserClassName")); OS << "static bool "; OS << "checkAsmTiedOperandConstraints(const " << Target.getName() << AsmParserName << "&AsmParser,\n"; @@ -3862,7 +3863,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " std::string Info;\n"; OS << " if (!getParser().getTargetParser().\n"; OS << " getTargetOptions().MCNoDeprecatedWarn &&\n"; - OS << " MII.get(Inst.getOpcode()).getDeprecatedInfo(Inst, getSTI(), Info)) {\n"; + OS << " MII.getDeprecatedInfo(Inst, getSTI(), Info)) {\n"; OS << " SMLoc Loc = ((" << Target.getName() << "Operand&)*Operands[0]).getStartLoc();\n"; OS << " getParser().Warning(Loc, Info, None);\n"; diff --git a/llvm/utils/TableGen/AsmWriterEmitter.cpp b/llvm/utils/TableGen/AsmWriterEmitter.cpp index 58c0d32d44eb..d10ea71e97e3 100644 --- a/llvm/utils/TableGen/AsmWriterEmitter.cpp +++ b/llvm/utils/TableGen/AsmWriterEmitter.cpp @@ -185,7 +185,7 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, InstIdxs[idx].push_back(i); } else { UniqueOperandCommands.push_back(std::move(Command)); - InstrsForCase.push_back(Inst.CGI->TheDef->getName()); + InstrsForCase.push_back(std::string(Inst.CGI->TheDef->getName())); InstIdxs.emplace_back(); InstIdxs.back().push_back(i); @@ -267,6 +267,27 @@ static void UnescapeString(std::string &Str) { } } +/// UnescapeAliasString - Supports literal braces in InstAlias asm string which +/// are escaped with '\\' to avoid being interpreted as variants. Braces must +/// be unescaped before c++ code is generated as (e.g.): +/// +/// AsmString = "foo \{$\x01\}"; +/// +/// causes non-standard escape character warnings. +static void UnescapeAliasString(std::string &Str) { + for (unsigned i = 0; i != Str.size(); ++i) { + if (Str[i] == '\\' && i != Str.size()-1) { + switch (Str[i+1]) { + default: continue; // Don't execute the code after the switch. + case '{': Str[i] = '{'; break; + case '}': Str[i] = '}'; break; + } + // Nuke the second character. + Str.erase(Str.begin()+i+1); + } + } +} + /// EmitPrintInstruction - Generate the code for the "printInstruction" method /// implementation. Destroys all instances of AsmWriterInst information, by /// clearing the Instructions vector. @@ -380,9 +401,7 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { } // Emit the string table itself. - O << " static const char AsmStrs[] = {\n"; - StringTable.emit(O, printChar); - O << " };\n\n"; + StringTable.emitStringLiteralDef(O, " static const char AsmStrs[]"); // Emit the lookup tables in pieces to minimize wasted bytes. unsigned BytesNeeded = ((OpcodeInfoBits - BitsLeft) + 7) / 8; @@ -509,9 +528,9 @@ emitRegisterNameString(raw_ostream &O, StringRef AltName, // "NoRegAltName" is special. We don't need to do a lookup for that, // as it's just a reference to the default register name. if (AltName == "" || AltName == "NoRegAltName") { - AsmName = Reg.TheDef->getValueAsString("AsmName"); + AsmName = std::string(Reg.TheDef->getValueAsString("AsmName")); if (AsmName.empty()) - AsmName = Reg.getName(); + AsmName = std::string(Reg.getName()); } else { // Make sure the register has an alternate name for this index. std::vector<Record*> AltNameList = @@ -530,16 +549,15 @@ emitRegisterNameString(raw_ostream &O, StringRef AltName, PrintFatalError(Reg.TheDef->getLoc(), "Register definition missing alt name for '" + AltName + "'."); - AsmName = AltNames[Idx]; + AsmName = std::string(AltNames[Idx]); } } StringTable.add(AsmName); } StringTable.layout(); - O << " static const char AsmStrs" << AltName << "[] = {\n"; - StringTable.emit(O, printChar); - O << " };\n\n"; + StringTable.emitStringLiteralDef(O, Twine(" static const char AsmStrs") + + AltName + "[]"); O << " static const " << getMinimalTypeForRange(StringTable.size() - 1, 32) << " RegAsmOffset" << AltName << "[] = {"; @@ -786,7 +804,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { // before it can be matched to the mnemonic. std::map<std::string, std::vector<IAPrinter>> IAPrinterMap; - std::vector<std::string> PrintMethods; + std::vector<std::pair<std::string, bool>> PrintMethods; // A list of MCOperandPredicates for all operands in use, and the reverse map std::vector<const Record*> MCOpPredicates; @@ -806,6 +824,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { std::string FlatAliasAsmString = CodeGenInstruction::FlattenAsmStringVariants(CGA.AsmString, Variant); + UnescapeAliasString(FlatAliasAsmString); // Don't emit the alias if it has more operands than what it's aliasing. if (NumResultOps < CountNumOperands(FlatAliasAsmString, Variant)) @@ -858,11 +877,16 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { if (Rec->isSubClassOf("RegisterOperand") || Rec->isSubClassOf("Operand")) { StringRef PrintMethod = Rec->getValueAsString("PrintMethod"); + bool IsPCRel = + Rec->getValueAsString("OperandType") == "OPERAND_PCREL"; if (PrintMethod != "" && PrintMethod != "printOperand") { - PrintMethodIdx = - llvm::find(PrintMethods, PrintMethod) - PrintMethods.begin(); + PrintMethodIdx = llvm::find_if(PrintMethods, + [&](auto &X) { + return X.first == PrintMethod; + }) - + PrintMethods.begin(); if (static_cast<unsigned>(PrintMethodIdx) == PrintMethods.size()) - PrintMethods.push_back(PrintMethod); + PrintMethods.emplace_back(std::string(PrintMethod), IsPCRel); } } @@ -874,12 +898,12 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { Record *R = CGA.ResultOperands[i].getRecord(); if (R->isSubClassOf("RegisterOperand")) R = R->getValueAsDef("RegClass"); - IAP.addCond(formatv( - "AliasPatternCond::K_RegClass, {0}::{1}RegClassID", Namespace, - R->getName())); + IAP.addCond(std::string( + formatv("AliasPatternCond::K_RegClass, {0}::{1}RegClassID", + Namespace, R->getName()))); } else { - IAP.addCond(formatv("AliasPatternCond::K_TiedReg, {0}", - IAP.getOpIndex(ROName))); + IAP.addCond(std::string(formatv( + "AliasPatternCond::K_TiedReg, {0}", IAP.getOpIndex(ROName)))); } } else { // Assume all printable operands are desired for now. This can be @@ -896,7 +920,8 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { } else break; // No conditions on this operand at all } - IAP.addCond(formatv("AliasPatternCond::K_Custom, {0}", Entry)); + IAP.addCond( + std::string(formatv("AliasPatternCond::K_Custom, {0}", Entry))); } break; } @@ -908,7 +933,8 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { if (Imm != Imm32) PrintFatalError("Matching an alias with an immediate out of the " "range of int32_t is not supported"); - IAP.addCond(formatv("AliasPatternCond::K_Imm, uint32_t({0})", Imm32)); + IAP.addCond(std::string( + formatv("AliasPatternCond::K_Imm, uint32_t({0})", Imm32))); break; } case CodeGenInstAlias::ResultOperand::K_Reg: @@ -920,8 +946,8 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { } StringRef Reg = CGA.ResultOperands[i].getRegister()->getName(); - IAP.addCond( - formatv("AliasPatternCond::K_Reg, {0}::{1}", Namespace, Reg)); + IAP.addCond(std::string( + formatv("AliasPatternCond::K_Reg, {0}::{1}", Namespace, Reg))); break; } @@ -942,20 +968,35 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { for (auto I = ReqFeatures.cbegin(); I != ReqFeatures.cend(); I++) { Record *R = *I; - StringRef AsmCondString = R->getValueAsString("AssemblerCondString"); - - // AsmCondString has syntax [!]F(,[!]F)* - SmallVector<StringRef, 4> Ops; - SplitString(AsmCondString, Ops, ","); - assert(!Ops.empty() && "AssemblerCondString cannot be empty"); - - for (StringRef Op : Ops) { - assert(!Op.empty() && "Empty operator"); - bool IsNeg = Op[0] == '!'; - StringRef Feature = Op.drop_front(IsNeg ? 1 : 0); - IAP.addCond(formatv("AliasPatternCond::K_{0}Feature, {1}::{2}", - IsNeg ? "Neg" : "", Namespace, Feature)); + const DagInit *D = R->getValueAsDag("AssemblerCondDag"); + std::string CombineType = D->getOperator()->getAsString(); + if (CombineType != "any_of" && CombineType != "all_of") + PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); + if (D->getNumArgs() == 0) + PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); + bool IsOr = CombineType == "any_of"; + + for (auto *Arg : D->getArgs()) { + bool IsNeg = false; + if (auto *NotArg = dyn_cast<DagInit>(Arg)) { + if (NotArg->getOperator()->getAsString() != "not" || + NotArg->getNumArgs() != 1) + PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); + Arg = NotArg->getArg(0); + IsNeg = true; + } + if (!isa<DefInit>(Arg) || + !cast<DefInit>(Arg)->getDef()->isSubClassOf("SubtargetFeature")) + PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); + + IAP.addCond(std::string(formatv( + "AliasPatternCond::K_{0}{1}Feature, {2}::{3}", IsOr ? "Or" : "", + IsNeg ? "Neg" : "", Namespace, Arg->getAsString()))); } + // If an AssemblerPredicate with ors is used, note end of list should + // these be combined. + if (IsOr) + IAP.addCond("AliasPatternCond::K_EndOrFeatures, 0"); } IAPrinterMap[Aliases.first].push_back(std::move(IAP)); @@ -971,7 +1012,8 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { HeaderO << "bool " << Target.getName() << ClassName << "::printAliasInstr(const MCInst" - << " *MI, " << (PassSubtarget ? "const MCSubtargetInfo &STI, " : "") + << " *MI, uint64_t Address, " + << (PassSubtarget ? "const MCSubtargetInfo &STI, " : "") << "raw_ostream &OS) {\n"; std::string PatternsForOpcode; @@ -1134,7 +1176,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { O << " ++I;\n"; O << " int OpIdx = AsmString[I++] - 1;\n"; O << " int PrintMethodIdx = AsmString[I++] - 1;\n"; - O << " printCustomAliasOperand(MI, OpIdx, PrintMethodIdx, "; + O << " printCustomAliasOperand(MI, Address, OpIdx, PrintMethodIdx, "; O << (PassSubtarget ? "STI, " : ""); O << "OS);\n"; O << " } else\n"; @@ -1156,7 +1198,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { O << "void " << Target.getName() << ClassName << "::" << "printCustomAliasOperand(\n" - << " const MCInst *MI, unsigned OpIdx,\n" + << " const MCInst *MI, uint64_t Address, unsigned OpIdx,\n" << " unsigned PrintMethodIdx,\n" << (PassSubtarget ? " const MCSubtargetInfo &STI,\n" : "") << " raw_ostream &OS) {\n"; @@ -1170,7 +1212,8 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { for (unsigned i = 0; i < PrintMethods.size(); ++i) { O << " case " << i << ":\n" - << " " << PrintMethods[i] << "(MI, OpIdx, " + << " " << PrintMethods[i].first << "(MI, " + << (PrintMethods[i].second ? "Address, " : "") << "OpIdx, " << (PassSubtarget ? "STI, " : "") << "OS);\n" << " break;\n"; } diff --git a/llvm/utils/TableGen/AsmWriterInst.cpp b/llvm/utils/TableGen/AsmWriterInst.cpp index c26e0e421183..24d29ffc28e5 100644 --- a/llvm/utils/TableGen/AsmWriterInst.cpp +++ b/llvm/utils/TableGen/AsmWriterInst.cpp @@ -36,6 +36,8 @@ std::string AsmWriterOperand::getCode(bool PassSubtarget) const { return Str; std::string Result = Str + "(MI"; + if (PCRel) + Result += ", Address"; if (MIOpNo != ~0U) Result += ", " + utostr(MIOpNo); if (PassSubtarget) @@ -179,7 +181,9 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex, CGIOperandList::OperandInfo OpInfo = CGI.Operands[OpNo]; unsigned MIOp = OpInfo.MIOperandNo; - Operands.emplace_back(OpInfo.PrinterMethodName, MIOp, Modifier); + Operands.emplace_back(OpInfo.PrinterMethodName, MIOp, Modifier, + AsmWriterOperand::isMachineInstrOperand, + OpInfo.OperandType == "MCOI::OPERAND_PCREL"); } LastEmitted = VarEnd; } diff --git a/llvm/utils/TableGen/AsmWriterInst.h b/llvm/utils/TableGen/AsmWriterInst.h index a59112efea44..366c9eca664f 100644 --- a/llvm/utils/TableGen/AsmWriterInst.h +++ b/llvm/utils/TableGen/AsmWriterInst.h @@ -48,6 +48,8 @@ namespace llvm { /// an operand, specified with syntax like ${opname:modifier}. std::string MiModifier; + bool PCRel = false; + // To make VS STL happy AsmWriterOperand(OpType op = isLiteralTextOperand):OperandType(op) {} @@ -55,11 +57,11 @@ namespace llvm { OpType op = isLiteralTextOperand) : OperandType(op), Str(LitStr) {} - AsmWriterOperand(const std::string &Printer, - unsigned _MIOpNo, + AsmWriterOperand(const std::string &Printer, unsigned _MIOpNo, const std::string &Modifier, - OpType op = isMachineInstrOperand) - : OperandType(op), MIOpNo(_MIOpNo), Str(Printer), MiModifier(Modifier) {} + OpType op = isMachineInstrOperand, bool PCRel = false) + : OperandType(op), MIOpNo(_MIOpNo), Str(Printer), MiModifier(Modifier), + PCRel(PCRel) {} bool operator!=(const AsmWriterOperand &Other) const { if (OperandType != Other.OperandType || Str != Other.Str) return true; diff --git a/llvm/utils/TableGen/Attributes.cpp b/llvm/utils/TableGen/Attributes.cpp index 6fbc595d7300..f3f875e8ce0b 100644 --- a/llvm/utils/TableGen/Attributes.cpp +++ b/llvm/utils/TableGen/Attributes.cpp @@ -23,51 +23,41 @@ public: void emit(raw_ostream &OS); private: - void emitTargetIndependentEnums(raw_ostream &OS); - void emitConversionFn(raw_ostream &OS); + void emitTargetIndependentNames(raw_ostream &OS); void emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr); - void printEnumAttrClasses(raw_ostream &OS, - const std::vector<Record *> &Records); - void printStrBoolAttrClasses(raw_ostream &OS, - const std::vector<Record *> &Records); - RecordKeeper &Records; }; } // End anonymous namespace. -void Attributes::emitTargetIndependentEnums(raw_ostream &OS) { - OS << "#ifdef GET_ATTR_ENUM\n"; - OS << "#undef GET_ATTR_ENUM\n"; - - std::vector<Record*> Attrs = - Records.getAllDerivedDefinitions("EnumAttr"); - - for (auto A : Attrs) - OS << A->getName() << ",\n"; - - OS << "#endif\n"; -} - -void Attributes::emitConversionFn(raw_ostream &OS) { - OS << "#ifdef GET_ATTR_KIND_FROM_NAME\n"; - OS << "#undef GET_ATTR_KIND_FROM_NAME\n"; - - std::vector<Record*> Attrs = - Records.getAllDerivedDefinitions("EnumAttr"); - - OS << "static Attribute::AttrKind getAttrKindFromName(StringRef AttrName) {\n"; - OS << " return StringSwitch<Attribute::AttrKind>(AttrName)\n"; - - for (auto A : Attrs) { - OS << " .Case(\"" << A->getValueAsString("AttrString"); - OS << "\", Attribute::" << A->getName() << ")\n"; - } - - OS << " .Default(Attribute::None);\n"; - OS << "}\n\n"; - +void Attributes::emitTargetIndependentNames(raw_ostream &OS) { + OS << "#ifdef GET_ATTR_NAMES\n"; + OS << "#undef GET_ATTR_NAMES\n"; + + OS << "#ifndef ATTRIBUTE_ALL\n"; + OS << "#define ATTRIBUTE_ALL(FIRST, SECOND)\n"; + OS << "#endif\n\n"; + + auto Emit = [&](ArrayRef<StringRef> KindNames, StringRef MacroName) { + OS << "#ifndef " << MacroName << "\n"; + OS << "#define " << MacroName + << "(FIRST, SECOND) ATTRIBUTE_ALL(FIRST, SECOND)\n"; + OS << "#endif\n\n"; + for (StringRef KindName : KindNames) { + for (auto A : Records.getAllDerivedDefinitions(KindName)) { + OS << MacroName << "(" << A->getName() << "," + << A->getValueAsString("AttrString") << ")\n"; + } + } + OS << "#undef " << MacroName << "\n\n"; + }; + + // Emit attribute enums in the same order llvm::Attribute::operator< expects. + Emit({"EnumAttr", "TypeAttr", "IntAttr"}, "ATTRIBUTE_ENUM"); + Emit({"StrBoolAttr"}, "ATTRIBUTE_STRBOOL"); + + OS << "#undef ATTRIBUTE_ALL\n"; OS << "#endif\n"; } @@ -75,35 +65,6 @@ void Attributes::emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr) { OS << "#ifdef GET_ATTR_COMPAT_FUNC\n"; OS << "#undef GET_ATTR_COMPAT_FUNC\n"; - OS << "struct EnumAttr {\n"; - OS << " static bool isSet(const Function &Fn,\n"; - OS << " Attribute::AttrKind Kind) {\n"; - OS << " return Fn.hasFnAttribute(Kind);\n"; - OS << " }\n\n"; - OS << " static void set(Function &Fn,\n"; - OS << " Attribute::AttrKind Kind, bool Val) {\n"; - OS << " if (Val)\n"; - OS << " Fn.addFnAttr(Kind);\n"; - OS << " else\n"; - OS << " Fn.removeFnAttr(Kind);\n"; - OS << " }\n"; - OS << "};\n\n"; - - OS << "struct StrBoolAttr {\n"; - OS << " static bool isSet(const Function &Fn,\n"; - OS << " StringRef Kind) {\n"; - OS << " auto A = Fn.getFnAttribute(Kind);\n"; - OS << " return A.getValueAsString().equals(\"true\");\n"; - OS << " }\n\n"; - OS << " static void set(Function &Fn,\n"; - OS << " StringRef Kind, bool Val) {\n"; - OS << " Fn.addFnAttr(Kind, Val ? \"true\" : \"false\");\n"; - OS << " }\n"; - OS << "};\n\n"; - - printEnumAttrClasses(OS ,Records.getAllDerivedDefinitions("EnumAttr")); - printStrBoolAttrClasses(OS , Records.getAllDerivedDefinitions("StrBoolAttr")); - OS << "static inline bool hasCompatibleFnAttrs(const Function &Caller,\n" << " const Function &Callee) {\n"; OS << " bool Ret = true;\n\n"; @@ -135,35 +96,8 @@ void Attributes::emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr) { OS << "#endif\n"; } -void Attributes::printEnumAttrClasses(raw_ostream &OS, - const std::vector<Record *> &Records) { - OS << "// EnumAttr classes\n"; - for (const auto *R : Records) { - OS << "struct " << R->getName() << "Attr : EnumAttr {\n"; - OS << " static enum Attribute::AttrKind getKind() {\n"; - OS << " return llvm::Attribute::" << R->getName() << ";\n"; - OS << " }\n"; - OS << "};\n"; - } - OS << "\n"; -} - -void Attributes::printStrBoolAttrClasses(raw_ostream &OS, - const std::vector<Record *> &Records) { - OS << "// StrBoolAttr classes\n"; - for (const auto *R : Records) { - OS << "struct " << R->getName() << "Attr : StrBoolAttr {\n"; - OS << " static StringRef getKind() {\n"; - OS << " return \"" << R->getValueAsString("AttrString") << "\";\n"; - OS << " }\n"; - OS << "};\n"; - } - OS << "\n"; -} - void Attributes::emit(raw_ostream &OS) { - emitTargetIndependentEnums(OS); - emitConversionFn(OS); + emitTargetIndependentNames(OS); emitFnAttrCompatCheck(OS, false); } diff --git a/llvm/utils/TableGen/CallingConvEmitter.cpp b/llvm/utils/TableGen/CallingConvEmitter.cpp index 9eabb44d9004..a4e993f80ec9 100644 --- a/llvm/utils/TableGen/CallingConvEmitter.cpp +++ b/llvm/utils/TableGen/CallingConvEmitter.cpp @@ -197,11 +197,12 @@ void CallingConvEmitter::EmitAction(Record *Action, "getTypeAllocSize(EVT(LocVT).getTypeForEVT(State.getContext()))," " "; if (Align) - O << Align; + O << "Align(" << Align << ")"; else - O << "\n" << IndentStr + O << "\n" + << IndentStr << " State.getMachineFunction().getDataLayout()." - "getABITypeAlignment(EVT(LocVT).getTypeForEVT(State.getContext()" + "getABITypeAlign(EVT(LocVT).getTypeForEVT(State.getContext()" "))"; O << ");\n" << IndentStr << "State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset" @@ -224,8 +225,7 @@ void CallingConvEmitter::EmitAction(Record *Action, O << "\n" << IndentStr << "};\n"; O << IndentStr << "unsigned Offset" << ++Counter - << " = State.AllocateStack(" - << Size << ", " << Align << ", " + << " = State.AllocateStack(" << Size << ", Align(" << Align << "), " << "ShadowRegList" << ShadowRegListNumber << ");\n"; O << IndentStr << "State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset" << Counter << ", LocVT, LocInfo));\n"; @@ -275,9 +275,8 @@ void CallingConvEmitter::EmitAction(Record *Action, } else if (Action->isSubClassOf("CCPassByVal")) { int Size = Action->getValueAsInt("Size"); int Align = Action->getValueAsInt("Align"); - O << IndentStr - << "State.HandleByVal(ValNo, ValVT, LocVT, LocInfo, " - << Size << ", " << Align << ", ArgFlags);\n"; + O << IndentStr << "State.HandleByVal(ValNo, ValVT, LocVT, LocInfo, " + << Size << ", Align(" << Align << "), ArgFlags);\n"; O << IndentStr << "return false;\n"; } else if (Action->isSubClassOf("CCCustom")) { O << IndentStr diff --git a/llvm/utils/TableGen/CodeEmitterGen.cpp b/llvm/utils/TableGen/CodeEmitterGen.cpp index 68cb8f181e62..6338d44fb2a7 100644 --- a/llvm/utils/TableGen/CodeEmitterGen.cpp +++ b/llvm/utils/TableGen/CodeEmitterGen.cpp @@ -313,8 +313,8 @@ std::string CodeEmitterGen::getInstructionCaseForEncoding(Record *R, Record *Enc // bits<5> RST = { ?, ?, ?, ?, ? }; if (RV.getPrefix() || RV.getValue()->isComplete()) continue; - - AddCodeToMergeInOperand(R, BI, RV.getName(), NumberedOp, + + AddCodeToMergeInOperand(R, BI, std::string(RV.getName()), NumberedOp, NamedOpIndices, Case, Target); } diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp index 7e0ba98da94a..6fdc116721f3 100644 --- a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp @@ -277,7 +277,7 @@ bool TypeSetByHwMode::intersect(SetType &Out, const SetType &In) { // Compute the intersection of scalars separately to account for only // one set containing iPTR. - // The itersection of iPTR with a set of integer scalar types that does not + // The intersection of iPTR with a set of integer scalar types that does not // include iPTR will result in the most specific scalar type: // - iPTR is more specific than any set with two elements or more // - iPTR is less specific than any single integer scalar type. @@ -999,9 +999,9 @@ std::string TreePredicateFn::getPredCode() const { int64_t MinAlign = getMinAlignment(); if (MinAlign > 0) { - Code += "if (cast<MemSDNode>(N)->getAlignment() < "; + Code += "if (cast<MemSDNode>(N)->getAlign() < Align("; Code += utostr(MinAlign); - Code += ")\nreturn false;\n"; + Code += "))\nreturn false;\n"; } Record *MemoryVT = getMemoryVT(); @@ -1091,7 +1091,8 @@ std::string TreePredicateFn::getPredCode() const { .str(); } - std::string PredicateCode = PatFragRec->getRecord()->getValueAsString("PredicateCode"); + std::string PredicateCode = + std::string(PatFragRec->getRecord()->getValueAsString("PredicateCode")); Code += PredicateCode; @@ -1106,7 +1107,8 @@ bool TreePredicateFn::hasImmCode() const { } std::string TreePredicateFn::getImmCode() const { - return PatFragRec->getRecord()->getValueAsString("ImmediateCode"); + return std::string( + PatFragRec->getRecord()->getValueAsString("ImmediateCode")); } bool TreePredicateFn::immCodeUsesAPInt() const { @@ -1223,7 +1225,8 @@ bool TreePredicateFn::hasGISelPredicateCode() const { .empty(); } std::string TreePredicateFn::getGISelPredicateCode() const { - return PatFragRec->getRecord()->getValueAsString("GISelPredicateCode"); + return std::string( + PatFragRec->getRecord()->getValueAsString("GISelPredicateCode")); } StringRef TreePredicateFn::getImmType() const { @@ -2517,6 +2520,9 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { } } + unsigned NumResults = Inst.getNumResults(); + unsigned NumFixedOperands = InstInfo.Operands.size(); + // If one or more operands with a default value appear at the end of the // formal operand list for an instruction, we allow them to be overridden // by optional operands provided in the pattern. @@ -2525,14 +2531,15 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { // operand A with a default, then we don't allow A to be overridden, // because there would be no way to specify whether the next operand in // the pattern was intended to override A or skip it. - unsigned NonOverridableOperands = Inst.getNumOperands(); - while (NonOverridableOperands > 0 && - CDP.operandHasDefault(Inst.getOperand(NonOverridableOperands-1))) + unsigned NonOverridableOperands = NumFixedOperands; + while (NonOverridableOperands > NumResults && + CDP.operandHasDefault(InstInfo.Operands[NonOverridableOperands-1].Rec)) --NonOverridableOperands; unsigned ChildNo = 0; - for (unsigned i = 0, e = Inst.getNumOperands(); i != e; ++i) { - Record *OperandNode = Inst.getOperand(i); + assert(NumResults <= NumFixedOperands); + for (unsigned i = NumResults, e = NumFixedOperands; i != e; ++i) { + Record *OperandNode = InstInfo.Operands[i].Rec; // If the operand has a default value, do we use it? We must use the // default if we've run out of children of the pattern DAG to consume, @@ -2741,7 +2748,7 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit, if (R->getName() == "node" && !OpName.empty()) { if (OpName.empty()) error("'node' argument requires a name to match with operand list"); - Args.push_back(OpName); + Args.push_back(std::string(OpName)); } Res->setName(OpName); @@ -2753,7 +2760,7 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit, if (OpName.empty()) error("'?' argument requires a name to match with operand list"); TreePatternNodePtr Res = std::make_shared<TreePatternNode>(TheInit, 1); - Args.push_back(OpName); + Args.push_back(std::string(OpName)); Res->setName(OpName); return Res; } @@ -2915,8 +2922,15 @@ static bool SimplifyTree(TreePatternNodePtr &N) { // If we have a bitconvert with a resolved type and if the source and // destination types are the same, then the bitconvert is useless, remove it. + // + // We make an exception if the types are completely empty. This can come up + // when the pattern being simplified is in the Fragments list of a PatFrags, + // so that the operand is just an untyped "node". In that situation we leave + // bitconverts unsimplified, and simplify them later once the fragment is + // expanded into its true context. if (N->getOperator()->getName() == "bitconvert" && N->getExtType(0).isValueTypeByHwMode(false) && + !N->getExtType(0).empty() && N->getExtType(0) == N->getChild(0)->getExtType(0) && N->getName().empty()) { N = N->getChildShared(0); @@ -3105,7 +3119,8 @@ void CodeGenDAGPatterns::ParseNodeTransforms() { Record *XFormNode = Xforms.back(); Record *SDNode = XFormNode->getValueAsDef("Opcode"); StringRef Code = XFormNode->getValueAsString("XFormFunction"); - SDNodeXForms.insert(std::make_pair(XFormNode, NodeXForm(SDNode, Code))); + SDNodeXForms.insert( + std::make_pair(XFormNode, NodeXForm(SDNode, std::string(Code)))); Xforms.pop_back(); } @@ -3173,7 +3188,7 @@ void CodeGenDAGPatterns::ParsePatternFragments(bool OutFrags) { P->error("'" + ArgNameStr + "' does not occur in pattern or was multiply specified!"); OperandsSet.erase(ArgNameStr); - Args.push_back(ArgNameStr); + Args.push_back(std::string(ArgNameStr)); } if (!OperandsSet.empty()) diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.h b/llvm/utils/TableGen/CodeGenDAGPatterns.h index 2c081b670609..a3b84d76fde9 100644 --- a/llvm/utils/TableGen/CodeGenDAGPatterns.h +++ b/llvm/utils/TableGen/CodeGenDAGPatterns.h @@ -430,7 +430,7 @@ class ScopedName { std::string Identifier; public: ScopedName(unsigned Scope, StringRef Identifier) - : Scope(Scope), Identifier(Identifier) { + : Scope(Scope), Identifier(std::string(Identifier)) { assert(Scope != 0 && "Scope == 0 is used to indicate predicates without arguments"); } @@ -1075,8 +1075,9 @@ public: // The string will excute in a subclass of SelectionDAGISel. // Cast to std::string explicitly to avoid ambiguity with StringRef. std::string C = IsHwMode - ? std::string("MF->getSubtarget().checkFeatures(\"" + Features + "\")") - : std::string(Def->getValueAsString("CondString")); + ? std::string("MF->getSubtarget().checkFeatures(\"" + + Features + "\")") + : std::string(Def->getValueAsString("CondString")); if (C.empty()) return ""; return IfCond ? C : "!("+C+')'; diff --git a/llvm/utils/TableGen/CodeGenHwModes.cpp b/llvm/utils/TableGen/CodeGenHwModes.cpp index 9052cdd2bd3e..2fec46c44100 100644 --- a/llvm/utils/TableGen/CodeGenHwModes.cpp +++ b/llvm/utils/TableGen/CodeGenHwModes.cpp @@ -20,7 +20,7 @@ StringRef CodeGenHwModes::DefaultModeName = "DefaultMode"; HwMode::HwMode(Record *R) { Name = R->getName(); - Features = R->getValueAsString("Features"); + Features = std::string(R->getValueAsString("Features")); } LLVM_DUMP_METHOD diff --git a/llvm/utils/TableGen/CodeGenHwModes.h b/llvm/utils/TableGen/CodeGenHwModes.h index 1ff2faaa0e52..55507cbca37d 100644 --- a/llvm/utils/TableGen/CodeGenHwModes.h +++ b/llvm/utils/TableGen/CodeGenHwModes.h @@ -12,6 +12,7 @@ #define LLVM_UTILS_TABLEGEN_CODEGENHWMODES_H #include "llvm/ADT/StringMap.h" +#include <cassert> #include <map> #include <string> #include <vector> diff --git a/llvm/utils/TableGen/CodeGenInstruction.cpp b/llvm/utils/TableGen/CodeGenInstruction.cpp index 6bb4dbb511b6..1df5902b081e 100644 --- a/llvm/utils/TableGen/CodeGenInstruction.cpp +++ b/llvm/utils/TableGen/CodeGenInstruction.cpp @@ -56,6 +56,7 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) { std::set<std::string> OperandNames; unsigned e = InDI->getNumArgs() + OutDI->getNumArgs(); OperandList.reserve(e); + bool VariadicOuts = false; for (unsigned i = 0; i != e; ++i){ Init *ArgInit; StringRef ArgName; @@ -80,16 +81,16 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) { unsigned NumOps = 1; DagInit *MIOpInfo = nullptr; if (Rec->isSubClassOf("RegisterOperand")) { - PrintMethod = Rec->getValueAsString("PrintMethod"); - OperandType = Rec->getValueAsString("OperandType"); - OperandNamespace = Rec->getValueAsString("OperandNamespace"); - EncoderMethod = Rec->getValueAsString("EncoderMethod"); + PrintMethod = std::string(Rec->getValueAsString("PrintMethod")); + OperandType = std::string(Rec->getValueAsString("OperandType")); + OperandNamespace = std::string(Rec->getValueAsString("OperandNamespace")); + EncoderMethod = std::string(Rec->getValueAsString("EncoderMethod")); } else if (Rec->isSubClassOf("Operand")) { - PrintMethod = Rec->getValueAsString("PrintMethod"); - OperandType = Rec->getValueAsString("OperandType"); - OperandNamespace = Rec->getValueAsString("OperandNamespace"); + PrintMethod = std::string(Rec->getValueAsString("PrintMethod")); + OperandType = std::string(Rec->getValueAsString("OperandType")); + OperandNamespace = std::string(Rec->getValueAsString("OperandNamespace")); // If there is an explicit encoder method, use it. - EncoderMethod = Rec->getValueAsString("EncoderMethod"); + EncoderMethod = std::string(Rec->getValueAsString("EncoderMethod")); MIOpInfo = Rec->getValueAsDag("MIOperandInfo"); // Verify that MIOpInfo has an 'ops' root value. @@ -109,6 +110,8 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) { else if (Rec->isSubClassOf("OptionalDefOperand")) hasOptionalDef = true; } else if (Rec->getName() == "variable_ops") { + if (i < NumDefs) + VariadicOuts = true; isVariadic = true; continue; } else if (Rec->isSubClassOf("RegisterClass")) { @@ -124,18 +127,21 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) { PrintFatalError(R->getLoc(), "In instruction '" + R->getName() + "', operand #" + Twine(i) + " has no name!"); - if (!OperandNames.insert(ArgName).second) + if (!OperandNames.insert(std::string(ArgName)).second) PrintFatalError(R->getLoc(), "In instruction '" + R->getName() + "', operand #" + Twine(i) + " has the same name as a previous operand!"); - OperandList.emplace_back(Rec, ArgName, PrintMethod, EncoderMethod, - OperandNamespace + "::" + OperandType, MIOperandNo, - NumOps, MIOpInfo); + OperandList.emplace_back( + Rec, std::string(ArgName), std::string(PrintMethod), + std::string(EncoderMethod), OperandNamespace + "::" + OperandType, + MIOperandNo, NumOps, MIOpInfo); MIOperandNo += NumOps; } + if (VariadicOuts) + --NumDefs; // Make sure the constraints list for each operand is large enough to hold // constraint info, even if none is present. @@ -265,7 +271,8 @@ static void ParseConstraint(const std::string &CStr, CGIOperandList &Ops, PrintFatalError( Rec->getLoc(), "Illegal format for tied-to constraint in '" + Rec->getName() + "': '" + CStr + "'"); - std::string LHSOpName = StringRef(CStr).substr(start, wpos - start); + std::string LHSOpName = + std::string(StringRef(CStr).substr(start, wpos - start)); std::pair<unsigned,unsigned> LHSOp = Ops.ParseOperandName(LHSOpName, false); wpos = CStr.find_first_not_of(" \t", pos + 1); @@ -273,7 +280,7 @@ static void ParseConstraint(const std::string &CStr, CGIOperandList &Ops, PrintFatalError( Rec->getLoc(), "Illegal format for tied-to constraint: '" + CStr + "'"); - std::string RHSOpName = StringRef(CStr).substr(wpos); + std::string RHSOpName = std::string(StringRef(CStr).substr(wpos)); std::pair<unsigned,unsigned> RHSOp = Ops.ParseOperandName(RHSOpName, false); // Sort the operands into order, which should put the output one @@ -339,8 +346,8 @@ static void ParseConstraints(const std::string &CStr, CGIOperandList &Ops, void CGIOperandList::ProcessDisableEncoding(std::string DisableEncoding) { while (1) { std::pair<StringRef, StringRef> P = getToken(DisableEncoding, " ,\t"); - std::string OpName = P.first; - DisableEncoding = P.second; + std::string OpName = std::string(P.first); + DisableEncoding = std::string(P.second); if (OpName.empty()) break; // Figure out which operand this is. @@ -361,7 +368,7 @@ void CGIOperandList::ProcessDisableEncoding(std::string DisableEncoding) { CodeGenInstruction::CodeGenInstruction(Record *R) : TheDef(R), Operands(R), InferredFrom(nullptr) { Namespace = R->getValueAsString("Namespace"); - AsmString = R->getValueAsString("AsmString"); + AsmString = std::string(R->getValueAsString("AsmString")); isPreISelOpcode = R->getValueAsBit("isPreISelOpcode"); isReturn = R->getValueAsBit("isReturn"); @@ -420,15 +427,18 @@ CodeGenInstruction::CodeGenInstruction(Record *R) hasChain_Inferred = false; // Parse Constraints. - ParseConstraints(R->getValueAsString("Constraints"), Operands, R); + ParseConstraints(std::string(R->getValueAsString("Constraints")), Operands, + R); // Parse the DisableEncoding field. - Operands.ProcessDisableEncoding(R->getValueAsString("DisableEncoding")); + Operands.ProcessDisableEncoding( + std::string(R->getValueAsString("DisableEncoding"))); // First check for a ComplexDeprecationPredicate. if (R->getValue("ComplexDeprecationPredicate")) { HasComplexDeprecationPredicate = true; - DeprecatedReason = R->getValueAsString("ComplexDeprecationPredicate"); + DeprecatedReason = + std::string(R->getValueAsString("ComplexDeprecationPredicate")); } else if (RecordVal *Dep = R->getValue("DeprecatedFeatureMask")) { // Check if we have a Subtarget feature mask. HasComplexDeprecationPredicate = false; @@ -541,7 +551,8 @@ bool CodeGenInstAlias::tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo, if (!Result->getArgName(AliasOpNo)) PrintFatalError(Loc, "result argument #" + Twine(AliasOpNo) + " must have a name!"); - ResOp = ResultOperand(Result->getArgNameStr(AliasOpNo), ResultRecord); + ResOp = ResultOperand(std::string(Result->getArgNameStr(AliasOpNo)), + ResultRecord); return true; } @@ -559,7 +570,8 @@ bool CodeGenInstAlias::tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo, if (!T.getRegisterClass(InstOpRec) .hasSubClass(&T.getRegisterClass(ADI->getDef()))) return false; - ResOp = ResultOperand(Result->getArgNameStr(AliasOpNo), ResultRecord); + ResOp = ResultOperand(std::string(Result->getArgNameStr(AliasOpNo)), + ResultRecord); return true; } @@ -641,7 +653,8 @@ bool CodeGenInstAlias::tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo, // MIOperandInfo perhaps? if (InstOpRec->getValueInit("Type") != ADI->getDef()->getValueInit("Type")) return false; - ResOp = ResultOperand(Result->getArgNameStr(AliasOpNo), ADI->getDef()); + ResOp = ResultOperand(std::string(Result->getArgNameStr(AliasOpNo)), + ADI->getDef()); return true; } @@ -668,8 +681,7 @@ unsigned CodeGenInstAlias::ResultOperand::getMINumOperands() const { CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) { Result = R->getValueAsDag("ResultInst"); - AsmString = R->getValueAsString("AsmString"); - + AsmString = std::string(R->getValueAsString("AsmString")); // Verify that the root of the result is an instruction. DefInit *DI = dyn_cast<DefInit>(Result->getOperator()); diff --git a/llvm/utils/TableGen/CodeGenInstruction.h b/llvm/utils/TableGen/CodeGenInstruction.h index 1f08ce481a89..af851a11676b 100644 --- a/llvm/utils/TableGen/CodeGenInstruction.h +++ b/llvm/utils/TableGen/CodeGenInstruction.h @@ -16,6 +16,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/MachineValueType.h" #include "llvm/Support/SMLoc.h" +#include <cassert> #include <string> #include <utility> #include <vector> diff --git a/llvm/utils/TableGen/CodeGenIntrinsics.h b/llvm/utils/TableGen/CodeGenIntrinsics.h index 723bbe0cc23d..af59c1f3d833 100644 --- a/llvm/utils/TableGen/CodeGenIntrinsics.h +++ b/llvm/utils/TableGen/CodeGenIntrinsics.h @@ -123,6 +123,12 @@ struct CodeGenIntrinsic { /// True if the intrinsic is no-return. bool isNoReturn; + /// True if the intrinsic is no-sync. + bool isNoSync; + + /// True if the intrinsic is no-free. + bool isNoFree; + /// True if the intrinsic is will-return. bool isWillReturn; @@ -139,17 +145,32 @@ struct CodeGenIntrinsic { // True if the intrinsic is marked as speculatable. bool isSpeculatable; - enum ArgAttribute { + enum ArgAttrKind { NoCapture, NoAlias, Returned, ReadOnly, WriteOnly, ReadNone, - ImmArg + ImmArg, + Alignment + }; + + struct ArgAttribute { + unsigned Index; + ArgAttrKind Kind; + uint64_t Value; + + ArgAttribute(unsigned Idx, ArgAttrKind K, uint64_t V) + : Index(Idx), Kind(K), Value(V) {} + + bool operator<(const ArgAttribute &Other) const { + return std::tie(Index, Kind, Value) < + std::tie(Other.Index, Other.Kind, Other.Value); + } }; - std::vector<std::pair<unsigned, ArgAttribute>> ArgumentAttributes; + std::vector<ArgAttribute> ArgumentAttributes; bool hasProperty(enum SDNP Prop) const { return Properties & (1 << Prop); diff --git a/llvm/utils/TableGen/CodeGenMapTable.cpp b/llvm/utils/TableGen/CodeGenMapTable.cpp index 793bb61481e7..baca0768b26b 100644 --- a/llvm/utils/TableGen/CodeGenMapTable.cpp +++ b/llvm/utils/TableGen/CodeGenMapTable.cpp @@ -98,7 +98,7 @@ private: public: InstrMap(Record* MapRec) { - Name = MapRec->getName(); + Name = std::string(MapRec->getName()); // FilterClass - It's used to reduce the search space only to the // instructions that define the kind of relationship modeled by diff --git a/llvm/utils/TableGen/CodeGenRegisters.cpp b/llvm/utils/TableGen/CodeGenRegisters.cpp index 6153c759b123..4584bc7cfae3 100644 --- a/llvm/utils/TableGen/CodeGenRegisters.cpp +++ b/llvm/utils/TableGen/CodeGenRegisters.cpp @@ -52,18 +52,18 @@ using namespace llvm; CodeGenSubRegIndex::CodeGenSubRegIndex(Record *R, unsigned Enum) : TheDef(R), EnumValue(Enum), AllSuperRegsCovered(true), Artificial(true) { - Name = R->getName(); + Name = std::string(R->getName()); if (R->getValue("Namespace")) - Namespace = R->getValueAsString("Namespace"); + Namespace = std::string(R->getValueAsString("Namespace")); Size = R->getValueAsInt("Size"); Offset = R->getValueAsInt("Offset"); } CodeGenSubRegIndex::CodeGenSubRegIndex(StringRef N, StringRef Nspace, unsigned Enum) - : TheDef(nullptr), Name(N), Namespace(Nspace), Size(-1), Offset(-1), - EnumValue(Enum), AllSuperRegsCovered(true), Artificial(true) { -} + : TheDef(nullptr), Name(std::string(N)), Namespace(std::string(Nspace)), + Size(-1), Offset(-1), EnumValue(Enum), AllSuperRegsCovered(true), + Artificial(true) {} std::string CodeGenSubRegIndex::getQualifiedName() const { std::string N = getNamespace(); @@ -739,11 +739,9 @@ static void sortAndUniqueRegisters(CodeGenRegister::Vec &M) { } CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R) - : TheDef(R), - Name(R->getName()), - TopoSigs(RegBank.getNumTopoSigs()), - EnumValue(-1) { - + : TheDef(R), Name(std::string(R->getName())), + TopoSigs(RegBank.getNumTopoSigs()), EnumValue(-1) { + GeneratePressureSet = R->getValueAsBit("GeneratePressureSet"); std::vector<Record*> TypeList = R->getValueAsListOfDefs("RegTypes"); for (unsigned i = 0, e = TypeList.size(); i != e; ++i) { Record *Type = TypeList[i]; @@ -816,16 +814,11 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R) // class structure has been computed. CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, StringRef Name, Key Props) - : Members(*Props.Members), - TheDef(nullptr), - Name(Name), - TopoSigs(RegBank.getNumTopoSigs()), - EnumValue(-1), - RSI(Props.RSI), - CopyCost(0), - Allocatable(true), - AllocationPriority(0) { + : Members(*Props.Members), TheDef(nullptr), Name(std::string(Name)), + TopoSigs(RegBank.getNumTopoSigs()), EnumValue(-1), RSI(Props.RSI), + CopyCost(0), Allocatable(true), AllocationPriority(0) { Artificial = true; + GeneratePressureSet = false; for (const auto R : Members) { TopoSigs.set(R->getTopoSig()); Artificial &= R->Artificial; @@ -848,6 +841,7 @@ void CodeGenRegisterClass::inheritProperties(CodeGenRegBank &RegBank) { Allocatable = Super.Allocatable; AltOrderSelect = Super.AltOrderSelect; AllocationPriority = Super.AllocationPriority; + GeneratePressureSet |= Super.GeneratePressureSet; // Copy all allocation orders, filter out foreign registers from the larger // super-class. @@ -863,6 +857,16 @@ bool CodeGenRegisterClass::contains(const CodeGenRegister *Reg) const { deref<std::less<>>()); } +unsigned CodeGenRegisterClass::getWeight(const CodeGenRegBank& RegBank) const { + if (TheDef && !TheDef->isValueUnset("Weight")) + return TheDef->getValueAsInt("Weight"); + + if (Members.empty() || Artificial) + return 0; + + return (*Members.begin())->getWeight(RegBank); +} + namespace llvm { raw_ostream &operator<<(raw_ostream &OS, const CodeGenRegisterClass::Key &K) { @@ -990,8 +994,12 @@ void CodeGenRegisterClass::computeSubClasses(CodeGenRegBank &RegBank) { Optional<std::pair<CodeGenRegisterClass *, CodeGenRegisterClass *>> CodeGenRegisterClass::getMatchingSubClassWithSubRegs( CodeGenRegBank &RegBank, const CodeGenSubRegIndex *SubIdx) const { - auto SizeOrder = [](const CodeGenRegisterClass *A, + auto SizeOrder = [this](const CodeGenRegisterClass *A, const CodeGenRegisterClass *B) { + // If there are multiple, identical register classes, prefer the original + // register class. + if (A->getMembers().size() == B->getMembers().size()) + return A == this; return A->getMembers().size() > B->getMembers().size(); }; @@ -1007,8 +1015,10 @@ CodeGenRegisterClass::getMatchingSubClassWithSubRegs( for (auto &RC : RegClasses) if (SuperRegRCsBV[RC.EnumValue]) SuperRegRCs.emplace_back(&RC); - llvm::sort(SuperRegRCs, SizeOrder); - assert(SuperRegRCs.front() == BiggestSuperRegRC && "Biggest class wasn't first"); + llvm::stable_sort(SuperRegRCs, SizeOrder); + + assert(SuperRegRCs.front() == BiggestSuperRegRC && + "Biggest class wasn't first"); // Find all the subreg classes and order them by size too. std::vector<std::pair<CodeGenRegisterClass *, BitVector>> SuperRegClasses; @@ -1223,6 +1233,12 @@ CodeGenSubRegIndex *CodeGenRegBank::getSubRegIdx(Record *Def) { return Idx; } +const CodeGenSubRegIndex * +CodeGenRegBank::findSubRegIdx(const Record* Def) const { + auto I = Def2SubRegIdx.find(Def); + return (I == Def2SubRegIdx.end()) ? nullptr : I->second; +} + CodeGenRegister *CodeGenRegBank::getReg(Record *Def) { CodeGenRegister *&Reg = Def2Reg[Def]; if (Reg) @@ -1259,8 +1275,8 @@ CodeGenRegBank::getOrCreateSubClass(const CodeGenRegisterClass *RC, return &RegClasses.back(); } -CodeGenRegisterClass *CodeGenRegBank::getRegClass(Record *Def) { - if (CodeGenRegisterClass *RC = Def2RC[Def]) +CodeGenRegisterClass *CodeGenRegBank::getRegClass(const Record *Def) const { + if (CodeGenRegisterClass *RC = Def2RC.lookup(Def)) return RC; PrintFatalError(Def->getLoc(), "Not a known RegisterClass!"); @@ -1879,7 +1895,7 @@ void CodeGenRegBank::computeRegUnitSets() { // Compute a unique RegUnitSet for each RegClass. auto &RegClasses = getRegClasses(); for (auto &RC : RegClasses) { - if (!RC.Allocatable || RC.Artificial) + if (!RC.Allocatable || RC.Artificial || !RC.GeneratePressureSet) continue; // Speculatively grow the RegUnitSets to hold the new set. @@ -1940,7 +1956,7 @@ void CodeGenRegBank::computeRegUnitSets() { // Speculatively grow the RegUnitSets to hold the new set. RegUnitSets.resize(RegUnitSets.size() + 1); RegUnitSets.back().Name = - RegUnitSets[Idx].Name + "+" + RegUnitSets[SearchIdx].Name; + RegUnitSets[Idx].Name + "_with_" + RegUnitSets[SearchIdx].Name; std::set_union(RegUnitSets[Idx].Units.begin(), RegUnitSets[Idx].Units.end(), diff --git a/llvm/utils/TableGen/CodeGenRegisters.h b/llvm/utils/TableGen/CodeGenRegisters.h index a8e9e0fbccbe..2b200adef312 100644 --- a/llvm/utils/TableGen/CodeGenRegisters.h +++ b/llvm/utils/TableGen/CodeGenRegisters.h @@ -86,6 +86,7 @@ namespace llvm { CodeGenSubRegIndex(Record *R, unsigned Enum); CodeGenSubRegIndex(StringRef N, StringRef Nspace, unsigned Enum); + CodeGenSubRegIndex(CodeGenSubRegIndex&) = delete; const std::string &getName() const { return Name; } const std::string &getNamespace() const { return Namespace; } @@ -338,6 +339,9 @@ namespace llvm { bool CoveredBySubRegs; /// A register class is artificial if all its members are artificial. bool Artificial; + /// Generate register pressure set for this register class and any class + /// synthesized from it. + bool GeneratePressureSet; // Return the Record that defined this class, or NULL if the class was // created by TableGen. @@ -437,11 +441,15 @@ namespace llvm { // Get a bit vector of TopoSigs present in this register class. const BitVector &getTopoSigs() const { return TopoSigs; } + // Get a weight of this register class. + unsigned getWeight(const CodeGenRegBank&) const; + // Populate a unique sorted list of units from a register set. void buildRegUnitSet(const CodeGenRegBank &RegBank, std::vector<unsigned> &RegUnits) const; CodeGenRegisterClass(CodeGenRegBank&, Record *R); + CodeGenRegisterClass(CodeGenRegisterClass&) = delete; // A key representing the parts of a register class used for forming // sub-classes. Note the ordering provided by this key is not the same as @@ -611,6 +619,7 @@ namespace llvm { public: CodeGenRegBank(RecordKeeper&, const CodeGenHwModes&); + CodeGenRegBank(CodeGenRegBank&) = delete; SetTheory &getSets() { return Sets; } @@ -623,9 +632,13 @@ namespace llvm { return SubRegIndices; } - // Find a SubRegIndex form its Record def. + // Find a SubRegIndex from its Record def or add to the list if it does + // not exist there yet. CodeGenSubRegIndex *getSubRegIdx(Record*); + // Find a SubRegIndex from its Record def. + const CodeGenSubRegIndex *findSubRegIdx(const Record* Def) const; + // Find or create a sub-register index representing the A+B composition. CodeGenSubRegIndex *getCompositeSubRegIndex(CodeGenSubRegIndex *A, CodeGenSubRegIndex *B); @@ -706,7 +719,7 @@ namespace llvm { } // Find a register class from its def. - CodeGenRegisterClass *getRegClass(Record*); + CodeGenRegisterClass *getRegClass(const Record *) const; /// getRegisterClassForRegister - Find the register class that contains the /// specified physical register. If the register is not in a register diff --git a/llvm/utils/TableGen/CodeGenSchedule.cpp b/llvm/utils/TableGen/CodeGenSchedule.cpp index f12d7d484a8e..67583c736cd2 100644 --- a/llvm/utils/TableGen/CodeGenSchedule.cpp +++ b/llvm/utils/TableGen/CodeGenSchedule.cpp @@ -106,7 +106,7 @@ struct InstRegexOp : public SetTheory::Operator { StringRef PatStr = Original.substr(FirstMeta); if (!PatStr.empty()) { // For the rest use a python-style prefix match. - std::string pat = PatStr; + std::string pat = std::string(PatStr); if (pat[0] != '^') { pat.insert(0, "^("); pat.insert(pat.end(), ')'); @@ -546,7 +546,7 @@ void CodeGenSchedModels::addProcModel(Record *ProcDef) { if (!ProcModelMap.insert(std::make_pair(ModelKey, ProcModels.size())).second) return; - std::string Name = ModelKey->getName(); + std::string Name = std::string(ModelKey->getName()); if (ModelKey->isSubClassOf("SchedMachineModel")) { Record *ItinsDef = ModelKey->getValueAsDef("Itineraries"); ProcModels.emplace_back(ProcModels.size(), Name, ModelKey, ItinsDef); @@ -977,7 +977,7 @@ CodeGenSchedModels::createSchedClassName(Record *ItinClassDef, std::string Name; if (ItinClassDef && ItinClassDef->getName() != "NoItinerary") - Name = ItinClassDef->getName(); + Name = std::string(ItinClassDef->getName()); for (unsigned Idx : OperWrites) { if (!Name.empty()) Name += '_'; @@ -1082,15 +1082,14 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { for (Record *RWD : RWDefs) { if (RWD->getValueAsDef("SchedModel") == RWModelDef && RWModelDef->getValueAsBit("FullInstRWOverlapCheck")) { - for (Record *Inst : InstDefs) { - PrintFatalError - (InstRWDef->getLoc(), - "Overlapping InstRW definition for \"" + - Inst->getName() + - "\" also matches previous \"" + - RWD->getValue("Instrs")->getValue()->getAsString() + - "\"."); - } + 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() + + "\"."); } } LLVM_DEBUG(dbgs() << "InstRW: Reuse SC " << OldSCIdx << ":" @@ -1118,15 +1117,14 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel"); for (Record *OldRWDef : SchedClasses[OldSCIdx].InstRWs) { if (OldRWDef->getValueAsDef("SchedModel") == RWModelDef) { - for (Record *InstDef : InstDefs) { - PrintFatalError - (InstRWDef->getLoc(), - "Overlapping InstRW definition for \"" + - InstDef->getName() + - "\" also matches previous \"" + - OldRWDef->getValue("Instrs")->getValue()->getAsString() + - "\"."); - } + 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() + + "\"."); } assert(OldRWDef != InstRWDef && "SchedClass has duplicate InstRW def"); diff --git a/llvm/utils/TableGen/CodeGenSchedule.h b/llvm/utils/TableGen/CodeGenSchedule.h index c26fb1f97807..c487d142d46c 100644 --- a/llvm/utils/TableGen/CodeGenSchedule.h +++ b/llvm/utils/TableGen/CodeGenSchedule.h @@ -58,7 +58,7 @@ struct CodeGenSchedRW { HasVariants(false), IsVariadic(false), IsSequence(false) {} CodeGenSchedRW(unsigned Idx, Record *Def) : Index(Idx), TheDef(Def), IsAlias(false), IsVariadic(false) { - Name = Def->getName(); + Name = std::string(Def->getName()); IsRead = Def->isSubClassOf("SchedRead"); HasVariants = Def->isSubClassOf("SchedVariant"); if (HasVariants) diff --git a/llvm/utils/TableGen/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp index acfb143120af..891a08ea590e 100644 --- a/llvm/utils/TableGen/CodeGenTarget.cpp +++ b/llvm/utils/TableGen/CodeGenTarget.cpp @@ -69,6 +69,7 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::fAny: return "MVT::fAny"; case MVT::vAny: return "MVT::vAny"; case MVT::f16: return "MVT::f16"; + case MVT::bf16: return "MVT::bf16"; case MVT::f32: return "MVT::f32"; case MVT::f64: return "MVT::f64"; case MVT::f80: return "MVT::f80"; @@ -132,6 +133,16 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::v8f16: return "MVT::v8f16"; case MVT::v16f16: return "MVT::v16f16"; case MVT::v32f16: return "MVT::v32f16"; + case MVT::v64f16: return "MVT::v64f16"; + case MVT::v128f16: return "MVT::v128f16"; + case MVT::v2bf16: return "MVT::v2bf16"; + case MVT::v3bf16: return "MVT::v3bf16"; + case MVT::v4bf16: return "MVT::v4bf16"; + case MVT::v8bf16: return "MVT::v8bf16"; + case MVT::v16bf16: return "MVT::v16bf16"; + case MVT::v32bf16: return "MVT::v32bf16"; + case MVT::v64bf16: return "MVT::v64bf16"; + case MVT::v128bf16: return "MVT::v128bf16"; case MVT::v1f32: return "MVT::v1f32"; case MVT::v2f32: return "MVT::v2f32"; case MVT::v3f32: return "MVT::v3f32"; @@ -150,18 +161,22 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::v2f64: return "MVT::v2f64"; case MVT::v4f64: return "MVT::v4f64"; case MVT::v8f64: return "MVT::v8f64"; + case MVT::v16f64: return "MVT::v16f64"; + case MVT::v32f64: return "MVT::v32f64"; case MVT::nxv1i1: return "MVT::nxv1i1"; case MVT::nxv2i1: return "MVT::nxv2i1"; case MVT::nxv4i1: return "MVT::nxv4i1"; case MVT::nxv8i1: return "MVT::nxv8i1"; case MVT::nxv16i1: return "MVT::nxv16i1"; case MVT::nxv32i1: return "MVT::nxv32i1"; + case MVT::nxv64i1: return "MVT::nxv64i1"; case MVT::nxv1i8: return "MVT::nxv1i8"; case MVT::nxv2i8: return "MVT::nxv2i8"; case MVT::nxv4i8: return "MVT::nxv4i8"; case MVT::nxv8i8: return "MVT::nxv8i8"; case MVT::nxv16i8: return "MVT::nxv16i8"; case MVT::nxv32i8: return "MVT::nxv32i8"; + case MVT::nxv64i8: return "MVT::nxv64i8"; case MVT::nxv1i16: return "MVT::nxv1i16"; case MVT::nxv2i16: return "MVT::nxv2i16"; case MVT::nxv4i16: return "MVT::nxv4i16"; @@ -173,14 +188,22 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::nxv4i32: return "MVT::nxv4i32"; case MVT::nxv8i32: return "MVT::nxv8i32"; case MVT::nxv16i32: return "MVT::nxv16i32"; + case MVT::nxv32i32: return "MVT::nxv32i32"; case MVT::nxv1i64: return "MVT::nxv1i64"; case MVT::nxv2i64: return "MVT::nxv2i64"; case MVT::nxv4i64: return "MVT::nxv4i64"; case MVT::nxv8i64: return "MVT::nxv8i64"; case MVT::nxv16i64: return "MVT::nxv16i64"; + case MVT::nxv32i64: return "MVT::nxv32i64"; + case MVT::nxv1f16: return "MVT::nxv1f16"; case MVT::nxv2f16: return "MVT::nxv2f16"; case MVT::nxv4f16: return "MVT::nxv4f16"; case MVT::nxv8f16: return "MVT::nxv8f16"; + case MVT::nxv16f16: return "MVT::nxv16f16"; + case MVT::nxv32f16: return "MVT::nxv32f16"; + 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"; @@ -206,8 +229,9 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { std::string llvm::getQualifiedName(const Record *R) { std::string Namespace; if (R->getValue("Namespace")) - Namespace = R->getValueAsString("Namespace"); - if (Namespace.empty()) return R->getName(); + Namespace = std::string(R->getValueAsString("Namespace")); + if (Namespace.empty()) + return std::string(R->getName()); return Namespace + "::" + R->getName().str(); } @@ -526,7 +550,7 @@ bool CodeGenTarget::guessInstructionProperties() const { ComplexPattern::ComplexPattern(Record *R) { Ty = ::getValueType(R->getValueAsDef("Ty")); NumOperands = R->getValueAsInt("NumOperands"); - SelectFunc = R->getValueAsString("SelectFunc"); + SelectFunc = std::string(R->getValueAsString("SelectFunc")); RootNodes = R->getValueAsListOfDefs("RootNodes"); // FIXME: This is a hack to statically increase the priority of patterns which @@ -598,7 +622,7 @@ CodeGenIntrinsicTable::CodeGenIntrinsicTable(const RecordKeeper &RC) { CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { TheDef = R; - std::string DefName = R->getName(); + std::string DefName = std::string(R->getName()); ArrayRef<SMLoc> DefLoc = R->getLoc(); ModRef = ReadWriteMem; Properties = 0; @@ -606,6 +630,8 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { isCommutative = false; canThrow = false; isNoReturn = false; + isNoSync = false; + isNoFree = false; isWillReturn = false; isCold = false; isNoDuplicate = false; @@ -621,12 +647,12 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { EnumName = std::string(DefName.begin()+4, DefName.end()); if (R->getValue("GCCBuiltinName")) // Ignore a missing GCCBuiltinName field. - GCCBuiltinName = R->getValueAsString("GCCBuiltinName"); + GCCBuiltinName = std::string(R->getValueAsString("GCCBuiltinName")); if (R->getValue("MSBuiltinName")) // Ignore a missing MSBuiltinName field. - MSBuiltinName = R->getValueAsString("MSBuiltinName"); + MSBuiltinName = std::string(R->getValueAsString("MSBuiltinName")); - TargetPrefix = R->getValueAsString("TargetPrefix"); - Name = R->getValueAsString("LLVMName"); + TargetPrefix = std::string(R->getValueAsString("TargetPrefix")); + Name = std::string(R->getValueAsString("LLVMName")); if (Name == "") { // If an explicit name isn't specified, derive one from the DefName. @@ -725,8 +751,7 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { // variants with iAny types; otherwise, if the intrinsic is not // overloaded, all the types can be specified directly. assert(((!TyEl->isSubClassOf("LLVMExtendedType") && - !TyEl->isSubClassOf("LLVMTruncatedType") && - !TyEl->isSubClassOf("LLVMScalarOrSameVectorWidth")) || + !TyEl->isSubClassOf("LLVMTruncatedType")) || VT == MVT::iAny || VT == MVT::vAny) && "Expected iAny or vAny type"); } else @@ -771,6 +796,10 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { 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") @@ -781,25 +810,29 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { hasSideEffects = true; else if (Property->isSubClassOf("NoCapture")) { unsigned ArgNo = Property->getValueAsInt("ArgNo"); - ArgumentAttributes.push_back(std::make_pair(ArgNo, NoCapture)); + ArgumentAttributes.emplace_back(ArgNo, NoCapture, 0); } else if (Property->isSubClassOf("NoAlias")) { unsigned ArgNo = Property->getValueAsInt("ArgNo"); - ArgumentAttributes.push_back(std::make_pair(ArgNo, NoAlias)); + ArgumentAttributes.emplace_back(ArgNo, NoAlias, 0); } else if (Property->isSubClassOf("Returned")) { unsigned ArgNo = Property->getValueAsInt("ArgNo"); - ArgumentAttributes.push_back(std::make_pair(ArgNo, Returned)); + ArgumentAttributes.emplace_back(ArgNo, Returned, 0); } else if (Property->isSubClassOf("ReadOnly")) { unsigned ArgNo = Property->getValueAsInt("ArgNo"); - ArgumentAttributes.push_back(std::make_pair(ArgNo, ReadOnly)); + ArgumentAttributes.emplace_back(ArgNo, ReadOnly, 0); } else if (Property->isSubClassOf("WriteOnly")) { unsigned ArgNo = Property->getValueAsInt("ArgNo"); - ArgumentAttributes.push_back(std::make_pair(ArgNo, WriteOnly)); + ArgumentAttributes.emplace_back(ArgNo, WriteOnly, 0); } else if (Property->isSubClassOf("ReadNone")) { unsigned ArgNo = Property->getValueAsInt("ArgNo"); - ArgumentAttributes.push_back(std::make_pair(ArgNo, ReadNone)); + ArgumentAttributes.emplace_back(ArgNo, ReadNone, 0); } else if (Property->isSubClassOf("ImmArg")) { unsigned ArgNo = Property->getValueAsInt("ArgNo"); - ArgumentAttributes.push_back(std::make_pair(ArgNo, ImmArg)); + 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!"); } @@ -819,7 +852,8 @@ bool CodeGenIntrinsic::isParamAPointer(unsigned ParamIdx) const { } bool CodeGenIntrinsic::isParamImmArg(unsigned ParamIdx) const { - std::pair<unsigned, ArgAttribute> Val = {ParamIdx, ImmArg}; + // Convert argument index to attribute index starting from `FirstArgIndex`. + ArgAttribute Val{ParamIdx + 1, ImmArg, 0}; return std::binary_search(ArgumentAttributes.begin(), ArgumentAttributes.end(), Val); } diff --git a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp index e9f1fb93d516..d9ec14aab8a8 100644 --- a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp +++ b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -281,7 +281,7 @@ void MatcherTableEmitter::EmitPatternMatchTable(raw_ostream &OS) { unsigned MatcherTableEmitter:: EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, raw_ostream &OS) { - OS.indent(Indent*2); + OS.indent(Indent); switch (N->getKind()) { case Matcher::Scope: { @@ -291,6 +291,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, 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, "; @@ -298,9 +299,9 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, } else { if (!OmitComments) { OS << "/*" << format_decimal(CurrentIdx, IndexWidth) << "*/"; - OS.indent(Indent*2) << "/*Scope*/ "; + OS.indent(Indent) << "/*Scope*/ "; } else - OS.indent(Indent*2); + OS.indent(Indent); } // We need to encode the child and the offset of the failure code before @@ -308,7 +309,6 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, // 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. - SmallString<128> TmpBuf; unsigned ChildSize = 0; unsigned VBRSize = 0; do { @@ -337,7 +337,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, // Emit a zero as a sentinel indicating end of 'Scope'. if (!OmitComments) OS << "/*" << format_decimal(CurrentIdx, IndexWidth) << "*/"; - OS.indent(Indent*2) << "0, "; + OS.indent(Indent) << "0, "; if (!OmitComments) OS << "/*End of Scope*/"; OS << '\n'; @@ -450,6 +450,7 @@ 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; @@ -466,7 +467,6 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, // 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. - SmallString<128> TmpBuf; unsigned ChildSize = 0; unsigned VBRSize = 0; do { @@ -483,7 +483,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, if (i != 0) { if (!OmitComments) OS << "/*" << format_decimal(CurrentIdx, IndexWidth) << "*/"; - OS.indent(Indent*2); + OS.indent(Indent); if (!OmitComments) OS << (isa<SwitchOpcodeMatcher>(N) ? "/*SwitchOpcode*/ " : "/*SwitchType*/ "); @@ -509,7 +509,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, // Emit the final zero to terminate the switch. if (!OmitComments) OS << "/*" << format_decimal(CurrentIdx, IndexWidth) << "*/"; - OS.indent(Indent*2) << "0,"; + OS.indent(Indent) << "0,"; if (!OmitComments) OS << (isa<SwitchOpcodeMatcher>(N) ? " // EndSwitchOpcode" : " // EndSwitchType"); @@ -619,7 +619,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, } case Matcher::EmitStringInteger: { const std::string &Val = cast<EmitStringIntegerMatcher>(N)->getValue(); - // These should always fit into one byte. + // These should always fit into 7 bits. OS << "OPC_EmitInteger, " << getEnumName(cast<EmitStringIntegerMatcher>(N)->getVT()) << ", " << Val << ",\n"; @@ -712,7 +712,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, unsigned Offset = getPatternIdxFromTable(src + " -> " + dst, std::move(include_src)); OS << "TARGET_VAL(" << Offset << "),\n"; - OS.indent(FullIndexWidth + Indent * 2); + OS.indent(FullIndexWidth + Indent); } } const EmitNodeMatcherCommon *EN = cast<EmitNodeMatcherCommon>(N); @@ -731,7 +731,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, OS << "|OPFL_Variadic" << EN->getNumFixedArityOperands(); OS << ",\n"; - OS.indent(FullIndexWidth + Indent*2+4); + OS.indent(FullIndexWidth + Indent+4); if (!CompressVTs) { OS << EN->getNumVTs(); if (!OmitComments) @@ -762,10 +762,10 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, OS << '\n'; if (const MorphNodeToMatcher *SNT = dyn_cast<MorphNodeToMatcher>(N)) { - OS.indent(FullIndexWidth + Indent*2) << "// Src: " + OS.indent(FullIndexWidth + Indent) << "// Src: " << *SNT->getPattern().getSrcPattern() << " - Complexity = " << SNT->getPattern().getPatternComplexity(CGP) << '\n'; - OS.indent(FullIndexWidth + Indent*2) << "// Dst: " + OS.indent(FullIndexWidth + Indent) << "// Dst: " << *SNT->getPattern().getDstPattern() << '\n'; } } else @@ -789,7 +789,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, unsigned Offset = getPatternIdxFromTable(src + " -> " + dst, std::move(include_src)); OS << "TARGET_VAL(" << Offset << "),\n"; - OS.indent(FullIndexWidth + Indent * 2); + OS.indent(FullIndexWidth + Indent); } OS << "OPC_CompleteMatch, " << CM->getNumResults() << ", "; unsigned NumResultBytes = 0; @@ -797,10 +797,10 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, NumResultBytes += EmitVBRValue(CM->getResult(i), OS); OS << '\n'; if (!OmitComments) { - OS.indent(FullIndexWidth + Indent*2) << " // Src: " + OS.indent(FullIndexWidth + Indent) << " // Src: " << *CM->getPattern().getSrcPattern() << " - Complexity = " << CM->getPattern().getPatternComplexity(CGP) << '\n'; - OS.indent(FullIndexWidth + Indent*2) << " // Dst: " + OS.indent(FullIndexWidth + Indent) << " // Dst: " << *CM->getPattern().getDstPattern(); } OS << '\n'; @@ -960,7 +960,8 @@ void MatcherTableEmitter::EmitPredicateFunctions(raw_ostream &OS) { OS << "// " << NodeXForms[i]->getName(); OS << '\n'; - std::string ClassName = CGP.getSDNodeInfo(SDNode).getSDClassName(); + std::string ClassName = + std::string(CGP.getSDNodeInfo(SDNode).getSDClassName()); if (ClassName == "SDNode") OS << " SDNode *N = V.getNode();\n"; else diff --git a/llvm/utils/TableGen/DAGISelMatcherGen.cpp b/llvm/utils/TableGen/DAGISelMatcherGen.cpp index 6a86868a9bcd..123ea3374c74 100644 --- a/llvm/utils/TableGen/DAGISelMatcherGen.cpp +++ b/llvm/utils/TableGen/DAGISelMatcherGen.cpp @@ -311,7 +311,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N, // The "name" of a non-leaf complex pattern (MY_PAT $op1, $op2) is // "MY_PAT:op1:op2". We should already have validated that the uses are // consistent. - std::string PatternName = N->getOperator()->getName(); + std::string PatternName = std::string(N->getOperator()->getName()); for (unsigned i = 0; i < N->getNumChildren(); ++i) { PatternName += ":"; PatternName += N->getChild(i)->getName(); @@ -707,14 +707,36 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N, if (Def->isSubClassOf("RegisterOperand")) Def = Def->getValueAsDef("RegClass"); if (Def->isSubClassOf("RegisterClass")) { - std::string Value = getQualifiedName(Def) + "RegClassID"; - AddMatcher(new EmitStringIntegerMatcher(Value, MVT::i32)); - ResultOps.push_back(NextRecordedOperandNo++); + // If the register class has an enum integer value greater than 127, the + // encoding overflows the limit of 7 bits, which precludes the use of + // StringIntegerMatcher. In this case, fallback to using IntegerMatcher. + const CodeGenRegisterClass &RC = + CGP.getTargetInfo().getRegisterClass(Def); + if (RC.EnumValue <= 127) { + std::string Value = getQualifiedName(Def) + "RegClassID"; + AddMatcher(new EmitStringIntegerMatcher(Value, MVT::i32)); + ResultOps.push_back(NextRecordedOperandNo++); + } else { + AddMatcher(new EmitIntegerMatcher(RC.EnumValue, MVT::i32)); + ResultOps.push_back(NextRecordedOperandNo++); + } return; } // Handle a subregister index. This is used for INSERT_SUBREG etc. if (Def->isSubClassOf("SubRegIndex")) { + const CodeGenRegBank &RB = CGP.getTargetInfo().getRegBank(); + // If we have more than 127 subreg indices the encoding can overflow + // 7 bit and we cannot use StringInteger. + if (RB.getSubRegIndices().size() > 127) { + const CodeGenSubRegIndex *I = RB.findSubRegIdx(Def); + assert(I && "Cannot find subreg index by name!"); + if (I->EnumValue > 127) { + AddMatcher(new EmitIntegerMatcher(I->EnumValue, MVT::i32)); + ResultOps.push_back(NextRecordedOperandNo++); + return; + } + } std::string Value = getQualifiedName(Def); AddMatcher(new EmitStringIntegerMatcher(Value, MVT::i32)); ResultOps.push_back(NextRecordedOperandNo++); diff --git a/llvm/utils/TableGen/DFAEmitter.cpp b/llvm/utils/TableGen/DFAEmitter.cpp index dd3db7c150ba..7391f6845a4b 100644 --- a/llvm/utils/TableGen/DFAEmitter.cpp +++ b/llvm/utils/TableGen/DFAEmitter.cpp @@ -53,14 +53,14 @@ void DfaEmitter::addTransition(state_type From, state_type To, action_type A) { ++NumNfaTransitions; } -void DfaEmitter::visitDfaState(DfaState DS) { +void DfaEmitter::visitDfaState(const DfaState &DS) { // For every possible action... auto FromId = DfaStates.idFor(DS); for (action_type A : Actions) { DfaState NewStates; DfaTransitionInfo TI; // For every represented state, word pair in the original NFA... - for (state_type &FromState : DS) { + for (state_type FromState : DS) { // If this action is possible from this state add the transitioned-to // states to NewStates. auto I = NfaTransitions.find({FromState, A}); @@ -90,8 +90,11 @@ void DfaEmitter::constructDfa() { // Note that UniqueVector starts indices at 1, not zero. unsigned DfaStateId = 1; - while (DfaStateId <= DfaStates.size()) - visitDfaState(DfaStates[DfaStateId++]); + while (DfaStateId <= DfaStates.size()) { + DfaState S = DfaStates[DfaStateId]; + visitDfaState(S); + DfaStateId++; + } } void DfaEmitter::emit(StringRef Name, raw_ostream &OS) { @@ -119,7 +122,7 @@ void DfaEmitter::emit(StringRef Name, raw_ostream &OS) { for (auto &T : DfaTransitions) Table.add(T.second.second); Table.layout(); - OS << "std::array<NfaStatePair, " << Table.size() << "> " << Name + OS << "const std::array<NfaStatePair, " << Table.size() << "> " << Name << "TransitionInfo = {{\n"; Table.emit( OS, @@ -143,8 +146,8 @@ void DfaEmitter::emit(StringRef Name, raw_ostream &OS) { OS << "// A table of DFA transitions, ordered by {FromDfaState, Action}.\n"; OS << "// The initial state is 1, not zero.\n"; - OS << "std::array<" << Name << "Transition, " << DfaTransitions.size() << "> " - << Name << "Transitions = {{\n"; + OS << "const std::array<" << Name << "Transition, " + << DfaTransitions.size() << "> " << Name << "Transitions = {{\n"; for (auto &KV : DfaTransitions) { dfa_state_type From = KV.first.first; dfa_state_type To = KV.second.first; @@ -345,7 +348,7 @@ Transition::Transition(Record *R, Automaton *Parent) { Types.emplace_back("unsigned"); } else if (isa<StringRecTy>(SymbolV->getType()) || isa<CodeRecTy>(SymbolV->getType())) { - Actions.emplace_back(nullptr, 0, R->getValueAsString(A)); + Actions.emplace_back(nullptr, 0, std::string(R->getValueAsString(A))); Types.emplace_back("std::string"); } else { report_fatal_error("Unhandled symbol type!"); @@ -353,7 +356,7 @@ Transition::Transition(Record *R, Automaton *Parent) { StringRef TypeOverride = Parent->getActionSymbolType(A); if (!TypeOverride.empty()) - Types.back() = TypeOverride; + Types.back() = std::string(TypeOverride); } } diff --git a/llvm/utils/TableGen/DFAEmitter.h b/llvm/utils/TableGen/DFAEmitter.h index 76de8f72cd88..44e5d97d544f 100644 --- a/llvm/utils/TableGen/DFAEmitter.h +++ b/llvm/utils/TableGen/DFAEmitter.h @@ -17,16 +17,16 @@ #ifndef LLVM_UTILS_TABLEGEN_DFAEMITTER_H #define LLVM_UTILS_TABLEGEN_DFAEMITTER_H -#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/UniqueVector.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/TableGen/Record.h" +#include <map> #include <set> -#include <unordered_map> namespace llvm { class raw_ostream; +class StringRef; + /// Construct a deterministic finite state automaton from possible /// nondeterministic state and transition data. /// @@ -99,7 +99,7 @@ private: void constructDfa(); /// Visit a single DFA state and construct all possible transitions to new DFA /// states. - void visitDfaState(DfaState DS); + void visitDfaState(const DfaState &DS); }; } // namespace llvm diff --git a/llvm/utils/TableGen/DFAPacketizerEmitter.cpp b/llvm/utils/TableGen/DFAPacketizerEmitter.cpp index 018bda1b6090..bc4a084b3224 100644 --- a/llvm/utils/TableGen/DFAPacketizerEmitter.cpp +++ b/llvm/utils/TableGen/DFAPacketizerEmitter.cpp @@ -93,7 +93,7 @@ public: } // end anonymous namespace DFAPacketizerEmitter::DFAPacketizerEmitter(RecordKeeper &R) - : TargetName(CodeGenTarget(R).getName()), Records(R) {} + : TargetName(std::string(CodeGenTarget(R).getName())), Records(R) {} int DFAPacketizerEmitter::collectAllFuncUnits( ArrayRef<const CodeGenProcModel *> ProcModels) { @@ -120,7 +120,7 @@ int DFAPacketizerEmitter::collectAllFuncUnits( assert((j < DFA_MAX_RESOURCES) && "Exceeded maximum number of representable resources"); uint64_t FuncResources = 1ULL << j; - FUNameToBitsMap[FUs[j]->getName()] = FuncResources; + FUNameToBitsMap[std::string(FUs[j]->getName())] = FuncResources; LLVM_DEBUG(dbgs() << " " << FUs[j]->getName() << ":0x" << Twine::utohexstr(FuncResources)); } @@ -152,13 +152,13 @@ int DFAPacketizerEmitter::collectAllComboFuncs(ArrayRef<Record *> ComboFuncList) Record *ComboFunc = FuncData->getValueAsDef("TheComboFunc"); const std::vector<Record *> &FuncList = FuncData->getValueAsListOfDefs("FuncList"); - const std::string &ComboFuncName = ComboFunc->getName(); + const std::string &ComboFuncName = std::string(ComboFunc->getName()); uint64_t ComboBit = FUNameToBitsMap[ComboFuncName]; uint64_t ComboResources = ComboBit; LLVM_DEBUG(dbgs() << " combo: " << ComboFuncName << ":0x" << Twine::utohexstr(ComboResources) << "\n"); for (unsigned k = 0, M = FuncList.size(); k < M; ++k) { - std::string FuncName = FuncList[k]->getName(); + std::string FuncName = std::string(FuncList[k]->getName()); uint64_t FuncResources = FUNameToBitsMap[FuncName]; LLVM_DEBUG(dbgs() << " " << FuncName << ":0x" << Twine::utohexstr(FuncResources) << "\n"); @@ -181,7 +181,7 @@ DFAPacketizerEmitter::getResourcesForItinerary(Record *Itinerary) { for (Record *StageDef : Itinerary->getValueAsListOfDefs("Stages")) { uint64_t StageResources = 0; for (Record *Unit : StageDef->getValueAsListOfDefs("Units")) { - StageResources |= FUNameToBitsMap[Unit->getName()]; + StageResources |= FUNameToBitsMap[std::string(Unit->getName())]; } if (StageResources != 0) Resources.push_back(StageResources); @@ -219,7 +219,7 @@ void DFAPacketizerEmitter::run(raw_ostream &OS) { for (const CodeGenProcModel &ProcModel : CGS.procModels()) { if (ProcModel.hasItineraries()) { auto NS = ProcModel.ItinsDef->getValueAsString("PacketizerNamespace"); - ItinsByNamespace[NS].push_back(&ProcModel); + ItinsByNamespace[std::string(NS)].push_back(&ProcModel); } } @@ -246,7 +246,8 @@ void DFAPacketizerEmitter::emitForItineraries( // Output the mapping from ScheduleClass to ResourcesIdx. unsigned Idx = 0; - OS << "unsigned " << TargetName << DFAName << "ResourceIndices[] = {"; + OS << "constexpr unsigned " << TargetName << DFAName + << "ResourceIndices[] = {"; for (const ScheduleClass &SC : ScheduleClasses) { if (Idx++ % 32 == 0) OS << "\n "; @@ -255,7 +256,7 @@ void DFAPacketizerEmitter::emitForItineraries( OS << "\n};\n\n"; // And the mapping from Itinerary index into the previous table. - OS << "unsigned " << TargetName << DFAName + OS << "constexpr unsigned " << TargetName << DFAName << "ProcResourceIndexStart[] = {\n"; OS << " 0, // NoSchedModel\n"; for (const CodeGenProcModel *Model : ProcModels) { diff --git a/llvm/utils/TableGen/DirectiveEmitter.cpp b/llvm/utils/TableGen/DirectiveEmitter.cpp new file mode 100644 index 000000000000..2061ff1fdd1a --- /dev/null +++ b/llvm/utils/TableGen/DirectiveEmitter.cpp @@ -0,0 +1,524 @@ +//===- DirectiveEmitter.cpp - Directive Language Emitter ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// DirectiveEmitter uses the descriptions of directives and clauses to construct +// common code declarations to be used in Frontends. +// +//===----------------------------------------------------------------------===// + +#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" +#include "llvm/TableGen/TableGenBackend.h" + +using namespace llvm; + +namespace { +// Simple RAII helper for defining ifdef-undef-endif scopes. +class IfDefScope { +public: + IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) { + OS << "#ifdef " << Name << "\n" + << "#undef " << Name << "\n"; + } + + ~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; } + +private: + StringRef Name; + raw_ostream &OS; +}; +} // end anonymous namespace + +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) { + OS << "\n"; + OS << "enum class " << Enum << " {\n"; + for (const auto &R : Records) { + const auto Name = R->getValueAsString("name"); + OS << " " << Prefix << getFormattedName(Name) << ",\n"; + } + OS << "};\n"; + OS << "\n"; + OS << "static constexpr std::size_t " << Enum + << "_enumSize = " << Records.size() << ";\n"; + + // Make the enum values available in the defined namespace. This allows us to + // write something like Enum_X if we have a `using namespace <CppNamespace>`. + // 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) { + 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"; + } + } +} + +// 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."); + 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 << "\n#include \"llvm/ADT/BitmaskEnum.h\"\n"; + + OS << "\n"; + OS << "namespace llvm {\n"; + OS << "class StringRef;\n"; + + // Open namespaces defined in the directive language + llvm::SmallVector<StringRef, 2> Namespaces; + llvm::SplitString(CppNamespace, Namespaces, "::"); + for (auto Ns : Namespaces) + OS << "namespace " << Ns << " {\n"; + + if (EnableBitmaskEnumInNamespace) + OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; + + // Emit Directive enumeration + const auto &Directives = Records.getAllDerivedDefinitions("Directive"); + GenerateEnumClass(Directives, OS, "Directive", DirectivePrefix, CppNamespace, + MakeEnumAvailableInNamespace); + + // Emit Clause enumeration + const auto &Clauses = Records.getAllDerivedDefinitions("Clause"); + GenerateEnumClass(Clauses, OS, "Clause", ClausePrefix, CppNamespace, + MakeEnumAvailableInNamespace); + + // Generic function signatures + OS << "\n"; + OS << "// Enumeration helper functions\n"; + OS << "Directive get" << LanguageName + << "DirectiveKind(llvm::StringRef Str);\n"; + OS << "\n"; + OS << "llvm::StringRef get" << LanguageName + << "DirectiveName(Directive D);\n"; + OS << "\n"; + OS << "Clause get" << LanguageName << "ClauseKind(llvm::StringRef Str);\n"; + OS << "\n"; + OS << "llvm::StringRef get" << LanguageName << "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"; + + // Closing namespaces + for (auto Ns : llvm::reverse(Namespaces)) + OS << "} // namespace " << Ns << "\n"; + + OS << "} // namespace llvm\n"; + + OS << "#endif // LLVM_" << LanguageName << "_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) { + OS << "\n"; + OS << "llvm::StringRef llvm::" << Namespace << "::get" << LanguageName << 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"; + OS << " return \""; + if (AlternativeName.empty()) + OS << Name; + else + OS << AlternativeName; + OS << "\";\n"; + } + OS << " }\n"; // switch + OS << " llvm_unreachable(\"Invalid " << LanguageName << " " << 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) { + + auto DefaultIt = std::find_if(Records.begin(), Records.end(), [](Record *R) { + return R->getValueAsBit("isDefault") == true; + }); + + if (DefaultIt == Records.end()) { + PrintError("A least one " + Enum + " must be defined as default."); + return; + } + + const auto FormattedDefaultName = + getFormattedName((*DefaultIt)->getValueAsString("name")); + + OS << "\n"; + OS << Enum << " llvm::" << Namespace << "::get" << LanguageName << Enum + << "Kind(llvm::StringRef Str) {\n"; + OS << " return llvm::StringSwitch<" << Enum << ">(Str)\n"; + + for (const auto &R : Records) { + const auto Name = R->getValueAsString("name"); + if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) { + OS << " .Case(\"" << Name << "\"," << Prefix << FormattedDefaultName + << ")\n"; + } else { + OS << " .Case(\"" << Name << "\"," << Prefix << getFormattedName(Name) + << ")\n"; + } + } + OS << " .Default(" << Prefix << FormattedDefaultName << ");\n"; + OS << "}\n"; +} + +void GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses, + raw_ostream &OS, StringRef DirectiveName, + StringRef DirectivePrefix, + StringRef ClausePrefix, + 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"; + } + } +} + +// Generate the isAllowedClauseForDirective function implementation. +void GenerateIsAllowedClause(const std::vector<Record *> &Directives, + raw_ostream &OS, StringRef LanguageName, + StringRef DirectivePrefix, StringRef ClausePrefix, + StringRef CppNamespace) { + OS << "\n"; + OS << "bool llvm::" << CppNamespace << "::isAllowedClauseForDirective(" + << "Directive D, Clause C, unsigned Version) {\n"; + OS << " assert(unsigned(D) <= llvm::" << CppNamespace + << "::Directive_enumSize);\n"; + OS << " assert(unsigned(C) <= llvm::" << CppNamespace + << "::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"); + + OS << " case " << DirectivePrefix << getFormattedName(DirectiveName) + << ":\n"; + if (AllowedClauses.size() == 0 && AllowedOnceClauses.size() == 0 && + AllowedExclusiveClauses.size() == 0 && RequiredClauses.size() == 0) { + OS << " return false;\n"; + } else { + OS << " switch (C) {\n"; + + llvm::StringSet<> Cases; + + GenerateCaseForVersionedClauses(AllowedClauses, OS, DirectiveName, + DirectivePrefix, ClausePrefix, Cases); + + GenerateCaseForVersionedClauses(AllowedOnceClauses, OS, DirectiveName, + DirectivePrefix, ClausePrefix, Cases); + + GenerateCaseForVersionedClauses(AllowedExclusiveClauses, OS, + DirectiveName, DirectivePrefix, + ClausePrefix, Cases); + + GenerateCaseForVersionedClauses(RequiredClauses, OS, DirectiveName, + DirectivePrefix, ClausePrefix, Cases); + + OS << " default:\n"; + OS << " return false;\n"; + OS << " }\n"; // End of clauses switch + } + OS << " break;\n"; + } + + OS << " }\n"; // End of directives switch + OS << " llvm_unreachable(\"Invalid " << LanguageName + << " 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) { + + OS << "\n"; + OS << " static " << ClauseEnumSetClass << " " << ClauseSetPrefix + << DirectivePrefix << getFormattedName(DirectiveName) << " {\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"; + } + 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) { + + IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS); + + OS << "\n"; + OS << "namespace llvm {\n"; + + // Open namespaces defined in the directive language. + llvm::SmallVector<StringRef, 2> Namespaces; + llvm::SplitString(CppNamespace, 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"); + + 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); + } + + // Closing namespaces + for (auto Ns : llvm::reverse(Namespaces)) + OS << "} // namespace " << Ns << "\n"; + + OS << "} // namespace llvm\n"; +} + +// 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) { + + 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 << "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"; + 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 << " }\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) { + + GenerateDirectiveClauseSets(Directives, OS, LanguageName, ClauseEnumSetClass, + DirectivePrefix, ClausePrefix, CppNamespace); + + GenerateDirectiveClauseMap(Directives, OS, LanguageName, ClauseEnumSetClass, + DirectivePrefix, ClausePrefix, CppNamespace); +} + +// Generate the implemenation section for the enumeration in the directive +// language. +void EmitDirectivesGen(RecordKeeper &Records, raw_ostream &OS) { + + const auto &DirectiveLanguages = + Records.getAllDerivedDefinitions("DirectiveLanguage"); + + if (DirectiveLanguages.size() != 1) { + PrintError("A single definition of DirectiveLanguage is needed."); + return; + } + + 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"); + + const auto &Directives = Records.getAllDerivedDefinitions("Directive"); + + EmitDirectivesFlangImpl(Directives, OS, LanguageName, ClauseEnumSetClass, + DirectivePrefix, ClausePrefix, CppNamespace); +} + +// Generate the implemenation for the enumeration in the directive +// language. This code can be included in library. +void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) { + + const auto &DirectiveLanguages = + Records.getAllDerivedDefinitions("DirectiveLanguage"); + + if (DirectiveLanguages.size() != 1) { + PrintError("A single definition of DirectiveLanguage is needed."); + return; + } + + 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"); + + StringRef IncludeHeader = + DirectiveLanguage->getValueAsString("includeHeader"); + + if (!IncludeHeader.empty()) + OS << "#include \"" << IncludeHeader << "\"\n\n"; + + OS << "#include \"llvm/ADT/StringRef.h\"\n"; + OS << "#include \"llvm/ADT/StringSwitch.h\"\n"; + OS << "#include \"llvm/Support/ErrorHandling.h\"\n"; + OS << "\n"; + OS << "using namespace llvm;\n"; + llvm::SmallVector<StringRef, 2> Namespaces; + llvm::SplitString(CppNamespace, Namespaces, "::"); + for (auto Ns : Namespaces) + OS << "using namespace " << Ns << ";\n"; + + // getDirectiveKind(StringRef Str) + GenerateGetKind(Directives, OS, "Directive", DirectivePrefix, LanguageName, + CppNamespace, /*ImplicitAsUnknown=*/false); + + // getDirectiveName(Directive Kind) + GenerateGetName(Directives, OS, "Directive", DirectivePrefix, LanguageName, + CppNamespace); + + // getClauseKind(StringRef Str) + GenerateGetKind(Clauses, OS, "Clause", ClausePrefix, LanguageName, + CppNamespace, /*ImplicitAsUnknown=*/true); + + // getClauseName(Clause Kind) + GenerateGetName(Clauses, OS, "Clause", ClausePrefix, LanguageName, + CppNamespace); + + // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version) + GenerateIsAllowedClause(Directives, OS, LanguageName, DirectivePrefix, + ClausePrefix, CppNamespace); +} + +} // namespace llvm diff --git a/llvm/utils/TableGen/DisassemblerEmitter.cpp b/llvm/utils/TableGen/DisassemblerEmitter.cpp index 0002b0e14db6..7c3f53b31bf4 100644 --- a/llvm/utils/TableGen/DisassemblerEmitter.cpp +++ b/llvm/utils/TableGen/DisassemblerEmitter.cpp @@ -136,7 +136,7 @@ void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) { // ARM and Thumb have a CHECK() macro to deal with DecodeStatuses. if (Target.getName() == "ARM" || Target.getName() == "Thumb" || Target.getName() == "AArch64" || Target.getName() == "ARM64") { - std::string PredicateNamespace = Target.getName(); + std::string PredicateNamespace = std::string(Target.getName()); if (PredicateNamespace == "Thumb") PredicateNamespace = "ARM"; @@ -148,9 +148,9 @@ void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) { return; } - EmitFixedLenDecoder(Records, OS, Target.getName(), - "if (", " == MCDisassembler::Fail)", - "MCDisassembler::Success", "MCDisassembler::Fail", ""); + EmitFixedLenDecoder(Records, OS, std::string(Target.getName()), "if (", + " == MCDisassembler::Fail)", "MCDisassembler::Success", + "MCDisassembler::Fail", ""); } } // end namespace llvm diff --git a/llvm/utils/TableGen/ExegesisEmitter.cpp b/llvm/utils/TableGen/ExegesisEmitter.cpp index 976d5f51776f..8f784e4a4121 100644 --- a/llvm/utils/TableGen/ExegesisEmitter.cpp +++ b/llvm/utils/TableGen/ExegesisEmitter.cpp @@ -101,7 +101,7 @@ ExegesisEmitter::ExegesisEmitter(RecordKeeper &RK) PrintFatalError("ERROR: No 'Target' subclasses defined!"); if (Targets.size() != 1) PrintFatalError("ERROR: Multiple subclasses of Target defined!"); - Target = Targets[0]->getName(); + Target = std::string(Targets[0]->getName()); } void ExegesisEmitter::emitPfmCountersInfo(const Record &Def, diff --git a/llvm/utils/TableGen/FastISelEmitter.cpp b/llvm/utils/TableGen/FastISelEmitter.cpp index b39956859fe8..0729ab70d696 100644 --- a/llvm/utils/TableGen/FastISelEmitter.cpp +++ b/llvm/utils/TableGen/FastISelEmitter.cpp @@ -414,7 +414,7 @@ private: } // End anonymous namespace static std::string getOpcodeName(Record *Op, CodeGenDAGPatterns &CGP) { - return CGP.getSDNodeInfo(Op).getEnumName(); + return std::string(CGP.getSDNodeInfo(Op).getEnumName()); } static std::string getLegalCName(std::string OpName) { @@ -719,22 +719,20 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) { MVT::SimpleValueType RetVT = RI->first; const PredMap &PM = RI->second; - OS << "unsigned fastEmit_" - << getLegalCName(Opcode) - << "_" << getLegalCName(getName(VT)) - << "_" << getLegalCName(getName(RetVT)) << "_"; + OS << "unsigned fastEmit_" << getLegalCName(Opcode) << "_" + << getLegalCName(std::string(getName(VT))) << "_" + << getLegalCName(std::string(getName(RetVT))) << "_"; Operands.PrintManglingSuffix(OS, ImmediatePredicates); OS << "("; Operands.PrintParameters(OS); OS << ") {\n"; - emitInstructionCode(OS, Operands, PM, getName(RetVT)); + emitInstructionCode(OS, Operands, PM, std::string(getName(RetVT))); } // Emit one function for the type that demultiplexes on return type. - OS << "unsigned fastEmit_" - << getLegalCName(Opcode) << "_" - << getLegalCName(getName(VT)) << "_"; + OS << "unsigned fastEmit_" << getLegalCName(Opcode) << "_" + << getLegalCName(std::string(getName(VT))) << "_"; Operands.PrintManglingSuffix(OS, ImmediatePredicates); OS << "(MVT RetVT"; if (!Operands.empty()) @@ -745,8 +743,9 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) { RI != RE; ++RI) { MVT::SimpleValueType RetVT = RI->first; OS << " case " << getName(RetVT) << ": return fastEmit_" - << getLegalCName(Opcode) << "_" << getLegalCName(getName(VT)) - << "_" << getLegalCName(getName(RetVT)) << "_"; + << getLegalCName(Opcode) << "_" + << getLegalCName(std::string(getName(VT))) << "_" + << getLegalCName(std::string(getName(RetVT))) << "_"; Operands.PrintManglingSuffix(OS, ImmediatePredicates); OS << "("; Operands.PrintArguments(OS); @@ -756,9 +755,8 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) { } else { // Non-variadic return type. - OS << "unsigned fastEmit_" - << getLegalCName(Opcode) << "_" - << getLegalCName(getName(VT)) << "_"; + OS << "unsigned fastEmit_" << getLegalCName(Opcode) << "_" + << getLegalCName(std::string(getName(VT))) << "_"; Operands.PrintManglingSuffix(OS, ImmediatePredicates); OS << "(MVT RetVT"; if (!Operands.empty()) @@ -788,7 +786,7 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) { for (TypeRetPredMap::const_iterator TI = TM.begin(), TE = TM.end(); TI != TE; ++TI) { MVT::SimpleValueType VT = TI->first; - std::string TypeName = getName(VT); + std::string TypeName = std::string(getName(VT)); OS << " case " << TypeName << ": return fastEmit_" << getLegalCName(Opcode) << "_" << getLegalCName(TypeName) << "_"; Operands.PrintManglingSuffix(OS, ImmediatePredicates); diff --git a/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp b/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp index 21ec5897ea50..88d210f7fd39 100644 --- a/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp +++ b/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp @@ -1182,15 +1182,6 @@ unsigned FilterChooser::getDecoderIndex(DecoderSet &Decoders, return (unsigned)(P - Decoders.begin()); } -static void emitSinglePredicateMatch(raw_ostream &o, StringRef str, - const std::string &PredicateNamespace) { - if (str[0] == '!') - o << "!Bits[" << PredicateNamespace << "::" - << str.slice(1,str.size()) << "]"; - else - o << "Bits[" << PredicateNamespace << "::" << str << "]"; -} - bool FilterChooser::emitPredicateMatch(raw_ostream &o, unsigned &Indentation, unsigned Opc) const { ListInit *Predicates = @@ -1201,21 +1192,50 @@ bool FilterChooser::emitPredicateMatch(raw_ostream &o, unsigned &Indentation, if (!Pred->getValue("AssemblerMatcherPredicate")) continue; - StringRef P = Pred->getValueAsString("AssemblerCondString"); - - if (P.empty()) + if (!dyn_cast<DagInit>(Pred->getValue("AssemblerCondDag")->getValue())) continue; + const DagInit *D = Pred->getValueAsDag("AssemblerCondDag"); + std::string CombineType = D->getOperator()->getAsString(); + if (CombineType != "any_of" && CombineType != "all_of") + PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!"); + if (D->getNumArgs() == 0) + PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!"); + bool IsOr = CombineType == "any_of"; + if (!IsFirstEmission) o << " && "; - std::pair<StringRef, StringRef> pairs = P.split(','); - while (!pairs.second.empty()) { - emitSinglePredicateMatch(o, pairs.first, Emitter->PredicateNamespace); - o << " && "; - pairs = pairs.second.split(','); + if (IsOr) + o << "("; + + bool First = true; + for (auto *Arg : D->getArgs()) { + if (!First) { + if (IsOr) + o << " || "; + else + o << " && "; + } + if (auto *NotArg = dyn_cast<DagInit>(Arg)) { + if (NotArg->getOperator()->getAsString() != "not" || + NotArg->getNumArgs() != 1) + PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!"); + Arg = NotArg->getArg(0); + o << "!"; + } + if (!isa<DefInit>(Arg) || + !cast<DefInit>(Arg)->getDef()->isSubClassOf("SubtargetFeature")) + PrintFatalError(Pred->getLoc(), "Invalid AssemblerCondDag!"); + o << "Bits[" << Emitter->PredicateNamespace << "::" << Arg->getAsString() + << "]"; + + First = false; } - emitSinglePredicateMatch(o, pairs.first, Emitter->PredicateNamespace); + + if (IsOr) + o << ")"; + IsFirstEmission = false; } return !Predicates->empty(); @@ -1229,12 +1249,8 @@ bool FilterChooser::doesOpcodeNeedPredicate(unsigned Opc) const { if (!Pred->getValue("AssemblerMatcherPredicate")) continue; - StringRef P = Pred->getValueAsString("AssemblerCondString"); - - if (P.empty()) - continue; - - return true; + if (dyn_cast<DagInit>(Pred->getValue("AssemblerCondDag")->getValue())) + return true; } return false; } @@ -1772,7 +1788,7 @@ static std::string findOperandDecoderMethod(TypedInit *TI) { StringInit *String = DecoderString ? dyn_cast<StringInit>(DecoderString->getValue()) : nullptr; if (String) { - Decoder = String->getValue(); + Decoder = std::string(String->getValue()); if (!Decoder.empty()) return Decoder; } @@ -1809,7 +1825,8 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, StringRef InstDecoder = EncodingDef.getValueAsString("DecoderMethod"); if (InstDecoder != "") { bool HasCompleteInstDecoder = EncodingDef.getValueAsBit("hasCompleteDecoder"); - InsnOperands.push_back(OperandInfo(InstDecoder, HasCompleteInstDecoder)); + InsnOperands.push_back( + OperandInfo(std::string(InstDecoder), HasCompleteInstDecoder)); Operands[Opc] = InsnOperands; return true; } @@ -1839,8 +1856,10 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, if (tiedTo != -1) { std::pair<unsigned, unsigned> SO = CGI.Operands.getSubOperandNumber(tiedTo); - TiedNames[InOutOperands[i].second] = InOutOperands[SO.first].second; - TiedNames[InOutOperands[SO.first].second] = InOutOperands[i].second; + TiedNames[std::string(InOutOperands[i].second)] = + std::string(InOutOperands[SO.first].second); + TiedNames[std::string(InOutOperands[SO.first].second)] = + std::string(InOutOperands[i].second); } } @@ -1936,7 +1955,7 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, StringInit *String = DecoderString ? dyn_cast<StringInit>(DecoderString->getValue()) : nullptr; if (String && String->getValue() != "") - Decoder = String->getValue(); + Decoder = std::string(String->getValue()); if (Decoder == "" && CGI.Operands[SO.first].MIOperandInfo && @@ -1963,7 +1982,7 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, String = DecoderString ? dyn_cast<StringInit>(DecoderString->getValue()) : nullptr; if (!isReg && String && String->getValue() != "") - Decoder = String->getValue(); + Decoder = std::string(String->getValue()); RecordVal *HasCompleteDecoderVal = TypeRecord->getValue("hasCompleteDecoder"); @@ -1989,16 +2008,17 @@ 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[Op.second].empty()) { + if (!NumberedInsnOperands[std::string(Op.second)].empty()) { InsnOperands.insert(InsnOperands.end(), - NumberedInsnOperands[Op.second].begin(), - NumberedInsnOperands[Op.second].end()); + NumberedInsnOperands[std::string(Op.second)].begin(), + NumberedInsnOperands[std::string(Op.second)].end()); continue; } - if (!NumberedInsnOperands[TiedNames[Op.second]].empty()) { - if (!NumberedInsnOperandsNoTie.count(TiedNames[Op.second])) { + if (!NumberedInsnOperands[TiedNames[std::string(Op.second)]].empty()) { + if (!NumberedInsnOperandsNoTie.count(TiedNames[std::string(Op.second)])) { // Figure out to which (sub)operand we're tied. - unsigned i = CGI.Operands.getOperandNamed(TiedNames[Op.second]); + unsigned i = + CGI.Operands.getOperandNamed(TiedNames[std::string(Op.second)]); int tiedTo = CGI.Operands[i].getTiedRegister(); if (tiedTo == -1) { i = CGI.Operands.getOperandNamed(Op.second); @@ -2009,8 +2029,9 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, std::pair<unsigned, unsigned> SO = CGI.Operands.getSubOperandNumber(tiedTo); - InsnOperands.push_back(NumberedInsnOperands[TiedNames[Op.second]] - [SO.second]); + InsnOperands.push_back( + NumberedInsnOperands[TiedNames[std::string(Op.second)]] + [SO.second]); } } continue; @@ -2065,7 +2086,7 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, } if (Var->getName() != Op.second && - Var->getName() != TiedNames[Op.second]) { + Var->getName() != TiedNames[std::string(Op.second)]) { if (Base != ~0U) { OpInfo.addField(Base, Width, Offset); Base = ~0U; @@ -2460,7 +2481,7 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) { if (populateInstruction(Target, *EncodingDef, *Inst, i, Operands)) { std::string DecoderNamespace = - EncodingDef->getValueAsString("DecoderNamespace"); + std::string(EncodingDef->getValueAsString("DecoderNamespace")); if (!NumberedEncodings[i].HwModeName.empty()) DecoderNamespace += std::string("_") + NumberedEncodings[i].HwModeName.str(); diff --git a/llvm/utils/TableGen/GICombinerEmitter.cpp b/llvm/utils/TableGen/GICombinerEmitter.cpp index 34eb4edac8de..e2a670070ae7 100644 --- a/llvm/utils/TableGen/GICombinerEmitter.cpp +++ b/llvm/utils/TableGen/GICombinerEmitter.cpp @@ -636,7 +636,8 @@ void GICombinerEmitter::emitNameMatcher(raw_ostream &OS) const { std::string Code; raw_string_ostream SS(Code); SS << "return " << EnumeratedRule.getID() << ";\n"; - Cases.push_back(std::make_pair(EnumeratedRule.getName(), SS.str())); + Cases.push_back( + std::make_pair(std::string(EnumeratedRule.getName()), SS.str())); } OS << "static Optional<uint64_t> getRuleIdxForIdentifier(StringRef " @@ -742,7 +743,8 @@ void GICombinerEmitter::generateCodeForTree(raw_ostream &OS, const Record &RuleDef = Rule->getDef(); OS << Indent << "// Rule: " << RuleDef.getName() << "\n" - << Indent << "if (!isRuleDisabled(" << Rule->getID() << ")) {\n"; + << Indent << "if (!RuleConfig->isRuleDisabled(" << Rule->getID() + << ")) {\n"; CodeExpansions Expansions; for (const auto &VarBinding : Leaf.var_bindings()) { @@ -840,6 +842,13 @@ void GICombinerEmitter::generateCodeForTree(raw_ostream &OS, OS << Indent << "return false;\n"; } +static void emitAdditionalHelperMethodArguments(raw_ostream &OS, + Record *Combiner) { + for (Record *Arg : Combiner->getValueAsListOfDefs("AdditionalArguments")) + OS << ",\n " << Arg->getValueAsString("Type") + << Arg->getValueAsString("Name"); +} + void GICombinerEmitter::run(raw_ostream &OS) { gatherRules(Rules, Combiner->getValueAsListOfDefs("Rules")); if (StopAfterParse) { @@ -889,81 +898,136 @@ void GICombinerEmitter::run(raw_ostream &OS) { << "#endif // ifdef " << Name.upper() << "_GENCOMBINERHELPER_DEPS\n\n"; OS << "#ifdef " << Name.upper() << "_GENCOMBINERHELPER_H\n" - << "class " << getClassName() << " {\n" + << "class " << getClassName() << "RuleConfig {\n" << " SparseBitVector<> DisabledRules;\n" << "\n" << "public:\n" << " bool parseCommandLineOption();\n" << " bool isRuleDisabled(unsigned ID) const;\n" + << " bool setRuleEnabled(StringRef RuleIdentifier);\n" << " bool setRuleDisabled(StringRef RuleIdentifier);\n" << "\n" + << "};\n" + << "\n" + << "class " << getClassName(); + StringRef StateClass = Combiner->getValueAsString("StateClass"); + if (!StateClass.empty()) + OS << " : public " << StateClass; + OS << " {\n" + << " const " << getClassName() << "RuleConfig *RuleConfig;\n" + << "\n" + << "public:\n" + << " template<typename ... Args>" << getClassName() << "(const " + << getClassName() << "RuleConfig &RuleConfig, Args &&... args) : "; + if (!StateClass.empty()) + OS << StateClass << "(std::forward<Args>(args)...), "; + OS << "RuleConfig(&RuleConfig) {}\n" + << "\n" << " bool tryCombineAll(\n" << " GISelChangeObserver &Observer,\n" << " MachineInstr &MI,\n" - << " MachineIRBuilder &B,\n" - << " CombinerHelper &Helper) const;\n" - << "};\n\n"; + << " MachineIRBuilder &B"; + emitAdditionalHelperMethodArguments(OS, Combiner); + OS << ") const;\n"; + OS << "};\n\n"; emitNameMatcher(OS); - OS << "bool " << getClassName() - << "::setRuleDisabled(StringRef RuleIdentifier) {\n" + OS << "static Optional<std::pair<uint64_t, uint64_t>> " + "getRuleRangeForIdentifier(StringRef RuleIdentifier) {\n" << " std::pair<StringRef, StringRef> RangePair = " "RuleIdentifier.split('-');\n" << " if (!RangePair.second.empty()) {\n" - << " const auto First = getRuleIdxForIdentifier(RangePair.first);\n" - << " const auto Last = getRuleIdxForIdentifier(RangePair.second);\n" + << " const auto First = " + "getRuleIdxForIdentifier(RangePair.first);\n" + << " const auto Last = " + "getRuleIdxForIdentifier(RangePair.second);\n" << " if (!First.hasValue() || !Last.hasValue())\n" - << " return false;\n" + << " return None;\n" << " if (First >= Last)\n" - << " report_fatal_error(\"Beginning of range should be before end of " - "range\");\n" - << " for (auto I = First.getValue(); I < Last.getValue(); ++I)\n" - << " DisabledRules.set(I);\n" - << " return true;\n" + << " report_fatal_error(\"Beginning of range should be before " + "end of range\");\n" + << " return {{ *First, *Last + 1 }};\n" + << " } else if (RangePair.first == \"*\") {\n" + << " return {{ 0, " << Rules.size() << " }};\n" << " } else {\n" << " const auto I = getRuleIdxForIdentifier(RangePair.first);\n" << " if (!I.hasValue())\n" - << " return false;\n" - << " DisabledRules.set(I.getValue());\n" - << " return true;\n" + << " return None;\n" + << " return {{*I, *I + 1}};\n" << " }\n" - << " return false;\n" - << "}\n"; + << " return None;\n" + << "}\n\n"; + + for (bool Enabled : {true, false}) { + OS << "bool " << getClassName() << "RuleConfig::setRule" + << (Enabled ? "Enabled" : "Disabled") << "(StringRef RuleIdentifier) {\n" + << " auto MaybeRange = getRuleRangeForIdentifier(RuleIdentifier);\n" + << " if(!MaybeRange.hasValue())\n" + << " return false;\n" + << " for (auto I = MaybeRange->first; I < MaybeRange->second; ++I)\n" + << " DisabledRules." << (Enabled ? "reset" : "set") << "(I);\n" + << " return true;\n" + << "}\n\n"; + } OS << "bool " << getClassName() - << "::isRuleDisabled(unsigned RuleID) const {\n" + << "RuleConfig::isRuleDisabled(unsigned RuleID) const {\n" << " return DisabledRules.test(RuleID);\n" << "}\n"; OS << "#endif // ifdef " << Name.upper() << "_GENCOMBINERHELPER_H\n\n"; OS << "#ifdef " << Name.upper() << "_GENCOMBINERHELPER_CPP\n" << "\n" - << "cl::list<std::string> " << Name << "Option(\n" + << "std::vector<std::string> " << Name << "Option;\n" + << "cl::list<std::string> " << Name << "DisableOption(\n" << " \"" << Name.lower() << "-disable-rule\",\n" << " cl::desc(\"Disable one or more combiner rules temporarily in " << "the " << Name << " pass\"),\n" << " cl::CommaSeparated,\n" << " cl::Hidden,\n" - << " cl::cat(GICombinerOptionCategory));\n" + << " cl::cat(GICombinerOptionCategory),\n" + << " cl::callback([](const std::string &Str) {\n" + << " " << Name << "Option.push_back(Str);\n" + << " }));\n" + << "cl::list<std::string> " << Name << "OnlyEnableOption(\n" + << " \"" << Name.lower() << "-only-enable-rule\",\n" + << " cl::desc(\"Disable all rules in the " << Name + << " pass then re-enable the specified ones\"),\n" + << " cl::Hidden,\n" + << " cl::cat(GICombinerOptionCategory),\n" + << " cl::callback([](const std::string &CommaSeparatedArg) {\n" + << " StringRef Str = CommaSeparatedArg;\n" + << " " << Name << "Option.push_back(\"*\");\n" + << " do {\n" + << " auto X = Str.split(\",\");\n" + << " " << Name << "Option.push_back((\"!\" + X.first).str());\n" + << " Str = X.second;\n" + << " } while (!Str.empty());\n" + << " }));\n" << "\n" - << "bool " << getClassName() << "::parseCommandLineOption() {\n" - << " for (const auto &Identifier : " << Name << "Option)\n" - << " if (!setRuleDisabled(Identifier))\n" + << "bool " << getClassName() << "RuleConfig::parseCommandLineOption() {\n" + << " for (StringRef Identifier : " << Name << "Option) {\n" + << " bool Enabled = Identifier.consume_front(\"!\");\n" + << " if (Enabled && !setRuleEnabled(Identifier))\n" << " return false;\n" + << " if (!Enabled && !setRuleDisabled(Identifier))\n" + << " return false;\n" + << " }\n" << " return true;\n" << "}\n\n"; OS << "bool " << getClassName() << "::tryCombineAll(\n" << " GISelChangeObserver &Observer,\n" << " MachineInstr &MI,\n" - << " MachineIRBuilder &B,\n" - << " CombinerHelper &Helper) const {\n" + << " MachineIRBuilder &B"; + emitAdditionalHelperMethodArguments(OS, Combiner); + OS << ") const {\n" << " MachineBasicBlock *MBB = MI.getParent();\n" << " MachineFunction *MF = MBB->getParent();\n" << " MachineRegisterInfo &MRI = MF->getRegInfo();\n" << " SmallVector<MachineInstr *, 8> MIs = { &MI };\n\n" - << " (void)MBB; (void)MF; (void)MRI;\n\n"; + << " (void)MBB; (void)MF; (void)MRI; (void)RuleConfig;\n\n"; OS << " // Match data\n"; for (const auto &Rule : Rules) diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp b/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp index 4884bdadea91..96dc4fc94893 100644 --- a/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp +++ b/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp @@ -10,6 +10,7 @@ #include "../CodeGenInstruction.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" @@ -611,18 +612,23 @@ void GIMatchTreeOpcodePartitioner::emitPartitionResults( void GIMatchTreeOpcodePartitioner::generatePartitionSelectorCode( raw_ostream &OS, StringRef Indent) const { - OS << Indent << "Partition = -1;\n" - << Indent << "switch (MIs[" << InstrID << "]->getOpcode()) {\n"; - for (const auto &EnumInstr : enumerate(PartitionToInstr)) { - if (EnumInstr.value() == nullptr) - OS << Indent << "default:"; - else - OS << Indent << "case " << EnumInstr.value()->Namespace - << "::" << EnumInstr.value()->TheDef->getName() << ":"; - OS << " Partition = " << EnumInstr.index() << "; break;\n"; + // Make sure not to emit empty switch or switch with just default + if (PartitionToInstr.size() == 1 && PartitionToInstr[0] == nullptr) { + OS << Indent << "Partition = 0;\n"; + } else if (PartitionToInstr.size()) { + OS << Indent << "Partition = -1;\n" + << Indent << "switch (MIs[" << InstrID << "]->getOpcode()) {\n"; + for (const auto &EnumInstr : enumerate(PartitionToInstr)) { + if (EnumInstr.value() == nullptr) + OS << Indent << "default:"; + else + OS << Indent << "case " << EnumInstr.value()->Namespace + << "::" << EnumInstr.value()->TheDef->getName() << ":"; + OS << " Partition = " << EnumInstr.index() << "; break;\n"; + } + OS << Indent << "}\n"; } - OS << Indent << "}\n" - << Indent + OS << Indent << "// Default case but without conflicting with potential default case " "in selection.\n" << Indent << "if (Partition == -1) return false;\n"; @@ -774,4 +780,3 @@ void GIMatchTreeVRegDefPartitioner::generatePartitionSelectorCode( OS << Indent << "if (Partition == -1) return false;\n"; } - diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp index c14294951cc1..4e8dcc52fc20 100644 --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -448,7 +448,6 @@ public: : LabelID(LabelID_.hasValue() ? LabelID_.getValue() : ~0u), EmitStr(EmitStr), NumElements(NumElements), Flags(Flags), RawValue(RawValue) { - assert((!LabelID_.hasValue() || LabelID != ~0u) && "This value is reserved for non-labels"); } @@ -1044,6 +1043,28 @@ public: for (const auto &Predicate : predicates()) Predicate->emitPredicateOpcodes(Table, std::forward<Args>(args)...); } + + /// Provide a function to avoid emitting certain predicates. This is used to + /// defer some predicate checks until after others + using PredicateFilterFunc = std::function<bool(const PredicateTy&)>; + + /// Emit MatchTable opcodes for predicates which satisfy \p + /// ShouldEmitPredicate. This should be called multiple times to ensure all + /// predicates are eventually added to the match table. + template <class... Args> + void emitFilteredPredicateListOpcodes(PredicateFilterFunc ShouldEmitPredicate, + MatchTable &Table, Args &&... args) { + if (Predicates.empty() && !Optimized) { + Table << MatchTable::Comment(getNoPredicateComment()) + << MatchTable::LineBreak; + return; + } + + for (const auto &Predicate : predicates()) { + if (ShouldEmitPredicate(*Predicate)) + Predicate->emitPredicateOpcodes(Table, std::forward<Args>(args)...); + } + } }; class PredicateMatcher { @@ -1101,6 +1122,13 @@ public: PredicateKind getKind() const { return Kind; } + bool dependsOnOperands() const { + // Custom predicates really depend on the context pattern of the + // instruction, not just the individual instruction. This therefore + // implicitly depends on all other pattern constraints. + return Kind == IPM_GenericPredicate; + } + virtual bool isIdentical(const PredicateMatcher &B) const { return B.getKind() == getKind() && InsnVarID == B.InsnVarID && OpIdx == B.OpIdx; @@ -1498,7 +1526,7 @@ public: const StringRef getSymbolicName() const { return SymbolicName; } void setSymbolicName(StringRef Name) { assert(SymbolicName.empty() && "Operand already has a symbolic name"); - SymbolicName = Name; + SymbolicName = std::string(Name); } /// Construct a new operand predicate and add it to the matcher. @@ -2128,10 +2156,23 @@ public: InstructionNumOperandsMatcher(InsnVarID, getNumOperands()) .emitPredicateOpcodes(Table, Rule); - emitPredicateListOpcodes(Table, Rule); + // First emit all instruction level predicates need to be verified before we + // can verify operands. + emitFilteredPredicateListOpcodes( + [](const PredicateMatcher &P) { + return !P.dependsOnOperands(); + }, Table, Rule); + // Emit all operand constraints. for (const auto &Operand : Operands) Operand->emitPredicateOpcodes(Table, Rule); + + // All of the tablegen defined predicates should now be matched. Now emit + // any custom predicates that rely on all generated checks. + emitFilteredPredicateListOpcodes( + [](const PredicateMatcher &P) { + return P.dependsOnOperands(); + }, Table, Rule); } /// Compare the priority of this object and B. @@ -2585,26 +2626,37 @@ class TempRegRenderer : public OperandRenderer { protected: unsigned InsnID; unsigned TempRegID; + const CodeGenSubRegIndex *SubRegIdx; bool IsDef; public: - TempRegRenderer(unsigned InsnID, unsigned TempRegID, bool IsDef = false) + TempRegRenderer(unsigned InsnID, unsigned TempRegID, bool IsDef = false, + const CodeGenSubRegIndex *SubReg = nullptr) : OperandRenderer(OR_Register), InsnID(InsnID), TempRegID(TempRegID), - IsDef(IsDef) {} + SubRegIdx(SubReg), IsDef(IsDef) {} static bool classof(const OperandRenderer *R) { return R->getKind() == OR_TempRegister; } void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { - Table << MatchTable::Opcode("GIR_AddTempRegister") - << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID) + if (SubRegIdx) { + assert(!IsDef); + Table << MatchTable::Opcode("GIR_AddTempSubRegister"); + } else + Table << MatchTable::Opcode("GIR_AddTempRegister"); + + Table << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID) << MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID) << MatchTable::Comment("TempRegFlags"); + if (IsDef) Table << MatchTable::NamedValue("RegState::Define"); else Table << MatchTable::IntValue(0); + + if (SubRegIdx) + Table << MatchTable::NamedValue(SubRegIdx->getQualifiedName()); Table << MatchTable::LineBreak; } }; @@ -2779,7 +2831,7 @@ private: std::string S; public: - DebugCommentAction(StringRef S) : S(S) {} + DebugCommentAction(StringRef S) : S(std::string(S)) {} void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { Table << MatchTable::Comment(S) << MatchTable::LineBreak; @@ -2950,8 +3002,8 @@ public: Table << MatchTable::Opcode("GIR_ConstrainOperandRC") << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID) << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx) - << MatchTable::Comment("RC " + RC.getName()) - << MatchTable::IntValue(RC.EnumValue) << MatchTable::LineBreak; + << MatchTable::NamedValue(RC.getQualifiedName() + "RegClassID") + << MatchTable::LineBreak; } }; @@ -3260,6 +3312,22 @@ void SameOperandMatcher::emitPredicateOpcodes(MatchTable &Table, //===- GlobalISelEmitter class --------------------------------------------===// +static Expected<LLTCodeGen> getInstResultType(const TreePatternNode *Dst) { + ArrayRef<TypeSetByHwMode> ChildTypes = Dst->getExtTypes(); + if (ChildTypes.size() != 1) + return failedImport("Dst pattern child has multiple results"); + + Optional<LLTCodeGen> MaybeOpTy; + if (ChildTypes.front().isMachineValueType()) { + MaybeOpTy = + MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy); + } + + if (!MaybeOpTy) + return failedImport("Dst operand has an unsupported type"); + return *MaybeOpTy; +} + class GlobalISelEmitter { public: explicit GlobalISelEmitter(RecordKeeper &RK); @@ -3269,7 +3337,7 @@ private: const RecordKeeper &RK; const CodeGenDAGPatterns CGP; const CodeGenTarget &Target; - CodeGenRegBank CGRegs; + CodeGenRegBank &CGRegs; /// Keep track of the equivalence between SDNodes and Instruction by mapping /// SDNodes to the GINodeEquiv mapping. We need to map to the GINodeEquiv to @@ -3477,7 +3545,7 @@ GlobalISelEmitter::getEquivNode(Record &Equiv, const TreePatternNode *N) const { GlobalISelEmitter::GlobalISelEmitter(RecordKeeper &RK) : RK(RK), CGP(RK), Target(CGP.getTargetInfo()), - CGRegs(RK, Target.getHwModes()) {} + CGRegs(Target.getRegBank()) {} //===- Emitter ------------------------------------------------------------===// @@ -3737,7 +3805,7 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher( CCDef->getValueAsString("ICmpPredicate"); if (!PredType.empty()) { - OM.addPredicate<CmpPredicateOperandMatcher>(PredType); + OM.addPredicate<CmpPredicateOperandMatcher>(std::string(PredType)); // Process the other 2 operands normally. --NumChildren; } @@ -3836,9 +3904,10 @@ Error GlobalISelEmitter::importChildMatcher( Record *PhysReg = nullptr; StringRef SrcChildName = getSrcChildName(SrcChild, PhysReg); - OperandMatcher &OM = PhysReg ? - InsnMatcher.addPhysRegInput(PhysReg, OpIdx, TempOpIdx) : - InsnMatcher.addOperand(OpIdx, SrcChildName, TempOpIdx); + OperandMatcher &OM = + PhysReg + ? InsnMatcher.addPhysRegInput(PhysReg, OpIdx, TempOpIdx) + : InsnMatcher.addOperand(OpIdx, std::string(SrcChildName), TempOpIdx); if (OM.isSameAsAnotherOperand()) return Error::success(); @@ -3971,6 +4040,10 @@ Error GlobalISelEmitter::importChildMatcher( "Src pattern child def is an unsupported tablegen class (ImmLeaf)"); } + // Place holder for SRCVALUE nodes. Nothing to do here. + if (ChildRec->getName() == "srcvalue") + return Error::success(); + return failedImport( "Src pattern child def is an unsupported tablegen class"); } @@ -4040,20 +4113,13 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer( } if (DstChild->getOperator()->isSubClassOf("Instruction")) { - ArrayRef<TypeSetByHwMode> ChildTypes = DstChild->getExtTypes(); - if (ChildTypes.size() != 1) - return failedImport("Dst pattern child has multiple results"); - - Optional<LLTCodeGen> OpTyOrNone = None; - if (ChildTypes.front().isMachineValueType()) - OpTyOrNone = - MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy); - if (!OpTyOrNone) - return failedImport("Dst operand has an unsupported type"); + auto OpTy = getInstResultType(DstChild); + if (!OpTy) + return OpTy.takeError(); unsigned TempRegID = Rule.allocateTempRegID(); InsertPt = Rule.insertAction<MakeTempRegisterAction>( - InsertPt, OpTyOrNone.getValue(), TempRegID); + InsertPt, *OpTy, TempRegID); DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID); auto InsertPtOrError = createAndImportSubInstructionRenderer( @@ -4225,7 +4291,7 @@ GlobalISelEmitter::createAndImportSubInstructionRenderer( if (!SubIdx) return failedImport("EXTRACT_SUBREG child #1 is not a subreg index"); - const auto &SrcRCDstRCPair = + const auto SrcRCDstRCPair = (*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx); assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass"); M.insertAction<ConstrainOperandToRegClassAction>( @@ -4257,6 +4323,29 @@ GlobalISelEmitter::createAndImportSubInstructionRenderer( return InsertPtOrError.get(); } + if (OpName == "REG_SEQUENCE") { + auto SuperClass = inferRegClassFromPattern(Dst->getChild(0)); + M.insertAction<ConstrainOperandToRegClassAction>( + InsertPt, DstMIBuilder.getInsnID(), 0, **SuperClass); + + unsigned Num = Dst->getNumChildren(); + for (unsigned I = 1; I != Num; I += 2) { + TreePatternNode *SubRegChild = Dst->getChild(I + 1); + + auto SubIdx = inferSubRegIndexForNode(SubRegChild); + if (!SubIdx) + return failedImport("REG_SEQUENCE child is not a subreg index"); + + const auto SrcRCDstRCPair = + (*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx); + assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass"); + M.insertAction<ConstrainOperandToRegClassAction>( + InsertPt, DstMIBuilder.getInsnID(), I, *SrcRCDstRCPair->second); + } + + return InsertPtOrError.get(); + } + M.insertAction<ConstrainOperandsToDefinitionAction>(InsertPt, DstMIBuilder.getInsnID()); return InsertPtOrError.get(); @@ -4303,33 +4392,51 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers( // EXTRACT_SUBREG needs to use a subregister COPY. if (Name == "EXTRACT_SUBREG") { - if (!Dst->getChild(0)->isLeaf()) - return failedImport("EXTRACT_SUBREG child #1 is not a leaf"); - - if (DefInit *SubRegInit = - dyn_cast<DefInit>(Dst->getChild(1)->getLeafValue())) { - Record *RCDef = getInitValueAsRegClass(Dst->getChild(0)->getLeafValue()); - if (!RCDef) - return failedImport("EXTRACT_SUBREG child #0 could not " - "be coerced to a register class"); - - CodeGenRegisterClass *RC = CGRegs.getRegClass(RCDef); - CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef()); - - const auto &SrcRCDstRCPair = - RC->getMatchingSubClassWithSubRegs(CGRegs, SubIdx); - if (SrcRCDstRCPair.hasValue()) { - assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass"); - if (SrcRCDstRCPair->first != RC) - return failedImport("EXTRACT_SUBREG requires an additional COPY"); - } + DefInit *SubRegInit = dyn_cast<DefInit>(Dst->getChild(1)->getLeafValue()); + if (!SubRegInit) + return failedImport("EXTRACT_SUBREG child #1 is not a subreg index"); + + CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef()); + TreePatternNode *ValChild = Dst->getChild(0); + if (!ValChild->isLeaf()) { + // We really have to handle the source instruction, and then insert a + // copy from the subregister. + auto ExtractSrcTy = getInstResultType(ValChild); + if (!ExtractSrcTy) + return ExtractSrcTy.takeError(); + + unsigned TempRegID = M.allocateTempRegID(); + InsertPt = M.insertAction<MakeTempRegisterAction>( + InsertPt, *ExtractSrcTy, TempRegID); - DstMIBuilder.addRenderer<CopySubRegRenderer>(Dst->getChild(0)->getName(), - SubIdx); + auto InsertPtOrError = createAndImportSubInstructionRenderer( + ++InsertPt, M, ValChild, TempRegID); + if (auto Error = InsertPtOrError.takeError()) + return std::move(Error); + + DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID, false, SubIdx); return InsertPt; } - return failedImport("EXTRACT_SUBREG child #1 is not a subreg index"); + // If this is a source operand, this is just a subregister copy. + Record *RCDef = getInitValueAsRegClass(ValChild->getLeafValue()); + if (!RCDef) + return failedImport("EXTRACT_SUBREG child #0 could not " + "be coerced to a register class"); + + CodeGenRegisterClass *RC = CGRegs.getRegClass(RCDef); + + const auto SrcRCDstRCPair = + RC->getMatchingSubClassWithSubRegs(CGRegs, SubIdx); + if (SrcRCDstRCPair.hasValue()) { + assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass"); + if (SrcRCDstRCPair->first != RC) + return failedImport("EXTRACT_SUBREG requires an additional COPY"); + } + + DstMIBuilder.addRenderer<CopySubRegRenderer>(Dst->getChild(0)->getName(), + SubIdx); + return InsertPt; } if (Name == "REG_SEQUENCE") { @@ -4731,15 +4838,13 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { if (DstIOpRec == nullptr) return failedImport("REG_SEQUENCE operand #0 isn't a register class"); } else if (DstIName == "EXTRACT_SUBREG") { - if (!Dst->getChild(0)->isLeaf()) - return failedImport("EXTRACT_SUBREG operand #0 isn't a leaf"); + auto InferredClass = inferRegClassFromPattern(Dst->getChild(0)); + if (!InferredClass) + return failedImport("Could not infer class for EXTRACT_SUBREG operand #0"); // We can assume that a subregister is in the same bank as it's super // register. - DstIOpRec = getInitValueAsRegClass(Dst->getChild(0)->getLeafValue()); - - if (DstIOpRec == nullptr) - return failedImport("EXTRACT_SUBREG operand #0 isn't a register class"); + DstIOpRec = (*InferredClass)->getDef(); } else if (DstIName == "INSERT_SUBREG") { auto MaybeSuperClass = inferSuperRegisterClassForNode( VTy, Dst->getChild(0), Dst->getChild(2)); @@ -4832,8 +4937,13 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { assert(Src->getExtTypes().size() == 1 && "Expected Src of EXTRACT_SUBREG to have one result type"); - const auto &SrcRCDstRCPair = + const auto SrcRCDstRCPair = (*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx); + if (!SrcRCDstRCPair) { + return failedImport("subreg index is incompatible " + "with inferred reg class"); + } + assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass"); M.addAction<ConstrainOperandToRegClassAction>(0, 0, *SrcRCDstRCPair->second); M.addAction<ConstrainOperandToRegClassAction>(0, 1, *SrcRCDstRCPair->first); @@ -4889,6 +4999,30 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { return std::move(M); } + if (DstIName == "REG_SEQUENCE") { + auto SuperClass = inferRegClassFromPattern(Dst->getChild(0)); + + M.addAction<ConstrainOperandToRegClassAction>(0, 0, **SuperClass); + + unsigned Num = Dst->getNumChildren(); + for (unsigned I = 1; I != Num; I += 2) { + TreePatternNode *SubRegChild = Dst->getChild(I + 1); + + auto SubIdx = inferSubRegIndexForNode(SubRegChild); + if (!SubIdx) + return failedImport("REG_SEQUENCE child is not a subreg index"); + + const auto SrcRCDstRCPair = + (*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx); + + M.addAction<ConstrainOperandToRegClassAction>(0, I, + *SrcRCDstRCPair->second); + } + + ++NumPatternImported; + return std::move(M); + } + M.addAction<ConstrainOperandsToDefinitionAction>(0); // We're done with this pattern! It's eligible for GISel emission; return it. diff --git a/llvm/utils/TableGen/InstrDocsEmitter.cpp b/llvm/utils/TableGen/InstrDocsEmitter.cpp index 07efa1885409..66744bf9ecef 100644 --- a/llvm/utils/TableGen/InstrDocsEmitter.cpp +++ b/llvm/utils/TableGen/InstrDocsEmitter.cpp @@ -61,7 +61,7 @@ void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) { unsigned VariantCount = Target.getAsmParserVariantCount(); // Page title. - std::string Title = Target.getName(); + std::string Title = std::string(Target.getName()); Title += " Instructions"; writeTitle(Title, OS); OS << "\n"; diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp index 6ab58bd26a2c..f3141735a995 100644 --- a/llvm/utils/TableGen/InstrInfoEmitter.cpp +++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -524,7 +524,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "namespace llvm {\n\n"; CodeGenTarget &Target = CDP.getTargetInfo(); - const std::string &TargetName = Target.getName(); + const std::string &TargetName = std::string(Target.getName()); Record *InstrInfo = Target.getInstructionSet(); // Keep track of all of the def lists we have emitted already. @@ -561,7 +561,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) { unsigned Num = 0; for (const CodeGenInstruction *Inst : NumberedInstructions) { // Keep a list of the instruction names. - InstrNames.add(Inst->TheDef->getName()); + InstrNames.add(std::string(Inst->TheDef->getName())); // Emit the record into the table. emitRecord(*Inst, Num++, InstrInfo, EmittedLists, OperandInfoIDs, OS); } @@ -569,9 +569,8 @@ void InstrInfoEmitter::run(raw_ostream &OS) { // Emit the array of instruction names. InstrNames.layout(); - OS << "extern const char " << TargetName << "InstrNameData[] = {\n"; - InstrNames.emit(OS, printChar); - OS << "};\n\n"; + InstrNames.emitStringLiteralDef(OS, Twine("extern const char ") + TargetName + + "InstrNameData[]"); OS << "extern const unsigned " << TargetName <<"InstrNameIndices[] = {"; Num = 0; @@ -579,18 +578,69 @@ void InstrInfoEmitter::run(raw_ostream &OS) { // Newline every eight entries. if (Num % 8 == 0) OS << "\n "; - OS << InstrNames.get(Inst->TheDef->getName()) << "U, "; + OS << InstrNames.get(std::string(Inst->TheDef->getName())) << "U, "; ++Num; } - OS << "\n};\n\n"; + bool HasDeprecationFeatures = + llvm::any_of(NumberedInstructions, [](const CodeGenInstruction *Inst) { + return !Inst->HasComplexDeprecationPredicate && + !Inst->DeprecatedReason.empty(); + }); + if (HasDeprecationFeatures) { + OS << "extern const uint8_t " << TargetName + << "InstrDeprecationFeatures[] = {"; + Num = 0; + for (const CodeGenInstruction *Inst : NumberedInstructions) { + if (Num % 8 == 0) + OS << "\n "; + if (!Inst->HasComplexDeprecationPredicate && + !Inst->DeprecatedReason.empty()) + OS << Target.getInstNamespace() << "::" << Inst->DeprecatedReason + << ", "; + else + OS << "uint8_t(-1), "; + ++Num; + } + OS << "\n};\n\n"; + } + + bool HasComplexDeprecationInfos = + llvm::any_of(NumberedInstructions, [](const CodeGenInstruction *Inst) { + return Inst->HasComplexDeprecationPredicate; + }); + if (HasComplexDeprecationInfos) { + OS << "extern const MCInstrInfo::ComplexDeprecationPredicate " << TargetName + << "InstrComplexDeprecationInfos[] = {"; + Num = 0; + for (const CodeGenInstruction *Inst : NumberedInstructions) { + if (Num % 8 == 0) + OS << "\n "; + if (Inst->HasComplexDeprecationPredicate) + // Emit a function pointer to the complex predicate method. + OS << "&get" << Inst->DeprecatedReason << "DeprecationInfo, "; + else + OS << "nullptr, "; + ++Num; + } + OS << "\n};\n\n"; + } + // MCInstrInfo initialization routine. OS << "static inline void Init" << TargetName << "MCInstrInfo(MCInstrInfo *II) {\n"; - OS << " II->InitMCInstrInfo(" << TargetName << "Insts, " - << TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, " - << NumberedInstructions.size() << ");\n}\n\n"; + OS << " II->InitMCInstrInfo(" << TargetName << "Insts, " << TargetName + << "InstrNameIndices, " << TargetName << "InstrNameData, "; + if (HasDeprecationFeatures) + OS << TargetName << "InstrDeprecationFeatures, "; + else + OS << "nullptr, "; + if (HasComplexDeprecationInfos) + OS << TargetName << "InstrComplexDeprecationInfos, "; + else + OS << "nullptr, "; + OS << NumberedInstructions.size() << ");\n}\n\n"; OS << "} // end namespace llvm\n"; @@ -630,12 +680,28 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "extern const MCInstrDesc " << TargetName << "Insts[];\n"; OS << "extern const unsigned " << TargetName << "InstrNameIndices[];\n"; OS << "extern const char " << TargetName << "InstrNameData[];\n"; + if (HasDeprecationFeatures) + OS << "extern const uint8_t " << TargetName + << "InstrDeprecationFeatures[];\n"; + if (HasComplexDeprecationInfos) + OS << "extern const MCInstrInfo::ComplexDeprecationPredicate " << TargetName + << "InstrComplexDeprecationInfos[];\n"; OS << ClassName << "::" << ClassName - << "(int CFSetupOpcode, int CFDestroyOpcode, int CatchRetOpcode, int ReturnOpcode)\n" - << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode, ReturnOpcode) {\n" + << "(int CFSetupOpcode, int CFDestroyOpcode, int CatchRetOpcode, int " + "ReturnOpcode)\n" + << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode, " + "ReturnOpcode) {\n" << " InitMCInstrInfo(" << TargetName << "Insts, " << TargetName - << "InstrNameIndices, " << TargetName << "InstrNameData, " - << NumberedInstructions.size() << ");\n}\n"; + << "InstrNameIndices, " << TargetName << "InstrNameData, "; + if (HasDeprecationFeatures) + OS << TargetName << "InstrDeprecationFeatures, "; + else + OS << "nullptr, "; + if (HasComplexDeprecationInfos) + OS << TargetName << "InstrComplexDeprecationInfos, "; + else + OS << "nullptr, "; + OS << NumberedInstructions.size() << ");\n}\n"; OS << "} // end namespace llvm\n"; OS << "#endif // GET_INSTRINFO_CTOR_DTOR\n\n"; @@ -746,18 +812,6 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, else OS << "OperandInfo" << OpInfo.find(OperandInfo)->second; - if (Inst.HasComplexDeprecationPredicate) - // Emit a function pointer to the complex predicate method. - OS << ", -1 " - << ",&get" << Inst.DeprecatedReason << "DeprecationInfo"; - else if (!Inst.DeprecatedReason.empty()) - // Emit the Subtarget feature. - OS << ", " << Target.getInstNamespace() << "::" << Inst.DeprecatedReason - << " ,nullptr"; - else - // Instruction isn't deprecated. - OS << ", -1 ,nullptr"; - OS << " }, // Inst #" << Num << " = " << Inst.TheDef->getName() << "\n"; } @@ -768,7 +822,7 @@ void InstrInfoEmitter::emitEnums(raw_ostream &OS) { OS << "namespace llvm {\n\n"; - CodeGenTarget Target(Records); + const CodeGenTarget &Target = CDP.getTargetInfo(); // We must emit the PHI opcode first... StringRef Namespace = Target.getInstNamespace(); diff --git a/llvm/utils/TableGen/IntrinsicEmitter.cpp b/llvm/utils/TableGen/IntrinsicEmitter.cpp index 9a12571ac6bc..7e4191494149 100644 --- a/llvm/utils/TableGen/IntrinsicEmitter.cpp +++ b/llvm/utils/TableGen/IntrinsicEmitter.cpp @@ -244,7 +244,9 @@ enum IIT_Info { IIT_SCALABLE_VEC = 43, IIT_SUBDIVIDE2_ARG = 44, IIT_SUBDIVIDE4_ARG = 45, - IIT_VEC_OF_BITCASTS_TO_INT = 46 + IIT_VEC_OF_BITCASTS_TO_INT = 46, + IIT_V128 = 47, + IIT_BF16 = 48 }; static void EncodeFixedValueType(MVT::SimpleValueType VT, @@ -265,6 +267,7 @@ static void EncodeFixedValueType(MVT::SimpleValueType VT, switch (VT) { default: PrintFatalError("unhandled MVT in intrinsic!"); case MVT::f16: return Sig.push_back(IIT_F16); + case MVT::bf16: return Sig.push_back(IIT_BF16); case MVT::f32: return Sig.push_back(IIT_F32); case MVT::f64: return Sig.push_back(IIT_F64); case MVT::f128: return Sig.push_back(IIT_F128); @@ -380,6 +383,7 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes, case 16: Sig.push_back(IIT_V16); break; 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 512: Sig.push_back(IIT_V512); break; case 1024: Sig.push_back(IIT_V1024); break; } @@ -577,6 +581,12 @@ struct AttributeComparator { if (L->isNoReturn != R->isNoReturn) return R->isNoReturn; + if (L->isNoSync != R->isNoSync) + return R->isNoSync; + + if (L->isNoFree != R->isNoFree) + return R->isNoFree; + if (L->isWillReturn != R->isWillReturn) return R->isWillReturn; @@ -656,14 +666,15 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints, unsigned ai = 0, ae = intrinsic.ArgumentAttributes.size(); if (ae) { while (ai != ae) { - unsigned argNo = intrinsic.ArgumentAttributes[ai].first; - unsigned attrIdx = argNo + 1; // Must match AttributeList::FirstArgIndex + unsigned attrIdx = intrinsic.ArgumentAttributes[ai].Index; OS << " const Attribute::AttrKind AttrParam" << attrIdx << "[]= {"; bool addComma = false; + bool AllValuesAreZero = true; + SmallVector<uint64_t, 8> Values; do { - switch (intrinsic.ArgumentAttributes[ai].second) { + switch (intrinsic.ArgumentAttributes[ai].Kind) { case CodeGenIntrinsic::NoCapture: if (addComma) OS << ","; @@ -706,21 +717,48 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints, OS << "Attribute::ImmArg"; addComma = true; break; + case CodeGenIntrinsic::Alignment: + if (addComma) + OS << ','; + OS << "Attribute::Alignment"; + addComma = true; + break; } + uint64_t V = intrinsic.ArgumentAttributes[ai].Value; + Values.push_back(V); + AllValuesAreZero &= (V == 0); ++ai; - } while (ai != ae && intrinsic.ArgumentAttributes[ai].first == argNo); + } while (ai != ae && intrinsic.ArgumentAttributes[ai].Index == attrIdx); OS << "};\n"; + + // Generate attribute value array if not all attribute values are zero. + if (!AllValuesAreZero) { + OS << " const uint64_t AttrValParam" << attrIdx << "[]= {"; + addComma = false; + for (const auto V : Values) { + if (addComma) + OS << ','; + OS << V; + addComma = true; + } + OS << "};\n"; + } + OS << " AS[" << numAttrs++ << "] = AttributeList::get(C, " - << attrIdx << ", AttrParam" << attrIdx << ");\n"; + << attrIdx << ", AttrParam" << attrIdx; + if (!AllValuesAreZero) + OS << ", AttrValParam" << attrIdx; + OS << ");\n"; } } if (!intrinsic.canThrow || - (intrinsic.ModRef != CodeGenIntrinsic::ReadWriteMem && !intrinsic.hasSideEffects) || - intrinsic.isNoReturn || intrinsic.isWillReturn || intrinsic.isCold || - intrinsic.isNoDuplicate || intrinsic.isConvergent || - intrinsic.isSpeculatable) { + (intrinsic.ModRef != CodeGenIntrinsic::ReadWriteMem && + !intrinsic.hasSideEffects) || + intrinsic.isNoReturn || intrinsic.isNoSync || intrinsic.isNoFree || + intrinsic.isWillReturn || intrinsic.isCold || intrinsic.isNoDuplicate || + intrinsic.isConvergent || intrinsic.isSpeculatable) { OS << " const Attribute::AttrKind Atts[] = {"; bool addComma = false; if (!intrinsic.canThrow) { @@ -733,6 +771,18 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints, OS << "Attribute::NoReturn"; addComma = true; } + if (intrinsic.isNoSync) { + if (addComma) + OS << ","; + OS << "Attribute::NoSync"; + addComma = true; + } + if (intrinsic.isNoFree) { + if (addComma) + OS << ","; + OS << "Attribute::NoFree"; + addComma = true; + } if (intrinsic.isWillReturn) { if (addComma) OS << ","; diff --git a/llvm/utils/TableGen/OptParserEmitter.cpp b/llvm/utils/TableGen/OptParserEmitter.cpp index c1978ac7ac66..251533a8d154 100644 --- a/llvm/utils/TableGen/OptParserEmitter.cpp +++ b/llvm/utils/TableGen/OptParserEmitter.cpp @@ -10,20 +10,22 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" #include <cctype> #include <cstring> #include <map> +#include <memory> using namespace llvm; static const std::string getOptionName(const Record &R) { // Use the record name unless EnumName is defined. if (isa<UnsetInit>(R.getValueInit("EnumName"))) - return R.getName(); + return std::string(R.getName()); - return R.getValueAsString("EnumName"); + return std::string(R.getValueAsString("EnumName")); } static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) { @@ -33,6 +35,210 @@ static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) { return OS; } +static const 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) { + size_t PrefixLength; + return getOptionSpelling(R, PrefixLength); +} + +static void emitNameUsingSpelling(raw_ostream &OS, const Record &R) { + size_t PrefixLength; + OS << "&"; + write_cstring(OS, StringRef(getOptionSpelling(R, PrefixLength))); + OS << "[" << PrefixLength << "]"; +} + +class MarshallingKindInfo { +public: + const Record &R; + const char *MacroName; + bool ShouldAlwaysEmit; + 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 Normalizer; + StringRef Denormalizer; + int TableIndex = -1; + std::vector<StringRef> Values; + std::vector<StringRef> NormalizedValues; + std::string ValueTableName; + + static constexpr const char *ValueTablePreamble = R"( +struct SimpleEnumValue { + const char *Name; + unsigned Value; +}; + +struct SimpleEnumValueTable { + const SimpleEnumValue *Table; + unsigned Size; +}; +)"; + + static constexpr const char *ValueTablesDecl = + "static const SimpleEnumValueTable SimpleEnumValueTables[] = "; + + void emitSpecific(raw_ostream &OS) const override { + emitScopedNormalizedValue(OS, NormalizerRetTy); + OS << ", "; + OS << Normalizer; + OS << ", "; + OS << Denormalizer; + OS << ", "; + OS << TableIndex; + } + + Optional<StringRef> emitValueTable(raw_ostream &OS) const override { + if (TableIndex == -1) + return {}; + OS << "static const SimpleEnumValue " << ValueTableName << "[] = {\n"; + for (unsigned I = 0, E = Values.size(); I != E; ++I) { + OS << "{"; + write_cstring(OS, Values[I]); + OS << ","; + OS << "static_cast<unsigned>("; + emitScopedNormalizedValue(OS, NormalizedValues[I]); + OS << ")},"; + } + OS << "};\n"; + 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; +}; + +size_t MarshallingStringInfo::NextTableIndex = 0; + +std::unique_ptr<MarshallingKindInfo> +MarshallingKindInfo::create(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"); + return Ret; +} + /// OptParserEmitter - This tablegen backend takes an input .td file /// describing a list of options and emits a data structure for parsing and /// working with those options when given an input command line. @@ -102,7 +308,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { OS << ", \"" << R.getValueAsString("Name") << '"'; // The option identifier name. - OS << ", "<< getOptionName(R); + OS << ", " << getOptionName(R); // The option kind. OS << ", Group"; @@ -135,21 +341,17 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { OS << "//////////\n"; OS << "// Options\n\n"; - for (unsigned i = 0, e = Opts.size(); i != e; ++i) { - const Record &R = *Opts[i]; - - // Start a single option entry. - OS << "OPTION("; + 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())] << ", "; // The option string. - write_cstring(OS, R.getValueAsString("Name")); + emitNameUsingSpelling(OS, R); // The option identifier name. - OS << ", "<< getOptionName(R); + OS << ", " << getOptionName(R); // The option kind. OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name"); @@ -190,8 +392,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { int NumFlags = 0; const ListInit *LI = R.getValueAsListInit("Flags"); for (Init *I : *LI) - OS << (NumFlags++ ? " | " : "") - << cast<DefInit>(I)->getDef()->getName(); + OS << (NumFlags++ ? " | " : "") << cast<DefInit>(I)->getDef()->getName(); if (GroupFlags) { for (Init *I : *GroupFlags) OS << (NumFlags++ ? " | " : "") @@ -224,11 +425,52 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { write_cstring(OS, R.getValueAsString("Values")); else OS << "nullptr"; + }; + + std::vector<std::unique_ptr<MarshallingKindInfo>> OptsWithMarshalling; + for (unsigned I = 0, E = Opts.size(); I != E; ++I) { + const Record &R = *Opts[I]; + // Start a single option entry. + OS << "OPTION("; + WriteOptRecordFields(OS, R); OS << ")\n"; + if (!isa<UnsetInit>(R.getValueInit("MarshallingKind"))) + OptsWithMarshalling.push_back(MarshallingKindInfo::create(R)); } OS << "#endif // OPTION\n"; + for (const auto &KindInfo : OptsWithMarshalling) { + OS << "#ifdef " << KindInfo->MacroName << "\n"; + OS << KindInfo->MacroName << "("; + WriteOptRecordFields(OS, KindInfo->R); + OS << ", "; + KindInfo->emit(OS); + OS << ")\n"; + OS << "#endif // " << KindInfo->MacroName << "\n"; + } + + OS << "\n"; + OS << "#ifdef SIMPLE_ENUM_VALUE_TABLE"; + OS << "\n"; + OS << MarshallingStringInfo::ValueTablePreamble; + std::vector<StringRef> ValueTableNames; + for (const auto &KindInfo : OptsWithMarshalling) + if (auto MaybeValueTableName = KindInfo->emitValueTable(OS)) + ValueTableNames.push_back(*MaybeValueTableName); + + OS << MarshallingStringInfo::ValueTablesDecl << "{"; + for (auto ValueTableName : ValueTableNames) + OS << "{" << ValueTableName << ", sizeof(" << ValueTableName + << ") / sizeof(SimpleEnumValue)" + << "},\n"; + OS << "};\n"; + OS << "static const unsigned SimpleEnumValueTablesSize = " + "sizeof(SimpleEnumValueTables) / sizeof(SimpleEnumValueTable);\n"; + + OS << "#endif // SIMPLE_ENUM_VALUE_TABLE\n"; + OS << "\n"; + OS << "\n"; OS << "#ifdef OPTTABLE_ARG_INIT\n"; OS << "//////////\n"; @@ -241,8 +483,9 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { OS << "bool ValuesWereAdded;\n"; OS << R.getValueAsString("ValuesCode"); OS << "\n"; - for (std::string S : R.getValueAsListOfStrings("Prefixes")) { + for (StringRef Prefix : R.getValueAsListOfStrings("Prefixes")) { OS << "ValuesWereAdded = Opt.addValues("; + std::string S(Prefix); S += R.getValueAsString("Name"); write_cstring(OS, S); OS << ", Values);\n"; diff --git a/llvm/utils/TableGen/OptRSTEmitter.cpp b/llvm/utils/TableGen/OptRSTEmitter.cpp index 3102f378bc1e..5e44d033109a 100644 --- a/llvm/utils/TableGen/OptRSTEmitter.cpp +++ b/llvm/utils/TableGen/OptRSTEmitter.cpp @@ -9,6 +9,7 @@ #include "OptEmitter.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" diff --git a/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp b/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp index 96e4f95937b2..f298e639bf7f 100644 --- a/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp +++ b/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp @@ -85,7 +85,7 @@ class RISCVCompressInstEmitter { MapKind Kind; union { unsigned Operand; // Operand number mapped to. - uint64_t Imm; // Integer immediate value. + int64_t Imm; // Integer immediate value. Record *Reg; // Physical register. } Data; int TiedOpIdx = -1; // Tied operand index within the instruction. @@ -141,7 +141,7 @@ 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"); - CodeGenRegisterClass RC = Target.getRegisterClass(RegClass); + 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()); @@ -160,8 +160,8 @@ bool RISCVCompressInstEmitter::validateTypes(Record *DagOpType, if (DagOpType->isSubClassOf("RegisterClass") && InstOpType->isSubClassOf("RegisterClass")) { - CodeGenRegisterClass RC = Target.getRegisterClass(InstOpType); - CodeGenRegisterClass SubRC = Target.getRegisterClass(DagOpType); + const CodeGenRegisterClass &RC = Target.getRegisterClass(InstOpType); + const CodeGenRegisterClass &SubRC = Target.getRegisterClass(DagOpType); return RC.hasSubClass(&SubRC); } @@ -474,19 +474,40 @@ void RISCVCompressInstEmitter::evaluateCompressPat(Record *Rec) { SourceOperandMap, DestOperandMap)); } -static void getReqFeatures(std::set<StringRef> &FeaturesSet, - const std::vector<Record *> &ReqFeatures) { +static void +getReqFeatures(std::set<std::pair<bool, StringRef>> &FeaturesSet, + std::set<std::set<std::pair<bool, StringRef>>> &AnyOfFeatureSets, + const std::vector<Record *> &ReqFeatures) { for (auto &R : ReqFeatures) { - StringRef AsmCondString = R->getValueAsString("AssemblerCondString"); - - // AsmCondString has syntax [!]F(,[!]F)* - SmallVector<StringRef, 4> Ops; - SplitString(AsmCondString, Ops, ","); - assert(!Ops.empty() && "AssemblerCondString cannot be empty"); - for (auto &Op : Ops) { - assert(!Op.empty() && "Empty operator"); - FeaturesSet.insert(Op); + const DagInit *D = R->getValueAsDag("AssemblerCondDag"); + std::string CombineType = D->getOperator()->getAsString(); + if (CombineType != "any_of" && CombineType != "all_of") + PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); + if (D->getNumArgs() == 0) + PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); + bool IsOr = CombineType == "any_of"; + std::set<std::pair<bool, StringRef>> AnyOfSet; + + for (auto *Arg : D->getArgs()) { + bool IsNot = false; + if (auto *NotArg = dyn_cast<DagInit>(Arg)) { + if (NotArg->getOperator()->getAsString() != "not" || + NotArg->getNumArgs() != 1) + PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); + Arg = NotArg->getArg(0); + IsNot = true; + } + if (!isa<DefInit>(Arg) || + !cast<DefInit>(Arg)->getDef()->isSubClassOf("SubtargetFeature")) + PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); + if (IsOr) + AnyOfSet.insert({IsNot, cast<DefInit>(Arg)->getDef()->getName()}); + else + FeaturesSet.insert({IsNot, cast<DefInit>(Arg)->getDef()->getName()}); } + + if (IsOr) + AnyOfFeatureSets.insert(AnyOfSet); } } @@ -547,7 +568,7 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, "'PassSubtarget' is false. SubTargetInfo object is needed " "for target features.\n"); - std::string Namespace = Target.getName(); + std::string Namespace = std::string(Target.getName()); // Sort entries in CompressPatterns to handle instructions that can have more // than one candidate for compression\uncompression, e.g ADD can be @@ -651,9 +672,10 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, CaseStream.indent(4) << "case " + Namespace + "::" + CurOp + ": {\n"; } - std::set<StringRef> FeaturesSet; + std::set<std::pair<bool, StringRef>> FeaturesSet; + std::set<std::set<std::pair<bool, StringRef>>> AnyOfFeatureSets; // Add CompressPat required features. - getReqFeatures(FeaturesSet, CompressPat.PatReqFeatures); + getReqFeatures(FeaturesSet, AnyOfFeatureSets, CompressPat.PatReqFeatures); // Add Dest instruction required features. std::vector<Record *> ReqFeatures; @@ -661,19 +683,28 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, copy_if(RF, std::back_inserter(ReqFeatures), [](Record *R) { return R->getValueAsBit("AssemblerMatcherPredicate"); }); - getReqFeatures(FeaturesSet, ReqFeatures); + getReqFeatures(FeaturesSet, AnyOfFeatureSets, ReqFeatures); // Emit checks for all required features. for (auto &Op : FeaturesSet) { - if (Op[0] == '!') - CondStream.indent(6) << ("!STI.getFeatureBits()[" + Namespace + - "::" + Op.substr(1) + "]") - .str() + - " &&\n"; - else - CondStream.indent(6) - << ("STI.getFeatureBits()[" + Namespace + "::" + Op + "]").str() + - " &&\n"; + StringRef Not = Op.first ? "!" : ""; + CondStream.indent(6) + << Not << ("STI.getFeatureBits()[" + Namespace + "::" + Op.second + "]").str() + + " &&\n"; + } + + // Emit checks for all required feature groups. + for (auto &Set : AnyOfFeatureSets) { + CondStream.indent(6) << "("; + for (auto &Op : Set) { + bool isLast = &Op == &*Set.rbegin(); + StringRef Not = Op.first ? "!" : ""; + CondStream << Not << ("STI.getFeatureBits()[" + Namespace + "::" + Op.second + + "]").str(); + if (!isLast) + CondStream << " || "; + } + CondStream << ") &&\n"; } // Start Source Inst operands validation. diff --git a/llvm/utils/TableGen/RegisterBankEmitter.cpp b/llvm/utils/TableGen/RegisterBankEmitter.cpp index 7f6b3931d3de..586f857b1fb0 100644 --- a/llvm/utils/TableGen/RegisterBankEmitter.cpp +++ b/llvm/utils/TableGen/RegisterBankEmitter.cpp @@ -19,6 +19,7 @@ #include "CodeGenHwModes.h" #include "CodeGenRegisters.h" +#include "CodeGenTarget.h" #define DEBUG_TYPE "register-bank-emitter" @@ -60,10 +61,10 @@ public: /// Get the register classes listed in the RegisterBank.RegisterClasses field. std::vector<const CodeGenRegisterClass *> - getExplictlySpecifiedRegisterClasses( - CodeGenRegBank &RegisterClassHierarchy) const { + getExplicitlySpecifiedRegisterClasses( + const CodeGenRegBank &RegisterClassHierarchy) const { std::vector<const CodeGenRegisterClass *> RCs; - for (const auto &RCDef : getDef().getValueAsListOfDefs("RegisterClasses")) + for (const auto *RCDef : getDef().getValueAsListOfDefs("RegisterClasses")) RCs.push_back(RegisterClassHierarchy.getRegClass(RCDef)); return RCs; } @@ -104,8 +105,8 @@ public: class RegisterBankEmitter { private: + CodeGenTarget Target; RecordKeeper &Records; - CodeGenRegBank RegisterClassHierarchy; void emitHeader(raw_ostream &OS, const StringRef TargetName, const std::vector<RegisterBank> &Banks); @@ -115,8 +116,7 @@ private: std::vector<RegisterBank> &Banks); public: - RegisterBankEmitter(RecordKeeper &R) - : Records(R), RegisterClassHierarchy(Records, CodeGenHwModes(R)) {} + RegisterBankEmitter(RecordKeeper &R) : Target(R), Records(R) {} void run(raw_ostream &OS); }; @@ -167,8 +167,8 @@ void RegisterBankEmitter::emitBaseClassDefinition( /// multiple times for a given class if there are multiple paths /// to the class. static void visitRegisterBankClasses( - CodeGenRegBank &RegisterClassHierarchy, const CodeGenRegisterClass *RC, - const Twine Kind, + const CodeGenRegBank &RegisterClassHierarchy, + const CodeGenRegisterClass *RC, const Twine Kind, std::function<void(const CodeGenRegisterClass *, StringRef)> VisitFn, SmallPtrSetImpl<const CodeGenRegisterClass *> &VisitedRCs) { @@ -212,6 +212,7 @@ static void visitRegisterBankClasses( void RegisterBankEmitter::emitBaseClassImplementation( raw_ostream &OS, StringRef TargetName, std::vector<RegisterBank> &Banks) { + const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank(); OS << "namespace llvm {\n" << "namespace " << TargetName << " {\n"; @@ -275,10 +276,8 @@ void RegisterBankEmitter::emitBaseClassImplementation( } void RegisterBankEmitter::run(raw_ostream &OS) { - std::vector<Record*> Targets = Records.getAllDerivedDefinitions("Target"); - if (Targets.size() != 1) - PrintFatalError("ERROR: Too many or too few subclasses of Target defined!"); - StringRef TargetName = Targets[0]->getName(); + StringRef TargetName = Target.getName(); + const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank(); std::vector<RegisterBank> Banks; for (const auto &V : Records.getAllDerivedDefinitions("RegisterBank")) { @@ -286,7 +285,7 @@ void RegisterBankEmitter::run(raw_ostream &OS) { RegisterBank Bank(*V); for (const CodeGenRegisterClass *RC : - Bank.getExplictlySpecifiedRegisterClasses(RegisterClassHierarchy)) { + Bank.getExplicitlySpecifiedRegisterClasses(RegisterClassHierarchy)) { visitRegisterBankClasses( RegisterClassHierarchy, RC, "explicit", [&Bank](const CodeGenRegisterClass *RC, StringRef Kind) { @@ -301,14 +300,14 @@ void RegisterBankEmitter::run(raw_ostream &OS) { } // Warn about ambiguous MIR caused by register bank/class name clashes. - for (const auto &Class : Records.getAllDerivedDefinitions("RegisterClass")) { + for (const auto &Class : RegisterClassHierarchy.getRegClasses()) { for (const auto &Bank : Banks) { - if (Bank.getName().lower() == Class->getName().lower()) { + if (Bank.getName().lower() == StringRef(Class.getName()).lower()) { PrintWarning(Bank.getDef().getLoc(), "Register bank names should be " "distinct from register classes " "to avoid ambiguous MIR"); PrintNote(Bank.getDef().getLoc(), "RegisterBank was declared here"); - PrintNote(Class->getLoc(), "RegisterClass was declared here"); + PrintNote(Class.getDef()->getLoc(), "RegisterClass was declared here"); } } } diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp index 2586ec671b2a..a615587efdee 100644 --- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp +++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp @@ -173,7 +173,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, std::string Namespace = SubRegIndices.front().getNamespace(); if (!Namespace.empty()) OS << "namespace " << Namespace << " {\n"; - OS << "enum {\n NoSubRegister,\n"; + OS << "enum : uint16_t {\n NoSubRegister,\n"; unsigned i = 0; for (const auto &Idx : SubRegIndices) OS << " " << Idx.getName() << ",\t// " << ++i << "\n"; @@ -182,6 +182,20 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, OS << "} // end namespace " << Namespace << "\n\n"; } + OS << "// Register pressure sets enum.\n"; + if (!Namespace.empty()) + OS << "namespace " << Namespace << " {\n"; + OS << "enum RegisterPressureSets {\n"; + unsigned NumSets = Bank.getNumRegPressureSets(); + for (unsigned i = 0; i < NumSets; ++i ) { + const RegUnitSet &RegUnits = Bank.getRegSetAt(i); + OS << " " << RegUnits.Name << " = " << i << ",\n"; + } + OS << "};\n"; + if (!Namespace.empty()) + OS << "} // end namespace " << Namespace << '\n'; + OS << '\n'; + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_REGINFO_ENUM\n\n"; } @@ -202,13 +216,13 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, << " static const RegClassWeight RCWeightTable[] = {\n"; for (const auto &RC : RegBank.getRegClasses()) { const CodeGenRegister::Vec &Regs = RC.getMembers(); + OS << " {" << RC.getWeight(RegBank) << ", "; if (Regs.empty() || RC.Artificial) - OS << " {0, 0"; + OS << '0'; else { std::vector<unsigned> RegUnits; RC.buildRegUnitSet(RegBank, RegUnits); - OS << " {" << (*Regs.begin())->getWeight(RegBank) - << ", " << RegBank.getRegUnitSetWeight(RegUnits); + OS << RegBank.getRegUnitSetWeight(RegUnits); } OS << "}, \t// " << RC.getName() << "\n"; } @@ -897,7 +911,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, unsigned i = 0; for (auto I = Regs.begin(), E = Regs.end(); I != E; ++I, ++i) { const auto &Reg = *I; - RegStrings.add(Reg.getName()); + RegStrings.add(std::string(Reg.getName())); // Compute the ordered sub-register list. SetVector<const CodeGenRegister*> SR; @@ -963,7 +977,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, OS << "namespace llvm {\n\n"; - const std::string &TargetName = Target.getName(); + const std::string &TargetName = std::string(Target.getName()); // Emit the shared table of differential lists. OS << "extern const MCPhysReg " << TargetName << "RegDiffLists[] = {\n"; @@ -992,9 +1006,8 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, // Emit the string table. RegStrings.layout(); - OS << "extern const char " << TargetName << "RegStrings[] = {\n"; - RegStrings.emit(OS, printChar); - OS << "};\n\n"; + RegStrings.emitStringLiteralDef(OS, Twine("extern const char ") + TargetName + + "RegStrings[]"); OS << "extern const MCRegisterDesc " << TargetName << "RegDesc[] = { // Descriptors\n"; @@ -1003,7 +1016,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, // Emit the register descriptors now. i = 0; for (const auto &Reg : Regs) { - OS << " { " << RegStrings.get(Reg.getName()) << ", " + OS << " { " << RegStrings.get(std::string(Reg.getName())) << ", " << DiffSeqs.get(SubRegLists[i]) << ", " << DiffSeqs.get(SuperRegLists[i]) << ", " << SubRegIdxSeqs.get(SubRegIdxLists[i]) << ", " << (DiffSeqs.get(RegUnitLists[i]) * 16 + RegUnitInitScale[i]) << ", " @@ -1065,9 +1078,8 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, OS << "} // end anonymous namespace\n\n"; RegClassStrings.layout(); - OS << "extern const char " << TargetName << "RegClassStrings[] = {\n"; - RegClassStrings.emit(OS, printChar); - OS << "};\n\n"; + RegClassStrings.emitStringLiteralDef( + OS, Twine("extern const char ") + TargetName + "RegClassStrings[]"); OS << "extern const MCRegisterClass " << TargetName << "MCRegisterClasses[] = {\n"; @@ -1134,7 +1146,7 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target, OS << "\n#ifdef GET_REGINFO_HEADER\n"; OS << "#undef GET_REGINFO_HEADER\n\n"; - const std::string &TargetName = Target.getName(); + const std::string &TargetName = std::string(Target.getName()); std::string ClassName = TargetName + "GenRegisterInfo"; OS << "#include \"llvm/CodeGen/TargetRegisterInfo.h\"\n\n"; @@ -1430,7 +1442,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, OS << "} // end anonymous namespace\n"; // Emit extra information about registers. - const std::string &TargetName = Target.getName(); + const std::string &TargetName = std::string(Target.getName()); OS << "\nstatic const TargetRegisterInfoDesc " << TargetName << "RegInfoDesc[] = { // Extra Descriptors\n"; OS << " { 0, false },\n"; diff --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp index cfe48eb1949d..326cb4e54edc 100644 --- a/llvm/utils/TableGen/SearchableTableEmitter.cpp +++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp @@ -57,7 +57,7 @@ struct GenericField { bool IsInstruction = false; GenericEnum *Enum = nullptr; - GenericField(StringRef Name) : Name(Name) {} + GenericField(StringRef Name) : Name(std::string(Name)) {} }; struct SearchIndex { @@ -114,13 +114,17 @@ private: else if (BitInit *BI = dyn_cast<BitInit>(I)) return BI->getValue() ? "true" : "false"; else if (CodeInit *CI = dyn_cast<CodeInit>(I)) - return CI->getValue(); + return std::string(CI->getValue()); else if (Field.IsIntrinsic) return "Intrinsic::" + getIntrinsic(I).EnumName; else if (Field.IsInstruction) return I->getAsString(); - else if (Field.Enum) - return Field.Enum->EntryMap[cast<DefInit>(I)->getDef()]->first; + else if (Field.Enum) { + auto *Entry = Field.Enum->EntryMap[cast<DefInit>(I)->getDef()]; + if (!Entry) + PrintFatalError(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"); } @@ -274,7 +278,7 @@ bool SearchableTableEmitter::compareBy(Record *LHS, Record *RHS, void SearchableTableEmitter::emitIfdef(StringRef Guard, raw_ostream &OS) { OS << "#ifdef " << Guard << "\n"; - PreprocessorGuards.insert(Guard); + PreprocessorGuards.insert(std::string(Guard)); } /// Emit a generic enum. @@ -542,7 +546,7 @@ SearchableTableEmitter::parseSearchIndex(GenericTable &Table, StringRef Name, const std::vector<StringRef> &Key, bool EarlyOut) { auto Index = std::make_unique<SearchIndex>(); - Index->Name = Name; + Index->Name = std::string(Name); Index->EarlyOut = EarlyOut; for (const auto &FieldName : Key) { @@ -595,10 +599,13 @@ void SearchableTableEmitter::collectEnumEntries( void SearchableTableEmitter::collectTableEntries( GenericTable &Table, const std::vector<Record *> &Items) { + if (Items.empty()) + PrintWarning(Twine("Table '") + Table.Name + "' has no items"); + for (auto EntryRec : Items) { for (auto &Field : Table.Fields) { auto TI = dyn_cast<TypedInit>(EntryRec->getValueInit(Field.Name)); - if (!TI) { + if (!TI || !TI->isComplete()) { PrintFatalError(EntryRec->getLoc(), Twine("Record '") + EntryRec->getName() + "' in table '" + Table.Name + @@ -623,6 +630,10 @@ void SearchableTableEmitter::collectTableEntries( Record *IntrinsicClass = Records.getClass("Intrinsic"); Record *InstructionClass = Records.getClass("Instruction"); for (auto &Field : Table.Fields) { + if (!Field.RecType) + PrintFatalError(Twine("Cannot determine type of field '") + Field.Name + + "' in table '" + Table.Name + "'. Maybe it is not used?"); + if (auto RecordTy = dyn_cast<RecordRecTy>(Field.RecType)) { if (IntrinsicClass && RecordTy->isSubClassOf(IntrinsicClass)) Field.IsIntrinsic = true; @@ -648,8 +659,8 @@ void SearchableTableEmitter::run(raw_ostream &OS) { ValueField = EnumRec->getValueAsString("ValueField"); auto Enum = std::make_unique<GenericEnum>(); - Enum->Name = EnumRec->getName(); - Enum->PreprocessorGuard = EnumRec->getName(); + Enum->Name = std::string(EnumRec->getName()); + Enum->PreprocessorGuard = std::string(EnumRec->getName()); StringRef FilterClass = EnumRec->getValueAsString("FilterClass"); Enum->Class = Records.getClass(FilterClass); @@ -665,9 +676,9 @@ void SearchableTableEmitter::run(raw_ostream &OS) { for (auto TableRec : Records.getAllDerivedDefinitions("GenericTable")) { auto Table = std::make_unique<GenericTable>(); - Table->Name = TableRec->getName(); - Table->PreprocessorGuard = TableRec->getName(); - Table->CppTypeName = TableRec->getValueAsString("CppTypeName"); + Table->Name = std::string(TableRec->getName()); + 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) { @@ -746,10 +757,10 @@ void SearchableTableEmitter::run(raw_ostream &OS) { auto Table = std::make_unique<GenericTable>(); Table->Name = (Twine(Class->getName()) + "sList").str(); Table->PreprocessorGuard = Class->getName().upper(); - Table->CppTypeName = Class->getName(); + Table->CppTypeName = std::string(Class->getName()); for (const RecordVal &Field : Class->getValues()) { - std::string FieldName = Field.getName(); + std::string FieldName = std::string(Field.getName()); // Skip uninteresting fields: either special to us, or injected // template parameters (if they contain a ':'). diff --git a/llvm/utils/TableGen/SequenceToOffsetTable.h b/llvm/utils/TableGen/SequenceToOffsetTable.h index 327da39f4774..41cdefdb1949 100644 --- a/llvm/utils/TableGen/SequenceToOffsetTable.h +++ b/llvm/utils/TableGen/SequenceToOffsetTable.h @@ -15,6 +15,7 @@ #ifndef LLVM_UTILS_TABLEGEN_SEQUENCETOOFFSETTABLE_H #define LLVM_UTILS_TABLEGEN_SEQUENCETOOFFSETTABLE_H +#include "llvm/Support/CommandLine.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cassert> @@ -23,6 +24,61 @@ #include <map> namespace llvm { +extern llvm::cl::opt<bool> EmitLongStrLiterals; + +// Helper function for SequenceToOffsetTable<string>. +static inline void printStrLitEscChar(raw_ostream &OS, char C) { + const char *Escapes[] = { + "\\000", "\\001", "\\002", "\\003", "\\004", "\\005", "\\006", "\\007", + "\\010", "\\t", "\\n", "\\013", "\\014", "\\r", "\\016", "\\017", + "\\020", "\\021", "\\022", "\\023", "\\024", "\\025", "\\026", "\\027", + "\\030", "\\031", "\\032", "\\033", "\\034", "\\035", "\\036", "\\037", + " ", "!", "\\\"", "#", "$", "%", "&", "'", + "(", ")", "*", "+", ",", "-", ".", "/", + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", ":", ";", "<", "=", ">", "?", + "@", "A", "B", "C", "D", "E", "F", "G", + "H", "I", "J", "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", "U", "V", "W", + "X", "Y", "Z", "[", "\\\\", "]", "^", "_", + "`", "a", "b", "c", "d", "e", "f", "g", + "h", "i", "j", "k", "l", "m", "n", "o", + "p", "q", "r", "s", "t", "u", "v", "w", + "x", "y", "z", "{", "|", "}", "~", "\\177", + "\\200", "\\201", "\\202", "\\203", "\\204", "\\205", "\\206", "\\207", + "\\210", "\\211", "\\212", "\\213", "\\214", "\\215", "\\216", "\\217", + "\\220", "\\221", "\\222", "\\223", "\\224", "\\225", "\\226", "\\227", + "\\230", "\\231", "\\232", "\\233", "\\234", "\\235", "\\236", "\\237", + "\\240", "\\241", "\\242", "\\243", "\\244", "\\245", "\\246", "\\247", + "\\250", "\\251", "\\252", "\\253", "\\254", "\\255", "\\256", "\\257", + "\\260", "\\261", "\\262", "\\263", "\\264", "\\265", "\\266", "\\267", + "\\270", "\\271", "\\272", "\\273", "\\274", "\\275", "\\276", "\\277", + "\\300", "\\301", "\\302", "\\303", "\\304", "\\305", "\\306", "\\307", + "\\310", "\\311", "\\312", "\\313", "\\314", "\\315", "\\316", "\\317", + "\\320", "\\321", "\\322", "\\323", "\\324", "\\325", "\\326", "\\327", + "\\330", "\\331", "\\332", "\\333", "\\334", "\\335", "\\336", "\\337", + "\\340", "\\341", "\\342", "\\343", "\\344", "\\345", "\\346", "\\347", + "\\350", "\\351", "\\352", "\\353", "\\354", "\\355", "\\356", "\\357", + "\\360", "\\361", "\\362", "\\363", "\\364", "\\365", "\\366", "\\367", + "\\370", "\\371", "\\372", "\\373", "\\374", "\\375", "\\376", "\\377"}; + + static_assert(sizeof Escapes / sizeof Escapes[0] == + std::numeric_limits<unsigned char>::max() + 1, + "unsupported character type"); + OS << Escapes[static_cast<unsigned char>(C)]; +} + +static inline void printChar(raw_ostream &OS, char C) { + unsigned char UC(C); + if (isalnum(UC) || ispunct(UC)) { + OS << '\''; + if (C == '\\' || C == '\'') + OS << '\\'; + OS << C << '\''; + } else { + OS << unsigned(UC); + } +} /// SequenceToOffsetTable - Collect a number of terminated sequences of T. /// Compute the layout of a table that contains all the sequences, possibly by @@ -108,6 +164,37 @@ public: return I->second + (I->first.size() - Seq.size()); } + /// `emitStringLiteralDef` - Print out the table as the body of an array + /// initializer, where each element is a C string literal terminated by + /// `\0`. Falls back to emitting a comma-separated integer list if + /// `EmitLongStrLiterals` is false + void emitStringLiteralDef(raw_ostream &OS, const llvm::Twine &Decl) const { + assert(Entries && "Call layout() before emitStringLiteralDef()"); + if (EmitLongStrLiterals) { + OS << "\n#ifdef __GNUC__\n" + << "#pragma GCC diagnostic push\n" + << "#pragma GCC diagnostic ignored \"-Woverlength-strings\"\n" + << "#endif\n" + << Decl << " = {\n"; + } else { + OS << Decl << " = {\n"; + emit(OS, printChar, "0"); + OS << "\n};\n\n"; + return; + } + for (auto I : Seqs) { + OS << " /* " << I.second << " */ \""; + for (auto C : I.first) { + printStrLitEscChar(OS, C); + } + OS << "\\0\"\n"; + } + OS << "};\n" + << "#ifdef __GNUC__\n" + << "#pragma GCC diagnostic pop\n" + << "#endif\n\n"; + } + /// emit - Print out the table as the body of an array initializer. /// Use the Print function to print elements. void emit(raw_ostream &OS, @@ -127,19 +214,6 @@ public: } }; -// Helper function for SequenceToOffsetTable<string>. -static inline void printChar(raw_ostream &OS, char C) { - unsigned char UC(C); - if (isalnum(UC) || ispunct(UC)) { - OS << '\''; - if (C == '\\' || C == '\'') - OS << '\\'; - OS << C << '\''; - } else { - OS << unsigned(UC); - } -} - } // end namespace llvm #endif diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp index 9b094adb7d5c..68ee839c43ba 100644 --- a/llvm/utils/TableGen/SubtargetEmitter.cpp +++ b/llvm/utils/TableGen/SubtargetEmitter.cpp @@ -128,8 +128,8 @@ class SubtargetEmitter { public: SubtargetEmitter(RecordKeeper &R, CodeGenTarget &TGT) - : TGT(TGT), Records(R), SchedModels(TGT.getSchedModels()), - Target(TGT.getName()) {} + : TGT(TGT), Records(R), SchedModels(TGT.getSchedModels()), + Target(TGT.getName()) {} void run(raw_ostream &o); }; @@ -396,8 +396,8 @@ EmitStageAndOperandCycleData(raw_ostream &OS, << "namespace " << Name << "FU {\n"; for (unsigned j = 0, FUN = FUs.size(); j < FUN; ++j) - OS << " const unsigned " << FUs[j]->getName() - << " = 1 << " << j << ";\n"; + OS << " const InstrStage::FuncUnits " << FUs[j]->getName() + << " = 1ULL << " << j << ";\n"; OS << "} // end namespace " << Name << "FU\n"; @@ -460,7 +460,8 @@ EmitStageAndOperandCycleData(raw_ostream &OS, std::string ItinStageString; unsigned NStages = 0; if (ItinData) - FormItineraryStageString(Name, ItinData, ItinStageString, NStages); + FormItineraryStageString(std::string(Name), ItinData, ItinStageString, + NStages); // Get string and operand cycle count std::string ItinOperandCycleString; @@ -470,7 +471,7 @@ EmitStageAndOperandCycleData(raw_ostream &OS, FormItineraryOperandCycleString(ItinData, ItinOperandCycleString, NOperandCycles); - FormItineraryBypassString(Name, ItinData, ItinBypassString, + FormItineraryBypassString(std::string(Name), ItinData, ItinBypassString, NOperandCycles); } diff --git a/llvm/utils/TableGen/SubtargetFeatureInfo.cpp b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp index 5430f73d5e09..3821f4757464 100644 --- a/llvm/utils/TableGen/SubtargetFeatureInfo.cpp +++ b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp @@ -119,33 +119,43 @@ void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures( const SubtargetFeatureInfo &SFI = SF.second; OS << " if ("; - std::string CondStorage = - SFI.TheDef->getValueAsString("AssemblerCondString"); - StringRef Conds = CondStorage; - std::pair<StringRef, StringRef> Comma = Conds.split(','); - bool First = true; - do { - if (!First) - OS << " && "; - - bool Neg = false; - StringRef Cond = Comma.first; - if (Cond[0] == '!') { - Neg = true; - Cond = Cond.substr(1); - } + const DagInit *D = SFI.TheDef->getValueAsDag("AssemblerCondDag"); + std::string CombineType = D->getOperator()->getAsString(); + if (CombineType != "any_of" && CombineType != "all_of") + PrintFatalError(SFI.TheDef->getLoc(), "Invalid AssemblerCondDag!"); + if (D->getNumArgs() == 0) + PrintFatalError(SFI.TheDef->getLoc(), "Invalid AssemblerCondDag!"); + bool IsOr = CombineType == "any_of"; + + if (IsOr) OS << "("; - if (Neg) - OS << "!"; - OS << "FB[" << TargetName << "::" << Cond << "])"; - if (Comma.second.empty()) - break; + bool First = true; + for (auto *Arg : D->getArgs()) { + if (!First) { + if (IsOr) + OS << " || "; + else + OS << " && "; + } + if (auto *NotArg = dyn_cast<DagInit>(Arg)) { + if (NotArg->getOperator()->getAsString() != "not" || + NotArg->getNumArgs() != 1) + PrintFatalError(SFI.TheDef->getLoc(), "Invalid AssemblerCondDag!"); + Arg = NotArg->getArg(0); + OS << "!"; + } + if (!isa<DefInit>(Arg) || + !cast<DefInit>(Arg)->getDef()->isSubClassOf("SubtargetFeature")) + PrintFatalError(SFI.TheDef->getLoc(), "Invalid AssemblerCondDag!"); + OS << "FB[" << TargetName << "::" << Arg->getAsString() << "]"; First = false; - Comma = Comma.second.split(','); - } while (true); + } + + if (IsOr) + OS << ")"; OS << ")\n"; OS << " Features.set(" << SFI.getEnumBitName() << ");\n"; diff --git a/llvm/utils/TableGen/TableGen.cpp b/llvm/utils/TableGen/TableGen.cpp index bdb963c15d32..8015a58471ca 100644 --- a/llvm/utils/TableGen/TableGen.cpp +++ b/llvm/utils/TableGen/TableGen.cpp @@ -54,12 +54,21 @@ enum ActionType { GenRegisterBank, GenExegesis, GenAutomata, + GenDirectivesEnumDecl, + GenDirectivesEnumImpl, + GenDirectivesEnumGen, }; 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 " + "comma-separated char literals. This can be a readability and " + "compile-time performance win, but upsets some compilers"), + cl::Hidden, cl::init(true)); } // end namespace llvm namespace { @@ -122,7 +131,13 @@ cl::opt<ActionType> Action( "Generate registers bank descriptions"), clEnumValN(GenExegesis, "gen-exegesis", "Generate llvm-exegesis tables"), - clEnumValN(GenAutomata, "gen-automata", "Generate generic automata"))); + clEnumValN(GenAutomata, "gen-automata", "Generate generic automata"), + clEnumValN(GenDirectivesEnumDecl, "gen-directive-decl", + "Generate directive related declaration code (header file)"), + clEnumValN(GenDirectivesEnumImpl, "gen-directive-impl", + "Generate directive related implementation code"), + clEnumValN(GenDirectivesEnumGen, "gen-directive-gen", + "Generate directive related implementation code part"))); cl::OptionCategory PrintEnumsCat("Options for -print-enums"); cl::opt<std::string> Class("class", cl::desc("Print Enum list for this class"), @@ -247,6 +262,15 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenAutomata: EmitAutomata(Records, OS); break; + case GenDirectivesEnumDecl: + EmitDirectivesDecl(Records, OS); + break; + case GenDirectivesEnumImpl: + EmitDirectivesImpl(Records, OS); + break; + case GenDirectivesEnumGen: + EmitDirectivesGen(Records, OS); + break; } return false; diff --git a/llvm/utils/TableGen/TableGenBackends.h b/llvm/utils/TableGen/TableGenBackends.h index 9eef77a4577f..92204f39f8fa 100644 --- a/llvm/utils/TableGen/TableGenBackends.h +++ b/llvm/utils/TableGen/TableGenBackends.h @@ -90,6 +90,9 @@ void EmitX86FoldTables(RecordKeeper &RK, raw_ostream &OS); void EmitRegisterBank(RecordKeeper &RK, raw_ostream &OS); void EmitExegesis(RecordKeeper &RK, raw_ostream &OS); void EmitAutomata(RecordKeeper &RK, raw_ostream &OS); +void EmitDirectivesDecl(RecordKeeper &RK, raw_ostream &OS); +void EmitDirectivesImpl(RecordKeeper &RK, raw_ostream &OS); +void EmitDirectivesGen(RecordKeeper &RK, raw_ostream &OS); } // End llvm namespace diff --git a/llvm/utils/TableGen/X86DisassemblerTables.cpp b/llvm/utils/TableGen/X86DisassemblerTables.cpp index 5dc653ac3806..76e4fd9a13ee 100644 --- a/llvm/utils/TableGen/X86DisassemblerTables.cpp +++ b/llvm/utils/TableGen/X86DisassemblerTables.cpp @@ -669,7 +669,7 @@ void DisassemblerTables::emitModRMDecision(raw_ostream &o1, raw_ostream &o2, if (dt == MODRM_ONEENTRY && decision.instructionIDs[0] == 0) { // Empty table. - o2 << "{ " << stringForDecisionType(dt) << ", 0 }"; + o2 << "{" << stringForDecisionType(dt) << ", 0}"; return; } @@ -708,18 +708,17 @@ void DisassemblerTables::emitModRMDecision(raw_ostream &o1, raw_ostream &o2, EntryNumber = ModRMTableNum; ModRMTableNum += ModRMDecision.size(); - o1 << "/* Table" << EntryNumber << " */\n"; + o1 << "/*Table" << EntryNumber << "*/\n"; i1++; for (std::vector<unsigned>::const_iterator I = ModRMDecision.begin(), E = ModRMDecision.end(); I != E; ++I) { - o1.indent(i1 * 2) << format("0x%hx", *I) << ", /* " - << InstructionSpecifiers[*I].name << " */\n"; + o1.indent(i1 * 2) << format("0x%hx", *I) << ", /*" + << InstructionSpecifiers[*I].name << "*/\n"; } i1--; } - o2 << "{ " << stringForDecisionType(dt) << ", " << EntryNumber << " /* Table" - << EntryNumber << " */ }"; + o2 << "{" << stringForDecisionType(dt) << ", " << EntryNumber << "}"; switch (dt) { default: @@ -769,11 +768,10 @@ void DisassemblerTables::emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2, o2 << "},\n"; } else { o2 << " /* struct OpcodeDecision */ {\n"; - ++i2; for (index = 0; index < 256; ++index) { o2.indent(i2); - o2 << "/* 0x" << format("%02hhx", index) << " */ "; + o2 << "/*0x" << format("%02hhx", index) << "*/"; emitModRMDecision(o1, o2, i1, i2, ModRMTableNum, opDecision.modRMDecisions[index]); @@ -783,7 +781,6 @@ void DisassemblerTables::emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2, o2 << "\n"; } - --i2; o2.indent(i2) << "}\n"; --i2; o2.indent(i2) << "},\n"; @@ -795,24 +792,20 @@ void DisassemblerTables::emitContextDecision(raw_ostream &o1, raw_ostream &o2, unsigned &ModRMTableNum, ContextDecision &decision, const char* name) const { - o2.indent(i2) << "static const struct ContextDecision " << name << " = {\n"; - i2++; - o2.indent(i2) << "{ /* opcodeDecisions */" << "\n"; + o2.indent(i2) << "static const struct ContextDecision " << name << " = {{/* opcodeDecisions */\n"; i2++; for (unsigned index = 0; index < IC_max; ++index) { - o2.indent(i2) << "/* "; + o2.indent(i2) << "/*"; o2 << stringForContext((InstructionContext)index); - o2 << " */ "; + o2 << "*/ "; emitOpcodeDecision(o1, o2, i1, i2, ModRMTableNum, decision.opcodeDecisions[index]); } i2--; - o2.indent(i2) << "}" << "\n"; - i2--; - o2.indent(i2) << "};" << "\n"; + o2.indent(i2) << "}};" << "\n"; } void DisassemblerTables::emitInstructionInfo(raw_ostream &o, @@ -976,9 +969,7 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const { else o << "IC"; - o << ", /* " << index << " */"; - - o << "\n"; + o << ", // " << index << "\n"; } i--; @@ -1021,7 +1012,7 @@ void DisassemblerTables::emit(raw_ostream &o) const { std::vector<unsigned> EmptyTable(1, 0); ModRMTable[EmptyTable] = ModRMTableNum; ModRMTableNum += EmptyTable.size(); - o1 << "/* EmptyTable */\n"; + o1 << "/*EmptyTable*/\n"; o1.indent(i1 * 2) << "0x0,\n"; i1--; emitContextDecisions(o1, o2, i1, i2, ModRMTableNum); diff --git a/llvm/utils/TableGen/X86ModRMFilters.cpp b/llvm/utils/TableGen/X86ModRMFilters.cpp index 98e6fb6104d7..cf7507094fa7 100644 --- a/llvm/utils/TableGen/X86ModRMFilters.cpp +++ b/llvm/utils/TableGen/X86ModRMFilters.cpp @@ -18,4 +18,6 @@ void ModFilter::anchor() { } void ExtendedFilter::anchor() { } +void ExtendedRMFilter::anchor() { } + void ExactFilter::anchor() { } diff --git a/llvm/utils/TableGen/X86ModRMFilters.h b/llvm/utils/TableGen/X86ModRMFilters.h index c77b4c21aec4..f0b8af5fb82a 100644 --- a/llvm/utils/TableGen/X86ModRMFilters.h +++ b/llvm/utils/TableGen/X86ModRMFilters.h @@ -108,6 +108,29 @@ public: } }; +/// ExtendedRMFilter - Extended opcodes are classified based on the value of the +/// mod field [bits 7-6] and the value of the nnn field [bits 2-0]. +class ExtendedRMFilter : public ModRMFilter { + void anchor() override; + bool R; + uint8_t NNN; +public: + /// Constructor + /// + /// \param r True if the mod field must be set to 11; false otherwise. + /// The name is explained at ModFilter. + /// \param nnn The required value of the nnn field. + ExtendedRMFilter(bool r, uint8_t nnn) : + ModRMFilter(), + R(r), + NNN(nnn) { + } + + bool accepts(uint8_t modRM) const override { + return ((R && ((modRM & 0xc0) == 0xc0)) && + ((modRM & 0x7) == NNN)); + } +}; /// ExactFilter - The occasional extended opcode (such as VMCALL or MONITOR) /// requires the ModR/M byte to have a specific value. class ExactFilter : public ModRMFilter { diff --git a/llvm/utils/TableGen/X86RecognizableInstr.cpp b/llvm/utils/TableGen/X86RecognizableInstr.cpp index 1048ef81a378..84f6d5210d74 100644 --- a/llvm/utils/TableGen/X86RecognizableInstr.cpp +++ b/llvm/utils/TableGen/X86RecognizableInstr.cpp @@ -65,7 +65,7 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables, UID = uid; Rec = insn.TheDef; - Name = Rec->getName(); + Name = std::string(Rec->getName()); Spec = &tables.specForUID(UID); if (!Rec->isSubClassOf("X86Inst")) { @@ -94,7 +94,7 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables, ForceDisassemble = Rec->getValueAsBit("ForceDisassemble"); CD8_Scale = byteFromRec(Rec, "CD8_Scale"); - Name = Rec->getName(); + Name = std::string(Rec->getName()); Operands = &insn.Operands.OperandList; @@ -352,10 +352,13 @@ void RecognizableInstr::adjustOperandEncoding(OperandEncoding &encoding) { // The scaling factor for AVX512 compressed displacement encoding is an // instruction attribute. Adjust the ModRM encoding type to include the // scale for compressed displacement. - if ((encoding != ENCODING_RM && encoding != ENCODING_VSIB) ||CD8_Scale == 0) + if ((encoding != ENCODING_RM && + encoding != ENCODING_VSIB && + encoding != ENCODING_SIB) ||CD8_Scale == 0) return; encoding = (OperandEncoding)(encoding + Log2_32(CD8_Scale)); assert(((encoding >= ENCODING_RM && encoding <= ENCODING_RM_CD64) || + (encoding == ENCODING_SIB) || (encoding >= ENCODING_VSIB && encoding <= ENCODING_VSIB_CD64)) && "Invalid CDisp scaling"); } @@ -383,12 +386,12 @@ void RecognizableInstr::handleOperand(bool optional, unsigned &operandIndex, StringRef typeName = (*Operands)[operandIndex].Rec->getName(); - OperandEncoding encoding = encodingFromString(typeName, OpSize); + OperandEncoding encoding = encodingFromString(std::string(typeName), OpSize); // Adjust the encoding type for an operand based on the instruction. adjustOperandEncoding(encoding); Spec->operands[operandIndex].encoding = encoding; - Spec->operands[operandIndex].type = typeFromString(typeName, - HasREX_WPrefix, OpSize); + Spec->operands[operandIndex].type = + typeFromString(std::string(typeName), HasREX_WPrefix, OpSize); ++operandIndex; ++physicalOperandIndex; @@ -459,6 +462,8 @@ void RecognizableInstr::emitInstructionSpecifier() { switch (Form) { default: llvm_unreachable("Unhandled form"); + case X86Local::PrefixByte: + return; case X86Local::RawFrmSrc: HANDLE_OPERAND(relocation); return; @@ -517,6 +522,7 @@ void RecognizableInstr::emitInstructionSpecifier() { HANDLE_OPTIONAL(immediate) break; case X86Local::MRMDestMem: + case X86Local::MRMDestMemFSIB: // Operand 1 is a memory operand (possibly SIB-extended) // Operand 2 is a register operand in the Reg/Opcode field. // - In AVX, there is a register operand in the VEX.vvvv field here - @@ -587,6 +593,7 @@ void RecognizableInstr::emitInstructionSpecifier() { HANDLE_OPERAND(opcodeModifier) break; case X86Local::MRMSrcMem: + case X86Local::MRMSrcMemFSIB: // Operand 1 is a register operand in the Reg/Opcode field. // Operand 2 is a memory operand (possibly SIB-extended) // - In AVX, there is a register operand in the VEX.vvvv field here - @@ -639,6 +646,10 @@ void RecognizableInstr::emitInstructionSpecifier() { HANDLE_OPERAND(rmRegister) HANDLE_OPERAND(opcodeModifier) break; + case X86Local::MRMr0: + // Operand 1 is a register operand in the R/M field. + HANDLE_OPERAND(roRegister) + break; case X86Local::MRMXr: case X86Local::MRM0r: case X86Local::MRM1r: @@ -706,6 +717,14 @@ void RecognizableInstr::emitInstructionSpecifier() { HANDLE_OPERAND(immediate) HANDLE_OPERAND(immediate) break; + case X86Local::MRM0X: + case X86Local::MRM1X: + case X86Local::MRM2X: + case X86Local::MRM3X: + case X86Local::MRM4X: + case X86Local::MRM5X: + case X86Local::MRM6X: + case X86Local::MRM7X: #define MAP(from, to) case X86Local::MRM_##from: X86_INSTR_MRM_MAPPING #undef MAP @@ -749,6 +768,7 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { case X86Local::RawFrmImm8: case X86Local::RawFrmImm16: case X86Local::AddCCFrm: + case X86Local::PrefixByte: filter = std::make_unique<DumbFilter>(); break; case X86Local::MRMDestReg: @@ -761,7 +781,9 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { filter = std::make_unique<ModFilter>(true); break; case X86Local::MRMDestMem: + case X86Local::MRMDestMemFSIB: case X86Local::MRMSrcMem: + case X86Local::MRMSrcMemFSIB: case X86Local::MRMSrcMem4VOp3: case X86Local::MRMSrcMemOp4: case X86Local::MRMSrcMemCC: @@ -775,6 +797,15 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { case X86Local::MRM6r: case X86Local::MRM7r: filter = std::make_unique<ExtendedFilter>(true, Form - X86Local::MRM0r); break; + case X86Local::MRM0X: case X86Local::MRM1X: + case X86Local::MRM2X: case X86Local::MRM3X: + case X86Local::MRM4X: case X86Local::MRM5X: + case X86Local::MRM6X: case X86Local::MRM7X: + filter = std::make_unique<ExtendedFilter>(true, Form - X86Local::MRM0X); + break; + case X86Local::MRMr0: + filter = std::make_unique<ExtendedRMFilter>(true, Form - X86Local::MRMr0); + break; case X86Local::MRM0m: case X86Local::MRM1m: case X86Local::MRM2m: case X86Local::MRM3m: case X86Local::MRM4m: case X86Local::MRM5m: @@ -894,6 +925,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s, TYPE("i64imm", TYPE_IMM) TYPE("anymem", TYPE_M) TYPE("opaquemem", TYPE_M) + TYPE("sibmem", TYPE_MSIB) TYPE("SEGMENT_REG", TYPE_SEGMENTREG) TYPE("DEBUG_REG", TYPE_DEBUGREG) TYPE("CONTROL_REG", TYPE_CONTROLREG) @@ -952,6 +984,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s, TYPE("vz256mem", TYPE_MVSIBZ) TYPE("vz512mem", TYPE_MVSIBZ) TYPE("BNDR", TYPE_BNDR) + TYPE("TILE", TYPE_TMM) errs() << "Unhandled type string " << s << "\n"; llvm_unreachable("Unhandled type string"); } @@ -991,6 +1024,7 @@ RecognizableInstr::immediateEncodingFromString(const std::string &s, ENCODING("VR128X", ENCODING_IB) ENCODING("VR256X", ENCODING_IB) ENCODING("VR512", ENCODING_IB) + ENCODING("TILE", ENCODING_IB) errs() << "Unhandled immediate encoding " << s << "\n"; llvm_unreachable("Unhandled immediate encoding"); } @@ -1029,6 +1063,7 @@ RecognizableInstr::rmRegisterEncodingFromString(const std::string &s, ENCODING("VK8PAIR", ENCODING_RM) ENCODING("VK16PAIR", ENCODING_RM) ENCODING("BNDR", ENCODING_RM) + ENCODING("TILE", ENCODING_RM) errs() << "Unhandled R/M register encoding " << s << "\n"; llvm_unreachable("Unhandled R/M register encoding"); } @@ -1075,6 +1110,7 @@ RecognizableInstr::roRegisterEncodingFromString(const std::string &s, ENCODING("VK32WM", ENCODING_REG) ENCODING("VK64WM", ENCODING_REG) ENCODING("BNDR", ENCODING_REG) + ENCODING("TILE", ENCODING_REG) errs() << "Unhandled reg/opcode register encoding " << s << "\n"; llvm_unreachable("Unhandled reg/opcode register encoding"); } @@ -1106,6 +1142,7 @@ RecognizableInstr::vvvvRegisterEncodingFromString(const std::string &s, ENCODING("VK4PAIR", ENCODING_VVVV) ENCODING("VK8PAIR", ENCODING_VVVV) ENCODING("VK16PAIR", ENCODING_VVVV) + ENCODING("TILE", ENCODING_VVVV) errs() << "Unhandled VEX.vvvv register encoding " << s << "\n"; llvm_unreachable("Unhandled VEX.vvvv register encoding"); } @@ -1146,6 +1183,7 @@ RecognizableInstr::memoryEncodingFromString(const std::string &s, ENCODING("lea64mem", ENCODING_RM) ENCODING("anymem", ENCODING_RM) ENCODING("opaquemem", ENCODING_RM) + ENCODING("sibmem", ENCODING_SIB) ENCODING("vx64mem", ENCODING_VSIB) ENCODING("vx128mem", ENCODING_VSIB) ENCODING("vx256mem", ENCODING_VSIB) diff --git a/llvm/utils/TableGen/X86RecognizableInstr.h b/llvm/utils/TableGen/X86RecognizableInstr.h index b15bef4e1931..a7b88b4d12ed 100644 --- a/llvm/utils/TableGen/X86RecognizableInstr.h +++ b/llvm/utils/TableGen/X86RecognizableInstr.h @@ -102,22 +102,28 @@ namespace X86Local { RawFrmImm8 = 7, RawFrmImm16 = 8, AddCCFrm = 9, - MRMDestMem = 32, - MRMSrcMem = 33, - MRMSrcMem4VOp3 = 34, - MRMSrcMemOp4 = 35, - MRMSrcMemCC = 36, - MRMXmCC = 38, MRMXm = 39, - MRM0m = 40, MRM1m = 41, MRM2m = 42, MRM3m = 43, - MRM4m = 44, MRM5m = 45, MRM6m = 46, MRM7m = 47, - MRMDestReg = 48, - MRMSrcReg = 49, - MRMSrcReg4VOp3 = 50, - MRMSrcRegOp4 = 51, - MRMSrcRegCC = 52, - MRMXrCC = 54, MRMXr = 55, - MRM0r = 56, MRM1r = 57, MRM2r = 58, MRM3r = 59, - MRM4r = 60, MRM5r = 61, MRM6r = 62, MRM7r = 63, + PrefixByte = 10, + MRMr0 = 21, + MRMSrcMemFSIB = 22, + MRMDestMemFSIB = 23, + MRMDestMem = 24, + MRMSrcMem = 25, + MRMSrcMem4VOp3 = 26, + MRMSrcMemOp4 = 27, + MRMSrcMemCC = 28, + MRMXmCC = 30, MRMXm = 31, + MRM0m = 32, MRM1m = 33, MRM2m = 34, MRM3m = 35, + MRM4m = 36, MRM5m = 37, MRM6m = 38, MRM7m = 39, + MRMDestReg = 40, + MRMSrcReg = 41, + MRMSrcReg4VOp3 = 42, + MRMSrcRegOp4 = 43, + MRMSrcRegCC = 44, + MRMXrCC = 46, MRMXr = 47, + MRM0r = 48, MRM1r = 49, MRM2r = 50, MRM3r = 51, + MRM4r = 52, MRM5r = 53, MRM6r = 54, MRM7r = 55, + MRM0X = 56, MRM1X = 57, MRM2X = 58, MRM3X = 59, + MRM4X = 60, MRM5X = 61, MRM6X = 62, MRM7X = 63, #define MAP(from, to) MRM_##from = to, X86_INSTR_MRM_MAPPING #undef MAP |