Reply by Dan Bloomquist November 17, 20092009-11-17
t...@l-3com.com wrote:
>> -----Original Message-----
>> From: m... [mailto:m...] On Behalf
>> Of Dan Bloomquist
>> Sent: Sunday, 15 November 2009 2:07 AM
>> To: m...
>> Subject: Re: [msp430] IAR project port to Crossworks issue
>>
>>
>
> [Wade, Tim (FN) @ Nautronix]
>
>> As for the:
>>
>> while ((I2CDCTL & I2CBUSY) == TRUE)// Wait for I2C module to go
>> idle
>>
>> That evolved to
>> ((I2CDCTL & I2CBUSY) != 0)
>>
>> What is wrong with a simple?
>> for( ; I2CDCTL & I2CBUSY; )
>> ;
>> Procedural wordiness belongs in the comments, not the code. (IMHO)
>>
>
> [Wade, Tim (FN) @ Nautronix]
> We mostly have C++ programmers and they use the Boolean keyword and it (sometimes) protects them from this "== true" stuff -- they usually go tits up in C where true is basically anything that isn't 0 but not necessarily what you expect it to be. We used to mandate "!= FALSE" instead of "== TRUE" but Dan is probably correct in it being necessary at all...
>
>

Hi Tim,
C came before c++ for me. But I've been doing c++ for so long that it is
now my first language. I'm not sure where comparisons to bool ever
started but from bad examples and poor curriculums. But in either
language I would conditioner it bad form to use the compare. Sure, you
should be able to trust that '! 1 == false' is true in c++, but what is
the point?!? '1' says it all! In either language I just don't mess
around. And it gets richer for me as I use MFC on the box.* What ever
its origin, they used TRUE/FALSE defined from the get go. So if I'm
answering to MFC I use 'TRUE/FALSE' even if I use true/false exclusively
in 'my' code. In fact, I'm anal about truth in C or C++ and trust the
compiler to understand that. I like bools and define true/false in C for
the MSP430. That way I can work with comfort between c and c++. But
never, never would I consider a bool to be anything but a truth even in
c++. ( 23 == true, would scare me, shudder! even when 'if( 23 )' is
natural. ) If I want to assign an 'if NULL pointer' or value to a bool
it is 'bBool= !! value;' in either language. Otherwise I trust that if I
set my pointer to NULL, it will test false as a truth. From there I
trust the compiler to do the right thing and optimize as needed. As long
as I consider bBool as only a truth and not a value, it should work...

So, I'm agreeing with you, that there should never be a good reason to
compare to a truth, and pushing that into c++. You are way more
guaranteed to get the right result, with less code, by never doing it.

*I've seen them do bool compares in MFC, I just don't know what they
were thinking....

Best, Dan.

Beginning Microcontrollers with the MSP430

Reply by Jon Kirwan November 17, 20092009-11-17
On Tue, 17 Nov 2009 01:48:43 -0000, you wrote:

>On Tue, 17 Nov 2009 01:24:56 -0000, Jon Kirwan
>wrote:
>
>>> Let's use reference parameters:
>>>
>>> volatile int x;
>>>
>>> void set_zero_twice(volatile int &y)
>>> {
>>> y = y = 0;
>>> }
>>>
>>> void main(void)
>>> {
>>> set_zero_twice(x);
>>> }
>>>
>>> C15 generates this:
>>>
>>> set_zero_twice:
>>> mov eax, DWORD PTR _y$[esp-4]
>>> mov DWORD PTR [eax], 0
>>> mov DWORD PTR [eax], 0
>>> ret 0
>>>
>>> main: // inlined!
>>> xor eax, eax
>>> mov DWORD PTR ?x@@3HC, eax
>>> mov DWORD PTR ?x@@3HC, eax
>>>
>>> Flip.
>>>
>>
>> Equivalent, aren't they? The function code has to fetch the address
>> into eax. But it is a reference and so follows the logic I laid out
>> earlier. In the inline case, same thing. It follows the rules of
>> inlining "as if" it were a pointer action and not an instance. The
>> "as if" rule applies strongly here, yes?
>
>What you may have missed is that in this case, "y = y = 0" generates
>*different* code from "x = x = 0" even though x and y are the "same
>thing", except x is a file-scope variable and y is a reference to a
>global. YOU MUST NOT ACCEPT THIS!

