Skip to content

Commit 26b6f18

Browse files
committed
Properly check if subleaf is available
1 parent d3d3b74 commit 26b6f18

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

include/xsimd/config/xsimd_cpu_features_x86.hpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,13 @@ namespace xsimd
9494
constexpr x86_cpuid_regs() noexcept = default;
9595

9696
using eax_bitset::all_bits_set;
97+
using eax_bitset::get_range;
9798
using ebx_bitset::all_bits_set;
99+
using ebx_bitset::get_range;
98100
using ecx_bitset::all_bits_set;
101+
using ecx_bitset::get_range;
99102
using edx_bitset::all_bits_set;
103+
using edx_bitset::get_range;
100104
};
101105

102106
template <typename T>
@@ -239,6 +243,10 @@ namespace xsimd
239243

240244
enum class eax
241245
{
246+
/* Start bit for the encoding of the highest subleaf available. */
247+
highest_subleaf_start = 0,
248+
/* End bit for the encoding of the highest subleaf available. */
249+
highest_subleaf_end = 32,
242250
};
243251
enum class ebx
244252
{
@@ -645,7 +653,25 @@ namespace xsimd
645653

646654
inline x86_cpuid_leaf7sub1 const& leaf7sub1() const
647655
{
648-
return safe_get_leaf<status::leaf7sub1_valid>(m_leaf7sub1);
656+
// Check if already initialized
657+
if (m_status.bit_is_set<status::leaf7sub1_valid>())
658+
{
659+
return m_leaf7sub1;
660+
}
661+
662+
// Check if safe to call CPUID with this value as subleaf.
663+
constexpr auto start = x86_cpuid_leaf7::eax::highest_subleaf_start;
664+
constexpr auto end = x86_cpuid_leaf7::eax::highest_subleaf_end;
665+
const auto highest_subleaf7 = leaf7().get_range<start, end>();
666+
if (x86_cpuid_leaf7sub1::subleaf <= highest_subleaf7)
667+
{
668+
m_leaf7sub1 = x86_cpuid_leaf7sub1::read();
669+
}
670+
671+
// Mark as valid in all cases, including if it was not read.
672+
// In this case it will be filled with zeros (all false).
673+
m_status.set_bit<status::leaf7sub1_valid>();
674+
return m_leaf7sub1;
649675
}
650676

651677
inline x86_cpuid_leaf80000001 const& leaf80000001() const

include/xsimd/utils/bits.hpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,21 @@ namespace xsimd
4646
return value | mask;
4747
}
4848

49+
/**
50+
* Return a mask with the `width` lowest bits set.
51+
*/
52+
template <typename I>
53+
constexpr I make_low_mask(I width) noexcept
54+
{
55+
assert(width >= 0);
56+
assert(width <= static_cast<I>(8 * sizeof(I)));
57+
if (width == static_cast<I>(8 * sizeof(I)))
58+
{
59+
return ~I { 0 };
60+
}
61+
return (I { 1 } << width) - I { 1 };
62+
}
63+
4964
/* A bitset over an unsigned integer type, indexed by an enum key type. */
5065
template <typename K, typename U>
5166
struct uint_bitset
@@ -82,6 +97,17 @@ namespace xsimd
8297
m_bitset = utils::set_bit<static_cast<storage_type>(bit)>(m_bitset);
8398
}
8499

100+
/* Extract the bits in [start, end[, shifted down to start at bit 0. */
101+
template <key_type start, key_type end>
102+
constexpr storage_type get_range() const noexcept
103+
{
104+
constexpr storage_type start_bit = static_cast<storage_type>(start);
105+
constexpr storage_type end_bit = static_cast<storage_type>(end);
106+
constexpr storage_type width = end_bit - start_bit;
107+
constexpr storage_type mask = make_low_mask<storage_type>(width);
108+
return (m_bitset >> start_bit) & mask;
109+
}
110+
85111
private:
86112
storage_type m_bitset = { 0 };
87113
};

0 commit comments

Comments
 (0)