Skip to content

Commit

Permalink
Move x86 cpuid code from cpuid.hpp to src/arch/x86/cpuid.cpp
Browse files Browse the repository at this point in the history
  • Loading branch information
kimwalisch committed Jun 21, 2024
1 parent f4f3c91 commit a1f8ea1
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 142 deletions.
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,14 @@ else()
set(LIB_SRC ${LIB_SRC} src/gourdon/AC.cpp)
endif()

# On x86 CPUs compile cpuid.cpp ######################################

include("${PROJECT_SOURCE_DIR}/cmake/x86_cpuid.cmake")

if(x86_cpuid)
set(LIB_SRC ${LIB_SRC} src/arch/x86/cpuid.cpp)
endif()

# Enable __float128 support (requires libquadmath) ###################

if(WITH_FLOAT128)
Expand Down
3 changes: 2 additions & 1 deletion ChangeLog
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Changes in primecount-7.14, 2024-06-20
Changes in primecount-7.14, 2024-06-21

* Move x86 cpuid code from cpuid.hpp to src/arch/x86/cpuid.cpp.
* int128_t.hpp: Rename namespace port to pstd (portable std namespace).
* popcnt.hpp: Improve GCC performance on x86 CPUs.
* Sieve.hpp: Tune AVX512 code.
Expand Down
6 changes: 3 additions & 3 deletions cmake/multiarch_avx512_vpopcnt.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ include(CheckCXXSourceCompiles)
include(CMakePushCheckState)

cmake_push_check_state()
set(CMAKE_REQUIRED_INCLUDES "${PROJECT_SOURCE_DIR}/include")
set(CMAKE_REQUIRED_INCLUDES "${PROJECT_SOURCE_DIR}")

