2012-03-13 30 views
5
long long r = 0; 
long long k = 0; 
for (; k < 9999999999999; k++) 
{ 
    for (long long i = 0; i < 9999999999999; i++) 
    { 
     for (long long j = 0; j < 9999999999999; j++) 
     { 
      r = (r + (i * j) % 100) % 47; 
      if (r != 0) 
      { 
       r++; 
      } 
     } 
    } 
} 

Mã này thực hiện trên i3Core trong 0,000001 giây giây, được kiểm tra với boost::timer::auto_cpu_timer trên i7Core.Tại sao mã với nhiều vòng lặp lồng nhau có thể kết thúc ngay lập tức trên GCC nhưng mất mãi mãi trên VS?

Nhưng với studio hình ảnh 2010 có vẻ như nó chạy trong thời gian vô hạn.

Có gì sai với GCC hoặc VS? GCC có tối ưu hóa quá nhiều không?

+4

là 'r' được từng sử dụng? Nó có thể bị loại bỏ cùng với tất cả các vòng lặp. Xem lắp ráp. Nếu bạn muốn đảm bảo thực thi vòng lặp, hãy in 'r' – Anycorn

+2

Lưu ý, thuật ngữ" siêu tối ưu "thường được sử dụng cho các trình biên dịch tạo ra tất cả các kết hợp có thể có của một cái gì đó và chọn kết hợp hiệu quả nhất. – Lindydancer

+0

quá xấu nó thậm chí không siêu định dạng mã của bạn ;-) – CAFxX

Trả lời

15

Có, GCC đang tối ưu hóa mã đó.

Cụ thể, nó biết rằng bạn không sử dụng kết quả, do đó, nó loại bỏ tất cả.
(Bạn không bao giờ sử dụng biến số r.)

Điều này được gọi là Dead Code Elimination.

Để ngăn trình biên dịch tối ưu hóa nó ra, bạn sẽ cần phải sử dụng kết quả bằng cách nào đó. Thử in r ra ở cuối:

cout << r << endl; 

Tuy nhiên, tôi cảnh báo rằng bạn sẽ cần phải giảm đếm lặp, hoặc nó có thể sẽ không kết thúc trong cuộc đời của bạn.


Tôi vừa thử nghiệm điều này trong VS2010 x64. Nhìn vào lắp ráp, rõ ràng là VS2010 không thể tối ưu hóa toàn bộ vòng lặp.

Nó cho thấy rằng các trình biên dịch khác nhau khác nhau về khả năng tối ưu hóa những thứ khác nhau của chúng.


liên quan và sâu sắc hơn: How does GCC optimize out an unused variable incremented inside a loop?

+3

Visual Studio không thể tối ưu hóa hoàn toàn này thực sự là một chút đáng sợ ... Tôi sẽ thử nghiệm với VS11 Beta và báo cáo lại. – Xeo

+0

Việc gán cho một 'biến động' cũng là một tùy chọn nếu bạn không muốn in bất cứ thứ gì. –

+1

@ edA-qamort-ora-y Điều đó sẽ có tác dụng, mặc dù nó cũng sẽ chặn trình biên dịch thực hiện việc đăng ký mem-to-register - có thể là hiệu suất nuke. – Mysticial

1

Bạn đang chạy hành vi undefined

Mã của bạn đã không xác định hành vi tại i * j trên hầu hết các nền tảng bởi vì:

9999999999999 * 9999999999999 > 2^64 

long long2^64 trên hầu hết các p latforms vì có quá ít phần cứng hỗ trợ cho các số nguyên 128 bit.

Nhờ GCC -O3 để chỉ ra điều này trong cảnh báo: có thể giả sử UB không xảy ra và chạy vòng lặp ít hơn. Xem thêm: Why does this loop produce "warning: iteration 3u invokes undefined behavior" and output more than 4 lines?

Vì vậy, mọi thứ đều có thể xảy ra.

Hãy dịch ngược nó để xem những gì đang thực sự xảy ra

GCC 4.8:

gcc -c -g -std=c99 -O0 a.c 
objudmp -S a.o 

Output:

a.o:  file format elf64-x86-64 


Disassembly of section .text: 

