fix typing error in compound assignment
commit398201cc7feaee0f3f777920bc76f9a720aad10c
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>
Sat, 10 Dec 2016 22:43:17 +0000 (10 23:43 +0100)
committerChristopher Li <sparse@chrisli.org>
Mon, 13 Feb 2017 01:34:44 +0000 (13 09:34 +0800)
tree0561f5d6d97ae9f0e0bc8de6467485d96fe4ba29
parent62cab21fe13b7f9ac2008eae54bebfd45bb7e75a
fix typing error in compound assignment

A compound assignment like, for example:
x /= a;
should have the same effect as the operation followed by the
assignment except that the left side should only be evaluated
once. So the statement above (assuming 'x' free of side-effects)
should have the same effect as:
x = x / a;

In particular, the usual conversions should applied. So, if the
type of 'x' and 'a' is, respectively, 'unsigned int' (32 bit) and
'long' (64 bit), the statement above should be equivalent to:
x = (unsigned int) ((long) x / a);

But what is really done currently is something like:
x = x / (unsigned int) a;
In other words, the right-hand side is casted to the same type as the
lhs and the operation is always done with this type, neglecting the
usual conversions and thus forcing the operation to always be done
with the lhs type, here 'unsigned int' instead of 'long'.
For example, with the values:
        unsigned int x = 1;
        long a = -1;

We have:
x = 1 / (unsigned int) (-1L);
x = 1 / 0xffffffff;
x = 0;
instead of the expected:
x = (unsigned int) ((long)1 / -1L);
x = (unsigned int) (-1L);
x = 0xffffffff;

The patch fix this by first calculating the type corresponding to
the usual conversion and then casting the right-hand side to this
type, which is fine since it's a rvalue anyway.
Later steps will then use the rhs type when doing the operation.
On the example above, the cast will be a no-op and the operation will
be done with the correct type:
x = x / (long) a;
which, at linearization, will become:
x = (unsigned int) ((long) x / (long) a);
and with unneeded casts optimized away:
x = (unsigned int) ((long) x / a);
Which will give us the expected result.

If the types where in the other order, the result will also be done
with the correct type:
long x;
unsigned int a;
...
x /= a;
will become:
x = x / (long) a;
and, at linearization:
x = (long) ((long) x / (long) a);
and with unneeded casts optimized away:
x = (x / (long) a);

Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Ramsay Jones <ramsay@ramsayjones.plus.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
Signed-off-by: Christopher Li <sparse@chrisli.org>
evaluate.c
linearize.c
validation/compound-assign-type.c [new file with mode: 0644]