| /* | |
| * Copyright 2023 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| // Include guards are intentionally omitted | |
| #include "include/private/SkFeatures.h" | |
| #if !defined(SK_OPTS_TARGET) | |
| #error Define SK_OPTS_TARGET before including SkOpts_SetTarget | |
| #endif | |
| #if defined(SK_OPTS_NS) | |
| // For testing define SK_OPTS_NS before including. | |
| #elif SK_OPTS_TARGET == SK_OPTS_TARGET_DEFAULT | |
| #if defined(SK_ARM_HAS_NEON) | |
| #define SK_OPTS_NS neon | |
| #elif SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_ML4 | |
| #define SK_OPTS_NS ml4 | |
| #elif SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_AVX2 | |
| #define SK_OPTS_NS avx2 | |
| #elif SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_AVX | |
| #define SK_OPTS_NS avx | |
| #elif SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_SSE42 | |
| #define SK_OPTS_NS sse42 | |
| #elif SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_SSE41 | |
| #define SK_OPTS_NS sse41 | |
| #elif SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_SSSE3 | |
| #define SK_OPTS_NS ssse3 | |
| #elif SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_SSE3 | |
| #define SK_OPTS_NS sse3 | |
| #elif SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_SSE2 | |
| #define SK_OPTS_NS sse2 | |
| #elif SK_CPU_X64_LEVEL >= SK_CPU_X64_LEVEL_SSE1 | |
| #define SK_OPTS_NS sse | |
| #elif SK_CPU_LSX_LEVEL >= SK_CPU_LSX_LEVEL_LASX | |
| #define SK_OPTS_NS lasx | |
| #elif SK_CPU_LSX_LEVEL >= SK_CPU_LSX_LEVEL_LSX | |
| #define SK_OPTS_NS lsx | |
| #else | |
| #define SK_OPTS_NS portable | |
| #endif | |
| #define DEFINE_DEFAULT(name) decltype(name) name = SK_OPTS_NS::name | |
| #else // SK_OPTS_TARGET != SK_OPTS_TARGET_DEFAULT | |
| #if defined(SK_OLD_CPU_X64_LEVEL) | |
| #error Include SkOpts_RestoreTarget before re-including SkOpts_SetTarget | |
| #endif | |
| #define SK_OLD_CPU_X64_LEVEL SK_CPU_X64_LEVEL | |
| #undef SK_CPU_X64_LEVEL | |
| #undef SK_CPU_LSX_LEVEL | |
| // NOTE: Below, we automatically include arch-specific intrinsic headers when we've detected | |
| // that the compiler is clang-cl. Clang's headers skip including "unsupported" intrinsics (via | |
| // defines like __AVX__ etc.), but only when _MSC_VER is also defined. To get around that, we | |
| // directly include the headers for any intrinsics that ought to be present in each opts target. | |
| // | |
| // Each of the specific intrinsic headers also checks to ensure that immintrin.h has been | |
| // included, so do that here, first. | |
| #if defined(__clang__) && defined(_MSC_VER) | |
| #define __RTMINTRIN_H // Workaround for https://github.com/llvm/llvm-project/issues/95133 | |
| #include <immintrin.h> | |
| #endif | |
| // Why not put the target string in a #define, and remove the boilerplate? Because GCC doesn't | |
| // allow the target() option to be expanded by the preprocessor - it must be a literal string. | |
| #if SK_OPTS_TARGET == SK_OPTS_TARGET_SSSE3 | |
| #define SK_CPU_X64_LEVEL SK_CPU_X64_LEVEL_SSSE3 | |
| #define SK_OPTS_NS ssse3 | |
| #if defined(__clang__) | |
| #pragma clang attribute push(__attribute__((target("sse2,ssse3"))), apply_to=function) | |
| #elif defined(__GNUC__) | |
| #pragma GCC push_options | |
| #pragma GCC target("sse2,ssse3") | |
| #endif | |
| #if defined(__clang__) && defined(_MSC_VER) | |
| #include <pmmintrin.h> | |
| #include <tmmintrin.h> | |
| #endif | |
| #elif SK_OPTS_TARGET == SK_OPTS_TARGET_AVX | |
| #define SK_CPU_X64_LEVEL SK_CPU_X64_LEVEL_AVX | |
| #define SK_OPTS_NS avx | |
| #if defined(__clang__) | |
| #pragma clang attribute push(__attribute__((target("sse2,ssse3,sse4.1,sse4.2,avx"))), apply_to=function) | |
| #elif defined(__GNUC__) | |
| #pragma GCC push_options | |
| #pragma GCC target("sse2,ssse3,sse4.1,sse4.2,avx") | |
| #endif | |
| #if defined(__clang__) && defined(_MSC_VER) | |
| #include <pmmintrin.h> | |
| #include <tmmintrin.h> | |
| #include <smmintrin.h> | |
| #include <avxintrin.h> | |
| #endif | |
| #elif SK_OPTS_TARGET == SK_OPTS_TARGET_ML3 | |
| #define SK_CPU_X64_LEVEL SK_CPU_X64_LEVEL_AVX2 | |
| #define SK_OPTS_NS ml3 | |
| #if defined(__clang__) | |
| #pragma clang attribute push(__attribute__((target("sse2,ssse3,sse4.1,sse4.2,avx,avx2,bmi,bmi2,f16c,fma"))), apply_to=function) | |
| #elif defined(__GNUC__) | |
| #pragma GCC push_options | |
| #pragma GCC target("sse2,ssse3,sse4.1,sse4.2,avx,avx2,bmi,bmi2,f16c,fma") | |
| #endif | |
| #if defined(__clang__) && defined(_MSC_VER) | |
| #include <pmmintrin.h> | |
| #include <tmmintrin.h> | |
| #include <smmintrin.h> | |
| #include <avxintrin.h> | |
| #include <avx2intrin.h> | |
| #include <f16cintrin.h> | |
| #include <bmi2intrin.h> | |
| #include <fmaintrin.h> | |
| #endif | |
| #elif SK_OPTS_TARGET == SK_OPTS_TARGET_LASX | |
| #define SK_CPU_LSX_LEVEL SK_CPU_LSX_LEVEL_LASX | |
| #define SK_OPTS_NS lasx | |
| // The intrinsic from lasxintrin.h is wrapped by the __loongarch_asx macro, so we need to define it. | |
| #define __loongarch_asx | |
| #if defined(__clang__) | |
| #pragma clang attribute push(__attribute__((target("lasx"))), apply_to=function) | |
| #endif | |
| #else | |
| #error Unexpected value of SK_OPTS_TARGET | |
| #endif | |
| #endif // !SK_OPTS_TARGET_DEFAULT |