----- Original Message -----
From: "Roberto Padovani" <padovan...@gmail.com>
To: "GCC for MSP430 - http://mspgcc.sf.net";
<mspgcc-users@lists.sourceforge.net>
Sent: Monday, July 03, 2006 11:57 AM
Subject: Re: [Mspgcc-users] Code generation question


> Hi David,
>
> criticism is fine....I'll explain my view.
>
> 2006/7/3, David Brown <da...@westcontrol.com>:
> > I don't mean to sound patronising, but I don't think you are aware of
what
> > compilers do, how they work, how "volatile" works, or how to write good
C
> > code for embedded systems.  I'm afraid your post is almost completely
> > incorrect - I hope you take my reply here as constructive critisism to
aid
> > your better understanding.  Thinking about these things is good, and
> > discussing them will refine that thinking.
> >
>
>
> > > knowing how a compiler works in the most unusual situations is always
> > > interesting...and this discussion is no different.
> >
> > That's not only true, but essential to embedded programming.  Knowing
your
> > compiler is vital, including knowing its shortcomings.
>
> up to now, we agreee....
>
> >
> > > however, a compiler is just a machine with a lot of rules, so you
> > > cannot expect it to be "clever" anytime, even if correct code is a
> > > necessity and efficiency is only a plus;
> >
> > You can certainly expect the compiler to be "clever" - the people who
wrote
> > it were clever people, and I have often looked at generated assembly
code
> > and admired neat tricks I hadn't thought of myself.  The aim of the
> > compiler's optimiser is to give you the best generated assembly that has
the
> > same effect as the code you wrote, regardless of the style in which you
> > wrote it.
> [omissis...]
>
> in that sense, compilers are nowadays definitely clever, especially gcc.
> What I meant is that you can always find a way to complicate the input
> to any compiler, so that you'll need still another rule to have it
> take the right decision....do you get the difference? English is not
> my mother language, I hope I'm writing what I'm thinking.
>

Your English is fine - your spelling is probably better than mine.  Your
understanding of how compilers work is not quite right, however.  A compiler
does not pattern match on the input, and use that to determine the output
(unless it is a very simplistic compiler).  The input is analysed into an
abstract tree of some sort, which may then be modified by front-end
optimisations (this part is source-language specific).  Then there are a
number of passes and re-arrangements in the middle (independant of both the
source language and the target).  Then comes the back-end, with the code
generation and target-specific optimisations.  While there is some
communication and co-operation between the parts, in general the abstract
internal tree seen by the backend is not changed by making small
semantically equivilent changes to the source code.

The back-end code generator does work, to some extent, by pattern matching
and generating appropriate code.  But it matches on the internal structures,
not the source code.  So changes like adding extra temporary variables have
no effect on the data seen by the backend (assuming you have at least basic
optimisations enabled - as you normally would).  In this particular case, it
seems that these back-end match rules are not quite right, and an
optimisation rule aimed at generating tight code for volatile accesses is
accidently triggered.

There could, of course, be mistakes in the front-end analysis parts of the
compiler that get triggered by particularly complicated source code.
However, that's not the case here.  Grant's code is not complicated in any
way, and other gcc ports (with the same front end, but different back ends)
have no problems.


>
> > > but in this case, reading the C source code, I honestly can't
> > > understand for sure what it meant....if I were to translate manually
> > > that code into asm, I would have asked a clarification to the
> > > programmer: did you want to sample twice the port and then add these
> > > two samples ? (say for making an average) or did you want two sample
> > > the port once and double that reading ?
> > > IMHO the answer wasn't clear, even if I considered all the volatile
> > qualifiers;
> >
>
> > In that case, you simply don't have the experiance to understand
volatiles
> > properly.  The code was perfectly clear - the port should be sampled
twice,
> > and it's sum taken.  If Grant had wanted to sample it once and double
it, he
> > would have writen "two = 2 * P6IN;".  Of course, in real code the
function
> > and variable names would have given an indication of *why* he was doing
> > this, but the code itself is perfectly clear.
> >
>
> I do know what volatile means and my first thought was that he wanted
> to sample twice; nevertheless, my experience is that way of writing
> code saves 1 line in the source file, but may potentially cause
> headaches in debugging...it's not a good practice to access two
> devices in one line...there's no drawback in splitting it a little
> more and sometimes compilers have more chances to apply the
> optimization rules
>

