Есть ли способ заставить Rust обрабатывать указатели как сглаживание, поэтому он может обозначать их как "noalias" для оптимизатора LLVM?

Следующий пример сглаживания указателя:

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. Моя первая мысль заключалась в том, чтобы избежать использования указателей в назначениях и вместо этого использовать безопасные ссылки (поскольку те

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 один раз и сохранить его во временном, который используется для назначения. Код здесь просто должен быть супер простым алиасинговым тестом, и меня интересует более широкая картина, которую задает мой вопрос.

Ответы