2014-12-09 13 views
6

Hãy xem xét các loại giả thuyết sau đây: (. Thuần túy để tăng cường khả năng đọc)Trình biên dịch có tối ưu hóa sự phủ nhận hợp lý kép trong điều kiện không?

typedef struct Stack { 
    unsigned long len; 
    void **elements; 
} Stack; 

Và các macro giả thuyết sau đây để đối phó với các loại Trong các macro tôi am giả định rằng lập luận cho có kiểu (Stack *) thay vì chỉ đơn thuần là Stack (tôi có thể không bị làm phiền để gõ ra một biểu _Generic ở đây.)

#define stackNull(stack) (!stack->len) 
#define stackHasItems(stack) (stack->len) 

Tại sao tôi không chỉ đơn giản là sử dụng !stackNull(x) để kiểm tra nếu một chồng có mục? Tôi nghĩ rằng điều này sẽ hơi kém hiệu quả (đọc: không đáng chú ý ở tất cả thực sự, nhưng tôi nghĩ rằng nó là thú vị) hơn chỉ đơn giản là kiểm tra stack->len bởi vì nó sẽ dẫn đến đôi phủ định. Trong trường hợp sau:

int thingy = !!31337; 
printf("%d\n", thingy); 
if (thingy) 
    doSomethingImportant(thingy); 

Chuỗi "1 \ n" sẽ được in và không thể tối ưu hóa biến điều kiện (thực tế, không thể nếu biến thingy không có bộ khởi tạo không đổi hoặc đã được sửa đổi trước khi thử nghiệm, nhưng chúng tôi sẽ nói trong trường hợp này là 31337 không phải là hằng số) bởi vì (!!x) được đảm bảo là 0 hoặc 1.

Nhưng tôi tự hỏi, nếu trình biên dịch sẽ tối ưu hóa giống như sau

int thingy = wellOkaySoImNotAConstantThingyAnyMore(); 
if (!!thingy) 
    doSomethingFarLessImportant(); 

này sẽ được tối ưu hóa để thực sự chỉ cần sử dụng (thingy) trong câu lệnh if, như thể báo cáo kết quả if đã được viết như

if (thingy) 
    doSomethingFarLessImportant(); 

Nếu có, mở rộng thành (!!!!!thingy), v.v ...? (Tuy nhiên đây là một câu hỏi hơi khác nhau, vì điều này có thể được tối ưu hóa trong mọi trường hợp, !thingy!!!!!thingy không có vấn đề gì, giống như -(-(-(1))) = -1.)

Trong tiêu đề câu hỏi tôi đã nói "biên dịch", bởi tôi có nghĩa là tôi đang hỏi nếu bất kỳ trình biên dịch thực hiện điều này, tuy nhiên tôi đặc biệt quan tâm đến cách GCC sẽ cư xử trong trường hợp này vì nó là trình biên dịch của tôi về sự lựa chọn.

+3

Bất kỳ trình biên dịch nào * không * làm tối ưu hóa tầm thường này tôi sẽ xem xét không thể chấp nhận. –

Trả lời

7

Điều này có vẻ giống như một khá reasonable optimization và một thử nghiệm nhanh bằng godbolt với mã này (see it live):

#include <stdio.h> 

void func(int x) 
{ 
    if(!!x) 
    { 
    printf("first\n") ; 
    } 

    if(!!!x) 
    { 
    printf("second\n") ; 
    } 
} 

int main() 
{ 
    int x = 0 ; 

    scanf("%d", &x) ; 
    func(x) ; 
} 

dường như chỉ ra gcc làm tốt, nó tạo ra như sau:

func: 
    testl %edi, %edi # x 
    jne .L4 #, 
    movl $.LC1, %edi #, 
    jmp puts # 
.L4: 
    movl $.LC0, %edi #, 
    jmp puts # 

chúng ta có thể nhìn thấy từ dòng đầu tiên:

testl %edi, %edi # x 

nó chỉ sử dụng x mà không làm bất kỳ hoạt động trên đó, cũng lưu ý trình tối ưu hóa đủ thông minh để kết hợp cả hai thử nghiệm thành một vì nếu điều kiện đầu tiên là true thì khác phải là false.

Lưu ý rằng tôi đã sử dụng printfscanf để biết các tác dụng phụ để ngăn trình tối ưu hóa tối ưu hóa tất cả mã.

+2

Trong thực tế, ngay cả với '-O0' (tối ưu hóa tắt), bản sao cài đặt gcc-4.8.3 của tôi tạo ra mã giống hệt nhau cho'! X' và '!!! x'. – ArjunShankar

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