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
28 #include "jit/arm64/vixl/Cpu-Features-vixl.h"
29
30 #include <ostream>
31
32 #include "jit/arm64/vixl/Cpu-vixl.h"
33 #include "jit/arm64/vixl/Globals-vixl.h"
34 #include "jit/arm64/vixl/Utils-vixl.h"
35
36 #define VIXL_USE_AARCH64_CPU_HELPERS
37
38 namespace vixl {
39
MakeFeatureMask(CPUFeatures::Feature feature)40 static 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
CPUFeatures(Feature feature0,Feature feature1,Feature feature2,Feature feature3)52 CPUFeatures::CPUFeatures(Feature feature0,
53 Feature feature1,
54 Feature feature2,
55 Feature feature3)
56 : features_(0) {
57 Combine(feature0, feature1, feature2, feature3);
58 }
59
All()60 CPUFeatures 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
InferFromIDRegisters()68 CPUFeatures 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(CPU::InferCPUFeaturesFromIDRegisters());
75 #endif
76 return features;
77 }
78
InferFromOS(QueryIDRegistersOption option)79 CPUFeatures CPUFeatures::InferFromOS(QueryIDRegistersOption option) {
80 #ifdef VIXL_USE_AARCH64_CPU_HELPERS
81 return CPU::InferCPUFeaturesFromOS(option);
82 #else
83 USE(option);
84 return CPUFeatures();
85 #endif
86 }
87
Combine(const CPUFeatures & other)88 void CPUFeatures::Combine(const CPUFeatures& other) {
89 features_ |= other.features_;
90 }
91
Combine(Feature feature0,Feature feature1,Feature feature2,Feature feature3)92 void 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
Remove(const CPUFeatures & other)102 void CPUFeatures::Remove(const CPUFeatures& other) {
103 features_ &= ~other.features_;
104 }
105
Remove(Feature feature0,Feature feature1,Feature feature2,Feature feature3)106 void 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
With(const CPUFeatures & other) const116 CPUFeatures CPUFeatures::With(const CPUFeatures& other) const {
117 CPUFeatures f(*this);
118 f.Combine(other);
119 return f;
120 }
121
With(Feature feature0,Feature feature1,Feature feature2,Feature feature3) const122 CPUFeatures 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
Without(const CPUFeatures & other) const131 CPUFeatures CPUFeatures::Without(const CPUFeatures& other) const {
132 CPUFeatures f(*this);
133 f.Remove(other);
134 return f;
135 }
136
Without(Feature feature0,Feature feature1,Feature feature2,Feature feature3) const137 CPUFeatures 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
Has(const CPUFeatures & other) const146 bool CPUFeatures::Has(const CPUFeatures& other) const {
147 return (features_ & other.features_) == other.features_;
148 }
149
Has(Feature feature0,Feature feature1,Feature feature2,Feature feature3) const150 bool 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
Count() const159 size_t CPUFeatures::Count() const { return CountSetBits(features_); }
160
operator <<(std::ostream & os,CPUFeatures::Feature feature)161 std::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;
167 VIXL_CPU_FEATURE_LIST(VIXL_FORMAT_FEATURE)
168 #undef VIXL_FORMAT_FEATURE
169 case CPUFeatures::kNone:
170 return os << "none";
171 case CPUFeatures::kNumberOfFeatures:
172 VIXL_UNREACHABLE();
173 }
174 // clang-format on
175 VIXL_UNREACHABLE();
176 return os;
177 }
178
begin() const179 CPUFeatures::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
end() const188 CPUFeatures::const_iterator CPUFeatures::end() const {
189 return const_iterator(this, kNone);
190 }
191
operator <<(std::ostream & os,const CPUFeatures & features)192 std::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
operator ==(const CPUFeaturesConstIterator & other) const202 bool CPUFeaturesConstIterator::operator==(
203 const CPUFeaturesConstIterator& other) const {
204 VIXL_ASSERT(IsValid());
205 return (cpu_features_ == other.cpu_features_) && (feature_ == other.feature_);
206 }
207
operator ++()208 CPUFeatures::Feature CPUFeaturesConstIterator::operator++() { // Prefix
209 VIXL_ASSERT(IsValid());
210 do {
211 // Find the next feature. The order is unspecified.
212 feature_ = static_cast<CPUFeatures::Feature>(feature_ + 1);
213 if (feature_ == CPUFeatures::kNumberOfFeatures) {
214 feature_ = CPUFeatures::kNone;
215 VIXL_STATIC_ASSERT(CPUFeatures::kNone == -1);
216 }
217 VIXL_ASSERT(CPUFeatures::kNone <= feature_);
218 VIXL_ASSERT(feature_ < CPUFeatures::kNumberOfFeatures);
219 // 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
operator ++(int)225 CPUFeatures::Feature CPUFeaturesConstIterator::operator++(int) { // Postfix
226 CPUFeatures::Feature result = feature_;
227 ++(*this);
228 return result;
229 }
230
231 } // namespace vixl
232