EmbeddedRelated.com
Forums

Code execution Speed (Rowley vs CC)

Started by Richard May 25, 2008
Hi!

As a compiler writer, I find that using "volatile" on a local variable
is 100% pointless. The reason is that even though the standard says that
the compiler should expect the value to be modified by "someone else",
it is free to place it anywhere it likes, eliminating the possibility of
outside access.

For example, people here have debated whether it should be placed on the
stack or in a register. Well, there are many more options, it could be
combined with a pointer and simply be eliminated.

The locations where the volatile keyword do make sense is for global
variables and as pointer attributes.

-- Anders Lindgren, IAR Systems

Veronica Merryfield wrote:
> Consider a function foo
>
> void foo (void)
> {
> volatile int ix;
>
> /* some code using ix */
> }
>
> is it wrong for the compiler to use a register in this context? The
> first ANSI standard says "the purpose of volatile is to force an
> implementation to suppress optimization that could otherwise occur".
> The standard does not stipulate what resources are to be used or not
> used in an implementation for automatic variables simply that they
> exist for the duration of the block within which they are declared. It
> is far from saying don't make assumptions but rather is actually
> directing an implementer very carefully. I therefore move that an
> automatic variable declared volatile could use a register and conform
> to the standard.
--
Disclaimer: Opinions expressed in this posting are strictly my own and
not necessarily those of my employer.

Beginning Microcontrollers with the MSP430

John,

> This is an EXPLICIT simple black and white proof, with additonal
> comments, that Rowley is not standards conformant with regard to use
> of the the word volatile.
>
> The proof appears banal, however it is a valid proof and it is in the
> appropriate style of a valid proof.
>
> The standard requires a volatile qualified object may be modified in
> ways unknown. This requires a compiler allows an object to be
> modified in ways unknown.

This is not a proof. It's a lot of hand waving and misdirection without
reference to standards with flawed reasoning. The first "requires"
(implication) is all wrong.

Let me restate this to demonstrate the flawed reasoning with something
concrete that we can all relate to.

Let's choose "Weather" for "volatile object". That's a good model, we know
that weather changes outside our control. Now let's substitute "I" for "the
compiler", both being things that deal with volatile objects changing.

Take John's statement:

"A volatile object may be modified in ways unknown. This requires a
compiler allows an object to be modified in ways unknown."

Restating:

"The weather changes in ways unknown. This requires I allow the weather to
be changed in ways unknown."

You can clearly see the nonsense in this logic. A compiler, or my free
will, has no influence on binding the behaviour of the volatile object or
the weather, it only needs to deal with the consequences of things changing.
All "volatile" means is that "it may change" not that "I must go out of my
way to allow it to change". THESE ARE TWO COMPLETELY INDEPENDENT STATEMENTS
THAT JOHN LINKED WITH AN IMPLICATION.

It just isn't so. This is basic logic, taught in sixth form or first year
of university.

Even more concrete:

Consider the following:

volatile char x @ 0xF00; // using a common extension, you get the idea...

void wait_for_change(void)
{
char old_x = x;
while (old_x != *x) ;
}

Ok, we have a volatile object in 'x'. It might change, and
wait_for_change() knows it might change. Now, according to Jon, the
compiler "must allow" x to change. How come? There's no way in the world
that x is going to change, it's in ROM. The compiler cannot arrange for "x"
to be modifiable, no matter how hard it tries.

John, your proof is shown for the sham that it is. You would not score any
marks in an exam for this proof.

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
CrossWorks for ARM, MSP430, AVR, MAXQ, and now Cortex-M3 processors

I've been following this discussion with much interest. I don't know
much about compilers, but I proud myself of being very good at
understanding what a sentence really says, and I just couldn't let
this one passthere is no way I would let this one pass.

There is no way that the standards wording of "An object that has
volatile-qualified type may be modified in ways unknown to the
implementation or have other unknown side effects." means "This
requires a compiler allows an object to be modified in ways unknown.".

What it says is that the compiler has to be aware that the object
'MAY' change at any given time. This only means that the compiler
cannot assume the objects value is the same between two instructions.
For example, the object migh be the count of a read-only hardware
timer and there would be no way to change its value no matter how hard
the compiler or the programmer would want it to.

I agree with Paul that having a local automatic volatile variable
makes no sense. If it's automatic, then the compiler has to choose
where to put that variable because the programmer doesn't care where
its placed and it's only alive during the execution of the function
it's declared in. This means the program writer has no idea where the
variable is and the compiler has no idea what the variables value may
be. I have no clue of what use such a variable might be, other than an
easy (lazy?) way to implement a delay routine which will be totally
compiler (and probably optimization-level) dependant. If anyone has an
idea, please enlighten me.

If one joins a discussion one has to be aware one might make a mistake
or just be wrong an be mature enought to accept being corrected.

John, if there has being bullying around, you have been carrying the
flag and make sure it's not dropped. Don't take each and every comment
of people trying to contribute as a personal attack to you and please
try to focus on the topic at hand. Your comments about Rowley v/s GCC
where totally inapropiate and off topic.

Michael K.

