I work on compilers for a couple of embedded platforms. A user has recently complained about the following behaviour from one of our compilers. Given code like this:
extern volatile int MY_REGISTER;
void Test(void)
{
(void) (MY_REGISTER = 1);
}
The compiler generates this (in pseudo-assembler):
Test:
move regA, 1
store regA, MY_REGISTER
load regB, MY_REGISER
That is, it not only writes to MY_REGISTER, but reads it back afterwards. The extra load upset him for performance reasons. I explained that this was because according to the standard "An assignment expression has the value of the left operand after the assignment, [...]".
Strangely, removing the cast-to-void changes the behaviour: the load disappears. The user's happy, but I'm just confused.
So I also checked this out in a couple of versions of GCC (3.3 and 4.4). There, the compiler never generates a load, even if the value is explicitly used, e.g.
int TestTwo(void)
{
return (MY_REGISTER = 1);
}
Turns into
TestTwo:
move regA, 1
store regA, MY_REGISTER
move returnValue, 1
return
Does anyone have a view on which is a correct interpretation of the standard? Should the read-back happen at all? Is it correct or useful to add the read only if the value is used or cast to void?