Skip to content

Commit

Permalink
Fix x86 SIMD Extension Handling (scp-fs2open#6384)
Browse files Browse the repository at this point in the history
* Fix AVX2 detection

* Also query for proper OS support

* Actually properly set ISA level on all platforms

* Expose level of x86-SIMD instructions to the code.

* Fix handling of forced instruction set

* Fix errors

* Fix MSVC

* Properly deal with linux CI builds

* fix clang
  • Loading branch information
BMagnu authored Oct 28, 2024
1 parent 2eb2af6 commit 95fef2a
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 93 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build-nightly.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,13 @@ jobs:
if [ "$ARCHITECTURE" = "Win32" ]; then
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
-G "Visual Studio 16 2019" -T "v142" ..
else
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
-G "Visual Studio 16 2019" -T "v142" ..
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,13 @@ jobs:
if [ "$ARCHITECTURE" = "Win32" ]; then
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
-G "Visual Studio 16 2019" -T "v142" ..
else
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
-G "Visual Studio 16 2019" -T "v142" ..
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,13 @@ jobs:
if [ "$ARCHITECTURE" = "Win32" ]; then
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
-G "Visual Studio 16 2019" -T "v142" ..
else
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
-G "Visual Studio 16 2019" -T "v142" ..
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test-pull_request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,11 @@ jobs:
else
if [ "$ARCHITECTURE" = "Win32" ]; then
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -G "Visual Studio 16 2019" \
-DFORCED_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -G "Visual Studio 16 2019" \
-DFSO_BUILD_QTFRED=OFF -T "v142" -A "$ARCHITECTURE" ..
else
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "Visual Studio 16 2019" \
-DFORCED_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "Visual Studio 16 2019" \
-DFSO_BUILD_QTFRED=OFF -T "v142" -A "$ARCHITECTURE" ..
fi
fi
Expand Down
5 changes: 1 addition & 4 deletions ci/linux/configure_cmake.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,13 @@ if [ "$RUNNER_OS" = "macOS" ]; then
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_WITH_VULKAN=OFF"
export CMAKE_OSX_ARCHITECTURES="$ARCHITECTURE"
else
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas -static-libstdc++"
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_APPIMAGE=ON"
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_APPIMAGE=ON -DFORCED_SIMD_INSTRUCTIONS=SSE2 -DUSE_STATIC_LIBCXX=ON"
fi

CMAKE_OPTIONS="$JOB_CMAKE_OPTIONS"
if [[ "$COMPILER" =~ ^clang.*$ ]]; then
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCLANG_USE_LIBCXX=ON"
# force clang to silently allow -static-libstdc++ flag
CXXFLAGS="$CXXFLAGS -Qunused-arguments"
fi

if [ ! "$CCACHE_PATH" = "" ]; then
Expand Down
50 changes: 36 additions & 14 deletions cmake/cpufeatures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,72 @@
#ifdef _WIN32
#include <intrin.h>
// Windows
#define cpuid __cpuid
#define cpuid __cpuidex
#define xgetbv _xgetbv

#else

#include <cstdint>

// GCC Inline Assembly
void cpuid(int CPUInfo[4],int InfoType){
void cpuid(int CPUInfo[4], int InfoType, int SubType){
__asm__ __volatile__ (
"cpuid":
"=a" (CPUInfo[0]),
"=b" (CPUInfo[1]),
"=c" (CPUInfo[2]),
"=d" (CPUInfo[3]) :
"a" (InfoType)
"a" (InfoType),
"c" (SubType)
);
}

uint64_t xgetbv(uint32_t xcr) {
uint32_t lower, higher;
__asm__ __volatile__ (
"xgetbv":
"=a"(lower),
"=d"(higher) :
"c"(xcr)
);
return (static_cast<uint64_t>(higher) << static_cast<uint64_t>(32)) | static_cast<uint64_t>(lower);
}

#endif

#include <iostream>

int main( int argc, char* argv[] )
{
int SSE = false;
int SSE2 = false;
int AVX = false;
int AVX2 = false;
bool SSE = false;
bool SSE2 = false;
bool OSXSAVE = false;
bool AVX = false;
bool AVX2 = false;

int info[4];
cpuid(info, 0);
cpuid(info, 0, 0);
int nIds = info[0];

// Detect Instruction Set
if (nIds >= 1){
cpuid(info,0x00000001);
SSE = (info[3] & ((int)1 << 25)) != 0;
SSE2 = (info[3] & ((int)1 << 26)) != 0;

AVX = (info[2] & ((int)1 << 28)) != 0;
cpuid(info, 0x00000001, 0);
SSE = (info[3] & ((int)1 << 25)) != 0;
SSE2 = (info[3] & ((int)1 << 26)) != 0;
OSXSAVE = (info[2] & ((int)1 << 27)) != 0;
AVX = (info[2] & ((int)1 << 28)) != 0;
}
if (nIds >= 7){
cpuid(info,0x00000007);
cpuid(info,0x00000007, 0);
AVX2 = (info[1] & ((int)1 << 5)) != 0;
}

// Detect OS Support
if (!OSXSAVE || (xgetbv(0) & 0x6) == 0) {
AVX = false;
AVX2 = false;
}

if (AVX2)
std::cout << "AVX2";
else if(AVX)
Expand Down
5 changes: 5 additions & 0 deletions cmake/globals.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,8 @@ else()
set(IS_RISCV TRUE)
endif()
endif()

set(IS_X86 FALSE)
if (NOT IS_ARM64 AND NOT IS_RISCV)
set(IS_X86 TRUE)
endif()
49 changes: 35 additions & 14 deletions cmake/toolchain-clang.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,41 @@ option(CLANG_ENABLE_ADDRESS_SANITIZER "Enable -fsanitize=address" OFF)

option(CLANG_USE_LIBCXX "Use libc++" OFF)

# Clang does not support -march=native for RISC-V
if(IS_RISCV)
# You do not need to pass a -march, passing nothing will make clang to choose itself.
# If you want a specific set of instructions like vectors, set -march in CFLAGS and CXXFLAGS env variables
set(C_BASE_FLAGS "-pipe")
set(CXX_BASE_FLAGS "-pipe")
else()
# These are the default values
set(C_BASE_FLAGS "-march=native -pipe")
set(CXX_BASE_FLAGS "-march=native -pipe")
# These are the default values
set(C_BASE_FLAGS "-pipe")
set(CXX_BASE_FLAGS "-pipe")

if(IS_X86)
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
set(CLANG_EXTENSIONS "-march=native")
elseif (FSO_INSTRUCTION_SET STREQUAL "")
set(CLANG_EXTENSIONS "-march=x86-64")
elseif (FSO_INSTRUCTION_SET STREQUAL "SSE")
set(CLANG_EXTENSIONS "-march=x86-64 -msse -mfpmath=sse")
elseif (FSO_INSTRUCTION_SET STREQUAL "SSE2")
set(CLANG_EXTENSIONS "-march=x86-64 -msse -msse2 -mfpmath=sse")
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX")
set(CLANG_EXTENSIONS "-march=x86-64-v2 -msse -msse2 -mavx -mfpmath=sse")
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX2")
set(CLANG_EXTENSIONS "-march=x86-64-v3 -msse -msse2 -mavx -mavx2 -mfpmath=sse")
else ()
message( FATAL_ERROR "Unknown instruction set encountered for clang. Update toolchain-clang.cmake!" )
endif()

set(C_BASE_FLAGS "${C_BASE_FLAGS} ${CLANG_EXTENSIONS}")
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} ${CLANG_EXTENSIONS}")
elseif(IS_ARM)
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
set(C_BASE_FLAGS "${C_BASE_FLAGS} -march=native")
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -march=native")
endif ()
elseif(IS_RISCV)
# Default C/CXX_BASE_FLAGS are fine for RISC-V
endif()

if (USE_STATIC_LIBCXX)
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -static-libstdc++ -Qunused-arguments")
set(CLANG_USE_LIBCXX ON)
endif()

# For C and C++, the values can be overwritten independently
Expand All @@ -43,10 +68,6 @@ set(COMPILER_FLAGS "${COMPILER_FLAGS} ${_flags}")

set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsigned-char -Wno-unknown-pragmas")

# Omit "argument unused during compilation" when clang is used with ccache.
if(${CMAKE_CXX_COMPILER} MATCHES "ccache")
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Qunused-arguments")
endif()

if ("${CMAKE_GENERATOR}" STREQUAL "Ninja")
# Force color diagnostics for Ninja generator
Expand Down
53 changes: 42 additions & 11 deletions cmake/toolchain-gcc.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,49 @@ option(GCC_ENABLE_SANITIZE_UNDEFINED "Enable -fsanitize=undefined" OFF)
option(GCC_USE_GOLD "Use the gold linker instead of the standard linker" OFF)
option(GCC_GENERATE_GDB_INDEX "Adds linker option to generate the gdb index for debug builds" OFF)

# GCC does not support -march=native in RISC-V
if(IS_RISCV)
# You do not need to pass a -march, passing nothing will make gcc to choose itself.
# If you want a specific set of instructions like vectors, set -march in CFLAGS and CXXFLAGS env variables
# Example for vectors: -march=rv64gcv
# These are the default values
set(C_BASE_FLAGS "-pipe")
set(CXX_BASE_FLAGS "-pipe")

if(IS_X86)
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
set(GCC_EXTENSIONS "-march=native")
elseif (FSO_INSTRUCTION_SET STREQUAL "")
set(GCC_EXTENSIONS "-march=x86-64")
elseif (FSO_INSTRUCTION_SET STREQUAL "SSE")
set(GCC_EXTENSIONS "-march=x86-64 -msse -mfpmath=sse")
elseif (FSO_INSTRUCTION_SET STREQUAL "SSE2")
set(GCC_EXTENSIONS "-march=x86-64 -msse -msse2 -mfpmath=sse")
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX")
set(GCC_EXTENSIONS "-march=x86-64-v2 -msse -msse2 -mavx -mfpmath=sse")
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX2")
set(GCC_EXTENSIONS "-march=x86-64-v3 -msse -msse2 -mavx -mavx2 -mfpmath=sse")
else ()
message( FATAL_ERROR "Unknown instruction set encountered for GCC. Update toolchain-gcc.cmake!" )
endif()

set(C_BASE_FLAGS "${C_BASE_FLAGS} ${GCC_EXTENSIONS}")
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} ${GCC_EXTENSIONS}")
elseif(IS_ARM)
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
set(C_BASE_FLAGS "${C_BASE_FLAGS} -march=native")
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -march=native")
endif ()
elseif(IS_RISCV)
# You do not need to pass a -march, passing nothing will make gcc to choose itself.
# If you want a specific set of instructions like vectors, set -march in CFLAGS and CXXFLAGS env variables
# Example for vectors: -march=rv64gcv
# https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Options.html
set(C_BASE_FLAGS "-pipe")
set(CXX_BASE_FLAGS "-pipe")
else()
# These are the default values
set(C_BASE_FLAGS "-march=native -pipe")
set(CXX_BASE_FLAGS "-march=native -pipe")
# As such, default C/CXX_BASE_FLAGS are sufficient.
endif()

if (IS_64BIT)
set(C_BASE_FLAGS "${C_BASE_FLAGS} -m64")
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -m64")
endif()

if (USE_STATIC_LIBCXX)
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -static-libstdc++")
endif()

# For C and C++, the values can be overwritten independently
Expand Down
64 changes: 23 additions & 41 deletions cmake/toolchain-msvc.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -95,49 +95,31 @@ ENDIF(MSVC_USE_RUNTIME_DLL)
INCLUDE(MSVCMultipleProcessCompile)

# Visual Studio supports compiling for multiple vector instruction sets
SET(POSSIBLE_INSTUCTION_SETS "" SSE SSE2 AVX AVX2)

if (NOT DEFINED MSVC_SIMD_INSTRUCTIONS)
detect_simd_instructions(MSVC_DETECTED_SIMD_INSTRUCTIONS)
if(IS_X86)
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
# MSVC has no direct -march=native equivalent, so just use the detected extensions.
SET(FSO_INSTRUCTION_SET ${DETECTED_SIMD_INSTRUCTIONS})
endif()

if(FSO_INSTRUCTION_SET STREQUAL "")
set(MSVC_SIMD_INSTRUCTIONS "IA32")
else()
set(MSVC_SIMD_INSTRUCTIONS ${FSO_INSTRUCTION_SET})
endif()

if (NOT (IS_64BIT AND (MSVC_SIMD_INSTRUCTIONS STREQUAL "IA32" OR MSVC_SIMD_INSTRUCTIONS STREQUAL "SSE" OR MSVC_SIMD_INSTRUCTIONS STREQUAL "SSE2")))
# 32-Bit and SSE(2) mustn't be set, as these are implied in x86_64 and thus MSVC does not support it for the /arch argument
CHECK_CXX_COMPILER_FLAG("/arch:${MSVC_SIMD_INSTRUCTIONS}" COMPILER_SUPPORTS_ARCH)

IF(COMPILER_SUPPORTS_ARCH)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:${MSVC_SIMD_INSTRUCTIONS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:${MSVC_SIMD_INSTRUCTIONS}")
ELSE()
message( FATAL_ERROR "Your version of MSVC does not support the requested instruction set. Consider updating!" )
ENDIF()
endif()

SET(MSVC_SIMD_INSTRUCTIONS "${MSVC_DETECTED_SIMD_INSTRUCTIONS}" CACHE FILEPATH "The SIMD instructions which will be used, possible values are ${POSSIBLE_INSTUCTION_SETS}")
MARK_AS_ADVANCED(FORCE MSVC_SIMD_INSTRUCTIONS)
endif()
set(FSO_INSTRUCTION_SET ${MSVC_SIMD_INSTRUCTIONS})

LIST(FIND POSSIBLE_INSTUCTION_SETS "${MSVC_SIMD_INSTRUCTIONS}" SET_INDEX)

if (SET_INDEX LESS 0)
MESSAGE(STATUS "An invalid instruction set was specified, defaulting to no special compiler options.")
else()
IF (NOT SET_INDEX EQUAL 0)
SET(FOUND)

FOREACH(list_index RANGE ${SET_INDEX} 1)
list(GET POSSIBLE_INSTUCTION_SETS ${list_index} _simd_set)
CHECK_CXX_COMPILER_FLAG("/arch:${_simd_set}" COMPILER_SUPPORTS_ARCH_${_simd_set})

IF(COMPILER_SUPPORTS_ARCH_${_simd_set})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:${_simd_set}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:${_simd_set}")

SET(FOUND TRUE)
BREAK()
ENDIF()
ENDFOREACH(list_index)

IF(NOT FOUND)
# Don't set anything, it will likely not work
MESSAGE(STATUS "Your compiler does not support any optimization flags, defaulting to none")
ENDIF(NOT FOUND)
ELSE()
CHECK_CXX_COMPILER_FLAG("/arch:IA32" COMPILER_SUPPORTS_ARCH_IA32)

IF(COMPILER_SUPPORTS_ARCH_IA32)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:IA32")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:IA32")
ENDIF(COMPILER_SUPPORTS_ARCH_IA32)
ENDIF()
endif()

target_compile_definitions(compiler INTERFACE _CRT_SECURE_NO_DEPRECATE _CRT_SECURE_NO_WARNINGS _SECURE_SCL=0 NOMINMAX
Expand Down
Loading

0 comments on commit 95fef2a

Please sign in to comment.