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