从模板参数中提取 simd 向量长度以用于本地类型
Extracting the simd-vector length from a template parameter to use for a local type
我正在努力寻找正确的 C++/clang 语句来解决以下问题。首先请注意,由于在算术发生之前进行整数提升,以下内容不会溢出无符号短整型。
unsigned short testme = 16320;
testme = testme * 257 / 64;
结果是 65535。但是当我使用 simd 在无符号短裤向量上尝试类似的东西时,它不起作用:
#import <simd/simd.h>
template <typename T>
void muldiv( T* data, unsigned multiply, unsigned divide)
{
*data = (*data * multiply) / divide;
}
...
simd::ushort4 testme = 16320;
muldiv( &testme, 257, 64);
这给出了一个包含四个 1023 的向量。没有发生整数提升并且乘法包装。在 clang 文档中查看之后,我能想到的最好的就是这个。请注意,调用者必须提供一个虚拟参数以提供工作精度作为模板类型参数。
#import <simd/simd.h>
template <typename T, typename W>
void muldiv( T* data, unsigned multiply, unsigned divide, W workingtype)
{
*data = __builtin_convertvector( (__builtin_convertvector(*data, W) * multiply) / divide, T);
}
...
simd::ushort4 testme = 16320;
muldiv( &testme, 257, 64, simd::uint4());
现在我得到了四个 65535 的向量。 T 是模板参数的原因是有时我传递 ushort4、ushort8、ushort16 等。但我发现将工作精度作为参数传递很丑陋,因为它始终是无符号整数。我想不出从 T 中提取 simd-length 的方法,因此我可以在本地声明类型 W。函数中这样的东西会很好:
typedef unsigned int W __attribute__((__vector_size__( ?? )));
但我不知道该怎么做。我试过这样的事情:
bool hopeful = __is_convertible_to( simd::ushort4, simd::uint4);
但希望总是returns错误。
谁能告诉我我需要的魔法?
请注意,这是在提供 的 Apple 平台上。
因此 clang 允许您对属性进行模式匹配并在模板中生成新的属性修改类型。
所以我们可以做到这一点。
simd 宽度属性的第一个模式匹配:
template<class T>
struct get_simd_width;
template<class T, std::size_t x>
struct get_simd_width< __attribute__((__ext_vector_type__(x))) T >:
std::integral_constant<std::size_t, x>
{};
此外,提取属性类型的基础类型:
template<class T>
struct get_simd_type;
template<class T, std::size_t x>
struct get_simd_type< __attribute__((__ext_vector_type__(x))) T >
{
using type = T;
};
然后我们做了一些语法糖,使它们更易于使用:
template<class T>
constexpr std::size_t simd_width = get_simd_width<T>{};
template<class T>
using simd_type = typename get_simd_type<T>::type;
这是为了生成一个新的 simd 类型,其属性为:
template<class T>
struct simd_helper;
template<class T, std::size_t N>
struct simd_helper<T[N]> {
using type = __attribute__((__ext_vector_type__(N))) T;
};
template<class T>
using simd = typename simd_helper<T>::type;
然后simd<int[4]>
制作一个宽度为4的simd类型。
这些应该可以解决您的问题。 Live example.
template <class T>
void muldiv( T* data, unsigned multiply, unsigned divide)
{
using W = simd<int[simd_width<T>]>;
*data = __builtin_convertvector( (__builtin_convertvector(*data, W) * multiply) / divide, T);
}
我正在努力寻找正确的 C++/clang 语句来解决以下问题。首先请注意,由于在算术发生之前进行整数提升,以下内容不会溢出无符号短整型。
unsigned short testme = 16320;
testme = testme * 257 / 64;
结果是 65535。但是当我使用 simd 在无符号短裤向量上尝试类似的东西时,它不起作用:
#import <simd/simd.h>
template <typename T>
void muldiv( T* data, unsigned multiply, unsigned divide)
{
*data = (*data * multiply) / divide;
}
...
simd::ushort4 testme = 16320;
muldiv( &testme, 257, 64);
这给出了一个包含四个 1023 的向量。没有发生整数提升并且乘法包装。在 clang 文档中查看之后,我能想到的最好的就是这个。请注意,调用者必须提供一个虚拟参数以提供工作精度作为模板类型参数。
#import <simd/simd.h>
template <typename T, typename W>
void muldiv( T* data, unsigned multiply, unsigned divide, W workingtype)
{
*data = __builtin_convertvector( (__builtin_convertvector(*data, W) * multiply) / divide, T);
}
...
simd::ushort4 testme = 16320;
muldiv( &testme, 257, 64, simd::uint4());
现在我得到了四个 65535 的向量。 T 是模板参数的原因是有时我传递 ushort4、ushort8、ushort16 等。但我发现将工作精度作为参数传递很丑陋,因为它始终是无符号整数。我想不出从 T 中提取 simd-length 的方法,因此我可以在本地声明类型 W。函数中这样的东西会很好:
typedef unsigned int W __attribute__((__vector_size__( ?? )));
但我不知道该怎么做。我试过这样的事情:
bool hopeful = __is_convertible_to( simd::ushort4, simd::uint4);
但希望总是returns错误。
谁能告诉我我需要的魔法?
请注意,这是在提供
因此 clang 允许您对属性进行模式匹配并在模板中生成新的属性修改类型。
所以我们可以做到这一点。
simd 宽度属性的第一个模式匹配:
template<class T>
struct get_simd_width;
template<class T, std::size_t x>
struct get_simd_width< __attribute__((__ext_vector_type__(x))) T >:
std::integral_constant<std::size_t, x>
{};
此外,提取属性类型的基础类型:
template<class T>
struct get_simd_type;
template<class T, std::size_t x>
struct get_simd_type< __attribute__((__ext_vector_type__(x))) T >
{
using type = T;
};
然后我们做了一些语法糖,使它们更易于使用:
template<class T>
constexpr std::size_t simd_width = get_simd_width<T>{};
template<class T>
using simd_type = typename get_simd_type<T>::type;
这是为了生成一个新的 simd 类型,其属性为:
template<class T>
struct simd_helper;
template<class T, std::size_t N>
struct simd_helper<T[N]> {
using type = __attribute__((__ext_vector_type__(N))) T;
};
template<class T>
using simd = typename simd_helper<T>::type;
然后simd<int[4]>
制作一个宽度为4的simd类型。
这些应该可以解决您的问题。 Live example.
template <class T>
void muldiv( T* data, unsigned multiply, unsigned divide)
{
using W = simd<int[simd_width<T>]>;
*data = __builtin_convertvector( (__builtin_convertvector(*data, W) * multiply) / divide, T);
}