blob: 5c95c2014a941ba56ca55c1ed86d21dc269500e3 [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 {
Jacob Bramleycaa40ee2020-07-08 20:46:38 +0100180 // For iterators in general, it's undefined to increment `end()`, but here we
181 // control the implementation and it is safe to do this.
182 return ++end();
Jacob Bramley2af191d2018-05-16 10:22:44 +0100183}
184
185CPUFeatures::const_iterator CPUFeatures::end() const {
186 return const_iterator(this, kNone);
187}
188
189std::ostream& operator<<(std::ostream& os, const CPUFeatures& features) {
Jacob Bramleycaa40ee2020-07-08 20:46:38 +0100190 bool need_separator = false;
191 for (CPUFeatures::Feature feature : features) {
192 if (need_separator) os << ", ";
193 need_separator = true;
194 os << feature;
Jacob Bramley2af191d2018-05-16 10:22:44 +0100195 }
196 return os;
197}
198
199bool CPUFeaturesConstIterator::operator==(
200 const CPUFeaturesConstIterator& other) const {
201 VIXL_ASSERT(IsValid());
202 return (cpu_features_ == other.cpu_features_) && (feature_ == other.feature_);
203}
204
Jacob Bramleycaa40ee2020-07-08 20:46:38 +0100205CPUFeaturesConstIterator& CPUFeaturesConstIterator::operator++() { // Prefix
Jacob Bramley2af191d2018-05-16 10:22:44 +0100206 VIXL_ASSERT(IsValid());
207 do {
208 // Find the next feature. The order is unspecified.
Jacob Bramleyfdf332a2018-09-17 11:17:54 +0100209 feature_ = static_cast<CPUFeatures::Feature>(feature_ + 1);
210 if (feature_ == CPUFeatures::kNumberOfFeatures) {
211 feature_ = CPUFeatures::kNone;
212 VIXL_STATIC_ASSERT(CPUFeatures::kNone == -1);
Jacob Bramley2af191d2018-05-16 10:22:44 +0100213 }
Jacob Bramleyfdf332a2018-09-17 11:17:54 +0100214 VIXL_ASSERT(CPUFeatures::kNone <= feature_);
215 VIXL_ASSERT(feature_ < CPUFeatures::kNumberOfFeatures);
Jacob Bramley2af191d2018-05-16 10:22:44 +0100216 // cpu_features_->Has(kNone) is always true, so this will terminate even if
217 // the features list is empty.
218 } while (!cpu_features_->Has(feature_));
Jacob Bramleycaa40ee2020-07-08 20:46:38 +0100219 return *this;
Jacob Bramley2af191d2018-05-16 10:22:44 +0100220}
221
Jacob Bramleycaa40ee2020-07-08 20:46:38 +0100222CPUFeaturesConstIterator CPUFeaturesConstIterator::operator++(int) { // Postfix
223 CPUFeaturesConstIterator result = *this;
Jacob Bramley2af191d2018-05-16 10:22:44 +0100224 ++(*this);
225 return result;
226}
227
228} // namespace vixl