>

Hehe. I pointed out earlier that I could certainly make an argument
that there should be no semantic difference. However, I decided to
take, for argument's sake, a different position -- one that derives
from CFRONT... that a reference is mechanically equivalent to a
dereferenced pointer. It's an optimization trick to allow the
compiler to know a little something more from the context, but the
implementation mechanism is 1:1 equivalent. Once I take that position
(which I don't like taking much), then I can argue that a dereference
implies action but not an instance, which means the compiler is free
to construct a temporary instance to represent the result of the
assignment expression. In the case of the named variable itself,
there is a named lvalue and the result of the expression is exactly
the rvalue contained there.

I hate arguing like that. It's grueling.

But then... a lot of c stuff is.

So, is this something that varies a lot in compilers? What do the
folks worth listening to at the standards meetings say around the
water cooler about this? :)

Jon
Reply by Paul Curtis November 16, 20092009-11-16
On Tue, 17 Nov 2009 01:24:56 -0000, Jon Kirwan
wrote:

>> Let's use reference parameters:
>>
>> volatile int x;
>>
>> void set_zero_twice(volatile int &y)
>> {
>> y = y = 0;
>> }
>>
>> void main(void)
>> {
>> set_zero_twice(x);
>> }
>>
>> C15 generates this:
>>
>> set_zero_twice:
>> mov eax, DWORD PTR _y$[esp-4]
>> mov DWORD PTR [eax], 0
>> mov DWORD PTR [eax], 0
>> ret 0
>>
>> main: // inlined!
>> xor eax, eax
>> mov DWORD PTR ?x@@3HC, eax
>> mov DWORD PTR ?x@@3HC, eax
>>
>> Flip.
>> Equivalent, aren't they? The function code has to fetch the address
> into eax. But it is a reference and so follows the logic I laid out
> earlier. In the inline case, same thing. It follows the rules of
> inlining "as if" it were a pointer action and not an instance. The
> "as if" rule applies strongly here, yes?

What you may have missed is that in this case, "y = y = 0" generates
*different* code from "x = x = 0" even though x and y are the "same
thing", except x is a file-scope variable and y is a reference to a
global. YOU MUST NOT ACCEPT THIS!

volatile int x;
x = x = 0;

and

void foo(volatile int &y) { y = y = 0; } foo(x)

should generate the same access pattern, but they do not. In one case,
it's a write-read-write-back whereas in the other it's
write-write-same-value. One, or the other, *must* be wrong, they can't
both be right.

So something is broken.

In short, best practice:

ALWAYS use simple expressions when dealing with volatiles--assume your
compiler is broken for anything else.

Don't use volatile bitfields or declare a structure volatile that contains
bitfields.

Know the difference between a volatile pointer and a pointer to volatile.

Know that volatile != atomic.

-- Paul.
Reply by Jon Kirwan November 16, 20092009-11-16
On Mon, 16 Nov 2009 21:51:58 -0000, Paul wrote:

>
>Now lets take a look another case. Let's change it a little:
>
>volatile int x;
>volatile int *y = &x; // y points to volatile int x

Okay.

>*y = *y = 0;
>
>Given the code generated above, you'd expect a write of *y, a read of *y,
>and a write of *y, yes? 'y' is not volatile, therefore y's value does not
>change during the execution of this statement and *is* constant. But the
>code?
>
> mov eax, DWORD PTR _y
> mov DWORD PTR [eax], 0
> mov ecx, DWORD PTR _y
> mov DWORD PTR [ecx], 0
>
>Holy crap! Two writes to *y, both of zero, and a read has been
>eliminated! Why did the compiler do this?

Interesting. I'm guessing that the difference is that the c compiler
considers (*y) to be an action verb, but not an actual instance in and
of it's own right. So it creates a compiler temporary to hold the
rvalue of the right side's computation. This compiler temporary does
not have the volatile qualifier. In the earlier case, the rvalue of
the expression is found at 'x', so the compiler temporary is
eliminated leaving 'x' in its place, which does have the volatile
qualifier still.

>Ok, let's give the compiler the benefit of the doubt that it got confused
>about pointers--perhaps they're special in the case of "volatile" (they
>are not!).

Well, maybe the above argument I made is sound. But I'm struggling. I
like these kinds of questions, Paul!

