106c3fb27SDimitry Andric //=== llvm/TargetParser/SubtargetFeature.h - CPU characteristics-*- C++ -*-===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric //
906c3fb27SDimitry Andric /// \file Defines and manages user or tool specified CPU characteristics.
1006c3fb27SDimitry Andric /// The intent is to be able to package specific features that should or should
1106c3fb27SDimitry Andric /// not be used on a specific target processor.  A tool, such as llc, could, as
1206c3fb27SDimitry Andric /// as example, gather chip info from the command line, a long with features
1306c3fb27SDimitry Andric /// that should be used on that chip.
1406c3fb27SDimitry Andric //
1506c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
1606c3fb27SDimitry Andric 
1706c3fb27SDimitry Andric #ifndef LLVM_TARGETPARSER_SUBTARGETFEATURE_H
1806c3fb27SDimitry Andric #define LLVM_TARGETPARSER_SUBTARGETFEATURE_H
1906c3fb27SDimitry Andric 
2006c3fb27SDimitry Andric #include "llvm/ADT/ArrayRef.h"
2106c3fb27SDimitry Andric #include "llvm/ADT/STLExtras.h"
2206c3fb27SDimitry Andric #include "llvm/ADT/StringRef.h"
2306c3fb27SDimitry Andric #include "llvm/Support/MathExtras.h"
2406c3fb27SDimitry Andric #include <array>
2506c3fb27SDimitry Andric #include <initializer_list>
2606c3fb27SDimitry Andric #include <string>
2706c3fb27SDimitry Andric #include <vector>
2806c3fb27SDimitry Andric 
2906c3fb27SDimitry Andric namespace llvm {
3006c3fb27SDimitry Andric 
3106c3fb27SDimitry Andric class raw_ostream;
3206c3fb27SDimitry Andric class Triple;
3306c3fb27SDimitry Andric 
34*5f757f3fSDimitry Andric const unsigned MAX_SUBTARGET_WORDS = 5;
3506c3fb27SDimitry Andric const unsigned MAX_SUBTARGET_FEATURES = MAX_SUBTARGET_WORDS * 64;
3606c3fb27SDimitry Andric 
3706c3fb27SDimitry Andric /// Container class for subtarget features.
3806c3fb27SDimitry Andric /// This is a constexpr reimplementation of a subset of std::bitset. It would be
3906c3fb27SDimitry Andric /// nice to use std::bitset directly, but it doesn't support constant
4006c3fb27SDimitry Andric /// initialization.
4106c3fb27SDimitry Andric class FeatureBitset {
4206c3fb27SDimitry Andric   static_assert((MAX_SUBTARGET_FEATURES % 64) == 0,
4306c3fb27SDimitry Andric                 "Should be a multiple of 64!");
4406c3fb27SDimitry Andric   std::array<uint64_t, MAX_SUBTARGET_WORDS> Bits{};
4506c3fb27SDimitry Andric 
4606c3fb27SDimitry Andric protected:
FeatureBitset(const std::array<uint64_t,MAX_SUBTARGET_WORDS> & B)4706c3fb27SDimitry Andric   constexpr FeatureBitset(const std::array<uint64_t, MAX_SUBTARGET_WORDS> &B)
4806c3fb27SDimitry Andric       : Bits{B} {}
4906c3fb27SDimitry Andric 
5006c3fb27SDimitry Andric public:
5106c3fb27SDimitry Andric   constexpr FeatureBitset() = default;
FeatureBitset(std::initializer_list<unsigned> Init)5206c3fb27SDimitry Andric   constexpr FeatureBitset(std::initializer_list<unsigned> Init) {
5306c3fb27SDimitry Andric     for (auto I : Init)
5406c3fb27SDimitry Andric       set(I);
5506c3fb27SDimitry Andric   }
5606c3fb27SDimitry Andric 
set()5706c3fb27SDimitry Andric   FeatureBitset &set() {
5806c3fb27SDimitry Andric     std::fill(std::begin(Bits), std::end(Bits), -1ULL);
5906c3fb27SDimitry Andric     return *this;
6006c3fb27SDimitry Andric   }
6106c3fb27SDimitry Andric 
set(unsigned I)6206c3fb27SDimitry Andric   constexpr FeatureBitset &set(unsigned I) {
63*5f757f3fSDimitry Andric     Bits[I / 64] |= uint64_t(1) << (I % 64);
6406c3fb27SDimitry Andric     return *this;
6506c3fb27SDimitry Andric   }
6606c3fb27SDimitry Andric 
reset(unsigned I)6706c3fb27SDimitry Andric   constexpr FeatureBitset &reset(unsigned I) {
68*5f757f3fSDimitry Andric     Bits[I / 64] &= ~(uint64_t(1) << (I % 64));
6906c3fb27SDimitry Andric     return *this;
7006c3fb27SDimitry Andric   }
7106c3fb27SDimitry Andric 
flip(unsigned I)7206c3fb27SDimitry Andric   constexpr FeatureBitset &flip(unsigned I) {
73*5f757f3fSDimitry Andric     Bits[I / 64] ^= uint64_t(1) << (I % 64);
7406c3fb27SDimitry Andric     return *this;
7506c3fb27SDimitry Andric   }
7606c3fb27SDimitry Andric 
7706c3fb27SDimitry Andric   constexpr bool operator[](unsigned I) const {
7806c3fb27SDimitry Andric     uint64_t Mask = uint64_t(1) << (I % 64);
7906c3fb27SDimitry Andric     return (Bits[I / 64] & Mask) != 0;
8006c3fb27SDimitry Andric   }
8106c3fb27SDimitry Andric 
test(unsigned I)8206c3fb27SDimitry Andric   constexpr bool test(unsigned I) const { return (*this)[I]; }
8306c3fb27SDimitry Andric 
size()8406c3fb27SDimitry Andric   constexpr size_t size() const { return MAX_SUBTARGET_FEATURES; }
8506c3fb27SDimitry Andric 
any()8606c3fb27SDimitry Andric   bool any() const {
8706c3fb27SDimitry Andric     return llvm::any_of(Bits, [](uint64_t I) { return I != 0; });
8806c3fb27SDimitry Andric   }
none()8906c3fb27SDimitry Andric   bool none() const { return !any(); }
count()9006c3fb27SDimitry Andric   size_t count() const {
9106c3fb27SDimitry Andric     size_t Count = 0;
9206c3fb27SDimitry Andric     for (auto B : Bits)
9306c3fb27SDimitry Andric       Count += llvm::popcount(B);
9406c3fb27SDimitry Andric     return Count;
9506c3fb27SDimitry Andric   }
9606c3fb27SDimitry Andric 
9706c3fb27SDimitry Andric   constexpr FeatureBitset &operator^=(const FeatureBitset &RHS) {
9806c3fb27SDimitry Andric     for (unsigned I = 0, E = Bits.size(); I != E; ++I) {
9906c3fb27SDimitry Andric       Bits[I] ^= RHS.Bits[I];
10006c3fb27SDimitry Andric     }
10106c3fb27SDimitry Andric     return *this;
10206c3fb27SDimitry Andric   }
10306c3fb27SDimitry Andric   constexpr FeatureBitset operator^(const FeatureBitset &RHS) const {
10406c3fb27SDimitry Andric     FeatureBitset Result = *this;
10506c3fb27SDimitry Andric     Result ^= RHS;
10606c3fb27SDimitry Andric     return Result;
10706c3fb27SDimitry Andric   }
10806c3fb27SDimitry Andric 
10906c3fb27SDimitry Andric   constexpr FeatureBitset &operator&=(const FeatureBitset &RHS) {
110*5f757f3fSDimitry Andric     for (unsigned I = 0, E = Bits.size(); I != E; ++I)
11106c3fb27SDimitry Andric       Bits[I] &= RHS.Bits[I];
11206c3fb27SDimitry Andric     return *this;
11306c3fb27SDimitry Andric   }
11406c3fb27SDimitry Andric   constexpr FeatureBitset operator&(const FeatureBitset &RHS) const {
11506c3fb27SDimitry Andric     FeatureBitset Result = *this;
11606c3fb27SDimitry Andric     Result &= RHS;
11706c3fb27SDimitry Andric     return Result;
11806c3fb27SDimitry Andric   }
11906c3fb27SDimitry Andric 
12006c3fb27SDimitry Andric   constexpr FeatureBitset &operator|=(const FeatureBitset &RHS) {
12106c3fb27SDimitry Andric     for (unsigned I = 0, E = Bits.size(); I != E; ++I) {
12206c3fb27SDimitry Andric       Bits[I] |= RHS.Bits[I];
12306c3fb27SDimitry Andric     }
12406c3fb27SDimitry Andric     return *this;
12506c3fb27SDimitry Andric   }
12606c3fb27SDimitry Andric   constexpr FeatureBitset operator|(const FeatureBitset &RHS) const {
12706c3fb27SDimitry Andric     FeatureBitset Result = *this;
12806c3fb27SDimitry Andric     Result |= RHS;
12906c3fb27SDimitry Andric     return Result;
13006c3fb27SDimitry Andric   }
13106c3fb27SDimitry Andric 
13206c3fb27SDimitry Andric   constexpr FeatureBitset operator~() const {
13306c3fb27SDimitry Andric     FeatureBitset Result = *this;
13406c3fb27SDimitry Andric     for (auto &B : Result.Bits)
13506c3fb27SDimitry Andric       B = ~B;
13606c3fb27SDimitry Andric     return Result;
13706c3fb27SDimitry Andric   }
13806c3fb27SDimitry Andric 
13906c3fb27SDimitry Andric   bool operator==(const FeatureBitset &RHS) const {
14006c3fb27SDimitry Andric     return std::equal(std::begin(Bits), std::end(Bits), std::begin(RHS.Bits));
14106c3fb27SDimitry Andric   }
14206c3fb27SDimitry Andric 
14306c3fb27SDimitry Andric   bool operator!=(const FeatureBitset &RHS) const { return !(*this == RHS); }
14406c3fb27SDimitry Andric 
14506c3fb27SDimitry Andric   bool operator < (const FeatureBitset &Other) const {
14606c3fb27SDimitry Andric     for (unsigned I = 0, E = size(); I != E; ++I) {
14706c3fb27SDimitry Andric       bool LHS = test(I), RHS = Other.test(I);
14806c3fb27SDimitry Andric       if (LHS != RHS)
14906c3fb27SDimitry Andric         return LHS < RHS;
15006c3fb27SDimitry Andric     }
15106c3fb27SDimitry Andric     return false;
15206c3fb27SDimitry Andric   }
15306c3fb27SDimitry Andric };
15406c3fb27SDimitry Andric 
15506c3fb27SDimitry Andric /// Class used to store the subtarget bits in the tables created by tablegen.
15606c3fb27SDimitry Andric class FeatureBitArray : public FeatureBitset {
15706c3fb27SDimitry Andric public:
FeatureBitArray(const std::array<uint64_t,MAX_SUBTARGET_WORDS> & B)15806c3fb27SDimitry Andric   constexpr FeatureBitArray(const std::array<uint64_t, MAX_SUBTARGET_WORDS> &B)
15906c3fb27SDimitry Andric       : FeatureBitset(B) {}
16006c3fb27SDimitry Andric 
getAsBitset()16106c3fb27SDimitry Andric   const FeatureBitset &getAsBitset() const { return *this; }
16206c3fb27SDimitry Andric };
16306c3fb27SDimitry Andric 
16406c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
16506c3fb27SDimitry Andric 
16606c3fb27SDimitry Andric /// Manages the enabling and disabling of subtarget specific features.
16706c3fb27SDimitry Andric ///
16806c3fb27SDimitry Andric /// Features are encoded as a string of the form
16906c3fb27SDimitry Andric ///   "+attr1,+attr2,-attr3,...,+attrN"
17006c3fb27SDimitry Andric /// A comma separates each feature from the next (all lowercase.)
17106c3fb27SDimitry Andric /// Each of the remaining features is prefixed with + or - indicating whether
17206c3fb27SDimitry Andric /// that feature should be enabled or disabled contrary to the cpu
17306c3fb27SDimitry Andric /// specification.
17406c3fb27SDimitry Andric class SubtargetFeatures {
17506c3fb27SDimitry Andric   std::vector<std::string> Features;    ///< Subtarget features as a vector
17606c3fb27SDimitry Andric 
17706c3fb27SDimitry Andric public:
17806c3fb27SDimitry Andric   explicit SubtargetFeatures(StringRef Initial = "");
17906c3fb27SDimitry Andric 
18006c3fb27SDimitry Andric   /// Returns features as a string.
18106c3fb27SDimitry Andric   std::string getString() const;
18206c3fb27SDimitry Andric 
18306c3fb27SDimitry Andric   /// Adds Features.
18406c3fb27SDimitry Andric   void AddFeature(StringRef String, bool Enable = true);
18506c3fb27SDimitry Andric 
18606c3fb27SDimitry Andric   void addFeaturesVector(const ArrayRef<std::string> OtherFeatures);
18706c3fb27SDimitry Andric 
18806c3fb27SDimitry Andric   /// Returns the vector of individual subtarget features.
getFeatures()18906c3fb27SDimitry Andric   const std::vector<std::string> &getFeatures() const { return Features; }
19006c3fb27SDimitry Andric 
19106c3fb27SDimitry Andric   /// Prints feature string.
19206c3fb27SDimitry Andric   void print(raw_ostream &OS) const;
19306c3fb27SDimitry Andric 
19406c3fb27SDimitry Andric   // Dumps feature info.
19506c3fb27SDimitry Andric   void dump() const;
19606c3fb27SDimitry Andric 
19706c3fb27SDimitry Andric   /// Adds the default features for the specified target triple.
19806c3fb27SDimitry Andric   void getDefaultSubtargetFeatures(const Triple& Triple);
19906c3fb27SDimitry Andric 
20006c3fb27SDimitry Andric   /// Determine if a feature has a flag; '+' or '-'
hasFlag(StringRef Feature)20106c3fb27SDimitry Andric   static bool hasFlag(StringRef Feature) {
20206c3fb27SDimitry Andric     assert(!Feature.empty() && "Empty string");
20306c3fb27SDimitry Andric     // Get first character
20406c3fb27SDimitry Andric     char Ch = Feature[0];
20506c3fb27SDimitry Andric     // Check if first character is '+' or '-' flag
20606c3fb27SDimitry Andric     return Ch == '+' || Ch =='-';
20706c3fb27SDimitry Andric   }
20806c3fb27SDimitry Andric 
20906c3fb27SDimitry Andric   /// Return string stripped of flag.
StripFlag(StringRef Feature)21006c3fb27SDimitry Andric   static StringRef StripFlag(StringRef Feature) {
21106c3fb27SDimitry Andric     return hasFlag(Feature) ? Feature.substr(1) : Feature;
21206c3fb27SDimitry Andric   }
21306c3fb27SDimitry Andric 
21406c3fb27SDimitry Andric   /// Return true if enable flag; '+'.
isEnabled(StringRef Feature)21506c3fb27SDimitry Andric   static inline bool isEnabled(StringRef Feature) {
21606c3fb27SDimitry Andric     assert(!Feature.empty() && "Empty string");
21706c3fb27SDimitry Andric     // Get first character
21806c3fb27SDimitry Andric     char Ch = Feature[0];
21906c3fb27SDimitry Andric     // Check if first character is '+' for enabled
22006c3fb27SDimitry Andric     return Ch == '+';
22106c3fb27SDimitry Andric   }
22206c3fb27SDimitry Andric 
22306c3fb27SDimitry Andric   /// Splits a string of comma separated items in to a vector of strings.
22406c3fb27SDimitry Andric   static void Split(std::vector<std::string> &V, StringRef S);
22506c3fb27SDimitry Andric };
22606c3fb27SDimitry Andric 
22706c3fb27SDimitry Andric } // end namespace llvm
22806c3fb27SDimitry Andric 
22906c3fb27SDimitry Andric #endif // LLVM_TARGETPARSER_SUBTARGETFEATURE_H
230