Dlaczego kompilator Rusta nie optymalizuje kodu przy założeniu, że dwa zmienne odniesienia nie mogą być aliasem?
Z tego, co wiem, aliasing referencji/wskaźników może utrudnić kompilatorowi generowanie zoptymalizowanego kodu, ponieważ musi zapewnić, że wygenerowany plik binarny zachowuje się poprawnie w przypadku, gdy dwa referencje/wskaźniki rzeczywiście alias. Na przykład w następującym kodzie C
void adds(int *a, int *b) {
*a += *b;
*a += *b;
}
Po skompilowaniu przez clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
z flagą -O3
, emituje
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
Tutaj Kod przechowuje się z powrotem do (%rdi)
dwa razy w przypadku int *a
i int *b
aliasu.
Kiedy wyraźnie powiemy kompilator, którego te dwa wskaźniki nie mogą nazwać słowem kluczowym restrict
:
void adds(int * restrict a, int * restrict b) {
*a += *b;
*a += *b;
}
Wtedy Clang będzie emitował bardziej zoptymalizowaną wersję kodu binarnego:
0000000000000000 <adds>:
0: 8b 06 mov (%rsi),%eax
2: 01 c0 add %eax,%eax
4: 01 07 add %eax,(%rdi)
6: c3 retq
Ponieważ Rust upewnia się (z wyjątkiem kodu unsafe), że dwa zmienne odniesienia nie mogą być aliasem, myślę, że kompilator powinien być w stanie emitować bardziej zoptymalizowaną wersję kodu.
Kiedy testuję z poniższym kodem i kompiluję go z rustc 1.35.0
z -C opt-level=3 --emit obj
,
#![crate_type = "staticlib"]
#[no_mangle]
fn adds(a: &mut i32, b: &mut i32) {
*a += *b;
*a += *b;
}
It generuje:
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
To nie korzysta z gwarancji, że a
i b
nie mogą być używane.
Czy to dlatego, że obecny kompilator Rusta jest nadal w fazie rozwoju i nie włączył jeszcze analizy aliasów do optymalizacji?
Czy to dlatego, że jest jeszcze szansa, że a
i b
mogą się nazywać, nawet w safe Rust?
1 answers
Rust pierwotnie włączył atrybut LLVM noalias
, ale to spowodowało błędną kompilację kodu . Gdy wszystkie obsługiwane wersje LLVM nie będą już źle kompilować kodu, zostanie on ponownie włączony.
Jeśli dodasz -Zmutable-noalias=yes
do opcji kompilatora, otrzymasz oczekiwany skład:
adds:
mov eax, dword ptr [rsi]
add eax, eax
add dword ptr [rdi], eax
ret
Mówiąc najprościej, Rust umieścił odpowiednik słowa kluczowego C restrict
wszędzie , znacznie bardziej rozpowszechniony niż jakikolwiek zwykły program C. To ćwiczyło narożne przypadki LLVM więcej niż to był w stanie obsłużyć poprawnie. Okazuje się, że programiści C i c++ po prostu nie używają restrict
tak często, jak &mut
jest używany w Rust.
To się zdarzyło wiele razy .
- Rust 1.0 do 1.7 -
noalias
włączone - Rust 1.8 do 1.27 -
noalias
wyłączone - Rust 1.28 do 1.29 -
noalias
włączone
Rust 1.30 do ??? -
noalias
wyłączone
Powiązane problemy z rdzą
-
Current case
-
Poprzedni przypadek
-
Inne
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-01 17:28:50