c++ - 从模板参数中提取 simd vector 长度以用于本地类型

标签 c++ templates clang simd metal

我正在努力寻找正确的 C++/clang 语句来解决以下问题。首先请注意,由于算术发生之前的整数提升,以下代码不会溢出无符号短整型。

unsigned short testme = 16320;
testme = testme * 257 / 64;

结果是 65535。但是当我使用 simd 在无符号短裤 vector 上尝试类似的操作时,它不起作用:

#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 组成的 vector 。没有发生整数提升并且乘法换行。在查看 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 组成的 vector 。 T 是模板参数的原因是有时我传递 ushort4、ushort8、ushort16 等。但我发现将工作精度作为参数传递很丑陋,因为它始终是无符号整数。我无法找到从 T 中提取 simd-length 的方法,因此我可以在本地声明类型 W。在函数中像这样的东西会很好:

typedef unsigned int W __attribute__((__vector_size__( ?? )));

但我不知道如何实现这一点。我尝试过这样的事情:

bool hopeful = __is_convertible_to( simd::ushort4, simd::uint4);

但充满希望的总是返回错误。

谁能告诉我我需要什么魔法?

请注意,这是在提供 的 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]>生成 width-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++ - 从模板参数中提取 simd vector 长度以用于本地类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65555207/

相关文章:

c++ - 具有类类型非类型模板参数的类模板成员的类外定义

c++ - 使用 clang 编译时出现正则表达式段错误,可能是编译器错误?

c++ - 使用 'ofstream' 代码错误写入文本文件

c++ - 为什么此代码不创建竞争条件?

C++冒泡排序返回奇怪的值

swift - 有没有办法一起使用模板、输入输出参数和可选参数?

c++ - 函数指针 vs 函数作为模板非类型参数

c++ - 语义规则的编译时执行

c++ - 为 OSX 上的简单 C/CPP 程序获取文本化二进制文件(0 和 1)的最简单方法

c++ - 使用 g++5 进行的内联构建时出现 valgrind 错误 - valgrind 或 g++5 中的错误?