diff --git a/Source/Core/Common/Intrinsics.h b/Source/Core/Common/Intrinsics.h index 6ea9038c67..3e3fdb5d29 100644 --- a/Source/Core/Common/Intrinsics.h +++ b/Source/Core/Common/Intrinsics.h @@ -4,28 +4,69 @@ #pragma once -#ifdef _M_X86 +#if defined(_M_X86) + +/** + * It is assumed that all compilers used to build Dolphin support intrinsics up to and including + * SSE 4.2 on x86/x64. + */ + +#if defined(__GNUC__) || defined(__clang__) + +/** + * Due to limitations in GCC, SSE intrinsics are only available when compiling with the + * corresponding instruction set enabled. However, using the target attribute, we can compile + * single functions with a different target instruction set, while still creating a generic build. + * + * Since this instruction set is enabled per-function, any callers should verify that the + * instruction set is supported at runtime before calling it, and provide a fallback implementation + * when not supported. + * + * When building with -march=native, or enabling the instruction sets in the compile flags, permit + * usage of the instrinsics without any function attributes. If the command-line architecture does + * not support this instruction set, enable it via function targeting. +*/ -#ifdef _MSC_VER -#include -#else #include +#ifndef __SSE4_2__ +#define FUNCTION_TARGET_SSE42 [[gnu::target("sse4.2")]] +#endif +#ifndef __SSE4_1__ +#define FUNCTION_TARGET_SSR41 [[gnu::target("sse4.1")]] +#endif +#ifndef __SSSE3__ +#define FUNCTION_TARGET_SSSE3 [[gnu::target("ssse3")]] +#endif +#ifndef __SSE3__ +#define FUNCTION_TARGET_SSE3 [[gnu::target("sse3")]] #endif -#if defined _M_GENERIC -#define _M_SSE 0 -#elif _MSC_VER || __INTEL_COMPILER -#define _M_SSE 0x402 -#elif defined __GNUC__ -#if defined __SSE4_2__ -#define _M_SSE 0x402 -#elif defined __SSE4_1__ -#define _M_SSE 0x401 -#elif defined __SSSE3__ -#define _M_SSE 0x301 -#elif defined __SSE3__ -#define _M_SSE 0x300 -#endif -#endif +#elif defined(_MSC_VER) || defined(__INTEL_COMPILER) + +/** + * MSVC and ICC support intrinsics for any instruction set without any function attributes. + */ +#include + +#endif // defined(_MSC_VER) || defined(__INTEL_COMPILER) #endif // _M_X86 + +/** + * Define the FUNCTION_TARGET macros to nothing if they are not needed, or not on an X86 platform. + * This way when a function is defined with FUNCTION_TARGET you don't need to define a second + * version without the macro around a #ifdef guard. Be careful when using intrinsics, as all use + * should still be placed around a #ifdef _M_X86 if the file is compiled on all architectures. + */ +#ifndef FUNCTION_TARGET_SSE42 +#define FUNCTION_TARGET_SSE42 +#endif +#ifndef FUNCTION_TARGET_SSR41 +#define FUNCTION_TARGET_SSR41 +#endif +#ifndef FUNCTION_TARGET_SSSE3 +#define FUNCTION_TARGET_SSSE3 +#endif +#ifndef FUNCTION_TARGET_SSE3 +#define FUNCTION_TARGET_SSE3 +#endif