410 lines · cpp
1//===- MCSubtargetInfo.cpp - Subtarget Information ------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/MC/MCSubtargetInfo.h"10#include "llvm/ADT/ArrayRef.h"11#include "llvm/ADT/StringRef.h"12#include "llvm/ADT/Twine.h"13#include "llvm/MC/MCInstrItineraries.h"14#include "llvm/MC/MCSchedule.h"15#include "llvm/Support/Format.h"16#include "llvm/Support/raw_ostream.h"17#include "llvm/TargetParser/SubtargetFeature.h"18#include <algorithm>19#include <cassert>20#include <cstring>21#include <optional>22 23using namespace llvm;24 25/// Find KV in array using binary search.26template <typename T>27static const T *Find(StringRef S, ArrayRef<T> A) {28 // Binary search the array29 auto F = llvm::lower_bound(A, S);30 // If not found then return NULL31 if (F == A.end() || StringRef(F->Key) != S) return nullptr;32 // Return the found array item33 return F;34}35 36/// For each feature that is (transitively) implied by this feature, set it.37static38void SetImpliedBits(FeatureBitset &Bits, const FeatureBitset &Implies,39 ArrayRef<SubtargetFeatureKV> FeatureTable) {40 // OR the Implies bits in outside the loop. This allows the Implies for CPUs41 // which might imply features not in FeatureTable to use this.42 Bits |= Implies;43 for (const SubtargetFeatureKV &FE : FeatureTable)44 if (Implies.test(FE.Value))45 SetImpliedBits(Bits, FE.Implies.getAsBitset(), FeatureTable);46}47 48/// For each feature that (transitively) implies this feature, clear it.49static50void ClearImpliedBits(FeatureBitset &Bits, unsigned Value,51 ArrayRef<SubtargetFeatureKV> FeatureTable) {52 for (const SubtargetFeatureKV &FE : FeatureTable) {53 if (FE.Implies.getAsBitset().test(Value)) {54 Bits.reset(FE.Value);55 ClearImpliedBits(Bits, FE.Value, FeatureTable);56 }57 }58}59 60static void ApplyFeatureFlag(FeatureBitset &Bits, StringRef Feature,61 ArrayRef<SubtargetFeatureKV> FeatureTable) {62 assert(SubtargetFeatures::hasFlag(Feature) &&63 "Feature flags should start with '+' or '-'");64 65 // Find feature in table.66 const SubtargetFeatureKV *FeatureEntry =67 Find(SubtargetFeatures::StripFlag(Feature), FeatureTable);68 // If there is a match69 if (FeatureEntry) {70 // Enable/disable feature in bits71 if (SubtargetFeatures::isEnabled(Feature)) {72 Bits.set(FeatureEntry->Value);73 74 // For each feature that this implies, set it.75 SetImpliedBits(Bits, FeatureEntry->Implies.getAsBitset(), FeatureTable);76 } else {77 Bits.reset(FeatureEntry->Value);78 79 // For each feature that implies this, clear it.80 ClearImpliedBits(Bits, FeatureEntry->Value, FeatureTable);81 }82 } else {83 errs() << "'" << Feature << "' is not a recognized feature for this target"84 << " (ignoring feature)\n";85 }86}87 88/// Return the length of the longest entry in the table.89static size_t getLongestEntryLength(ArrayRef<SubtargetFeatureKV> Table) {90 size_t MaxLen = 0;91 for (auto &I : Table)92 MaxLen = std::max(MaxLen, std::strlen(I.Key));93 return MaxLen;94}95 96static size_t getLongestEntryLength(ArrayRef<StringRef> Table) {97 size_t MaxLen = 0;98 for (StringRef I : Table)99 MaxLen = std::max(MaxLen, I.size());100 return MaxLen;101}102 103/// Display help for feature and mcpu choices.104static void Help(ArrayRef<StringRef> CPUNames,105 ArrayRef<SubtargetFeatureKV> FeatTable) {106 // the static variable ensures that the help information only gets107 // printed once even though a target machine creates multiple subtargets108 static bool PrintOnce = false;109 if (PrintOnce) {110 return;111 }112 113 // Determine the length of the longest CPU and Feature entries.114 unsigned MaxCPULen = getLongestEntryLength(CPUNames);115 unsigned MaxFeatLen = getLongestEntryLength(FeatTable);116 117 // Print the CPU table.118 errs() << "Available CPUs for this target:\n\n";119 for (auto &CPUName : CPUNames) {120 // Skip apple-latest, as that's only meant to be used in121 // disassemblers/debuggers, and we don't want normal code to be built with122 // it as an -mcpu=123 if (CPUName == "apple-latest")124 continue;125 errs() << format(" %-*s - Select the %s processor.\n", MaxCPULen,126 CPUName.str().c_str(), CPUName.str().c_str());127 }128 errs() << '\n';129 130 // Print the Feature table.131 errs() << "Available features for this target:\n\n";132 for (auto &Feature : FeatTable)133 errs() << format(" %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc);134 errs() << '\n';135 136 errs() << "Use +feature to enable a feature, or -feature to disable it.\n"137 "For example, llc -mcpu=mycpu -mattr=+feature1,-feature2\n";138 139 PrintOnce = true;140}141 142/// Display help for mcpu choices only143static void cpuHelp(ArrayRef<StringRef> CPUNames) {144 // the static variable ensures that the help information only gets145 // printed once even though a target machine creates multiple subtargets146 static bool PrintOnce = false;147 if (PrintOnce) {148 return;149 }150 151 // Print the CPU table.152 errs() << "Available CPUs for this target:\n\n";153 for (auto &CPU : CPUNames) {154 // Skip apple-latest, as that's only meant to be used in155 // disassemblers/debuggers, and we don't want normal code to be built with156 // it as an -mcpu=157 if (CPU == "apple-latest")158 continue;159 errs() << "\t" << CPU << "\n";160 }161 errs() << '\n';162 163 errs() << "Use -mcpu or -mtune to specify the target's processor.\n"164 "For example, clang --target=aarch64-unknown-linux-gnu "165 "-mcpu=cortex-a35\n";166 167 PrintOnce = true;168}169 170static FeatureBitset getFeatures(MCSubtargetInfo &STI, StringRef CPU,171 StringRef TuneCPU, StringRef FS,172 ArrayRef<StringRef> ProcNames,173 ArrayRef<SubtargetSubTypeKV> ProcDesc,174 ArrayRef<SubtargetFeatureKV> ProcFeatures) {175 SubtargetFeatures Features(FS);176 177 if (ProcDesc.empty() || ProcFeatures.empty())178 return FeatureBitset();179 180 assert(llvm::is_sorted(ProcDesc) && "CPU table is not sorted");181 assert(llvm::is_sorted(ProcFeatures) && "CPU features table is not sorted");182 // Resulting bits183 FeatureBitset Bits;184 185 // Check if help is needed186 if (CPU == "help")187 Help(ProcNames, ProcFeatures);188 189 // Find CPU entry if CPU name is specified.190 else if (!CPU.empty()) {191 const SubtargetSubTypeKV *CPUEntry = Find(CPU, ProcDesc);192 193 // If there is a match194 if (CPUEntry) {195 // Set the features implied by this CPU feature, if any.196 SetImpliedBits(Bits, CPUEntry->Implies.getAsBitset(), ProcFeatures);197 } else {198 errs() << "'" << CPU << "' is not a recognized processor for this target"199 << " (ignoring processor)\n";200 }201 }202 203 if (!TuneCPU.empty()) {204 const SubtargetSubTypeKV *CPUEntry = Find(TuneCPU, ProcDesc);205 206 // If there is a match207 if (CPUEntry) {208 // Set the features implied by this CPU feature, if any.209 SetImpliedBits(Bits, CPUEntry->TuneImplies.getAsBitset(), ProcFeatures);210 } else if (TuneCPU != CPU) {211 errs() << "'" << TuneCPU << "' is not a recognized processor for this "212 << "target (ignoring processor)\n";213 }214 }215 216 // Iterate through each feature217 for (const std::string &Feature : Features.getFeatures()) {218 // Check for help219 if (Feature == "+help")220 Help(ProcNames, ProcFeatures);221 else if (Feature == "+cpuhelp")222 cpuHelp(ProcNames);223 else224 ApplyFeatureFlag(Bits, Feature, ProcFeatures);225 }226 227 return Bits;228}229 230void MCSubtargetInfo::InitMCProcessorInfo(StringRef CPU, StringRef TuneCPU,231 StringRef FS) {232 FeatureBits =233 getFeatures(*this, CPU, TuneCPU, FS, ProcNames, ProcDesc, ProcFeatures);234 FeatureString = std::string(FS);235 236 if (!TuneCPU.empty())237 CPUSchedModel = &getSchedModelForCPU(TuneCPU);238 else239 CPUSchedModel = &MCSchedModel::Default;240}241 242void MCSubtargetInfo::setDefaultFeatures(StringRef CPU, StringRef TuneCPU,243 StringRef FS) {244 FeatureBits =245 getFeatures(*this, CPU, TuneCPU, FS, ProcNames, ProcDesc, ProcFeatures);246 FeatureString = std::string(FS);247}248 249MCSubtargetInfo::MCSubtargetInfo(250 const Triple &TT, StringRef C, StringRef TC, StringRef FS,251 ArrayRef<StringRef> PN, ArrayRef<SubtargetFeatureKV> PF,252 ArrayRef<SubtargetSubTypeKV> PD, const MCWriteProcResEntry *WPR,253 const MCWriteLatencyEntry *WL, const MCReadAdvanceEntry *RA,254 const InstrStage *IS, const unsigned *OC, const unsigned *FP)255 : TargetTriple(TT), CPU(std::string(C)), TuneCPU(std::string(TC)),256 ProcNames(PN), ProcFeatures(PF), ProcDesc(PD), WriteProcResTable(WPR),257 WriteLatencyTable(WL), ReadAdvanceTable(RA), Stages(IS),258 OperandCycles(OC), ForwardingPaths(FP) {259 InitMCProcessorInfo(CPU, TuneCPU, FS);260}261 262FeatureBitset MCSubtargetInfo::ToggleFeature(uint64_t FB) {263 FeatureBits.flip(FB);264 return FeatureBits;265}266 267FeatureBitset MCSubtargetInfo::ToggleFeature(const FeatureBitset &FB) {268 FeatureBits ^= FB;269 return FeatureBits;270}271 272FeatureBitset MCSubtargetInfo::SetFeatureBitsTransitively(273 const FeatureBitset &FB) {274 SetImpliedBits(FeatureBits, FB, ProcFeatures);275 return FeatureBits;276}277 278FeatureBitset MCSubtargetInfo::ClearFeatureBitsTransitively(279 const FeatureBitset &FB) {280 for (unsigned I = 0, E = FB.size(); I < E; I++) {281 if (FB[I]) {282 FeatureBits.reset(I);283 ClearImpliedBits(FeatureBits, I, ProcFeatures);284 }285 }286 return FeatureBits;287}288 289FeatureBitset MCSubtargetInfo::ToggleFeature(StringRef Feature) {290 // Find feature in table.291 const SubtargetFeatureKV *FeatureEntry =292 Find(SubtargetFeatures::StripFlag(Feature), ProcFeatures);293 // If there is a match294 if (FeatureEntry) {295 if (FeatureBits.test(FeatureEntry->Value)) {296 FeatureBits.reset(FeatureEntry->Value);297 // For each feature that implies this, clear it.298 ClearImpliedBits(FeatureBits, FeatureEntry->Value, ProcFeatures);299 } else {300 FeatureBits.set(FeatureEntry->Value);301 302 // For each feature that this implies, set it.303 SetImpliedBits(FeatureBits, FeatureEntry->Implies.getAsBitset(),304 ProcFeatures);305 }306 } else {307 errs() << "'" << Feature << "' is not a recognized feature for this target"308 << " (ignoring feature)\n";309 }310 311 return FeatureBits;312}313 314FeatureBitset MCSubtargetInfo::ApplyFeatureFlag(StringRef FS) {315 ::ApplyFeatureFlag(FeatureBits, FS, ProcFeatures);316 return FeatureBits;317}318 319bool MCSubtargetInfo::checkFeatures(StringRef FS) const {320 SubtargetFeatures T(FS);321 return all_of(T.getFeatures(), [this](const std::string &F) {322 assert(SubtargetFeatures::hasFlag(F) &&323 "Feature flags should start with '+' or '-'");324 const SubtargetFeatureKV *FeatureEntry =325 Find(SubtargetFeatures::StripFlag(F), ProcFeatures);326 if (!FeatureEntry)327 report_fatal_error(Twine("'") + F +328 "' is not a recognized feature for this target");329 330 return FeatureBits.test(FeatureEntry->Value) ==331 SubtargetFeatures::isEnabled(F);332 });333}334 335const MCSchedModel &MCSubtargetInfo::getSchedModelForCPU(StringRef CPU) const {336 assert(llvm::is_sorted(ProcDesc) &&337 "Processor machine model table is not sorted");338 339 // Find entry340 const SubtargetSubTypeKV *CPUEntry = Find(CPU, ProcDesc);341 342 if (!CPUEntry) {343 if (CPU != "help") // Don't error if the user asked for help.344 errs() << "'" << CPU345 << "' is not a recognized processor for this target"346 << " (ignoring processor)\n";347 return MCSchedModel::Default;348 }349 assert(CPUEntry->SchedModel && "Missing processor SchedModel value");350 return *CPUEntry->SchedModel;351}352 353InstrItineraryData354MCSubtargetInfo::getInstrItineraryForCPU(StringRef CPU) const {355 const MCSchedModel &SchedModel = getSchedModelForCPU(CPU);356 return InstrItineraryData(SchedModel, Stages, OperandCycles, ForwardingPaths);357}358 359void MCSubtargetInfo::initInstrItins(InstrItineraryData &InstrItins) const {360 InstrItins = InstrItineraryData(getSchedModel(), Stages, OperandCycles,361 ForwardingPaths);362}363 364std::vector<SubtargetFeatureKV>365MCSubtargetInfo::getEnabledProcessorFeatures() const {366 std::vector<SubtargetFeatureKV> EnabledFeatures;367 auto IsEnabled = [&](const SubtargetFeatureKV &FeatureKV) {368 return FeatureBits.test(FeatureKV.Value);369 };370 llvm::copy_if(ProcFeatures, std::back_inserter(EnabledFeatures), IsEnabled);371 return EnabledFeatures;372}373 374std::optional<unsigned> MCSubtargetInfo::getCacheSize(unsigned Level) const {375 return std::nullopt;376}377 378std::optional<unsigned>379MCSubtargetInfo::getCacheAssociativity(unsigned Level) const {380 return std::nullopt;381}382 383std::optional<unsigned>384MCSubtargetInfo::getCacheLineSize(unsigned Level) const {385 return std::nullopt;386}387 388unsigned MCSubtargetInfo::getPrefetchDistance() const {389 return 0;390}391 392unsigned MCSubtargetInfo::getMaxPrefetchIterationsAhead() const {393 return UINT_MAX;394}395 396bool MCSubtargetInfo::enableWritePrefetching() const {397 return false;398}399 400unsigned MCSubtargetInfo::getMinPrefetchStride(unsigned NumMemAccesses,401 unsigned NumStridedMemAccesses,402 unsigned NumPrefetches,403 bool HasCall) const {404 return 1;405}406 407bool MCSubtargetInfo::shouldPrefetchAddressSpace(unsigned AS) const {408 return !AS;409}410