>
> This is not a proof. It's a lot of hand waving and misdirection without
> reference to standards with flawed reasoning. The first "requires"
> (implication) is all wrong.
>
> Let me restate this to demonstrate the flawed reasoning with something
> concrete that we can all relate to.
>
> Let's choose "Weather" for "volatile object". That's a good model,
we know
> that weather changes outside our control. Now let's substitute "I"
for "the
> compiler", both being things that deal with volatile objects changing.
>
> Take John's statement:
>
> "A volatile object may be modified in ways unknown. This requires a
> compiler allows an object to be modified in ways unknown."
>
> Restating:
>
> "The weather changes in ways unknown. This requires I allow the
weather to
> be changed in ways unknown."
>
> You can clearly see the nonsense in this logic. A compiler, or my free
> will, has no influence on binding the behaviour of the volatile
object or
> the weather, it only needs to deal with the consequences of things
changing.
> All "volatile" means is that "it may change" not that "I must go out
of my
> way to allow it to change". THESE ARE TWO COMPLETELY INDEPENDENT
STATEMENTS
> THAT JOHN LINKED WITH AN IMPLICATION.
>
> It just isn't so. This is basic logic, taught in sixth form or
first year
> of university.
>
> Even more concrete:
>
> Consider the following:
>
> volatile char x @ 0xF00; // using a common extension, you get the
idea...
>
> void wait_for_change(void)
> {
> char old_x = x;
> while (old_x != *x) ;
> }
>
> Ok, we have a volatile object in 'x'. It might change, and
> wait_for_change() knows it might change. Now, according to Jon, the
> compiler "must allow" x to change. How come? There's no way in the
world
> that x is going to change, it's in ROM. The compiler cannot arrange
for "x"
> to be modifiable, no matter how hard it tries.
>
> John, your proof is shown for the sham that it is. You would not
score any
> marks in an exam for this proof.
>
> --
> Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
> CrossWorks for ARM, MSP430, AVR, MAXQ, and now Cortex-M3 processors
>

Hi!

Ing.Antonio Morra wrote:

> I just tested this on the IAR compiler.
> It does allocate the variable in memory : xx(sp) .
> It will do so even if the variable x is defined as REGISTER volatile .
> This is with the no-optimization choice.

In a way I should be flattered, as it seems as though you are using the
IAR compiler as the source of truth.

In this case, however, you can not draw that conclusion. We place
volatile variables on the stack for a number of reasons, non of which
are really good:

* That is what people expect.

* That is how we always have treated them.

* It allows our assembler-level optimizer to do all of its tricks (and
it has a lot of them) on all code, without having to check every single
register access for volatileness. (Basically, it makes the compiler more
robust.)

* Finally, our goal is to generate really good code for well-written
programs. A program that uses volatile autos does not fall into this
category.

In my book, Paul is doing the Right Thing in the Rowley compiler!

-- Anders Lindgren, IAR Systems

Ps. The "register" keyword, by the way, is another dead-in-the-water
duck whose best-before date expired somewhere around 1985. We simply
ignore it, just like basically all modern compilers do.

--
Disclaimer: Opinions expressed in this posting are strictly my own and
not necessarily those of my employer.

On Fri, 2008-05-30 at 14:59 +0000, tintronic wrote:

> I agree with Paul that having a local automatic volatile variable
> makes no sense. If it's automatic, then the compiler has to choose
> where to put that variable because the programmer doesn't care where
> its placed and it's only alive during the execution of the function
> it's declared in. This means the program writer has no idea where the
> variable is and the compiler has no idea what the variables value may
> be. I have no clue of what use such a variable might be, other than an
> easy (lazy?) way to implement a delay routine which will be totally
> compiler (and probably optimization-level) dependant. If anyone has an
> idea, please enlighten me.

I agree with both of you.

If you have an automatic variable there is no way the outside function
will know where it is.

If it puts it on the stack, then it depends on what called the function
as to where on the stack it resides. That is no different than putting
it in a register. In either case the outside routine can not get to it.

It only makes sense if the volatile variable was in a static RAM
location where it will always be in the same memory location from start
to finish.

By the way there is no magic in any of this. You can't do it any other
way.

Kip
--
Kipton Moravec KE5NGX
"Always do right; this will gratify some people and astonish the rest."
--Mark Twain

On Fri, 30 May 2008 11:27:43 +0200, Anders wrote:

>As a compiler writer, I find that using "volatile" on a local variable
>is 100% pointless. The reason is that even though the standard says that
>the compiler should expect the value to be modified by "someone else",
>it is free to place it anywhere it likes, eliminating the possibility of
>outside access.
>
>For example, people here have debated whether it should be placed on the
>stack or in a register. Well, there are many more options, it could be
>combined with a pointer and simply be eliminated.
>
>The locations where the volatile keyword do make sense is for global
>variables and as pointer attributes.

I have to tentatively disagree with this, since the c standard
explicitly discusses the automatic variable case in the context of
setjmp(), if I'm reading it correctly.

Jon

Jon,

> >The locations where the volatile keyword do make sense is for global
> >variables and as pointer attributes.
>
> I have to tentatively disagree with this, since the c standard
> explicitly discusses the automatic variable case in the context of
> setjmp(), if I'm reading it correctly.

