Operator precedence question.

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
uint16_t RowIndx; is a local
uint8_t CursRow; is a global

In Debug mode this:

if(CursRow + RowIndx == 1)

was true and in Release mode it was not.
After changing it to

if((CursRow + RowIndx) == 1)

it worked for both Debug and release. In both cases the variables added to 1

I am puzzled and a bit worried that there might be something else wrong.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

While IMO it is a good practice to use parentheses liberally (they are quite inexpensive in full-reel quantities), + is a higher precedence than ==.

Why don't you post the generated code for both fragments? Also, what toolchain/version, and which target AVR model.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sounds like an optimisation issue. Perhaps CursRow has been cached to a register so external updates are not being seen?

As Lee says, post the generated code from the .lss or .s files in both cases.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

volatile

"Demons after money.
Whatever happened to the still beating heart of a virgin?
No one has any standards anymore." -- Giles

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

volatile

Perhaps, but we can't tell until we see more. Complete test program, and build options for each, and the generated code fragments.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the suggestions - After getting GCC to create the .S file and sifting through the code I figured out what is happening.
RowIndx is a uint16 but when I sent the value to the PC I sent it as a byte :oops: without a cast. This sent the MSB which was 0 so it appeared the two variables = 0 + 1 but in reality there was some random data in the LSB which seems to be set to 0 when in debug mode.
When I tested it with the extra () I think it was just luck that it worked differently. In the S file I could see that the code was the same.
Well I am glad it is not a lib bug else I would have a lot of testing to do.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It appears that the 'random' data comes from the fact that in the release version the compiler decided that the part where I initialise the variable to 0 is not required :(

RowIndx = 0;
ViewChanged = 0;

Debug:

RowIndx = 0;
46ea:	1a 82       	std	Y+2, r1	; 0x02
46ec:	1b 82       	std	Y+3, r1	; 0x03
ViewChanged = 0;
46ee:	10 92 4e 28 	sts	0x284E, r1

Release:

RowIndx = 0;
ViewChanged = 0;
368c:	10 92 4e 28 	sts	0x284E, r1

Release with volatile:

RowIndx = 0;
368c:	19 82       	std	Y+1, r1	; 0x01
368e:	1a 82       	std	Y+2, r1	; 0x02
ViewChanged = 0;
3690:	10 92 4e 28 	sts	0x284E, r1

So I have changed it to volatile. I know it is the optimiser, but is this not just a plain old bug in the optimiser?
This is in an FSM inside a function. The variable is local and cleared in state 1, the state changes to state 2 and remains there. The code then exits function and that is it. Apart from the setting to 0 there is only one other line that changes the variable and for testing I commented it out.
Does make one wonder how many other variables that have been assigned a known value are just left with random data :roll:

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I know it is the optimiser, but is this not just a plain old bug in the optimiser?

The reason it's not setting Y+1 / Y+2 is because it is not creating a stack frame variable to hold "RoWIndx" but it is cached into a register elsewhere. As I said above:
Quote:

Perhaps ... has been cached to a register

So for you Release code show more context. Determine where the compiler has chosen to hold "RowIndx" and, if a register pair, do you see CLR/EOR or a MOV of R1 to the registers involved anywhere in the code (again it may not follow the sequence you wrote - the optimiser is allowed to do that too).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
The reason it's not setting Y+1 / Y+2 is because it is not creating a stack frame variable to hold "RoWIndx" but it is cached into a register elsewhere

That might be true, but regardless of that, the nett result is that it is not clearing a variable that was cleared by code in a previous state of the FSM.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You aren't getting the points I'm making:

(a) that variable is NOT being created on the stack frame so there's nothing in RAM to be cleared - hence no ST Y+ operations.

(b) my belief is that the optimiser has cached the 16 bit variable into two machine registers and I think you'll find those two registers ARE being cleared (which is the equivalent of "RowIndx = 0;") but it may not be sequential. It could be 30 opcodes back if those registers are not used in the meantime (or maybe they are - but as a source of 0x0000 - the optimiser is clever like that!). So look at where RowIndx is actually used and determine which two registers it is held in. Then work back and see if you can spot where they are cleared (as I say: CLR, EOR or a MOV from R1). You may even find that if the optimiser was smart enough to realise that RowIndx never exceeded 255 that it was able to use just one, not two registers to hold the value - again it's clever like that.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
You aren't getting the points I'm making

I am getting your points and thank you for taking the time to make them.

:oops: :oops: :oops: :oops:
The variable is a local. I set it to 0 then exit the FSM and the function its in. I return later and expect it to still be 0 :oops: :oops: :oops: :oops:

It was while taking Clawsons suggestion of seeing where it was set to 0 that I saw it was getting the value off the stack that made me realize what was happening.

thanks to all who helped