J'ai revendiqué à un collègue qui if (i < input.size() - 1) print(0);
serait optimisé dans cette boucle afin que ce input.size()
ne soit pas lu à chaque itération, mais il s'avère que ce n'est pas le cas!
void print(int x) {
std::cout << x << std::endl;
}
void print_list(const std::vector<int>& input) {
int i = 0;
for (size_t i = 0; i < input.size(); i++) {
print(input[i]);
if (i < input.size() - 1) print(0);
}
}
Selon l' explorateur du compilateur avec les options gcc, -O3 -fno-exceptions
nous lisons actuellement input.size()
chaque itération et utilisons lea
pour effectuer une soustraction!
movq 0(%rbp), %rdx
movq 8(%rbp), %rax
subq %rdx, %rax
sarq $2, %rax
leaq -1(%rax), %rcx
cmpq %rbx, %rcx
ja .L35
addq $1, %rbx
Fait intéressant, dans Rust, cette optimisation se produit. Il semble que i
soit remplacé par une variable j
qui est décrémentée à chaque itération, et le test i < input.size() - 1
est remplacé par quelque chose comme j > 0
.
fn print(x: i32) {
println!("{}", x);
}
pub fn print_list(xs: &Vec<i32>) {
for (i, x) in xs.iter().enumerate() {
print(*x);
if i < xs.len() - 1 {
print(0);
}
}
}
Dans l' explorateur du compilateur, l'assembly correspondant ressemble à ceci:
cmpq %r12, %rbx
jae .LBB0_4
J'ai vérifié et je suis sûr que r12
c'est xs.len() - 1
et rbx
c'est le comptoir. Plus tôt, il y a un add
pour rbx
et un mov
extérieur dans la boucle r12
.
Pourquoi est-ce? Il semble que si GCC est en mesure d'aligner le size()
et operator[]
comme il l'a fait, il devrait pouvoir savoir que size()
cela ne change pas. Mais peut-être que l'optimiseur de GCC juge qu'il ne vaut pas la peine de le retirer dans une variable? Ou peut-être y a-t-il un autre effet secondaire possible qui rendrait cela dangereux - quelqu'un le sait-il?
cout.operator<<()
. Le compilateur ne sait pas que cette fonction de boîte noire n'obtient pas de référence à std::vector
partir d'un global.
println
ou operator<<
est la clé.
println
probablement une méthode complexe, le compilateur peut avoir du mal à prouver queprintln
cela ne mute pas le vecteur.