This is the one case where volatile on auto makes sense. However, whether
volatile autos are put in registers or held on the stack is a choice of the
implementation of the compiler code generator and its tightly-coupled
setjmp/longjmp implementation.

Regards,

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
CrossWorks for ARM, MSP430, AVR, MAXQ, and now Cortex-M3 processors

On Thu, 29 May 2008 23:40:03 -0000, John wrote:

>You just don't seem to get it. Whether some of your comments were
>passing or not, there were good grounds to belive you were joining in
>the bullying.
>
>No I was not polite in my response to your passing amateurish remarks
>but I was certainly not rude or poorly behaved.
>
>Don't expect politeness if you attack. If you have comments of a
>factual nature and expect a polite response, then keep them factual,
>which you have certainly failed to do now.

You've obviously (1) no apparent clue where I was coming from in my
first post and (2) probably didn't even read it with understanding and
(3) seem to imagine everyone is out to get you and (4) have been
consistently wrong on almost every instance of your writing on this
point and (5) cannot seem to recognize the obvious when it is laid out
in fine detail for you.

Don't be surprised if, considering the source, I don't take your "you
just don't seem to get it" with any force.

My first post set aside your thrust, which is dead wrong on its face
and is based on a bizarrely selective choice in the facts you consider
and instead I offered an option you might use instead to save
yourself. I doubt you even read it. Certainly, not with any care.

You preference to abuse people instead of carefully considering the
ground you stand on is manifest. If there is anyone who has earned
the name 'bully' it is you. I suggest you look in a mirror.

In the meantime, you've been also presented ample rebuttals as well
as, in the case of my first post on this subject, an alternative you
might consider in criticizing code generation.

There is no flaw in selecting a register versus a stack location
within an activation record. Compilers are free to change automatic
variables to register if their addresses aren't taken. Volatile,
applied to automatic variables, has an intended use -- usually for
cases of setjmp(). But that isn't about register vs stack.

You are struggling against your own preconceived notions. That's no
one else's problem.

Jon

On Fri, 30 May 2008 18:52:48 +0100, Paul wrote:

>Jon,
>
>> >The locations where the volatile keyword do make sense is for global
>> >variables and as pointer attributes.
>>
>> I have to tentatively disagree with this, since the c standard
>> explicitly discusses the automatic variable case in the context of
>> setjmp(), if I'm reading it correctly.
>
>This is the one case where volatile on auto makes sense. However, whether
>volatile autos are put in registers or held on the stack is a choice of the
>implementation of the compiler code generator and its tightly-coupled
>setjmp/longjmp implementation.
>
>Regards,

Indeed. I didn't mean to imply anything otherwise, too.

By the way, did you look at my thoughts on the number of reads and
writes performed in the example case I discussed? I'm curious about
your response to that tiny point.

Thanks,
Jon

On Fri, 30 May 2008 11:27:43 +0200, Anders wrote:

>I find that using "volatile" on a local variable is 100% pointless.

Consider:

#define EXCEPTENTERED 0
#define EXCEPTRAISED 1
#define EXCEPTHANDLED 2
#define EXCEPTFINALIZED 3

#define TRY do { \
volatile int exceptflag; \
exceptframe_t exceptframe; \
exceptframe.prev= pexceptstack( ); \
psetexceptstack( & exceptframe ); \
exceptflag= setjmp( exceptframe.env ); \
if ( exceptflag == EXCEPTENTERED ) {

In the above case, I'm illustrating some code I actually use for
handling per-thread exceptions under c and with a small operating
system I've written.

An exception try-block might look like:

TRY
try-block of code
EXCEPT( e1 )
code for the 'e1' type of exception
EXCEPT( e2 )
code for the 'e2' type of exception
ELSE
code for all other exceptions
ENDTRY;

Or,

TRY
try-block of code
EXCEPT( e1 )
code for the 'e1' type of exception
EXCEPT( e2 )
code for the 'e2' type of exception
ELSE
RERAISE;
ENDTRY;

Sometimes, it is desirable to perform a function return within the
try-block handling section. If so, use the RETURN macro,

TRY
try-block of code
EXCEPT( e1 )
some code for the 'e1' type of exception
RETURN 0;
ELSE
RERAISE;
ENDTRY;

I use the following two simple structures:

typedef struct except_s {
char *reason; /* user-defined exception message */
} except_t;
typedef struct exceptframe_s exceptframe_t;
typedef struct exceptframe_s {
exceptframe_t *prev;
jmp_buf env;
const except_t *exception;
const char *file;
int line;
} exceptframe_t;

The exceptframe_t structure includes a file and line number that comes
from the following:

#define RAISE(e) exceptraise( &(e), __FILE__, __LINE__ )

The function exceptraise() accepts those values and stuffs the
structure, accordingly, so that if there is no enclosing TRY block,
that some kind of error message can be displayed that is meaningful.

I can provide the other interesting details, such as the macros I use
for all of the above (RETURN, EXCEPT, ENDTRY and so on.) But I think
this gets the idea across. The use of 'volatile' in TRY is fairly
important here.

Jon