uint32_t * uint32_t = uint64_t与gcc的向量乘法

时间:2019-11-13 13:09:18

标签: c gcc vectorization avx2 gcc9

我正在尝试将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理解问题并从单个源代码中产生正确的解决方案。

1 个答案:

答案 0 :(得分:2)

如chtz的注释中所述,mul1和mul2都通过clang进行了优化。与mul3类似的代码也将使用for循环进行优化(但效果也不理想)。

所以对我来说,表达代码应做的语法似乎是正确的,到目前为止,gcc根本没有明智的方法来优化此功能。