1 | /* |
2 | * Copyright 2016 Google Inc. |
3 | * |
4 | * Use of this source code is governed by a BSD-style license that can be |
5 | * found in the LICENSE file. |
6 | */ |
7 | |
8 | #ifndef SkCpu_DEFINED |
9 | #define SkCpu_DEFINED |
10 | |
11 | #include "include/core/SkTypes.h" |
12 | |
13 | struct SkCpu { |
14 | enum { |
15 | SSE1 = 1 << 0, |
16 | SSE2 = 1 << 1, |
17 | SSE3 = 1 << 2, |
18 | SSSE3 = 1 << 3, |
19 | SSE41 = 1 << 4, |
20 | SSE42 = 1 << 5, |
21 | AVX = 1 << 6, |
22 | F16C = 1 << 7, |
23 | FMA = 1 << 8, |
24 | AVX2 = 1 << 9, |
25 | BMI1 = 1 << 10, |
26 | BMI2 = 1 << 11, |
27 | // Handy alias for all the cool Haswell+ instructions. |
28 | HSW = AVX2 | BMI1 | BMI2 | F16C | FMA, |
29 | |
30 | AVX512F = 1 << 12, |
31 | AVX512DQ = 1 << 13, |
32 | AVX512IFMA = 1 << 14, |
33 | AVX512PF = 1 << 15, |
34 | AVX512ER = 1 << 16, |
35 | AVX512CD = 1 << 17, |
36 | AVX512BW = 1 << 18, |
37 | AVX512VL = 1 << 19, |
38 | |
39 | // Handy alias for all the cool Skylake Xeon+ instructions. |
40 | SKX = AVX512F | AVX512DQ | AVX512CD | AVX512BW | AVX512VL, |
41 | }; |
42 | enum { |
43 | NEON = 1 << 0, |
44 | NEON_FMA = 1 << 1, |
45 | VFP_FP16 = 1 << 2, |
46 | CRC32 = 1 << 3, |
47 | ASIMDHP = 1 << 4, |
48 | }; |
49 | |
50 | static void CacheRuntimeFeatures(); |
51 | static bool Supports(uint32_t); |
52 | private: |
53 | static uint32_t gCachedFeatures; |
54 | }; |
55 | |
56 | inline bool SkCpu::Supports(uint32_t mask) { |
57 | uint32_t features = gCachedFeatures; |
58 | |
59 | // If we mask in compile-time known lower limits, the compiler can |
60 | // often compile away this entire function. |
61 | #if SK_CPU_X86 |
62 | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE1 |
63 | features |= SSE1; |
64 | #endif |
65 | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 |
66 | features |= SSE2; |
67 | #endif |
68 | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE3 |
69 | features |= SSE3; |
70 | #endif |
71 | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 |
72 | features |= SSSE3; |
73 | #endif |
74 | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 |
75 | features |= SSE41; |
76 | #endif |
77 | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE42 |
78 | features |= SSE42; |
79 | #endif |
80 | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX |
81 | features |= AVX; |
82 | #endif |
83 | // F16C goes here if we add SK_CPU_SSE_LEVEL_F16C |
84 | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX2 |
85 | features |= AVX2; |
86 | #endif |
87 | // FMA doesn't fit neatly into this total ordering. |
88 | // It's available on Haswell+ just like AVX2, but it's technically a different bit. |
89 | // TODO: circle back on this if we find ourselves limited by lack of compile-time FMA |
90 | |
91 | #if defined(SK_CPU_LIMIT_AVX) |
92 | features &= (SSE1 | SSE2 | SSE3 | SSSE3 | SSE41 | SSE42 | AVX); |
93 | #elif defined(SK_CPU_LIMIT_SSE41) |
94 | features &= (SSE1 | SSE2 | SSE3 | SSSE3 | SSE41); |
95 | #elif defined(SK_CPU_LIMIT_SSE2) |
96 | features &= (SSE1 | SSE2); |
97 | #endif |
98 | |
99 | #else |
100 | #if defined(SK_ARM_HAS_NEON) |
101 | features |= NEON; |
102 | #endif |
103 | |
104 | #if defined(SK_CPU_ARM64) |
105 | features |= NEON|NEON_FMA|VFP_FP16; |
106 | #endif |
107 | |
108 | #if defined(SK_ARM_HAS_CRC32) |
109 | features |= CRC32; |
110 | #endif |
111 | |
112 | #endif |
113 | return (features & mask) == mask; |
114 | } |
115 | |
116 | #endif//SkCpu_DEFINED |
117 | |