My problem is how to force the compiler to perform `b` - `a` > 0 when I write `b - a > 0`, because (it is not shown in the above code example) but when I wrote:
if (spin && !unlock && ticks && (epoch - at > 0)) {
__CLREX();
return false;
}
I get a program that didn't work because (epoch - at > 0) was assembled as the previous "CMP + BGT" sequence that didn't work.
"CMP + BGT" is exactly correct and exactly what you asked it to do.
"CMP" and "SUBS" are the same operation, with the sole difference being that "CMP" doesn't write the result of the subtraction to a register.
As I demonstrated before "CMP + BGT" and "SUBS + CMP #0 + BGT" are different.
Of course they are. The "CMP #0" throws away information, specifically the carry and overflow flags from the CMP/SUBS, so you get the result of a wrapped calculation not the mathematically correct result of the subtract.
"CMP + BGT" and "SUBS + BGT" are the same thing.
EDIT:
LDR R0, =0x80000002
LDR R1, =0x7FFFFFFA
SUBS R2, R0, R1
CMP R2, #0
BGT test
will take the branch.
LDR R0, =0x80000002
LDR R1, =0x7FFFFFFA
CMP R0, R1
BGT test
will not.
Your numbers are -2147483646 and 2147483642. The former is clearly much smaller and a signed comparison (using SUBS/BGT or SMP/BGT) will show that.
If you subtract them the mathematical result is -4294967288, which is very negative so BGT correctly does not branch.
If you force the result of the subtraction to be brought into the 32 bit range by storing it to memory and loading it back, or by comparing directly to 0, then you get 8, which is greater than 0, which is why the first one branches.
Overflow in signed arithmetic in C is UB. The compiler is allowed by the rules of the language to assume that you do not do anything that overflows, and that you are happy with either the true mathematical result or the wrapped result -- or in fact with anything else.
In particular for signed values the compiler is allowed to assume mathematical rules such as commutativity and associativity and assume that for the values you give it, "epoch - at > 0" and "epoch - at + at > 0 + at" and "epoch > at" are equivalent. In the vast vast majority of code this is a *good* thing.
But you are trying to do something tricky and non-mathematical.
If you want to depend on wrapping modulo 2^32 arithmetic in C then you *must* use "unsigned". It's as simple as that.
If you want to program in C then learn the language. Don't try to figure out how to trick some particular compiler. Write code that is guaranteed by the clearly written rules of the language to work with any compiler, at any optimisation level, on any instruction set, on any day of the week.