>How about using C++ and references which just allow me to use
>synonyms?
>
>volatile int x;
>volatile int &y = x; // y is another name for volatile int x
>
>y = y = 0;
>x = x = 0;
>
> mov eax, DWORD PTR ?y@@3ACHC
> mov DWORD PTR [eax], 0
> mov ecx, DWORD PTR ?y@@3ACHC
> mov DWORD PTR [ecx], 0
> mov DWORD PTR ?x@@3HC, 0
> mov edx, DWORD PTR ?x@@3HC
> mov DWORD PTR ?x@@3HC, edx
>
>Again, the principle of least astonishment is broken.

Well, if you start out accepting that *y in the earlier pointer case
and y in the later reference case are equivalent from the compiler's
point of view (I think I could argue against that, but let's go with
it), and if you accept that it generated correct code (though
different) in each of the two earlier examples, then you'd certainly
expect this output you found.

Nothing new here.

Which gets back to whether or not I made a sound argument, earlier
here. (I don't know enough to know, but I can certainly put words
together and make the argument.) If I'm right; if it is true that the
c compiler considers *y to be an action but not an instance, then it
has to create a compiler temporary for the right half of the
assignment statement's result. In the 'x'-only, case, it doesn't have
to do that because the rvalue of 'x' __is__ the assignment fragment's
rvalue.

>Blimey. Ok,
>perhaps the compiler confused global references and pointers. Let's shove
>it into a function:

Hehe. I'll try to follow through.

>Let's use reference parameters:
>
>volatile int x;
>
>void set_zero_twice(volatile int &y)
>{
> y = y = 0;
>}
>
>void main(void)
>{
> set_zero_twice(x);
>}
>
>C15 generates this:
>
>set_zero_twice:
> mov eax, DWORD PTR _y$[esp-4]
> mov DWORD PTR [eax], 0
> mov DWORD PTR [eax], 0
> ret 0
>
>main: // inlined!
> xor eax, eax
> mov DWORD PTR ?x@@3HC, eax
> mov DWORD PTR ?x@@3HC, eax
>
>Flip.
>

Equivalent, aren't they? The function code has to fetch the address
into eax. But it is a reference and so follows the logic I laid out
earlier. In the inline case, same thing. It follows the rules of
inlining "as if" it were a pointer action and not an instance. The
"as if" rule applies strongly here, yes?

Hehe.

Enjoyed thinking a little, Paul. Now tear me apart!!

Jon
Reply by Jon Kirwan November 16, 20092009-11-16
On Mon, 16 Nov 2009 21:51:58 -0000, you wrote:

>Hi Jon,
>
>>> The compiler has proven that it doesn't need the read; this is as much a
>>> failing of the standard as anything.
>>
>> But it sure is an interesting case to consider, even if it comes from
>> accidentally writing code to incorrectly use ! instead of ~.
>>
>> I'd never considered closely this particular instance. But it is
>> interesting to think about the case of (volatile_instance_varname & 0)
>> as part of a conditional expression, which by one set of rules not
>> only can be pruned away in optimization but might even seem that they
>> _must be_, because of short-circuit evaluation. Of course, one could
>> deal with the _must be_ argument by simply pointing out that causing
>> code to actually execute the subexpression doesn't inhibit applying
>> short circuit rules, afterwards. So it _could_ still generate
>> executable code, I suppose.
>>
>> By one interpretation of the rules of volatile, it should still
>> produce a read event. And since creating executable code can arguably
>> still permit short circuit evaluation... just at run-time instead of
>> compile-time... the question then becomes, "Would a compiler violate
>> the c standard by _not_ eliminating such a read?"
>>
>> In other words, Paul, could __you__ personally choose to arrange the
>> compiler to maintain such volatile accesses and be able to argue
>> strongly that you still are well within the c standard in doing so?
>
>This is a compiler choice; the code can be rewritten internally by the
>compiler, but I choose not to.

Got it.

