| /* |
| * Copyright 2016 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef SkCpu_DEFINED |
| #define SkCpu_DEFINED |
| |
| #include "include/private/SkFeatures.h" |
| |
| #include <cstdint> |
| |
| struct SkX64 { |
| constexpr static uint32_t SSE1 = 1 << 0; |
| constexpr static uint32_t SSE2 = 1 << 1; |
| constexpr static uint32_t SSE3 = 1 << 2; |
| constexpr static uint32_t SSSE3 = 1 << 3; |
| constexpr static uint32_t SSE41 = 1 << 4; |
| constexpr static uint32_t SSE42 = 1 << 5; |
| constexpr static uint32_t AVX = 1 << 6; |
| constexpr static uint32_t F16C = 1 << 7; |
| constexpr static uint32_t FMA = 1 << 8; |
| constexpr static uint32_t AVX2 = 1 << 9; |
| constexpr static uint32_t BMI1 = 1 << 10; |
| constexpr static uint32_t BMI2 = 1 << 11; |
| constexpr static uint32_t AVX512F = 1 << 12; |
| constexpr static uint32_t AVX512DQ = 1 << 13; |
| constexpr static uint32_t AVX512IFMA = 1 << 14; |
| constexpr static uint32_t AVX512PF = 1 << 15; |
| constexpr static uint32_t AVX512ER = 1 << 16; |
| constexpr static uint32_t AVX512CD = 1 << 17; |
| constexpr static uint32_t AVX512BW = 1 << 18; |
| constexpr static uint32_t AVX512VL = 1 << 19; |
| constexpr static uint32_t ERMS = 1 << 20; |
| |
| // Some of these are grouped together into "levels" |
| // https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels |
| // -march=x86-64-v3 |
| constexpr static uint32_t ML3 = AVX2 | BMI1 | BMI2 | F16C | FMA; |
| // -march=x86-64-v4 |
| constexpr static uint32_t ML4 = AVX512F | AVX512DQ | AVX512CD | AVX512BW | AVX512VL; |
| }; |
| |
| struct SkLoongArch { |
| constexpr static uint32_t SX = 1 << 0; |
| constexpr static uint32_t ASX = 1 << 1; |
| }; |
| |
| struct SkCpu { |
| static void CacheRuntimeFeatures(); |
| static bool Supports(uint32_t); |
| private: |
| static uint32_t gCachedFeatures; |
| }; |
| |
| inline bool SkCpu::Supports(uint32_t mask) { |
| uint32_t features = gCachedFeatures; |
| |
| // If we mask in compile-time known lower limits, the compiler can |
| // often compile away this entire function. |
| #if SK_CPU_X86 |
| #if SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_SSE1 |
| features |= SkX64::SSE1; |
| #endif |
| #if SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_SSE2 |
| features |= SkX64::SSE2; |
| #endif |
| #if SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_SSE3 |
| features |= SkX64::SSE3; |
| #endif |
| #if SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_SSSE3 |
| features |= SkX64::SSSE3; |
| #endif |
| #if SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_SSE41 |
| features |= SkX64::SSE41; |
| #endif |
| #if SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_SSE42 |
| features |= SkX64::SSE42; |
| #endif |
| #if SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_AVX |
| features |= SkX64::AVX; |
| #endif |
| // F16C goes here if we add SK_CPU_X64_LEVEL_F16C |
| #if SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_AVX2 |
| features |= SkX64::AVX2; |
| #endif |
| #if SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_ML4 |
| features |= (SkX64::AVX512F | SkX64::AVX512DQ | SkX64::AVX512CD | SkX64::AVX512BW | SkX64::AVX512VL); |
| #endif |
| // FMA doesn't fit neatly into this total ordering. |
| // It's available on Haswell+ just like AVX2, but it's technically a different bit. |
| // TODO: circle back on this if we find ourselves limited by lack of compile-time FMA |
| |
| #if defined(SK_CPU_LIMIT_AVX) |
| features &= (SkX64::SSE1 | SkX64::SSE2 | SkX64::SSE3 | SkX64::SSSE3 | SkX64::SSE41 | SkX64::SSE42 | SkX64::AVX); |
| #elif defined(SK_CPU_LIMIT_SSE41) |
| features &= (SkX64::SSE1 | SkX64::SSE2 | SkX64::SSE3 | SkX64::SSSE3 | SkX64::SSE41); |
| #elif defined(SK_CPU_LIMIT_SSE2) |
| features &= (SkX64::SSE1 | SkX64::SSE2); |
| #endif |
| |
| #elif SK_CPU_LOONGARCH |
| #if SK_CPU_LSX_LEVEL >= SK_CPU_LSX_LEVEL_LSX |
| features |= SkLoongArch::SX; |
| #endif |
| #if SK_CPU_LSX_LEVEL >= SK_CPU_LSX_LEVEL_LASX |
| features |= SkLoongArch::ASX; |
| #endif |
| |
| #endif |
| return (features & mask) == mask; |
| } |
| |
| #endif // SkCpu_DEFINED |