Pour autant que je sache, l'alias de référence / pointeur peut entraver la capacité du compilateur à générer du code optimisé, car ils doivent garantir que le binaire généré se comporte correctement dans le cas où les deux références / pointeurs sont effectivement des alias. Par exemple, dans le code C suivant,
void adds(int *a, int *b) {
*a += *b;
*a += *b;
}
une fois compilé clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
avec le -O3
drapeau, il émet
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
Ici, le code stocke (%rdi)
deux fois au cas où int *a
et int *b
alias.
Lorsque nous disons explicitement au compilateur que ces deux pointeurs ne peuvent pas être alias avec le restrict
mot clé:
void adds(int * restrict a, int * restrict b) {
*a += *b;
*a += *b;
}
Ensuite, Clang émettra une version plus optimisée du code binaire:
0000000000000000 <adds>:
0: 8b 06 mov (%rsi),%eax
2: 01 c0 add %eax,%eax
4: 01 07 add %eax,(%rdi)
6: c3 retq
Étant donné que Rust s'assure (sauf dans le code non sûr) que deux références mutables ne peuvent pas être alias, je pense que le compilateur devrait être capable d'émettre la version la plus optimisée du code.
Lorsque je teste avec le code ci-dessous et que je le compile rustc 1.35.0
avec -C opt-level=3 --emit obj
,
#![crate_type = "staticlib"]
#[no_mangle]
fn adds(a: &mut i32, b: &mut i32) {
*a += *b;
*a += *b;
}
il génère:
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
Cela ne profite pas de la garantie que a
et b
ne peut pas alias.
Est-ce parce que le compilateur Rust actuel est toujours en développement et n'a pas encore intégré d'analyse d'alias pour faire l'optimisation?
Est-ce parce qu'il y a encore une chance a
et b
pourrait alias, même en toute sécurité Rust?
unsafe
code, les références mutables d'alias ne sont pas autorisées et entraînent un comportement indéfini. Vous pouvez avoir des pointeurs bruts d'alias, mais le unsafe
code ne vous permet pas d'ignorer les règles standard de Rust. C'est juste une idée fausse commune et mérite donc d'être soulignée.
+=
opérations dans le corps de adds
peuvent être réinterprétées comme *a = *a + *b + *b
. Si les pointeurs ne font pas alias, ils peuvent, vous pouvez même voir ce qui équivaut à b* + *b
la deuxième liste asm: 2: 01 c0 add %eax,%eax
. Mais s'ils font un alias, ils ne peuvent pas, car au moment où vous ajoutez *b
pour la deuxième fois, il contiendra une valeur différente de la première fois (celle que vous stockez en ligne 4:
de la première liste asm).