Per quanto ne so, l'aliasing di riferimento / puntatore può ostacolare la capacità del compilatore di generare codice ottimizzato, dal momento che devono assicurarsi che il binario generato si comporti correttamente nel caso in cui i due riferimenti / puntatori siano effettivamente alias. Ad esempio, nel seguente codice C,
void adds(int *a, int *b) {
*a += *b;
*a += *b;
}
quando compilato da clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
con la -O3
bandiera, emette
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
Qui il codice viene archiviato (%rdi)
due volte nel caso int *a
e int *b
alias.
Quando diciamo esplicitamente al compilatore che questi due puntatori non possono alias con la restrict
parola chiave:
void adds(int * restrict a, int * restrict b) {
*a += *b;
*a += *b;
}
Quindi Clang emetterà una versione più ottimizzata del codice binario:
0000000000000000 <adds>:
0: 8b 06 mov (%rsi),%eax
2: 01 c0 add %eax,%eax
4: 01 07 add %eax,(%rdi)
6: c3 retq
Dal momento che Rust si assicura (tranne che nel codice non sicuro) che due riferimenti mutabili non possono essere alias, penso che il compilatore dovrebbe essere in grado di emettere la versione più ottimizzata del codice.
Quando eseguo il test con il codice seguente e lo compilo con rustc 1.35.0
con -C opt-level=3 --emit obj
,
#![crate_type = "staticlib"]
#[no_mangle]
fn adds(a: &mut i32, b: &mut i32) {
*a += *b;
*a += *b;
}
genera:
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
Questo non sfrutta la garanzia che a
e b
non può alias.
Questo perché l'attuale compilatore Rust è ancora in fase di sviluppo e non ha ancora incorporato l'analisi degli alias per eseguire l'ottimizzazione?
È perché c'è ancora una possibilità che a
e b
alias, anche in Rust sicuro?
unsafe
codice, i riferimenti mutabili alias non sono consentiti e comportano un comportamento indefinito. È possibile avere alias di puntatori unsafe
non elaborati, ma il codice non consente in realtà di ignorare le regole standard di Rust. È solo un malinteso comune e quindi vale la pena sottolineare.
+=
operazioni nel corpo di adds
possano essere reinterpretate come *a = *a + *b + *b
. Se i puntatori non lo fanno alias, si può, si può anche vedere ciò che equivale a b* + *b
nel secondo asm messa in vendita: 2: 01 c0 add %eax,%eax
. Ma se fanno alias, non possono, perché quando aggiungi *b
per la seconda volta, conterrà un valore diverso rispetto alla prima volta (quello che memorizzi sulla riga 4:
del primo elenco asm).