7 ms·
Most (all?) modern processors have instructions and flags specifically for querying and reacting to integer overflow/carry. This seems like a situation where d
by phibz 8y ago
Most (all?) modern processors have instructions and flags specifically for querying and reacting to integer overflow/carry.
This seems like a situation where dropping to assembly to perform the addition and testing the flag makes sense. GCC has a mechanism for inline assembly where you list the variables you read from, you write to, and registers you modify and the optimizer plays nice with you. You could provide it as a function to use instead of doing the addition in C.
- abenedic 8y agoI have been doing a lot of assembly programming, and I can't help but agree with this. It is crazy how simple x86 assembly language programming makes checking overflow compared to C.
- saagarjha 8y agoThat's the issue: while x86 exposes such operations, not all assembly dialects do. They too have to support C and emulating overflow detection in software would be unreasonable.
- acqq 8y agoIt seems to me that it would not be unreasonable. If you need that detection, you need it at any price, on any platform. If you don't need it, meaning, the code doesn't test it, the compiler has still the right to optimize it away.
- saagarjha 8y agoSo it would be implementation defined behavior. I'm fine with that; personally, I think the standard was too quick to assign "undefined" here. But it can't mandate a certain behavior in the standard across all platforms.
- bsder 8y ago> It is crazy how simple x86 assembly language programming makes checking overflow compared to C. It's easy to write, but not so easy to optimize the performance. Overflow checking creates a dependency in between operations and requires the emission of instructions that didn't have to be there before. i += 1 <branch if overflow> i += 1 <etc> Means that you are executing more than twice the number of instructions and are getting further behind on the dependency chain each iteration. Eventually, your branch subsystem is completely overwhelmed by a branch that is taken effectively never.
- abenedic 8y agoish, you can use cmov for some stuff.
- AstralStorm 8y agoWhere is it available in MIPS?
- snaky 8y ago> cmov's can make a difference. You can use them to avoid polluting your branch prediction tables, you can use them to make code smaller, and you can use them when they simply just fit the problem really well. It's just _not_ the case that they are "obviously better". They simply aren't. https://yarchive.net/comp/linux/cmov.html https://yarchive.net/comp/linux/cmov.html
- Mikhail_Edoshin 8y agoIf the upper bound is known, then we'll just make the check once before the loop, no?
- olliej 8y agoThe issue isn’t what the hardware can do, but rather that the C spec leaves it undefined. Over the last decade have increasingly abused this idea basically making the spec a land mine of UB and then claiming that UB allows them to do whatever they want, even when the programmer intent is obvious. That said in modern clang and gcc you can (and should) use the overflow builtins which are all essentially: Bool __builtin_[operation]_overflow(type a, type b, type* out) Returning true if the operation overflowed. These produce “ideal” code, e.g if(overflowoperation(x,y,&out)) ... Produces the platform branch on overflow instructions.
- xenadu02 8y ago> Over the last decade have increasingly abused this idea basically making the spec a land mine of UB and then claiming that UB allows them to do whatever they want, even when the programmer intent is obvious. That is not an accurate or fair assessment. However signed integer overflow being undefined behavior is a bit over the top given modern hardware. I'd like to see the C standard adopt a policy of wrapping for signed overflow, then either add new operators or functions for trapping behavior. Most reasonable hardware has the instructions to trap or branch if add/sub/mul/div overflows or underflows so the checks are very cheap. Unlike the early days, in this day if C made it part of the standard processor manufacturers would simply stop selling CPUs without those features. Same goes for two's-compliment integer representations. They already did the same for 8-bit char/byte; other sizes are no longer supported.
- olliej 8y agoThere has been an ever increasing creep of undefined behaviour, which has broken existing code - type punning through unions was literally the “correct” mechanism for type coercion, which then became invalid when they established new, questionable, type aliasing rules that rendered it UB. The new type aliasing rules also mean that you can’t implement memcpy/memmove/bzero/memset without hitting UB. That requires hacks in the spec treatment of type aliasing to work around. Hell, even Malloc/free technically is UB due to type aliasing. Obviously there is signed integer overflow, which has resulted in numerous security flaws for questionable performance gains. Then there are other fun things, like technically it is UB for bzero to skip padding bytes in a struct (because that is UB), which means bzero(&somestruct, siseof(somestruct)) is not technically guaranteed to clear all of the struct, so I hope there’s not any secrets in left over memory.