//===- 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; using ConstRecVec = std::vector; TargetFeaturesEmitter::TargetFeaturesEmitter(const RecordKeeper &R) : Records(R) { ArrayRef 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 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 FeatureList, const FeatureMapTy &FeatureMap) { std::array 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 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 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 X("gen-target-features", "Generate subtarget enumerations");