1 //=== llvm/TargetParser/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_TARGETPARSER_SUBTARGETFEATURE_H
18 #define LLVM_TARGETPARSER_SUBTARGETFEATURE_H
19 
20 #include "llvm/ADT/ArrayRef.h"
21 #include "llvm/ADT/STLExtras.h"
22 #include "llvm/ADT/StringRef.h"
23 #include "llvm/Support/MathExtras.h"
24 #include <array>
25 #include <initializer_list>
26 #include <string>
27 #include <vector>
28 
29 namespace llvm {
30 
31 class raw_ostream;
32 class Triple;
33 
34 const unsigned MAX_SUBTARGET_WORDS = 4;
35 const unsigned MAX_SUBTARGET_FEATURES = MAX_SUBTARGET_WORDS * 64;
36 
37 /// Container class for subtarget features.
38 /// This is a constexpr reimplementation of a subset of std::bitset. It would be
39 /// nice to use std::bitset directly, but it doesn't support constant
40 /// initialization.
41 class FeatureBitset {
42   static_assert((MAX_SUBTARGET_FEATURES % 64) == 0,
43                 "Should be a multiple of 64!");
44   std::array<uint64_t, MAX_SUBTARGET_WORDS> Bits{};
45 
46 protected:
47   constexpr FeatureBitset(const std::array<uint64_t, MAX_SUBTARGET_WORDS> &B)
48       : Bits{B} {}
49 
50 public:
51   constexpr FeatureBitset() = default;
52   constexpr FeatureBitset(std::initializer_list<unsigned> Init) {
53     for (auto I : Init)
54       set(I);
55   }
56 
57   FeatureBitset &set() {
58     std::fill(std::begin(Bits), std::end(Bits), -1ULL);
59     return *this;
60   }
61 
62   constexpr FeatureBitset &set(unsigned I) {
63     // GCC <6.2 crashes if this is written in a single statement.
64     uint64_t NewBits = Bits[I / 64] | (uint64_t(1) << (I % 64));
65     Bits[I / 64] = NewBits;
66     return *this;
67   }
68 
69   constexpr FeatureBitset &reset(unsigned I) {
70     // GCC <6.2 crashes if this is written in a single statement.
71     uint64_t NewBits = Bits[I / 64] & ~(uint64_t(1) << (I % 64));
72     Bits[I / 64] = NewBits;
73     return *this;
74   }
75 
76   constexpr FeatureBitset &flip(unsigned I) {
77     // GCC <6.2 crashes if this is written in a single statement.
78     uint64_t NewBits = Bits[I / 64] ^ (uint64_t(1) << (I % 64));
79     Bits[I / 64] = NewBits;
80     return *this;
81   }
82 
83   constexpr bool operator[](unsigned I) const {
84     uint64_t Mask = uint64_t(1) << (I % 64);
85     return (Bits[I / 64] & Mask) != 0;
86   }
87 
88   constexpr bool test(unsigned I) const { return (*this)[I]; }
89 
90   constexpr size_t size() const { return MAX_SUBTARGET_FEATURES; }
91 
92   bool any() const {
93     return llvm::any_of(Bits, [](uint64_t I) { return I != 0; });
94   }
95   bool none() const { return !any(); }
96   size_t count() const {
97     size_t Count = 0;
98     for (auto B : Bits)
99       Count += llvm::popcount(B);
100     return Count;
101   }
102 
103   constexpr FeatureBitset &operator^=(const FeatureBitset &RHS) {
104     for (unsigned I = 0, E = Bits.size(); I != E; ++I) {
105       Bits[I] ^= RHS.Bits[I];
106     }
107     return *this;
108   }
109   constexpr FeatureBitset operator^(const FeatureBitset &RHS) const {
110     FeatureBitset Result = *this;
111     Result ^= RHS;
112     return Result;
113   }
114 
115   constexpr FeatureBitset &operator&=(const FeatureBitset &RHS) {
116     for (unsigned I = 0, E = Bits.size(); I != E; ++I) {
117       Bits[I] &= RHS.Bits[I];
118     }
119     return *this;
120   }
121   constexpr FeatureBitset operator&(const FeatureBitset &RHS) const {
122     FeatureBitset Result = *this;
123     Result &= RHS;
124     return Result;
125   }
126 
127   constexpr FeatureBitset &operator|=(const FeatureBitset &RHS) {
128     for (unsigned I = 0, E = Bits.size(); I != E; ++I) {
129       Bits[I] |= RHS.Bits[I];
130     }
131     return *this;
132   }
133   constexpr FeatureBitset operator|(const FeatureBitset &RHS) const {
134     FeatureBitset Result = *this;
135     Result |= RHS;
136     return Result;
137   }
138 
139   constexpr FeatureBitset operator~() const {
140     FeatureBitset Result = *this;
141     for (auto &B : Result.Bits)
142       B = ~B;
143     return Result;
144   }
145 
146   bool operator==(const FeatureBitset &RHS) const {
147     return std::equal(std::begin(Bits), std::end(Bits), std::begin(RHS.Bits));
148   }
149 
150   bool operator!=(const FeatureBitset &RHS) const { return !(*this == RHS); }
151 
152   bool operator < (const FeatureBitset &Other) const {
153     for (unsigned I = 0, E = size(); I != E; ++I) {
154       bool LHS = test(I), RHS = Other.test(I);
155       if (LHS != RHS)
156         return LHS < RHS;
157     }
158     return false;
159   }
160 };
161 
162 /// Class used to store the subtarget bits in the tables created by tablegen.
163 class FeatureBitArray : public FeatureBitset {
164 public:
165   constexpr FeatureBitArray(const std::array<uint64_t, MAX_SUBTARGET_WORDS> &B)
166       : FeatureBitset(B) {}
167 
168   const FeatureBitset &getAsBitset() const { return *this; }
169 };
170 
171 //===----------------------------------------------------------------------===//
172 
173 /// Manages the enabling and disabling of subtarget specific features.
174 ///
175 /// Features are encoded as a string of the form
176 ///   "+attr1,+attr2,-attr3,...,+attrN"
177 /// A comma separates each feature from the next (all lowercase.)
178 /// Each of the remaining features is prefixed with + or - indicating whether
179 /// that feature should be enabled or disabled contrary to the cpu
180 /// specification.
181 class SubtargetFeatures {
182   std::vector<std::string> Features;    ///< Subtarget features as a vector
183 
184 public:
185   explicit SubtargetFeatures(StringRef Initial = "");
186 
187   /// Returns features as a string.
188   std::string getString() const;
189 
190   /// Adds Features.
191   void AddFeature(StringRef String, bool Enable = true);
192 
193   void addFeaturesVector(const ArrayRef<std::string> OtherFeatures);
194 
195   /// Returns the vector of individual subtarget features.
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 '-'
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.
217   static StringRef StripFlag(StringRef Feature) {
218     return hasFlag(Feature) ? Feature.substr(1) : Feature;
219   }
220 
221   /// Return true if enable flag; '+'.
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_TARGETPARSER_SUBTARGETFEATURE_H
237