This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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
--


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]