rust - 循环的自动向量化,对 4 个 int 元素进行打乱,并取与之前排列的绝对差值

标签 rust simd auto-vectorization

我正在尝试使 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 每次都会评估 ab。当然,应该允许编译器在“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/

相关文章:

rust - 当 U 的 From<T> 可用时,将 Vec<T> 转换为 Vec<U>

mysql - 在 mac OS 中安装 mysqlclient 库

rust - 递归特征函数的生命周期问题

rust - 解包时无法移出共享引用背后的值

c++ - 为什么矢量化在这个 for 循环中没有好处?

c99 - 将限制限定符与 C99 可变长度数组 (VLA) 一起使用

optimization - SSE 是多余的还是不鼓励的?

c - 为什么这个 SIMD 示例代码可以使用 minGW 进行 C 编译,但可执行文件无法在我的 Windows 计算机上运行?

arm - ARM和NEON可以并行工作吗?

c++ - 由于 cout,GCC 4.8.2 自动矢量化失败