Reply by Anders Lindgren June 3, 20082008-06-03
Hi Veronica!

> This is departing from a standards conformance C compiler
> implementation of volatile automatics discussion into a language
> extension for embedded programming discussion. They are different
> issues.

The issues are very much connected. In fact, I consider it to be
impossible to write a program that requires sensitive timing, and expect
it to work with any standard-conforming compiler, using only standard C.

On the other hand, a compiler that provides extra features does not
automatically become non-standard compliant.

What I really do object against is the argument that has been put
forward that can be summarized as:

"since writing a loop with a volatile auto variable is the only way
to do a delay in standard C, then all compiler *must* compile this into
code that takes a specified amount of time."

This simply does not work, in practice. Standard C has no concept of
time or delays. For example, on the IAR compiler we store the variable
on the stack, Rowley store it in a register, which make a big difference
when it comes to timing. If you look at it even further, the register
pressure could force the variable onto the stack, which would really
kill all attempts to creating a fine-tuned delay.

Hence, if it is possible to optimize away any construct such as a loop,
while sticking to the rules, I, as a compiler developer, will gladly do so!

However, in this particular case, I still consider it to be an open
issue whether or not it really is legal to optimize away the loop in
question.
A similar example is how the MSP430 handles low-power-mode, where an
interrupt routine modifies the value that the status register later
should be restored to. In the beginning, our compiler had no direct
support for this and programmers tried to change the value by measuring
the amount of data on the stack, and modified the value based on this.
Of course, the compiler could generate different stack offset for
thousands of reasons (different optimization level, new compiler
version, changes in user code), making this a very fragile solution.

The solution for this situation was to provide the intrinsics
__xxx_SR_register_on_exit, since this clearly is a situation that can
not be handled by standard C.
> > In my opinion, a program that relies on the fact that a compiler would
> > generate a specific code sequence is broken.

> An interesting assertion. Off the top of my head, does this mean
> Windows COM and Symbian OS are broken? Both rely on the compiler to
> generate a specific code sequence to make interfaces work. I know both
> these examples are outside the remit of this list, but your assertion
> is pretty broad.

The compiler has made a "contract" with the outside world that the
generated code should follow certain basic rules. The rules are
specified by the C standard, the calling convention, rules for C objects
named to assembler labels, and, in C++, name mangling and object layout,
etc.

As I said earlier, I consider that global variables to be part of the
contract, but local variables are not.

A specific compiler can, in addition, promise more than the standard
requires it to do. I am not familiar with the examples you provided, but
either they only use the standard conventions, or they can be seen as
tightly coupled with the compiler.

I still consider a program to be broken if it relies on anything that
falls outside the agreed conventions. (By "broken" I mean that if you
test it with a bunch of different compiler, you will eventually find one
where the program doesn't run correctly, even though the compiler
follows the standard.)
> How does this affect EABI specifications? Are they a
> product of broken programming too?

Of course not, they are part of the "contract" that an EABI-compilant
compiler promises to fulfill.

-- Anders Lindgren, IAR Systems
--
Disclaimer: Opinions expressed in this posting are strictly my own and
not necessarily those of my employer.

Beginning Microcontrollers with the MSP430

Reply by Veronica Merryfield June 2, 20082008-06-02
Hi Anders

