在 GCC/CLang 自动矢量化中强制对齐加载/存储的对齐属性

2023-12-09

众所周知,GCC/CLang 使用 SIMD 指令可以很好地自动向量化循环。

还已知存在对齐()标准 C++ 属性,除其他用途外还允许对齐堆栈变量,例如以下代码:

在线尝试一下!

#include <cstdint>
#include <iostream>

int main() {
    alignas(1024) int x[3] = {1, 2, 3};
    alignas(1024) int (&y)[3] = *(&x);

    std::cout << uint64_t(&x) % 1024 << " "
        << uint64_t(&x) % 16384 << std::endl;
    std::cout << uint64_t(&y) % 1024 << " "
        << uint64_t(&y) % 16384 << std::endl;
}

Outputs:

0 9216
0 9216

这意味着两者x and y在堆栈上按 1024 字节对齐,但不是 16384 字节。

现在让我们看另一个代码:

在线尝试一下!

#include <cstdint>

void f(uint64_t * x, uint64_t * y) {
    for (int i = 0; i < 16; ++i)
        x[i] ^= y[i];
}

如果编译时使用-std=c++20 -O3 -mavx512fGCC 上的属性它会生成以下 asm 代码(提供部分代码):

        vmovdqu64       zmm1, ZMMWORD PTR [rdi]
        vpxorq  zmm0, zmm1, ZMMWORD PTR [rsi]
        vmovdqu64       ZMMWORD PTR [rdi], zmm0
        vmovdqu64       zmm0, ZMMWORD PTR [rsi+64]
        vpxorq  zmm0, zmm0, ZMMWORD PTR [rdi+64]
        vmovdqu64       ZMMWORD PTR [rdi+64], zmm0

AVX-512 未对齐加载 + 异或 + 未对齐存储执行两次。所以我们可以理解,我们的 64 位数组异或操作被 GCC 自动向量化以使用 AVX-512 寄存器,并且循环也被展开。

我的问题是如何告诉 GCC 提供给函数指针x and y都对齐到 64 字节,因此而不是未对齐的负载 (vmovdqu64)就像上面的代码一样,我可以强制 GCC 使用对齐负载 (vmovdqa64)。众所周知,对齐的加载/存储可以快得多。

我第一次尝试强制 GCC 进行对齐加载/存储是通过以下代码:

在线尝试一下!

#include <cstdint>

void  g(uint64_t (&x_)[16],
        uint64_t const (&y_)[16]) {

    alignas(64) uint64_t (&x)[16] = x_;
    alignas(64) uint64_t const (&y)[16] = y_;

    for (int i = 0; i < 16; ++i)
        x[i] ^= y[i];
}

但这段代码仍然会产生未对齐的负载(vmovdqu64)与上面的 asm 代码(之前的代码片段)相同。因此这个alignas(64)提示没有提供任何有用的信息来改进 GCC 汇编代码。

我的问题是如何强制 GCC 进行对齐的自动矢量化,除了为所有操作手动编写 SIMD 内在函数,例如_mm512_load_epi64()?

如果可能的话,我需要所有 GCC/CLang/MSVC 的解决方案。


尽管并非所有编译器都完全可移植,__builtin_assume_aligned会告诉 GCC 假设指针是对齐的。

我经常使用一种不同的策略,使用辅助结构更易于移植:

template<size_t Bits>
struct alignas(Bits/8) uint64_block_t
{
    static const size_t bits = Bits;
    static const size_t size = bits/64;
    
    std::array<uint64_t,size> v;
    
