Option to make unsigned->signed conversion always well-defined?

Ian Lance Taylor iant@google.com
Thu Oct 6 18:19:00 GMT 2011


Andrew Haley <aph@redhat.com> writes:

> On 10/05/2011 09:11 PM, Ulf Magnusson wrote:
>> Hi,
>>
>> I've been experimenting with different methods for emulating the
>> signed overflow of an 8-bit CPU. The method I've found that seems to
>> generate the most efficient code on both ARM and x86 is
>>
>> bool overflow(unsigned int a, unsigned int b) {
>>     const unsigned int sum = (int8_t)a + (int8_t)b;
>>     return (int8_t)sum != sum;
>> }
>>
>> (The real function would probably be 'inline', of course. Regs are
>> stored in overlong variables, hence 'unsigned int'.)
>>
>> Looking at the spec, it unfortunately seems the behavior of this
>> function is undefined, as it relies on signed int addition wrapping,
>> and that (int8_t)sum truncates bits. Is there some way to make this
>> guaranteed safe with GCC without resorting to inline asm? Locally
>> enabling -fwrap takes care of the addition, but that still leaves the
>> conversion.
>
> inline int8_t as_signed_8 (unsigned int a) {
>   a &= 0xff;
>   return a & 0x80 ? (int)a - 0x100 : a;
> }
>
> int overflow(unsigned int a, unsigned int b) {
>   int sum = as_signed_8(a) + as_signed_8(b);
>   return as_signed_8(sum) != sum;
> }

This version looks good to me.

In general there are two cases: if you have a wider type, and if you do
not.  If you have a wider type, do what Andrew suggests.  If you do not
have a wider type, do the addition using an unsigned type, and see if
the result is smaller than either of the operands.

Ian



More information about the Gcc-help mailing list