26

以下是指针别名的示例:

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

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

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

4

1 回答 1

3

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

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
于 2018-09-20T16:54:55.193 回答