Catching addition overflow in C

Is there a standard way to catch an integer overflow in C using GNU GCC for ARM? I’m pretty sure this should just be a CPU flag check, but I don’t know how to do it.

I know I can do a compare before hand, e.g.

//a = b + c
if (max_value - b < c) //Then we'll have an overflow.

but that method seems to slow. This code is going in an interrupt that gets called many many times.

Also, I always want to add the too numbers, regardless of whether an overflow will occur. I just want to know when one does.

Should I be looking at inline assembly?

Thanks.

I think it can generate an exception that can be trapped.

Leon

What size variables are you using, 8, 16 or 32 bit and are they signed or unsigned ?

Andy

Thanks for the reply leon.

After looking in the [Technical Reference Manual I found the Program Status Register (page 2-6) has an overflow flag. So I think all I need to do is check this flag.

I don’t really know how to check it, though.](Documentation – Arm Developer)

I’m adding two unsigned 16 and 32 bit variables. I’d really like to just know how to code some inline assembly to check that overflow flag though (if it would work).

Thanks again.

If you’re adding two 16 bit values with a 16 bit destiniation, you can promote them to 32 bit and test for > 16 bit. In assembly there is normally a Carry flag, and branch with carry set

Andy

Hi guys,

I played around some more on my problem. Here is what I’ve come up with so far.

u32 a = 0xFFFFFFFF;
u16 b = 0x0001;
a += b;

asm("\tBVC noOverflow\n"); //Branch only if no overflow.

//This code only runs if there was an overflow.
//Code goes here.

asm("noOverflow:\n");

It doesn’t work though. Here is what it complies to:

u32 a = 0xFFFFFFFF;
   	F04F33FF   mov.w r3, #0xFFFFFFFF
   	643B       str r3, [r7, #0x40]
u16 b = 0x0001;
   	F04F0301   mov.w r3, #0x00000001
   	F8A73046   strh.w r3, [r7, #+0x046]
a += b;
   	F8B72046   ldrh.w r2, [r7, #+0x046]
   	6C3B       ldr r3, [r7, #0x40]
   	4413       add r3, r2 <----- if only that was "adds r3, r2"
   	643B       str r3, [r7, #0x40]
asm("\tBVC noOverflow\n"); //Branch only if no overflow.
   	D7FF       bvc 0x08000374 <noOverflow>

The reason it doesn’t work is because the ADD command doesn’t update the overflow register. It should use the ADDS command to update the status registers.

I made an inline function that also did the addition part, but the compiler wanted to generate a bunch of interface code (load the variables into different registers, run my assembly, load them back).

I’ll probably just stick to a slow C implementation for now, but it looks like I’ll probably be rewriting the entire function in assembly soon.

Any more suggestions?

I’ve never seen any one doing what you tried to do, because the compiler can generate what it likes for the code, as you saw. Typically, people would at least code the add in asm as well.

I’m making this up, so it might need some debugging, it’s a C implementation of the carry flag in effect.

#define BIT31 0x80000000

u32 a = 0xFFFFFFFF;
u16 b = 0x0001;
u32 carry=0;

carry = a & BIT31;
a = a & ~BIT31;

a += b; 
if (carry & ( a & BIT31 ) )
{
 // code for overflow

}
else
{
// code for no overflow

}

HTH,

Andy

Thanks Andy, that’s a good idea.

I think you had a small bug in the if statement, though. Here is what I’m going to use for now.

#define MSB (1 << 31) //Most sig bit flag.

u32 a = 0xFFFFFFFF;
u16 b = 0x0005;
u32 carry = MSB & a; //See if the MSB is set.

a += b;

if (carry && !(a & MSB)) //If the MSB was set before and isn't now, then it overflowed.
{
  //code for overflow
}

After looking at the assembly this all generates, I still don’t really like it. This should just be one BVC (branch if not overflow) instruction. Instead this all complies to a lot of extra stuff. When I’ve learned more, I’ll rewrite the entire function in assembly.

Anyway, Andy, I’m going to use your idea for now. Thanks again.

One method we used in some app’s where we couldn’t check the overflow bit was to check if the addition result was less than the largest component.

For example,

if A+B < A or A+B < B then overflowed

Imbue:
The reason it doesn’t work is because the ADD command doesn’t update the overflow register.

What compiler command-line options are you using? Assuming that your version of gcc has implemented the machine-independent options, if option -fwrapv is specified it would cause the value to wraparound.

A possible alternative approach might be to use -ftrapv to generate a trap which you would then need to handle appropriately. However, that should generates traps for signed overflow on all addition, subtraction, and multiplication operations which might not be what you really want.

Shifted, thanks for another good idea.

cfb, I’m not sure I completely understand what you’re saying. The [-fwrapv option seems to only apply to signed operations (with twos-complement representation), and even then I don’t see how it could help me.

In any case, the addition does overflow and “wrap around” as expected. I’ve never seen a system where that wasn’t the case for unsigned integers. My only problem is that I can’t detect the overflow flag, because the C code uses the ADD instruction and that doesn’t update the state flags. Only the ADDS instruction updates the state flags (negative, zero, carry, and overflow).](Code Gen Options - Using the GNU Compiler Collection (GCC))

Imbue:
cfb, I’m not sure I completely understand what you’re saying.

Not surprising since I mistakenly thought you were talking about signed integers - sorry :cry: . In that case I second shifted’s suggestion.

if you don’t want all the glue code from a function, would it be ok to just do your inline asm ADDS as a macro?

something like this (not sure if the inline asm syntax is correct?):

#define carry_add(a,b) asm(“adds %0, %1”: “=r”(a) : “r”(b))

then in your code,

a+=b; becomes carry_add(a,b);

also you could try defining your function as inline, that might work too.

i’ve never written any serious inline asm with gcc, so hopefully this isn’t too off base…

-sjg

I think adds has three arguments

adds a, b, c //pseudo code: a=b+c

so it should be like this

#define carry_add(a,b) asm(“adds %0, %0, %1”: “=r”(a) : “r”(b))