1 //===- llvm/MC/SubtargetFeature.h - CPU characteristics ---------*- C++ -*-===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 /// \file Defines and manages user or tool specified CPU characteristics.
10 /// The intent is to be able to package specific features that should or should
11 /// not be used on a specific target processor.  A tool, such as llc, could, as
12 /// as example, gather chip info from the command line, a long with features
13 /// that should be used on that chip.
14 //
15 //===----------------------------------------------------------------------===//
16 
17 #ifndef LLVM_MC_SUBTARGETFEATURE_H
18 #define LLVM_MC_SUBTARGETFEATURE_H
19 
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/Support/MathExtras.h"
22 #include <array>
23 #include <bitset>
24 #include <initializer_list>
25 #include <string>
26 #include <vector>
27 
28 namespace llvm {
29 
30 class raw_ostream;
31 class Triple;
32 
33 const unsigned MAX_SUBTARGET_WORDS = 3;
34 const unsigned MAX_SUBTARGET_FEATURES = MAX_SUBTARGET_WORDS * 64;
35 
36 /// Container class for subtarget features.
37 /// This is a constexpr reimplementation of a subset of std::bitset. It would be
38 /// nice to use std::bitset directly, but it doesn't support constant
39 /// initialization.
40 class FeatureBitset {
41   static_assert((MAX_SUBTARGET_FEATURES % 64) == 0,
42                 "Should be a multiple of 64!");
43   // This cannot be a std::array, operator[] is not constexpr until C++17.
44   uint64_t Bits[MAX_SUBTARGET_WORDS] = {};
45 
46 protected:
FeatureBitset(const std::array<uint64_t,MAX_SUBTARGET_WORDS> & B)47   constexpr FeatureBitset(const std::array<uint64_t, MAX_SUBTARGET_WORDS> &B) {
48     for (unsigned I = 0; I != B.size(); ++I)
49       Bits[I] = B[I];
50   }
51 
52 public:
53   constexpr FeatureBitset() = default;
FeatureBitset(std::initializer_list<unsigned> Init)54   constexpr FeatureBitset(std::initializer_list<unsigned> Init) {
55     for (auto I : Init)
56       set(I);
57   }
58 
set()59   FeatureBitset &set() {
60     std::fill(std::begin(Bits), std::end(Bits), -1ULL);
61     return *this;
62   }
63 
set(unsigned I)64   constexpr FeatureBitset &set(unsigned I) {
65     // GCC <6.2 crashes if this is written in a single statement.
66     uint64_t NewBits = Bits[I / 64] | (uint64_t(1) << (I % 64));
67     Bits[I / 64] = NewBits;
68     return *this;
69   }
70 
reset(unsigned I)71   constexpr FeatureBitset &reset(unsigned I) {
72     // GCC <6.2 crashes if this is written in a single statement.
73     uint64_t NewBits = Bits[I / 64] & ~(uint64_t(1) << (I % 64));
74     Bits[I / 64] = NewBits;
75     return *this;
76   }
77 
flip(unsigned I)78   constexpr FeatureBitset &flip(unsigned I) {
79     // GCC <6.2 crashes if this is written in a single statement.
80     uint64_t NewBits = Bits[I / 64] ^ (uint64_t(1) << (I % 64));
81     Bits[I / 64] = NewBits;
82     return *this;
83   }
84 
85   constexpr bool operator[](unsigned I) const {
86     uint64_t Mask = uint64_t(1) << (I % 64);
87     return (Bits[I / 64] & Mask) != 0;
88   }
89 
test(unsigned I)90   constexpr bool test(unsigned I) const { return (*this)[I]; }
91 
size()92   constexpr size_t size() const { return MAX_SUBTARGET_FEATURES; }
93 
any()94   bool any() const {
95     return llvm::any_of(Bits, [](uint64_t I) { return I != 0; });
96   }
none()97   bool none() const { return !any(); }
count()98   size_t count() const {
99     size_t Count = 0;
100     for (auto B : Bits)
101       Count += countPopulation(B);
102     return Count;
103   }
104 
105   constexpr FeatureBitset &operator^=(const FeatureBitset &RHS) {
106     for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I) {
107       Bits[I] ^= RHS.Bits[I];
108     }
109     return *this;
110   }
111   constexpr FeatureBitset operator^(const FeatureBitset &RHS) const {
112     FeatureBitset Result = *this;
113     Result ^= RHS;
114     return Result;
115   }
116 
117   constexpr FeatureBitset &operator&=(const FeatureBitset &RHS) {
118     for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I) {
119       Bits[I] &= RHS.Bits[I];
120     }
121     return *this;
122   }
123   constexpr FeatureBitset operator&(const FeatureBitset &RHS) const {
124     FeatureBitset Result = *this;
125     Result &= RHS;
126     return Result;
127   }
128 
129   constexpr FeatureBitset &operator|=(const FeatureBitset &RHS) {
130     for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I) {
131       Bits[I] |= RHS.Bits[I];
132     }
133     return *this;
134   }
135   constexpr FeatureBitset operator|(const FeatureBitset &RHS) const {
136     FeatureBitset Result = *this;
137     Result |= RHS;
138     return Result;
139   }
140 
141   constexpr FeatureBitset operator~() const {
142     FeatureBitset Result = *this;
143     for (auto &B : Result.Bits)
144       B = ~B;
145     return Result;
146   }
147 
148   bool operator==(const FeatureBitset &RHS) const {
149     return std::equal(std::begin(Bits), std::end(Bits), std::begin(RHS.Bits));
150   }
151 
152   bool operator!=(const FeatureBitset &RHS) const { return !(*this == RHS); }
153 
154   bool operator < (const FeatureBitset &Other) const {
155     for (unsigned I = 0, E = size(); I != E; ++I) {
156       bool LHS = test(I), RHS = Other.test(I);
157       if (LHS != RHS)
158         return LHS < RHS;
159     }
160     return false;
161   }
162 };
163 
164 /// Class used to store the subtarget bits in the tables created by tablegen.
165 class FeatureBitArray : public FeatureBitset {
166 public:
FeatureBitArray(const std::array<uint64_t,MAX_SUBTARGET_WORDS> & B)167   constexpr FeatureBitArray(const std::array<uint64_t, MAX_SUBTARGET_WORDS> &B)
168       : FeatureBitset(B) {}
169 
getAsBitset()170   const FeatureBitset &getAsBitset() const { return *this; }
171 };
172 
173 //===----------------------------------------------------------------------===//
174 
175 /// Manages the enabling and disabling of subtarget specific features.
176 ///
177 /// Features are encoded as a string of the form
178 ///   "+attr1,+attr2,-attr3,...,+attrN"
179 /// A comma separates each feature from the next (all lowercase.)
180 /// Each of the remaining features is prefixed with + or - indicating whether
181 /// that feature should be enabled or disabled contrary to the cpu
182 /// specification.
183 class SubtargetFeatures {
184   std::vector<std::string> Features;    ///< Subtarget features as a vector
185 
186 public:
187   explicit SubtargetFeatures(StringRef Initial = "");
188 
189   /// Returns features as a string.
190   std::string getString() const;
191 
192   /// Adds Features.
193   void AddFeature(StringRef String, bool Enable = true);
194 
195   /// Returns the vector of individual subtarget features.
getFeatures()196   const std::vector<std::string> &getFeatures() const { return Features; }
197 
198   /// Prints feature string.
199   void print(raw_ostream &OS) const;
200 
201   // Dumps feature info.
202   void dump() const;
203 
204   /// Adds the default features for the specified target triple.
205   void getDefaultSubtargetFeatures(const Triple& Triple);
206 
207   /// Determine if a feature has a flag; '+' or '-'
hasFlag(StringRef Feature)208   static bool hasFlag(StringRef Feature) {
209     assert(!Feature.empty() && "Empty string");
210     // Get first character
211     char Ch = Feature[0];
212     // Check if first character is '+' or '-' flag
213     return Ch == '+' || Ch =='-';
214   }
215 
216   /// Return string stripped of flag.
StripFlag(StringRef Feature)217   static std::string StripFlag(StringRef Feature) {
218     return hasFlag(Feature) ? Feature.substr(1) : Feature;
219   }
220 
221   /// Return true if enable flag; '+'.
isEnabled(StringRef Feature)222   static inline bool isEnabled(StringRef Feature) {
223     assert(!Feature.empty() && "Empty string");
224     // Get first character
225     char Ch = Feature[0];
226     // Check if first character is '+' for enabled
227     return Ch == '+';
228   }
229 
230   /// Splits a string of comma separated items in to a vector of strings.
231   static void Split(std::vector<std::string> &V, StringRef S);
232 };
233 
234 } // end namespace llvm
235 
236 #endif // LLVM_MC_SUBTARGETFEATURE_H
237