There are certainly reasons why you might want to seperate the statement
into two lines - for example, if the code had been "two = P6IN + P5IN" and
you wanted to be sure which port was read first, or if you want to
single-step with a debugger but don't fancy assembly-level stepping.  There
are also compilers that can benefit from re-writing your code in different
equivilent ways, because they are not as smart as gcc at optimising.
Typical examples are writing pointer code manually instead of using arrays,
or changing incrementing for loops into decrementing while loops.  A big
advantage of using gcc is that it does a lot of that sort of thing for you,
letting you write your code in the most logical way.

> Oh, except when you're taking part in the IOCCC   :-)
>
> > > so I wouldn't try to add another complicated rule to gcc, but I would
> > > rather write a better C code...an unambiguous one that the "simple"
> > > rules of any compiler can understand.
> > >
> >
> > A C compiler is required to generate correct code for all legal input -
it
> > would be a poor compiler indeed if it required specific simplistic
styles to
> > generate correct code.  What has been uncovered here are two issues -
one is
> > inefficient code (which will be fixed if it can easily be done), and the
> > other is incorrect code (which people are already working on to find a
fix).
> > It may be that in the meantime, people will need to use a workaround to
> > avoid the bug - but that's an exceptional circumstance, not a solution.
>
> I agree
>
> > > for sampling twice:  x = P6IN;   x += P6IN;
> >
> > Why do you thing that is better than "x = P6IN + P6IN" ?  To the
compiler,
> > this is exactly the same (assuming "x" is a local variable), and it
> > generates exactly the same output.  To the writer (and reader) of the C
> > code, it is more verbose without adding any useful information - and
> > therefore worse code.
> >
>
> in the first post, x was not a local variable
>

If x is a global variable, then splitting the access will normally produce
larger slower code.  It is possible that this would be a helpful workaround
until the actual compiler bug is fixed, but it does not improve the code in
any other way.  Additionally, the compiler is free to do the two reads and
the add in registers, and only write out the data to x at the end of the
function.  In fact, with the improvements in optimisation in gcc 4.1, it
could quite well eliminate x altogether and generate the same code as if x
were local.

>
> > > By the way, I think it's also better to change your initial example:
> > >
> > > unsigned two;
> > > void foo(void)
> > > {
> > >  two = P6IN + P6IN;
> > > }
> > >
> > > into:
> > >
> > > unsigned two;
> > >
> > > void foo(void)
> > > unsigned int tmp;
> > > {

I'm assuming the above two lines are swapped, so that tmp is a local
variable rather than a syntax error.

> > >  tmp = P6IN + P6IN;  //  <-----  tmp = 2 * P6IN;  //  <----- tmp =
> > > P6IN; tmp+= P6IN;
> > >  two = tmp;
> > > }
> > >
> >
> > You may think that, but no one will agree with you.  There is no benifit
in
> > introducing an extra temporary variable here - it simply makes the code
more
> > verbose and thus less readable.  You are writing in C, using a
compiler -
> > you are not writing everything out explicitly in assembler.  It is up to
the
> > compiler to figure out what extra temporary variables it needs - in
fact,
> > the compiler will probably internally use exactly the code you have
written
> > out explicitly.  And unless you are specifically compiling with no
> > optimisation, the code generated is identical with or without the "tmp"
> > variable.
> >
>
> Apart from the fact that the compiler generates two completely
> different codes if you use the temp variable or not (try it!),

I have tried it, and the code is the same.  Unless, of course, you use no
optimisation flags, which would be a very strange way to compile real code
for a real application (even during testing and debugging).

> I don't know what others would say...but  I don't think that is
> "verbose"; on the contrary, it's more readable because you may have
> that memory variable defined far away (in terms of code lines) and you
> may forget the type....and....and......it's error prone.

There is no excuse for not knowing the type or purpose of the variables you
use - you simply should not be writing code like that.

