我正在尝试将uint32_t
向量相乘,生成一个uint64_t
向量,使用gcc编译时会出现问题。 我期望的结果是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能够理解问题并从单个源代码生成正确的解决方案。
mul
和mul2
在使用clang进行优化后表现良好:https://godbolt.org/z/d3MAay,但是`mul3`不等效,因为它需要将结果截断为32位。我猜你的选择是:a)使用clang,b)使用内置函数,c)提供一个补丁给gcc以正确地优化它(或者提交一个错误报告并希望有人修复它)。 - chtz_mm256_mul_epu32
пјҢеңЁimmintrin.h
дёӯе®ҡд№үгҖӮ - Peter Cordes