【问题标题】:Do gcc vector extensions support variable length vectors?gcc 向量扩展是否支持可变长度向量?
【发布时间】:2021-04-12 18:39:29
【问题描述】:

这似乎不起作用/编译

void vec(size_t n) {
    typedef char v4si __attribute__((vector_size(n)));
    v4si t={1};
}

是否有适当的方法来声明或不受支持?

【问题讨论】:

  • 由于大小只允许基类型的二的正幂倍数,我认为不支持。该文档没有说明非常量大小。 -- 您可以考虑预先定义应用程序中需要的所有类型,并使用开关来选择请求的类型。
  • 你想在这里实现什么?编写一个简单的 for 循环并使用 -O3 进行编译是一种选择吗?切换到 C++ 是一种选择吗? (如果在编译时已知,您可以将n 作为模板参数传递)
  • @chtz 问题是 gcc 倾向于不矢量化简单循环,因此需要明确说明。
  • @thebusybee 大小可以是 1 和 10Gb 之间的任意值。
  • 如果循环没有被矢量化,那么你需要检查日志看看为什么它没有被矢量化并修复

标签: c gcc vector simd c99


【解决方案1】:

不,那没有任何意义。这就像在运行时尝试根据某个变量的值选择 uint32_t 还是 uint64_t。

手动向量化通过将整个数组视为一个巨大的 SIMD 向量来工作,它通过告诉编译器确切地告诉编译器如何使用固定大小的短向量来工作。如果自动矢量化不适用于普通数组,这将无济于事。

如果您不想手动执行循环,要让 GCC “更努力地”自动矢量化循环,#pragma omp SIMDgcc -fopenmp 可以在 -O2 自动矢量化。或者使用-O3 进行编译会将每个循环都视为自动矢量化的候选对象。 (还有关于单个结构的东西;不过,clang 通常比 gcc 更擅长在非循环代码中找到 SIMD 用例。clang 有时可能过于激进,并且花费更多时间将数据混洗在一起,而不是单独进行标量工作.)

但请注意,GCC 和 clang 的自动矢量化只有在循环行程计数可以在第一次迭代之前计算时才能工作。它可以是运行时变量计数,但可能会根据数据随时触发的if()break; 退出条件会破坏它们。所以例如他们无法自动矢量化使用 while(*p++ != 0){...} 的幼稚循环 strlenstrchr 实现。 ICC 可以做到这一点。

此外,如果您需要任何类型的改组,您通常需要自己使用 GNU C 本机向量或特定目标的内在函数(例如 x86 的 SSE/AVX、ARM 的 NEON/AdvSIMD、Power 的 AltiVec 等) .


Cray 机器显然有 SIMD,它通过给硬件一个指针 + 长度并让它在它想要的任何块中“循环”来工作(可能就像现代 x86 rep movsd 实际上可以在其微码中使用更大的块一样)。但现代 CPU 具有固定宽度的短向量 SIMD 指令,例如可以执行 16 或 32 个字节。

(ARM SVE 介于两者之间,它允许代码向前兼容以利用未来硬件上更宽的向量,而不是完全以向量宽度烘焙。不过,它仍然是您无法控制的固定大小。你仍然必须循环使用它,并通过硬件的向量宽度增加你的指针.它有掩蔽的东西来忽略你想要处理的结束之后的元素,所以你可以将它用于任意短的数组,我认为,并且数组的剩余端。但是对于任意长的数组,您仍然需要循环。此外,很少有 CPU 支持 SVE。顺便说一句,SVE 与Agner Fog's ForwardCom blue-sky paper architecture 中的 SIMD 类似的概念,其目的也是让代码利用未来更广泛的硬件,而无需重新编译或重做手动矢量化。)

当您针对具有固定宽度 SIMD 向量的机器(例如选择 16 或 32)时,您希望从 运行时 可变大小的“向量”中获得什么样的 asm 代码生成字节,选择作为指令编码的一部分?

【讨论】:

  • 虽然有一种特殊情况是初始化可变长度数组。这里的问题是我需要在一个固定的地址(据我所知只有 cilk 覆盖)。 您的其中一个陈述也有点错误,因为 arm 现在具有可扩展的矢量扩展功能,就像 cray 机器允许的那样工作。与 Neon 不同,在这种情况下,向量长度可以是任何值。
  • 其实彼得是对的; SVE 并不是这样工作的。有一个确定长度的函数,您可以在递增计数器的同时循环遍历数据。在循环中,您生成一个基于剩余元素数量的掩码(基于长度和计数器),因此对于最后一次迭代,机器将屏蔽任何剩余元素并且不触摸它们。有关示例,请参见 developer.arm.com/documentation/101726/0210/…
  • @user2284570:您是否正在寻找memsetwmemset,如果其中任何一个与您的数组的元素大小匹配? GCC 可以内联它们,或者调用一个高效的 libc 实现。此外,SVE 很有趣且值得一提,但 SVE 不像 Cray 矢量化或 x86 rep stosd。谢谢你提醒我。
  • @PeterCordes 我正在为我的自定义分配器重新实现 memset()
  • @user2284570:你希望通过调用memset获得什么? GCC 和 clang 通常非常擅长编译对 memset 的调用。手动矢量化充其量对于某些与您正在调整的唯一类似的微架构有好处,但是 GCC 已经知道 memset 策略在不同 ISA 的不同微架构上是好的。 (至少在理论上;有时可能会遗漏一些优化,您可以在 GCC 的 bugzilla 上报告这些优化。)
猜你喜欢
  • 2013-09-26
  • 1970-01-01
  • 1970-01-01
  • 2015-08-25
  • 2020-06-19
  • 2013-08-23
  • 2014-06-07
  • 2012-01-25
相关资源
最近更新 更多