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