| //===- TargetFeaturesEmitter.cpp - Generate CPU Target feature ----===// | |
| // | |
| // 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This tablegen backend exports cpu target features | |
| // and cpu sub-type. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "TargetFeaturesEmitter.h" | |
| #include "llvm/TableGen/CodeGenHelpers.h" | |
| #include "llvm/TableGen/Error.h" | |
| #include "llvm/TableGen/TableGenBackend.h" | |
| #include "llvm/TargetParser/SubtargetFeature.h" | |
| using namespace llvm; | |
| using FeatureMapTy = DenseMap<const Record *, unsigned>; | |
| using ConstRecVec = std::vector<const Record *>; | |
| TargetFeaturesEmitter::TargetFeaturesEmitter(const RecordKeeper &R) | |
| : Records(R) { | |
| ArrayRef<const Record *> Targets = Records.getAllDerivedDefinitions("Target"); | |
| if (Targets.size() == 0) | |
| PrintFatalError("No 'Target' subclasses defined!"); | |
| if (Targets.size() != 1) | |
| PrintFatalError("Multiple subclasses of Target defined!"); | |
| Target = Targets[0]->getName(); | |
| } | |
| FeatureMapTy TargetFeaturesEmitter::enumeration(raw_ostream &OS) { | |
| ArrayRef<const Record *> DefList = | |
| Records.getAllDerivedDefinitions("SubtargetFeature"); | |
| unsigned N = DefList.size(); | |
| if (N == 0) | |
| return FeatureMapTy(); | |
| if (N + 1 > MAX_SUBTARGET_FEATURES) | |
| PrintFatalError( | |
| "Too many subtarget features! Bump MAX_SUBTARGET_FEATURES."); | |
| NamespaceEmitter NS(OS, Target); | |
| OS << "enum {\n"; | |
| FeatureMapTy FeatureMap; | |
| for (unsigned I = 0; I < N; ++I) { | |
| const Record *Def = DefList[I]; | |
| // Print the Feature Name. | |
| OS << " " << Def->getName() << " = " << I << ",\n"; | |
| FeatureMap[Def] = I; | |
| } | |
| OS << " " << "NumSubtargetFeatures = " << N << "\n"; | |
| // Close enumeration. | |
| OS << "};\n"; | |
| return FeatureMap; | |
| } | |
| void TargetFeaturesEmitter::printFeatureMask( | |
| raw_ostream &OS, ArrayRef<const Record *> FeatureList, | |
| const FeatureMapTy &FeatureMap) { | |
| std::array<uint64_t, MAX_SUBTARGET_WORDS> Mask = {}; | |
| for (const Record *Feature : FeatureList) { | |
| unsigned Bit = FeatureMap.lookup(Feature); | |
| Mask[Bit / 64] |= 1ULL << (Bit % 64); | |
| } | |
| OS << "{ { { "; | |
| for (unsigned I = 0; I != Mask.size(); ++I) { | |
| OS << "0x"; | |
| OS.write_hex(Mask[I]); | |
| OS << "ULL, "; | |
| } | |
| OS << "} } }"; | |
| } | |
| void TargetFeaturesEmitter::printFeatureKeyValues( | |
| raw_ostream &OS, const FeatureMapTy &FeatureMap) { | |
| std::vector<const Record *> FeatureList = | |
| Records.getAllDerivedDefinitions("SubtargetFeature"); | |
| // Remove features with empty name. | |
| llvm::erase_if(FeatureList, [](const Record *Rec) { | |
| return Rec->getValueAsString("Name").empty(); | |
| }); | |
| if (FeatureList.empty()) | |
| return; | |
| llvm::sort(FeatureList, LessRecordFieldName()); | |
| // Begin feature table. | |
| OS << "// Sorted (by key) array of values for CPU features.\n" | |
| << "extern const llvm::BasicSubtargetFeatureKV " << "Basic" << Target | |
| << "FeatureKV[] = {\n"; | |
| for (const Record *Feature : FeatureList) { | |
| StringRef Name = Feature->getName(); | |
| StringRef ValueName = Feature->getValueAsString("Name"); | |
| OS << " { " << "\"" << ValueName << "\", " << Target << "::" << Name | |
| << ", "; | |
| ConstRecVec ImpliesList = Feature->getValueAsListOfDefs("Implies"); | |
| printFeatureMask(OS, ImpliesList, FeatureMap); | |
| OS << " },\n"; | |
| } | |
| // End feature table. | |
| OS << "};\n"; | |
| } | |
| void TargetFeaturesEmitter::printCPUKeyValues(raw_ostream &OS, | |
| const FeatureMapTy &FeatureMap) { | |
| // Gather and sort processor information | |
| std::vector<const Record *> ProcessorList = | |
| Records.getAllDerivedDefinitions("Processor"); | |
| llvm::sort(ProcessorList, LessRecordFieldName()); | |
| // Begin processor table. | |
| OS << "// Sorted (by key) array of values for CPU subtype.\n" | |
| << "extern const llvm::BasicSubtargetSubTypeKV " << "Basic" << Target | |
| << "SubTypeKV[] = {\n"; | |
| for (const Record *Processor : ProcessorList) { | |
| StringRef Name = Processor->getValueAsString("Name"); | |
| ConstRecVec FeatureList = Processor->getValueAsListOfDefs("Features"); | |
| OS << " { " << "\"" << Name << "\", "; | |
| printFeatureMask(OS, FeatureList, FeatureMap); | |
| OS << " },\n"; | |
| } | |
| // End processor table. | |
| OS << "};\n"; | |
| } | |
| void TargetFeaturesEmitter::run(raw_ostream &OS) { | |
| OS << "// Autogenerated by TargetFeatureEmitter.cpp\n\n"; | |
| FeatureMapTy FeatureMap; | |
| { | |
| IfDefEmitter IfDef(OS, "GET_SUBTARGETFEATURES_ENUM"); | |
| NamespaceEmitter NS(OS, "llvm"); | |
| FeatureMap = enumeration(OS); | |
| } | |
| { | |
| IfDefEmitter IfDef(OS, "GET_SUBTARGETFEATURES_KV"); | |
| NamespaceEmitter NS(OS, "llvm"); | |
| printFeatureKeyValues(OS, FeatureMap); | |
| OS << "\n"; | |
| printCPUKeyValues(OS, FeatureMap); | |
| OS << "\n"; | |
| } | |
| } | |
| static TableGen::Emitter::OptClass<TargetFeaturesEmitter> | |
| X("gen-target-features", "Generate subtarget enumerations"); |