There are certainly occasions when extra temporary variables is a good
thing.  For example, it can make type changes much clearer (such as if a
16-bit local was used as temporary storage before the sum was divided by two
and written out to an eight bit variable).  Adding them for no reason to a
one line function does not make it less error prone.

> And it's no more efficient then using explicitely the temp var.

Omitting the temp variable is either more efficient (if you have forgot the
optimisation flag), as you found out yourself, or it generates the same
code.

>
>
> > > or even better a function. it's more efficient (and easier to compile)
> > > if you make the calculations through local variables.
> > >
> >
> > It is hard to split up a single-line function into smaller functions.
>
> first of all, if in that function there was really just that
> instruction (and I don't believe so), you would be wasting stack,
> making calls, and so on.....which is the opposite of you should do
> with embedded systems. In PC your CPU has the pipelines doing nops for
> the most part of the time, so you wouldn't affect the performances
> significantly, but with an MSP430 you should keep an eye on not
> wasting anything.

On a PC, avoiding such extra functions can be at least as important - the
change of flow plays havoc with your pipelines.

The reason for using an optimising compiler, is that it optimises the
generated code for you so that you can choose yourself when to divide the
code up into smaller or bigger functions.  The compiler will automatically
inline small functions - I use "static inline" functions all the time rather
than old-fashioned macros.

The reason for not dividing a small function into even smaller functions is
nothing to do with the generated code overhead - it has everything to do
with the programmer being able to see what the code is doing without having
to jump around in the source files.

> Note also that every extra instruction means extra current that you're
> drawing from the battery....
>

Indeed - that's why I let the compiler generate the best code it can, and
check that it is doing so (and occasionally change my source code if
necessary).

> if you really want that single instruction as a function by itself and
> you want it to write directly in the global variable, then you should
> at least declare it naked.
>

Perhaps this is a case where we have misunderstood each other - as far as I
can tell, you said that Grant's code should be split with an extra function,
and I disagreed.  Did I misunderstand you?

>
> > And as for being easier to compile - I try to be nice to my computer,
but I
> > refuse to structure my code differently just to save the computer a
couple
> > of microsecond's effort during compilation.
>
> I didn't care about the compilation time....if you got there, it means
> my English is really bad...sorry everyone!

I was being a little sarcastic - I should have added a smiley, as I did
understand what you meant.

> "easier" meant that you help the compiler to understand when to use a
> register instead of a direct memory access
>
> > Local variables are, in general, more efficient than global variables -
but
> > they are not more efficient than calculations carried out internally by
the
> > compiler using registers.  Add variables when they make sense in your
code,
> > and make the logic of your code clearer - don't do it for the compiler's
> > sake.
>
> when you are writing firmware, using explicitely a local variable
> means that you _prefer_ it to be a register !!! And if I happen to see
> that I used too many local variables (which is quite difficult with 16
> registers), so that the compiler is forced to allocate some of them in
> memory, then I try to rearrange my code.

The less specific you are in your code, the easier it is for the compiler to
re-arrange things for the greatest efficiency.  If you make a local "tmp"
variable at the start of a function, and use it in several places in the
function, and you have debugging enabled, then the compiler is going to give
it a specific register so that the debugger can track it (newer versions of
gcc, gdb, and dwarf are more flexible, but I don't thing the msp430-gcc
toolchain is there yet).  That means you have used up a specific register.
If you make new "tmp" variables inside smaller block scopes, the compiler
can use a different register each time.  If you can omit the "tmp" variable
altogether, the compiler has even greater freedom.

In other words, let the compiler do its job, and don't try and do it
yourself.

> Efficiency comes also at the cost of coding time, if efficiency is your
aim.
>

Sometimes that's true - but sometimes you can try too hard, ending up being
inefficient in your code, and inefficient in your coding time.

> Are you sure you know everything about embedded systems ?

If I knew everything, then I'd start looking for a new career - learning is
part of what makes this stuff fun!

But I have worked with a wide range of systems (both compilers and targets),
and I've learned a lot about the myths and truths of efficient embedded
programming over the years.

mvh.,

David

>
> R.
>
> [omissis]
>



Reply via email to