diff --git a/cmake/DaemonArchitecture.cmake b/cmake/DaemonArchitecture.cmake index 662343ee7a..d379d9c14e 100644 --- a/cmake/DaemonArchitecture.cmake +++ b/cmake/DaemonArchitecture.cmake @@ -90,3 +90,28 @@ endif() # Quotes cannot be part of the define as support for them is not reliable. add_definitions(-DNACL_ARCH_STRING=${NACL_ARCH}) + +option(USE_ARCH_INTRINSICS "Enable custom code using intrinsics functions or asm declarations" ON) +mark_as_advanced(USE_ARCH_INTRINSICS) + +macro(set_arch_intrinsics name) + if (USE_ARCH_INTRINSICS) + message(STATUS "Enabling ${name} architecture intrinsics") + add_definitions(-DDAEMON_USE_ARCH_INTRINSICS_${name}=1) + else() + message(STATUS "Disabling ${name} architecture intrinsics") + endif() +endmacro() + +if (USE_ARCH_INTRINSICS) + add_definitions(-DDAEMON_USE_ARCH_INTRINSICS=1) +endif() + +set_arch_intrinsics(${ARCH}) + +set(amd64_PARENT "i686") +set(arm64_PARENT "armhf") + +if (${ARCH}_PARENT) + set_arch_intrinsics(${${ARCH}_PARENT}) +endif() diff --git a/cmake/DaemonFlags.cmake b/cmake/DaemonFlags.cmake index cface099a9..b8b10a0336 100644 --- a/cmake/DaemonFlags.cmake +++ b/cmake/DaemonFlags.cmake @@ -29,6 +29,26 @@ include(CheckCXXCompilerFlag) add_definitions(-DDAEMON_BUILD_${CMAKE_BUILD_TYPE}) +option(USE_COMPILER_INTRINSICS "Enable usage of compiler intrinsics" ON) +mark_as_advanced(USE_COMPILER_INTRINSICS) + +if (USE_COMPILER_INTRINSICS) + add_definitions(-DDAEMON_USE_COMPILER_INTRINSICS=1) + message(STATUS "Enabling compiler intrinsics") +else() + message(STATUS "Disabling compiler intrinsics") +endif() + +option(USE_COMPILER_CUSTOMIZATION "Enable usage of compiler custom attributes and operators" ON) +mark_as_advanced(USE_COMPILER_CUSTOMIZATION) + +if (USE_COMPILER_CUSTOMIZATION) + add_definitions(-DDAEMON_USE_COMPILER_CUSTOMIZATION=1) + message(STATUS "Enabling compiler custom attributes and operators") +else() + message(STATUS "Disabling compiler custom attributes and operators") +endif() + # Set flag without checking, optional argument specifies build type macro(set_c_flag FLAG) if (${ARGC} GREATER 1) @@ -133,6 +153,9 @@ if (MSVC) set_c_cxx_flag("/fp:fast") set_c_cxx_flag("/d2Zi+" RELWITHDEBINFO) + # https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ + set_cxx_flag("/Zc:__cplusplus") + # At least Ninja doesn't remove the /W3 flag when we add /W4|/Wall one, which # leads to compilation warnings. Remove /W3 entirely, as /W4|/Wall be used. foreach(flag_var diff --git a/src/common/Compiler.h b/src/common/Compiler.h index 6b8fc45940..3add821f49 100644 --- a/src/common/Compiler.h +++ b/src/common/Compiler.h @@ -33,14 +33,81 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef COMMON_COMPILER_H_ #define COMMON_COMPILER_H_ -// CountTrailingZeroes returns the number of trailing zeroes of the argument in binary. -// The result is unspecified if the input is 0. -int CountTrailingZeroes(unsigned int x); -int CountTrailingZeroes(unsigned long x); -int CountTrailingZeroes(unsigned long long x); +// Code making use of compiler intrinsics. -// GCC and Clang -#ifdef __GNUC__ +/* CountTrailingZeroes returns the number of +trailing zeroes of the argument in binary. +The result is unspecified if the input is 0. */ +#if defined(DAEMON_USE_COMPILER_INTRINSICS) && defined(__GNUC__) +inline int CountTrailingZeroes(unsigned int x) +{ + return __builtin_ctz(x); +} +inline int CountTrailingZeroes(unsigned long x) +{ + return __builtin_ctzl(x); +} +inline int CountTrailingZeroes(unsigned long long x) +{ + return __builtin_ctzll(x); +} +#elif defined(DAEMON_USE_COMPILER_INTRINSICS) && defined(_MSC_VER) +inline int CountTrailingZeroes(unsigned int x) +{ + unsigned long ans; _BitScanForward(&ans, x); return ans; +} +inline int CountTrailingZeroes(unsigned long x) +{ + unsigned long ans; _BitScanForward(&ans, x); return ans; +} +inline int CountTrailingZeroes(unsigned long long x) +{ + unsigned long ans; + #ifdef _WIN64 + _BitScanForward64(&ans, x); return ans; + #else + bool nonzero = _BitScanForward(&ans, static_cast(x)); + if (!nonzero) { _BitScanForward(&ans, x >> 32); } + #endif + return ans; +} +#else +inline int CountTrailingZeroes(unsigned int x) +{ + int i = 0; while (i < 32 && !(x & 1)) { ++i; x >>= 1; } return i; +} +inline int CountTrailingZeroes(unsigned long x) +{ + int i = 0; while (i < 64 && !(x & 1)) { ++i; x >>= 1; } return i; +} +inline int CountTrailingZeroes(unsigned long long x) +{ + int i = 0; while (i < 64 && !(x & 1)) { ++i; x >>= 1; } return i; +} +#endif + +// Sanitizer detection + +#if defined(__SANITIZE_ADDRESS__) // Detects GCC and MSVC AddressSanitizer + #define USING_ADDRESS_SANITIZER + #define USING_SANITIZER +#elif defined(__SANITIZE_THREAD__) // Detects GCC ThreadSanitizer + #define USING_SANITIZER +#elif defined(__has_feature) + #if __has_feature(address_sanitizer) // Detects Clang AddressSanitizer + #define USING_ADDRESS_SANITIZER + #define USING_SANITIZER + #elif __has_feature(leak_sanitizer) // Detects Clang LeakSanitizer + #define USING_SANITIZER + #elif __has_feature(memory_sanitizer) // Detects Clang MemorySanitizer + #define USING_SANITIZER + #elif __has_feature(thread_sanitizer) // Detects Clang ThreadSanitizer + #define USING_SANITIZER + #endif +#endif + +// GCC and Clang attribute and operator customization. +#if defined(DAEMON_USE_COMPILER_CUSTOMIZATION) && defined(__GNUC__) // Emit a nice warning when a function is used #define DEPRECATED __attribute__((__deprecated__)) @@ -67,9 +134,6 @@ int CountTrailingZeroes(unsigned long long x); // other pointer #define MALLOC_LIKE __attribute__((__malloc__)) -// Marks this function as memory allocator -#define ALLOCATOR - // Shared library function import/export #ifdef _WIN32 #define DLLEXPORT __attribute__((__dllexport__)) @@ -81,170 +145,150 @@ int CountTrailingZeroes(unsigned long long x); // Raise an exception and break in the debugger #if defined(DAEMON_ARCH_i686) || defined(DAEMON_ARCH_amd64) + // Always run this asm code even if DAEMON_USE_ARCH_INTRINSICS is not defined. #define BREAKPOINT() __asm__ __volatile__("int $3\n\t") -#elif defined(DAEMON_ARCH_nacl) - // TODO: find how to implement breakpoint on NaCl - // Accept our fate, do not raise a warning. - #define BREAKPOINT() -#else - #warning BREAKPOINT is not implemented for this platform - #define BREAKPOINT() #endif -// noexcept keyword, this should be used on all move constructors and move -// assignments so that containers move objects instead of copying them. -#define NOEXCEPT noexcept -#define NOEXCEPT_IF(x) noexcept(x) -#define NOEXCEPT_EXPR(x) noexcept(x) +/* Compiler can be fooled when calling ASSERT_UNREACHABLE() macro at end of non-void function. +In this case, compiler is complaining because control reaches end of non-void function, +even if the execution flow is expected to be taken down by assert before. -// Work around lack of constexpr -#define CONSTEXPR constexpr +That's why we use these compiler specific unreachable builtin on modern compilers, +ASSERT_UNREACHABLE() macro makes use of this UNREACHABLE() macro, preventing useless warnings. +Unsupported compilers will raise "control reaches end of non-void function" warnings but +that's not a big issue and that's likely to never happen (these compilers would be too old and +would lack too much features to compile Daemon anyway). -#if defined(__SANITIZE_ADDRESS__) // Detects GCC and MSVC AddressSanitizer -# define USING_ADDRESS_SANITIZER -# define USING_SANITIZER -#elif defined(__SANITIZE_THREAD__) // Detects GCC ThreadSanitizer -# define USING_SANITIZER -#elif defined(__has_feature) -# if __has_feature(address_sanitizer) // Detects Clang AddressSanitizer -# define USING_ADDRESS_SANITIZER -# define USING_SANITIZER -# elif __has_feature(leak_sanitizer) // Detects Clang LeakSanitizer -# define USING_SANITIZER -# elif __has_feature(memory_sanitizer) // Detects Clang MemorySanitizer -# define USING_SANITIZER -# elif __has_feature(thread_sanitizer) // Detects Clang ThreadSanitizer -# define USING_SANITIZER -# endif -#endif +See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0627r0.pdf */ +#define UNREACHABLE() __builtin_unreachable() // To mark functions which cause issues with address sanitizer #ifdef USING_ADDRESS_SANITIZER -# define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) -#else -# define ATTRIBUTE_NO_SANITIZE_ADDRESS + #define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) #endif -inline int CountTrailingZeroes(unsigned int x) { return __builtin_ctz(x); } -inline int CountTrailingZeroes(unsigned long x) { return __builtin_ctzl(x); } -inline int CountTrailingZeroes(unsigned long long x) { return __builtin_ctzll(x); } +// The new -Wimplicit-fallthrough warning... +#if defined(__clang__) && __clang_major__ >= 6 + #define DAEMON_FALLTHROUGH [[clang::fallthrough]] +#elif __GNUC__ >= 7 + #define DAEMON_FALLTHROUGH [[gnu::fallthrough]] +#endif -// Microsoft Visual C++ -#elif defined( _MSC_VER ) +// Microsoft Visual C++ attribute and operator customization. +#elif defined(DAEMON_USE_COMPILER_CUSTOMIZATION) && defined(_MSC_VER) // See descriptions above #define DEPRECATED __declspec(deprecated) #define WARN_UNUSED_RESULT _Check_return_ -#define COLD #define NORETURN __declspec(noreturn) -#define NORETURN_PTR -#define PRINTF_LIKE(n) -#define VPRINTF_LIKE(n) -#define PRINTF_TRANSLATE_ARG(a) + +// Marks this function as memory allocator #if _MSC_VER >= 1900 && !defined( _CORECRT_BUILD ) -#define ALLOCATOR __declspec(allocator) -#else -#define ALLOCATOR + #define ALLOCATOR __declspec(allocator) #endif + #define MALLOC_LIKE ALLOCATOR __declspec(restrict) #define DLLEXPORT __declspec(dllexport) #define DLLIMPORT __declspec(dllimport) #define BREAKPOINT() __debugbreak() +#define UNREACHABLE() __assume(0) + +// Other compilers, unsupported +#else + #warning "Unsupported compiler" +#endif + +// Work around lack of compiler customization. +#if !defined(DEPRECATED) + #define DEPRECATED +#endif +#if !defined(WARN_UNUSED_RESULT) + #define WARN_UNUSED_RESULT +#endif +#if !defined(COLD) + #define COLD +#endif +#if !defined(NORETURN) + #define NORETURN +#endif +#if !defined(NORETURN_PTR) + #define NORETURN_PTR +#endif +#if !defined(PRINTF_LIKE) + #define PRINTF_LIKE(n) +#endif +#if !defined(VPRINTF_LIKE) + #define VPRINTF_LIKE(n) +#endif +#if !defined(PRINTF_TRANSLATE_ARG) + #define PRINTF_TRANSLATE_ARG(a) +#endif +#if !defined(MALLOC_LIKE) + #define MALLOC_LIKE +#endif +#if !defined(ALLOCATOR) + #define ALLOCATOR +#endif +#if !defined(DLLEXPORT) + #define DLLEXPORT +#endif +#if !defined(DLLIMPORT) + #define DLLIMPORT +#endif +#if !defined(BREAKPOINT) + #define BREAKPOINT() +#endif +#if !defined(UNREACHABLE) + #define UNREACHABLE() +#endif +#if !defined(ATTRIBUTE_NO_SANITIZE_ADDRESS) + #define ATTRIBUTE_NO_SANITIZE_ADDRESS +#endif +#if !defined(DAEMON_FALLTHROUGH) + #define DAEMON_FALLTHROUGH +#endif + +// Keywords specific to C++ versions + +/* TODO: Rewrite all NOEXCEPT usages from the whole code base. + +The noexcept keyword should be used on all move constructors and move +assignments so that containers move objects instead of copying them. +That keyword was added in C++11, all compilers should now support it. */ #define NOEXCEPT noexcept #define NOEXCEPT_IF(x) noexcept(x) #define NOEXCEPT_EXPR(x) noexcept(x) -#define CONSTEXPR constexpr -#define ATTRIBUTE_NO_SANITIZE_ADDRESS -inline int CountTrailingZeroes(unsigned int x) { unsigned long ans; _BitScanForward(&ans, x); return ans; } -inline int CountTrailingZeroes(unsigned long x) { unsigned long ans; _BitScanForward(&ans, x); return ans; } -#ifdef _WIN64 -inline int CountTrailingZeroes(unsigned long long x) { unsigned long ans; _BitScanForward64(&ans, x); return ans; } -#else -inline int CountTrailingZeroes(unsigned long long x) -{ - unsigned long ans; - bool nonzero = _BitScanForward(&ans, static_cast(x)); - if (!nonzero) { - _BitScanForward(&ans, x >> 32); - } - return ans; -} +// Uses SD-6 Feature Test Recommendations +#if defined(__cpp_constexpr) + #define CONSTEXPR constexpr + #define CONSTEXPR_FUNCTION constexpr + #if __cpp_constexpr >= 201304 + #define CONSTEXPR_FUNCTION_RELAXED constexpr + #endif #endif -// Other compilers, unsupported -#else -#warning "Unsupported compiler" -#define DEPRECATED -#define WARN_UNUSED_RESULT -#define COLD -#define NORETURN -#define PRINTF_LIKE(n) -#define VPRINTF_LIKE(n) -#define PRINTF_TRANSLATE_ARG(a) -#define MALLOC_LIKE -#define ALLOCATOR -#define DLLEXPORT -#define DLLIMPORT -#define BREAKPOINT() - -inline int CountTrailingZeroes(unsigned int x) { int i = 0; while (i < 32 && !(x & 1)) { ++i; x >>= 1; } return i; } -inline int CountTrailingZeroes(unsigned long x) { int i = 0; while (i < 64 && !(x & 1)) { ++i; x >>= 1; } return i; } -inline int CountTrailingZeroes(unsigned long long x) { int i = 0; while (i < 64 && !(x & 1)) { ++i; x >>= 1; } return i; } +// Work around lack of language keywords. +#if !defined(CONSTEXPR) + #define CONSTEXPR +#endif +#if !defined(CONSTEXPR_FUNCTION) + #define CONSTEXPR_FUNCTION +#endif +#if !defined(CONSTEXPR_FUNCTION_RELAXED) + #define CONSTEXPR_FUNCTION_RELAXED #endif +// Compiler specificities we can't disable. + #if defined(__MINGW32__) && defined(__i386__) // On x86, GCC expects 16-byte stack alignment (used for SSE instructions), but MSVC only uses 4-byte alignment. // Therefore the stack needs to be adjusted whenever MSVC code calls into GCC code. -# define ALIGN_STACK_FOR_MINGW __attribute__((force_align_arg_pointer)) + #define ALIGN_STACK_FOR_MINGW __attribute__((force_align_arg_pointer)) #else -# define ALIGN_STACK_FOR_MINGW + #define ALIGN_STACK_FOR_MINGW #endif -// Uses SD-6 Feature Test Recommendations -#ifdef __cpp_constexpr -# if __cpp_constexpr >= 201304 -# define CONSTEXPR_FUNCTION_RELAXED constexpr -# else -# define CONSTEXPR_FUNCTION_RELAXED -# endif -# define CONSTEXPR_FUNCTION constexpr -#else -// Work around lack of constexpr -# define CONSTEXPR_FUNCTION -# define CONSTEXPR_FUNCTION_RELAXED -#endif - -// The new -Wimplicit-fallthrough warning... -#if defined(__clang__) && __clang_major__ >= 6 -# define DAEMON_FALLTHROUGH [[clang::fallthrough]] -#elif __GNUC__ >= 7 -# define DAEMON_FALLTHROUGH [[gnu::fallthrough]] -#else -# define DAEMON_FALLTHROUGH -#endif - -/* Compiler can be fooled when calling ASSERT_UNREACHABLE() macro at end of non-void function. - * In this case, compiler is complaining because control reaches end of non-void function, - * even if the execution flow is expected to be taken down by assert before. - * - * That's why we use these compiler specific unreachable builtin on modern compilers, - * ASSERT_UNREACHABLE() macro makes use of this UNREACHABLE() macro, preventing useless warnings. - * Unsupported compilers will raise "control reaches end of non-void function" warnings but - * that's not a big issue and that's likely to never happen (these compilers would be too old and - * would lack too much features to compile Daemon anyway). - * - * See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0627r0.pdf -*/ -#if defined(_MSC_VER) //UNREACHABLE - #define UNREACHABLE() __assume(0) -// All of gcc, clang and icc define __GNUC__ -#elif defined(__GNUC__) - #define UNREACHABLE() __builtin_unreachable() -#else // UNREACHABLE - #define UNREACHABLE() -#endif // UNREACHABLE - /* Use a C++11 braced initializer on MSVC instead of a bracket initializer when zeroing a struct. This works around a bug in how MSVC generates implicit default constructors. -- Amanieu diff --git a/src/common/Platform.h b/src/common/Platform.h index 9ccef8df7e..13269a35c7 100644 --- a/src/common/Platform.h +++ b/src/common/Platform.h @@ -63,15 +63,74 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define __x86_64__ 1 #endif -// SSE support -#if defined(__x86_64__) || defined(__SSE__) || _M_IX86_FP >= 1 -#include -#if defined(__x86_64__) || defined(__SSE2__) || _M_IX86_FP >= 2 -#include -#define idx86_sse 2 -#else -#define idx86_sse 1 -#endif +/* The definition name syntax is: DAEMON_USE_ARCH_INTRINSICS_[_extension] + +Examples: + +- DAEMON_USE_ARCH_INTRINSICS_i686: i686 specific code, including asm code. +- DAEMON_USE_ARCH_INTRINSICS_i686_sse: i686 SSE specific code. +- DAEMON_USE_ARCH_INTRINSICS_i686_sse2: i686 SSE2 specific code. + +If a architecture inherits a feature from an parent architecture, the parent +architecture name is used. For example on amd64, the definition enabling +SSE code is DAEMON_USE_ARCH_INTRINSICS_i686_sse, enabling SSE code on both +i686 with SSE and amd64. + +The definitions for the architecture itself are automatically set by CMake. */ + +#if defined(DAEMON_USE_ARCH_INTRINSICS) + // Set architecture extensions definitions. + + #if defined(_MSC_VER) + /* Detect MSVC providing SSE and SSE2. + + MSVC doesn't set __SSE*__, and only sets _M_IX86_FP on i686. + We should look for _M_AMD64 or _M_X64 to know if SSE and SSE2 + are enabled when building code for amd64. Beware that _M_AMD64 + and _M_X64 are also enabled when building for ARM64EC: + + > - _M_AMD64 Defined as the integer literal value 100 for compilations + > that target x64 processors or ARM64EC. Otherwise, undefined. + > - _M_X64 Defined as the integer literal value 100 for compilations + > that target x64 processors or ARM64EC. Otherwise, undefined. + > - _M_ARM64EC Defined as 1 for compilations that target ARM64EC. + > Otherwise, undefined. + > -- https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170 + + It is unclear if xmmintrin.h is available on ARM64EC. */ + + #if defined(_M_IX86_FP) + #if _M_IX86_FP >= 2 + #define DAEMON_USE_ARCH_INTRINSICS_i686_sse + #define DAEMON_USE_ARCH_INTRINSICS_i686_sse2 + #elif _M_IX86_FP == 1 + #define DAEMON_USE_ARCH_INTRINSICS_i686_sse + #endif + #elif defined(_M_AMD64) || defined(_M_X64) + #if !defined(_M_ARM64EC) + #define DAEMON_USE_ARCH_INTRINSICS_i686_sse + #define DAEMON_USE_ARCH_INTRINSICS_i686_sse2 + #endif + #endif + #else + #if defined(__SSE__) || defined(MSVC_SSE) + #define DAEMON_USE_ARCH_INTRINSICS_i686_sse + #endif + + #if defined(__SSE2__) || defined(MSVC_SSE2) + #define DAEMON_USE_ARCH_INTRINSICS_i686_sse2 + #endif + #endif + + // Include intrinsics-specific headers. + + #if defined(DAEMON_USE_ARCH_INTRINSICS_i686_sse) + #include + #endif + + #if defined(DAEMON_USE_ARCH_INTRINSICS_i686_sse2) + #include + #endif #endif // VM Prefixes diff --git a/src/engine/qcommon/q_math.cpp b/src/engine/qcommon/q_math.cpp index 511aad85ed..9c667d2477 100644 --- a/src/engine/qcommon/q_math.cpp +++ b/src/engine/qcommon/q_math.cpp @@ -743,7 +743,7 @@ void SetPlaneSignbits( cplane_t *out ) int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const cplane_t *p ) { -#if idx86_sse +#if defined(DAEMON_USE_ARCH_INTRINSICS_i686_sse) auto mins = sseLoadVec3Unsafe( emins ); auto maxs = sseLoadVec3Unsafe( emaxs ); auto normal = sseLoadVec3Unsafe( p->normal ); @@ -1802,7 +1802,7 @@ void MatrixSetupShear( matrix_t m, vec_t x, vec_t y ) void MatrixMultiply( const matrix_t a, const matrix_t b, matrix_t out ) { -#if idx86_sse +#if defined(DAEMON_USE_ARCH_INTRINSICS_i686_sse) //#error MatrixMultiply int i; __m128 _t0, _t1, _t2, _t3, _t4, _t5, _t6, _t7; @@ -3291,7 +3291,8 @@ void QuatTransformVectorInverse( const quat_t q, const vec3_t in, vec3_t out ) VectorAdd( out, tmp2, out ); } -#if !idx86_sse +// The SSE variants are inline functions in q_shared.h file. +#if !defined(DAEMON_USE_ARCH_INTRINSICS_i686_sse) // create an identity transform void TransInit( transform_t *t ) { diff --git a/src/engine/qcommon/q_shared.h b/src/engine/qcommon/q_shared.h index e1ec6ac5eb..1ab3217870 100644 --- a/src/engine/qcommon/q_shared.h +++ b/src/engine/qcommon/q_shared.h @@ -241,7 +241,7 @@ void Com_Free_Aligned( void *ptr ); // floats (quat: 4, scale: 1, translation: 3), which is very // convenient for SSE and GLSL, which operate on 4-dimensional // float vectors. -#if idx86_sse +#if defined(DAEMON_USE_ARCH_INTRINSICS_i686_sse) // Here we have a union of scalar struct and sse struct, transform_u and the // scalar struct must match transform_t so we have to use anonymous structs. // We disable compiler warnings when using -Wpedantic for this specific case. @@ -348,7 +348,7 @@ extern const quat_t quatIdentity; float y; // compute approximate inverse square root -#if defined( idx86_sse ) +#if defined(DAEMON_USE_ARCH_INTRINSICS_i686_sse) // SSE rsqrt relative error bound: 3.7 * 10^-4 _mm_store_ss( &y, _mm_rsqrt_ss( _mm_load_ss( &number ) ) ); #else @@ -831,7 +831,7 @@ void SnapVector( V &&v ) //============================================= // combining Transformations -#if idx86_sse +#if defined(DAEMON_USE_ARCH_INTRINSICS_i686_sse) /* swizzles for _mm_shuffle_ps instruction */ #define SWZ_XXXX 0x00 #define SWZ_YXXX 0x01 @@ -1350,6 +1350,7 @@ void SnapVector( V &&v ) t->sseRot = sseQuatNormalize( t->sseRot ); } #else + // The non-SSE variants are in q_math.cpp file. void TransInit( transform_t *t ); void TransCopy( const transform_t *in, transform_t *out );