blob: 0ccf8662e182e23b7143f3b398d2f400dfd57791 [file]
/*
* 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