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