rust - 有没有办法让 Rust 将指针视为非别名,以便它可以将它们标记为 `noalias` 用于 LLVM 的优化器?

标签 rust llvm-codegen

下面是指针别名的例子:

pub unsafe fn f(a: *mut i32, b: *mut i32, x: *const i32) {
  *a = *x;
  *b = *x;
}

编译成以下程序集(使用 -C opt-level=s):

example::f:
        push    rbp
        mov     rbp, rsp
        mov     eax, dword ptr [rdx]
        mov     dword ptr [rdi], eax
        mov     eax, dword ptr [rdx]
        mov     dword ptr [rsi], eax
        pop     rbp
        ret

请注意 x 被取消引用了两次。 LLVM 不会将其视为 noalias。我的第一个想法是避免在赋值中使用指针,而是使用安全引用(因为那些“follow LLVM’s scoped noalias model”)向优化器提供提示:

pub fn g(a: *mut i32, b: *mut i32, x: *const i32) {
  let safe_a = unsafe { &mut *a };
  let safe_b = unsafe { &mut *b };
  let safe_x = unsafe { &*x };
  *safe_a = *safe_x;
  *safe_b = *safe_x;
}

但是,这会产生完全相同的结果。 safe_x 仍然被取消引用两次。

我知道这个示例代码很笨。参数可以很容易地更改为 &i32/&mut i32,或者我可以只取消引用 x 一次并将其存储在用于分配。这里的代码只是一个 super 简单的别名测试,我对我的问题所问的更广泛的情况感兴趣。

最佳答案

有,将安全引用包装在函数或闭包中:

pub unsafe fn f(a: *mut i32, b: *mut i32, x: *const i32) {
    (|safe_a: &mut i32, safe_b: &mut i32, safe_x: &i32| {
        *safe_a = *safe_x;
        *safe_b = *safe_x;
    })(&mut *a, &mut *b, &*x)
}

这会产生所需的无锯齿行为:

example::f:
        movl    (%rdx), %eax
        movl    %eax, (%rdi)
        movl    %eax, (%rsi)
        retq

关于rust - 有没有办法让 Rust 将指针视为非别名,以便它可以将它们标记为 `noalias` 用于 LLVM 的优化器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41541835/

相关文章:

rust - 为什么Option <T>::and_then()与后面的.unwrap_or()不互斥?

rust - Release模式下安全 Rust 中的有符号整数溢出是否被视为未定义行为?

optimization - 我可以强制 Rust 不优化单个函数吗?

c - 对简单算术序列求和的 Rust 代码应用了哪些优化技术?

performance - 为什么在 Go 中交换 []float64 的元素比在 Rust 中交换 Vec<f64> 的元素更快?

optimization - 在 Rust 中从迭代器填充切片的最佳方法是什么?

string - 类似 str 的迭代器

rust - 在标识位置找到 `once`

asynchronous - 如何优雅地关闭 Tokio 运行时以响应 SIGTERM?