Skip to content

Commit b76dc2b

Browse files
authored
[libc] Clean up mask helpers after allowing implicit conversions (#158681)
Summary: I landed a change in clang that allows integral vectors to implicitly convert to boolean ones. This means I can simplify the interface and remove the need to cast to bool on every use. Also do some other cleanups of the traits.
1 parent b8efe1c commit b76dc2b

File tree

4 files changed

+77
-62
lines changed

4 files changed

+77
-62
lines changed

libc/src/__support/CPP/simd.h

Lines changed: 61 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,29 @@ using simd = T [[clang::ext_vector_type(N)]];
5757
template <typename T>
5858
using simd_mask = simd<bool, internal::native_vector_size<T>>;
5959

60+
// Type trait helpers.
61+
template <typename T>
62+
struct simd_size : cpp::integral_constant<size_t, __builtin_vectorelements(T)> {
63+
};
64+
template <class T> constexpr size_t simd_size_v = simd_size<T>::value;
65+
66+
template <typename T> struct is_simd : cpp::integral_constant<bool, false> {};
67+
template <typename T, unsigned N>
68+
struct is_simd<simd<T, N>> : cpp::integral_constant<bool, true> {};
69+
template <class T> constexpr bool is_simd_v = is_simd<T>::value;
70+
71+
template <typename T>
72+
struct is_simd_mask : cpp::integral_constant<bool, false> {};
73+
template <unsigned N>
74+
struct is_simd_mask<simd<bool, N>> : cpp::integral_constant<bool, true> {};
75+
template <class T> constexpr bool is_simd_mask_v = is_simd_mask<T>::value;
76+
77+
template <typename T> struct simd_element_type;
78+
template <typename T, size_t N> struct simd_element_type<simd<T, N>> {
79+
using type = T;
80+
};
81+
template <typename T>
82+
using simd_element_type_t = typename simd_element_type<T>::type;
6083
namespace internal {
6184

6285
template <typename T>
@@ -123,34 +146,14 @@ LIBC_INLINE constexpr static auto split(cpp::simd<T, N> x) {
123146
return result;
124147
}
125148

126-
} // namespace internal
127-
128-
// Type trait helpers.
149+
// Helper trait
129150
template <typename T>
130-
struct simd_size : cpp::integral_constant<size_t, __builtin_vectorelements(T)> {
131-
};
132-
template <class T> constexpr size_t simd_size_v = simd_size<T>::value;
133-
134-
template <typename T> struct is_simd : cpp::integral_constant<bool, false> {};
135-
template <typename T, unsigned N>
136-
struct is_simd<simd<T, N>> : cpp::integral_constant<bool, true> {};
137-
template <class T> constexpr bool is_simd_v = is_simd<T>::value;
138-
139-
template <typename T>
140-
struct is_simd_mask : cpp::integral_constant<bool, false> {};
141-
template <unsigned N>
142-
struct is_simd_mask<simd<bool, N>> : cpp::integral_constant<bool, true> {};
143-
template <class T> constexpr bool is_simd_mask_v = is_simd_mask<T>::value;
151+
using enable_if_integral_t = cpp::enable_if_t<cpp::is_integral_v<T>, T>;
144152

145-
template <typename T> struct simd_element_type;
146-
template <typename T, size_t N> struct simd_element_type<simd<T, N>> {
147-
using type = T;
148-
};
149153
template <typename T>
150-
using simd_element_type_t = typename simd_element_type<T>::type;
154+
using enable_if_simd_t = cpp::enable_if_t<is_simd_v<T>, bool>;
151155

152-
template <typename T>
153-
using enable_if_simd_t = cpp::enable_if_t<is_simd_v<T>, T>;
156+
} // namespace internal
154157

155158
// Casting.
156159
template <typename To, typename From, size_t N>
@@ -159,29 +162,34 @@ LIBC_INLINE constexpr static simd<To, N> simd_cast(simd<From, N> v) {
159162
}
160163

