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.
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’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).
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
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.
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
}
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.
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.
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))