>> I'm curious.
>
>Here's a mindbender, so try the following:
>
>volatile int x;
>
>x = x = 0;
>
>What should a compiler do? There are two assignments there. What can you
>say about x after executing this statement?
>
>Well, here's that Microsoft's C15 generates for the first:
>
> mov DWORD PTR _x, 0 ; #1
> mov eax, DWORD PTR _x ; #2
> mov DWORD PTR _x, eax ; #3
>
>Going through this...
>
>#1 assigns x = 0
>#2 loads the current value of 'x' into eax. As x could be a hardware
>location (it's volatile, remember?) 'x' could have changed!
>#3 assigns what it just read from 'x' (now in eax) to 'x'.
>
>Now, if your answer was that the final value assigned to 'x' in this case
>is zero, you'd be wrong in this case, wouldn't you? So, that's two writes
>to x and one read!

Actually, that is one of two possibilities I would have "expected" to
see. I don't delve into these things every day, which is why I'd be
ignorant enough to not know which of the two possibilities it should
be.

I see "x=x=0;" in all cases (regardless of volatile or not) as either:

x= 0; // right side of the assignments.
temp= x; // assign the 'value' of the right side (x=0) to temp.
x= temp; // now pass along this value a second time.

or as,

x= 0; // right side of the assignments.
temp= 0; // assign the 'value' of the right side (x=0) to temp.
x= temp; // now pass along this value a second time.

Now that I write my equivocation out like this, it's a lot clearer to
me which is the correct one. In c, the result of an assignment is
never an lvalue, it always has the type that is exactly equal to the
unconverted, unqualified type of its left operand, and the result is
always the _value_ that is stored into the left operand... not the
right side expression value, which is not necessarily always the same
thing.

So from that analysis, I come to the conclusion that my first example
is correct and that the Microsoft example you provided follows that
pretty well. In other words, the statement 'x=x=0;' requires two
writes and one read, if 'x' is volatile. And the Microsoft compiler
has got it right.

>Assume that writes to 'x' are passed to a device and reads from 'x' always
>read -1 *and* have some side effect. In *this* case, x would be written
>with 0, read, and then written with -1 which is way outside the "principle
>of least astonishment".

Doesn't matter. 'x' is volatile. End of story. Now if it weren't, I
might see this principle applying. But it doesn't in this case.

>Do you *really* know the language you're using?
>That single statement above says it all doesn't it? A programmer will
>read that as "write to x twice, both times value 0" whereas the compiler
>has interpreted it completely differently.

The compiler has it right and I would NOT be flummoxed by it. In
fact, that's how I'd read the statement and __expect__ to get as the
resulting code. I'd be angry if it didn't do that.

I'll get to the second case you mentioned, later.

Jon
Reply by Paul Curtis November 16, 20092009-11-16
Hi Jon,

>> The compiler has proven that it doesn't need the read; this is as much a
>> failing of the standard as anything.
>
> But it sure is an interesting case to consider, even if it comes from
> accidentally writing code to incorrectly use ! instead of ~.
>
> I'd never considered closely this particular instance. But it is
> interesting to think about the case of (volatile_instance_varname & 0)
> as part of a conditional expression, which by one set of rules not
> only can be pruned away in optimization but might even seem that they
> _must be_, because of short-circuit evaluation. Of course, one could
> deal with the _must be_ argument by simply pointing out that causing
> code to actually execute the subexpression doesn't inhibit applying
> short circuit rules, afterwards. So it _could_ still generate
> executable code, I suppose.
>
> By one interpretation of the rules of volatile, it should still
> produce a read event. And since creating executable code can arguably
> still permit short circuit evaluation... just at run-time instead of
> compile-time... the question then becomes, "Would a compiler violate
> the c standard by _not_ eliminating such a read?"
>
> In other words, Paul, could __you__ personally choose to arrange the
> compiler to maintain such volatile accesses and be able to argue
> strongly that you still are well within the c standard in doing so?

This is a compiler choice; the code can be rewritten internally by the
compiler, but I choose not to.

> I'm curious.

Here's a mindbender, so try the following:

volatile int x;

x = x = 0;

What should a compiler do? There are two assignments there. What can you
say about x after executing this statement?

Well, here's that Microsoft's C15 generates for the first:

mov DWORD PTR _x, 0 ; #1
mov eax, DWORD PTR _x ; #2
mov DWORD PTR _x, eax ; #3

Going through this...

#1 assigns x = 0
#2 loads the current value of 'x' into eax. As x could be a hardware
location (it's volatile, remember?) 'x' could have changed!
#3 assigns what it just read from 'x' (now in eax) to 'x'.

Now, if your answer was that the final value assigned to 'x' in this case
is zero, you'd be wrong in this case, wouldn't you? So, that's two writes
to x and one read!

Assume that writes to 'x' are passed to a device and reads from 'x' always
read -1 *and* have some side effect. In *this* case, x would be written
with 0, read, and then written with -1 which is way outside the "principle
of least astonishment". Do you *really* know the language you're using?
That single statement above says it all doesn't it? A programmer will
read that as "write to x twice, both times value 0" whereas the compiler
has interpreted it completely differently.

Now lets take a look another case. Let's change it a little:

volatile int x;
volatile int *y = &x; // y points to volatile int x

*y = *y = 0;

Given the code generated above, you'd expect a write of *y, a read of *y,
and a write of *y, yes? 'y' is not volatile, therefore y's value does not
change during the execution of this statement and *is* constant. But the
code?

mov eax, DWORD PTR _y
mov DWORD PTR [eax], 0
mov ecx, DWORD PTR _y
mov DWORD PTR [ecx], 0

Holy crap! Two writes to *y, both of zero, and a read has been
eliminated! Why did the compiler do this?

Ok, let's give the compiler the benefit of the doubt that it got confused
about pointers--perhaps they're special in the case of "volatile" (they
are not!). How about using C++ and references which just allow me to use
synonyms?

volatile int x;
volatile int &y = x; // y is another name for volatile int x

y = y = 0;
x = x = 0;

mov eax, DWORD PTR ?y@@3ACHC
mov DWORD PTR [eax], 0
mov ecx, DWORD PTR ?y@@3ACHC
mov DWORD PTR [ecx], 0
mov DWORD PTR ?x@@3HC, 0
mov edx, DWORD PTR ?x@@3HC
mov DWORD PTR ?x@@3HC, edx

Again, the principle of least astonishment is broken. Blimey. Ok,
perhaps the compiler confused global references and pointers. Let's shove
it into a function:

Let's use reference parameters:

volatile int x;

void set_zero_twice(volatile int &y)
{
y = y = 0;
}

void main(void)
{
set_zero_twice(x);
}

C15 generates this:

set_zero_twice:
mov eax, DWORD PTR _y$[esp-4]
mov DWORD PTR [eax], 0
mov DWORD PTR [eax], 0
ret 0

main: // inlined!
xor eax, eax
mov DWORD PTR ?x@@3HC, eax
mov DWORD PTR ?x@@3HC, eax

Flip. Final try:

void
main(void)
{
volatile int &y = x; // y is a synonym for x by the laws of C++,
y = y = 0; // for all intents and purposes, 'y' is 'x'
x = x = 0;
}

xor eax, eax
mov DWORD PTR ?x@@3HC, eax
mov DWORD PTR ?x@@3HC, eax
; Line 8
mov DWORD PTR ?x@@3HC, eax
mov eax, DWORD PTR ?x@@3HC
mov DWORD PTR ?x@@3HC, eax

Now, I challenge *anybody* to explain why volatile' behaves differently in
*this* case using those two "identical" statements.

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
CrossWorks V2 is out for LPC1700, LPC3100, LPC3200, SAM9, and more!
Reply by finefrenzyrolling November 16, 20092009-11-16
Thanks for all the feedback.
Half of me wants to figure out why the code worked at all with IAR.

I take it Crossworks is considered a more strict compiler and IAR is a bit looser in what it lets you get away with? Perhaps more experienced hands than I could summarize the differences between the major compiler options as I have not been able to find much in the way of a centralized summary/review(mostly each company website touting their own selling points).

I have not solved all my problems yet but I believe you have given me some insight on the right directions to look.
I am coming from a desktop C++ background expanding another more experienced programmer's code so my understanding of things like volatile and bitwise operations is perhaps not yet as deep as it should be. A compiler that keeps me on the straight and narrow path is probably for the best though right now part of me wants to go back to IAR where it all works(for some reason).

As I have a full crossworks license and a program that has outgrown the free IAR, I shall proceed down the straight and narrow path.
Thanks for all the help.

--- In m..., tim.wade@... wrote:
>
> > -----Original Message-----
> > From: m... [mailto:m...] On Behalf
> > Of Dan Bloomquist
> > Sent: Sunday, 15 November 2009 2:07 AM
> > To: m...
> > Subject: Re: [msp430] IAR project port to Crossworks issue
> > [Wade, Tim (FN) @ Nautronix]
> > As for the:
> >
> > while ((I2CDCTL & I2CBUSY) == TRUE)// Wait for I2C module to go
> > idle
> >
> > That evolved to
> > ((I2CDCTL & I2CBUSY) != 0)
> >
> > What is wrong with a simple?
> > for( ; I2CDCTL & I2CBUSY; )
> > ;
> > Procedural wordiness belongs in the comments, not the code. (IMHO)
>
> [Wade, Tim (FN) @ Nautronix]
> We mostly have C++ programmers and they use the Boolean keyword and it (sometimes) protects them from this "== true" stuff -- they usually go tits up in C where true is basically anything that isn't 0 but not necessarily what you expect it to be. We used to mandate "!= FALSE" instead of "== TRUE" but Dan is probably correct in it being necessary at all...
>

Reply by Jon Kirwan November 16, 20092009-11-16
On Mon, 16 Nov 2009 14:59:43 -0000, you wrote:

>Hi,
>
>> > Anything bitwise-anded with zero is zero. Hence the compiler is
>> > warning you that it is eliminating the read of P3OUT because it's
>> > not necessary and generates:
>> >
>> > P3OUT = 0
>>
>> I'm not sure why the compiler is eliminationg the read of P3OUT. Given
>> P3OUT is a volatile, the compiler shouldn't elliminate the read.
>
>The compiler has proven that it doesn't need the read; this is as much a
>failing of the standard as anything.

But it sure is an interesting case to consider, even if it comes from
accidentally writing code to incorrectly use ! instead of ~.

I'd never considered closely this particular instance. But it is
interesting to think about the case of (volatile_instance_varname & 0)
as part of a conditional expression, which by one set of rules not
only can be pruned away in optimization but might even seem that they
_must be_, because of short-circuit evaluation. Of course, one could
deal with the _must be_ argument by simply pointing out that causing
code to actually execute the subexpression doesn't inhibit applying
short circuit rules, afterwards. So it _could_ still generate
executable code, I suppose.

By one interpretation of the rules of volatile, it should still
produce a read event. And since creating executable code can arguably
still permit short circuit evaluation... just at run-time instead of
compile-time... the question then becomes, "Would a compiler violate
the c standard by _not_ eliminating such a read?"

In other words, Paul, could __you__ personally choose to arrange the
compiler to maintain such volatile accesses and be able to argue
strongly that you still are well within the c standard in doing so?

I'm curious.

(Of course, the OP was using the wrong syntax. But that's merely a
footnote. The question can remain all the same.)

>> Being it volatile, the compiler cannot assume anything about P3OUT, so the
>>compiler
>> cannot assume that eliminating the read operation will have no effect (for
>> example if it were U0RXBUF).
>
>The compiler is telling you that the volatile read is being eliminated; if
>you want to make the read "really read" you need to write maintainable code.

Hehe. There is that.

>> Is this because the compiler knows the real behaviour of P3OUT as
>different
>> from a 'general volatile'? Or does volatile only apply to an access of the
>> variable (address), no matter if that access is a read or write operation?
>> Even so, a read followed by a write are 2 accesses which is different than
>> just one.
>
>I believe what our compiler is doing is within the bounds of the standard;
>given customers cannot use const correctly, don't know how to use volatile
>correctly, and can't write straightforward code, the warning is of little
>consequence in this instance.

You mean you can't __read between the c lines__ and figure out what
the programmer __really__ wanted to do?? ;) It's time for another
good, ground-breaking research paper in compiler theory, I suspect!

