我正在尝试使 Rust 编译器 ( rustc 1.66.0
) 自动向量化以下函数(不使用任何 unsafe
内在函数),但没有成功:
pub fn get_transforms(s: &mut [i32]) -> u32 {
assert_eq!(s.len(), 4);
let mut transforms = 1;
while s[0] > 0 || s[1] > 0 || s[2] > 0 || s[3] > 0 {
// Calculate deltas
let d0 = s[0] - s[1];
let d1 = s[1] - s[2];
let d2 = s[2] - s[3];
let d3 = s[3] - s[0];
// Assign absolute values
s[0] = d0.abs();
s[1] = d1.abs();
s[2] = d2.abs();
s[3] = d3.abs();
transforms += 1;
}
transforms
}
我的想法是让它执行减法和 abs()
一次(使用 16 字节寄存器)而不是四次。
我读到迭代器可能会有所帮助,但我还没有找到在这里使用它们的简单方法。 编译器标志似乎也没有帮助。
这是我用作引用的编译器资源管理器输出的链接:https://godbolt.org/z/7sqq6bszT
最佳答案
正如 @ChayimFriedman 在评论中指出的,您需要将 -Copt-level=3
添加到命令行。但此外,您需要确保 bool 表达式不会延迟计算,即使用 |
运算符而不是 ||
(需要在比较周围加上括号):
while (s[0] > 0) | (s[1] > 0) | (s[2] > 0) | (s[3] > 0) {
// rest of code unmodified
Compiling this产生以下循环:
.LBB0_13:
vpshufd xmm2, xmm0, 57
vpsubd xmm0, xmm0, xmm2
vpabsd xmm0, xmm0
inc eax
vpcmpgtd xmm2, xmm0, xmm1
vmovmskps ecx, xmm2
test ecx, ecx
jne .LBB0_13
|
而不是 ||
对编译器有帮助的原因是对于像 a || 这样的表达式b
如果 a
已经为 true
,则不应计算 b
表达式 —— 大多数时候,这需要一个分支,具体取决于a
的值。另一方面,对于 a | b
每次都会评估 a
和 b
。当然,应该允许编译器在“as-if”规则下进行任何优化,即,如果计算 b
没有任何副作用(并且编译器可以证明这一点),一个 || b 和 a | b
可以编译为相同的代码。
注意:如果您确定 s[i]
永远不会为负(如果输入非负,这显然是正确的),则可以替换 s[i] > 0
by s[i] != 0
,这将减少 vpcmpgtd
+vmovmskps
+test
到单个 vptest
。
关于rust - 循环的自动向量化,对 4 个 int 元素进行打乱,并取与之前排列的绝对差值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75082436/