This is the mail archive of the
gcc-help@gcc.gnu.org
mailing list for the GCC project.
Question on signed overflow
- From: Georg Lay <avr at gjlay dot de>
- To: gcc-help at gcc dot gnu dot org
- Date: Fri, 18 Jun 2010 09:56:25 +0200
- Subject: Question on signed overflow
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