Certain operations involving shifts have incorrect results. The bug only happens on CPUX architectures.
For example, when compiling (with no optimization) and then executing the following lines of code the obtained result is 16 instead of 64.
uint32_t u32_var;
int main(void)
{
int tmp;
...
u32_var = 0xa;
tmp = 16 << (u32_var & 0x07);
printf("tmp: %d\n", tmp); // "tmp: 16" is printed instead of "tmp: 64"
...
}
That happens because the compiler generates incorrect assembly code:
5c44: b2 40 0a 00 mov #10, &0x1c02 ;#0x000a
5c48: 02 1c
5c4a: 82 43 04 1c mov #0, &0x1c04 ;r3 As==00
5c4e: 1e 42 02 1c mov &0x1c02,r14
5c52: 1f 42 04 1c mov &0x1c04,r15
5c56: 0f 4e mov r14, r15
5c58: 3f f0 07 00 and #7, r15 ;#0x0007
5c5c: 3e 40 10 00 mov #16, r14 ;#0x0010
5c60: 4f 4f mov.b r15, r15
5c62: 7f f0 0f 00 and.b #15, r15 ;#0x000f
5c66: 84 4e fc ff mov r14, -4(r4) ;0xfffc(r4)
5c6a: 4f 93 tst.b r15
5c6c: 03 24 jz $+8 ;abs 0x5c74
5c6e: 7f 53 add.b #-1, r15 ;r3 As==11
5c70: cf 18 0e 5e .rpt r15
addx r14, r14
5c74: 14 12 fc ff push -4(r4) ;0xfffc(r4)
5c78: 30 12 9a 66 push #26266 ;#0x669a
5c7c: b0 12 ae 5c call #0x5cae
As you can see, at address 0x5c66, register 14 (containing 16) is stored in memory before being shifted. The stored valued (i.e., 16) is then pushed in the stack (i.e., passed as an argument to the printf() function).
With more complex code, the bug can happen also when using optimization.
The attached patch appears to fix this. It has not undergone complete regression testing, but I will be using it in my internal development.
Never mind, that fix broke the other code path. Back soon....
Third time's the charm? We'll see....