有没有一种方法可以让Rust将指针视为非别名,这样它就可以将它们标记为LLVM'的“noalias”;什么是优化器?
下面是指针别名的示例:有没有一种方法可以让Rust将指针视为非别名,这样它就可以将它们标记为LLVM'的“noalias”;什么是优化器?,rust,llvm-codegen,Rust,Llvm Codegen,下面是指针别名的示例: pub unsafe fn f(a: *mut i32, b: *mut i32, x: *const i32) { *a = *x; *b = *x; } 编译成以下程序集(使用-C opt level=s): 请注意,x被取消引用了两次。LLVM没有将其视为noalias。我的第一个想法是避免在赋值中使用指针,而是使用安全引用(因为这些引用是“”)来提示优化器: pub fn g(a: *mut i32, b: *mut i32, x: *const i32
pub unsafe fn f(a: *mut i32, b: *mut i32, x: *const i32) {
*a = *x;
*b = *x;
}
编译成以下程序集(使用-C opt level=s
):
请注意,x
被取消引用了两次。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;
}
但遗憾的是,这产生了完全相同的结果safe_x
仍被取消引用两次
我知道这个示例代码很愚蠢。参数可以很容易地更改为
&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
有趣的是,如果我使用
&muti32、&muti32、&i32
作为原型,那么noalias
属性将被附加在x
上。我似乎记得,noalias
没有主动传递给LLVM,因为有人担心需要首先澄清unsafe
语义,然后应用优化,以免LLVM“破坏”代码。可能相关:作为记录,我在这里报告了缺少优化。@MatthieuM.:你可能在想什么?事实上,由于LLVM中的一个bug(最近已经修复),一些引用没有标记为noalias
,但不是全部。有些仍然可以标记为noalias
。不需要函数/闭包。这并没有真正说明如何将指针视为非别名,只是说明如何将指针转换为引用。@Shepmaster这不是真的-比较程序集。在您的示例中,safe_x
被加载了两次,这表明引用不被视为无别名。结束是必要的。嗯,我明白你的意思。根据定义,这似乎是一个bug(限制?),引用不应该是别名。寻找一个问题,我发现!是的,对不起,我应该在我的OP中更明确地说明这一点(这就是我所说的“参数可以很容易地更改为&i32
/&mut i32
”等等)。目前,据我所知,noalias
仅适用于引用函数参数。不过,我想这是一个完全正确的答案。
example::f:
movl (%rdx), %eax
movl %eax, (%rdi)
movl %eax, (%rsi)
retq