How do I make an infinite empty loop that won't be optimized away?

前端 未结 13 1454
后悔当初
后悔当初 2020-12-23 13:16

The C11 standard appears to imply that iteration statements with constant controlling expressions should not be optimized out. I\'m taking my advice from this answer, which

13条回答
  •  误落风尘
    2020-12-23 13:44

    I have been convinced this is just a plain old bug. I leave the my tests below and in particular the reference to the discussion in the standard committee for some reasoning I previously had.


    I think this is undefined behavior (see end), and Clang just has one implementation. GCC indeed works as you expect, optimizing out only the unreachable print statement but leaving the loop. Some how Clang is oddly making decisions when combining the in-lining and determining what it can do with the loop.

    The behavior is extra weird - it removes the final print, so "seeing" the infinite loop, but then getting rid of the loop as well.

    It's even worse as far as I can tell. Removing the inline we get:

    die: # @die
    .LBB0_1: # =>This Inner Loop Header: Depth=1
      jmp .LBB0_1
    main: # @main
      push rax
      mov edi, offset .Lstr
      call puts
    .Lstr:
      .asciz "begin"
    

    so the function is created, and the call optimized out. This is even more resilient than expected:

    #include 
    
    void die(int x) {
        while(x);
    }
    
    int main() {
        printf("begin\n");
        die(1);
        printf("unreachable\n");
    }
    

    results in a very non-optimal assembly for the function, but the function call is again optimized out! Even worse:

    void die(x) {
        while(x++);
    }
    
    int main() {
        printf("begin\n");
        die(1);
        printf("unreachable\n");
    }
    

    I made a bunch of other test with adding a local variable and increasing it, passing a pointer, using a goto etc... At this point I would give up. If you must use clang

    static void die() {
        int volatile x = 1;
        while(x);
    }
    

    does the job. It sucks at optimizing (obviously), and leaves in the redundant final printf. At least the program does not halt. Maybe GCC after all?

    Addendum

    Following discussion with David, I yield that the standard does not say "if the condition is constant, you may not assume the loop terminates". As such, and granted under the standard there is no observable behavior (as defined in the standard), I would argue only for consistency - if a compiler is optimizing out a loop because it assume it terminates, it should not optimize out following statements.

    Heck n1528 has these as undefined behavior if I read that right. Specifically

    A major issue for doing so is that it allows code to move across a potentially non-terminating loop

    From here I think it can only devolve into a discussion of what we want (expected?) rather than what is allowed.

提交回复
热议问题