[英]How do I vectorize loop with functors?
我使用一些使用一些容器来存储数据的类; 有多维容器的类。 这些类重载operator ()
以索引数据。 我在循环中使用了很多这样的对象,并希望对它们进行矢量化。 海湾合作委员会无法直接对其进行矢量化; 它说“在基本块中找不到SLP机会”并且驳回了矢量化。
我将如何进行矢量化代码?
我还没有与其他编译器一起检查,因为我希望这可以被少数使用中的着名编译器进行矢量化。
首先,我同意评论说如果你打算成功地对你的循环进行矢量化,你必须“非常接近地管理你的记忆”。 如果不知道这一点 - 请参阅本答案末尾的脚注,以获得关于内存对齐的简短而肤浅的介绍。
然而,即使你的记忆很好地对齐,也有可能让你退缩。 Georg Hager和Gerhard Wellein是受人尊敬的着作“科学家和工程师高性能计算简介”的作者,他明确表示C ++运算符重载可能会阻止循环向量化
用他们自己的话说:
“(....)STL可以通过以下方式定义此运算符(改编自GNU ISO C ++库源):
const T& operator[](size_t __n) const{ return *(this->_M_impl._M_start + __n); }
虽然这看起来很简单,可以有效地内联,但是当前的编译器拒绝将SIMD矢量化应用于上面的求和循环。 单层抽象,在这种情况下是一个重载索引操作符,因此可以防止创建最佳循环代码。“
一位好朋友让我相信,对于stl容器来说,这实际上并不正确,因为编译器可以消除与operator[]
相关的间接层。 但是,您似乎编写了自己的容器,因此必须检查编译器是否可以消除与您自己的operator()
关联的间接层! 一个好的交叉检查是为你自己提供一种方法来直接处理你的容器所拥有的底层数组(意思是:编写一个类似于std::vector.data()
的成员函数,并使用C指针作为你内部的“迭代器”循环)。
关于内存对齐的脚注:
问题:假设你想要矢量化c[i] = a[i] + b[i]
。
第一个事实: size(double)
= 8个字节= 64位。
第二个事实:有一个汇编指令在内存中读取2个双精度数并将它们放在128位寄存器=>一个汇编指令,你可以读取2个双精度数据=>它们可以读取a[0]
和a[1]
然后b[0]
和b[1]
!
第三个事实:当您在寄存器上应用指令时,您可以同时将两个64位的和double
。
问题是只有当a[0]
和b[0]
的内存地址是16的倍数时,程序集才能同时读取a[0]
和a[1]
(如果不是,他可以测试如果a[1]
和b[1]
是对齐等等)。 这就是为什么内存可能成为阻止矢量化的问题。 要解决这个问题,您必须编写容器分配器,以确保容器的第一个元素将写入16的倍数的内存地址。
更新: 此答案提供了有关如何编码对齐内存的分配器的详细说明。
更新2:学习如何编码分配器的另一个有用的答案
更新3:使用posix_memalign / _aligned_malloc的替代方法
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.