    uint64_block_t& operator&=(const uint64_block_t& v2) { for (size_t i = 0; i < size; ++i) v[i] &= v2.v[i]; return *this; }
    uint64_block_t& operator^=(const uint64_block_t& v2) { for (size_t i = 0; i < size; ++i) v[i] ^= v2.v[i]; return *this; }
    uint64_block_t& operator|=(const uint64_block_t& v2) { for (size_t i = 0; i < size; ++i) v[i] |= v2.v[i]; return *this; }
    uint64_block_t operator&(const uint64_block_t& v2) const { uint64_block_t tmp(*this); return tmp &= v2; }
    uint64_block_t operator^(const uint64_block_t& v2) const { uint64_block_t tmp(*this); return tmp ^= v2; }
    uint64_block_t operator|(const uint64_block_t& v2) const { uint64_block_t tmp(*this); return tmp |= v2; }
    uint64_block_t operator~() const { uint64_block_t tmp; for (size_t i = 0; i < size; ++i) tmp.v[i] = ~v[i]; return tmp; }
    bool operator==(const uint64_block_t& v2) const { for (size_t i = 0; i < size; ++i) if (v[i] != v2.v[i]) return false; return true; }
    bool operator!=(const uint64_block_t& v2) const { for (size_t i = 0; i < size; ++i) if (v[i] != v2.v[i]) return true; return false; }
    
    bool get_bit(size_t c) const   { return (v[c/64]>>(c%64))&1; }
    void set_bit(size_t c)         { v[c/64] |= uint64_t(1)<<(c%64); }
    void flip_bit(size_t c)        { v[c/64] ^= uint64_t(1)<<(c%64); }
    void clear_bit(size_t c)       { v[c/64] &= ~(uint64_t(1)<<(c%64)); }
    void set_bit(size_t c, bool b) { v[c/64] &= ~(uint64_t(1)<<(c%64)); v[c/64] |= uint64_t(b ? 1 : 0)<<(c%64); }
    size_t hammingweight() const   { size_t w = 0; for (size_t i = 0; i < size; ++i) w += mccl::hammingweight(v[i]); return w; }
    bool parity() const            { uint64_t x = 0; for (size_t i = 0; i < size; ++i) x ^= v[i]; return mccl::hammingweight(x)%2; }
};

然后使用reinterpret_cast将指向uint64_t的指针转换为指向该结构的指针。

将 uint64_t 上的循环转换为这些块上的循环通常可以很好地自动矢量化。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 GCC/CLang 自动矢量化中强制对齐加载/存储的对齐属性 的相关文章

