Tôi đã tuyên bố với một đồng nghiệp if (i < input.size() - 1) print(0);sẽ được tối ưu hóa trong vòng lặp này để nó input.size()không được đọc trong mỗi lần lặp, nhưng hóa ra đó không phải là trường hợp!
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);
}
}
Theo Compiler Explorer với các tùy chọn gcc, -O3 -fno-exceptionschúng tôi thực sự đang đọc input.size()từng vòng lặp và sử dụng leađể thực hiện phép trừ!
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
Thật thú vị, trong Rust tối ưu hóa này xảy ra. Dường như iđược thay thế bằng một biến jđược giảm dần mỗi lần lặp và thử nghiệm i < input.size() - 1được thay thế bằng một cái gì đó như thế 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);
}
}
}
Trong Compiler Explorer , hội đồng có liên quan trông như thế này:
cmpq %r12, %rbx
jae .LBB0_4
Tôi đã kiểm tra và tôi khá chắc chắn r12là xs.len() - 1và rbxlà quầy. Trước đó có một addfor rbxvà movbên ngoài của vòng lặp vào r12.
Tại sao lại thế này? Có vẻ như nếu GCC có thể nội tuyến size()và operator[]như đã làm, nó sẽ có thể biết rằng điều size()đó không thay đổi. Nhưng có lẽ trình tối ưu hóa của GCC đánh giá rằng không đáng để kéo nó ra thành một biến? Hoặc có thể có một số tác dụng phụ có thể khác sẽ làm cho điều này không an toàn - có ai biết không?
cout.operator<<(). Trình biên dịch không biết rằng hàm hộp đen này không nhận được tham chiếu đến std::vectortừ toàn cầu.
printlnhoặc operator<<là chính.
printlncó thể là một phương thức phức tạp, trình biên dịch có thể gặp khó khăn khi chứng minh rằngprintlnkhông làm biến đổi vectơ.