Search code examples
c++ccompiler-constructioninteger-overflow

(A + B + C) ≠ (A + C + B​) and compiler reordering


Adding two 32-bit integers can result an integer overflow:

uint64_t u64_z = u32_x + u32_y;

This overflow can be avoided if one of the 32-bit integers is first casted or added to a 64-bit integer.

uint64_t u64_z = u32_x + u64_a + u32_y;

However, if the compiler decides to reorder the addition:

uint64_t u64_z = u32_x + u32_y + u64_a;

the integer overflow might still happen.

Are compilers allowed to do such a reordering or can we trust them to notice the result inconsistency and keep the expression order as is?


Solution

  • If the optimiser does such a reordering it is still bound to the C specification, so such a reordering would become:

    uint64_t u64_z = (uint64_t)u32_x + (uint64_t)u32_y + u64_a;
    

    Rationale:

    We start with

    uint64_t u64_z = u32_x + u64_a + u32_y;
    

    Addition is performed left-to-right.

    The integer promotion rules state that in the first addition in the original expression, u32_x be promoted to uint64_t. In the second addition, u32_y will also be promoted to uint64_t.

    So, in order to be compliant with the C specification, any optimiser must promote u32_x and u32_y to 64 bit unsigned values. This is equivalent to adding a cast. (The actual optimising is not done at the C level, but I use C notation because that is a notation that we understand.)