gcc - 为 GCC 的矢量扩展加载数据

标签 gcc checksum vectorization simd

GCC vector extensions提供一种不错的、合理的可移植方式来访问不同硬件架构上的一些 SIMD 指令,而无需求助于 hardware specific intrinsics (或自动矢量化)。

一个真正的用例是计算一个简单的附加校验和。尚不清楚的一件事是如何安全地将数据加载到向量中。

typedef char v16qi __attribute__ ((vector_size(16)));

static uint8_t checksum(uint8_t *buf, size_t size)
{
    assert(size%16 == 0);
    uint8_t sum = 0;

    vec16qi vec = {0};
    for (size_t i=0; i<(size/16); i++)
    {
        // XXX: Yuck! Is there a better way?
        vec += *((v16qi*) buf+i*16);
    }

    // Sum up the vector
    sum = vec[0] + vec[1] + vec[2] + vec[3] + vec[4] + vec[5] + vec[6] + vec[7] + vec[8] + vec[9] + vec[10] + vec[11] + vec[12] + vec[13] + vec[14] + vec[15];

    return sum;
}

将指针转换到向量类型似乎有效,但我担心如果 SIMD 硬件期望向量类型正确对齐,这可能会以一种可怕的方式爆炸。

我想到的唯一其他选择是使用临时向量并显式加载值(通过 memcpy 或按元素分配),但在测试此抵消时,大部分加速都使用了 SIMD 指令。理想情况下,我认为这将类似于通用 __builtin_load()功能,但似乎不存在。

将数据加载到向量中可能会出现对齐问题的更安全方法是什么?

最佳答案

编辑 (感谢 Peter Cordes)您可以转换指针:

typedef char v16qi __attribute__ ((vector_size (16), aligned (16)));

v16qi vec = *(v16qi*)&buf[i]; // load
*(v16qi*)(buf + i) = vec; // store whole vector

这编译为 vmovdqa加载和 vmovups储藏。如果不知道数据是否对齐,请设置 aligned (1)生成 vmovdqu . ( godbolt )

请注意,还有几个用于加载和卸载这些寄存器的专用内置函数( Edit 2 ):
v16qi vec = _mm_loadu_si128((__m128i*)&buf[i]); // _mm_load_si128 for aligned
_mm_storeu_si128((__m128i*)&buf[i]), vec); // _mm_store_si128 for aligned

好像有必要用-flax-vector-conversions出发地 char转至 v16qi有了这个功能。

另见:C - How to access elements of vector using GCC SSE vector extension
另见:SSE loading ints into __m128

(提示:谷歌最好的短语是“gcc loading __m128i”。)

关于gcc - 为 GCC 的矢量扩展加载数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9318115/

相关文章:

matlab - 使用 bsxfun 批处理外部产品

gcc - 如何在cgo中使用Xlinker?格式错误的#cgo 参数 : -(

c++ - gcc优化标志-O3使代码慢于-O2

matlab - 在MatLab中将矩阵的列与3d矩阵的2d矩阵切片相乘

wifi - 如何计算IEEE 802.11 CRC-32 FCS?

python - 基于python中的文件内容创建唯一键

r - 如何检查短语列表中的任何单词是否包含在 R 列表中?

c - 使用 GCC 链接器强制执行 32 位枚举

linux - 在 Linux 上使用 gcc 进行增量链接。可能吗?

vb.net - 我怎样才能简化和优化这个校验和代码?