I have a problem where 2 different compilers (GCC and IAR) are dropping my mask from an if of different sized variables.
I have the following code:
uint8_t Value2;
uint16_t WriteOffset;
bool Fail;
void test(void)
{
uint8_t buff[100];
uint16_t r;
for(r=0;r<Value2+1;r++)
{
if(buff[r]!=(WriteOffset+r)&0xFF)
{
Fail=true;
}
}
}
The if fails (goes into the {} block) when buff[r] ==0 and WriteOffset+r == 0x100.
GCC outputs the following assembly:
movzwl -0xc(%ebp),%eax ; Load 'r'->EAX
mov -0x70(%ebp,%eax,1),%al ; Load 'buff[r]'->AL
movzbl %al,%edx ; Move AL to (unsigned int)EDX
mov 0x4b19e0,%ax ; Load 'WriteOffset'->AX
movzwl %ax,%ecx ; Move AX to (unsigned int)ECX
movzwl -0xc(%ebp),%eax ; Load 'r'->EAX
lea (%ecx,%eax,1),%eax ; 'WriteOffset' + 'r'->EAX
cmp %eax,%edx ; (unsigned int)'WriteOffset+r' == (unsigned int)'buff[r]'
je 0x445e28 <Test+1254> ; If == skip {} block
My question is why is the compiler dropping my &0xFF from the if (I have already fixed the problem with a cast, but I still do not understand why it dropped it in the first place)?
It isn’t, operator precedence is biting you here
You want
if( buff[r] != ((WriteOffset+r)&0xFF) )What you currently have is the same as
if( (buff[r]!=(WriteOffset+r)) & 0xFF )The precedence confusion is causing you to mask a value that can only be 0 or 1 (the result of the comparison expression) with 0xFF, so the optimizer is quite reasonably removing it.