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



以下指针别名示例:

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。我的第一个想法是避免在赋值中使用指针,而是使用安全引用(因为这些引用"遵循LLVM的作用域noalias模型")来向优化器提供提示:

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;
}

但遗憾的是,这产生了完全相同的结果。CCD_ 5仍然被取消引用两次。

我知道这个示例代码很愚蠢。参数可以很容易地更改为&i32/&mut i32,或者我可以只取消引用x一次,并将其存储在用于分配的临时文件中。这里的代码只是一个超级简单的混叠测试,我对我的问题所问的更广泛的问题感兴趣。

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

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

相关内容

  • 没有找到相关文章

最新更新