| //===- 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/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."); |
| |
| OS << "namespace " << Target << " {\n"; |
| |
| 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 and namespace |
| OS << "};\n"; |
| OS << "} // end namespace " << Target << "\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"; |
| |
| OS << "\n#ifdef GET_SUBTARGETFEATURES_ENUM\n"; |
| OS << "#undef GET_SUBTARGETFEATURES_ENUM\n\n"; |
| |
| OS << "namespace llvm {\n"; |
| auto FeatureMap = enumeration(OS); |
| OS << "} // end namespace llvm\n\n"; |
| OS << "#endif // GET_SUBTARGETFEATURES_ENUM\n\n"; |
| |
| OS << "\n#ifdef GET_SUBTARGETFEATURES_KV\n"; |
| OS << "#undef GET_SUBTARGETFEATURES_KV\n\n"; |
| |
| OS << "namespace llvm {\n"; |
| printFeatureKeyValues(OS, FeatureMap); |
| OS << "\n"; |
| |
| printCPUKeyValues(OS, FeatureMap); |
| OS << "\n"; |
| OS << "} // end namespace llvm\n\n"; |
| OS << "#endif // GET_SUBTARGETFEATURES_KV\n\n"; |
| } |
| |
| static TableGen::Emitter::OptClass<TargetFeaturesEmitter> |
| X("gen-target-features", "Generate subtarget enumerations"); |