MH Tay wrote:
> (Something like ways to write program such that compiler
> will generate smaller code.
If the code is reasonably well written and structured, it is often
futile to 'second guess' the compiler optimizer. You have probbaly
already taken the steps that would result in significant benefit (thumb,
> May be Other techniques
> of using lookup table, recursive calls and etc).
> Generic 'C' skill for embedded application would do.
C is pretty transparent in terms of code cost, any such techniques are
likely to save very little, and techniques that work for one target
processor, may not work, or be detrimental on another - due to things
like different register and instruction set capabilities. Most web
resources discussing the subject of optimisation are focussed on code
speed, not just because they assume desktop platforms with large
memories, but also because that is where there is most scope - space
wasting code is easy to see and avoid, time wasting code is harder to
spot and is both algorithm and target specific. This book may have
something useful: http://www.cmpbooks.com/product/1929629044/index.html
- it has a chapter on optimisation - I have not read it, but CMP usually
publish good stuff (they produce Dr Dobb's and CUJ).
The greatest improvements are likely to come from considering your code
design in a more holistic manner. Remember that as well as the code,
literal string constants, and any other static const data will also be
stored in ROM. Also stored in ROM are the static initialiser data, this
is copied to the initialised static data in RAM at startup. Avoid
explicit initialisation of static data where possible, implicit
initialisation to zero is performed otherwise, and does not require ROM
storage of initialisers.
Consider also that library functions are a 'black-box', check their size
impact and consider if a self coded or simpler alternative might be less
expensive - this is usually only the case for large complex functions
that have functionality that you are not using. For example printf()
(and other formatted I/O functions), have a huge amount of functionality
to support different data types and formtting options, most of which you
are unlikley to be be using (they also eat large ammounts of stack RAM)
- consider the less capable puts() - but not if you just end up using
sprintf to create the string of course!
I would recommend creating a map file of your code (using arm-elf-nm).
This will allow you to see exactly where objects are located and how
much space they take up - not just the code, but the static initialisers
and const data also. Target the largest objects over which you have
control (i.e. your code, rather than library code); then consider the
larger library objects and consider if there is redundant functionality
that you could re-code in a tighter application specific form. Remember
that removing your calls to a library function will not remove it if it
is also called by some other library function you are using - use the
map file to check that a function is truely eradicated from the build.
The map file will also allow you to check the effect of any changes you
make, to see what is most significant. You can also use it to see which
modules the optimizer is having difficulty with (i.e. those that do not
change size significantly, (or even get larger!), and consider them for
hand optimisation or re-organisation.
I hesitate to suggest this - because it is generally bad practice and I
doubt its effectiveness; but the optimiser performs most of its work at
the function and compilation unit level (prior to GCC 4.x I believe that
is all it could do). So you may find that piling your code into fewer
files may allow the optimiser more scope. This would depend on the
structire of your code, and I would not expect it to be particularly
significant, if at all. If it does have benefits, I would question the
structre of your code in the first instance.
Remember also that some compiler space optimisations may require greater
use of RAM, and that too is a limited resource. Conversely the compiler
optimisation will not distinguish betwen ROM and RAM (since in non
embedded-targets - and many embedded targets - code and data are all in
the same RAM space), and -Os may even use more ROM to achieve a greater
saving in RAM. This may not be what you want, so experiment with all the
optimisation levels -O1, -O2, -O3 to determine if they might produce
more acceptable results.