随机推荐

  • MySQL JOIN 忽略 NULL 值

    我有以下带有 JOIN 的 SQL 如果我运行它 它会忽略 users 表中的 group id 中具有 NULL 值的记录 因此 我得到的结果较少 SELECT u user id u email g group name FROM us
  • 使用 Python 将 CSV 文件上传到 Google Cloud Storage

    我需要使用 Python 自动将本地 csv 文件上传到 Google Cloud 存储桶中 我可以使用哪个 Python 库 任何示例代码将不胜感激 我们可以使用google python客户端api将文件上传到google云存储 首先
  • iPhone 5 中的定位服务进入“非活动”状态

    甚至我的应用程序也在后台注册位置更新 在我的代码中 self locationManager desiredAccuracy kCLLocationAccuracyThreeKilometers self locationManager d
  • C中使用scanf()连续读取两个字符

    我正在尝试输入用户的两个字符t次数 这是我的代码 int main int t scanf d t char a b for i 0 i
  • 通过 Paramiko 从 SFTP 服务器将 CSV 文件读入 Pandas 失败,并显示“'utf-8'编解码器无法解码字节...在位置...:无效的起始字节”

    我正在尝试使用 Paramiko 从 SFTP 服务器将 CSV 文件读入 Pandas with sftp open path file filename as fp fp aux pd read csv fp separator 但是当
  • 菜单元素的 ListView 信号和槽

    我正在尝试使用自定义元素实现某种自定义菜单 最终目标是创建某种带有文本和图标的弹出菜单 但在创作过程中我遇到了一些问题 我可以展示两个主要问题 有一个带有标题的奇怪菜单元素Hello world在第一个位置 看起来像是读取应用程序窗口的标题
  • 当我们显式调用 Finalize() 时,对象内存是否被释放? [复制]

    这个问题在这里已经有答案了 据我的理解 finalize 和 GC 是两个不同的方面 GC使用finalize 方法来释放Object内存 我们无法说明 GC 何时发生 即使我们显式调用 System gc 但我们可以在对象上显式调用 Fi
  • 在 PowerShell 中迭代 PSObject 属性

    我有这个PSObject 来自 XML bool IsActive ShowOnB2C ShowOnB2B IsWebNews str id ProductId GroupName Unit int ProductIdNumeric Pri
  • 无对话发送 Facebook 应用请求

    由于可以使用 FB api Id feed 在没有请求对话框的情况下在用户墙上发布内容 是否可以通过 FB api 向用户发送应用请求 而不是 FB ui apprequests 谢谢您的回答 我真的需要帮助 我已经四处寻找了几个星期 您可
  • SVG CSS 悬停样式

    尝试使用 CSS 对该多色 HTML 图像的 SVG 进行样式化 以便 5 的右侧在悬停时为白色 body background color gray svg height 50vh fill white html5 g st2 st0 f
  • 在 OpenLayers (KML) 中刷新/重绘图层网络链接自动刷新

    TLDR我想刷新计时器上的图层 以便它绘制新的 kml 数据 如更新链接 网络链接 到目前为止 我已经尝试过操作功能如下 function RefreshKMLData layer layer loaded false layer setV
  • 如何通过事务以多模型形式显示错误消息?

    组织和用户这两个模型具有一对多关系 我有一个组合注册表单 其中一个组织加上该组织的用户进行了注册 我遇到的问题是 当为用户提交无效信息时 它会再次呈现表单 但不会显示用户的错误消息 例如 用户名不能为空 当提交有效信息时 该表单确实有效 并
  • 如何使用反向代理来绕过 X-Frame-Options: SAMEORIGIN for iframe

    我正在努力解决某些页面上的 X Frame Options SAMEORIGIN 限制 以便我可以将它们放入 iframe 中 我知道可以使用反向代理服务器来解决这个问题 但我不确定如何做 我需要的是为一些大厅监视器创建一个触摸屏界面 这些
  • Apache Ant 与 Graal VM

    我们将 Apache Ant 与 Nashorn JavaScript Engine 结合使用 该引擎在 jdk 15 及更高版本中已弃用并删除 我试图找到如何从 Nashorn 切换到 Graal VM 但即使在 Apache 网站上也没
  • WebView方向改变问题

    我有一个下面的布局 其中有一个以重力为中心的线性布局 以使子项居中对齐 我想以编程方式添加一个 webview 并在其中加载 youtube 视频 问题是 webview 的高度和宽度是wrap content wrap content 因
  • docker CMD 中的命令替换

    Using CMD pipenv venv bin python3 main py root uploads 导致错误docker run Error response from daemon invalid header field va
  • Laravel 5.1 中的表单验证异常没有被异常捕获?

    在 laravel5 中 我捕获了所有错误app Exceptions Handler render功能并且工作正常 下面给出的代码 public function render request Exception e error resp
  • 使用 Python 将 PDF 转换为图像 [重复]

    这个问题在这里已经有答案了 我正在尝试在我安装的 ubuntu 服务器中将 pdf 文件转换为图像文件 蟒蛇2 7 poppler 工具 pdf2image 1 12 1 My code from pdf2image import conv
  • Java 易失性关键字

    我知道有很多关于 volatile 的问题 但我只是从这个讨论中感到困惑 Java 挥发性如何保证这段代码中 数据 的可见性 我读过的每个网站都说变量可以存储在缓存中 使该值对其他线程不可见 我什至找到了这个例子https dzone co
  • 在 GCC/CLang 自动矢量化中强制对齐加载/存储的对齐属性

    众所周知 GCC CLang 使用 SIMD 指令可以很好地自动向量化循环 还已知存在对齐 标准 C 属性 除其他用途外还允许对齐堆栈变量 例如以下代码 在线尝试一下 include