O ile mi wiadomo, aliasing odniesień / wskaźników może utrudniać kompilatorowi generowanie zoptymalizowanego kodu, ponieważ muszą one zapewnić, że wygenerowany plik binarny zachowuje się poprawnie w przypadku, gdy dwa odniesienia / wskaźniki faktycznie są aliasami. Na przykład w poniższym kodzie C
void adds(int *a, int *b) {
*a += *b;
*a += *b;
}
po skompilowaniu clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)z -O3flagą, 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 z powrotem do (%rdi)dwukrotności w przypadku int *ai int *baliasu.
Gdy wyraźnie informujemy kompilator, że te dwa wskaźniki nie mogą aliasu ze restrictsłowem kluczowym:
void adds(int * restrict a, int * restrict b) {
*a += *b;
*a += *b;
}
Następnie Clang wyemituje 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 niebezpiecznego kodu), że dwa zmienne odwołania nie mogą być aliasami, pomyślałem, że kompilator powinien być w stanie wyemitować bardziej zoptymalizowaną wersję kodu.
Kiedy testuję poniższy kod i kompiluję go za rustc 1.35.0pomocą -C opt-level=3 --emit obj,
#![crate_type = "staticlib"]
#[no_mangle]
fn adds(a: &mut i32, b: &mut i32) {
*a += *b;
*a += *b;
}
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
Nie korzysta to z gwarancji ai bnie może być alias.
Czy to dlatego, że obecny kompilator Rust jest wciąż w fazie rozwoju i nie wprowadził jeszcze analizy aliasów w celu optymalizacji?
Czy to dlatego, że jest jeszcze szansa, że ai bmoże alias, nawet w bezpiecznym Rust?
unsafekodzie aliasing zmiennych zmiennych nie jest dozwolony i powoduje niezdefiniowane zachowanie. Możesz mieć aliasing surowych wskaźników, ale unsafekod w rzeczywistości nie pozwala zignorować standardowych reguł Rust. To tylko powszechne nieporozumienie i dlatego warto na nie zwrócić uwagę.
+=operacje w ciele addsmożna interpretować jako *a = *a + *b + *b. Jeśli wskaźniki nie alias, mogą one, można nawet zobaczyć, co wynosi b* + *bw drugim asm ogłoszenia: 2: 01 c0 add %eax,%eax. Ale jeśli robią alias, nie mogą, ponieważ do czasu dodania *bpo raz drugi, będzie on zawierał inną wartość niż za pierwszym razem (ten, który przechowujesz w wierszu 4:pierwszego wykazu asm).