[Solved]Incorrect assembly output?!

Here's a snippet of code:

  uint32_t upperDuty = MAX_PWM_DUTY - PWM_BUFFER;
  uint32_t dutyA = a, dutyB = b, dutyC = c;
  if (dutyA < PWM_BUFFER) dutyA = 0;
  if (dutyB < PWM_BUFFER) dutyB = 0;
  if (dutyC < PWM_BUFFER) dutyC = 0;

  if (dutyA > upperDuty) dutyA = MAX_PWM_DUTY;
  if (dutyB > upperDuty) dutyB = MAX_PWM_DUTY;
  if (dutyC > upperDuty) dutyC = MAX_PWM_DUTY;

For the purposes of this discussion, assume that MAX_PWM_DUTY is 1000 and PWM_BUFFER is 45. The code, then, seems pretty straight forward. I'm limiting the ability of the PWM outputs to get too close to the min or max and if they try I'll set them to min or max. It should all work fine. But, the assembly output is not correct. I don't know what the compiler is thinking. Here's the assembly:

   80d20:	2e2c      	cmp	r6, #44	; 0x2c
   80d22:	bf98      	it	ls
   80d24:	2600      	movls	r6, #0
   80d26:	2d2c      	cmp	r5, #44	; 0x2c
   80d28:	bf98      	it	ls
   80d2a:	2500      	movls	r5, #0
   80d2c:	2c2c      	cmp	r4, #44	; 0x2c
   80d2e:	bf98      	it	ls
   80d30:	2400      	movls	r4, #0
   80d32:	f5b6 6f81 	cmp.w	r6, #1032	; 0x408
   80d36:	bf28      	it	cs
   80d38:	f44f 767a 	movcs.w	r6, #1000	; 0x3e8
   80d3c:	f5b5 6f81 	cmp.w	r5, #1032	; 0x408
   80d40:	bf28      	it	cs
   80d42:	f44f 757a 	movcs.w	r5, #1000	; 0x3e8
   80d46:	b2b2      	uxth	r2, r6
   80d48:	f5b4 6f81 	cmp.w	r4, #1032	; 0x408
   80d4c:	480d      	ldr	r0, [pc, #52]	; (80d84 <_Z9updatePWMjjj+0xac>)
   80d4e:	f04f 0100 	mov.w	r1, #0
   80d52:	bf28      	it	cs
   80d54:	f44f 747a 	movcs.w	r4, #1000	; 0x3e8

The first part seems fine - R4-R6 have the values for PWM. Each is compared to 44 and then set to zero if they were 44 or less. The next part sure seems to me to be checking the three against 1032 and then setting them to 1000 if they were greater than or equal to 1032. But, they can't be greater than or equal to because 1032 is over the max PWM duty! This makes no sense. 1000 - 45 is 955 not 1032. I can't figure out where on earth the compiler is getting a value of 1032 from. It does this at least with both 1.6.7 IDE and 1.6.9 IDE along with the newest (1.6.8?) version of the Due board support files. I could try hard coding the value instead but I want configurability. If I change my PWM parameters I want all of the code to update as well.

Has anyone else experienced an aggravation like this? I seem to remember various people saying that they had problems with the most recent Due support files. I wonder if this has anything to do with it?

Btw, I know everyone's first thought will be that I messed up the defines and thats why the weird value is there. I added these lines to the function:


What I get back is:

Now, maybe missing something but upperDuty, remember, is defined with this line:

uint32_t upperDuty = MAX_PWM_DUTY - PWM_BUFFER;

I think that upperDuty = 1000 - 45 should certainly resolve to 955 not 1031. This value is being done by the compiler / preprocessor (you don't see the calculation in code) so somehow the preprocessor has gone insane.

As it turns out, it was my fault so nevermind. For future reference, don't forget to enclose complicated defines in parenthesis or the compiler might not do what you want.

In other words, any (no, not just complicated ones) #define that uses an expression should have enclosing parens.
Consider a simple example:

#define NELEMENTS 10
#define BUFFERSIZE NELEMENTS+1  // leave room for end marker
long buf[BUFFERSIZE];
memset(buf, 0, BUFFERSIZE*sizeof(long));  // clear the buffer

BUFFERSIZE is clearly 11, and sizeof(long) is 4, so the memset() should clear the entire array of 44 bytes, right?
Nope. Because #define causes a TEXT SUBSTITUTION rather than being a real expression. The memset ends up looking like memset(buf, 0, 10+14); and thanks to the normal order of operations, 10+14 is only 14, and much of the array is NOT cleared.
It should have been:

#define BUFFERSIZE (NELEMENTS+1)  // leave room for end marker

Yes, it would have been more accurate for me to say that any define that is something other than a straight literal needs () or it could get messed up. I had some of my defines properly surrounded and some weren't. This caused some code to work fine and other code to mess up in ways that are very strange because the ending code gets a literal in place of all the math operations while the source code seems to look differently. Do. not. be. me. Surround your defines with ().