1224133Sdim//===- SubtargetFeature.cpp - CPU characteristics Implementation ----------===// 2224133Sdim// 3224133Sdim// The LLVM Compiler Infrastructure 4224133Sdim// 5224133Sdim// This file is distributed under the University of Illinois Open Source 6224133Sdim// License. See LICENSE.TXT for details. 7224133Sdim// 8224133Sdim//===----------------------------------------------------------------------===// 9224133Sdim// 10224133Sdim// This file implements the SubtargetFeature interface. 11224133Sdim// 12224133Sdim//===----------------------------------------------------------------------===// 13224133Sdim 14224133Sdim#include "llvm/MC/SubtargetFeature.h" 15224133Sdim#include "llvm/Support/Debug.h" 16235633Sdim#include "llvm/Support/Format.h" 17224133Sdim#include "llvm/Support/raw_ostream.h" 18224133Sdim#include <algorithm> 19224133Sdim#include <cassert> 20224133Sdim#include <cctype> 21224133Sdim#include <cstdlib> 22224133Sdimusing namespace llvm; 23224133Sdim 24224133Sdim//===----------------------------------------------------------------------===// 25224133Sdim// Static Helper Functions 26224133Sdim//===----------------------------------------------------------------------===// 27224133Sdim 28224133Sdim/// hasFlag - Determine if a feature has a flag; '+' or '-' 29224133Sdim/// 30224133Sdimstatic inline bool hasFlag(const StringRef Feature) { 31224133Sdim assert(!Feature.empty() && "Empty string"); 32224133Sdim // Get first character 33224133Sdim char Ch = Feature[0]; 34224133Sdim // Check if first character is '+' or '-' flag 35224133Sdim return Ch == '+' || Ch =='-'; 36224133Sdim} 37224133Sdim 38224133Sdim/// StripFlag - Return string stripped of flag. 39224133Sdim/// 40224133Sdimstatic inline std::string StripFlag(const StringRef Feature) { 41224133Sdim return hasFlag(Feature) ? Feature.substr(1) : Feature; 42224133Sdim} 43224133Sdim 44224133Sdim/// isEnabled - Return true if enable flag; '+'. 45224133Sdim/// 46224133Sdimstatic inline bool isEnabled(const StringRef Feature) { 47224133Sdim assert(!Feature.empty() && "Empty string"); 48224133Sdim // Get first character 49224133Sdim char Ch = Feature[0]; 50224133Sdim // Check if first character is '+' for enabled 51224133Sdim return Ch == '+'; 52224133Sdim} 53224133Sdim 54224133Sdim/// PrependFlag - Return a string with a prepended flag; '+' or '-'. 55224133Sdim/// 56224133Sdimstatic inline std::string PrependFlag(const StringRef Feature, 57224133Sdim bool IsEnabled) { 58224133Sdim assert(!Feature.empty() && "Empty string"); 59224133Sdim if (hasFlag(Feature)) 60224133Sdim return Feature; 61224133Sdim std::string Prefix = IsEnabled ? "+" : "-"; 62224133Sdim Prefix += Feature; 63224133Sdim return Prefix; 64224133Sdim} 65224133Sdim 66224133Sdim/// Split - Splits a string of comma separated items in to a vector of strings. 67224133Sdim/// 68224133Sdimstatic void Split(std::vector<std::string> &V, const StringRef S) { 69224133Sdim if (S.empty()) 70224133Sdim return; 71224133Sdim 72224133Sdim // Start at beginning of string. 73224133Sdim size_t Pos = 0; 74224133Sdim while (true) { 75224133Sdim // Find the next comma 76224133Sdim size_t Comma = S.find(',', Pos); 77224133Sdim // If no comma found then the rest of the string is used 78224133Sdim if (Comma == std::string::npos) { 79224133Sdim // Add string to vector 80224133Sdim V.push_back(S.substr(Pos)); 81224133Sdim break; 82224133Sdim } 83224133Sdim // Otherwise add substring to vector 84224133Sdim V.push_back(S.substr(Pos, Comma - Pos)); 85224133Sdim // Advance to next item 86224133Sdim Pos = Comma + 1; 87224133Sdim } 88224133Sdim} 89224133Sdim 90224133Sdim/// Join a vector of strings to a string with a comma separating each element. 91224133Sdim/// 92224133Sdimstatic std::string Join(const std::vector<std::string> &V) { 93224133Sdim // Start with empty string. 94224133Sdim std::string Result; 95245431Sdim // If the vector is not empty 96224133Sdim if (!V.empty()) { 97224133Sdim // Start with the first feature 98224133Sdim Result = V[0]; 99224133Sdim // For each successive feature 100224133Sdim for (size_t i = 1; i < V.size(); i++) { 101224133Sdim // Add a comma 102224133Sdim Result += ","; 103224133Sdim // Add the feature 104224133Sdim Result += V[i]; 105224133Sdim } 106224133Sdim } 107245431Sdim // Return the features string 108224133Sdim return Result; 109224133Sdim} 110224133Sdim 111224133Sdim/// Adding features. 112224133Sdimvoid SubtargetFeatures::AddFeature(const StringRef String, 113224133Sdim bool IsEnabled) { 114224133Sdim // Don't add empty features 115224133Sdim if (!String.empty()) { 116224133Sdim // Convert to lowercase, prepend flag and add to vector 117235633Sdim Features.push_back(PrependFlag(String.lower(), IsEnabled)); 118224133Sdim } 119224133Sdim} 120224133Sdim 121224133Sdim/// Find KV in array using binary search. 122245431Sdimstatic const SubtargetFeatureKV *Find(StringRef S, const SubtargetFeatureKV *A, 123245431Sdim size_t L) { 124224133Sdim // Determine the end of the array 125245431Sdim const SubtargetFeatureKV *Hi = A + L; 126224133Sdim // Binary search the array 127263509Sdim const SubtargetFeatureKV *F = std::lower_bound(A, Hi, S); 128224133Sdim // If not found then return NULL 129224133Sdim if (F == Hi || StringRef(F->Key) != S) return NULL; 130224133Sdim // Return the found array item 131224133Sdim return F; 132224133Sdim} 133224133Sdim 134224133Sdim/// getLongestEntryLength - Return the length of the longest entry in the table. 135224133Sdim/// 136224133Sdimstatic size_t getLongestEntryLength(const SubtargetFeatureKV *Table, 137224133Sdim size_t Size) { 138224133Sdim size_t MaxLen = 0; 139224133Sdim for (size_t i = 0; i < Size; i++) 140224133Sdim MaxLen = std::max(MaxLen, std::strlen(Table[i].Key)); 141224133Sdim return MaxLen; 142224133Sdim} 143224133Sdim 144224133Sdim/// Display help for feature choices. 145224133Sdim/// 146224133Sdimstatic void Help(const SubtargetFeatureKV *CPUTable, size_t CPUTableSize, 147224133Sdim const SubtargetFeatureKV *FeatTable, size_t FeatTableSize) { 148224133Sdim // Determine the length of the longest CPU and Feature entries. 149224133Sdim unsigned MaxCPULen = getLongestEntryLength(CPUTable, CPUTableSize); 150224133Sdim unsigned MaxFeatLen = getLongestEntryLength(FeatTable, FeatTableSize); 151224133Sdim 152224133Sdim // Print the CPU table. 153224133Sdim errs() << "Available CPUs for this target:\n\n"; 154224133Sdim for (size_t i = 0; i != CPUTableSize; i++) 155235633Sdim errs() << format(" %-*s - %s.\n", 156235633Sdim MaxCPULen, CPUTable[i].Key, CPUTable[i].Desc); 157235633Sdim errs() << '\n'; 158235633Sdim 159224133Sdim // Print the Feature table. 160224133Sdim errs() << "Available features for this target:\n\n"; 161224133Sdim for (size_t i = 0; i != FeatTableSize; i++) 162235633Sdim errs() << format(" %-*s - %s.\n", 163235633Sdim MaxFeatLen, FeatTable[i].Key, FeatTable[i].Desc); 164235633Sdim errs() << '\n'; 165235633Sdim 166224133Sdim errs() << "Use +feature to enable a feature, or -feature to disable it.\n" 167235633Sdim "For example, llc -mcpu=mycpu -mattr=+feature1,-feature2\n"; 168224133Sdim std::exit(1); 169224133Sdim} 170224133Sdim 171224133Sdim//===----------------------------------------------------------------------===// 172224133Sdim// SubtargetFeatures Implementation 173224133Sdim//===----------------------------------------------------------------------===// 174224133Sdim 175224133SdimSubtargetFeatures::SubtargetFeatures(const StringRef Initial) { 176224133Sdim // Break up string into separate features 177224133Sdim Split(Features, Initial); 178224133Sdim} 179224133Sdim 180224133Sdim 181224133Sdimstd::string SubtargetFeatures::getString() const { 182224133Sdim return Join(Features); 183224133Sdim} 184224133Sdim 185224133Sdim/// SetImpliedBits - For each feature that is (transitively) implied by this 186224133Sdim/// feature, set it. 187224133Sdim/// 188224133Sdimstatic 189224133Sdimvoid SetImpliedBits(uint64_t &Bits, const SubtargetFeatureKV *FeatureEntry, 190224133Sdim const SubtargetFeatureKV *FeatureTable, 191224133Sdim size_t FeatureTableSize) { 192224133Sdim for (size_t i = 0; i < FeatureTableSize; ++i) { 193224133Sdim const SubtargetFeatureKV &FE = FeatureTable[i]; 194224133Sdim 195224133Sdim if (FeatureEntry->Value == FE.Value) continue; 196224133Sdim 197224133Sdim if (FeatureEntry->Implies & FE.Value) { 198224133Sdim Bits |= FE.Value; 199224133Sdim SetImpliedBits(Bits, &FE, FeatureTable, FeatureTableSize); 200224133Sdim } 201224133Sdim } 202224133Sdim} 203224133Sdim 204224133Sdim/// ClearImpliedBits - For each feature that (transitively) implies this 205224133Sdim/// feature, clear it. 206245431Sdim/// 207224133Sdimstatic 208224133Sdimvoid ClearImpliedBits(uint64_t &Bits, const SubtargetFeatureKV *FeatureEntry, 209224133Sdim const SubtargetFeatureKV *FeatureTable, 210224133Sdim size_t FeatureTableSize) { 211224133Sdim for (size_t i = 0; i < FeatureTableSize; ++i) { 212224133Sdim const SubtargetFeatureKV &FE = FeatureTable[i]; 213224133Sdim 214224133Sdim if (FeatureEntry->Value == FE.Value) continue; 215224133Sdim 216224133Sdim if (FE.Implies & FeatureEntry->Value) { 217224133Sdim Bits &= ~FE.Value; 218224133Sdim ClearImpliedBits(Bits, &FE, FeatureTable, FeatureTableSize); 219224133Sdim } 220224133Sdim } 221224133Sdim} 222224133Sdim 223224133Sdim/// ToggleFeature - Toggle a feature and returns the newly updated feature 224224133Sdim/// bits. 225224133Sdimuint64_t 226224133SdimSubtargetFeatures::ToggleFeature(uint64_t Bits, const StringRef Feature, 227224133Sdim const SubtargetFeatureKV *FeatureTable, 228224133Sdim size_t FeatureTableSize) { 229224133Sdim // Find feature in table. 230224133Sdim const SubtargetFeatureKV *FeatureEntry = 231224133Sdim Find(StripFlag(Feature), FeatureTable, FeatureTableSize); 232224133Sdim // If there is a match 233224133Sdim if (FeatureEntry) { 234224133Sdim if ((Bits & FeatureEntry->Value) == FeatureEntry->Value) { 235224133Sdim Bits &= ~FeatureEntry->Value; 236224133Sdim 237224133Sdim // For each feature that implies this, clear it. 238224133Sdim ClearImpliedBits(Bits, FeatureEntry, FeatureTable, FeatureTableSize); 239224133Sdim } else { 240224133Sdim Bits |= FeatureEntry->Value; 241224133Sdim 242224133Sdim // For each feature that this implies, set it. 243224133Sdim SetImpliedBits(Bits, FeatureEntry, FeatureTable, FeatureTableSize); 244224133Sdim } 245224133Sdim } else { 246224133Sdim errs() << "'" << Feature 247224133Sdim << "' is not a recognized feature for this target" 248224133Sdim << " (ignoring feature)\n"; 249224133Sdim } 250224133Sdim 251224133Sdim return Bits; 252224133Sdim} 253224133Sdim 254245431Sdim 255224133Sdim/// getFeatureBits - Get feature bits a CPU. 256224133Sdim/// 257224133Sdimuint64_t SubtargetFeatures::getFeatureBits(const StringRef CPU, 258224133Sdim const SubtargetFeatureKV *CPUTable, 259224133Sdim size_t CPUTableSize, 260224133Sdim const SubtargetFeatureKV *FeatureTable, 261224133Sdim size_t FeatureTableSize) { 262224133Sdim if (!FeatureTableSize || !CPUTableSize) 263224133Sdim return 0; 264224133Sdim 265224133Sdim#ifndef NDEBUG 266224133Sdim for (size_t i = 1; i < CPUTableSize; i++) { 267224133Sdim assert(strcmp(CPUTable[i - 1].Key, CPUTable[i].Key) < 0 && 268224133Sdim "CPU table is not sorted"); 269224133Sdim } 270224133Sdim for (size_t i = 1; i < FeatureTableSize; i++) { 271224133Sdim assert(strcmp(FeatureTable[i - 1].Key, FeatureTable[i].Key) < 0 && 272224133Sdim "CPU features table is not sorted"); 273224133Sdim } 274224133Sdim#endif 275224133Sdim uint64_t Bits = 0; // Resulting bits 276224133Sdim 277224133Sdim // Check if help is needed 278224133Sdim if (CPU == "help") 279224133Sdim Help(CPUTable, CPUTableSize, FeatureTable, FeatureTableSize); 280245431Sdim 281224133Sdim // Find CPU entry if CPU name is specified. 282224133Sdim if (!CPU.empty()) { 283224133Sdim const SubtargetFeatureKV *CPUEntry = Find(CPU, CPUTable, CPUTableSize); 284224133Sdim // If there is a match 285224133Sdim if (CPUEntry) { 286224133Sdim // Set base feature bits 287224133Sdim Bits = CPUEntry->Value; 288224133Sdim 289224133Sdim // Set the feature implied by this CPU feature, if any. 290224133Sdim for (size_t i = 0; i < FeatureTableSize; ++i) { 291224133Sdim const SubtargetFeatureKV &FE = FeatureTable[i]; 292224133Sdim if (CPUEntry->Value & FE.Value) 293224133Sdim SetImpliedBits(Bits, &FE, FeatureTable, FeatureTableSize); 294224133Sdim } 295224133Sdim } else { 296224133Sdim errs() << "'" << CPU 297224133Sdim << "' is not a recognized processor for this target" 298224133Sdim << " (ignoring processor)\n"; 299224133Sdim } 300224133Sdim } 301224133Sdim 302224133Sdim // Iterate through each feature 303224133Sdim for (size_t i = 0, E = Features.size(); i < E; i++) { 304224133Sdim const StringRef Feature = Features[i]; 305245431Sdim 306224133Sdim // Check for help 307224133Sdim if (Feature == "+help") 308224133Sdim Help(CPUTable, CPUTableSize, FeatureTable, FeatureTableSize); 309245431Sdim 310224133Sdim // Find feature in table. 311224133Sdim const SubtargetFeatureKV *FeatureEntry = 312224133Sdim Find(StripFlag(Feature), FeatureTable, FeatureTableSize); 313224133Sdim // If there is a match 314224133Sdim if (FeatureEntry) { 315224133Sdim // Enable/disable feature in bits 316224133Sdim if (isEnabled(Feature)) { 317224133Sdim Bits |= FeatureEntry->Value; 318224133Sdim 319224133Sdim // For each feature that this implies, set it. 320224133Sdim SetImpliedBits(Bits, FeatureEntry, FeatureTable, FeatureTableSize); 321224133Sdim } else { 322224133Sdim Bits &= ~FeatureEntry->Value; 323224133Sdim 324224133Sdim // For each feature that implies this, clear it. 325224133Sdim ClearImpliedBits(Bits, FeatureEntry, FeatureTable, FeatureTableSize); 326224133Sdim } 327224133Sdim } else { 328224133Sdim errs() << "'" << Feature 329224133Sdim << "' is not a recognized feature for this target" 330224133Sdim << " (ignoring feature)\n"; 331224133Sdim } 332224133Sdim } 333224133Sdim 334224133Sdim return Bits; 335224133Sdim} 336224133Sdim 337224133Sdim/// print - Print feature string. 338224133Sdim/// 339224133Sdimvoid SubtargetFeatures::print(raw_ostream &OS) const { 340224133Sdim for (size_t i = 0, e = Features.size(); i != e; ++i) 341224133Sdim OS << Features[i] << " "; 342224133Sdim OS << "\n"; 343224133Sdim} 344224133Sdim 345245431Sdim#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 346224133Sdim/// dump - Dump feature info. 347224133Sdim/// 348224133Sdimvoid SubtargetFeatures::dump() const { 349224133Sdim print(dbgs()); 350224133Sdim} 351245431Sdim#endif 352224133Sdim 353263509Sdim/// Adds the default features for the specified target triple. 354224133Sdim/// 355224133Sdim/// FIXME: This is an inelegant way of specifying the features of a 356224133Sdim/// subtarget. It would be better if we could encode this information 357224133Sdim/// into the IR. See <rdar://5972456>. 358224133Sdim/// 359224133Sdimvoid SubtargetFeatures::getDefaultSubtargetFeatures(const Triple& Triple) { 360224133Sdim if (Triple.getVendor() == Triple::Apple) { 361224133Sdim if (Triple.getArch() == Triple::ppc) { 362224133Sdim // powerpc-apple-* 363224133Sdim AddFeature("altivec"); 364224133Sdim } else if (Triple.getArch() == Triple::ppc64) { 365224133Sdim // powerpc64-apple-* 366224133Sdim AddFeature("64bit"); 367224133Sdim AddFeature("altivec"); 368224133Sdim } 369224133Sdim } 370224133Sdim} 371