2015-06-10 32 views
10

Hãy xem xét những điều sau đây, chương trình đơn giản (chuyển thể từ this question):Tại sao chương trình này không được tối ưu hóa?

#include <cstdlib> 

int main(int argc, char** argv) { 
    int mul1[10] = { 4, 1, 8, 6, 3, 2, 5, 8, 6, 7 }; // sum = 50 
    int mul2[10] = { 4, 1, 8, 6, 7, 9, 5, 1, 2, 3 }; // sum = 46 

    int x1 = std::atoi(argv[1]); 
    int x2 = std::atoi(argv[2]); 

    int result = 0; 

    // For each element in mul1/mul2, accumulate the product with x1/x2 in result 
    for (int i = 0; i < 10; ++i) { 
     result += x1 * mul1[i] + x2 * mul2[i]; 
    } 

    return result; 
} 

Tôi tin rằng nó có chức năng tương đương với một sau:

#include <cstdlib> 

int main(int argc, char** argv) { 
    int x1 = std::atoi(argv[1]); 
    int x2 = std::atoi(argv[2]); 

    return x1 * 50 + x2 * 46; 
} 

Tuy nhiên clang 3.7.1, gcc 5.3icc 13.0.1 dường như là không thể để thực hiện tối ưu hóa như vậy, ngay cả với -Ofast. (Lưu ý bằng cách làm thế nào lắp ráp được tạo ra là rất khác nhau giữa các trình biên dịch!). Tuy nhiên, khi xóa mul2x2 khỏi phương trình, clang có thể thực hiện tối ưu hóa tương tự, ngay cả với -O2.

Điều gì ngăn cản cả hai trình biên dịch tối ưu hóa chương trình đầu tiên vào chương trình thứ hai?

+6

@buttiful buttefly Trong trường hợp hoạt động chung x1 * mul1 [i] có thể dẫn đến tràn, –

+0

Tôi ngạc nhiên rằng clang có thể tối ưu hóa vòng lặp khi bạn loại bỏ 'x2 * mul2 [i]' khỏi phương trình. Cá nhân tôi cảm thấy rằng người ta không nên mong đợi bất cứ điều gì từ trình tối ưu hóa trình biên dịch; bất cứ điều gì được nhận là tiền thưởng! – iammilind

+6

@vlad tràn là UB, vì vậy có thể được coi là không xảy ra khi tối ưu hóa. – Yakk

Trả lời

4

Biểu thức hoàn chỉnh quá phức tạp ngay cả đối với tiếng lóng. Nếu bạn chia nhỏ, mọi thứ sẽ được tối ưu hóa lại:

int result1 = 0; 
int result2 = 0; 

for (int i = 0; i < 10; ++i) { 
    result1 += x1 * mul1[i]; 
    result2 += x2 * mul2[i]; 
} 

std::cout << (result1 + result2); 
2

Tôi không phải là lập trình viên biên dịch vì vậy điều này chỉ có thể đoán. IMHO, câu trả lời là một phần trong câu trả lời của @ dlask và một phần trong nhận xét rằng clang thực hiện tối ưu hóa khi bạn xóa x2mul2 khỏi biểu thức.

Trình biên dịch có thể tối ưu hóa tất cả những gì có thể. Nhưng tôi cũng nghĩ rằng việc tối ưu hóa các trình biên dịch là các chương trình rất lớn và phức tạp, trong đó các lỗi có thể có hậu quả cao bởi vì chúng ở cơ sở gần như mọi thứ khác (Python phiên dịch mới nhất được viết bằng ... C)

phải là một sự cân bằng giữa hiệu quả của trình tối ưu hóa và độ phức tạp của nó, và tôi nghĩ rằng chương trình ví dụ này vượt quá nó cho gcc, và chỉ xung quanh cho tiếng kêu. Không có gì ngăn cản họ thực hiện tối ưu hóa đó ngoại trừ việc nó quá phức tạp đối với phiên bản hiện tại của những trình biên dịch đó.

+0

+1, nhưng tôi không chắc đó là vấn đề phức tạp. Tối ưu hóa được tạo ra bởi các nhà phát triển trình biên dịch, và như bất kỳ lập trình viên nào khác, họ cũng phải ưu tiên. Các chương trình hiếm khi chứa các con số được mã hóa cứng như trong ví dụ và một lập trình viên phong nha sẽ vẫn tối ưu hóa mã theo cách thủ công. Vì vậy, có trình tối ưu hóa xử lý trường hợp cụ thể này (và một triệu trường hợp đơn giản khác không khớp chính xác với một số mô hình) chỉ là một sự lãng phí tài nguyên. – eran

+1

@eran Tôi sẽ mạnh mẽ không đồng ý với bạn. Đôi khi, tối ưu hóa tay làm giảm khả năng đọc và do đó có thể bảo trì. Khả năng bảo trì thấp gây ra lãng phí tài nguyên lớn hơn nhiều (thời gian). Đó là miền của trình biên dịch để tạo mã kết thúc, vì vậy nó nên cố gắng hết sức, với thông tin có sẵn, để tạo ra kết quả tối ưu. – GreenScape

Các vấn đề liên quan