117a519f9SDimitry Andric //===- SubtargetFeature.cpp - CPU characteristics Implementation ----------===// 217a519f9SDimitry Andric // 317a519f9SDimitry Andric // The LLVM Compiler Infrastructure 417a519f9SDimitry Andric // 517a519f9SDimitry Andric // This file is distributed under the University of Illinois Open Source 617a519f9SDimitry Andric // License. See LICENSE.TXT for details. 717a519f9SDimitry Andric // 817a519f9SDimitry Andric //===----------------------------------------------------------------------===// 917a519f9SDimitry Andric // 1017a519f9SDimitry Andric // This file implements the SubtargetFeature interface. 1117a519f9SDimitry Andric // 1217a519f9SDimitry Andric //===----------------------------------------------------------------------===// 1317a519f9SDimitry Andric 1417a519f9SDimitry Andric #include "llvm/MC/SubtargetFeature.h" 1517a519f9SDimitry Andric #include "llvm/Support/Debug.h" 16dff0c46cSDimitry Andric #include "llvm/Support/Format.h" 1717a519f9SDimitry Andric #include "llvm/Support/raw_ostream.h" 1817a519f9SDimitry Andric #include <algorithm> 1917a519f9SDimitry Andric #include <cassert> 2017a519f9SDimitry Andric #include <cctype> 2117a519f9SDimitry Andric #include <cstdlib> 2217a519f9SDimitry Andric using namespace llvm; 2317a519f9SDimitry Andric 2417a519f9SDimitry Andric //===----------------------------------------------------------------------===// 2517a519f9SDimitry Andric // Static Helper Functions 2617a519f9SDimitry Andric //===----------------------------------------------------------------------===// 2717a519f9SDimitry Andric 2817a519f9SDimitry Andric /// hasFlag - Determine if a feature has a flag; '+' or '-' 2917a519f9SDimitry Andric /// 3017a519f9SDimitry Andric static inline bool hasFlag(const StringRef Feature) { 3117a519f9SDimitry Andric assert(!Feature.empty() && "Empty string"); 3217a519f9SDimitry Andric // Get first character 3317a519f9SDimitry Andric char Ch = Feature[0]; 3417a519f9SDimitry Andric // Check if first character is '+' or '-' flag 3517a519f9SDimitry Andric return Ch == '+' || Ch =='-'; 3617a519f9SDimitry Andric } 3717a519f9SDimitry Andric 3817a519f9SDimitry Andric /// StripFlag - Return string stripped of flag. 3917a519f9SDimitry Andric /// 4017a519f9SDimitry Andric static inline std::string StripFlag(const StringRef Feature) { 4117a519f9SDimitry Andric return hasFlag(Feature) ? Feature.substr(1) : Feature; 4217a519f9SDimitry Andric } 4317a519f9SDimitry Andric 4417a519f9SDimitry Andric /// isEnabled - Return true if enable flag; '+'. 4517a519f9SDimitry Andric /// 4617a519f9SDimitry Andric static inline bool isEnabled(const StringRef Feature) { 4717a519f9SDimitry Andric assert(!Feature.empty() && "Empty string"); 4817a519f9SDimitry Andric // Get first character 4917a519f9SDimitry Andric char Ch = Feature[0]; 5017a519f9SDimitry Andric // Check if first character is '+' for enabled 5117a519f9SDimitry Andric return Ch == '+'; 5217a519f9SDimitry Andric } 5317a519f9SDimitry Andric 5417a519f9SDimitry Andric /// Split - Splits a string of comma separated items in to a vector of strings. 5517a519f9SDimitry Andric /// 5617a519f9SDimitry Andric static void Split(std::vector<std::string> &V, const StringRef S) { 5791bc56edSDimitry Andric SmallVector<StringRef, 2> Tmp; 5891bc56edSDimitry Andric S.split(Tmp, ",", -1, false /* KeepEmpty */); 5991bc56edSDimitry Andric V.assign(Tmp.begin(), Tmp.end()); 6017a519f9SDimitry Andric } 6117a519f9SDimitry Andric 6217a519f9SDimitry Andric /// Join a vector of strings to a string with a comma separating each element. 6317a519f9SDimitry Andric /// 6417a519f9SDimitry Andric static std::string Join(const std::vector<std::string> &V) { 6517a519f9SDimitry Andric // Start with empty string. 6617a519f9SDimitry Andric std::string Result; 6717a519f9SDimitry Andric // If the vector is not empty 6817a519f9SDimitry Andric if (!V.empty()) { 6917a519f9SDimitry Andric // Start with the first feature 7017a519f9SDimitry Andric Result = V[0]; 7117a519f9SDimitry Andric // For each successive feature 7217a519f9SDimitry Andric for (size_t i = 1; i < V.size(); i++) { 7317a519f9SDimitry Andric // Add a comma 7417a519f9SDimitry Andric Result += ","; 7517a519f9SDimitry Andric // Add the feature 7617a519f9SDimitry Andric Result += V[i]; 7717a519f9SDimitry Andric } 7817a519f9SDimitry Andric } 7917a519f9SDimitry Andric // Return the features string 8017a519f9SDimitry Andric return Result; 8117a519f9SDimitry Andric } 8217a519f9SDimitry Andric 8317a519f9SDimitry Andric /// Adding features. 8491bc56edSDimitry Andric void SubtargetFeatures::AddFeature(const StringRef String) { 8591bc56edSDimitry Andric // Don't add empty features or features we already have. 8691bc56edSDimitry Andric if (!String.empty()) 8791bc56edSDimitry Andric // Convert to lowercase, prepend flag if we don't already have a flag. 8891bc56edSDimitry Andric Features.push_back(hasFlag(String) ? String.str() : "+" + String.lower()); 8917a519f9SDimitry Andric } 9017a519f9SDimitry Andric 9117a519f9SDimitry Andric /// Find KV in array using binary search. 9291bc56edSDimitry Andric static const SubtargetFeatureKV *Find(StringRef S, 9391bc56edSDimitry Andric ArrayRef<SubtargetFeatureKV> A) { 9417a519f9SDimitry Andric // Binary search the array 9591bc56edSDimitry Andric auto F = std::lower_bound(A.begin(), A.end(), S); 9617a519f9SDimitry Andric // If not found then return NULL 9791bc56edSDimitry Andric if (F == A.end() || StringRef(F->Key) != S) return nullptr; 9817a519f9SDimitry Andric // Return the found array item 9917a519f9SDimitry Andric return F; 10017a519f9SDimitry Andric } 10117a519f9SDimitry Andric 10217a519f9SDimitry Andric /// getLongestEntryLength - Return the length of the longest entry in the table. 10317a519f9SDimitry Andric /// 10491bc56edSDimitry Andric static size_t getLongestEntryLength(ArrayRef<SubtargetFeatureKV> Table) { 10517a519f9SDimitry Andric size_t MaxLen = 0; 10691bc56edSDimitry Andric for (auto &I : Table) 10791bc56edSDimitry Andric MaxLen = std::max(MaxLen, std::strlen(I.Key)); 10817a519f9SDimitry Andric return MaxLen; 10917a519f9SDimitry Andric } 11017a519f9SDimitry Andric 11117a519f9SDimitry Andric /// Display help for feature choices. 11217a519f9SDimitry Andric /// 11391bc56edSDimitry Andric static void Help(ArrayRef<SubtargetFeatureKV> CPUTable, 11491bc56edSDimitry Andric ArrayRef<SubtargetFeatureKV> FeatTable) { 11517a519f9SDimitry Andric // Determine the length of the longest CPU and Feature entries. 11691bc56edSDimitry Andric unsigned MaxCPULen = getLongestEntryLength(CPUTable); 11791bc56edSDimitry Andric unsigned MaxFeatLen = getLongestEntryLength(FeatTable); 11817a519f9SDimitry Andric 11917a519f9SDimitry Andric // Print the CPU table. 12017a519f9SDimitry Andric errs() << "Available CPUs for this target:\n\n"; 12191bc56edSDimitry Andric for (auto &CPU : CPUTable) 12291bc56edSDimitry Andric errs() << format(" %-*s - %s.\n", MaxCPULen, CPU.Key, CPU.Desc); 123dff0c46cSDimitry Andric errs() << '\n'; 12417a519f9SDimitry Andric 12517a519f9SDimitry Andric // Print the Feature table. 12617a519f9SDimitry Andric errs() << "Available features for this target:\n\n"; 12791bc56edSDimitry Andric for (auto &Feature : FeatTable) 12891bc56edSDimitry Andric errs() << format(" %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc); 129dff0c46cSDimitry Andric errs() << '\n'; 13017a519f9SDimitry Andric 13117a519f9SDimitry Andric errs() << "Use +feature to enable a feature, or -feature to disable it.\n" 132dff0c46cSDimitry Andric "For example, llc -mcpu=mycpu -mattr=+feature1,-feature2\n"; 13317a519f9SDimitry Andric } 13417a519f9SDimitry Andric 13517a519f9SDimitry Andric //===----------------------------------------------------------------------===// 13617a519f9SDimitry Andric // SubtargetFeatures Implementation 13717a519f9SDimitry Andric //===----------------------------------------------------------------------===// 13817a519f9SDimitry Andric 13917a519f9SDimitry Andric SubtargetFeatures::SubtargetFeatures(const StringRef Initial) { 14017a519f9SDimitry Andric // Break up string into separate features 14117a519f9SDimitry Andric Split(Features, Initial); 14217a519f9SDimitry Andric } 14317a519f9SDimitry Andric 14417a519f9SDimitry Andric 14517a519f9SDimitry Andric std::string SubtargetFeatures::getString() const { 14617a519f9SDimitry Andric return Join(Features); 14717a519f9SDimitry Andric } 14817a519f9SDimitry Andric 14917a519f9SDimitry Andric /// SetImpliedBits - For each feature that is (transitively) implied by this 15017a519f9SDimitry Andric /// feature, set it. 15117a519f9SDimitry Andric /// 15217a519f9SDimitry Andric static 15317a519f9SDimitry Andric void SetImpliedBits(uint64_t &Bits, const SubtargetFeatureKV *FeatureEntry, 15491bc56edSDimitry Andric ArrayRef<SubtargetFeatureKV> FeatureTable) { 15591bc56edSDimitry Andric for (auto &FE : FeatureTable) { 15617a519f9SDimitry Andric if (FeatureEntry->Value == FE.Value) continue; 15717a519f9SDimitry Andric 15817a519f9SDimitry Andric if (FeatureEntry->Implies & FE.Value) { 15917a519f9SDimitry Andric Bits |= FE.Value; 16091bc56edSDimitry Andric SetImpliedBits(Bits, &FE, FeatureTable); 16117a519f9SDimitry Andric } 16217a519f9SDimitry Andric } 16317a519f9SDimitry Andric } 16417a519f9SDimitry Andric 16517a519f9SDimitry Andric /// ClearImpliedBits - For each feature that (transitively) implies this 16617a519f9SDimitry Andric /// feature, clear it. 16717a519f9SDimitry Andric /// 16817a519f9SDimitry Andric static 16917a519f9SDimitry Andric void ClearImpliedBits(uint64_t &Bits, const SubtargetFeatureKV *FeatureEntry, 17091bc56edSDimitry Andric ArrayRef<SubtargetFeatureKV> FeatureTable) { 17191bc56edSDimitry Andric for (auto &FE : FeatureTable) { 17217a519f9SDimitry Andric if (FeatureEntry->Value == FE.Value) continue; 17317a519f9SDimitry Andric 17417a519f9SDimitry Andric if (FE.Implies & FeatureEntry->Value) { 17517a519f9SDimitry Andric Bits &= ~FE.Value; 17691bc56edSDimitry Andric ClearImpliedBits(Bits, &FE, FeatureTable); 17717a519f9SDimitry Andric } 17817a519f9SDimitry Andric } 17917a519f9SDimitry Andric } 18017a519f9SDimitry Andric 18117a519f9SDimitry Andric /// ToggleFeature - Toggle a feature and returns the newly updated feature 18217a519f9SDimitry Andric /// bits. 18317a519f9SDimitry Andric uint64_t 18417a519f9SDimitry Andric SubtargetFeatures::ToggleFeature(uint64_t Bits, const StringRef Feature, 18591bc56edSDimitry Andric ArrayRef<SubtargetFeatureKV> FeatureTable) { 18691bc56edSDimitry Andric 18717a519f9SDimitry Andric // Find feature in table. 18817a519f9SDimitry Andric const SubtargetFeatureKV *FeatureEntry = 18991bc56edSDimitry Andric Find(StripFlag(Feature), FeatureTable); 19017a519f9SDimitry Andric // If there is a match 19117a519f9SDimitry Andric if (FeatureEntry) { 19217a519f9SDimitry Andric if ((Bits & FeatureEntry->Value) == FeatureEntry->Value) { 19317a519f9SDimitry Andric Bits &= ~FeatureEntry->Value; 19417a519f9SDimitry Andric 19517a519f9SDimitry Andric // For each feature that implies this, clear it. 19691bc56edSDimitry Andric ClearImpliedBits(Bits, FeatureEntry, FeatureTable); 19717a519f9SDimitry Andric } else { 19817a519f9SDimitry Andric Bits |= FeatureEntry->Value; 19917a519f9SDimitry Andric 20017a519f9SDimitry Andric // For each feature that this implies, set it. 20191bc56edSDimitry Andric SetImpliedBits(Bits, FeatureEntry, FeatureTable); 20217a519f9SDimitry Andric } 20317a519f9SDimitry Andric } else { 20417a519f9SDimitry Andric errs() << "'" << Feature 20517a519f9SDimitry Andric << "' is not a recognized feature for this target" 20617a519f9SDimitry Andric << " (ignoring feature)\n"; 20717a519f9SDimitry Andric } 20817a519f9SDimitry Andric 20917a519f9SDimitry Andric return Bits; 21017a519f9SDimitry Andric } 21117a519f9SDimitry Andric 21217a519f9SDimitry Andric 21317a519f9SDimitry Andric /// getFeatureBits - Get feature bits a CPU. 21417a519f9SDimitry Andric /// 21591bc56edSDimitry Andric uint64_t 21691bc56edSDimitry Andric SubtargetFeatures::getFeatureBits(const StringRef CPU, 21791bc56edSDimitry Andric ArrayRef<SubtargetFeatureKV> CPUTable, 21891bc56edSDimitry Andric ArrayRef<SubtargetFeatureKV> FeatureTable) { 21991bc56edSDimitry Andric 22091bc56edSDimitry Andric if (CPUTable.empty() || FeatureTable.empty()) 22117a519f9SDimitry Andric return 0; 22217a519f9SDimitry Andric 22317a519f9SDimitry Andric #ifndef NDEBUG 22491bc56edSDimitry Andric for (size_t i = 1, e = CPUTable.size(); i != e; ++i) { 22517a519f9SDimitry Andric assert(strcmp(CPUTable[i - 1].Key, CPUTable[i].Key) < 0 && 22617a519f9SDimitry Andric "CPU table is not sorted"); 22717a519f9SDimitry Andric } 22891bc56edSDimitry Andric for (size_t i = 1, e = FeatureTable.size(); i != e; ++i) { 22917a519f9SDimitry Andric assert(strcmp(FeatureTable[i - 1].Key, FeatureTable[i].Key) < 0 && 23017a519f9SDimitry Andric "CPU features table is not sorted"); 23117a519f9SDimitry Andric } 23217a519f9SDimitry Andric #endif 23317a519f9SDimitry Andric uint64_t Bits = 0; // Resulting bits 23417a519f9SDimitry Andric 23517a519f9SDimitry Andric // Check if help is needed 23617a519f9SDimitry Andric if (CPU == "help") 23791bc56edSDimitry Andric Help(CPUTable, FeatureTable); 23817a519f9SDimitry Andric 23917a519f9SDimitry Andric // Find CPU entry if CPU name is specified. 24091bc56edSDimitry Andric else if (!CPU.empty()) { 24191bc56edSDimitry Andric const SubtargetFeatureKV *CPUEntry = Find(CPU, CPUTable); 24291bc56edSDimitry Andric 24317a519f9SDimitry Andric // If there is a match 24417a519f9SDimitry Andric if (CPUEntry) { 24517a519f9SDimitry Andric // Set base feature bits 24617a519f9SDimitry Andric Bits = CPUEntry->Value; 24717a519f9SDimitry Andric 24817a519f9SDimitry Andric // Set the feature implied by this CPU feature, if any. 24991bc56edSDimitry Andric for (auto &FE : FeatureTable) { 25017a519f9SDimitry Andric if (CPUEntry->Value & FE.Value) 25191bc56edSDimitry Andric SetImpliedBits(Bits, &FE, FeatureTable); 25217a519f9SDimitry Andric } 25317a519f9SDimitry Andric } else { 25417a519f9SDimitry Andric errs() << "'" << CPU 25517a519f9SDimitry Andric << "' is not a recognized processor for this target" 25617a519f9SDimitry Andric << " (ignoring processor)\n"; 25717a519f9SDimitry Andric } 25817a519f9SDimitry Andric } 25917a519f9SDimitry Andric 26017a519f9SDimitry Andric // Iterate through each feature 26191bc56edSDimitry Andric for (auto &Feature : Features) { 26217a519f9SDimitry Andric // Check for help 26317a519f9SDimitry Andric if (Feature == "+help") 26491bc56edSDimitry Andric Help(CPUTable, FeatureTable); 26517a519f9SDimitry Andric 26617a519f9SDimitry Andric // Find feature in table. 26717a519f9SDimitry Andric const SubtargetFeatureKV *FeatureEntry = 26891bc56edSDimitry Andric Find(StripFlag(Feature), FeatureTable); 26917a519f9SDimitry Andric // If there is a match 27017a519f9SDimitry Andric if (FeatureEntry) { 27117a519f9SDimitry Andric // Enable/disable feature in bits 27217a519f9SDimitry Andric if (isEnabled(Feature)) { 27317a519f9SDimitry Andric Bits |= FeatureEntry->Value; 27417a519f9SDimitry Andric 27517a519f9SDimitry Andric // For each feature that this implies, set it. 27691bc56edSDimitry Andric SetImpliedBits(Bits, FeatureEntry, FeatureTable); 27717a519f9SDimitry Andric } else { 27817a519f9SDimitry Andric Bits &= ~FeatureEntry->Value; 27917a519f9SDimitry Andric 28017a519f9SDimitry Andric // For each feature that implies this, clear it. 28191bc56edSDimitry Andric ClearImpliedBits(Bits, FeatureEntry, FeatureTable); 28217a519f9SDimitry Andric } 28317a519f9SDimitry Andric } else { 28417a519f9SDimitry Andric errs() << "'" << Feature 28517a519f9SDimitry Andric << "' is not a recognized feature for this target" 28617a519f9SDimitry Andric << " (ignoring feature)\n"; 28717a519f9SDimitry Andric } 28817a519f9SDimitry Andric } 28917a519f9SDimitry Andric 29017a519f9SDimitry Andric return Bits; 29117a519f9SDimitry Andric } 29217a519f9SDimitry Andric 29317a519f9SDimitry Andric /// print - Print feature string. 29417a519f9SDimitry Andric /// 29517a519f9SDimitry Andric void SubtargetFeatures::print(raw_ostream &OS) const { 29691bc56edSDimitry Andric for (auto &F : Features) 29791bc56edSDimitry Andric OS << F << " "; 29817a519f9SDimitry Andric OS << "\n"; 29917a519f9SDimitry Andric } 30017a519f9SDimitry Andric 3013861d79fSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 30217a519f9SDimitry Andric /// dump - Dump feature info. 30317a519f9SDimitry Andric /// 30417a519f9SDimitry Andric void SubtargetFeatures::dump() const { 30517a519f9SDimitry Andric print(dbgs()); 30617a519f9SDimitry Andric } 3073861d79fSDimitry Andric #endif 30817a519f9SDimitry Andric 309f785676fSDimitry Andric /// Adds the default features for the specified target triple. 31017a519f9SDimitry Andric /// 31117a519f9SDimitry Andric /// FIXME: This is an inelegant way of specifying the features of a 31217a519f9SDimitry Andric /// subtarget. It would be better if we could encode this information 31317a519f9SDimitry Andric /// into the IR. See <rdar://5972456>. 31417a519f9SDimitry Andric /// 31517a519f9SDimitry Andric void SubtargetFeatures::getDefaultSubtargetFeatures(const Triple& Triple) { 31617a519f9SDimitry Andric if (Triple.getVendor() == Triple::Apple) { 31717a519f9SDimitry Andric if (Triple.getArch() == Triple::ppc) { 31817a519f9SDimitry Andric // powerpc-apple-* 31917a519f9SDimitry Andric AddFeature("altivec"); 32017a519f9SDimitry Andric } else if (Triple.getArch() == Triple::ppc64) { 32117a519f9SDimitry Andric // powerpc64-apple-* 32217a519f9SDimitry Andric AddFeature("64bit"); 32317a519f9SDimitry Andric AddFeature("altivec"); 32417a519f9SDimitry Andric } 32517a519f9SDimitry Andric } 32617a519f9SDimitry Andric } 327