有没有一种方法可以让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