내가 아는 한, 참조 / 포인터 앨리어싱은 컴파일러가 최적화 된 코드를 생성하는 능력을 방해 할 수 있는데, 두 참조 / 포인터가 실제로 앨리어스 인 경우 생성 된 바이너리가 올바르게 동작해야하기 때문입니다. 예를 들어 다음 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 *a
와 int *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
이 보증 그 이용하지 않습니다 a
및 b
수없는 별명입니다.
현재 Rust 컴파일러가 아직 개발 중이며 최적화를 위해 별칭 분석을 아직 통합하지 않았기 때문입니까?
이 기회는 여전히 존재하기 때문에 그게 a
및 b
수도 안전 녹 별명?
답변
녹는 원래 한 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
비활성화
녹 관련 문제
-
현재 사례
-
이전 사례
-
다른