Option to make unsigned->signed conversion always well-defined?
Ulf Magnusson
ulfalizer@gmail.com
Thu Oct 6 14:42:00 GMT 2011
On Thu, Oct 6, 2011 at 10:25 AM, Ulf Magnusson <ulfalizer@gmail.com> wrote:
> On Thu, Oct 6, 2011 at 12:55 AM, Pedro Pedruzzi
> <pedro.pedruzzi@gmail.com> wrote:
>> Em 05-10-2011 17:11, Ulf Magnusson escreveu:
>>> Hi,
>>>
>>> I've been experimenting with different methods for emulating the
>>> signed overflow of an 8-bit CPU.
>>
>> You would like to check whether a 8-bit signed addition will overflow or
>> not, given the two operands. Is that correct?
>>
>> As you used the word `emulating', I am assuming that your function will
>> not run by the mentioned CPU.
>>
>
> No, it'll most likely only run on systems with a wider bitness.
>
>> Does this 8-bit CPU use two's complement representation?
>
> Yes, and the criterion for signed overflow is "both numbers have the
> same sign, but the sign of the sum is different". Should have made
> that more clear.
>
>>
>>> 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.
>>
>> I believe the cast from unsigned int to int8_t is implementation-defined
>> for values that can't be represented in int8_t (e.g. 0xff). A kind of
>> `undefined behavior' as well.
>>
>> I tried:
>>
>> bool overflow(unsigned int a, unsigned int b) {
>> const unsigned int sum = a + b;
>> return ((a & 0x80) == (b & 0x80)) && ((a & 0x80) != (sum & 0x80));
>> }
>>
>> But it is not as efficient as yours.
>>
>> --
>> Pedro Pedruzzi
>>
>
> Yeah, I tried similar bit-trickery along the lines of
>
> bool overflow(unsigned int a, unsigned int b) {
> const uint8_t ab = (uint8_t)a;
> const uint8_t bb = (uint8_t)b;
> const uint8_t sum = ab + bb;
> return (ab ^ bb) & ~(ab ^ sum) & 0x80;
> }
>
> , but it doesn't seem to generate very efficient code.
>
> /Ulf
>
Might as well do
bool overflowbit(unsigned int a, unsigned int b) {
const unsigned int sum = a + b;
return (a ^ b) & ~(a ^ sum) & 0x80;
}
But still not very good output compared to other approaches as expected.
/Ulf
More information about the Gcc
mailing list