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