blob: ea1e0d3e175a387283cdb4fa6e4be395069c363e [file] [log] [blame]
Jacob Bramley2af191d2018-05-16 10:22:44 +01001// 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
Jacob Bramley48934322019-02-04 18:27:53 +000033#if defined(__aarch64__) && defined(VIXL_INCLUDE_TARGET_AARCH64)
34#include "aarch64/cpu-aarch64.h"
35#define VIXL_USE_AARCH64_CPU_HELPERS
36#endif
37
Jacob Bramley2af191d2018-05-16 10:22:44 +010038namespace vixl {
39
40static uint64_t MakeFeatureMask(CPUFeatures::Feature feature) {
41 if (feature == CPUFeatures::kNone) {
42 return 0;
43 } else {
44 // Check that the shift is well-defined, and that the feature is valid.
45 VIXL_STATIC_ASSERT(CPUFeatures::kNumberOfFeatures <=
46 (sizeof(uint64_t) * 8));
47 VIXL_ASSERT(feature < CPUFeatures::kNumberOfFeatures);
48 return UINT64_C(1) << feature;
49 }
50}
51
52CPUFeatures::CPUFeatures(Feature feature0,
53 Feature feature1,
54 Feature feature2,
55 Feature feature3)
56 : features_(0) {
57 Combine(feature0, feature1, feature2, feature3);
58}
59
60CPUFeatures CPUFeatures::All() {
61 CPUFeatures all;
62 // Check that the shift is well-defined.
63 VIXL_STATIC_ASSERT(CPUFeatures::kNumberOfFeatures < (sizeof(uint64_t) * 8));
64 all.features_ = (UINT64_C(1) << kNumberOfFeatures) - 1;
65 return all;
66}
67
Jacob Bramley48934322019-02-04 18:27:53 +000068CPUFeatures CPUFeatures::InferFromIDRegisters() {
69 // This function assumes that kIDRegisterEmulation is available.
70 CPUFeatures features(CPUFeatures::kIDRegisterEmulation);
71#ifdef VIXL_USE_AARCH64_CPU_HELPERS
72 // Note that the Linux kernel filters these values during emulation, so the
73 // results may not exactly match the expected hardware support.
74 features.Combine(aarch64::CPU::InferCPUFeaturesFromIDRegisters());
75#endif
76 return features;
77}
78
79CPUFeatures CPUFeatures::InferFromOS(QueryIDRegistersOption option) {
80#ifdef VIXL_USE_AARCH64_CPU_HELPERS
81 return aarch64::CPU::InferCPUFeaturesFromOS(option);
82#else
83 USE(option);
Jacob Bramley2af191d2018-05-16 10:22:44 +010084 return CPUFeatures();
Jacob Bramley48934322019-02-04 18:27:53 +000085#endif
Jacob Bramley2af191d2018-05-16 10:22:44 +010086}
87
88void CPUFeatures::Combine(const CPUFeatures& other) {
89 features_ |= other.features_;
90}
91
92void CPUFeatures::Combine(Feature feature0,
93 Feature feature1,
94 Feature feature2,
95 Feature feature3) {
96 features_ |= MakeFeatureMask(feature0);
97 features_ |= MakeFeatureMask(feature1);
98 features_ |= MakeFeatureMask(feature2);
99 features_ |= MakeFeatureMask(feature3);
100}
101
102void CPUFeatures::Remove(const CPUFeatures& other) {
103 features_ &= ~other.features_;
104}
105
106void CPUFeatures::Remove(Feature feature0,
107 Feature feature1,
108 Feature feature2,
109 Feature feature3) {
110 features_ &= ~MakeFeatureMask(feature0);
111 features_ &= ~MakeFeatureMask(feature1);
112 features_ &= ~MakeFeatureMask(feature2);
113 features_ &= ~MakeFeatureMask(feature3);
114}
115
116CPUFeatures CPUFeatures::With(const CPUFeatures& other) const {
117 CPUFeatures f(*this);
118 f.Combine(other);
119 return f;
120}
121
122CPUFeatures CPUFeatures::With(Feature feature0,
123 Feature feature1,
124 Feature feature2,
125 Feature feature3) const {
126 CPUFeatures f(*this);
127 f.Combine(feature0, feature1, feature2, feature3);
128 return f;
129}
130
131CPUFeatures CPUFeatures::Without(const CPUFeatures& other) const {
132 CPUFeatures f(*this);
133 f.Remove(other);
134 return f;
135}
136
137CPUFeatures CPUFeatures::Without(Feature feature0,
138 Feature feature1,
139 Feature feature2,
140 Feature feature3) const {
141 CPUFeatures f(*this);
142 f.Remove(feature0, feature1, feature2, feature3);
143 return f;
144}
145
146bool CPUFeatures::Has(const CPUFeatures& other) const {
147 return (features_ & other.features_) == other.features_;
148}
149
150bool CPUFeatures::Has(Feature feature0,
151 Feature feature1,
152 Feature feature2,
153 Feature feature3) const {
154 uint64_t mask = MakeFeatureMask(feature0) | MakeFeatureMask(feature1) |
155 MakeFeatureMask(feature2) | MakeFeatureMask(feature3);
156 return (features_ & mask) == mask;
157}
158
Jacob Bramleyc44ce3d2018-06-12 15:39:09 +0100159size_t CPUFeatures::Count() const { return CountSetBits(features_); }
160
Jacob Bramley2af191d2018-05-16 10:22:44 +0100161std::ostream& operator<<(std::ostream& os, CPUFeatures::Feature feature) {
162 // clang-format off
163 switch (feature) {
164#define VIXL_FORMAT_FEATURE(SYMBOL, NAME, CPUINFO) \
165 case CPUFeatures::SYMBOL: \
166 return os << NAME;
167VIXL_CPU_FEATURE_LIST(VIXL_FORMAT_FEATURE)
168#undef VIXL_FORMAT_FEATURE
169 case CPUFeatures::kNone:
170 return os << "none";
Jacob Bramleyfdf332a2018-09-17 11:17:54 +0100171 case CPUFeatures::kNumberOfFeatures:
172 VIXL_UNREACHABLE();
Jacob Bramley2af191d2018-05-16 10:22:44 +0100173 }
174 // clang-format on
175 VIXL_UNREACHABLE();
176 return os;
177}
178
179CPUFeatures::const_iterator CPUFeatures::begin() const {
180 if (features_ == 0) return const_iterator(this, kNone);
181
182 int feature_number = CountTrailingZeros(features_);
183 vixl::CPUFeatures::Feature feature =
184 static_cast<CPUFeatures::Feature>(feature_number);
185 return const_iterator(this, feature);
186}
187
188CPUFeatures::const_iterator CPUFeatures::end() const {
189 return const_iterator(this, kNone);
190}
191
192std::ostream& operator<<(std::ostream& os, const CPUFeatures& features) {
193 CPUFeatures::const_iterator it = features.begin();
194 while (it != features.end()) {
195 os << *it;
196 ++it;
197 if (it != features.end()) os << ", ";
198 }
199 return os;
200}
201
202bool CPUFeaturesConstIterator::operator==(
203 const CPUFeaturesConstIterator& other) const {
204 VIXL_ASSERT(IsValid());
205 return (cpu_features_ == other.cpu_features_) && (feature_ == other.feature_);
206}
207
208CPUFeatures::Feature CPUFeaturesConstIterator::operator++() { // Prefix
209 VIXL_ASSERT(IsValid());
210 do {
211 // Find the next feature. The order is unspecified.
Jacob Bramleyfdf332a2018-09-17 11:17:54 +0100212 feature_ = static_cast<CPUFeatures::Feature>(feature_ + 1);
213 if (feature_ == CPUFeatures::kNumberOfFeatures) {
214 feature_ = CPUFeatures::kNone;
215 VIXL_STATIC_ASSERT(CPUFeatures::kNone == -1);
Jacob Bramley2af191d2018-05-16 10:22:44 +0100216 }
Jacob Bramleyfdf332a2018-09-17 11:17:54 +0100217 VIXL_ASSERT(CPUFeatures::kNone <= feature_);
218 VIXL_ASSERT(feature_ < CPUFeatures::kNumberOfFeatures);
Jacob Bramley2af191d2018-05-16 10:22:44 +0100219 // cpu_features_->Has(kNone) is always true, so this will terminate even if
220 // the features list is empty.
221 } while (!cpu_features_->Has(feature_));
222 return feature_;
223}
224
225CPUFeatures::Feature CPUFeaturesConstIterator::operator++(int) { // Postfix
226 CPUFeatures::Feature result = feature_;
227 ++(*this);
228 return result;
229}
230
231} // namespace vixl