Question on signed overflow

Georg Lay avr@gjlay.de
Fri Jun 18 09:20:00 GMT 2010


Hi, I have a question on gcc's signed overflow optimisation in the
following C function:

int abssat2 (int x)
{
    unsigned int y = x;

    if (x < 0)
        y = -y;

    if (y >= 0x80000000)
        y--;

    return y;
}

gcc optimises the second comparison and throws it away, and that's the
part I do not understand because all computations are performed on
unsigned int which has no undefined behaviour on overflow.

For the unary - the standard says in 6.5.3.3.3:
 The result of the unary - operator is the negative of its (promoted)
 operand. The integer promotions are performed on the operand, and
 the result has the promoted type.

And the promotion rules in 6.3.1.1.2:
  If an int can represent all values of the original type, the value
  is converted to an int; otherwise, it is converted to an unsigned int.
  These are called the integer promotions. All other types are unchanged
  by the integer promotions.

As an int cannot represent all values that can be represented by an
unsigned int, there is no signed int in the line y = -y.

Could anyone explain this? I see this on gcc 4.4.3.

The code looks as expected until RTL pass ce1 which replaces the first
comparison by abssi2 insn. The second comparison is optimised by insn
combiner. Why can the combiner do that? It operates on RTL and has no
information on the original types (or has it?), i.e. wether they were
signed or unsigned. STORE_FLAG_VALUE is 1.

With -Wstrict-overflow gcc prints
abs.c: In function 'abssat2':
abs.c:12: warning: assuming signed overflow does not occur when assuming
abs (x) < 0 is false
abs.c:12: warning: assuming signed overflow does not occur when assuming
abs (x) < 0 is false

Line 12 is the closing } of function body.

Just before insn combine, after dce, code looks like this:

(insn# # # 2 abs.c:6 (set (reg/v:SI 39 [ y ])
        (abs:SI (reg/v:SI 39 [ y ])))# {abssi2} (nil))

(insn# # # 2 abs.c:9 (set (reg:SI 43)
        (lt:SI (reg/v:SI 39 [ y ])
            (const_int 0 [0x0])))# {*slt} (nil))

(insn# # # 2 abs.c:9 (set (reg/v:SI 39 [ y ])
        (plus:SI (reg/v:SI 39 [ y ])
            (if_then_else:SI (ne (reg:SI 43)
                    (const_int 0 [0x0]))
                (const_int -1 [0xffffffff])
                (const_int 0 [0x0]))))# {*addsicc.ne}
(expr_list:REG_DEAD (reg:SI 43)
        (nil)))

Thanks



More information about the Gcc-help mailing list