Phiên bản đầu tiên thực hiện tối ưu hóa bằng cách di chuyển một giá trị từ bộ nhớ sang biến cục bộ. Phiên bản thứ hai thì không.Tại sao trình biên dịch ghi biến thành viên vào bộ nhớ cho mỗi lần lặp của vòng lặp này?
Tôi đã mong đợi trình biên dịch có thể chọn thực hiện tối ưu hóa localValue ở đây và không đọc và ghi giá trị từ bộ nhớ cho mỗi lần lặp của vòng lặp. Tại sao không?
class Example
{
public:
void processSamples(float * x, int num)
{
float localValue = v1;
for (int i = 0; i < num; ++i)
{
x[i] = x[i] + localValue;
localValue = 0.5 * x[i];
}
v1 = localValue;
}
void processSamples2(float * x, int num)
{
for (int i = 0; i < num; ++i)
{
x[i] = x[i] + v1;
v1 = 0.5 * x[i];
}
}
float v1;
};
processSamples lắp ráp mã như thế này:
.L4:
addss xmm0, DWORD PTR [rax]
movss DWORD PTR [rax], xmm0
mulss xmm0, xmm1
add rax, 4
cmp rax, rcx
jne .L4
processSamples2 này:
.L5:
movss xmm0, DWORD PTR [rax]
addss xmm0, DWORD PTR example[rip]
movss DWORD PTR [rax], xmm0
mulss xmm0, xmm1
movss DWORD PTR example[rip], xmm0
add rax, 4
cmp rax, rdx
jne .L5
Như trình biên dịch không phải lo lắng về chủ đề (v1 không phải là nguyên tử) . Nó không thể chỉ giả định không có gì khác sẽ được nhìn vào giá trị này và đi trước và giữ nó trong một đăng ký trong khi vòng lặp được quay?
Xem https://godbolt.org/g/RiF3B4 để lắp ráp đầy đủ và lựa chọn trình biên dịch để lựa chọn!
Ví dụ bạn đã liên kết gặp sự cố thêm. 'v1' được uninitialised khi lần đầu tiên được sử dụng. Đây là UB và sẽ gây gcc và clang để làm những điều kỳ quặc tại thời gian tối ưu hóa. –
Ồ vâng - điểm công bằng - đó không phải là mã thực mặc dù tôi chỉ muốn hiển thị vấn đề tôi quan tâm và điểm bắt đầu cho v1 không thực sự quan trọng. Mã thực tế là một chút tinh tế hơn. – JCx
đọc thú vị và thận trọng: https://blog.regehr.org/archives/759 –