Jon
Reply by Paul Curtis November 16, 20092009-11-16
Hi,

> > Anything bitwise-anded with zero is zero. Hence the compiler is
> > warning you that it is eliminating the read of P3OUT because it's
> > not necessary and generates:
> >
> > P3OUT = 0
>
> I'm not sure why the compiler is eliminationg the read of P3OUT. Given
> P3OUT is a volatile, the compiler shouldn't elliminate the read.

The compiler has proven that it doesn't need the read; this is as much a
failing of the standard as anything.

> Being it volatile, the compiler cannot assume anything about P3OUT, so the
compiler
> cannot assume that eliminating the read operation will have no effect (for
> example if it were U0RXBUF).

The compiler is telling you that the volatile read is being eliminated; if
you want to make the read "really read" you need to write maintainable code.

> Is this because the compiler knows the real behaviour of P3OUT as
different
> from a 'general volatile'? Or does volatile only apply to an access of the
> variable (address), no matter if that access is a read or write operation?
> Even so, a read followed by a write are 2 accesses which is different than
> just one.

I believe what our compiler is doing is within the bounds of the standard;
given customers cannot use const correctly, don't know how to use volatile
correctly, and can't write straightforward code, the warning is of little
consequence in this instance.

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
CrossWorks V2 is out for LPC1700, LPC3100, LPC3200, SAM9, and more!

