繁体   English   中英

uint32_t * uint32_t = uint64_t 向量乘法与 gcc

[英]uint32_t * uint32_t = uint64_t vector multiplication with gcc

我正在尝试将uint32_t的向量相乘以产生完整的 64 位结果,从而生成 gcc 中的uint64_t向量。 我期望的结果是 gcc 发出一条VPMULUDQ指令。 但是,gcc 输出的代码是可怕的,源向量的各个uint32_t混编,然后是完整的 64*64=64 乘法。 这是我尝试过的:

#include <stdint.h>

typedef uint32_t v8lu __attribute__ ((vector_size (32)));
typedef uint64_t v4llu __attribute__ ((vector_size (32)));

v4llu mul(v8lu x, v8lu y) {
    x[1] = 0; x[3] = 0; x[5] = 0; x[7] = 0;
    y[1] = 0; y[3] = 0; y[5] = 0; y[7] = 0;
    return (v4llu)x * (v4llu)y;
}

第一个屏蔽掉uint32_t向量中不需要的部分,希望 gcc 能够优化掉 64*64=64 乘法中不需要的部分,然后看到屏蔽也毫无意义。 没有这样的运气。

v4llu mul2(v8lu x, v8lu y) {
    v4llu tx = {x[0], x[2], x[4], x[6]};
    v4llu ty = {y[0], y[2], y[4], y[6]};
    return tx * ty;
}

在这里,我尝试从头开始创建一个uint64_t向量,其中仅包含使用过的部件集。 同样,gcc 应该看到每个uint64_t的前 32 位为 0,而不是进行完整的 64*64=64 乘法。 相反,会发生大量提取和放回值,并且 64*64=64 相乘。

v4llu mul3(v8lu x, v8lu y) {
    v4llu t = {x[0] * (uint64_t)y[0], x[2] * (uint64_t)y[2], x[4] * (uint64_t)y[4], x[6] * (uint64_t)y[6]};
    return t;
}

让我们通过将部分相乘来构建结果向量。 也许 gcc 认为它可以使用VPMULUDQ来实现这一点。 不走运,它回退到 4 个IMUL操作码。

有没有办法告诉 gcc 我想要它做什么(32 * 32 = 64 乘以完美放置的一切)?

注意:内联汇编或内在不是答案。 手动编写操作码显然有效。 但随后我将不得不为许多目标架构和功能集编写不同版本的代码。 我希望 gcc 能够理解问题并从单个源代码中生成正确的解决方案。

正如 chtz 在评论中所指出的, mul1 和 mul2 都由 clang 进行了优化。 类似于 mul3 但使用 for 循环的代码也将被优化(但不是那么好)。

所以在我看来,表达代码应该做什么的语法是正确的,而 gcc 到目前为止只是缺乏正确优化它的聪明才智。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM