[rust] 두 개의 가변 참조가 별칭을 지정할 수 없다고 가정 할 때 Rust 컴파일러가 코드를 최적화하지 않는 이유는 무엇입니까?

내가 아는 한, 참조 / 포인터 앨리어싱은 컴파일러가 최적화 된 코드를 생성하는 능력을 방해 할 수 있는데, 두 참조 / 포인터가 실제로 앨리어스 인 경우 생성 된 바이너리가 올바르게 동작해야하기 때문입니다. 예를 들어 다음 C 코드에서

void adds(int  *a, int *b) {
    *a += *b;
    *a += *b;
}

로 컴파일 할 때 clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)-O3플래그, 그것은 방출

0000000000000000 <adds>:
   0:    8b 07                    mov    (%rdi),%eax
   2:    03 06                    add    (%rsi),%eax
   4:    89 07                    mov    %eax,(%rdi)  # The first time
   6:    03 06                    add    (%rsi),%eax
   8:    89 07                    mov    %eax,(%rdi)  # The second time
   a:    c3                       retq

여기서 코드는 (%rdi)대소 문자 int *aint *b별칭 을 위해 두 번 다시 저장됩니다 .

컴파일러에게이 두 포인터가 restrict키워드 와 별명을 지정할 수 없다고 명시 적으로 말할 때 :

void adds(int * restrict a, int * restrict b) {
    *a += *b;
    *a += *b;
}

그러면 Clang은보다 최적화 된 이진 코드 버전을 내 보냅니다.

0000000000000000 <adds>:
   0:    8b 06                    mov    (%rsi),%eax
   2:    01 c0                    add    %eax,%eax
   4:    01 07                    add    %eax,(%rdi)
   6:    c3                       retq

Rust는 (안전하지 않은 코드를 제외하고) 두 개의 변경 가능한 참조가 별칭을 사용할 수 없음을 확인하므로 컴파일러는 더 최적화 된 코드 버전을 생성 할 수 있어야한다고 생각합니다.

나는 아래의 코드와 테스트로 컴파일 할 때 rustc 1.35.0-C opt-level=3 --emit obj,

#![crate_type = "staticlib"]
#[no_mangle]
fn adds(a: &mut i32, b: &mut i32) {
    *a += *b;
    *a += *b;
}

그것은 생성합니다 :

0000000000000000 <adds>:
   0:    8b 07                    mov    (%rdi),%eax
   2:    03 06                    add    (%rsi),%eax
   4:    89 07                    mov    %eax,(%rdi)
   6:    03 06                    add    (%rsi),%eax
   8:    89 07                    mov    %eax,(%rdi)
   a:    c3                       retq

이 보증 그 이용하지 않습니다 ab수없는 별명입니다.

현재 Rust 컴파일러가 아직 개발 중이며 최적화를 위해 별칭 분석을 아직 통합하지 않았기 때문입니까?

이 기회는 여전히 존재하기 때문에 그게 ab수도 안전 녹 별명?



답변

녹는 원래 LLVM의 수 noalias속성 만이 발생 잘못 컴파일 코드를 . 지원되는 모든 LLVM 버전이 더 이상 코드를 잘못 컴파일하지 않으면 다시 활성화 됩니다.

-Zmutable-noalias=yes컴파일러 옵션에 추가 하면 예상 어셈블리가 나타납니다.

adds:
        mov     eax, dword ptr [rsi]
        add     eax, eax
        add     dword ptr [rdi], eax
        ret

간단히 말해서, Rust는 C의 restrict키워드 와 동등한 것을 어디에나 넣었으며 , 일반적인 C 프로그램보다 훨씬 널리 퍼졌습니다. 이로 인해 LLVM의 코너 케이스가 올바르게 처리 할 수있는 것보다 더 많이 실행되었습니다. C 및 C ++ 프로그래머 는 Rust에서 사용하는 것만 restrict큼 자주 사용하지 않는 것으로 나타 &mut났습니다.

이것은 여러 번 일어났다 .

  • Rust 1.0 ~ 1.7 — noalias사용
  • 녹 1.8 ~ 1.27 — noalias비활성화
  • 녹 1.28 ~ 1.29 — noalias활성화
  • 녹 1.30부터 ??? —noalias 비활성화

녹 관련 문제


답변