Use atomics in CpuInfo::host()

The code was fine, however, some compilers may be able to optimize
it and in some border cases the features returned would be all zero.
This prevents such behavior.
This commit is contained in:
kobalicek
2024-02-10 21:56:59 +01:00
parent 9e39b1e814
commit d82e478fb8
2 changed files with 19 additions and 15 deletions

View File

@@ -7,6 +7,8 @@
#include "../core/cpuinfo.h" #include "../core/cpuinfo.h"
#include "../core/support.h" #include "../core/support.h"
#include <atomic>
// Required by `__cpuidex()` and `_xgetbv()`. // Required by `__cpuidex()` and `_xgetbv()`.
#if ASMJIT_ARCH_X86 #if ASMJIT_ARCH_X86
#if defined(_MSC_VER) #if defined(_MSC_VER)
@@ -1969,13 +1971,13 @@ static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
// CpuInfo - Detect - Host // CpuInfo - Detect - Host
// ======================= // =======================
static uint32_t cpuInfoInitialized;
static CpuInfo cpuInfoGlobal(Globals::NoInit);
const CpuInfo& CpuInfo::host() noexcept { const CpuInfo& CpuInfo::host() noexcept {
// This should never cause a problem as the resulting information should always be the same. static std::atomic<uint32_t> cpuInfoInitialized;
// In the worst case it would just be overwritten non-atomically. static CpuInfo cpuInfoGlobal(Globals::NoInit);
if (!cpuInfoInitialized) {
// This should never cause a problem as the resulting information should always
// be the same. In the worst case it would just be overwritten non-atomically.
if (!cpuInfoInitialized.load(std::memory_order_relaxed)) {
CpuInfo cpuInfoLocal; CpuInfo cpuInfoLocal;
cpuInfoLocal._arch = Arch::kHost; cpuInfoLocal._arch = Arch::kHost;
@@ -1989,7 +1991,7 @@ const CpuInfo& CpuInfo::host() noexcept {
cpuInfoLocal._hwThreadCount = detectHWThreadCount(); cpuInfoLocal._hwThreadCount = detectHWThreadCount();
cpuInfoGlobal = cpuInfoLocal; cpuInfoGlobal = cpuInfoLocal;
cpuInfoInitialized = 1; cpuInfoInitialized.store(1, std::memory_order_seq_cst);
} }
return cpuInfoGlobal; return cpuInfoGlobal;

View File

@@ -22,11 +22,6 @@ ASMJIT_BEGIN_NAMESPACE
//! Each feature is represented by a single bit in an embedded bit array. //! Each feature is represented by a single bit in an embedded bit array.
class CpuFeatures { class CpuFeatures {
public: public:
//! A word that is used to represents feature bits.
typedef Support::BitWord BitWord;
//! Iterator that can iterate all CPU features set.
typedef Support::BitVectorIterator<BitWord> Iterator;
//! \name Constants //! \name Constants
//! \{ //! \{
@@ -37,6 +32,13 @@ public:
}; };
//! \endcond //! \endcond
//! A word that is used to represents feature bits.
typedef Support::BitWord BitWord;
//! Iterator that can iterate all CPU features set.
typedef Support::BitVectorIterator<BitWord> Iterator;
typedef Support::Array<BitWord, kNumBitWords> Bits;
//! \} //! \}
//! \name Data //! \name Data
@@ -48,7 +50,7 @@ public:
//! \{ //! \{
//! Data bits. //! Data bits.
Support::Array<BitWord, kNumBitWords> _bits; Bits _bits;
//! \} //! \}
@@ -178,8 +180,7 @@ public:
#endif // !ASMJIT_NO_DEPRECATED #endif // !ASMJIT_NO_DEPRECATED
//! \} //! \}
};
};
//! X86 specific features data. //! X86 specific features data.
struct X86 : public Data { struct X86 : public Data {
@@ -948,6 +949,7 @@ public:
ASMJIT_INLINE_NODEBUG CpuFeatures() noexcept {} ASMJIT_INLINE_NODEBUG CpuFeatures() noexcept {}
ASMJIT_INLINE_NODEBUG CpuFeatures(const CpuFeatures& other) noexcept = default; ASMJIT_INLINE_NODEBUG CpuFeatures(const CpuFeatures& other) noexcept = default;
ASMJIT_INLINE_NODEBUG explicit CpuFeatures(const Data& other) noexcept : _data{other._bits} {}
ASMJIT_INLINE_NODEBUG explicit CpuFeatures(Globals::NoInit_) noexcept {} ASMJIT_INLINE_NODEBUG explicit CpuFeatures(Globals::NoInit_) noexcept {}
//! \} //! \}