161164
// SIMD mask operations.
162-
template <size_t N> LIBC_INLINE constexpr static bool all_of(simd<bool, N> m) {
163-
return __builtin_reduce_and(m);
165+
template <typename T, size_t N, internal::enable_if_integral_t<T> = 0>
166+
LIBC_INLINE constexpr static bool all_of(simd<T, N> v) {
167+
return __builtin_reduce_and(simd_cast<bool>(v));
164168
}
165-
template <size_t N> LIBC_INLINE constexpr static bool any_of(simd<bool, N> m) {
166-
return __builtin_reduce_or(m);
169+
template <typename T, size_t N, internal::enable_if_integral_t<T> = 0>
170+
LIBC_INLINE constexpr static bool any_of(simd<T, N> v) {
171+
return __builtin_reduce_or(simd_cast<bool>(v));
167172
}
168-
template <size_t N> LIBC_INLINE constexpr static bool none_of(simd<bool, N> m) {
169-
return !any_of(m);
173+
template <typename T, size_t N, internal::enable_if_integral_t<T> = 0>
174+
LIBC_INLINE constexpr static bool none_of(simd<T, N> v) {
175+
return !any_of(v);
170176
}
171-
template <size_t N> LIBC_INLINE constexpr static bool some_of(simd<bool, N> m) {
172-
return any_of(m) && !all_of(m);
177+
template <typename T, size_t N, internal::enable_if_integral_t<T> = 0>
178+
LIBC_INLINE constexpr static bool some_of(simd<T, N> v) {
179+
return any_of(v) && !all_of(v);
173180
}
174-
template <size_t N> LIBC_INLINE constexpr static int popcount(simd<bool, N> m) {
175-
return __builtin_popcountg(m);
181+
template <typename T, size_t N, internal::enable_if_integral_t<T> = 0>
182+
LIBC_INLINE constexpr static int popcount(simd<T, N> v) {
183+
return __builtin_popcountg(v);
176184
}
177-
template <size_t N>
178-
LIBC_INLINE constexpr static int find_first_set(simd<bool, N> m) {
179-
return __builtin_ctzg(m);
185+
template <typename T, size_t N, internal::enable_if_integral_t<T> = 0>
186+
LIBC_INLINE constexpr static int find_first_set(simd<T, N> v) {
187+
return __builtin_ctzg(simd_cast<bool>(v));
180188
}
181-
template <size_t N>
182-
LIBC_INLINE constexpr static int find_last_set(simd<bool, N> m) {
183-
constexpr size_t size = simd_size_v<simd<bool, N>>;
184-
return size - 1 - __builtin_clzg(m);
189+
template <typename T, size_t N, internal::enable_if_integral_t<T> = 0>
190+
LIBC_INLINE constexpr static int find_last_set(simd<T, N> v) {
191+
constexpr size_t size = simd_size_v<simd<T, N>>;
192+
return size - 1 - __builtin_clzg(simd_cast<bool>(v));
185193
}
186194

187195
// Elementwise operations.
@@ -279,33 +287,32 @@ LIBC_INLINE constexpr static T hmax(simd<T, N> v) {
279287
}
280288

281289
// Accessor helpers.
282-
template <typename T>
283-
LIBC_INLINE enable_if_simd_t<T> load_unaligned(const void *ptr) {
290+
template <typename T, internal::enable_if_simd_t<T> = 0>
291+
LIBC_INLINE T load_unaligned(const void *ptr) {
284292
T tmp;
285293
__builtin_memcpy(&tmp, ptr, sizeof(T));
286294
return tmp;
287295
}
288-
template <typename T>
289-
LIBC_INLINE enable_if_simd_t<T> load_aligned(const void *ptr) {
296+
template <typename T, internal::enable_if_simd_t<T> = 0>
297+
LIBC_INLINE T load_aligned(const void *ptr) {
290298
return load_unaligned<T>(__builtin_assume_aligned(ptr, alignof(T)));
291299
}
292-
template <typename T>
293-
LIBC_INLINE enable_if_simd_t<T> store_unaligned(T v, void *ptr) {
300+
template <typename T, internal::enable_if_simd_t<T> = 0>
301+
LIBC_INLINE T store_unaligned(T v, void *ptr) {
294302
__builtin_memcpy(ptr, &v, sizeof(T));
295303
}
296-
template <typename T>
297-
LIBC_INLINE enable_if_simd_t<T> store_aligned(T v, void *ptr) {
304+
template <typename T, internal::enable_if_simd_t<T> = 0>
305+
LIBC_INLINE T store_aligned(T v, void *ptr) {
298306
store_unaligned<T>(v, __builtin_assume_aligned(ptr, alignof(T)));
299307
}
300-
template <typename T>
301-
LIBC_INLINE enable_if_simd_t<T>
308+
template <typename T, internal::enable_if_simd_t<T> = 0>
309+
LIBC_INLINE T
302310
masked_load(simd<bool, simd_size_v<T>> m, void *ptr,
303311
T passthru = internal::poison<simd_element_type<T>>()) {
304312
return __builtin_masked_load(m, ptr, passthru);
305313
}
306-
template <typename T>
307-
LIBC_INLINE enable_if_simd_t<T> masked_store(simd<bool, simd_size_v<T>> m, T v,
308-
void *ptr) {
314+
template <typename T, internal::enable_if_simd_t<T> = 0>
315+
LIBC_INLINE T masked_store(simd<bool, simd_size_v<T>> m, T v, void *ptr) {
309316
__builtin_masked_store(
310317
m, v, static_cast<T *>(__builtin_assume_aligned(ptr, alignof(T))));
311318
}

libc/src/__support/CPP/type_traits/is_unsigned.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include "src/__support/macros/attributes.h"
1717
#include "src/__support/macros/config.h"
1818

19+
#include <stddef.h>
20+
1921
namespace LIBC_NAMESPACE_DECL {
2022
namespace cpp {
2123

@@ -46,6 +48,10 @@ template <typename T> struct is_unsigned {
4648
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
4749
};
4850
#endif // LIBC_COMPILER_HAS_FIXED_POINT
51+
#if LIBC_HAS_VECTOR_TYPE
52+
template <typename T, size_t N>
53+
struct is_unsigned<T [[clang::ext_vector_type(N)]]> : bool_constant<false> {};
54+
#endif
4955

5056
template <typename T>
5157
LIBC_INLINE_VAR constexpr bool is_unsigned_v = is_unsigned<T>::value;

libc/src/string/memory_utils/generic/inline_strlen.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ string_length(const char *src) {
3333
__builtin_align_down(src, alignment));
3434

3535
cpp::simd<char> chars = cpp::load_aligned<cpp::simd<char>>(aligned);
36-
cpp::simd_mask<char> mask = cpp::simd_cast<bool>(chars == null_byte);
36+
cpp::simd_mask<char> mask = chars == null_byte;
3737
size_t offset = src - reinterpret_cast<const char *>(aligned);
3838
if (cpp::any_of(shift_mask(mask, offset)))
3939
return cpp::find_first_set(shift_mask(mask, offset));
4040

4141
for (;;) {
4242
cpp::simd<char> chars = cpp::load_aligned<cpp::simd<char>>(++aligned);
43-
cpp::simd_mask<char> mask = cpp::simd_cast<bool>(chars == null_byte);
43+
cpp::simd_mask<char> mask = chars == null_byte;
4444
if (cpp::any_of(mask))
4545
return (reinterpret_cast<const char *>(aligned) - src) +
4646
cpp::find_first_set(mask);

libc/test/src/__support/CPP/simd_test.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,23 +64,25 @@ TEST(LlvmLibcSIMDTest, MaskOperations) {
6464

6565
EXPECT_TRUE(cpp::any_of(mask));
6666
EXPECT_FALSE(cpp::all_of(mask));
67+
EXPECT_FALSE(cpp::none_of(mask));
6768
EXPECT_TRUE(cpp::some_of(mask));
6869
EXPECT_EQ(cpp::find_first_set(mask), 0);
6970
EXPECT_EQ(cpp::find_last_set(mask), 2);
71+
EXPECT_EQ(cpp::popcount(mask), 2);
7072
}
7173

7274
TEST(LlvmLibcSIMDTest, SplitConcat) {
7375
cpp::simd<char, 8> v{1, 1, 2, 2, 3, 3, 4, 4};
7476
auto [v1, v2, v3, v4] = cpp::split<2, 2, 2, 2>(v);
75-
EXPECT_TRUE(cpp::all_of(cpp::simd_cast<bool>(v1 == 1)));
76-
EXPECT_TRUE(cpp::all_of(cpp::simd_cast<bool>(v2 == 2)));
77-
EXPECT_TRUE(cpp::all_of(cpp::simd_cast<bool>(v3 == 3)));
78-
EXPECT_TRUE(cpp::all_of(cpp::simd_cast<bool>(v4 == 4)));
77+
EXPECT_TRUE(cpp::all_of(v1 == 1));
78+
EXPECT_TRUE(cpp::all_of(v2 == 2));
79+
EXPECT_TRUE(cpp::all_of(v3 == 3));
80+
EXPECT_TRUE(cpp::all_of(v4 == 4));
7981

8082
cpp::simd<char, 8> m = cpp::concat(v1, v2, v3, v4);
81-
EXPECT_TRUE(cpp::all_of(cpp::simd_cast<bool>(m == v)));
83+
EXPECT_TRUE(cpp::all_of(m == v));
8284

8385
cpp::simd<char, 1> c(~0);
8486
cpp::simd<char, 8> n = cpp::concat(c, c, c, c, c, c, c, c);
85-
EXPECT_TRUE(cpp::all_of(cpp::simd_cast<bool>(n == ~0)));
87+
EXPECT_TRUE(cpp::all_of(n == ~0));
8688
}

0 commit comments

Comments
 (0)