0000000000000000 <main>: 
int main() { 
    0: 55      push %rbp 
    1: 48 89 e5    mov %rsp,%rbp 
    long long r = 0; 
    4: 48 c7 45 e0 00 00 00 movq $0x0,-0x20(%rbp) 
    b: 00 
    long long k = 0; 
    c: 48 c7 45 e8 00 00 00 movq $0x0,-0x18(%rbp) 
    13: 00 
    for (; k < 9999999999999; k++) 
    14: e9 f8 00 00 00   jmpq 111 <main+0x111> 
    { 
     for (long long i = 0; i < 9999999999999; i++) 
    19: 48 c7 45 f0 00 00 00 movq $0x0,-0x10(%rbp) 
    20: 00 
    21: e9 d2 00 00 00   jmpq f8 <main+0xf8> 
     { 
      for (long long j = 0; j < 9999999999999; j++) 
    26: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp) 
    2d: 00 
    2e: e9 ac 00 00 00   jmpq df <main+0xdf> 
      { 
       r = (r + (i * j) % 100) % 47; 
    33: 48 8b 45 f0    mov -0x10(%rbp),%rax 
    37: 48 0f af 45 f8   imul -0x8(%rbp),%rax 
    3c: 48 89 c1    mov %rax,%rcx 
    3f: 48 ba 0b d7 a3 70 3d movabs $0xa3d70a3d70a3d70b,%rdx 
    46: 0a d7 a3 
    49: 48 89 c8    mov %rcx,%rax 
    4c: 48 f7 ea    imul %rdx 
    4f: 48 8d 04 0a    lea (%rdx,%rcx,1),%rax 
    53: 48 c1 f8 06    sar $0x6,%rax 
    57: 48 89 c2    mov %rax,%rdx 
    5a: 48 89 c8    mov %rcx,%rax 
    5d: 48 c1 f8 3f    sar $0x3f,%rax 
    61: 48 29 c2    sub %rax,%rdx 
    64: 48 89 d0    mov %rdx,%rax 
    67: 48 c1 e0 02    shl $0x2,%rax 
    6b: 48 01 d0    add %rdx,%rax 
    6e: 48 8d 14 85 00 00 00 lea 0x0(,%rax,4),%rdx 
    75: 00 
    76: 48 01 d0    add %rdx,%rax 
    79: 48 c1 e0 02    shl $0x2,%rax 
    7d: 48 29 c1    sub %rax,%rcx 
    80: 48 89 ca    mov %rcx,%rdx 
    83: 48 8b 45 e0    mov -0x20(%rbp),%rax 
    87: 48 8d 0c 02    lea (%rdx,%rax,1),%rcx 
    8b: 48 ba 99 5c 41 4c ae movabs $0x572620ae4c415c99,%rdx 
    92: 20 26 57 
    95: 48 89 c8    mov %rcx,%rax 
    98: 48 f7 ea    imul %rdx 
    9b: 48 c1 fa 04    sar $0x4,%rdx 
    9f: 48 89 c8    mov %rcx,%rax 
    a2: 48 c1 f8 3f    sar $0x3f,%rax 
    a6: 48 29 c2    sub %rax,%rdx 
    a9: 48 89 d0    mov %rdx,%rax 
    ac: 48 89 45 e0    mov %rax,-0x20(%rbp) 
    b0: 48 8b 55 e0    mov -0x20(%rbp),%rdx 
    b4: 48 89 d0    mov %rdx,%rax 
    b7: 48 01 c0    add %rax,%rax 
    ba: 48 01 d0    add %rdx,%rax 
    bd: 48 c1 e0 04    shl $0x4,%rax 
    c1: 48 29 d0    sub %rdx,%rax 
    c4: 48 29 c1    sub %rax,%rcx 
    c7: 48 89 c8    mov %rcx,%rax 
    ca: 48 89 45 e0    mov %rax,-0x20(%rbp) 
       if (r != 0) 
    ce: 48 83 7d e0 00   cmpq $0x0,-0x20(%rbp) 
    d3: 74 05     je  da <main+0xda> 
       { 
        r++; 
    d5: 48 83 45 e0 01   addq $0x1,-0x20(%rbp) 
    long long k = 0; 
    for (; k < 9999999999999; k++) 
    { 
     for (long long i = 0; i < 9999999999999; i++) 
     { 
      for (long long j = 0; j < 9999999999999; j++) 
    da: 48 83 45 f8 01   addq $0x1,-0x8(%rbp) 
    df: 48 b8 fe 9f 72 4e 18 movabs $0x9184e729ffe,%rax 
    e6: 09 00 00 
    e9: 48 39 45 f8    cmp %rax,-0x8(%rbp) 
    ed: 0f 8e 40 ff ff ff  jle 33 <main+0x33> 
int main() { 
    long long r = 0; 
    long long k = 0; 
    for (; k < 9999999999999; k++) 
    { 
     for (long long i = 0; i < 9999999999999; i++) 
    f3: 48 83 45 f0 01   addq $0x1,-0x10(%rbp) 
    f8: 48 b8 fe 9f 72 4e 18 movabs $0x9184e729ffe,%rax 
    ff: 09 00 00 
102: 48 39 45 f0    cmp %rax,-0x10(%rbp) 
106: 0f 8e 1a ff ff ff  jle 26 <main+0x26> 
int main() { 
    long long r = 0; 
    long long k = 0; 
    for (; k < 9999999999999; k++) 
10c: 48 83 45 e8 01   addq $0x1,-0x18(%rbp) 
111: 48 b8 fe 9f 72 4e 18 movabs $0x9184e729ffe,%rax 
118: 09 00 00 
11b: 48 39 45 e8    cmp %rax,-0x18(%rbp) 
11f: 0f 8e f4 fe ff ff  jle 19 <main+0x19> 
125: b8 00 00 00 00   mov $0x0,%eax 
        r++; 
       } 
      } 
     } 
    } 
} 
12a: 5d      pop %rbp 
12b: c3      retq 

vì vậy tất cả các vòng dường như hiện tại.

Với -O3:

0000000000000000 <main>: 
    0: 31 c0     xor %eax,%eax 
    2: c3      retq 

vì vậy nó được rõ ràng tối ưu hóa đi. Không có gì trong tiêu chuẩn C ngăn chặn tối ưu hóa đó, vì vậy GCC thực hiện điều đó.

Nếu chúng tôi thêm printf("%lld", r); vào cuối như được đề cập bởi Mystical, nó sẽ mất vĩnh viễn ngay cả với -O3 và mã được tối ưu hóa được tạo gần giống với mã không được tối ưu hóa.

Đối với vòng lặp vô hạn nó được thú vị hơn: Are compilers allowed to eliminate infinite loops?

Làm thế nào để ngăn chặn nếu xảy ra: How to prevent GCC from optimizing out a busy wait loop?

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