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 namespace vixl {
34
MakeFeatureMask(CPUFeatures::Feature feature)35 static uint64_t MakeFeatureMask(CPUFeatures::Feature feature) {
36 if (feature == CPUFeatures::kNone) {
37 return 0;
38 } else {
39 // Check that the shift is well-defined, and that the feature is valid.
40 VIXL_STATIC_ASSERT(CPUFeatures::kNumberOfFeatures <=
41 (sizeof(uint64_t) * 8));
42 VIXL_ASSERT(feature < CPUFeatures::kNumberOfFeatures);
43 return UINT64_C(1) << feature;
44 }
45 }
46
CPUFeatures(Feature feature0,Feature feature1,Feature feature2,Feature feature3)47 CPUFeatures::CPUFeatures(Feature feature0,
48 Feature feature1,
49 Feature feature2,
50 Feature feature3)
51 : features_(0) {
52 Combine(feature0, feature1, feature2, feature3);
53 }
54
All()55 CPUFeatures CPUFeatures::All() {
56 CPUFeatures all;
57 // Check that the shift is well-defined.
58 VIXL_STATIC_ASSERT(CPUFeatures::kNumberOfFeatures < (sizeof(uint64_t) * 8));
59 all.features_ = (UINT64_C(1) << kNumberOfFeatures) - 1;
60 return all;
61 }
62
InferFromOS()63 CPUFeatures CPUFeatures::InferFromOS() {
64 // TODO: Actually infer features from the OS.
65 return CPUFeatures();
66 }
67
Combine(const CPUFeatures & other)68 void CPUFeatures::Combine(const CPUFeatures& other) {
69 features_ |= other.features_;
70 }
71
Combine(Feature feature0,Feature feature1,Feature feature2,Feature feature3)72 void CPUFeatures::Combine(Feature feature0,
73 Feature feature1,
74 Feature feature2,
75 Feature feature3) {
76 features_ |= MakeFeatureMask(feature0);
77 features_ |= MakeFeatureMask(feature1);
78 features_ |= MakeFeatureMask(feature2);
79 features_ |= MakeFeatureMask(feature3);
80 }
81
Remove(const CPUFeatures & other)82 void CPUFeatures::Remove(const CPUFeatures& other) {
83 features_ &= ~other.features_;
84 }
85
Remove(Feature feature0,Feature feature1,Feature feature2,Feature feature3)86 void CPUFeatures::Remove(Feature feature0,
87 Feature feature1,
88 Feature feature2,
89 Feature feature3) {
90 features_ &= ~MakeFeatureMask(feature0);
91 features_ &= ~MakeFeatureMask(feature1);
92 features_ &= ~MakeFeatureMask(feature2);
93 features_ &= ~MakeFeatureMask(feature3);
94 }
95
With(const CPUFeatures & other) const96 CPUFeatures CPUFeatures::With(const CPUFeatures& other) const {
97 CPUFeatures f(*this);
98 f.Combine(other);
99 return f;
100 }
101
With(Feature feature0,Feature feature1,Feature feature2,Feature feature3) const102 CPUFeatures CPUFeatures::With(Feature feature0,
103 Feature feature1,
104 Feature feature2,
105 Feature feature3) const {
106 CPUFeatures f(*this);
107 f.Combine(feature0, feature1, feature2, feature3);
108 return f;
109 }
110
Without(const CPUFeatures & other) const111 CPUFeatures CPUFeatures::Without(const CPUFeatures& other) const {
112 CPUFeatures f(*this);
113 f.Remove(other);
114 return f;
115 }
116
Without(Feature feature0,Feature feature1,Feature feature2,Feature feature3) const117 CPUFeatures CPUFeatures::Without(Feature feature0,
118 Feature feature1,
119 Feature feature2,
120 Feature feature3) const {
121 CPUFeatures f(*this);
122 f.Remove(feature0, feature1, feature2, feature3);
123 return f;
124 }
125
Has(const CPUFeatures & other) const126 bool CPUFeatures::Has(const CPUFeatures& other) const {
127 return (features_ & other.features_) == other.features_;
128 }
129
Has(Feature feature0,Feature feature1,Feature feature2,Feature feature3) const130 bool CPUFeatures::Has(Feature feature0,
131 Feature feature1,
132 Feature feature2,
133 Feature feature3) const {
134 uint64_t mask = MakeFeatureMask(feature0) | MakeFeatureMask(feature1) |
135 MakeFeatureMask(feature2) | MakeFeatureMask(feature3);
136 return (features_ & mask) == mask;
137 }
138
Count() const139 size_t CPUFeatures::Count() const { return CountSetBits(features_); }
140
operator <<(std::ostream & os,CPUFeatures::Feature feature)141 std::ostream& operator<<(std::ostream& os, CPUFeatures::Feature feature) {
142 // clang-format off
143 switch (feature) {
144 #define VIXL_FORMAT_FEATURE(SYMBOL, NAME, CPUINFO) \
145 case CPUFeatures::SYMBOL: \
146 return os << NAME;
147 VIXL_CPU_FEATURE_LIST(VIXL_FORMAT_FEATURE)
148 #undef VIXL_FORMAT_FEATURE
149 case CPUFeatures::kNone:
150 return os << "none";
151 case CPUFeatures::kNumberOfFeatures:
152 VIXL_UNREACHABLE();
153 }
154 // clang-format on
155 VIXL_UNREACHABLE();
156 return os;
157 }
158
begin() const159 CPUFeatures::const_iterator CPUFeatures::begin() const {
160 if (features_ == 0) return const_iterator(this, kNone);
161
162 int feature_number = CountTrailingZeros(features_);
163 vixl::CPUFeatures::Feature feature =
164 static_cast<CPUFeatures::Feature>(feature_number);
165 return const_iterator(this, feature);
166 }
167
end() const168 CPUFeatures::const_iterator CPUFeatures::end() const {
169 return const_iterator(this, kNone);
170 }
171
operator <<(std::ostream & os,const CPUFeatures & features)172 std::ostream& operator<<(std::ostream& os, const CPUFeatures& features) {
173 CPUFeatures::const_iterator it = features.begin();
174 while (it != features.end()) {
175 os << *it;
176 ++it;
177 if (it != features.end()) os << ", ";
178 }
179 return os;
180 }
181
operator ==(const CPUFeaturesConstIterator & other) const182 bool CPUFeaturesConstIterator::operator==(
183 const CPUFeaturesConstIterator& other) const {
184 VIXL_ASSERT(IsValid());
185 return (cpu_features_ == other.cpu_features_) && (feature_ == other.feature_);
186 }
187
operator ++()188 CPUFeatures::Feature CPUFeaturesConstIterator::operator++() { // Prefix
189 VIXL_ASSERT(IsValid());
190 do {
191 // Find the next feature. The order is unspecified.
192 feature_ = static_cast<CPUFeatures::Feature>(feature_ + 1);
193 if (feature_ == CPUFeatures::kNumberOfFeatures) {
194 feature_ = CPUFeatures::kNone;
195 VIXL_STATIC_ASSERT(CPUFeatures::kNone == -1);
196 }
197 VIXL_ASSERT(CPUFeatures::kNone <= feature_);
198 VIXL_ASSERT(feature_ < CPUFeatures::kNumberOfFeatures);
199 // cpu_features_->Has(kNone) is always true, so this will terminate even if
200 // the features list is empty.
201 } while (!cpu_features_->Has(feature_));
202 return feature_;
203 }
204
operator ++(int)205 CPUFeatures::Feature CPUFeaturesConstIterator::operator++(int) { // Postfix
206 CPUFeatures::Feature result = feature_;
207 ++(*this);
208 return result;
209 }
210
211 } // namespace vixl
212