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