我正在尝试将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理解问题并从单个源代码中产生正确的解决方案。
答案 0 :(得分:2)
如chtz的注释中所述,mul1和mul2都通过clang进行了优化。与mul3类似的代码也将使用for循环进行优化(但效果也不理想)。
所以对我来说,表达代码应做的语法似乎是正确的,到目前为止,gcc根本没有明智的方法来优化此功能。