useful to understand how a high-level language program is translated into
instructions. Since implementing an embedded computing system often requires
controlling the instruction sequences used to handle interrupts, placement of
data and instructions in memory, and so forth, understanding how the compiler
works can help you know when you cannot rely on the compiler.
because many applications are also performance sensitive, understanding how
code is generated can help you meet your performance goals, either by writing
high-level code that gets compiled into the instructions you want or by
recognizing when you must write your own assembly code.
compilation process is summarized in Figure 2.19. Compilation begins with
high-level language code such as C and generally produces assembly code. (Directly
producing object code simply duplicates the functions of an assembler which is
a very desirable stand-alone program to have.)
high-level language program is parsed to break it into statements and
expressions. In addition, a symbol table is generated, which includes all the
named objects in the program. Some compilers may then perform higher-level
optimizations that can be viewed as modifying the high-level language program
input without reference to instructions.
arithmetic expressions is one example of a machine-independent optimization.
Not all compilers do such optimizations, and compilers can vary widely
regarding which combinations of machine-independent optimizations they do
optimizations are aimed at generating code. They may work directly on real
instructions or on a pseudo-instruction format that is later mapped onto the
instructions of the target CPU. This level of optimization also helps
modularize the compiler by allowing code generation to create simpler code that
is later optimized. For example, consider the following array access code:
code generator would generate the address for x[i] twice, once for each
appearance in the statement. The later optimization phases can recognize this
as an example of common expressions that need not be duplicated. While in this
simple case it would be possible to create a code generator that never
generated the redundant expression, taking into account every such optimization
at code generation time is very difficult. We get better code and more reliable
compilers by generating simple code first and then optimizing it.