LLVM 中的 SIMD 向量内存加载

blu*_*rni 6 c++ simd llvm avx llvm-ir

LLVM 中将数据从内存加载到 SIMD 向量中的“正确”(即可移植)方式是什么?

查看 LLVM 的自动矢量化器为 x86 目标生成的典型 IR,模式似乎是:

  • 将指向标量类型(例如,double *)的指针位转换到相应的向量类型(例如,<4 x double>*),
  • 从转换后的指针加载,同时考虑对齐的考虑(即,不使用向量类型的自然对齐,而是使用相应标量类型的对齐)。

在 AVX 的情况下,这种模式很好地映射到 SIMD 内在函数,例如_mm256_loadu_pd()和朋友。但是,我不知道这种策略是否也适用于其他 ISA(例如 Neon、AltiVec)。

我无法在 LLVM 文档中找到有关该主题的信息。我错过了一些明显的东西吗?

blu*_*rni 1

花了更多时间思考这个问题,我相信便携式解决方案可能如下:

  • 以通常(非 SIMD)方式从内存中一一加载标量值,
  • 立即用重复的指令构建一个向量insertelement

类似地,为了将 SIMD 向量中的值存储到内存位置,请通过指令将向量元素提取为标量extractelement,并将它们一一存储。

在我的实验中,LLVM 优化器总是成功地识别这些模式并将它们融合到直接 SIMD 加载/存储指令中。

然而,这种策略也会导致生成的 IR 大小明显膨胀,并导致编译时间随之缩短。因此,目前我将坚持使用直接位播方法,并且如果位播方法在特定设置上失败,也许会实现其他方法作为后备。