Reply by Michael November 16, 20092009-11-16
Hello Paul,
I've a question about your recent reply:
> (...)
> Consider what you are writing.
>
> P3OUT &= !(0xFE)
>
> This is:
>
> P3OUT = P3OUT & !(0xFE)
>
> As !0xFE is zero, I get:
>
> P3OUT = P3OUT & 0
>
> Anything bitwise-anded with zero is zero. Hence the compiler is
> warning you that it is eliminating the read of P3OUT because it's
> not necessary and generates:
>
> P3OUT = 0

I'm not sure why the compiler is eliminationg the read of P3OUT. Given P3OUT is a volatile, the compiler shouldn't elliminate the read. Being it volatile, the compiler cannot assume anything about P3OUT, so the compiler cannot assume that eliminating the read operation will have no effect (for example if it were U0RXBUF).
Is this because the compiler knows the real behaviour of P3OUT as different from a 'general volatile'? Or does volatile only apply to an access of the variable (address), no matter if that access is a read or write operation? Even so, a read followed by a write are 2 accesses which is different than just one.

Regards,
Michael K.

--- In m..., "Paul Curtis" wrote:
>
> Hi,
>
> > "result of '==' is always zero"
> > referring to this line:
> >
> > while ((I2CDCTL & I2CBUSY) == TRUE)// Wait for I2C module to go idle
> >
> > As best I can see, it would only give this warning if I2CDCTL is static
> > since I2CBUSY, and of course TRUE are both constants.
>
> Assume I2CBUSY is 0x20 (which it is for 14x/16x) and TRUE is 1. Then
> I2CDCTL & I2CBUSY is either 0x20 or 0 which is never equal to 1. The
> compiler may have rewritten the expression in some way, rotating the test to
> the bottom (not uncommon); however, it's telling you that there is something
> wrong with your expression.
>
> > I am wondering if
> > the compiler skips this comparison since it believes the statement to
> > always be zero and, hence, breaks my I2C code.
>
> I believe that you need to look at the definition of TRUE (what value is
> it?) and I2CBUSY (I believe it is 0x20). If this is the case, then your
> code doesn't do what you think it's doing and the compiler is 100% right to
> warn you about it.
>
> > as I understand it sfrb is a shorthand for "volatile unsigned char" so the
> > difference between these definitions eludes me. Attempts to use the DEFC
> > macro in the CrossStudio .h file made the compiler very unhappy.
>
> Of course.
>
> > Also, the warning,"reference to 'volatile unsigned char' removed" was
> given
> > for this line:
> > P3OUT &= !(0xFE);
> > which is similarly defined as
> > #define P3OUT_ (0x0019) /* Port 3 Output */
> > sfrb P3OUT = P3OUT_;
> >
> > I think I am not understanding something about 'volatile unsigned char' in
> > crossworks. Anyone know how I am going wrong here?
>
> Consider what you are writing.
>
> P3OUT &= !(0xFE)
>
> This is:
>
> P3OUT = P3OUT & !(0xFE)
>
> As !0xFE is zero, I get:
>
> P3OUT = P3OUT & 0
>
> Anything bitwise-anded with zero is zero. Hence the compiler is warning you
> that it is eliminating the read of P3OUT because it's not necessary and
> generates:
>
> P3OUT = 0
>
> You know, I think you should (and here we go in capitals for emphasis)
> REALLY LOOK AT YOUR CODE BECAUSE I THINK CROSSWORKS IS TELLING YOU SOMETHING
> USEFUL HERE.
>
> --
> Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
> CrossWorks V2 is out for LPC1700, LPC3100, LPC3200, SAM9, and more!
>