On 2-Jun-08, at 1:56 AM, Anders Lindgren wrote:
> > > * 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.
> > > Veronica Merryfield wrote:
>
> > Whilst you could argue this to be true, are you really in a position
> > to make this call.
>
> I do believe I am. (As a senior compiler developer at IAR, it is my
> job
> to make calls like this.)
>
Whilst what you wrote below is often the case and may be all the use
of volatile automatics that you see are for delay loops, and whilst
many might agree that such use is not well written code, although many
use such code, as a compiler writer I don't think you can assume that
all volatile automatics are for that purpose nor that all are examples
of poorly written code. Of course a compiler writer does not have to
produce a standards conformant compiler if they do not wish but they
should not claim that their compiler is should they wish to drop
conformance to a standard (and I am not saying that IAR or other
compiler makers do or don't here).
> > If the coder wishes to use volatile for an
> > automatic, there is nothing in the ISO spec that says they can't.
> Give
> > you talked above about what people expect, people use volatile on
> > automatics to stop empty loops being optimsed away. If you do not
> > honor the volatile qualifier then you have to provide another
> > mechanism to allow it, do you not, which is likely not standard
> > conformant where as the use of volatile is.
>
> The problem with the C programming language is that it does not ever
> talk about the "time" aspect of different constructs.
>
> There is no way, in standard C, to do a delay of a specified amount
> of time.
>
> Most people create for loops to do this, using trial and error to
> find a
> suitable upper bound. When they change tool chain, the version of the
> tools, or simply change their program suddenly their well-tuned loop
> goes out the window.
>
> All tools for the embedded market has adopted the language to the need
> of the customers, for example, they support intrinsic and interrupt
> functions, direct access to memory-mapped peripheral units etc. In
> that
> spirit, it is also natural to provide a mechanism for handling time
> delays, which is done in many products using intrinsic functions like
> __delay_cycles().
>
This is departing from a standards conformance C compiler
implementation of volatile automatics discussion into a language
extension for embedded programming discussion. They are different
issues.
>
> In my opinion, a program that relies on the fact that a compiler would
> generate a specific code sequence is broken.
>
An interesting assertion. Off the top of my head, does this mean
Windows COM and Symbian OS are broken? Both rely on the compiler to
generate a specific code sequence to make interfaces work. I know both
these examples are outside the remit of this list, but your assertion
is pretty broad. How does this affect EABI specifications? Are they a
product of broken programming too?

However, I am sure you meant in the confines of the use of a volatile
automatic, or at least I hope you did. I know this is a MSP430 list
but we are discussing volatile automatics and standards conformance,
which is a broad subject as is embedded programming.
> -- Anders Lindgren, IAR Systems
> --
> Disclaimer: Opinions expressed in this posting are strictly my own and
> not necessarily those of my employer.
>
Reply by Anders Lindgren June 2, 20082008-06-02
Hi Veronica!

I Wrote:
> > * 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.
> >

Veronica Merryfield wrote:

> Whilst you could argue this to be true, are you really in a position
> to make this call.

I do believe I am. (As a senior compiler developer at IAR, it is my job
to make calls like this.)
> If the coder wishes to use volatile for an
> automatic, there is nothing in the ISO spec that says they can't. Give
> you talked above about what people expect, people use volatile on
> automatics to stop empty loops being optimsed away. If you do not
> honor the volatile qualifier then you have to provide another
> mechanism to allow it, do you not, which is likely not standard
> conformant where as the use of volatile is.

The problem with the C programming language is that it does not ever
talk about the "time" aspect of different constructs.

There is no way, in standard C, to do a delay of a specified amount of time.

Most people create for loops to do this, using trial and error to find a
suitable upper bound. When they change tool chain, the version of the
tools, or simply change their program suddenly their well-tuned loop
goes out the window.

All tools for the embedded market has adopted the language to the need
of the customers, for example, they support intrinsic and interrupt
functions, direct access to memory-mapped peripheral units etc. In that
spirit, it is also natural to provide a mechanism for handling time
delays, which is done in many products using intrinsic functions like
__delay_cycles().

In my opinion, a program that relies on the fact that a compiler would
generate a specific code sequence is broken.

-- Anders Lindgren, IAR Systems
--
Disclaimer: Opinions expressed in this posting are strictly my own and
not necessarily those of my employer.

Reply by Ken Rowberry June 1, 20082008-06-01
The other important use of a volatile is to keep the compiler from
optimizing it away. This is useful during debugging. It's invasive
but you can somewhat debug optimized code.

--- In m..., Veronica Merryfield
wrote:
>
> Exception handling is the most important use of volatile but there
are
> other ways to implement it. Exception handling can get complicated
> hence why I haven't used it as an example but it is good to see
this
> posted.
>
> On 30-May-08, at 11:19 AM, Jon Kirwan wrote:
>
> > 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
>
Reply by Veronica Merryfield May 30, 20082008-05-30
From memory now, GCC and many other compilers I have looked at
generate different code for switches depending on the data set.

Where the data is spread out, the code is usually a series of
if...then...else like constructs. If the data is contiguous and there
is more than some number of entries, it will produce a jump table. The
number of entries is usually determined to make a break from
if...then...else to a table based on the code space or cycles. You
also find a combination used.

Many moons ago I once saw a two entry table of values against
addresses but this was eithe ran older 68K compiler using a special
table lookup instruction or it was from an Aztec compiler for a Z80
but I've not seen this style in the last 10 years, not that it means
it isn't out there.

For anyone interest, compile some test code and see what you get. I
have this many times to look at what compilers do as part of a
selection process or to determine how to code thing to work with a
compiler.
On 30-May-08, at 4:12 PM, Paul Curtis wrote:

> --- In m..., "John Heenan" wrote:
> >
> > With regard to 'jump tables'. Both CCE and IAR provide KNOWN ways to
> > generate jump tables. On enquiry Rowley was dismissive. If there was
> > a way of generating jump tables they weren't going to tell us.
> Rather
> > odd given that the MSP430 has some interrupt facilities that are
> > ideally suited to jump table use, aside from the enormous general
> > benefits of jump tables.
> >
> > I did notice that a listing of ARM assembly code from C from the
> OPEN
> > SOURCE compiler USED by Rowley, that was posted on another group,
> did
> > produce a jump table. I was impressed and said this on the group.
>
> That would be this one here then...
>
> http://tech.groups.yahoo.com/group/lpc2000/message/10755
>
> ...from which I quote directly:
>
> > I am impressed GCC for ARM looks to use genuine jump tables.
> > This is how the code worked in an assembly listing.
> > A branch to a jump table was made if the value passed in was between
> > the minimum and maximum case values. This took only three
> instructions:
> > sub... ;subtract minimum from value passed in
> > cmp... ;compare result with maximum-minimun constant value
> > ldrls pc,... ;if result is less than maximum-minimum then use result
> > as as an index value into a table to determine where to branch to
> next
>
> Well, I chucked some old code I presented to this group into GCC and
> reproduced that
> "jump table" template, you must agree:
>
> ldr r3, .L10 ; &i
> ldr r3, [r3, #0] ; r3 = ii
> sub r3, r3, #1
> cmp r3, #3
> ldrls pc, [pc, r3, asl #2]
> b .L9
> .L7:
> .word .L3
> .word .L4
> .word .L5
> .word .L6
> .L3:
>
> Here's the program I compiled with -O1:
>
> int i;
>
> int foo(void)
> {
> switch (i)
> {
> case 1: i += 1; break;
> case 2: i += 2; break;
> case 3: i += 3; break;
> case 4: i += 4; break;
> }
> }
>
> CrossWorks generates the same damn thing. The MSP430 doesn't have
> predicated
> instructions or a shift capability in the addressing mode so it must
> use flow control and
> ALU computation instead:
>
> MOV.W &_i, R15
> SUB.W #1, R15
> CMP.W #4, R15
> JC @0
> ADD.W R15, R15
> BR @1(R15) ; Emulated Insn: MOV @1(R15), PC
> @1
> DW @2
> DW @3
> DW @4
> DW @5
>
> And what's more, I presented this implementation to you here, three
> years ago:
>
> http://tech.groups.yahoo.com/group/msp430/message/17099
>
> As you have stated that GCC generates jump tables, and I have
> presented evidence that
> CrossWorks C for MSP430 generates, within the bounds of the
> architecture, equivalent
> code, we are drawn to the inexorable conclusion that CrossWorks C
> generates jump tables
> too. It's inescapable. But this is not new evidence.
>
> I would just like to set the record straight as you do when you say
> facts are altered. Well
> John, I feel you rewrote history to suit you. I believe you have
> willfully misrepresented my
> position and the abilities and conformance of the compiler and code
> generator I wrote.
> And you clearly have no defense over the jump table issue.
>
> Of all the posts you have made on subjects I know nothing of, I have
> never passed
> comment. How can I? I would be less than an amateur in those fields.
> However, your
> position is one where you believe you know the ISO standard better
> than I, somebody who
> has been deeply involved in implementing language translation
> systems and embedded
> systems for 25 years now. You say that my compiler is outside
> "industry expectations,"
> yet industry expectations here clearly do not align with your views.
> Your position does not
> change, and you will not concede defeat gracefully when demonstrated
> incorrect.
>
> -- Paul.
>


Reply by Paul Curtis May 30, 20082008-05-30
--- In m..., "John Heenan" wrote:
>
> With regard to 'jump tables'. Both CCE and IAR provide KNOWN ways to
> generate jump tables. On enquiry Rowley was dismissive. If there was
> a way of generating jump tables they weren't going to tell us. Rather
> odd given that the MSP430 has some interrupt facilities that are
> ideally suited to jump table use, aside from the enormous general
> benefits of jump tables.
>
> I did notice that a listing of ARM assembly code from C from the OPEN
> SOURCE compiler USED by Rowley, that was posted on another group, did
> produce a jump table. I was impressed and said this on the group.

That would be this one here then...

http://tech.groups.yahoo.com/group/lpc2000/message/10755

...from which I quote directly:

> I am impressed GCC for ARM looks to use genuine jump tables.
> This is how the code worked in an assembly listing.
> A branch to a jump table was made if the value passed in was between
> the minimum and maximum case values. This took only three instructions:
> sub... ;subtract minimum from value passed in
> cmp... ;compare result with maximum-minimun constant value
> ldrls pc,... ;if result is less than maximum-minimum then use result
> as as an index value into a table to determine where to branch to next

Well, I chucked some old code I presented to this group into GCC and reproduced that
"jump table" template, you must agree:

ldr r3, .L10 ; &i
ldr r3, [r3, #0] ; r3 = ii
sub r3, r3, #1
cmp r3, #3
ldrls pc, [pc, r3, asl #2]
b .L9
.L7:
.word .L3
.word .L4
.word .L5
.word .L6
.L3:

Here's the program I compiled with -O1:

int i;

int foo(void)
{
switch (i)
{
case 1: i += 1; break;
case 2: i += 2; break;
case 3: i += 3; break;
case 4: i += 4; break;
}
}

CrossWorks generates the same damn thing. The MSP430 doesn't have predicated
instructions or a shift capability in the addressing mode so it must use flow control and
ALU computation instead:

MOV.W &_i, R15
SUB.W #1, R15
CMP.W #4, R15
JC @0
ADD.W R15, R15
BR @1(R15) ; Emulated Insn: MOV @1(R15), PC
@1
DW @2
DW @3
DW @4
DW @5

And what's more, I presented this implementation to you here, three years ago:

http://tech.groups.yahoo.com/group/msp430/message/17099

As you have stated that GCC generates jump tables, and I have presented evidence that
CrossWorks C for MSP430 generates, within the bounds of the architecture, equivalent
code, we are drawn to the inexorable conclusion that CrossWorks C generates jump tables
too. It's inescapable. But this is not new evidence.

I would just like to set the record straight as you do when you say facts are altered. Well
John, I feel you rewrote history to suit you. I believe you have willfully misrepresented my
position and the abilities and conformance of the compiler and code generator I wrote.
And you clearly have no defense over the jump table issue.

Of all the posts you have made on subjects I know nothing of, I have never passed
comment. How can I? I would be less than an amateur in those fields. However, your
position is one where you believe you know the ISO standard better than I, somebody who
has been deeply involved in implementing language translation systems and embedded
systems for 25 years now. You say that my compiler is outside "industry expectations,"
yet industry expectations here clearly do not align with your views. Your position does not
change, and you will not concede defeat gracefully when demonstrated incorrect.

-- Paul.

Reply by Veronica Merryfield May 30, 20082008-05-30
On 30-May-08, at 12:47 PM, Jon Kirwan wrote:

> On Fri, 30 May 2008 12:40:52 -0700, Veronica wrote:
>
> >Exception handling is the most important use of volatile but there
> are
> >other ways to implement it. Exception handling can get complicated
> >hence why I haven't used it as an example but it is good to see this
> >posted.
>
> I don't use exception handling in most embedded products. I'm pretty
> judicious about it and must have overwhelming justifications in hand
> before I use it. (I argue ferociously with myself against any
> temptation.) But when it is justified, it's handy.
>
It is rare to see it in small to medium sized embedded product where a
team produces everything. However, some product demand it and
specially where OSes/kernels come into play. They don't have to use
it, but often provide it as do some compiler makers (try catch for
instance).
>
> And I'm glad that the compiler writers work earnestly to support the
> concept for me, by way of supporting setjmp() and longjmp() in the
> library and in the compiler code generator.
>
> (I also provide the tool for other programmers who might be
> interested, perhaps in deep ignorance of what they are risking, in
> using it.)
>
Depends what they are doing. I am sure there is a lot of 'ignorance'
and that may never bite, but on the other hand, it might.

Reply by Veronica Merryfield May 30, 20082008-05-30
On 30-May-08, at 1:00 PM, Antonio Morra wrote:

> At 21.35 30/05/2008, you wrote:
> >Nice to see compiler writers communicating openly :)
>
> This is what we, the customers, do expect.
>
But it doesn't always happen that way. There are some circle where the
competition is fierce and openness is the last thing on the priority
list.
> Above all, there is one most important reason.
> Not all of us (the dirty-coders) do have the possibility to influence
> the BigBoss choice as of what is the best value for a compiler buy.
> So we badly need some "real-world" portability.
> Although IAR choice may be on the conservative side , I greatly
> appreciate it to be so.
> All of this discussion (between the C-Compiler Vips) helped me
> clarify some of my own doubts.
> I never used an automatic volatile variable. I think that I will not
> do that unless some extreme situation arises.
> Hope you get the point.
>
But at least you may be more equipped in this area now.
>
> By the way ... someone willing to open to me a little more on the
> subject of setjump() and similar constructs?
> Just curious ...
> Thanks in advance
>
http://en.wikipedia.org/wiki/Setjmp.h is a pretty good explanation.
Reply by Veronica Merryfield May 30, 20082008-05-30
I was replying to posts where the poster seemed to be talking about
optimsing away automatic volatiles or there being no case to have them
to start with. If I misinterpreted their posts, my sincere apologies.

On 30-May-08, at 12:54 PM, tintronic wrote:

> Hello Veronica.
> I've read your last 4 posts and I'm confused. It seems to me that you
> are talking that compilers should not optimize volatiles away, not
> 'honoring' the volatile declaration. Nobody has said it can.
> The issue being discussed is wether or not a compiler can use a
> register for that volatile.
> Am I misinterpreting you?
>
> Michael K.
>
> --- In m..., Veronica Merryfield
> wrote:
> >
> >
> > On 30-May-08, at 9:29 AM, Anders Lindgren wrote:
> >
> > > 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.
> > >
> > Although true, a compiler writer should not be bound by this.
> > > * That is how we always have treated them.
> > >
> > That's a policy design decision by the tool maker.
> > > * 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.)
> > >
> > It probably makes it simpler hence less test branches hence less
> scope
> > for possible errors hence more robust. An optimizer could deal
> with it.
> > > * 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.
> > >
> > Whilst you could argue this to be true, are you really in a position
> > to make this call. If the coder wishes to use volatile for an
> > automatic, there is nothing in the ISO spec that says they can't.
> Give
> > you talked above about what people expect, people use volatile on
> > automatics to stop empty loops being optimsed away. If you do not
> > honor the volatile qualifier then you have to provide another
> > mechanism to allow it, do you not, which is likely not standard
> > conformant where as the use of volatile is.
> > > In my book, Paul is doing the Right Thing in the Rowley compiler!
> > >
> >
> > Nice to see compiler writers communicating openly :)
>

Reply by Antonio Morra May 30, 20082008-05-30
At 21.35 30/05/2008, you wrote:
>Nice to see compiler writers communicating openly :)

This is what we, the customers, do expect.
Above all, there is one most important reason.
Not all of us (the dirty-coders) do have the possibility to influence
the BigBoss choice as of what is the best value for a compiler buy.
So we badly need some "real-world" portability.
Although IAR choice may be on the conservative side , I greatly
appreciate it to be so.
All of this discussion (between the C-Compiler Vips) helped me
clarify some of my own doubts.
I never used an automatic volatile variable. I think that I will not
do that unless some extreme situation arises.
Hope you get the point.

By the way ... someone willing to open to me a little more on the
subject of setjump() and similar constructs?
Just curious ...
Thanks in advance