Saya mengklaim rekan kerja yang if (i < input.size() - 1) print(0);
akan dioptimalkan dalam lingkaran ini sehingga input.size()
tidak dibaca di setiap iterasi, tetapi ternyata ini bukan masalahnya!
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);
}
}
Menurut Compiler Explorer dengan opsi gcc, -O3 -fno-exceptions
kami sebenarnya membaca input.size()
setiap iterasi dan menggunakan lea
untuk melakukan pengurangan!
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
Menariknya, di Rust optimasi ini memang terjadi. Sepertinya i
akan diganti dengan variabel j
yang dikurangi setiap iterasi, dan tes i < input.size() - 1
diganti dengan sesuatu seperti 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);
}
}
}
Di Penjelajah Kompiler , rakitan yang relevan terlihat seperti ini:
cmpq %r12, %rbx
jae .LBB0_4
Aku memeriksa dan saya cukup yakin r12
adalah xs.len() - 1
dan rbx
adalah meja. Sebelumnya ada add
for rbx
dan di mov
luar loop ke r12
.
Kenapa ini? Sepertinya jika GCC mampu menyejajarkan size()
dan operator[]
seperti yang terjadi, itu harus bisa tahu bahwa size()
tidak berubah. Tapi mungkin pengoptimal GCC menilai bahwa tidak layak menariknya ke dalam variabel? Atau mungkin ada beberapa efek samping lain yang mungkin membuat ini tidak aman - adakah yang tahu?
cout.operator<<()
. Kompiler tidak tahu bahwa fungsi kotak hitam ini tidak mendapatkan referensi ke std::vector
dari global.
println
atau operator<<
kuncinya.
println
mungkin metode yang kompleks, compiler mungkin mengalami kesulitan pembuktian bahwaprintln
tidak bermutasi vektor.