1//===- SubtargetFeature.cpp - CPU characteristics Implementation ----------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the SubtargetFeature interface. 11// 12//===----------------------------------------------------------------------===// 13 14#include "llvm/MC/SubtargetFeature.h" 15#include "llvm/ADT/ArrayRef.h" 16#include "llvm/ADT/StringExtras.h" 17#include "llvm/Support/Debug.h" 18#include "llvm/Support/Format.h" 19#include "llvm/Support/raw_ostream.h" 20#include <algorithm> 21#include <cassert> 22#include <cctype> 23#include <cstdlib> 24using namespace llvm; 25 26//===----------------------------------------------------------------------===// 27// Static Helper Functions 28//===----------------------------------------------------------------------===// 29 30/// hasFlag - Determine if a feature has a flag; '+' or '-' 31/// 32static inline bool hasFlag(StringRef Feature) { 33 assert(!Feature.empty() && "Empty string"); 34 // Get first character 35 char Ch = Feature[0]; 36 // Check if first character is '+' or '-' flag 37 return Ch == '+' || Ch =='-'; 38} 39 40/// StripFlag - Return string stripped of flag. 41/// 42static inline std::string StripFlag(StringRef Feature) { 43 return hasFlag(Feature) ? Feature.substr(1) : Feature; 44} 45 46/// isEnabled - Return true if enable flag; '+'. 47/// 48static inline bool isEnabled(StringRef Feature) { 49 assert(!Feature.empty() && "Empty string"); 50 // Get first character 51 char Ch = Feature[0]; 52 // Check if first character is '+' for enabled 53 return Ch == '+'; 54} 55 56/// Split - Splits a string of comma separated items in to a vector of strings. 57/// 58static void Split(std::vector<std::string> &V, StringRef S) { 59 SmallVector<StringRef, 3> Tmp; 60 S.split(Tmp, ',', -1, false /* KeepEmpty */); 61 V.assign(Tmp.begin(), Tmp.end()); 62} 63 64/// Adding features. 65void SubtargetFeatures::AddFeature(StringRef String, bool Enable) { 66 // Don't add empty features. 67 if (!String.empty()) 68 // Convert to lowercase, prepend flag if we don't already have a flag. 69 Features.push_back(hasFlag(String) ? String.lower() 70 : (Enable ? "+" : "-") + String.lower()); 71} 72 73/// Find KV in array using binary search. 74static const SubtargetFeatureKV *Find(StringRef S, 75 ArrayRef<SubtargetFeatureKV> A) { 76 // Binary search the array 77 auto F = std::lower_bound(A.begin(), A.end(), S); 78 // If not found then return NULL 79 if (F == A.end() || StringRef(F->Key) != S) return nullptr; 80 // Return the found array item 81 return F; 82} 83 84/// getLongestEntryLength - Return the length of the longest entry in the table. 85/// 86static size_t getLongestEntryLength(ArrayRef<SubtargetFeatureKV> Table) { 87 size_t MaxLen = 0; 88 for (auto &I : Table) 89 MaxLen = std::max(MaxLen, std::strlen(I.Key)); 90 return MaxLen; 91} 92 93/// Display help for feature choices. 94/// 95static void Help(ArrayRef<SubtargetFeatureKV> CPUTable, 96 ArrayRef<SubtargetFeatureKV> FeatTable) { 97 // Determine the length of the longest CPU and Feature entries. 98 unsigned MaxCPULen = getLongestEntryLength(CPUTable); 99 unsigned MaxFeatLen = getLongestEntryLength(FeatTable); 100 101 // Print the CPU table. 102 errs() << "Available CPUs for this target:\n\n"; 103 for (auto &CPU : CPUTable) 104 errs() << format(" %-*s - %s.\n", MaxCPULen, CPU.Key, CPU.Desc); 105 errs() << '\n'; 106 107 // Print the Feature table. 108 errs() << "Available features for this target:\n\n"; 109 for (auto &Feature : FeatTable) 110 errs() << format(" %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc); 111 errs() << '\n'; 112 113 errs() << "Use +feature to enable a feature, or -feature to disable it.\n" 114 "For example, llc -mcpu=mycpu -mattr=+feature1,-feature2\n"; 115} 116 117//===----------------------------------------------------------------------===// 118// SubtargetFeatures Implementation 119//===----------------------------------------------------------------------===// 120 121SubtargetFeatures::SubtargetFeatures(StringRef Initial) { 122 // Break up string into separate features 123 Split(Features, Initial); 124} 125 126 127std::string SubtargetFeatures::getString() const { 128 return join(Features.begin(), Features.end(), ","); 129} 130 131/// SetImpliedBits - For each feature that is (transitively) implied by this 132/// feature, set it. 133/// 134static 135void SetImpliedBits(FeatureBitset &Bits, const SubtargetFeatureKV *FeatureEntry, 136 ArrayRef<SubtargetFeatureKV> FeatureTable) { 137 for (auto &FE : FeatureTable) { 138 if (FeatureEntry->Value == FE.Value) continue; 139 140 if ((FeatureEntry->Implies & FE.Value).any()) { 141 Bits |= FE.Value; 142 SetImpliedBits(Bits, &FE, FeatureTable); 143 } 144 } 145} 146 147/// ClearImpliedBits - For each feature that (transitively) implies this 148/// feature, clear it. 149/// 150static 151void ClearImpliedBits(FeatureBitset &Bits, 152 const SubtargetFeatureKV *FeatureEntry, 153 ArrayRef<SubtargetFeatureKV> FeatureTable) { 154 for (auto &FE : FeatureTable) { 155 if (FeatureEntry->Value == FE.Value) continue; 156 157 if ((FE.Implies & FeatureEntry->Value).any()) { 158 Bits &= ~FE.Value; 159 ClearImpliedBits(Bits, &FE, FeatureTable); 160 } 161 } 162} 163 164/// ToggleFeature - Toggle a feature and update the feature bits. 165void 166SubtargetFeatures::ToggleFeature(FeatureBitset &Bits, StringRef Feature, 167 ArrayRef<SubtargetFeatureKV> FeatureTable) { 168 169 // Find feature in table. 170 const SubtargetFeatureKV *FeatureEntry = 171 Find(StripFlag(Feature), FeatureTable); 172 // If there is a match 173 if (FeatureEntry) { 174 if ((Bits & FeatureEntry->Value) == FeatureEntry->Value) { 175 Bits &= ~FeatureEntry->Value; 176 // For each feature that implies this, clear it. 177 ClearImpliedBits(Bits, FeatureEntry, FeatureTable); 178 } else { 179 Bits |= FeatureEntry->Value; 180 181 // For each feature that this implies, set it. 182 SetImpliedBits(Bits, FeatureEntry, FeatureTable); 183 } 184 } else { 185 errs() << "'" << Feature 186 << "' is not a recognized feature for this target" 187 << " (ignoring feature)\n"; 188 } 189} 190 191void SubtargetFeatures::ApplyFeatureFlag(FeatureBitset &Bits, StringRef Feature, 192 ArrayRef<SubtargetFeatureKV> FeatureTable) { 193 194 assert(hasFlag(Feature)); 195 196 // Find feature in table. 197 const SubtargetFeatureKV *FeatureEntry = 198 Find(StripFlag(Feature), FeatureTable); 199 // If there is a match 200 if (FeatureEntry) { 201 // Enable/disable feature in bits 202 if (isEnabled(Feature)) { 203 Bits |= FeatureEntry->Value; 204 205 // For each feature that this implies, set it. 206 SetImpliedBits(Bits, FeatureEntry, FeatureTable); 207 } else { 208 Bits &= ~FeatureEntry->Value; 209 210 // For each feature that implies this, clear it. 211 ClearImpliedBits(Bits, FeatureEntry, FeatureTable); 212 } 213 } else { 214 errs() << "'" << Feature 215 << "' is not a recognized feature for this target" 216 << " (ignoring feature)\n"; 217 } 218} 219 220 221/// getFeatureBits - Get feature bits a CPU. 222/// 223FeatureBitset 224SubtargetFeatures::getFeatureBits(StringRef CPU, 225 ArrayRef<SubtargetFeatureKV> CPUTable, 226 ArrayRef<SubtargetFeatureKV> FeatureTable) { 227 228 if (CPUTable.empty() || FeatureTable.empty()) 229 return FeatureBitset(); 230 231#ifndef NDEBUG 232 assert(std::is_sorted(std::begin(CPUTable), std::end(CPUTable)) && 233 "CPU table is not sorted"); 234 assert(std::is_sorted(std::begin(FeatureTable), std::end(FeatureTable)) && 235 "CPU features table is not sorted"); 236#endif 237 // Resulting bits 238 FeatureBitset Bits; 239 240 // Check if help is needed 241 if (CPU == "help") 242 Help(CPUTable, FeatureTable); 243 244 // Find CPU entry if CPU name is specified. 245 else if (!CPU.empty()) { 246 const SubtargetFeatureKV *CPUEntry = Find(CPU, CPUTable); 247 248 // If there is a match 249 if (CPUEntry) { 250 // Set base feature bits 251 Bits = CPUEntry->Value; 252 253 // Set the feature implied by this CPU feature, if any. 254 for (auto &FE : FeatureTable) { 255 if ((CPUEntry->Value & FE.Value).any()) 256 SetImpliedBits(Bits, &FE, FeatureTable); 257 } 258 } else { 259 errs() << "'" << CPU 260 << "' is not a recognized processor for this target" 261 << " (ignoring processor)\n"; 262 } 263 } 264 265 // Iterate through each feature 266 for (auto &Feature : Features) { 267 // Check for help 268 if (Feature == "+help") 269 Help(CPUTable, FeatureTable); 270 271 ApplyFeatureFlag(Bits, Feature, FeatureTable); 272 } 273 274 return Bits; 275} 276 277/// print - Print feature string. 278/// 279void SubtargetFeatures::print(raw_ostream &OS) const { 280 for (auto &F : Features) 281 OS << F << " "; 282 OS << "\n"; 283} 284 285#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 286/// dump - Dump feature info. 287/// 288LLVM_DUMP_METHOD void SubtargetFeatures::dump() const { 289 print(dbgs()); 290} 291#endif 292 293/// Adds the default features for the specified target triple. 294/// 295/// FIXME: This is an inelegant way of specifying the features of a 296/// subtarget. It would be better if we could encode this information 297/// into the IR. See <rdar://5972456>. 298/// 299void SubtargetFeatures::getDefaultSubtargetFeatures(const Triple& Triple) { 300 if (Triple.getVendor() == Triple::Apple) { 301 if (Triple.getArch() == Triple::ppc) { 302 // powerpc-apple-* 303 AddFeature("altivec"); 304 } else if (Triple.getArch() == Triple::ppc64) { 305 // powerpc64-apple-* 306 AddFeature("64bit"); 307 AddFeature("altivec"); 308 } 309 } 310} 311