1 /* 2 * Copyright 2023 Google LLC 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 // Include guards are intentionally omitted 9 10 #include "include/private/base/SkFeatures.h" 11 12 #if !defined(SK_OPTS_TARGET) 13 #error Define SK_OPTS_TARGET before including SkOpts_SetTarget 14 #endif 15 16 #if defined(SK_OPTS_NS) 17 // For testing define SK_OPTS_NS before including. 18 #elif SK_OPTS_TARGET == SK_OPTS_TARGET_DEFAULT 19 20 #if defined(SK_ARM_HAS_NEON) 21 #define SK_OPTS_NS neon 22 #elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SKX 23 #define SK_OPTS_NS skx 24 #elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX2 25 #define SK_OPTS_NS avx2 26 #elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX 27 #define SK_OPTS_NS avx 28 #elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE42 29 #define SK_OPTS_NS sse42 30 #elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 31 #define SK_OPTS_NS sse41 32 #elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 33 #define SK_OPTS_NS ssse3 34 #elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE3 35 #define SK_OPTS_NS sse3 36 #elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 37 #define SK_OPTS_NS sse2 38 #elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE1 39 #define SK_OPTS_NS sse 40 #elif SK_CPU_LSX_LEVEL >= SK_CPU_LSX_LEVEL_LASX 41 #define SK_OPTS_NS lasx 42 #elif SK_CPU_LSX_LEVEL >= SK_CPU_LSX_LEVEL_LSX 43 #define SK_OPTS_NS lsx 44 #else 45 #define SK_OPTS_NS portable 46 #endif 47 48 #define DEFINE_DEFAULT(name) decltype(name) name = SK_OPTS_NS::name 49 50 #else // SK_OPTS_TARGET != SK_OPTS_TARGET_DEFAULT 51 52 #if defined(SK_OLD_CPU_SSE_LEVEL) 53 #error Include SkOpts_RestoreTarget before re-including SkOpts_SetTarget 54 #endif 55 56 #define SK_OLD_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL 57 #undef SK_CPU_SSE_LEVEL 58 #undef SK_CPU_LSX_LEVEL 59 60 // NOTE: Below, we automatically include arch-specific intrinsic headers when we've detected 61 // that the compiler is clang-cl. Clang's headers skip including "unsupported" intrinsics (via 62 // defines like __AVX__ etc.), but only when _MSC_VER is also defined. To get around that, we 63 // directly include the headers for any intrinsics that ought to be present in each opts target. 64 // 65 // Each of the specific intrinsic headers also checks to ensure that immintrin.h has been 66 // included, so do that here, first. 67 #if defined(__clang__) && defined(_MSC_VER) 68 #include <immintrin.h> 69 #endif 70 71 // Why not put the target string in a #define, and remove the boilerplate? Because GCC doesn't 72 // allow the target() option to be expanded by the preprocessor - it must be a literal string. 73 #if SK_OPTS_TARGET == SK_OPTS_TARGET_SSSE3 74 75 #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSSE3 76 #define SK_OPTS_NS ssse3 77 78 #if defined(__clang__) 79 #pragma clang attribute push(__attribute__((target("sse2,ssse3"))), apply_to=function) 80 #elif defined(__GNUC__) 81 #pragma GCC push_options 82 #pragma GCC target("sse2,ssse3") 83 #endif 84 85 #if defined(__clang__) && defined(_MSC_VER) 86 #include <pmmintrin.h> 87 #include <tmmintrin.h> 88 #endif 89 90 #elif SK_OPTS_TARGET == SK_OPTS_TARGET_AVX 91 92 #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX 93 #define SK_OPTS_NS avx 94 95 #if defined(__clang__) 96 #pragma clang attribute push(__attribute__((target("sse2,ssse3,sse4.1,sse4.2,avx"))), apply_to=function) 97 #elif defined(__GNUC__) 98 #pragma GCC push_options 99 #pragma GCC target("sse2,ssse3,sse4.1,sse4.2,avx") 100 #endif 101 102 #if defined(__clang__) && defined(_MSC_VER) 103 #include <pmmintrin.h> 104 #include <tmmintrin.h> 105 #include <smmintrin.h> 106 #include <avxintrin.h> 107 #endif 108 109 #elif SK_OPTS_TARGET == SK_OPTS_TARGET_HSW 110 111 #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2 112 #define SK_OPTS_NS hsw 113 114 #if defined(__clang__) 115 #pragma clang attribute push(__attribute__((target("sse2,ssse3,sse4.1,sse4.2,avx,avx2,bmi,bmi2,f16c,fma"))), apply_to=function) 116 #elif defined(__GNUC__) 117 #pragma GCC push_options 118 #pragma GCC target("sse2,ssse3,sse4.1,sse4.2,avx,avx2,bmi,bmi2,f16c,fma") 119 #endif 120 121 #if defined(__clang__) && defined(_MSC_VER) 122 #include <pmmintrin.h> 123 #include <tmmintrin.h> 124 #include <smmintrin.h> 125 #include <avxintrin.h> 126 #include <avx2intrin.h> 127 #include <f16cintrin.h> 128 #include <bmi2intrin.h> 129 #include <fmaintrin.h> 130 #endif 131 132 #elif SK_OPTS_TARGET == SK_OPTS_TARGET_LASX 133 134 #define SK_CPU_LSX_LEVEL SK_CPU_LSX_LEVEL_LASX 135 #define SK_OPTS_NS lasx 136 // The intrinsic from lasxintrin.h is wrapped by the __loongarch_asx macro, so we need to define it. 137 #define __loongarch_asx 138 139 #if defined(__clang__) 140 #pragma clang attribute push(__attribute__((target("lasx"))), apply_to=function) 141 #endif 142 143 #else 144 #error Unexpected value of SK_OPTS_TARGET 145 146 #endif 147 148 #endif // !SK_OPTS_TARGET_DEFAULT 149