mirror of
				https://github.com/RetroDECK/Duckstation.git
				synced 2025-04-10 19:15:14 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			212 lines
		
	
	
		
			7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			212 lines
		
	
	
		
			7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2018, VIXL authors
 | |
| // All rights reserved.
 | |
| //
 | |
| // Redistribution and use in source and binary forms, with or without
 | |
| // modification, are permitted provided that the following conditions are met:
 | |
| //
 | |
| //   * Redistributions of source code must retain the above copyright notice,
 | |
| //     this list of conditions and the following disclaimer.
 | |
| //   * Redistributions in binary form must reproduce the above copyright notice,
 | |
| //     this list of conditions and the following disclaimer in the documentation
 | |
| //     and/or other materials provided with the distribution.
 | |
| //   * Neither the name of ARM Limited nor the names of its contributors may be
 | |
| //     used to endorse or promote products derived from this software without
 | |
| //     specific prior written permission.
 | |
| //
 | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
 | |
| // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | |
| // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 | |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
| 
 | |
| #include <ostream>
 | |
| 
 | |
| #include "cpu-features.h"
 | |
| #include "globals-vixl.h"
 | |
| #include "utils-vixl.h"
 | |
| 
 | |
| namespace vixl {
 | |
| 
 | |
| static uint64_t MakeFeatureMask(CPUFeatures::Feature feature) {
 | |
|   if (feature == CPUFeatures::kNone) {
 | |
|     return 0;
 | |
|   } else {
 | |
|     // Check that the shift is well-defined, and that the feature is valid.
 | |
|     VIXL_STATIC_ASSERT(CPUFeatures::kNumberOfFeatures <=
 | |
|                        (sizeof(uint64_t) * 8));
 | |
|     VIXL_ASSERT(feature < CPUFeatures::kNumberOfFeatures);
 | |
|     return UINT64_C(1) << feature;
 | |
|   }
 | |
| }
 | |
| 
 | |
| CPUFeatures::CPUFeatures(Feature feature0,
 | |
|                          Feature feature1,
 | |
|                          Feature feature2,
 | |
|                          Feature feature3)
 | |
|     : features_(0) {
 | |
|   Combine(feature0, feature1, feature2, feature3);
 | |
| }
 | |
| 
 | |
| CPUFeatures CPUFeatures::All() {
 | |
|   CPUFeatures all;
 | |
|   // Check that the shift is well-defined.
 | |
|   VIXL_STATIC_ASSERT(CPUFeatures::kNumberOfFeatures < (sizeof(uint64_t) * 8));
 | |
|   all.features_ = (UINT64_C(1) << kNumberOfFeatures) - 1;
 | |
|   return all;
 | |
| }
 | |
| 
 | |
| CPUFeatures CPUFeatures::InferFromOS() {
 | |
|   // TODO: Actually infer features from the OS.
 | |
|   return CPUFeatures();
 | |
| }
 | |
| 
 | |
| void CPUFeatures::Combine(const CPUFeatures& other) {
 | |
|   features_ |= other.features_;
 | |
| }
 | |
| 
 | |
| void CPUFeatures::Combine(Feature feature0,
 | |
|                           Feature feature1,
 | |
|                           Feature feature2,
 | |
|                           Feature feature3) {
 | |
|   features_ |= MakeFeatureMask(feature0);
 | |
|   features_ |= MakeFeatureMask(feature1);
 | |
|   features_ |= MakeFeatureMask(feature2);
 | |
|   features_ |= MakeFeatureMask(feature3);
 | |
| }
 | |
| 
 | |
| void CPUFeatures::Remove(const CPUFeatures& other) {
 | |
|   features_ &= ~other.features_;
 | |
| }
 | |
| 
 | |
| void CPUFeatures::Remove(Feature feature0,
 | |
|                          Feature feature1,
 | |
|                          Feature feature2,
 | |
|                          Feature feature3) {
 | |
|   features_ &= ~MakeFeatureMask(feature0);
 | |
|   features_ &= ~MakeFeatureMask(feature1);
 | |
|   features_ &= ~MakeFeatureMask(feature2);
 | |
|   features_ &= ~MakeFeatureMask(feature3);
 | |
| }
 | |
| 
 | |
| CPUFeatures CPUFeatures::With(const CPUFeatures& other) const {
 | |
|   CPUFeatures f(*this);
 | |
|   f.Combine(other);
 | |
|   return f;
 | |
| }
 | |
| 
 | |
| CPUFeatures CPUFeatures::With(Feature feature0,
 | |
|                               Feature feature1,
 | |
|                               Feature feature2,
 | |
|                               Feature feature3) const {
 | |
|   CPUFeatures f(*this);
 | |
|   f.Combine(feature0, feature1, feature2, feature3);
 | |
|   return f;
 | |
| }
 | |
| 
 | |
| CPUFeatures CPUFeatures::Without(const CPUFeatures& other) const {
 | |
|   CPUFeatures f(*this);
 | |
|   f.Remove(other);
 | |
|   return f;
 | |
| }
 | |
| 
 | |
| CPUFeatures CPUFeatures::Without(Feature feature0,
 | |
|                                  Feature feature1,
 | |
|                                  Feature feature2,
 | |
|                                  Feature feature3) const {
 | |
|   CPUFeatures f(*this);
 | |
|   f.Remove(feature0, feature1, feature2, feature3);
 | |
|   return f;
 | |
| }
 | |
| 
 | |
| bool CPUFeatures::Has(const CPUFeatures& other) const {
 | |
|   return (features_ & other.features_) == other.features_;
 | |
| }
 | |
| 
 | |
| bool CPUFeatures::Has(Feature feature0,
 | |
|                       Feature feature1,
 | |
|                       Feature feature2,
 | |
|                       Feature feature3) const {
 | |
|   uint64_t mask = MakeFeatureMask(feature0) | MakeFeatureMask(feature1) |
 | |
|                   MakeFeatureMask(feature2) | MakeFeatureMask(feature3);
 | |
|   return (features_ & mask) == mask;
 | |
| }
 | |
| 
 | |
| size_t CPUFeatures::Count() const { return CountSetBits(features_); }
 | |
| 
 | |
| std::ostream& operator<<(std::ostream& os, CPUFeatures::Feature feature) {
 | |
|   // clang-format off
 | |
|   switch (feature) {
 | |
| #define VIXL_FORMAT_FEATURE(SYMBOL, NAME, CPUINFO) \
 | |
|     case CPUFeatures::SYMBOL:                      \
 | |
|       return os << NAME;
 | |
| VIXL_CPU_FEATURE_LIST(VIXL_FORMAT_FEATURE)
 | |
| #undef VIXL_FORMAT_FEATURE
 | |
|     case CPUFeatures::kNone:
 | |
|       return os << "none";
 | |
|     case CPUFeatures::kNumberOfFeatures:
 | |
|       VIXL_UNREACHABLE();
 | |
|   }
 | |
|   // clang-format on
 | |
|   VIXL_UNREACHABLE();
 | |
|   return os;
 | |
| }
 | |
| 
 | |
| CPUFeatures::const_iterator CPUFeatures::begin() const {
 | |
|   if (features_ == 0) return const_iterator(this, kNone);
 | |
| 
 | |
|   int feature_number = CountTrailingZeros(features_);
 | |
|   vixl::CPUFeatures::Feature feature =
 | |
|       static_cast<CPUFeatures::Feature>(feature_number);
 | |
|   return const_iterator(this, feature);
 | |
| }
 | |
| 
 | |
| CPUFeatures::const_iterator CPUFeatures::end() const {
 | |
|   return const_iterator(this, kNone);
 | |
| }
 | |
| 
 | |
| std::ostream& operator<<(std::ostream& os, const CPUFeatures& features) {
 | |
|   CPUFeatures::const_iterator it = features.begin();
 | |
|   while (it != features.end()) {
 | |
|     os << *it;
 | |
|     ++it;
 | |
|     if (it != features.end()) os << ", ";
 | |
|   }
 | |
|   return os;
 | |
| }
 | |
| 
 | |
| bool CPUFeaturesConstIterator::operator==(
 | |
|     const CPUFeaturesConstIterator& other) const {
 | |
|   VIXL_ASSERT(IsValid());
 | |
|   return (cpu_features_ == other.cpu_features_) && (feature_ == other.feature_);
 | |
| }
 | |
| 
 | |
| CPUFeatures::Feature CPUFeaturesConstIterator::operator++() {  // Prefix
 | |
|   VIXL_ASSERT(IsValid());
 | |
|   do {
 | |
|     // Find the next feature. The order is unspecified.
 | |
|     feature_ = static_cast<CPUFeatures::Feature>(feature_ + 1);
 | |
|     if (feature_ == CPUFeatures::kNumberOfFeatures) {
 | |
|       feature_ = CPUFeatures::kNone;
 | |
|       VIXL_STATIC_ASSERT(CPUFeatures::kNone == -1);
 | |
|     }
 | |
|     VIXL_ASSERT(CPUFeatures::kNone <= feature_);
 | |
|     VIXL_ASSERT(feature_ < CPUFeatures::kNumberOfFeatures);
 | |
|     // cpu_features_->Has(kNone) is always true, so this will terminate even if
 | |
|     // the features list is empty.
 | |
|   } while (!cpu_features_->Has(feature_));
 | |
|   return feature_;
 | |
| }
 | |
| 
 | |
| CPUFeatures::Feature CPUFeaturesConstIterator::operator++(int) {  // Postfix
 | |
|   CPUFeatures::Feature result = feature_;
 | |
|   ++(*this);
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| }  // namespace vixl
 | 
