This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Fix a type mismatch in fold-const
- From: Roger Sayle <roger at eyesopen dot com>
- To: Andrew Pinski <pinskia at physics dot uc dot edu>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Sun, 24 Apr 2005 10:33:02 -0600 (MDT)
- Subject: Re: [PATCH] Fix a type mismatch in fold-const
On Sun, 24 Apr 2005, Roger Sayle wrote:
> I've made my head hurt going through the other cases, that may
> induce overflow in one type and not in the other. In your example,
> "(long)((unsigned)(a) * 4) - (long)((unsigned)(b) * 4)" we convert
> two unsigned multiplications which have defined semantics on overflow,
> into "(a-b)*4" whose multiplication has undefined semantics on overflow.
Arghh! Spoke to soon.
Consider your example,
(long)((unsigned)(a) * 4) - (long)((unsigned)(b) * 4) -> (a - b) * 4
where a = 0x80000000 and b = 0x40000000
Originally, this would be calculated as:
(long)((unsigned)(a) * 4) - (long)((unsigned)(b) * 4)
(long)(0x80000000u * 4) - (long)(0x40000000u * 4)
(long)0 - (long)0
0
Notice that the overflows in the unsigned multiplications have defined
behaviour and the result must always be zero.
With the transformed expression we have:
(a - b) * 4
(0x80000000 - 0x40000000) * 4
0x40000000 * 4
0
Notice that the result of the subtraction overflows and has undefined
behaviour, and the multiplication overflows and has undefined behaviour.
For example, if we transform
((long)((unsigned)a * 4) - (long)((unsigned)b * 4))/4
first into
((a-b)*4)/4
and then into
a-b
we'll get the wrong result!
Although this is another pre-existing condition and admittedly rare,
I think it's safest to add the following clause for integral types:
...
&& !flag_trapv
&& (flag_wrapv
|| TYPE_UNSIGNED_P (type)
|| (!TYPE_UNSIGNED_P (TREE_TYPE (arg0))
&& !TYPE_UNSIGNED_P (TREE_TYPE (arg1)))
...
Or something similar (we can ignore trapv if all three types are
unsigned).
I'm sorry to be the bearer of bad news, but it looks like this
transformation can't safely be applied to your example code,
when the signedness of the types don't match, unless GCC is
using wrapping semantics, i.e. -flag-wrapv. I doubt the orignal
author of this code ever considered the sinedness changing
effects of STRIP_NOPs on the operands.
Roger
--