1 // Copyright 2018, VIXL authors
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 //   * Redistributions of source code must retain the above copyright notice,
8 //     this list of conditions and the following disclaimer.
9 //   * Redistributions in binary form must reproduce the above copyright notice,
10 //     this list of conditions and the following disclaimer in the documentation
11 //     and/or other materials provided with the distribution.
12 //   * Neither the name of ARM Limited nor the names of its contributors may be
13 //     used to endorse or promote products derived from this software without
14 //     specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 #include "cpu-features.h"
28 
29 #include <ostream>
30 
31 #include "globals-vixl.h"
32 #include "utils-vixl.h"
33 
34 #if defined(__aarch64__) && defined(VIXL_INCLUDE_TARGET_AARCH64)
35 #include "aarch64/cpu-aarch64.h"
36 #define VIXL_USE_AARCH64_CPU_HELPERS
37 #endif
38 
39 namespace vixl {
40 
All()41 CPUFeatures CPUFeatures::All() {
42   CPUFeatures all;
43   all.features_.set();
44   return all;
45 }
46 
InferFromIDRegisters()47 CPUFeatures CPUFeatures::InferFromIDRegisters() {
48   // This function assumes that kIDRegisterEmulation is available.
49   CPUFeatures features(CPUFeatures::kIDRegisterEmulation);
50 #ifdef VIXL_USE_AARCH64_CPU_HELPERS
51   // Note that the Linux kernel filters these values during emulation, so the
52   // results may not exactly match the expected hardware support.
53   features.Combine(aarch64::CPU::InferCPUFeaturesFromIDRegisters());
54 #endif
55   return features;
56 }
57 
InferFromOS(QueryIDRegistersOption option)58 CPUFeatures CPUFeatures::InferFromOS(QueryIDRegistersOption option) {
59 #ifdef VIXL_USE_AARCH64_CPU_HELPERS
60   return aarch64::CPU::InferCPUFeaturesFromOS(option);
61 #else
62   USE(option);
63   return CPUFeatures();
64 #endif
65 }
66 
Combine(const CPUFeatures& other)67 void CPUFeatures::Combine(const CPUFeatures& other) {
68   features_ |= other.features_;
69 }
70 
Combine(Feature feature)71 void CPUFeatures::Combine(Feature feature) {
72   if (feature != CPUFeatures::kNone) features_.set(feature);
73 }
74 
Remove(const CPUFeatures& other)75 void CPUFeatures::Remove(const CPUFeatures& other) {
76   features_ &= ~other.features_;
77 }
78 
Remove(Feature feature)79 void CPUFeatures::Remove(Feature feature) {
80   if (feature != CPUFeatures::kNone) features_.reset(feature);
81 }
82 
Has(const CPUFeatures& other) const83 bool CPUFeatures::Has(const CPUFeatures& other) const {
84   return (features_ & other.features_) == other.features_;
85 }
86 
Has(Feature feature) const87 bool CPUFeatures::Has(Feature feature) const {
88   return (feature == CPUFeatures::kNone) || features_[feature];
89 }
90 
Count() const91 size_t CPUFeatures::Count() const { return features_.count(); }
92 
operator <<(std::ostream& os, CPUFeatures::Feature feature)93 std::ostream& operator<<(std::ostream& os, CPUFeatures::Feature feature) {
94   // clang-format off
95   switch (feature) {
96 #define VIXL_FORMAT_FEATURE(SYMBOL, NAME, CPUINFO) \
97     case CPUFeatures::SYMBOL:                      \
98       return os << NAME;
99 VIXL_CPU_FEATURE_LIST(VIXL_FORMAT_FEATURE)
100 #undef VIXL_FORMAT_FEATURE
101     case CPUFeatures::kNone:
102       return os << "none";
103     case CPUFeatures::kNumberOfFeatures:
104       VIXL_UNREACHABLE();
105   }
106   // clang-format on
107   VIXL_UNREACHABLE();
108   return os;
109 }
110 
begin() const111 CPUFeatures::const_iterator CPUFeatures::begin() const {
112   // For iterators in general, it's undefined to increment `end()`, but here we
113   // control the implementation and it is safe to do this.
114   return ++end();
115 }
116 
end() const117 CPUFeatures::const_iterator CPUFeatures::end() const {
118   return const_iterator(this, kNone);
119 }
120 
operator <<(std::ostream& os, const CPUFeatures& features)121 std::ostream& operator<<(std::ostream& os, const CPUFeatures& features) {
122   bool need_separator = false;
123   for (CPUFeatures::Feature feature : features) {
124     if (need_separator) os << ", ";
125     need_separator = true;
126     os << feature;
127   }
128   return os;
129 }
130 
operator ==( const CPUFeaturesConstIterator& other) const131 bool CPUFeaturesConstIterator::operator==(
132     const CPUFeaturesConstIterator& other) const {
133   VIXL_ASSERT(IsValid());
134   return (cpu_features_ == other.cpu_features_) && (feature_ == other.feature_);
135 }
136 
operator ++()137 CPUFeaturesConstIterator& CPUFeaturesConstIterator::operator++() {  // Prefix
138   VIXL_ASSERT(IsValid());
139   do {
140     // Find the next feature. The order is unspecified.
141     feature_ = static_cast<CPUFeatures::Feature>(feature_ + 1);
142     if (feature_ == CPUFeatures::kNumberOfFeatures) {
143       feature_ = CPUFeatures::kNone;
144       VIXL_STATIC_ASSERT(CPUFeatures::kNone == -1);
145     }
146     VIXL_ASSERT(CPUFeatures::kNone <= feature_);
147     VIXL_ASSERT(feature_ < CPUFeatures::kNumberOfFeatures);
148     // cpu_features_->Has(kNone) is always true, so this will terminate even if
149     // the features list is empty.
150   } while (!cpu_features_->Has(feature_));
151   return *this;
152 }
153 
operator ++(int)154 CPUFeaturesConstIterator CPUFeaturesConstIterator::operator++(int) {  // Postfix
155   CPUFeaturesConstIterator result = *this;
156   ++(*this);
157   return result;
158 }
159 
160 }  // namespace vixl
161