check_cxx_source_compiles("
// GCC/Clang function multiversioning for AVX512 is not needed if
Expand All @@ -20,7 +20,7 @@ check_cxx_source_compiles("
Error: AVX512 BMI2 multiarch not needed!
#endif
#include <cpu_supports_avx512_bmi2.hpp>
#include <src/arch/x86/cpuid.cpp>
#include <immintrin.h>
#include <stdint.h>
Expand Down Expand Up @@ -65,7 +65,7 @@ check_cxx_source_compiles("
uint64_t cnt = 0;
Sieve sieve;
if (cpu_supports_avx512_bmi2)
if (primecount::has_cpuid_avx512_bmi2())
cnt = sieve.count_avx512_bmi2(&array[0], 10);
else
cnt = sieve.count_default(&array[0], 10);
Expand Down
29 changes: 29 additions & 0 deletions cmake/x86_cpuid.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# On x86 CPUs we need to enable the use of cpuid.cpp.
# If cpuid.cpp compiles we assume it is a x86 CPU.

include(CheckCXXSourceCompiles)
include(CMakePushCheckState)

cmake_push_check_state()
set(CMAKE_REQUIRED_INCLUDES "${PROJECT_SOURCE_DIR}")

check_cxx_source_compiles("
#include <src/arch/x86/cpuid.cpp>
#include <iostream>
int main()
{
int abcd[4];
primecount::run_cpuid(1, 0, abcd);
int ecx = abcd[2];
if (ecx & (1 << 23)) == (1 << 23))
std::cout << \"CPU supports POPCNT!\" << std::endl;
else
std::cout << \"CPU does not support POPCNT!\" << std::endl;
return 0;
}
" x86_cpuid)

cmake_pop_check_state()
72 changes: 4 additions & 68 deletions include/cpu_supports_avx512_bmi2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,80 +11,16 @@
#ifndef CPU_SUPPORTS_AVX512_BMI2_HPP
#define CPU_SUPPORTS_AVX512_BMI2_HPP

#include <cpuid.hpp>
#include <stdint.h>
namespace primecount {

#if defined(_MSC_VER)
#include <immintrin.h>
#endif

// CPUID bits documentation:
// https://en.wikipedia.org/wiki/CPUID

// %ebx bit flags
#define bit_BMI2 (1 << 8)
#define bit_AVX512F (1 << 16)
bool has_cpuid_avx512_bmi2();

// %ecx bit flags
#define bit_AVX512_VPOPCNTDQ (1 << 14)

// xgetbv bit flags
#define XSTATE_SSE (1 << 1)
#define XSTATE_YMM (1 << 2)
#define XSTATE_ZMM (7 << 5)
} // namespace

namespace {

// Get Value of Extended Control Register
inline uint64_t get_xcr0()
{
#if defined(_MSC_VER)
return _xgetbv(0);
#else
uint32_t eax;
uint32_t edx;

__asm__ ("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));
return eax | (uint64_t(edx) << 32);
#endif
}

inline bool run_cpuid_avx512_bmi2()
{
int abcd[4];

run_cpuid(1, 0, abcd);

int osxsave_mask = (1 << 27);

// Ensure OS supports extended processor state management
if ((abcd[2] & osxsave_mask) != osxsave_mask)
return false;

uint64_t ymm_mask = XSTATE_SSE | XSTATE_YMM;
uint64_t zmm_mask = XSTATE_SSE | XSTATE_YMM | XSTATE_ZMM;
uint64_t xcr0 = get_xcr0();

// Check AVX OS support
if ((xcr0 & ymm_mask) != ymm_mask)
return false;

// Check AVX512 OS support
if ((xcr0 & zmm_mask) != zmm_mask)
return false;

run_cpuid(7, 0, abcd);

if ((abcd[1] & bit_BMI2) != bit_BMI2)
return false;

// AVX512F, AVX512VPOPCNTDQ
return ((abcd[1] & bit_AVX512F) == bit_AVX512F &&
(abcd[2] & bit_AVX512_VPOPCNTDQ) == bit_AVX512_VPOPCNTDQ);
}

/// Initialized at startup
bool cpu_supports_avx512_bmi2 = run_cpuid_avx512_bmi2();
bool cpu_supports_avx512_bmi2 = primecount::has_cpuid_avx512_bmi2();

} // namespace

Expand Down
26 changes: 11 additions & 15 deletions include/cpu_supports_popcnt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
#ifndef CPU_SUPPORTS_POPCNT_HPP
#define CPU_SUPPORTS_POPCNT_HPP

// Enable CPUID on x86 and x86-64 CPUs
// Enable CPUID for POPCNT on x86 and x86-64 CPUs.
// This is required because not all x86 and x86-64 CPUs
// support the POPCNT instruction.
#if defined(__x86_64__) || \
defined(__i386__) || \
defined(_M_X64) || \
Expand All @@ -23,6 +25,7 @@
// such as -mavx or -march=native.
#if defined(__POPCNT__)
#define HAS_POPCNT

// The MSVC compiler does not support a POPCNT macro, but if the user
// compiles with e.g. /arch:AVX or /arch:AVX512 then MSVC defines
// the __AVX__ macro and POPCNT is also supported.
Expand All @@ -31,29 +34,22 @@
#endif

#if !defined(HAS_POPCNT)

#include <cpuid.hpp>
#define ENABLE_CPUID_POPCNT

namespace {
namespace primecount {

inline bool run_cpuid_supports_popcnt()
{
int abcd[4];
run_cpuid(1, 0, abcd);
bool has_cpuid_popcnt();

// %ecx POPCNT bit flag
// https://en.wikipedia.org/wiki/CPUID
int bit_POPCNT = 1 << 23;
return (abcd[2] & bit_POPCNT) == bit_POPCNT;
}
} // namespace

namespace {

/// Initialized at startup
bool cpu_supports_popcnt = run_cpuid_supports_popcnt();
bool cpu_supports_popcnt = primecount::has_cpuid_popcnt();

} // namespace

#endif // !defined(HAS_POPCNT)
#endif // CPUID
#endif // x86 or x86-64

#endif
55 changes: 0 additions & 55 deletions include/cpuid.hpp

This file was deleted.

Loading

0 comments on commit a1f8ea1

Please sign in to comment.