diff options
Diffstat (limited to 'llvm/utils/TableGen/Basic')
| -rw-r--r-- | llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp | 11 | ||||
| -rw-r--r-- | llvm/utils/TableGen/Basic/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp | 69 | ||||
| -rw-r--r-- | llvm/utils/TableGen/Basic/CodeGenIntrinsics.h | 21 | ||||
| -rw-r--r-- | llvm/utils/TableGen/Basic/DirectiveEmitter.cpp | 197 | ||||
| -rw-r--r-- | llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp | 117 | ||||
| -rw-r--r-- | llvm/utils/TableGen/Basic/RuntimeLibcalls.cpp | 93 | ||||
| -rw-r--r-- | llvm/utils/TableGen/Basic/RuntimeLibcalls.h | 189 | ||||
| -rw-r--r-- | llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp | 294 | ||||
| -rw-r--r-- | llvm/utils/TableGen/Basic/SequenceToOffsetTable.h | 7 | ||||
| -rw-r--r-- | llvm/utils/TableGen/Basic/TableGen.cpp | 7 | ||||
| -rw-r--r-- | llvm/utils/TableGen/Basic/TargetLibraryInfoEmitter.cpp | 185 | ||||
| -rw-r--r-- | llvm/utils/TableGen/Basic/VTEmitter.cpp | 17 |
13 files changed, 798 insertions, 411 deletions
diff --git a/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp b/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp index 3f284ee..a18fed0 100644 --- a/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp +++ b/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp @@ -159,12 +159,15 @@ static void emitARMTargetDef(const RecordKeeper &RK, raw_ostream &OS) { << " if(I.size()) return I;\n" << " I.reserve(" << FMVExts.size() << ");\n"; for (const Record *Rec : FMVExts) { + auto FeatName = Rec->getValueAsString("BackendFeature"); + const Record *FeatRec = ExtensionMap[FeatName]; OS << " I.emplace_back("; OS << "\"" << Rec->getValueAsString("Name") << "\""; - OS << ", " << Rec->getValueAsString("FeatureBit"); + if (FeatRec) + OS << ", " << Rec->getValueAsString("FeatureBit"); + else + OS << ", std::nullopt"; OS << ", " << Rec->getValueAsString("PriorityBit"); - auto FeatName = Rec->getValueAsString("BackendFeature"); - const Record *FeatRec = ExtensionMap[FeatName]; if (FeatRec) OS << ", " << FeatRec->getValueAsString("ArchExtKindSpelling").upper(); else @@ -220,7 +223,7 @@ static void emitARMTargetDef(const RecordKeeper &RK, raw_ostream &OS) { ProfileLower + "'"); // Name of the object in C++ - const std::string CppSpelling = ArchInfoName(Major, Minor, ProfileUpper); + std::string CppSpelling = ArchInfoName(Major, Minor, ProfileUpper); OS << "inline constexpr ArchInfo " << CppSpelling << " = {\n"; CppSpellings.push_back(std::move(CppSpelling)); diff --git a/llvm/utils/TableGen/Basic/CMakeLists.txt b/llvm/utils/TableGen/Basic/CMakeLists.txt index b4a66ec..01ab8a0 100644 --- a/llvm/utils/TableGen/Basic/CMakeLists.txt +++ b/llvm/utils/TableGen/Basic/CMakeLists.txt @@ -16,9 +16,11 @@ add_llvm_library(LLVMTableGenBasic OBJECT EXCLUDE_FROM_ALL DISABLE_LLVM_LINK_LLV IntrinsicEmitter.cpp RISCVTargetDefEmitter.cpp RuntimeLibcallsEmitter.cpp + RuntimeLibcalls.cpp SDNodeProperties.cpp TableGen.cpp TargetFeaturesEmitter.cpp + TargetLibraryInfoEmitter.cpp VTEmitter.cpp ) diff --git a/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp b/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp index cd86646..d90fcc2 100644 --- a/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp +++ b/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp @@ -13,6 +13,7 @@ #include "CodeGenIntrinsics.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/TableGen/Error.h" @@ -377,7 +378,19 @@ void CodeGenIntrinsic::setProperty(const Record *R) { ME &= MemoryEffects::argMemOnly(); else if (R->getName() == "IntrInaccessibleMemOnly") ME &= MemoryEffects::inaccessibleMemOnly(); - else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly") + else if (R->isSubClassOf("IntrRead")) { + MemoryEffects ReadMask = MemoryEffects::writeOnly(); + for (const Record *RLoc : R->getValueAsListOfDefs("MemLoc")) + ReadMask = ReadMask.getWithModRef(getValueAsIRMemLocation(RLoc), + ModRefInfo::ModRef); + ME &= ReadMask; + } else if (R->isSubClassOf("IntrWrite")) { + MemoryEffects WriteMask = MemoryEffects::readOnly(); + for (const Record *WLoc : R->getValueAsListOfDefs("MemLoc")) + WriteMask = WriteMask.getWithModRef(getValueAsIRMemLocation(WLoc), + ModRefInfo::ModRef); + ME &= WriteMask; + } else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly") ME &= MemoryEffects::inaccessibleOrArgMemOnly(); else if (R->getName() == "Commutative") isCommutative = true; @@ -407,6 +420,8 @@ void CodeGenIntrinsic::setProperty(const Record *R) { hasSideEffects = true; else if (R->getName() == "IntrStrictFP") isStrictFP = true; + else if (R->getName() == "IntrNoCreateUndefOrPoison") + isNoCreateUndefOrPoison = true; else if (R->isSubClassOf("NoCapture")) { unsigned ArgNo = R->getValueAsInt("ArgNo"); addArgAttribute(ArgNo, NoCapture); @@ -447,11 +462,50 @@ void CodeGenIntrinsic::setProperty(const Record *R) { int64_t Lower = R->getValueAsInt("Lower"); int64_t Upper = R->getValueAsInt("Upper"); addArgAttribute(ArgNo, Range, Lower, Upper); + } else if (R->isSubClassOf("ArgInfo")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + if (ArgNo < 1) + PrintFatalError(R->getLoc(), + "ArgInfo requires ArgNo >= 1 (0 is return value)"); + const ListInit *Properties = R->getValueAsListInit("Properties"); + StringRef ArgName; + StringRef FuncName; + + for (const Init *PropInit : Properties->getElements()) { + if (const auto *PropDef = dyn_cast<DefInit>(PropInit)) { + const Record *PropRec = PropDef->getDef(); + + if (PropRec->isSubClassOf("ArgName")) + ArgName = PropRec->getValueAsString("Name"); + else if (PropRec->isSubClassOf("ImmArgPrinter")) + FuncName = PropRec->getValueAsString("FuncName"); + else + PrintFatalError(PropRec->getLoc(), + "Unknown ArgProperty type: " + PropRec->getName()); + } + } + addPrettyPrintFunction(ArgNo - 1, ArgName, FuncName); } else { llvm_unreachable("Unknown property!"); } } +llvm::IRMemLocation +CodeGenIntrinsic::getValueAsIRMemLocation(const Record *R) const { + StringRef Name = R->getName(); + IRMemLocation Loc = + StringSwitch<IRMemLocation>(Name) + .Case("TargetMem0", IRMemLocation::TargetMem0) + .Case("TargetMem1", IRMemLocation::TargetMem1) + .Case("InaccessibleMem", IRMemLocation::InaccessibleMem) + .Default(IRMemLocation::Other); // fallback enum + + if (Loc == IRMemLocation::Other) + PrintFatalError(R->getLoc(), "unknown IRMemLocation: " + Name); + + return Loc; +} + bool CodeGenIntrinsic::isParamAPointer(unsigned ParamIdx) const { if (ParamIdx >= IS.ParamTys.size()) return false; @@ -474,3 +528,16 @@ void CodeGenIntrinsic::addArgAttribute(unsigned Idx, ArgAttrKind AK, uint64_t V, ArgumentAttributes.resize(Idx + 1); ArgumentAttributes[Idx].emplace_back(AK, V, V2); } + +void CodeGenIntrinsic::addPrettyPrintFunction(unsigned ArgIdx, + StringRef ArgName, + StringRef FuncName) { + auto It = llvm::find_if(PrettyPrintFunctions, [ArgIdx](const auto &Info) { + return Info.ArgIdx == ArgIdx; + }); + if (It != PrettyPrintFunctions.end()) + PrintFatalError(TheDef->getLoc(), "ArgInfo for argument " + Twine(ArgIdx) + + " is already defined as '" + + It->FuncName + "'"); + PrettyPrintFunctions.emplace_back(ArgIdx, ArgName, FuncName); +} diff --git a/llvm/utils/TableGen/Basic/CodeGenIntrinsics.h b/llvm/utils/TableGen/Basic/CodeGenIntrinsics.h index 2e86149..305260a 100644 --- a/llvm/utils/TableGen/Basic/CodeGenIntrinsics.h +++ b/llvm/utils/TableGen/Basic/CodeGenIntrinsics.h @@ -114,6 +114,9 @@ struct CodeGenIntrinsic { // True if the intrinsic is marked as strictfp. bool isStrictFP = false; + // True if the intrinsic is marked as IntrNoCreateUndefOrPoison. + bool isNoCreateUndefOrPoison = false; + enum ArgAttrKind { NoCapture, NoAlias, @@ -149,6 +152,22 @@ struct CodeGenIntrinsic { void addArgAttribute(unsigned Idx, ArgAttrKind AK, uint64_t V = 0, uint64_t V2 = 0); + /// Structure to store pretty print and argument information. + struct PrettyPrintArgInfo { + unsigned ArgIdx; + StringRef ArgName; + StringRef FuncName; + + PrettyPrintArgInfo(unsigned Idx, StringRef Name, StringRef Func) + : ArgIdx(Idx), ArgName(Name), FuncName(Func) {} + }; + + /// Vector that stores ArgInfo (ArgIndex, ArgName, FunctionName). + SmallVector<PrettyPrintArgInfo> PrettyPrintFunctions; + + void addPrettyPrintFunction(unsigned ArgIdx, StringRef ArgName, + StringRef FuncName); + bool hasProperty(enum SDNP Prop) const { return Properties & (1 << Prop); } /// Goes through all IntrProperties that have IsDefault value set and sets @@ -167,6 +186,8 @@ struct CodeGenIntrinsic { bool isParamImmArg(unsigned ParamIdx) const; + llvm::IRMemLocation getValueAsIRMemLocation(const Record *R) const; + CodeGenIntrinsic(const Record *R, const CodeGenIntrinsicContext &Ctx); }; diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp index 3c6ff11..1126c83 100644 --- a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp +++ b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp @@ -81,6 +81,7 @@ static void generateEnumExports(ArrayRef<const Record *> Records, std::string N = getIdentifierName(R, Prefix); OS << "constexpr auto " << N << " = " << Enum << "::" << N << ";\n"; } + OS << "\n"; } // Generate enum class. Entries are emitted in the order in which they appear @@ -88,7 +89,6 @@ static void generateEnumExports(ArrayRef<const Record *> Records, static void generateEnumClass(ArrayRef<const Record *> Records, raw_ostream &OS, StringRef Enum, StringRef Prefix, bool ExportEnums) { - OS << "\n"; OS << "enum class " << Enum << " {\n"; if (!Records.empty()) { std::string N; @@ -104,17 +104,15 @@ static void generateEnumClass(ArrayRef<const Record *> Records, raw_ostream &OS, OS << "};\n"; OS << "\n"; OS << "static constexpr std::size_t " << Enum - << "_enumSize = " << Records.size() << ";\n"; + << "_enumSize = " << Records.size() << ";\n\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 (ExportEnums) { - OS << "\n"; + if (ExportEnums) generateEnumExports(Records, OS, Enum, Prefix); - } } // Generate enum class with values corresponding to different bit positions. @@ -127,7 +125,6 @@ static void generateEnumBitmask(ArrayRef<const Record *> Records, StringRef Type = Records.size() <= 32 ? "uint32_t" : "uint64_t"; StringRef TypeSuffix = Records.size() <= 32 ? "U" : "ULL"; - OS << "\n"; OS << "enum class " << Enum << " : " << Type << " {\n"; std::string LastName; for (auto [I, R] : llvm::enumerate(Records)) { @@ -138,17 +135,15 @@ static void generateEnumBitmask(ArrayRef<const Record *> Records, OS << "};\n"; OS << "\n"; OS << "static constexpr std::size_t " << Enum - << "_enumSize = " << Records.size() << ";\n"; + << "_enumSize = " << Records.size() << ";\n\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 (ExportEnums) { - OS << "\n"; + if (ExportEnums) generateEnumExports(Records, OS, Enum, Prefix); - } } // Generate enums for values that clauses can take. @@ -170,7 +165,6 @@ static void generateClauseEnumVal(ArrayRef<const Record *> Records, return; } - OS << "\n"; OS << "enum class " << Enum << " {\n"; for (const EnumVal Val : ClauseVals) OS << " " << Val.getRecordName() << "=" << Val.getValue() << ",\n"; @@ -182,6 +176,7 @@ static void generateClauseEnumVal(ArrayRef<const Record *> Records, OS << "constexpr auto " << CV->getName() << " = " << Enum << "::" << CV->getName() << ";\n"; } + OS << "\n"; EnumHelperFuncs += (Twine("LLVM_ABI ") + Twine(Enum) + Twine(" get") + Twine(Enum) + Twine("(StringRef Str);\n")) .str(); @@ -281,84 +276,81 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { OS << "#include <utility>\n"; // for std::pair OS << "\n"; NamespaceEmitter LlvmNS(OS, "llvm"); - NamespaceEmitter DirLangNS(OS, DirLang.getCppNamespace()); - - if (DirLang.hasEnableBitmaskEnumInNamespace()) - OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; - - // Emit Directive associations - std::vector<const Record *> Associations; - copy_if(DirLang.getAssociations(), std::back_inserter(Associations), - // Skip the "special" value - [](const Record *Def) { return Def->getName() != "AS_FromLeaves"; }); - generateEnumClass(Associations, OS, "Association", - /*Prefix=*/"", /*ExportEnums=*/false); - - generateEnumClass(DirLang.getCategories(), OS, "Category", /*Prefix=*/"", - /*ExportEnums=*/false); - - generateEnumBitmask(DirLang.getSourceLanguages(), OS, "SourceLanguage", + { + NamespaceEmitter DirLangNS(OS, DirLang.getCppNamespace()); + + if (DirLang.hasEnableBitmaskEnumInNamespace()) + OS << "LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n\n"; + + // Emit Directive associations + std::vector<const Record *> Associations; + copy_if( + DirLang.getAssociations(), std::back_inserter(Associations), + // Skip the "special" value + [](const Record *Def) { return Def->getName() != "AS_FromLeaves"; }); + generateEnumClass(Associations, OS, "Association", /*Prefix=*/"", /*ExportEnums=*/false); - // Emit Directive enumeration - generateEnumClass(DirLang.getDirectives(), OS, "Directive", - DirLang.getDirectivePrefix(), - DirLang.hasMakeEnumAvailableInNamespace()); + generateEnumClass(DirLang.getCategories(), OS, "Category", /*Prefix=*/"", + /*ExportEnums=*/false); - // Emit Clause enumeration - generateEnumClass(DirLang.getClauses(), OS, "Clause", - DirLang.getClausePrefix(), - DirLang.hasMakeEnumAvailableInNamespace()); + generateEnumBitmask(DirLang.getSourceLanguages(), OS, "SourceLanguage", + /*Prefix=*/"", /*ExportEnums=*/false); - // Emit ClauseVals enumeration - std::string EnumHelperFuncs; - generateClauseEnumVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs); + // Emit Directive enumeration + generateEnumClass(DirLang.getDirectives(), OS, "Directive", + DirLang.getDirectivePrefix(), + DirLang.hasMakeEnumAvailableInNamespace()); - // Generic function signatures - OS << "\n"; - OS << "// Enumeration helper functions\n"; + // Emit Clause enumeration + generateEnumClass(DirLang.getClauses(), OS, "Clause", + DirLang.getClausePrefix(), + DirLang.hasMakeEnumAvailableInNamespace()); - OS << "LLVM_ABI std::pair<Directive, directive::VersionRange> get" << Lang - << "DirectiveKindAndVersions(StringRef Str);\n"; + // Emit ClauseVals enumeration + std::string EnumHelperFuncs; + generateClauseEnumVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs); - OS << "inline Directive get" << Lang << "DirectiveKind(StringRef Str) {\n"; - OS << " return get" << Lang << "DirectiveKindAndVersions(Str).first;\n"; - OS << "}\n"; - OS << "\n"; + // Generic function signatures + OS << "// Enumeration helper functions\n"; - OS << "LLVM_ABI StringRef get" << Lang - << "DirectiveName(Directive D, unsigned Ver = 0);\n"; - OS << "\n"; + OS << "LLVM_ABI std::pair<Directive, directive::VersionRange> get" << Lang + << "DirectiveKindAndVersions(StringRef Str);\n"; - OS << "LLVM_ABI std::pair<Clause, directive::VersionRange> get" << Lang - << "ClauseKindAndVersions(StringRef Str);\n"; - OS << "\n"; + OS << "inline Directive get" << Lang << "DirectiveKind(StringRef Str) {\n"; + OS << " return get" << Lang << "DirectiveKindAndVersions(Str).first;\n"; + OS << "}\n"; + OS << "\n"; - OS << "inline Clause get" << Lang << "ClauseKind(StringRef Str) {\n"; - OS << " return get" << Lang << "ClauseKindAndVersions(Str).first;\n"; - OS << "}\n"; - OS << "\n"; + OS << "LLVM_ABI StringRef get" << Lang + << "DirectiveName(Directive D, unsigned Ver = 0);\n"; + OS << "\n"; - OS << "LLVM_ABI StringRef get" << Lang - << "ClauseName(Clause C, unsigned Ver = 0);\n"; - OS << "\n"; + OS << "LLVM_ABI std::pair<Clause, directive::VersionRange> get" << Lang + << "ClauseKindAndVersions(StringRef Str);\n"; + OS << "\n"; - OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p " - << "Version.\n"; - OS << "LLVM_ABI bool isAllowedClauseForDirective(Directive D, " - << "Clause C, unsigned Version);\n"; - OS << "\n"; - OS << "constexpr std::size_t getMaxLeafCount() { return " - << getMaxLeafCount(DirLang) << "; }\n"; - OS << "LLVM_ABI Association getDirectiveAssociation(Directive D);\n"; - OS << "LLVM_ABI Category getDirectiveCategory(Directive D);\n"; - OS << "LLVM_ABI SourceLanguage getDirectiveLanguages(Directive D);\n"; - if (EnumHelperFuncs.length() > 0) { - OS << EnumHelperFuncs; + OS << "inline Clause get" << Lang << "ClauseKind(StringRef Str) {\n"; + OS << " return get" << Lang << "ClauseKindAndVersions(Str).first;\n"; + OS << "}\n"; OS << "\n"; - } - DirLangNS.close(); + OS << "LLVM_ABI StringRef get" << Lang + << "ClauseName(Clause C, unsigned Ver = 0);\n"; + OS << "\n"; + + OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p " + << "Version.\n"; + OS << "LLVM_ABI bool isAllowedClauseForDirective(Directive D, " + << "Clause C, unsigned Version);\n"; + OS << "\n"; + OS << "constexpr std::size_t getMaxLeafCount() { return " + << getMaxLeafCount(DirLang) << "; }\n"; + OS << "LLVM_ABI Association getDirectiveAssociation(Directive D);\n"; + OS << "LLVM_ABI Category getDirectiveCategory(Directive D);\n"; + OS << "LLVM_ABI SourceLanguage getDirectiveLanguages(Directive D);\n"; + OS << EnumHelperFuncs; + } // close DirLangNS // These specializations need to be in ::llvm. for (StringRef Enum : {"Association", "Category", "Directive", "Clause"}) { @@ -368,7 +360,6 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { OS << " static constexpr bool is_iterable = true;\n"; OS << "};\n"; } - LlvmNS.close(); } // Given a list of spellings (for a given clause/directive), order them @@ -738,11 +729,12 @@ static void emitLeafTable(const DirectiveLanguage &DirLang, raw_ostream &OS, static void generateGetDirectiveAssociation(const DirectiveLanguage &DirLang, raw_ostream &OS) { enum struct Association { - None = 0, // None should be the smallest value. - Block, // The values of the rest don't matter. - Declaration, + None = 0, // None should be the smallest value. + Block, // If the order of the rest of these changes, update the + Declaration, // 'Reduce' function below. Delimited, - Loop, + LoopNest, + LoopSeq, Separating, FromLeaves, Invalid, @@ -755,7 +747,8 @@ static void generateGetDirectiveAssociation(const DirectiveLanguage &DirLang, .Case("AS_Block", Association::Block) .Case("AS_Declaration", Association::Declaration) .Case("AS_Delimited", Association::Delimited) - .Case("AS_Loop", Association::Loop) + .Case("AS_LoopNest", Association::LoopNest) + .Case("AS_LoopSeq", Association::LoopSeq) .Case("AS_None", Association::None) .Case("AS_Separating", Association::Separating) .Case("AS_FromLeaves", Association::FromLeaves) @@ -786,13 +779,12 @@ static void generateGetDirectiveAssociation(const DirectiveLanguage &DirLang, // Calculate the result using the following rules: // x + x = x // AS_None + x = x - // AS_Block + AS_Loop = AS_Loop + // AS_Block + AS_Loop{Nest|Seq} = AS_Loop{Nest|Seq} if (A == Association::None || A == B) return B; - if (A == Association::Block && B == Association::Loop) + if (A == Association::Block && + (B == Association::LoopNest || B == Association::LoopSeq)) return B; - if (A == Association::Loop && B == Association::Block) - return A; return Association::Invalid; }; @@ -940,27 +932,20 @@ static void generateClauseSet(ArrayRef<const Record *> VerClauses, // Generate an enum set for the 4 kinds of clauses linked to a directive. static void generateDirectiveClauseSets(const DirectiveLanguage &DirLang, Frontend FE, raw_ostream &OS) { + IfDefEmitter Scope(OS, "GEN_" + getFESpelling(FE).upper() + + "_DIRECTIVE_CLAUSE_SETS"); - std::string IfDefName{"GEN_"}; - IfDefName += getFESpelling(FE).upper(); - IfDefName += "_DIRECTIVE_CLAUSE_SETS"; - IfDefEmitter Scope(OS, IfDefName); - - StringRef Namespace = - getFESpelling(FE == Frontend::Flang ? Frontend::LLVM : FE); + std::string Namespace = + getFESpelling(FE == Frontend::Flang ? Frontend::LLVM : FE).str(); // The namespace has to be different for clang vs flang, as 2 structs with the // same name but different layout is UB. So just put the 'clang' on in the // clang namespace. - OS << "namespace " << Namespace << " {\n"; - - // Open namespaces defined in the directive language. - SmallVector<StringRef, 2> Namespaces; - SplitString(DirLang.getCppNamespace(), Namespaces, "::"); - for (auto Ns : Namespaces) - OS << "namespace " << Ns << " {\n"; + // Additionally, open namespaces defined in the directive language. + if (!DirLang.getCppNamespace().empty()) + Namespace += "::" + DirLang.getCppNamespace().str(); + NamespaceEmitter NS(OS, Namespace); for (const Directive Dir : DirLang.getDirectives()) { - OS << "\n"; OS << "// Sets for " << Dir.getSpellingForIdentifier() << "\n"; generateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir, @@ -972,12 +957,6 @@ static void generateDirectiveClauseSets(const DirectiveLanguage &DirLang, generateClauseSet(Dir.getRequiredClauses(), OS, "requiredClauses_", Dir, DirLang, FE); } - - // Closing namespaces - for (auto Ns : reverse(Namespaces)) - OS << "} // namespace " << Ns << "\n"; - - OS << "} // namespace " << Namespace << "\n"; } // Generate a map of directive (key) with DirectiveClauses struct as values. @@ -985,10 +964,8 @@ static void generateDirectiveClauseSets(const DirectiveLanguage &DirLang, // allowances (allowed, allowed once, allowed exclusive and required). static void generateDirectiveClauseMap(const DirectiveLanguage &DirLang, Frontend FE, raw_ostream &OS) { - std::string IfDefName{"GEN_"}; - IfDefName += getFESpelling(FE).upper(); - IfDefName += "_DIRECTIVE_CLAUSE_MAP"; - IfDefEmitter Scope(OS, IfDefName); + IfDefEmitter Scope(OS, "GEN_" + getFESpelling(FE).upper() + + "_DIRECTIVE_CLAUSE_MAP"); OS << "{\n"; diff --git a/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp b/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp index 75dffb1..9fed592 100644 --- a/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp +++ b/llvm/utils/TableGen/Basic/IntrinsicEmitter.cpp @@ -60,8 +60,16 @@ public: raw_ostream &OS); void EmitIntrinsicToOverloadTable(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); + void EmitIntrinsicToPrettyPrintTable(const CodeGenIntrinsicTable &Ints, + raw_ostream &OS); + void EmitIntrinsicBitTable( + const CodeGenIntrinsicTable &Ints, raw_ostream &OS, StringRef Guard, + StringRef TableName, StringRef Comment, + function_ref<bool(const CodeGenIntrinsic &Int)> GetProperty); void EmitGenerator(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); void EmitAttributes(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); + void EmitPrettyPrintArguments(const CodeGenIntrinsicTable &Ints, + raw_ostream &OS); void EmitIntrinsicToBuiltinMap(const CodeGenIntrinsicTable &Ints, bool IsClang, raw_ostream &OS); }; @@ -109,6 +117,12 @@ void IntrinsicEmitter::run(raw_ostream &OS, bool Enums) { // Emit the intrinsic parameter attributes. EmitAttributes(Ints, OS); + // Emit the intrinsic ID -> pretty print table. + EmitIntrinsicToPrettyPrintTable(Ints, OS); + + // Emit Pretty Print attribute. + EmitPrettyPrintArguments(Ints, OS); + // Emit code to translate Clang builtins into LLVM intrinsics. EmitIntrinsicToBuiltinMap(Ints, true, OS); @@ -240,6 +254,29 @@ static constexpr IntrinsicTargetInfo TargetInfos[] = { )"; } +/// Helper function to emit a bit table for intrinsic properties. +/// This is used for both overload and pretty print bit tables. +void IntrinsicEmitter::EmitIntrinsicBitTable( + const CodeGenIntrinsicTable &Ints, raw_ostream &OS, StringRef Guard, + StringRef TableName, StringRef Comment, + function_ref<bool(const CodeGenIntrinsic &Int)> GetProperty) { + OS << formatv("// {}\n", Comment); + OS << formatv("#ifdef {}\n", Guard); + OS << formatv("static constexpr uint8_t {}[] = {{\n", TableName); + OS << " 0\n "; + for (auto [I, Int] : enumerate(Ints)) { + // Add one to the index so we emit a null bit for the invalid #0 intrinsic. + size_t Idx = I + 1; + if (Idx % 8 == 0) + OS << ",\n 0"; + if (GetProperty(Int)) + OS << " | (1<<" << Idx % 8 << ')'; + } + OS << "\n};\n\n"; + OS << formatv("return ({}[id/8] & (1 << (id%8))) != 0;\n", TableName); + OS << formatv("#endif // {}\n\n", Guard); +} + void IntrinsicEmitter::EmitIntrinsicToNameTable( const CodeGenIntrinsicTable &Ints, raw_ostream &OS) { // Built up a table of the intrinsic names. @@ -276,24 +313,10 @@ static constexpr unsigned IntrinsicNameOffsetTable[] = { void IntrinsicEmitter::EmitIntrinsicToOverloadTable( const CodeGenIntrinsicTable &Ints, raw_ostream &OS) { - OS << R"(// Intrinsic ID to overload bitset. -#ifdef GET_INTRINSIC_OVERLOAD_TABLE -static constexpr uint8_t OTable[] = { - 0 - )"; - for (auto [I, Int] : enumerate(Ints)) { - // Add one to the index so we emit a null bit for the invalid #0 intrinsic. - size_t Idx = I + 1; - - if (Idx % 8 == 0) - OS << ",\n 0"; - if (Int.isOverloaded) - OS << " | (1<<" << Idx % 8 << ')'; - } - OS << "\n};\n\n"; - // OTable contains a true bit at the position if the intrinsic is overloaded. - OS << "return (OTable[id/8] & (1 << (id%8))) != 0;\n"; - OS << "#endif\n\n"; + EmitIntrinsicBitTable( + Ints, OS, "GET_INTRINSIC_OVERLOAD_TABLE", "OTable", + "Intrinsic ID to overload bitset.", + [](const CodeGenIntrinsic &Int) { return Int.isOverloaded; }); } using TypeSigTy = SmallVector<unsigned char>; @@ -421,7 +444,8 @@ static bool compareFnAttributes(const CodeGenIntrinsic *L, return std::tie(I->canThrow, I->isNoDuplicate, I->isNoMerge, I->isNoReturn, I->isNoCallback, I->isNoSync, I->isNoFree, I->isWillReturn, I->isCold, I->isConvergent, I->isSpeculatable, - I->hasSideEffects, I->isStrictFP); + I->hasSideEffects, I->isStrictFP, + I->isNoCreateUndefOrPoison); }; auto TieL = TieBoolAttributes(L); @@ -446,7 +470,8 @@ static bool hasFnAttributes(const CodeGenIntrinsic &Int) { return !Int.canThrow || Int.isNoReturn || Int.isNoCallback || Int.isNoSync || Int.isNoFree || Int.isWillReturn || Int.isCold || Int.isNoDuplicate || Int.isNoMerge || Int.isConvergent || Int.isSpeculatable || - Int.isStrictFP || getEffectiveME(Int) != MemoryEffects::unknown(); + Int.isStrictFP || Int.isNoCreateUndefOrPoison || + getEffectiveME(Int) != MemoryEffects::unknown(); } namespace { @@ -574,10 +599,10 @@ static AttributeSet getIntrinsicFnAttributeSet(LLVMContext &C, unsigned ID) { if (!UniqFnAttributes.try_emplace(&Int, ID).second) continue; OS << formatv(R"( - case {}: + case {}: // {} return AttributeSet::get(C, {{ )", - ID); + ID, Int.Name); auto addAttribute = [&OS](StringRef Attr) { OS << formatv(" Attribute::get(C, Attribute::{}),\n", Attr); }; @@ -605,6 +630,8 @@ static AttributeSet getIntrinsicFnAttributeSet(LLVMContext &C, unsigned ID) { addAttribute("Speculatable"); if (Int.isStrictFP) addAttribute("StrictFP"); + if (Int.isNoCreateUndefOrPoison) + addAttribute("NoCreateUndefOrPoison"); const MemoryEffects ME = getEffectiveME(Int); if (ME != MemoryEffects::unknown()) { @@ -805,6 +832,52 @@ AttributeSet Intrinsic::getFnAttributes(LLVMContext &C, ID id) {{ NoFunctionAttrsID); } +void IntrinsicEmitter::EmitIntrinsicToPrettyPrintTable( + const CodeGenIntrinsicTable &Ints, raw_ostream &OS) { + EmitIntrinsicBitTable(Ints, OS, "GET_INTRINSIC_PRETTY_PRINT_TABLE", "PPTable", + "Intrinsic ID to pretty print bitset.", + [](const CodeGenIntrinsic &Int) { + return !Int.PrettyPrintFunctions.empty(); + }); +} + +void IntrinsicEmitter::EmitPrettyPrintArguments( + const CodeGenIntrinsicTable &Ints, raw_ostream &OS) { + OS << R"( +#ifdef GET_INTRINSIC_PRETTY_PRINT_ARGUMENTS +void Intrinsic::printImmArg(ID IID, unsigned ArgIdx, raw_ostream &OS, const Constant *ImmArgVal) { + using namespace Intrinsic; + switch (IID) { +)"; + + for (const CodeGenIntrinsic &Int : Ints) { + if (Int.PrettyPrintFunctions.empty()) + continue; + + OS << " case " << Int.EnumName << ":\n"; + OS << " switch (ArgIdx) {\n"; + for (const auto [ArgIdx, ArgName, FuncName] : Int.PrettyPrintFunctions) { + OS << " case " << ArgIdx << ":\n"; + OS << " OS << \"" << ArgName << "=\";\n"; + if (!FuncName.empty()) { + OS << " "; + if (!Int.TargetPrefix.empty()) + OS << Int.TargetPrefix << "::"; + OS << FuncName << "(OS, ImmArgVal);\n"; + } + OS << " return;\n"; + } + OS << " }\n"; + OS << " break;\n"; + } + OS << R"( default: + break; + } +} +#endif // GET_INTRINSIC_PRETTY_PRINT_ARGUMENTS +)"; +} + void IntrinsicEmitter::EmitIntrinsicToBuiltinMap( const CodeGenIntrinsicTable &Ints, bool IsClang, raw_ostream &OS) { StringRef CompilerName = IsClang ? "Clang" : "MS"; diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcalls.cpp b/llvm/utils/TableGen/Basic/RuntimeLibcalls.cpp new file mode 100644 index 0000000..1e609a2 --- /dev/null +++ b/llvm/utils/TableGen/Basic/RuntimeLibcalls.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "RuntimeLibcalls.h" +#include "llvm/TableGen/Error.h" + +using namespace llvm; + +RuntimeLibcalls::RuntimeLibcalls(const RecordKeeper &Records) { + ArrayRef<const Record *> AllRuntimeLibcalls = + Records.getAllDerivedDefinitions("RuntimeLibcall"); + + RuntimeLibcallDefList.reserve(AllRuntimeLibcalls.size()); + + size_t CallTypeEnumVal = 0; + for (const Record *RuntimeLibcallDef : AllRuntimeLibcalls) { + RuntimeLibcallDefList.emplace_back(RuntimeLibcallDef, CallTypeEnumVal++); + Def2RuntimeLibcall[RuntimeLibcallDef] = &RuntimeLibcallDefList.back(); + } + + for (RuntimeLibcall &LibCall : RuntimeLibcallDefList) + Def2RuntimeLibcall[LibCall.getDef()] = &LibCall; + + ArrayRef<const Record *> AllRuntimeLibcallImplsRaw = + Records.getAllDerivedDefinitions("RuntimeLibcallImpl"); + + SmallVector<const Record *, 1024> AllRuntimeLibcallImpls( + AllRuntimeLibcallImplsRaw); + + // Sort by libcall impl name and secondarily by the enum name. + sort(AllRuntimeLibcallImpls, [](const Record *A, const Record *B) { + return std::pair(A->getValueAsString("LibCallFuncName"), A->getName()) < + std::pair(B->getValueAsString("LibCallFuncName"), B->getName()); + }); + + RuntimeLibcallImplDefList.reserve(AllRuntimeLibcallImpls.size()); + + size_t LibCallImplEnumVal = 1; + for (const Record *LibCallImplDef : AllRuntimeLibcallImpls) { + RuntimeLibcallImplDefList.emplace_back(LibCallImplDef, Def2RuntimeLibcall, + LibCallImplEnumVal++); + + const RuntimeLibcallImpl &LibCallImpl = RuntimeLibcallImplDefList.back(); + Def2RuntimeLibcallImpl[LibCallImplDef] = &LibCallImpl; + + if (LibCallImpl.isDefault()) { + const RuntimeLibcall *Provides = LibCallImpl.getProvides(); + if (!Provides) + PrintFatalError(LibCallImplDef->getLoc(), + "default implementations must provide a libcall"); + LibCallToDefaultImpl[Provides] = &LibCallImpl; + } + } +} + +void LibcallPredicateExpander::expand(SetTheory &ST, const Record *Def, + SetTheory::RecSet &Elts) { + assert(Def->isSubClassOf("LibcallImpls")); + + SetTheory::RecSet TmpElts; + + ST.evaluate(Def->getValueInit("MemberList"), TmpElts, Def->getLoc()); + + Elts.insert(TmpElts.begin(), TmpElts.end()); + + AvailabilityPredicate AP(Def->getValueAsDef("AvailabilityPredicate")); + const Record *CCClass = Def->getValueAsOptionalDef("CallingConv"); + + // This is assuming we aren't conditionally applying a calling convention to + // some subsets, and not another, but this doesn't appear to be used. + + for (const Record *LibcallImplDef : TmpElts) { + const RuntimeLibcallImpl *LibcallImpl = + Libcalls.getRuntimeLibcallImpl(LibcallImplDef); + if (!AP.isAlwaysAvailable() || CCClass) { + auto [It, Inserted] = Func2Preds.insert({LibcallImpl, {{}, CCClass}}); + if (!Inserted) { + PrintError( + Def, + "combining nested libcall set predicates currently unhandled: '" + + LibcallImpl->getLibcallFuncName() + "'"); + } + + It->second.first.push_back(AP.getDef()); + It->second.second = CCClass; + } + } +} diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcalls.h b/llvm/utils/TableGen/Basic/RuntimeLibcalls.h new file mode 100644 index 0000000..6c98976 --- /dev/null +++ b/llvm/utils/TableGen/Basic/RuntimeLibcalls.h @@ -0,0 +1,189 @@ +//===------------------------------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_UTILS_TABLEGEN_COMMON_RUNTIMELIBCALLS_H +#define LLVM_UTILS_TABLEGEN_COMMON_RUNTIMELIBCALLS_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/SetTheory.h" + +namespace llvm { + +class AvailabilityPredicate { + const Record *TheDef; + StringRef PredicateString; + +public: + AvailabilityPredicate(const Record *Def) : TheDef(Def) { + if (TheDef) + PredicateString = TheDef->getValueAsString("Cond"); + } + + const Record *getDef() const { return TheDef; } + + bool isAlwaysAvailable() const { return PredicateString.empty(); } + + void emitIf(raw_ostream &OS) const { + OS << "if (" << PredicateString << ") {\n"; + } + + void emitEndIf(raw_ostream &OS) const { OS << "}\n"; } + + void emitTableVariableNameSuffix(raw_ostream &OS) const { + if (TheDef) + OS << '_' << TheDef->getName(); + } +}; + +class RuntimeLibcalls; +class RuntimeLibcallImpl; + +/// Used to apply predicates to nested sets of libcalls. +struct LibcallPredicateExpander : SetTheory::Expander { + const RuntimeLibcalls &Libcalls; + DenseMap<const RuntimeLibcallImpl *, + std::pair<std::vector<const Record *>, const Record *>> &Func2Preds; + + LibcallPredicateExpander( + const RuntimeLibcalls &Libcalls, + DenseMap<const RuntimeLibcallImpl *, + std::pair<std::vector<const Record *>, const Record *>> + &Func2Preds) + : Libcalls(Libcalls), Func2Preds(Func2Preds) {} + + void expand(SetTheory &ST, const Record *Def, + SetTheory::RecSet &Elts) override; +}; + +class RuntimeLibcall { + const Record *TheDef = nullptr; + const size_t EnumVal; + +public: + RuntimeLibcall() = delete; + RuntimeLibcall(const Record *Def, size_t EnumVal) + : TheDef(Def), EnumVal(EnumVal) { + assert(Def); + } + + ~RuntimeLibcall() { assert(TheDef); } + + const Record *getDef() const { return TheDef; } + + StringRef getName() const { return TheDef->getName(); } + + size_t getEnumVal() const { return EnumVal; } + + void emitEnumEntry(raw_ostream &OS) const { + OS << "RTLIB::" << TheDef->getValueAsString("Name"); + } +}; + +class RuntimeLibcallImpl { + const Record *TheDef; + const RuntimeLibcall *Provides = nullptr; + const size_t EnumVal; + +public: + RuntimeLibcallImpl( + const Record *Def, + const DenseMap<const Record *, const RuntimeLibcall *> &ProvideMap, + size_t EnumVal) + : TheDef(Def), EnumVal(EnumVal) { + if (const Record *ProvidesDef = Def->getValueAsDef("Provides")) + Provides = ProvideMap.lookup(ProvidesDef); + } + + ~RuntimeLibcallImpl() = default; + + const Record *getDef() const { return TheDef; } + + StringRef getName() const { return TheDef->getName(); } + + size_t getEnumVal() const { return EnumVal; } + + const RuntimeLibcall *getProvides() const { return Provides; } + + StringRef getLibcallFuncName() const { + return TheDef->getValueAsString("LibCallFuncName"); + } + + const Record *getCallingConv() const { + return TheDef->getValueAsOptionalDef("CallingConv"); + } + + void emitQuotedLibcallFuncName(raw_ostream &OS) const { + OS << '\"' << getLibcallFuncName() << '\"'; + } + + bool isDefault() const { return TheDef->getValueAsBit("IsDefault"); } + + void emitEnumEntry(raw_ostream &OS) const { + OS << "RTLIB::impl_" << this->getName(); + } + + void emitSetImplCall(raw_ostream &OS) const { + OS << "setLibcallImpl("; + Provides->emitEnumEntry(OS); + OS << ", "; + emitEnumEntry(OS); + OS << "); // " << getLibcallFuncName() << '\n'; + } + + void emitTableEntry(raw_ostream &OS) const { + OS << '{'; + Provides->emitEnumEntry(OS); + OS << ", "; + emitEnumEntry(OS); + OS << "}, // " << getLibcallFuncName() << '\n'; + } + + void emitSetCallingConv(raw_ostream &OS) const {} +}; + +struct LibcallsWithCC { + std::vector<const RuntimeLibcallImpl *> LibcallImpls; + const Record *CallingConv = nullptr; +}; + +class RuntimeLibcalls { +private: + DenseMap<const Record *, const RuntimeLibcall *> Def2RuntimeLibcall; + DenseMap<const Record *, const RuntimeLibcallImpl *> Def2RuntimeLibcallImpl; + + std::vector<RuntimeLibcall> RuntimeLibcallDefList; + std::vector<RuntimeLibcallImpl> RuntimeLibcallImplDefList; + + DenseMap<const RuntimeLibcall *, const RuntimeLibcallImpl *> + LibCallToDefaultImpl; + +public: + RuntimeLibcalls(const RecordKeeper &Records); + + ArrayRef<RuntimeLibcall> getRuntimeLibcallDefList() const { + return RuntimeLibcallDefList; + } + + ArrayRef<RuntimeLibcallImpl> getRuntimeLibcallImplDefList() const { + return RuntimeLibcallImplDefList; + } + + const RuntimeLibcall *getRuntimeLibcall(const Record *Def) const { + return Def2RuntimeLibcall.lookup(Def); + } + + const RuntimeLibcallImpl *getRuntimeLibcallImpl(const Record *Def) const { + return Def2RuntimeLibcallImpl.lookup(Def); + } +}; + +} // namespace llvm + +#endif // LLVM_UTILS_TABLEGEN_COMMON_RUNTIMELIBCALLS_H diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp index 6a36f47..7aca87a6 100644 --- a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp +++ b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp @@ -8,6 +8,8 @@ #define DEBUG_TYPE "runtime-libcall-emitter" +#include "RuntimeLibcalls.h" + #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Debug.h" @@ -65,160 +67,12 @@ template <> struct DenseMapInfo<PredicateWithCC, void> { return LHS == RHS; } }; -} // namespace llvm - -namespace { - -class AvailabilityPredicate { - const Record *TheDef; - StringRef PredicateString; - -public: - AvailabilityPredicate(const Record *Def) : TheDef(Def) { - if (TheDef) - PredicateString = TheDef->getValueAsString("Cond"); - } - - const Record *getDef() const { return TheDef; } - - bool isAlwaysAvailable() const { return PredicateString.empty(); } - - void emitIf(raw_ostream &OS) const { - OS << "if (" << PredicateString << ") {\n"; - } - - void emitEndIf(raw_ostream &OS) const { OS << "}\n"; } - - void emitTableVariableNameSuffix(raw_ostream &OS) const { - if (TheDef) - OS << '_' << TheDef->getName(); - } -}; - -class RuntimeLibcallEmitter; -class RuntimeLibcallImpl; - -/// Used to apply predicates to nested sets of libcalls. -struct LibcallPredicateExpander : SetTheory::Expander { - const RuntimeLibcallEmitter &LibcallEmitter; - DenseMap<const RuntimeLibcallImpl *, - std::pair<std::vector<const Record *>, const Record *>> &Func2Preds; - - LibcallPredicateExpander( - const RuntimeLibcallEmitter &LibcallEmitter, - DenseMap<const RuntimeLibcallImpl *, - std::pair<std::vector<const Record *>, const Record *>> - &Func2Preds) - : LibcallEmitter(LibcallEmitter), Func2Preds(Func2Preds) {} - - void expand(SetTheory &ST, const Record *Def, - SetTheory::RecSet &Elts) override; -}; - -class RuntimeLibcall { - const Record *TheDef = nullptr; - const size_t EnumVal; - -public: - RuntimeLibcall() = delete; - RuntimeLibcall(const Record *Def, size_t EnumVal) - : TheDef(Def), EnumVal(EnumVal) { - assert(Def); - } - - ~RuntimeLibcall() { assert(TheDef); } - - const Record *getDef() const { return TheDef; } - - StringRef getName() const { return TheDef->getName(); } - - size_t getEnumVal() const { return EnumVal; } - - void emitEnumEntry(raw_ostream &OS) const { - OS << "RTLIB::" << TheDef->getValueAsString("Name"); - } -}; - -class RuntimeLibcallImpl { - const Record *TheDef; - const RuntimeLibcall *Provides = nullptr; - const size_t EnumVal; - -public: - RuntimeLibcallImpl( - const Record *Def, - const DenseMap<const Record *, const RuntimeLibcall *> &ProvideMap, - size_t EnumVal) - : TheDef(Def), EnumVal(EnumVal) { - if (const Record *ProvidesDef = Def->getValueAsDef("Provides")) - Provides = ProvideMap.lookup(ProvidesDef); - } - - ~RuntimeLibcallImpl() = default; - - const Record *getDef() const { return TheDef; } - - StringRef getName() const { return TheDef->getName(); } - - size_t getEnumVal() const { return EnumVal; } - - const RuntimeLibcall *getProvides() const { return Provides; } - - StringRef getLibcallFuncName() const { - return TheDef->getValueAsString("LibCallFuncName"); - } - - const Record *getCallingConv() const { - return TheDef->getValueAsOptionalDef("CallingConv"); - } - - void emitQuotedLibcallFuncName(raw_ostream &OS) const { - OS << '\"' << getLibcallFuncName() << '\"'; - } - - bool isDefault() const { return TheDef->getValueAsBit("IsDefault"); } - - void emitEnumEntry(raw_ostream &OS) const { - OS << "RTLIB::impl_" << this->getName(); - } - - void emitSetImplCall(raw_ostream &OS) const { - OS << "setLibcallImpl("; - Provides->emitEnumEntry(OS); - OS << ", "; - emitEnumEntry(OS); - OS << "); // " << getLibcallFuncName() << '\n'; - } - - void emitTableEntry(raw_ostream &OS) const { - OS << '{'; - Provides->emitEnumEntry(OS); - OS << ", "; - emitEnumEntry(OS); - OS << "}, // " << getLibcallFuncName() << '\n'; - } - - void emitSetCallingConv(raw_ostream &OS) const {} -}; - -struct LibcallsWithCC { - std::vector<const RuntimeLibcallImpl *> LibcallImpls; - const Record *CallingConv = nullptr; -}; class RuntimeLibcallEmitter { private: const RecordKeeper &Records; - DenseMap<const Record *, const RuntimeLibcall *> Def2RuntimeLibcall; - DenseMap<const Record *, const RuntimeLibcallImpl *> Def2RuntimeLibcallImpl; + RuntimeLibcalls Libcalls; - std::vector<RuntimeLibcall> RuntimeLibcallDefList; - std::vector<RuntimeLibcallImpl> RuntimeLibcallImplDefList; - - DenseMap<const RuntimeLibcall *, const RuntimeLibcallImpl *> - LibCallToDefaultImpl; - -private: void emitGetRuntimeLibcallEnum(raw_ostream &OS) const; void emitNameMatchHashTable(raw_ostream &OS, @@ -229,61 +83,7 @@ private: void emitSystemRuntimeLibrarySetCalls(raw_ostream &OS) const; public: - RuntimeLibcallEmitter(const RecordKeeper &R) : Records(R) { - - ArrayRef<const Record *> AllRuntimeLibcalls = - Records.getAllDerivedDefinitions("RuntimeLibcall"); - - RuntimeLibcallDefList.reserve(AllRuntimeLibcalls.size()); - - size_t CallTypeEnumVal = 0; - for (const Record *RuntimeLibcallDef : AllRuntimeLibcalls) { - RuntimeLibcallDefList.emplace_back(RuntimeLibcallDef, CallTypeEnumVal++); - Def2RuntimeLibcall[RuntimeLibcallDef] = &RuntimeLibcallDefList.back(); - } - - for (RuntimeLibcall &LibCall : RuntimeLibcallDefList) - Def2RuntimeLibcall[LibCall.getDef()] = &LibCall; - - ArrayRef<const Record *> AllRuntimeLibcallImplsRaw = - Records.getAllDerivedDefinitions("RuntimeLibcallImpl"); - - SmallVector<const Record *, 1024> AllRuntimeLibcallImpls( - AllRuntimeLibcallImplsRaw); - - // Sort by libcall impl name and secondarily by the enum name. - sort(AllRuntimeLibcallImpls, [](const Record *A, const Record *B) { - return std::pair(A->getValueAsString("LibCallFuncName"), A->getName()) < - std::pair(B->getValueAsString("LibCallFuncName"), B->getName()); - }); - - RuntimeLibcallImplDefList.reserve(AllRuntimeLibcallImpls.size()); - - size_t LibCallImplEnumVal = 1; - for (const Record *LibCallImplDef : AllRuntimeLibcallImpls) { - RuntimeLibcallImplDefList.emplace_back(LibCallImplDef, Def2RuntimeLibcall, - LibCallImplEnumVal++); - - const RuntimeLibcallImpl &LibCallImpl = RuntimeLibcallImplDefList.back(); - Def2RuntimeLibcallImpl[LibCallImplDef] = &LibCallImpl; - - if (LibCallImpl.isDefault()) { - const RuntimeLibcall *Provides = LibCallImpl.getProvides(); - if (!Provides) - PrintFatalError(LibCallImplDef->getLoc(), - "default implementations must provide a libcall"); - LibCallToDefaultImpl[Provides] = &LibCallImpl; - } - } - } - - const RuntimeLibcall *getRuntimeLibcall(const Record *Def) const { - return Def2RuntimeLibcall.lookup(Def); - } - - const RuntimeLibcallImpl *getRuntimeLibcallImpl(const Record *Def) const { - return Def2RuntimeLibcallImpl.lookup(Def); - } + RuntimeLibcallEmitter(const RecordKeeper &R) : Records(R), Libcalls(R) {} void run(raw_ostream &OS); }; @@ -297,24 +97,25 @@ void RuntimeLibcallEmitter::emitGetRuntimeLibcallEnum(raw_ostream &OS) const { "namespace RTLIB {\n" "enum Libcall : unsigned short {\n"; - for (const RuntimeLibcall &LibCall : RuntimeLibcallDefList) { + for (const RuntimeLibcall &LibCall : Libcalls.getRuntimeLibcallDefList()) { StringRef Name = LibCall.getName(); OS << " " << Name << " = " << LibCall.getEnumVal() << ",\n"; } - OS << " UNKNOWN_LIBCALL = " << RuntimeLibcallDefList.size() + OS << " UNKNOWN_LIBCALL = " << Libcalls.getRuntimeLibcallDefList().size() << "\n};\n\n" "enum LibcallImpl : unsigned short {\n" " Unsupported = 0,\n"; - for (const RuntimeLibcallImpl &LibCall : RuntimeLibcallImplDefList) { + for (const RuntimeLibcallImpl &LibCall : + Libcalls.getRuntimeLibcallImplDefList()) { OS << " impl_" << LibCall.getName() << " = " << LibCall.getEnumVal() << ", // " << LibCall.getLibcallFuncName() << '\n'; } OS << "};\n" << "constexpr size_t NumLibcallImpls = " - << RuntimeLibcallImplDefList.size() + 1 + << Libcalls.getRuntimeLibcallImplDefList().size() + 1 << ";\n" "} // End namespace RTLIB\n" "} // End namespace llvm\n"; @@ -394,6 +195,8 @@ constructPerfectHashTable(ArrayRef<RuntimeLibcallImpl> Keywords, /// Generate hash table based lookup by name. void RuntimeLibcallEmitter::emitNameMatchHashTable( raw_ostream &OS, StringToOffsetTable &OffsetTable) const { + ArrayRef<RuntimeLibcallImpl> RuntimeLibcallImplDefList = + Libcalls.getRuntimeLibcallImplDefList(); std::vector<uint64_t> Hashes(RuntimeLibcallImplDefList.size()); std::vector<unsigned> TableValues(RuntimeLibcallImplDefList.size()); DenseSet<StringRef> SeenFuncNames; @@ -495,7 +298,8 @@ void RuntimeLibcallEmitter::emitGetInitRuntimeLibcallNames( { IfDefEmitter IfDef(OS, "GET_INIT_RUNTIME_LIBCALL_NAMES"); - for (const RuntimeLibcallImpl &LibCallImpl : RuntimeLibcallImplDefList) + for (const RuntimeLibcallImpl &LibCallImpl : + Libcalls.getRuntimeLibcallImplDefList()) Table.GetOrAddStringOffset(LibCallImpl.getLibcallFuncName()); Table.EmitStringTableDef(OS, "RuntimeLibcallImplNameTable"); @@ -505,7 +309,8 @@ const uint16_t RTLIB::RuntimeLibcallsInfo::RuntimeLibcallNameOffsetTable[] = { OS << formatv(" {}, // {}\n", Table.GetStringOffset(""), ""); // Unsupported entry - for (const RuntimeLibcallImpl &LibCallImpl : RuntimeLibcallImplDefList) { + for (const RuntimeLibcallImpl &LibCallImpl : + Libcalls.getRuntimeLibcallImplDefList()) { StringRef ImplName = LibCallImpl.getLibcallFuncName(); OS << formatv(" {}, // {}\n", Table.GetStringOffset(ImplName), ImplName); } @@ -516,7 +321,8 @@ const uint8_t RTLIB::RuntimeLibcallsInfo::RuntimeLibcallNameSizeTable[] = { )"; OS << " 0,\n"; - for (const RuntimeLibcallImpl &LibCallImpl : RuntimeLibcallImplDefList) + for (const RuntimeLibcallImpl &LibCallImpl : + Libcalls.getRuntimeLibcallImplDefList()) OS << " " << LibCallImpl.getLibcallFuncName().size() << ",\n"; OS << "};\n\n"; @@ -525,7 +331,8 @@ const uint8_t RTLIB::RuntimeLibcallsInfo::RuntimeLibcallNameSizeTable[] = { "ImplToLibcall[RTLIB::NumLibcallImpls] = {\n" " RTLIB::UNKNOWN_LIBCALL, // RTLIB::Unsupported\n"; - for (const RuntimeLibcallImpl &LibCallImpl : RuntimeLibcallImplDefList) { + for (const RuntimeLibcallImpl &LibCallImpl : + Libcalls.getRuntimeLibcallImplDefList()) { const RuntimeLibcall *Provides = LibCallImpl.getProvides(); OS << " "; Provides->emitEnumEntry(OS); @@ -533,6 +340,7 @@ const uint8_t RTLIB::RuntimeLibcallsInfo::RuntimeLibcallNameSizeTable[] = { LibCallImpl.emitEnumEntry(OS); OS << '\n'; } + OS << "};\n\n"; } @@ -544,11 +352,8 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls( OS << "void llvm::RTLIB::RuntimeLibcallsInfo::setTargetRuntimeLibcallSets(" "const llvm::Triple &TT, ExceptionHandling ExceptionModel, " "FloatABI::ABIType FloatABI, EABI EABIVersion, " - "StringRef ABIName) {\n" - " struct LibcallImplPair {\n" - " RTLIB::Libcall Func;\n" - " RTLIB::LibcallImpl Impl;\n" - " };\n"; + "StringRef ABIName) {\n"; + ArrayRef<const Record *> AllLibs = Records.getAllDerivedDefinitions("SystemRuntimeLibrary"); @@ -579,7 +384,7 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls( std::pair<std::vector<const Record *>, const Record *>> Func2Preds; Sets.addExpander("LibcallImpls", std::make_unique<LibcallPredicateExpander>( - *this, Func2Preds)); + Libcalls, Func2Preds)); const SetTheory::RecVec *Elements = Sets.expand(R->getValueAsDef("MemberList")); @@ -592,11 +397,12 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls( constexpr unsigned BitsPerStorageElt = 64; DenseMap<PredicateWithCC, LibcallsWithCC> Pred2Funcs; - SmallVector<uint64_t, 32> BitsetValues( - divideCeil(RuntimeLibcallImplDefList.size() + 1, BitsPerStorageElt)); + SmallVector<uint64_t, 32> BitsetValues(divideCeil( + Libcalls.getRuntimeLibcallImplDefList().size() + 1, BitsPerStorageElt)); for (const Record *Elt : *Elements) { - const RuntimeLibcallImpl *LibCallImpl = getRuntimeLibcallImpl(Elt); + const RuntimeLibcallImpl *LibCallImpl = + Libcalls.getRuntimeLibcallImpl(Elt); if (!LibCallImpl) { PrintError(R, "entry for SystemLibrary is not a RuntimeLibcallImpl"); PrintNote(Elt->getLoc(), "invalid entry `" + Elt->getName() + "`"); @@ -703,7 +509,7 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls( Funcs.erase(UniqueI, Funcs.end()); OS << indent(IndentDepth + 2) - << "static const LibcallImplPair LibraryCalls"; + << "static const RTLIB::LibcallImpl LibraryCalls"; SubsetPredicate.emitTableVariableNameSuffix(OS); if (FuncsWithCC.CallingConv) OS << '_' << FuncsWithCC.CallingConv->getName(); @@ -711,18 +517,18 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls( OS << "[] = {\n"; for (const RuntimeLibcallImpl *LibCallImpl : Funcs) { OS << indent(IndentDepth + 6); - LibCallImpl->emitTableEntry(OS); + LibCallImpl->emitEnumEntry(OS); + OS << ", // " << LibCallImpl->getLibcallFuncName() << '\n'; } OS << indent(IndentDepth + 2) << "};\n\n" << indent(IndentDepth + 2) - << "for (const auto [Func, Impl] : LibraryCalls"; + << "for (const RTLIB::LibcallImpl Impl : LibraryCalls"; SubsetPredicate.emitTableVariableNameSuffix(OS); if (FuncsWithCC.CallingConv) OS << '_' << FuncsWithCC.CallingConv->getName(); - OS << ") {\n" - << indent(IndentDepth + 4) << "setLibcallImpl(Func, Impl);\n"; + OS << ") {\n" << indent(IndentDepth + 4) << "setAvailable(Impl);\n"; if (FuncsWithCC.CallingConv) { StringRef CCEnum = @@ -759,44 +565,10 @@ void RuntimeLibcallEmitter::run(raw_ostream &OS) { emitGetInitRuntimeLibcallNames(OS); { - IfDefEmitter IfDef(OS, "GET_SET_TARGET_RUNTIME_LIBCALL_SETS"); + IfDefEmitter IfDef(OS, "GET_RUNTIME_LIBCALLS_INFO"); emitSystemRuntimeLibrarySetCalls(OS); } } -void LibcallPredicateExpander::expand(SetTheory &ST, const Record *Def, - SetTheory::RecSet &Elts) { - assert(Def->isSubClassOf("LibcallImpls")); - - SetTheory::RecSet TmpElts; - - ST.evaluate(Def->getValueInit("MemberList"), TmpElts, Def->getLoc()); - - Elts.insert(TmpElts.begin(), TmpElts.end()); - - AvailabilityPredicate AP(Def->getValueAsDef("AvailabilityPredicate")); - const Record *CCClass = Def->getValueAsOptionalDef("CallingConv"); - - // This is assuming we aren't conditionally applying a calling convention to - // some subsets, and not another, but this doesn't appear to be used. - - for (const Record *LibcallImplDef : TmpElts) { - const RuntimeLibcallImpl *LibcallImpl = - LibcallEmitter.getRuntimeLibcallImpl(LibcallImplDef); - if (!AP.isAlwaysAvailable() || CCClass) { - auto [It, Inserted] = Func2Preds.insert({LibcallImpl, {{}, CCClass}}); - if (!Inserted) { - PrintError( - Def, - "combining nested libcall set predicates currently unhandled: '" + - LibcallImpl->getLibcallFuncName() + "'"); - } - - It->second.first.push_back(AP.getDef()); - It->second.second = CCClass; - } - } -} - static TableGen::Emitter::OptClass<RuntimeLibcallEmitter> X("gen-runtime-libcalls", "Generate RuntimeLibcalls"); diff --git a/llvm/utils/TableGen/Basic/SequenceToOffsetTable.h b/llvm/utils/TableGen/Basic/SequenceToOffsetTable.h index 8da6fbe..1cd18b7 100644 --- a/llvm/utils/TableGen/Basic/SequenceToOffsetTable.h +++ b/llvm/utils/TableGen/Basic/SequenceToOffsetTable.h @@ -44,7 +44,7 @@ inline void printChar(raw_ostream &OS, char C) { /// @tparam Less A stable comparator for SeqT elements. template <typename SeqT, typename Less = std::less<typename SeqT::value_type>> class SequenceToOffsetTable { - typedef typename SeqT::value_type ElemT; + using ElemT = typename SeqT::value_type; // Define a comparator for SeqT that sorts a suffix immediately before a // sequence with that suffix. @@ -58,7 +58,7 @@ class SequenceToOffsetTable { // Keep sequences ordered according to SeqLess so suffixes are easy to find. // Map each sequence to its offset in the table. - typedef std::map<SeqT, unsigned, SeqLess> SeqMap; + using SeqMap = std::map<SeqT, unsigned, SeqLess>; // Sequences added so far, with suffixes removed. SeqMap Seqs; @@ -162,7 +162,8 @@ public: /// emit - Print out the table as the body of an array initializer. /// Use the Print function to print elements. - void emit(raw_ostream &OS, void (*Print)(raw_ostream &, ElemT)) const { + void emit(raw_ostream &OS, + function_ref<void(raw_ostream &, ElemT)> Print) const { assert(IsLaidOut && "Call layout() before emit()"); for (const auto &[Seq, Offset] : Seqs) { OS << " /* " << Offset << " */ "; diff --git a/llvm/utils/TableGen/Basic/TableGen.cpp b/llvm/utils/TableGen/Basic/TableGen.cpp index edb7791..a655cbb 100644 --- a/llvm/utils/TableGen/Basic/TableGen.cpp +++ b/llvm/utils/TableGen/Basic/TableGen.cpp @@ -60,7 +60,9 @@ static TableGen::Emitter::Opt X[] = { true}, {"print-detailed-records", EmitDetailedRecords, "Print full details of all records to stdout"}, - {"null-backend", [](const RecordKeeper &Records, raw_ostream &OS) {}, + {"null-backend", + TableGen::Emitter::FnT( + [](const RecordKeeper &Records, raw_ostream &OS) {}), "Do nothing after parsing (useful for timing)"}, {"dump-json", EmitJSON, "Dump all records as machine-readable JSON"}, {"print-enums", printEnums, "Print enum values for a class"}, @@ -71,7 +73,8 @@ int tblgen_main(int argc, char **argv) { InitLLVM X(argc, argv); cl::ParseCommandLineOptions(argc, argv); - return TableGenMain(argv[0]); + MultiFileTableGenMainFn MainFn = nullptr; + return TableGenMain(argv[0], MainFn); } #ifndef __has_feature diff --git a/llvm/utils/TableGen/Basic/TargetLibraryInfoEmitter.cpp b/llvm/utils/TableGen/Basic/TargetLibraryInfoEmitter.cpp new file mode 100644 index 0000000..253d9df --- /dev/null +++ b/llvm/utils/TableGen/Basic/TargetLibraryInfoEmitter.cpp @@ -0,0 +1,185 @@ +//===- TargetLibraryInfoEmitter.cpp - Properties from TargetLibraryInfo.td ===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "SequenceToOffsetTable.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/SetTheory.h" +#include "llvm/TableGen/StringToOffsetTable.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <cstddef> + +#define DEBUG_TYPE "target-library-info-emitter" + +using namespace llvm; + +namespace { +class TargetLibraryInfoEmitter { +private: + const RecordKeeper &Records; + SmallVector<const Record *, 1024> AllTargetLibcalls; + +private: + void emitTargetLibraryInfoEnum(raw_ostream &OS) const; + void emitTargetLibraryInfoStringTable(raw_ostream &OS) const; + void emitTargetLibraryInfoSignatureTable(raw_ostream &OS) const; + +public: + TargetLibraryInfoEmitter(const RecordKeeper &R); + + void run(raw_ostream &OS); +}; + +} // End anonymous namespace. + +TargetLibraryInfoEmitter::TargetLibraryInfoEmitter(const RecordKeeper &R) + : Records(R) { + ArrayRef<const Record *> All = + Records.getAllDerivedDefinitions("TargetLibCall"); + AllTargetLibcalls.append(All.begin(), All.end()); + // Make sure that the records are in the same order as the input. + // TODO Find a better sorting order when all is migrated. + sort(AllTargetLibcalls, [](const Record *A, const Record *B) { + return A->getID() < B->getID(); + }); +} + +// Emits the LibFunc enumeration, which is an abstract name for each library +// function. +void TargetLibraryInfoEmitter::emitTargetLibraryInfoEnum( + raw_ostream &OS) const { + OS << "#ifdef GET_TARGET_LIBRARY_INFO_ENUM\n"; + OS << "#undef GET_TARGET_LIBRARY_INFO_ENUM\n"; + OS << "enum LibFunc : unsigned {\n"; + OS.indent(2) << "NotLibFunc = 0,\n"; + for (const auto *R : AllTargetLibcalls) { + OS.indent(2) << "LibFunc_" << R->getName() << ",\n"; + } + OS.indent(2) << "NumLibFuncs,\n"; + OS.indent(2) << "End_LibFunc = NumLibFuncs,\n"; + if (AllTargetLibcalls.size()) { + OS.indent(2) << "Begin_LibFunc = LibFunc_" + << AllTargetLibcalls[0]->getName() << ",\n"; + } else { + OS.indent(2) << "Begin_LibFunc = NotLibFunc,\n"; + } + OS << "};\n"; + OS << "#endif\n\n"; +} + +// The names of the functions are stored in a long string, along with support +// tables for accessing the offsets of the function names from the beginning of +// the string. +void TargetLibraryInfoEmitter::emitTargetLibraryInfoStringTable( + raw_ostream &OS) const { + llvm::StringToOffsetTable Table( + /*AppendZero=*/true, + "TargetLibraryInfoImpl::", /*UsePrefixForStorageMember=*/false); + for (const auto *R : AllTargetLibcalls) + Table.GetOrAddStringOffset(R->getValueAsString("String")); + + OS << "#ifdef GET_TARGET_LIBRARY_INFO_STRING_TABLE\n"; + OS << "#undef GET_TARGET_LIBRARY_INFO_STRING_TABLE\n"; + Table.EmitStringTableDef(OS, "StandardNamesStrTable"); + OS << "\n"; + size_t NumEl = AllTargetLibcalls.size() + 1; + OS << "const llvm::StringTable::Offset " + "TargetLibraryInfoImpl::StandardNamesOffsets[" + << NumEl + << "] = " + "{\n"; + OS.indent(2) << "0, //\n"; + for (const auto *R : AllTargetLibcalls) { + StringRef Str = R->getValueAsString("String"); + OS.indent(2) << Table.GetStringOffset(Str) << ", // " << Str << "\n"; + } + OS << "};\n"; + OS << "const uint8_t TargetLibraryInfoImpl::StandardNamesSizeTable[" << NumEl + << "] = {\n"; + OS << " 0,\n"; + for (const auto *R : AllTargetLibcalls) + OS.indent(2) << R->getValueAsString("String").size() << ",\n"; + OS << "};\n"; + OS << "#endif\n\n"; + OS << "#ifdef GET_TARGET_LIBRARY_INFO_IMPL_DECL\n"; + OS << "#undef GET_TARGET_LIBRARY_INFO_IMPL_DECL\n"; + OS << "LLVM_ABI static const llvm::StringTable StandardNamesStrTable;\n"; + OS << "LLVM_ABI static const llvm::StringTable::Offset StandardNamesOffsets[" + << NumEl << "];\n"; + OS << "LLVM_ABI static const uint8_t StandardNamesSizeTable[" << NumEl + << "];\n"; + OS << "#endif\n\n"; +} + +// Since there are much less type signatures then library functions, the type +// signatures are stored reusing existing entries. To access a table entry, an +// offset table is used. +void TargetLibraryInfoEmitter::emitTargetLibraryInfoSignatureTable( + raw_ostream &OS) const { + SmallVector<const Record *, 1024> FuncTypeArgs( + Records.getAllDerivedDefinitions("FuncArgType")); + + // Sort the records by ID. + sort(FuncTypeArgs, [](const Record *A, const Record *B) { + return A->getID() < B->getID(); + }); + + using Signature = std::vector<StringRef>; + SequenceToOffsetTable<Signature> SignatureTable("NoFuncArgType"); + auto GetSignature = [](const Record *R) -> Signature { + const auto *Tys = R->getValueAsListInit("ArgumentTypes"); + Signature Sig; + Sig.reserve(Tys->size() + 1); + const Record *RetType = R->getValueAsOptionalDef("ReturnType"); + if (RetType) + Sig.push_back(RetType->getName()); + for (unsigned I = 0, E = Tys->size(); I < E; ++I) { + Sig.push_back(Tys->getElementAsRecord(I)->getName()); + } + return Sig; + }; + Signature NoFuncSig({StringRef("Void")}); + SignatureTable.add(NoFuncSig); + for (const auto *R : AllTargetLibcalls) + SignatureTable.add(GetSignature(R)); + SignatureTable.layout(); + + OS << "#ifdef GET_TARGET_LIBRARY_INFO_SIGNATURE_TABLE\n"; + OS << "#undef GET_TARGET_LIBRARY_INFO_SIGNATURE_TABLE\n"; + OS << "enum FuncArgTypeID : char {\n"; + OS.indent(2) << "NoFuncArgType = 0,\n"; + for (const auto *R : FuncTypeArgs) { + OS.indent(2) << R->getName() << ",\n"; + } + OS << "};\n"; + OS << "static const FuncArgTypeID SignatureTable[] = {\n"; + SignatureTable.emit(OS, [](raw_ostream &OS, StringRef E) { OS << E; }); + OS << "};\n"; + OS << "static const uint16_t SignatureOffset[] = {\n"; + OS.indent(2) << SignatureTable.get(NoFuncSig) << ", //\n"; + for (const auto *R : AllTargetLibcalls) { + OS.indent(2) << SignatureTable.get(GetSignature(R)) << ", // " + << R->getName() << "\n"; + } + OS << "};\n"; + OS << "#endif\n\n"; +} + +void TargetLibraryInfoEmitter::run(raw_ostream &OS) { + emitSourceFileHeader("Target Library Info Source Fragment", OS, Records); + + emitTargetLibraryInfoEnum(OS); + emitTargetLibraryInfoStringTable(OS); + emitTargetLibraryInfoSignatureTable(OS); +} + +static TableGen::Emitter::OptClass<TargetLibraryInfoEmitter> + X("gen-target-library-info", "Generate TargetLibraryInfo"); diff --git a/llvm/utils/TableGen/Basic/VTEmitter.cpp b/llvm/utils/TableGen/Basic/VTEmitter.cpp index 301b27d..87f5f4b 100644 --- a/llvm/utils/TableGen/Basic/VTEmitter.cpp +++ b/llvm/utils/TableGen/Basic/VTEmitter.cpp @@ -91,11 +91,14 @@ void VTEmitter::run(raw_ostream &OS) { emitSourceFileHeader("ValueTypes Source Fragment", OS, Records); std::vector<const Record *> VTsByNumber{512}; - for (auto *VT : Records.getAllDerivedDefinitions("ValueType")) { - auto Number = VT->getValueAsInt("Value"); - assert(0 <= Number && Number < (int)VTsByNumber.size() && - "ValueType should be uint16_t"); - assert(!VTsByNumber[Number] && "Duplicate ValueType"); + unsigned Number = 0; + std::vector<const Record *> Defs( + Records.getAllDerivedDefinitions("ValueType")); + // Emit VTs in the order they were declared so that VTRanges stay contiguous. + llvm::sort(Defs, LessRecordByID()); + for (auto *VT : Defs) { + ++Number; + assert(Number < VTsByNumber.size() && "ValueType should be uint16_t"); VTsByNumber[Number] = VT; } @@ -120,13 +123,12 @@ void VTEmitter::run(raw_ostream &OS) { } }; - OS << "#ifdef GET_VT_ATTR // (Ty, n, sz, Any, Int, FP, Vec, Sc, Tup, NF, " + OS << "#ifdef GET_VT_ATTR // (Ty, sz, Any, Int, FP, Vec, Sc, Tup, NF, " "NElem, EltTy)\n"; for (const auto *VT : VTsByNumber) { if (!VT) continue; auto Name = VT->getValueAsString("LLVMName"); - auto Value = VT->getValueAsInt("Value"); bool IsInteger = VT->getValueAsBit("isInteger"); bool IsFP = VT->getValueAsBit("isFP"); bool IsVector = VT->getValueAsBit("isVector"); @@ -158,7 +160,6 @@ void VTEmitter::run(raw_ostream &OS) { // clang-format off OS << " GET_VT_ATTR(" << Name << ", " - << Value << ", " << VT->getValueAsInt("Size") << ", " << VT->getValueAsBit("isOverloaded") << ", " << (IsInteger ? Name[0] == 'i' ? 3 : 1 : 0) << ", " |
