1*f5c631daSSadaf Ebrahimi // Copyright 2018, VIXL authors
2*f5c631daSSadaf Ebrahimi // All rights reserved.
3*f5c631daSSadaf Ebrahimi //
4*f5c631daSSadaf Ebrahimi // Redistribution and use in source and binary forms, with or without
5*f5c631daSSadaf Ebrahimi // modification, are permitted provided that the following conditions are met:
6*f5c631daSSadaf Ebrahimi //
7*f5c631daSSadaf Ebrahimi // * Redistributions of source code must retain the above copyright notice,
8*f5c631daSSadaf Ebrahimi // this list of conditions and the following disclaimer.
9*f5c631daSSadaf Ebrahimi // * Redistributions in binary form must reproduce the above copyright notice,
10*f5c631daSSadaf Ebrahimi // this list of conditions and the following disclaimer in the documentation
11*f5c631daSSadaf Ebrahimi // and/or other materials provided with the distribution.
12*f5c631daSSadaf Ebrahimi // * Neither the name of ARM Limited nor the names of its contributors may be
13*f5c631daSSadaf Ebrahimi // used to endorse or promote products derived from this software without
14*f5c631daSSadaf Ebrahimi // specific prior written permission.
15*f5c631daSSadaf Ebrahimi //
16*f5c631daSSadaf Ebrahimi // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17*f5c631daSSadaf Ebrahimi // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18*f5c631daSSadaf Ebrahimi // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19*f5c631daSSadaf Ebrahimi // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20*f5c631daSSadaf Ebrahimi // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*f5c631daSSadaf Ebrahimi // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22*f5c631daSSadaf Ebrahimi // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23*f5c631daSSadaf Ebrahimi // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*f5c631daSSadaf Ebrahimi // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25*f5c631daSSadaf Ebrahimi // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*f5c631daSSadaf Ebrahimi
27*f5c631daSSadaf Ebrahimi #include <ostream>
28*f5c631daSSadaf Ebrahimi
29*f5c631daSSadaf Ebrahimi #include "cpu-features.h"
30*f5c631daSSadaf Ebrahimi #include "globals-vixl.h"
31*f5c631daSSadaf Ebrahimi #include "utils-vixl.h"
32*f5c631daSSadaf Ebrahimi
33*f5c631daSSadaf Ebrahimi #if defined(__aarch64__) && defined(VIXL_INCLUDE_TARGET_AARCH64)
34*f5c631daSSadaf Ebrahimi #include "aarch64/cpu-aarch64.h"
35*f5c631daSSadaf Ebrahimi #define VIXL_USE_AARCH64_CPU_HELPERS
36*f5c631daSSadaf Ebrahimi #endif
37*f5c631daSSadaf Ebrahimi
38*f5c631daSSadaf Ebrahimi namespace vixl {
39*f5c631daSSadaf Ebrahimi
All()40*f5c631daSSadaf Ebrahimi CPUFeatures CPUFeatures::All() {
41*f5c631daSSadaf Ebrahimi CPUFeatures all;
42*f5c631daSSadaf Ebrahimi all.features_.set();
43*f5c631daSSadaf Ebrahimi return all;
44*f5c631daSSadaf Ebrahimi }
45*f5c631daSSadaf Ebrahimi
InferFromIDRegisters()46*f5c631daSSadaf Ebrahimi CPUFeatures CPUFeatures::InferFromIDRegisters() {
47*f5c631daSSadaf Ebrahimi // This function assumes that kIDRegisterEmulation is available.
48*f5c631daSSadaf Ebrahimi CPUFeatures features(CPUFeatures::kIDRegisterEmulation);
49*f5c631daSSadaf Ebrahimi #ifdef VIXL_USE_AARCH64_CPU_HELPERS
50*f5c631daSSadaf Ebrahimi // Note that the Linux kernel filters these values during emulation, so the
51*f5c631daSSadaf Ebrahimi // results may not exactly match the expected hardware support.
52*f5c631daSSadaf Ebrahimi features.Combine(aarch64::CPU::InferCPUFeaturesFromIDRegisters());
53*f5c631daSSadaf Ebrahimi #endif
54*f5c631daSSadaf Ebrahimi return features;
55*f5c631daSSadaf Ebrahimi }
56*f5c631daSSadaf Ebrahimi
InferFromOS(QueryIDRegistersOption option)57*f5c631daSSadaf Ebrahimi CPUFeatures CPUFeatures::InferFromOS(QueryIDRegistersOption option) {
58*f5c631daSSadaf Ebrahimi #ifdef VIXL_USE_AARCH64_CPU_HELPERS
59*f5c631daSSadaf Ebrahimi return aarch64::CPU::InferCPUFeaturesFromOS(option);
60*f5c631daSSadaf Ebrahimi #else
61*f5c631daSSadaf Ebrahimi USE(option);
62*f5c631daSSadaf Ebrahimi return CPUFeatures();
63*f5c631daSSadaf Ebrahimi #endif
64*f5c631daSSadaf Ebrahimi }
65*f5c631daSSadaf Ebrahimi
Combine(const CPUFeatures & other)66*f5c631daSSadaf Ebrahimi void CPUFeatures::Combine(const CPUFeatures& other) {
67*f5c631daSSadaf Ebrahimi features_ |= other.features_;
68*f5c631daSSadaf Ebrahimi }
69*f5c631daSSadaf Ebrahimi
Combine(Feature feature)70*f5c631daSSadaf Ebrahimi void CPUFeatures::Combine(Feature feature) {
71*f5c631daSSadaf Ebrahimi if (feature != CPUFeatures::kNone) features_.set(feature);
72*f5c631daSSadaf Ebrahimi }
73*f5c631daSSadaf Ebrahimi
Remove(const CPUFeatures & other)74*f5c631daSSadaf Ebrahimi void CPUFeatures::Remove(const CPUFeatures& other) {
75*f5c631daSSadaf Ebrahimi features_ &= ~other.features_;
76*f5c631daSSadaf Ebrahimi }
77*f5c631daSSadaf Ebrahimi
Remove(Feature feature)78*f5c631daSSadaf Ebrahimi void CPUFeatures::Remove(Feature feature) {
79*f5c631daSSadaf Ebrahimi if (feature != CPUFeatures::kNone) features_.reset(feature);
80*f5c631daSSadaf Ebrahimi }
81*f5c631daSSadaf Ebrahimi
Has(const CPUFeatures & other) const82*f5c631daSSadaf Ebrahimi bool CPUFeatures::Has(const CPUFeatures& other) const {
83*f5c631daSSadaf Ebrahimi return (features_ & other.features_) == other.features_;
84*f5c631daSSadaf Ebrahimi }
85*f5c631daSSadaf Ebrahimi
Has(Feature feature) const86*f5c631daSSadaf Ebrahimi bool CPUFeatures::Has(Feature feature) const {
87*f5c631daSSadaf Ebrahimi return (feature == CPUFeatures::kNone) || features_[feature];
88*f5c631daSSadaf Ebrahimi }
89*f5c631daSSadaf Ebrahimi
Count() const90*f5c631daSSadaf Ebrahimi size_t CPUFeatures::Count() const { return features_.count(); }
91*f5c631daSSadaf Ebrahimi
operator <<(std::ostream & os,CPUFeatures::Feature feature)92*f5c631daSSadaf Ebrahimi std::ostream& operator<<(std::ostream& os, CPUFeatures::Feature feature) {
93*f5c631daSSadaf Ebrahimi // clang-format off
94*f5c631daSSadaf Ebrahimi switch (feature) {
95*f5c631daSSadaf Ebrahimi #define VIXL_FORMAT_FEATURE(SYMBOL, NAME, CPUINFO) \
96*f5c631daSSadaf Ebrahimi case CPUFeatures::SYMBOL: \
97*f5c631daSSadaf Ebrahimi return os << NAME;
98*f5c631daSSadaf Ebrahimi VIXL_CPU_FEATURE_LIST(VIXL_FORMAT_FEATURE)
99*f5c631daSSadaf Ebrahimi #undef VIXL_FORMAT_FEATURE
100*f5c631daSSadaf Ebrahimi case CPUFeatures::kNone:
101*f5c631daSSadaf Ebrahimi return os << "none";
102*f5c631daSSadaf Ebrahimi case CPUFeatures::kNumberOfFeatures:
103*f5c631daSSadaf Ebrahimi VIXL_UNREACHABLE();
104*f5c631daSSadaf Ebrahimi }
105*f5c631daSSadaf Ebrahimi // clang-format on
106*f5c631daSSadaf Ebrahimi VIXL_UNREACHABLE();
107*f5c631daSSadaf Ebrahimi return os;
108*f5c631daSSadaf Ebrahimi }
109*f5c631daSSadaf Ebrahimi
begin() const110*f5c631daSSadaf Ebrahimi CPUFeatures::const_iterator CPUFeatures::begin() const {
111*f5c631daSSadaf Ebrahimi // For iterators in general, it's undefined to increment `end()`, but here we
112*f5c631daSSadaf Ebrahimi // control the implementation and it is safe to do this.
113*f5c631daSSadaf Ebrahimi return ++end();
114*f5c631daSSadaf Ebrahimi }
115*f5c631daSSadaf Ebrahimi
end() const116*f5c631daSSadaf Ebrahimi CPUFeatures::const_iterator CPUFeatures::end() const {
117*f5c631daSSadaf Ebrahimi return const_iterator(this, kNone);
118*f5c631daSSadaf Ebrahimi }
119*f5c631daSSadaf Ebrahimi
operator <<(std::ostream & os,const CPUFeatures & features)120*f5c631daSSadaf Ebrahimi std::ostream& operator<<(std::ostream& os, const CPUFeatures& features) {
121*f5c631daSSadaf Ebrahimi bool need_separator = false;
122*f5c631daSSadaf Ebrahimi for (CPUFeatures::Feature feature : features) {
123*f5c631daSSadaf Ebrahimi if (need_separator) os << ", ";
124*f5c631daSSadaf Ebrahimi need_separator = true;
125*f5c631daSSadaf Ebrahimi os << feature;
126*f5c631daSSadaf Ebrahimi }
127*f5c631daSSadaf Ebrahimi return os;
128*f5c631daSSadaf Ebrahimi }
129*f5c631daSSadaf Ebrahimi
operator ==(const CPUFeaturesConstIterator & other) const130*f5c631daSSadaf Ebrahimi bool CPUFeaturesConstIterator::operator==(
131*f5c631daSSadaf Ebrahimi const CPUFeaturesConstIterator& other) const {
132*f5c631daSSadaf Ebrahimi VIXL_ASSERT(IsValid());
133*f5c631daSSadaf Ebrahimi return (cpu_features_ == other.cpu_features_) && (feature_ == other.feature_);
134*f5c631daSSadaf Ebrahimi }
135*f5c631daSSadaf Ebrahimi
operator ++()136*f5c631daSSadaf Ebrahimi CPUFeaturesConstIterator& CPUFeaturesConstIterator::operator++() { // Prefix
137*f5c631daSSadaf Ebrahimi VIXL_ASSERT(IsValid());
138*f5c631daSSadaf Ebrahimi do {
139*f5c631daSSadaf Ebrahimi // Find the next feature. The order is unspecified.
140*f5c631daSSadaf Ebrahimi feature_ = static_cast<CPUFeatures::Feature>(feature_ + 1);
141*f5c631daSSadaf Ebrahimi if (feature_ == CPUFeatures::kNumberOfFeatures) {
142*f5c631daSSadaf Ebrahimi feature_ = CPUFeatures::kNone;
143*f5c631daSSadaf Ebrahimi VIXL_STATIC_ASSERT(CPUFeatures::kNone == -1);
144*f5c631daSSadaf Ebrahimi }
145*f5c631daSSadaf Ebrahimi VIXL_ASSERT(CPUFeatures::kNone <= feature_);
146*f5c631daSSadaf Ebrahimi VIXL_ASSERT(feature_ < CPUFeatures::kNumberOfFeatures);
147*f5c631daSSadaf Ebrahimi // cpu_features_->Has(kNone) is always true, so this will terminate even if
148*f5c631daSSadaf Ebrahimi // the features list is empty.
149*f5c631daSSadaf Ebrahimi } while (!cpu_features_->Has(feature_));
150*f5c631daSSadaf Ebrahimi return *this;
151*f5c631daSSadaf Ebrahimi }
152*f5c631daSSadaf Ebrahimi
operator ++(int)153*f5c631daSSadaf Ebrahimi CPUFeaturesConstIterator CPUFeaturesConstIterator::operator++(int) { // Postfix
154*f5c631daSSadaf Ebrahimi CPUFeaturesConstIterator result = *this;
155*f5c631daSSadaf Ebrahimi ++(*this);
156*f5c631daSSadaf Ebrahimi return result;
157*f5c631daSSadaf Ebrahimi }
158*f5c631daSSadaf Ebrahimi
159*f5c631daSSadaf Ebrahimi } // namespace vixl
160