Optimizing away a “while(1);” in C++0x

前端 未结 8 1149
生来不讨喜
生来不讨喜 2020-11-22 10:37

Updated, see below!

I have heard and read that C++0x allows an compiler to print \"Hello\" for the following snippet

#include 

        
相关标签:
8条回答
  • 2020-11-22 11:12

    Does someone have a good explanation of why this was necessary to allow?

    Yes, Hans Boehm provides a rationale for this in N1528: Why undefined behavior for infinite loops?, although this is WG14 document the rationale applies to C++ as well and the document refers to both WG14 and WG21:

    As N1509 correctly points out, the current draft essentially gives undefined behavior to infinite loops in 6.8.5p6. A major issue for doing so is that it allows code to move across a potentially non-terminating loop. For example, assume we have the following loops, where count and count2 are global variables (or have had their address taken), and p is a local variable, whose address has not been taken:

    for (p = q; p != 0; p = p -> next) {
        ++count;
    }
    for (p = q; p != 0; p = p -> next) {
        ++count2;
    }
    

    Could these two loops be merged and replaced by the following loop?

    for (p = q; p != 0; p = p -> next) {
            ++count;
            ++count2;
    }
    

    Without the special dispensation in 6.8.5p6 for infinite loops, this would be disallowed: If the first loop doesn't terminate because q points to a circular list, the original never writes to count2. Thus it could be run in parallel with another thread that accesses or updates count2. This is no longer safe with the transformed version which does access count2 in spite of the infinite loop. Thus the transformation potentially introduces a data race.

    In cases like this, it is very unlikely that a compiler would be able to prove loop termination; it would have to understand that q points to an acyclic list, which I believe is beyond the ability of most mainstream compilers, and often impossible without whole program information.

    The restrictions imposed by non-terminating loops are a restriction on the optimization of terminating loops for which the compiler cannot prove termination, as well as on the optimization of actually non-terminating loops. The former are much more common than the latter, and often more interesting to optimize.

    There are clearly also for-loops with an integer loop variable in which it would be difficult for a compiler to prove termination, and it would thus be difficult for the compiler to restructure loops without 6.8.5p6. Even something like

    for (i = 1; i != 15; i += 2)
    

    or

    for (i = 1; i <= 10; i += j)
    

    seems nontrivial to handle. (In the former case, some basic number theory is required to prove termination, in the latter case, we need to know something about the possible values of j to do so. Wrap-around for unsigned integers may complicate some of this reasoning further.)

    This issue seems to apply to almost all loop restructuring transformations, including compiler parallelization and cache-optimization transformations, both of which are likely to gain in importance, and are already often important for numerical code. This appears likely to turn into a substantial cost for the benefit of being able to write infinite loops in the most natural way possible, especially since most of us rarely write intentionally infinite loops.

    The one major difference with C is that C11 provides an exception for controlling expressions that are constant expressions which differs from C++ and makes your specific example well-defined in C11.

    0 讨论(0)
  • 2020-11-22 11:16

    I think this is along the lines of the this type of question, which references another thread. Optimization can occasionally remove empty loops.

    0 讨论(0)
提交回复
热议问题