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 <ostream>
28
29 #include "cpu-features.h"
30 #include "globals-vixl.h"
31 #include "utils-vixl.h"
32
33 #if defined(__aarch64__) && defined(VIXL_INCLUDE_TARGET_AARCH64)
34 #include "aarch64/cpu-aarch64.h"
35 #define VIXL_USE_AARCH64_CPU_HELPERS
36 #endif
37
38 namespace vixl {
39
All()40 CPUFeatures CPUFeatures::All() {
41 CPUFeatures all;
42 all.features_.set();
43 return all;
44 }
45
InferFromIDRegisters()46 CPUFeatures CPUFeatures::InferFromIDRegisters() {
47 // This function assumes that kIDRegisterEmulation is available.
48 CPUFeatures features(CPUFeatures::kIDRegisterEmulation);
49 #ifdef VIXL_USE_AARCH64_CPU_HELPERS
50 // Note that the Linux kernel filters these values during emulation, so the
51 // results may not exactly match the expected hardware support.
52 features.Combine(aarch64::CPU::InferCPUFeaturesFromIDRegisters());
53 #endif
54 return features;
55 }
56
InferFromOS(QueryIDRegistersOption option)57 CPUFeatures CPUFeatures::InferFromOS(QueryIDRegistersOption option) {
58 #ifdef VIXL_USE_AARCH64_CPU_HELPERS
59 return aarch64::CPU::InferCPUFeaturesFromOS(option);
60 #else
61 USE(option);
62 return CPUFeatures();
63 #endif
64 }
65
Combine(const CPUFeatures & other)66 void CPUFeatures::Combine(const CPUFeatures& other) {
67 features_ |= other.features_;
68 }
69
Combine(Feature feature)70 void CPUFeatures::Combine(Feature feature) {
71 if (feature != CPUFeatures::kNone) features_.set(feature);
72 }
73
Remove(const CPUFeatures & other)74 void CPUFeatures::Remove(const CPUFeatures& other) {
75 features_ &= ~other.features_;
76 }
77
Remove(Feature feature)78 void CPUFeatures::Remove(Feature feature) {
79 if (feature != CPUFeatures::kNone) features_.reset(feature);
80 }
81
Has(const CPUFeatures & other) const82 bool CPUFeatures::Has(const CPUFeatures& other) const {
83 return (features_ & other.features_) == other.features_;
84 }
85
Has(Feature feature) const86 bool CPUFeatures::Has(Feature feature) const {
87 return (feature == CPUFeatures::kNone) || features_[feature];
88 }
89
Count() const90 size_t CPUFeatures::Count() const { return features_.count(); }
91
operator <<(std::ostream & os,CPUFeatures::Feature feature)92 std::ostream& operator<<(std::ostream& os, CPUFeatures::Feature feature) {
93 // clang-format off
94 switch (feature) {
95 #define VIXL_FORMAT_FEATURE(SYMBOL, NAME, CPUINFO) \
96 case CPUFeatures::SYMBOL: \
97 return os << NAME;
98 VIXL_CPU_FEATURE_LIST(VIXL_FORMAT_FEATURE)
99 #undef VIXL_FORMAT_FEATURE
100 case CPUFeatures::kNone:
101 return os << "none";
102 case CPUFeatures::kNumberOfFeatures:
103 VIXL_UNREACHABLE();
104 }
105 // clang-format on
106 VIXL_UNREACHABLE();
107 return os;
108 }
109
begin() const110 CPUFeatures::const_iterator CPUFeatures::begin() const {
111 // For iterators in general, it's undefined to increment `end()`, but here we
112 // control the implementation and it is safe to do this.
113 return ++end();
114 }
115
end() const116 CPUFeatures::const_iterator CPUFeatures::end() const {
117 return const_iterator(this, kNone);
118 }
119
operator <<(std::ostream & os,const CPUFeatures & features)120 std::ostream& operator<<(std::ostream& os, const CPUFeatures& features) {
121 bool need_separator = false;
122 for (CPUFeatures::Feature feature : features) {
123 if (need_separator) os << ", ";
124 need_separator = true;
125 os << feature;
126 }
127 return os;
128 }
129
operator ==(const CPUFeaturesConstIterator & other) const130 bool CPUFeaturesConstIterator::operator==(
131 const CPUFeaturesConstIterator& other) const {
132 VIXL_ASSERT(IsValid());
133 return (cpu_features_ == other.cpu_features_) && (feature_ == other.feature_);
134 }
135
operator ++()136 CPUFeaturesConstIterator& CPUFeaturesConstIterator::operator++() { // Prefix
137 VIXL_ASSERT(IsValid());
138 do {
139 // Find the next feature. The order is unspecified.
140 feature_ = static_cast<CPUFeatures::Feature>(feature_ + 1);
141 if (feature_ == CPUFeatures::kNumberOfFeatures) {
142 feature_ = CPUFeatures::kNone;
143 VIXL_STATIC_ASSERT(CPUFeatures::kNone == -1);
144 }
145 VIXL_ASSERT(CPUFeatures::kNone <= feature_);
146 VIXL_ASSERT(feature_ < CPUFeatures::kNumberOfFeatures);
147 // cpu_features_->Has(kNone) is always true, so this will terminate even if
148 // the features list is empty.
149 } while (!cpu_features_->Has(feature_));
150 return *this;
151 }
152
operator ++(int)153 CPUFeaturesConstIterator CPUFeaturesConstIterator::operator++(int) { // Postfix
154 CPUFeaturesConstIterator result = *this;
155 ++(*this);
156 return result;
157 }
158
159 } // namespace vixl
160