[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This chapter describes the target-independent part of the compiler. It documents the options and extensions which are not specific to a certain target. Be sure to also read the chapter on the backend you are using. It will likely contain important additional information like data-representation or additional options.
Usually vbcc
will be called by vc
. However, if called
directly it expects the following syntax:
|
The following options are supported by the machine independent part
of vbcc
(and will be passed through by vc
):
Do not print the copyright notice.
Write the intermediate code before optimizing to file.ic1.
Write the intermediate code after optimizing to file.ic2.
Set the debug level to n.
Write the generated assembler output to <ofile> rather than the default file.
Do not generate assembler output (only for testing).
Turns optimizing options on/off; every bit set in n turns on an option. Usually the predefined optimization options by the compiler driver should be used. See section Optimizations.
Turns on optimizations which improve speed even if they increase code-size quite a bit.
Turns on optimizations which improve code-size even if they have negative effect on execution-times.
This flag is useful only with higher optimization levels. It tells the compiler that all relevant files have been provided to the compiler (i.e. it is the link-stage). The compiler will try to eliminate all functions and variables which are not referenced.
See section Unused Object Elimination.
Create a high-level pseudo object for cross-module optimization (see section Cross-Module Optimizations).
Create debug output. Whether this is supported as well as the format of the debug information depends on the backend. Some backends may offer additional options to control the generation of debug output.
Usually DWARF2-output will be generated by default, if possible.
Also, options regarding optimization and code-generation may affect the debug output (see section Debugging Optimized Code).
A file containing additional command line options can be specified using this command. This may be useful for very long command lines.
Switch to the 1999 ISO standard for C /ISO/IEC9899:1999). Currently the following changes of C99 are handled:
inline
function-specifier
restrict
-qualifier
//
-comments
_Pragma
Make the unqualified type of char
unsigned.
Set maximum number of optimizer passes to n. See section Optimizations.
Set the maximum ’size’ of functions to be inlined. See section Function Inlining.
Inline functions up to n nesting-levels (including recursive calls). The default value is 1. Be careful with values greater than 2. See section Function Inlining.
Set the maximum ’size’ of unrolled loops. See section Loop Unrolling.
Unroll loops with a non-constant number of iterations if the number can be calculated at runtime before entering the loop. See section Loop Unrolling.
Some backends provide peephole-optimizers which perform
simple optimizations on the assembly code output by vbcc
.
By default, these optimizations will also be performed
on inline-assembly code of the application. This switch
turns off this behaviour. See section Inline-Assembly Functions.
Floating point operations do not obey the law of
associativity, e.g. (a+b)+c==a+(b+c)
is not true for all
floating point numbers a
,b
,c
. Therefore
certain optimizations
depending on this property cannot be performed on floating
point numbers.
This option tells vbcc
to treat floating point
operations as associative and perform those optimizations
even if that may change the results in some cases (not
ISO conforming).
Do not perform type-based alias analysis. See section Alias Analysis.
If the backend supports multiple condition code
registers, vbcc
will try to use them when optimizing.
This flag prevents vbcc
from using them.
On targets where function-arguments are passed in registers but also stack-slots are left empty for such arguments, pass those arguments both in registers and on the stack.
This generates less efficient code but some broken code (e.g. code which calls varargs functions without correct prototypes in scope) may work.
In the presence of a prototype, no promotion will be done on function arguments. For example, <char> will be passed as <char> rather than <int> and <float> will not be promoted to <double>. This may be more efficient on small targets.
However, please note that this feature may not be supported by all backends and that using this option breaks ANSI/ISO conformance. For example, a function with a <char> parameter must never be called without a prototype in scope.
On targets supporting this flag, software floating point emulation will be used rather than a hardware FPU. Please consult the corresponding backend documentation when using this flag.
Insert code for dynamic stack checking/extending if the backend and the environment support this feature.
Switch to ANSI/ISO mode.
Abort the compilation after n errors; do not stop if n==0.
Suppress warning number n; suppress all warnings if n<0. Multiple warnings may be separated by commas. See section Errors and Warnings
Turn on warning number n; turn on all warnings if n<0. See section Errors and Warnings
Strip the path of filenames from error messages. Error messages may look more convenient that way, but message browsers or similar programs might need full paths.
Allow C++ style comments (not ISO89 conforming).
Do not recognize trigraphs (not ISO conforming).
Write the preprocessor output to <file>.i.
Reserve that register not to be used by the backend. This option is dangerous and must only be used for registers otherwise available for the register allocator. If it used for special registers or registers used internally by the backend, it may be ignored, lead to corrupt code or even cause internal errors from the compiler.
Only use if you know what you are doing!
By default vbcc
keeps all data of initializations in memory
during the whole compilation (it can sometimes make use
of this when optimizing). This can take some amount of
memory, though. This options tells vbcc
to
keep as little of this data in memory as possible.
This has not yet been tested very well.
The assembler output will be saved to ‘file.asm’ (if ‘file’ already contained a suffix, this will first be removed; same applies to .ic1/.ic2)
vbcc
knows the following kinds of messages:
Something is badly wrong and further compilation is
impossible or pointless. vbcc
will abort.
E.g. no source file or really corrupt source.
There was an error and vbcc
cannot generate useful
code. Compilation continues, but no code will be
generated.
E.g. unknown identifiers.
Warnings with ISO-violations. The program is not
ISO-conforming, but vbcc
will generate code that
could be what you want (or not).
E.g. missing semicolon.
The code has no ISO-violations, but contains some strange things you should perhaps look at. E.g. unused variables.
Errors or the first kind of warnings are always displayed and cannot be suppressed.
Only some warnings of the second kind are turned on by default. Many of them are very useful for some but annoying to others, and their usability may depend on programming style. Everybody is recommended to find their own preferences.
A good way to do this is starting with all warnings turned on by ‘-warn=-1’. Now all possible warnings will be issued. Everytime a warning that is not considered useful appears, turn that one off with ‘-dontwarn=n’.
See List of Errors for a list of all diagnostic messages available.
See The Frontend to find out how to configure vc
to your
preferences.
vbcc
can handle the following atomic data types:
signed char
unsigned char
signed short
unsigned short
signed int
unsigned int
signed long int
unsigned long int
signed long long int
(with ‘-c99’)
unsigned long long int
(with ‘-c99’)
float
double
long double
The default signedness for integer types is signed
.
Depending on the backend, some of these types can have identical
representation. The representation (size, alignment etc.) of these types
usually varies between different backends. vbcc
is able to support
arbitrary implementations.
Backends may be restricted and omit some types (e.g. floating point on small embedded architectures) or offer additional types. E.g. some backends may provide special bit types or different pointer types.
vbcc
offers different levels of optimization, ranging from fast
compilation with straight-forward code suitable for easy debugging
to highly aggressive cross-module optimizations delivering very
fast and/or tight code.
This section describes the general phases of compilation and gives a short overview on the available optimizations.
In the first compilation phase every function is parsed into a tree structure one expression after the other. Type-checking and some minor optimizations like constant-folding or some algebraic simplifications are done on the trees. This phase of the translation is identical in optimizing and non-optimizing compilation.
Then intermediate code is generated from the trees. In non-optimizing compilation temporaries needed to evaluate the expression are immediately assigned to registers while in optimizing compilation, a new variable is generated for each temporary. Slightly different intermediate code is produced in optimizing compilation. Some minor optimizations are performed while generating the intermediate code (simple elimination of unreachable code, some optimizations on branches etc.).
After intermediate code for the whole function has been generated, simple register allocation may be done in non-optimizing compilation if bit 1 has been set in the ‘-O’ option. Afterwards, the intermediate code is passed to the code generator and then all memory for the function, its variables etc. is freed.
In optimizing compilation flowgraphs are constructed, data flow analysis is performed and many passes are made over the function’s intermediate code. Code may be moved around, new variables may be added, other variables removed etc. etc. (for more detailed information on the optimizations look at the description for the ‘-O’ option below).
Many of the optimization routines depend on each other. If one
routine finds an optimization, this often enables other routines to
find further ones. Also, some routines only do a first step and let
other routines ’clean up’ afterwards. Therefore vbcc
usually
makes many passes until no further optimizations are found.
To avoid possible extremely long optimization times, the number of
those passes can be limited with ‘-maxoptpasses’ (the
default is max. 10 passes).
vbcc
will display a warning if more passes might be useful.
Depending on the optimization level, a whole translation-unit or even several translation-units will be read at once. Also, the intermediate code for all functions may be kept in memory during the entire compilation. Be aware that higher optimization levels can take much more time and memory to complete.
The following table lists the optimizations which are activated by
bits in the argument of the ‘-O’ option. Note that not all
combinations are valid. It is heavily recommended not to fiddle with
this option but just use one of the settings provided by vc
(e.g. ‘-O0’ - ‘-O4’). These options also automatically
handle actions like invoking the scheduler or cross-module optimizer.
Perform Register allocation. See section Register Allocation.
This flag turns on the optimizer. If it is set to zero, no global optimizations will be performed, no matter what the other flags are set to. Slightly different intermediate code will be generated by the first translation phases and a flowgraph will be constructed. See section Flow Optimizations.
Perform common subexpression elimination (see section Common Subexpression Elimination) and copy propagation (see section Copy Propagation). This can be done globally or only within basic blocks depending on bit 5.
Perform constant propagation (see section Constant Propagation). This can be done globally or only within basic blocks depending on bit 5.
Perform dead code elimination (see section Dead Code Elimination).
Some optimizations are available in local and global versions. This flag turns on the global versions. Several major optimizations will not be performed and only one optimization pass is done unless this flag is set.
Reserved.
vbcc
will try to identify loops and perform some loop optimizations.
See Strength Reduction and Loop-Invariant Code Motion.
These only work if bit 5 (32) is set.
vbcc
tries to place variables at the same memory addresses if possible
(see Unused Object Elimination).
Reserved.
Pointers are analyzed and more precise alias-information is generated (see section Alias Analysis). Using this information, better data-flow analysis is possible.
Also, vbcc
tries to place global/static variables and variables which
have their address taken in registers, if possible
(see section Register Allocation).
More aggressive loop optimizations are performed (see Loop Unrolling and Induction Variable Elimination). Only works if bit 5 (32) and bit 7 (128) are set.
Perform function inlining (see section Function Inlining).
Reserved.
Perform inter-procedural analysis (see section Inter-Procedural Analysis) and cross-module optimizations (see section Cross-Module Optimizations).
Also look at the documentation for the target-dependent part of vbcc
.
There may be additional machine specific optimization options.
This optimization tries to assign variables or temporaries into machine registers to save time and space. The scope and details of this optimization vary on the optimization level.
With ‘-O0’ only temporaries during expression-evaluation are put into registers. This may be useful for debugging.
At the default level (without the optimizer), additionally local variables whose address has not been taken may be put into registers for a whole function. The decision which variables to assign to registers is based on very simple heuristics.
In optimizing compilation a different algorithm will be used which uses hierarchical live-range-splitting. This means that variables may be assigned to different registers at different time. This typically allows to put the most used variables into registers in all inner loops. Note that this means that a variable can be located in different registers at different locations. Most debuggers can not handle this.
Also, the use of registers can be guided by information provided by the backend, if available. For architectures which are not very orthogonal this allows to choose registers which are better suited to certain operations. Constants can also be assigned to registers, if this is beneficial for the architecture.
The options ‘-speed’ and ‘-size’ change the behaviour of the register-allocator to optimize for speed or size of the generated code.
On low optimization levels, only local variables whose address has not
been taken will be assigned to registers. On higher optimization levels,
vbcc
will also try to assign global/static variables and variables which
had their address taken, to registers. Typically, this occurs during
loops. The variables will be loaded into a register before entering a loop
and stored back after the loop. However, this can only be done if vbcc
can detect that the variable is not modified in unpredictable ways.
Therefore, alias-analysis is crucial for this optimization.
During register-allocation vbcc
will use information on
register usage of functions to minimize loading/saving of registers between
function-calls. Therefore, other optimizations will affect register
allocation.
See Alias Analysis, Inter-Procedural Analysis and
Cross-Module Optimizations.
When optimizing vbcc
will construct a flowgraph for every function and
perform optimizations based on control-flow. For example, code which is
unreachable will be removed and branches to other branches or branches
around branches will be simplified.
Also, unused labels will be removed and basic blocks united to allow further optimizations.
For example, the following code
void f(int x, int y) { if(x > y) goto label1; q(); label1: goto label2; r(); label2: } |
will be optimized like:
void f(int x, int y) { if(x <= y) q(); } |
Identical code at the beginning or end of basic blocks will be moved to the successors/predecessors under certain conditions.
If an expression has been computed on all paths leading to a second
evaluation and vbcc
knows that the operands have not been changed,
then the result of the original evaluation will be reused instead of
recomputing it. Also, memory operands will be loaded into registers and
reused instead of being reloaded, if possible.
For example, the following code
void f(int x, int y) { q(x * y, x * y); } |
will be optimized like:
void f(int x, int y) { int tmp; tmp = x * y; q(tmp, tmp); } |
Depending on the optimization level, vbcc
will perform this optimization
only locally within basic blocks or globally across an entire function.
As this optimization requires detecting whether operand of an expression may have changed, it will be affected by other optimizations. See Alias Analysis, Inter-Procedural Analysis and Cross-Module Optimizations.
If a variable is assigned to another one, the original variable will be used as long as it is not modified. This is especially useful in conjunction with other optimizations, e.g. common subexpression elimination.
For example, the following code
int y; int f() { int x; x = y; return x; } |
will be optimized like:
int y; int f() { return y; } |
Depending on the optimization level, vbcc
will perform this optimization
only locally within basic blocks or globally across an entire function.
As this optimization requires detecting whether a variable may have changed, it will be affected by other optimizations. See Alias Analysis, Inter-Procedural Analysis and Cross-Module Optimizations.
If a variable is known to have a constant value (this includes addresses of objects) at some use, it will be replaced by the constant.
For example, the following code
int f() { int x; x = 1; return x; } |
will be optimized like:
int f() { return 1; } |
Depending on the optimization level, vbcc
will perform this optimization
only locally within basic blocks or globally across an entire function.
As this optimization requires detecting whether a variable may have changed, it will be affected by other optimizations. See Alias Analysis, Inter-Procedural Analysis and Cross-Module Optimizations.
If a variable is assigned a value which is never used (either because it is overwritten or its lifetime ends), the assignment will be removed. This optimization is crucial to remove code which has become dead due to other optimizations.
For example, the following code
int x; void f() { int y; x = 1; y = 2; x = 3; } |
will be optimized like:
int x; void f() { x = 3; } |
As this optimization requires detecting whether a variable may be read, it will be affected by other optimizations. See Alias Analysis, Inter-Procedural Analysis and Cross-Module Optimizations.
If the operands of a computation within a loop will not change during iterations, the computation will be moved outside of the loop.
For example, the following code
void f(int x, int y) { int i; for (i = 0; i < 100; i++) q(x * y); } |
will be optimized like:
void f(int x, int y) { int i, tmp = x * y; for (i = 0; i < 100; i++) q(tmp); } |
As this optimization requires detecting whether operands of an expression may have changed, it will be affected by other optimizations. See Alias Analysis, Inter-Procedural Analysis and Cross-Module Optimizations.
This is an optimization applied to loops in order to replace more costly operations (usually multiplications) by cheaper ones (typically additions). Linear functions of an induction variable (a variable which is changed by a loop-invariant value in every iteration) will be replaced by new induction variables. If possible, the original induction variable will be eliminated.
As array accesses are actually composed of multiplications and additions, they often benefit significantly by this optimization.
For example, the following code
void f(int *p) { int i; for (i = 0; i < 100; i++) p[i] = i; } |
will be optimized like:
void f(int *p) { int i; for (i = 0; i < 100; i++) *p++ = i; } |
As this optimization requires detecting whether operands of an expression may have changed, it will be affected by other optimizations. See Alias Analysis, Inter-Procedural Analysis and Cross-Module Optimizations.
If an induction variable is only used to determine the number of iterations through the loop, it will be removed. Instead, a new variable will be created which counts down to zero. This is generally faster and often enables special decrement-and-branch or decrement-and-compare instructions.
For example, the following code
void f(int n) { int i; for (i = 0; i < n; i++) puts("hello"); } |
will be optimized like:
void f(int n) { int tmp; for(tmp = n; tmp > 0; tmp--) puts("hello"); } |
As this optimization requires detecting whether operands of an expression may have changed, it will be affected by other optimizations. See Alias Analysis, Inter-Procedural Analysis and Cross-Module Optimizations.
vbcc
reduces the loop overhead by replicating the loop body
and reducing the number of iterations. Also, additional optimizations between
different iterations of the loop will often be enabled by creating larger
basic blocks. However, code-size as well as compilation-times can
increase significantly.
This optimization can be controlled by ‘-unroll-size’ and
‘-unroll-all’. ‘-unroll-size’ specifies the maximum number
of intermediate instructions for the unrolled loop body. vbcc
will try
to unroll the loop as many times to suit this value.
If the number of iterations is constant and the size of the loop body multiplied by this number is less or equal to the value specified by ‘-unroll-size’, the loop will be unrolled completely. If the loop is known to be executed exactly once, it will always be unrolled completely.
For example, the following code
void f() { int i; for (i = 0; i < 4; i++) q(i); } |
will be optimized like:
void f() { q(0); q(1); q(2); q(3); } |
If the number of iteration is constant the loop will be unrolled as many times as permitted by the size of the loop and ‘-unroll-size’. If the number of iterations is not a multiple of the number of replications, the remaining iterations will be unrolled separately.
For example, the following code
void f() { int i; for (i = 0; i < 102; i++) q(i); } |
will be optimized like:
void f() { int i; q(0); q(1); for(i = 2; i < 102;){ q(i++); q(i++); q(i++); q(i++); } } |
By default, only loops with a constant number of iterations will be
unrolled. However, if ‘-unroll-all’ is specified, vbcc
will also
unroll loops if the number of iterations can be calculated at entry to
the loop.
For example, the following code
void f(int n) { int i; for (i = 0; i < n; i++) q(i); } |
will be optimized like:
void f(int n) { int i, tmp; i = 0; tmp = n & 3; switch(tmp){ case 3: q(i++); case 2: q(i++); case 1: q(i++); } while(i < n){ q(i++); q(i++); q(i++); q(i++); } } |
As this optimization requires detecting whether operands of an expression may have changed, it will be affected by other optimizations. See Alias Analysis, Inter-Procedural Analysis and Cross-Module Optimizations.
To reduce the overhead, a function call can be expanded inline. Passing parameters can be optimized as the arguments can be directly accessed by the inlined function. Also, further optimizations are enabled, e.g. constant arguments can be evaluated or common subexpressions between the caller and the callee can be eliminated. An inlined function call is as fast as a macro. However (just as with using large macros), code size and compilation time can increase significantly.
Therefore, this optimization can be controlled with ‘-inline-size’ and
‘-inline-depth’. vbcc
will only inline functions which contain
less intermediate instructions than specified with this option.
For example, the following code
int f(int n) { return q(&n,1); } void q(int *x, int y) { if(y > 0) *x = *x + y; else abort(); } |
will be optimized like:
int f(int n) { return n + 1; } void q(int *x, int y) { if(y > 0) *x = *x + y; else abort(); } |
If a function to be inlined calls another function, that function can also be inlined. This also includes a recursive call of the function.
For example, the following code
int f(int n) { if(n < 2) return 1; else return f(n - 1) + f(n - 2); } |
will be optimized like:
int f(int n) { if(n < 2) return 1; else{ int tmp1 = n - 1, tmp2, tmp3 = n - 2, tmp4; if(tmp1 < 2) tmp2 = 1; else tmp2 = f(tmp1 - 1) + f(tmp2 - 2); if(tmp3 < 2) tmp4 = 1; else tmp4 = f(tmp3 - 1) + f(tmp3 - 2); return tmp2 + tmp4; } } |
By default, only one level of inlining is done. The maximum nesting of inlining can be set with ‘-inline-depth’. However, this option should be used with care. The code-size can increase very fast and in many cases the code will be slower. Only use it for fine-tuning after measuring if it is really beneficial.
At lower optimization levels a function must be defined in the same
translation-unit as the caller to be inlined. With cross-module
optimizations, vbcc
will also inline functions which are defined in
other files. See section Cross-Module Optimizations.
See also Inline-Assembly Functions.
This optimization will replace calls to some known functions
(usually library functions) with calls to different functions or
special inline-code. This optimization usually depends on the
arguments to a function. Typical candidates are the printf
family of functions and string-functions applied to string-literals.
For example, the following code
int f() { return strlen("vbcc"); } |
will be optimized like:
int f() { return 4; } |
Note that there are also other possibilities of providing specially optimized library functions. See Inline-Assembly Functions and Function Inlining.
Depending on the optimization level, vbcc
will try to eliminate different
objects and reduce the size needed for objects.
Generally, vbcc
will try to use common storage for local non-static variables
with non-overlapping live-ranges .
At some optimization levels and with ‘-size’ specified, vbcc
will try to
order the placement of variables with static storage-duration to minimize
padding needed due to different alignment requirements. This optimization
generally benefits from an increased scope of optimization.
See section Cross-Module Optimizations.
At higher optimization levels objects and functions which are not referenced are eliminated. This includes functions which have always been inlined or variables which have always been replaced by constants.
When using separate compilation, objects and functions with external linkage usually cannot be eliminated, because they might be referenced from other translation-units. This precludes also elimination of anything referenced by such an object or function.
However, unused objects and functions with
external linkage can be eliminated if ‘-final’ is specified.
In this case vbcc
will assume that basically the entire program is presented
and eliminate everything which is not referenced directly or indirectly
from main(). If some objects are not referenced but must not be
eliminated, they have to be declared with the __entry
attribute.
Typical examples are callback functions which are called from a library
function or from anywhere outside the program, interrupt-handlers or
other data which should be preserved.
See section Cross-Module Optimizations.
Many optimizations can only be done if it is known that two expressions are not aliased, i.e. they do not refer to the same object. If such information is not available, worst-case assumptions have to be made in order to create correct code. In the C language aliasing can occur by use of pointers. As pointers are generally a very frequently used feature of C and also array accesses are just disguised pointer arithmetic, alias analysis is very important.
vbcc
uses the following methods to obtain aliasing information:
p1
and p2
must not point to the same object:
f(int *p1, long *p2) { ... } |
vbcc
will assume that the source is correct and does not break
this requirement of the C language. If a program does break this
requirement and cannot be fixed, then -no-alias-opt
must be
specified and some performance will be lost.
vbcc
will try to keep track of all
objects a pointer can point to. In the following example, vbcc
will see that p1
can only point to x
or y
whereas p2
can only point to z
. Therefore it
knows that p1
and p2
are not aliased.
int x[10], y[10], z[10]; int f(int a, int b, int c) { int *p1, *p2; if(a < b) p1 = &x[a]; else p1 = &y[b]; p2 = &z[c]; ... } |
As pointers itself may be aliased and function calls might modify pointers, this analysis sometimes benefits from a larger scope of optimization. See Inter-Procedural Analysis and Cross-Module Optimizations.
This optimization will alter the behaviour of broken code which uses pointer arithmetic to step from one object into another.
restrict
-qualifier to help
alias analysis. If a pointer is declared with this qualifier, the
compiler may assume that the object pointed to by this pointer is
only aliased by pointers which are derived from this pointer.
For a formal definition of the rules for restrict
please
consult ISO/IEC9899:1999.
vbcc
will make use of this information at higher optimization
levels (‘-c99’ must be used to use this new keyword).
A very useful application for restrict
are function
parameters. Consider the following example:
void cross_prod(float *restrict res, float *restrict x, float *restrict y) { res[0] = x[1] * y[2] - x[2] * y[1]; res[1] = x[2] * y[0] - x[0] * y[2]; res[2] = x[0] * y[1] - x[1] * y[0]; } |
Without restrict
, a compiler has to assume that writing the
results through res
can modify the object pointed to by
x
and y
. Therefore, the compiler has to reload all
the values on the right side twice. With restrict
vbcc
will optimize this code like:
void cross_prod(float *restrict res, float *restrict x, float *restrict y) { float x0 = x[0], x1 = x[1], x2 = x[2]; float y0 = y[0], y1 = x[1], y2 = y[2]; res[0] = x1 * y2 - x2 * y1; res[1] = x2 * y0 - x0 * y2; res[2] = x0 * y1 - x1 * y0; } |
Apart from the number of different optimizations a compiler offers, another important point is the scope of the underlying analysis. If a compiler only looks at small parts of code when deciding whether to do an optimization, it often cannot prove that a transformation does not change the behaviour and therefore has to reject it.
Simple compilers only look at single expressions, simple optimizing compilers often restrict their analysis to basic blocks or extended basic blocks. Analyzing a whole function is common in today’s optimizing compilers.
This already allows many optimizations but often worst-case assumptions
have to be made when a function is called.
To avoid this, vbcc
will not restrict its analysis to single functions
at higher optimization levels. Inter-procedural data-flow analysis often
allows for example to eliminate more common subexpressions or dead code.
Register allocation and many other optimizations also sometimes benefit
from inter-procedural analysis.
Further extension of the scope of optimizations is possible by activating cross-module optimizations. See section Cross-Module Optimizations.
Separate compilation has always been an important feature of the C language. Splitting up an application into several modules does not only reduce turn-around times and resource-requirements for compilation, but it also helps writing reusable well-structured code.
However, an optimizer has much more possibilities when it has access to the
entire source code. In order to provide maximum possible optimizations
without sacrificing structure and modularity of code, vbcc
can do
optimizations across different translation-units. Another benefit is
that cross-module analysis also will detect objects which are declared
inconsistently in different translation-units.
Unfortunately common object-code does not contain enough information to
perform aggressive optimization, To overcome this problem, vbcc
offers
two solutions:
vbcc
, it will read in all files at once, perform
optimizations across these files and generate a single object
file as output. This file is similar to what would have been
obtained by separately compiling the files and linking the
resulting objects together.
vbcc
also provides means
to generate some kind of special pseudo object files which pretain
enough high-level information to perform aggressive optimizations
at link time.
If ‘-wpo’ is specified (which will automatically be done by
vc
at higher optimization levels) vbcc
will generate such files
rather than normal assembly or object files. These files can
not be handled by normal linkers. However, vc
will detect these
files and before linking it will pass all such files to vbcc
again.
vbcc
will optimize the entire code and generate real code which
is then passed to the linker.
It is possible to pass vc
a mixture of real and pseudo object
files. vc
will detect the pseudo objects, compile them and link
them together with the real objects. Obviously, vc
has to be used
for linking. Directly calling the linker with pseudo objects will
not work.
Please note that optimization and code generation is deferred to link-time. Therefore, all compiler options related to optimization and code generation have to be specified at the linker command as well. Otherwise they would be ignored. Other options (e.g. setting paths or defining macros) have to be specified when compiling.
Also, turn-around times will obviously increase as usually everything will be rebuild even if makefiles are used. While only the corresponding pseudo object may be rebuilt if one file is changed, all the real work will be done at the linking stage.
Some backends provide an instruction scheduler which is automatically run
by vc
at higher optimization levels. The purpose is to reorder
instructions to make better use of the different pipelines a CPU may
offer.
The exact details depend heavily on the backend, but in general the scheduler will try to place instructions which can be executed in parallel (e.g. on super-scalar architectures) close to each other. Also, instructions which depend on the result of another instruction will be moved further apart to avoid pipeline-stalls.
Please note that it may be crucial to specify the correct derivate of a CPU family in order to get best results from the sceduler. Different variants of an architecture may have a different number and behaviour of pipelines requiring different scheduling decisions.
Consult the backend documentation for details.
In addition to those optimzations which are available for all targets, every backend will provide a series of additional optimizations. These vary between the different backends, but optimizations frequently done by backends are:
Debugging of optimized code is usually not possible without problems.
Many compilers turn off almost all optimizations when debugging.
vbcc
allows debugging output together with optimizations and
tries to still do all optimizations (some restrictions have to be made
regarding instruction-scheduling).
However, depending on the debugger and debugging-format used, the information displayed in the debugger may differ from the real situation. Typical problems are:
When optimizing vbcc will often remove certain variables or eliminate code which sets them. Sometimes it is possible, to tell the debugger that a variable has been optimized away, but most of the time the debugger does not allow this and you will just get bogus values when trying to inspect a variable.
Also, variables whose locations differs at various locations of the program (e.g. a variable is in a register at one place and in memory at another) can only be correctly displayed, if the debugger supports this.
Sometimes, this can even occur in non-optimized code (e.g. with register-parameters or a changing stack-pointer).
When stepping through a program, you may see lines of code be executed out-of-order or parts of the code skipped. This often occurs due to code being moved around or eliminated/combined.
Setting break-points (especially on source-lines) needs some care when optimized code is debugged. E.g. code may have been moved or even replicated at different parts. A break-point set in a debugger will usually only be set on one instance of the code. Therefore, a different instance of the code may have been executed although the break-point was not hit.
This section lists and describes all extensions to the C language provided
by vbcc
. Most of them are implemented in a way which does not break
correct C code and still allows all diagnostics required by the C standard
by using reserved identifiers.
The only exception (see section Inline-Assembly Functions) can be turned off using ‘-iso’ or ‘-ansi’.
vbcc
accepts the following #pragma
-directives:
#pragma printflike <function>
#pragma scanflike <function>
vbcc
will handle <function>
specially.
<function>
has to be an already declared
function, with external linkage, that
takes a variable number of arguments
and a const char *
as the last fixed
parameter.
If such a function is called with a
string-constant as format-string, vbcc
will check if the arguments seem to
match the format-specifiers in the
format-string, according to the rules
of printf or scanf.
Also, vbcc
will replace the call by a
call to a simplified version according
to the following rules, if such a
function has been declared with external
linkage:
__v0<function>
will be called.
d,i,x,X,o,s,c
are used, __v1<function>
will be called.
__v2<function>
will be called.
#pragma dontwarn <n>
Disables warning number n. Must be followed by #pragma popwarn
.
#pragma warn <n>
Enables warning number n. Must be followed by #pragma popwarn
.
#pragma popwarn
Undoes the last modification done by #pragma warn
or
#pragma dontwarn
.
#pragma only-inline on
The following functions will be parsed and are available for inlining (see section Function Inlining), but no out-of-line code will be generated, even if some calls could not be inlined.
Do not use this with functions that have local static variables!
#pragma only-inline off
The following functions are translated as usual again.
#pragma opt <n>
Sets the optimization options to <n> (similar to -O=<n>) for the following functions. This is only used for debugging purposes. Do not use!
#pragma begin_header
Used to mark the beginning of a system-header. Must be followed
by #pragma end_header
. Not for use in applications!
#pragma end_header
The counterpart to #pragma begin_header
. Marks the end
of a system-header. Not for use in applications!
If the parameters for certain functions should be passed in certain
registers, it is possible to specify the registers using
__reg("<reg>")
in the
prototype, e.g.
void f(__reg("d0") int x, __reg("a0") char *y) { ... } |
The names of the available registers depend on the backend and will be listed in the corresponding part of the documentation. Note that a matching prototype must be in scope when calling such a function - otherwise wrong code will be generated. Therefore it is not useful to use register parameters in an old-style function-definition.
If the backend cannot handle the specified register for a certain type, this will cause an error. Note that this may happen although the register could store that type, if the backend does not provide the necessary support.
Also note that this may force vbcc
to create worse code.
Only use them if you know what you are doing!
A function-declaration may be followed by ’=’ and a string-constant. If a function is called with such a declaration in scope, no function-call will be generated but the string-constant will be inserted in the assembly-output. Otherwise the compiler and optimizer will treat this like a function-call, i.e. the inline-assembly must not modify any callee-save registers without restoring them. However, it is also possible to specify the side-effects of inline-assembly functions like registers used or variables used and modified (see section Specifying side-effects).
Example:
double sin(__reg("fp0") double) = "\tfsin.x\tfp0\n"; |
There are several issues to take care of when writing inline-assembly.
vbcc
assumes that inline-assembly does not introduce any new
control-flow edges. I.e. control will only enter inline-assembly
if the function call is reached and if control leaves
inline-assembly it will continue after the call.
Inline-assembly-functions are not recognized when ANSI/ISO mode is turned on.
vbcc
offers attributes to variables or functions. These attributes
can be specified at the declaration of a variable or function and
are syntactically similar to storage-class-specifiers
(e.g. static
).
Often, these attributes are specific to one backend and will be
documented in the backend-documentation (typical attributes would
e.g. be __interrupt
or __section
). Attributes may
also have parameters. A generally available
attribute s __entry
which is used to preserve unreferenced
objects and functions (see section Unused Object Elimination):
__entry __interrupt __section("vectab") void my_handler() |
Additional non-target-specific attributes are available to specify side-effects of functions (see section Specifying side-effects).
Please note that some common extensions like __far
are
variable attributes on some architectures, but actually type
attributes (see section Type Attributes) on others. This is due to
significantly different meanings on different architectures.
Types may be qualified by additional attributes, e.g. __far
,
on some backends. Regarding the availability of type attributes
please consult the backend documentation.
Syntactically type attributes have to be placed like a type-qualifier
(e.g. const
).
As example, some backends know the attribute __far
.
Declaration of a pointer to a far-qualified character would be
__far char *p; |
whereas
char * __far p; |
is a far-qualified pointer to an unqualified char.
Please note that some common extensions like __far
are
type attributes on some architectures, but actually variable
attributes (see section Variable Attributes) on others. This is due to
significantly different meanings on different architectures.
__typeof
__typeof
is syntactically equivalent to sizeof, but its result is of
type int and is a number representing the type of its argument.
This may be necessary for implementing ‘stdarg.h’.
__alignof
__alignof
is syntactically equivalent to sizeof, but its result is of
type int and is the alignment in bytes of the type of the argument.
This may be necessary for implementing ‘stdarg.h’.
__offsetof
__offsetof
is a builtin version of the offsetof
-macro
as defined in the C language. The first argument is a structure
type and the second a member of the structure type. The result
will be a constant expression representing the offset of the
specified member in the structure.
Only use if you know what you are doing!
When optimizing and generating code, vbcc
often has to take
into account side-effects of function-calls, e.g. which registers might
be modified by this function and what variables are read or modified.
A rather imprecise way to make assumptions on side-effects is given by the ABI of a certain system (that defines which registers have to be preserved by functions) or rules derived from the language (e.g. local variables whose address has not been taken cannot be accessed by another function).
On higher optimization levels (see section Inter-Procedural Analysis and
see section Cross-Module Optimizations)) vbcc
will try to analyse
functions and often gets much more precise informations regarding
side-effects.
However, if the source code of functions is not visible to vbcc
,
e.g. because the functions are from libraries or they are
written in assembly (see section Inline-Assembly Functions), it is obviously
not possible to analyze the code. In this case, it is possible to specify
these side-effects using the following special variable-attributes
(see section Variable Attributes).
The __regsused(<register-list>)
attribute specifies the volatile
registers used or modified by a function. The register list is a list of
register names (as defined in the backend-documentation) separated by
slashes and enclosed in double-quotes, e.g.
__regsused("d0/d1") int abs();
declares a function abs
which only uses registers d0
and
d1
.
__varsmodified(<variable-list>)
specifies a list of variables with
external linkage
which are modified by the function. __varsused
is similar, but
specifies the external variables read by the function. If a variable is
read and written, both attributes have to be specified. The variable-list
ist a list of identifiers, separated by slashes and enclosed in double
quotes.
The attribute __writesmem(<type>)
is used to specify that the
function accesses memory using a certain type. This is necessary if the
function modifies memory accessible to the calling function which cannot
be specified using __varsmodified
(e.g. because it is accessed via
pointers). __readsmem
is similar, but specifies memory which is
read.
If one of __varsused
, varsmodified
, __readsmem
and
__writesmem
is specified, all relevant side-effects must be
specified. If, for example, only __varsused("my_global")
is specified, this implies that the function only reads my_global
and does not modify any variable accessible to the caller.
All of these attributes may be specified multiple times.
The linker vlink
provides a feature to collect pointers to
all functions starting with the names _INIT
or _EXIT
in
a prioritized array, labeled by __CTOR_LIST__
and
__DTOR_LIST__
. The C-library (vclib) calls the constructor functions
before entering main()
and the destructor functions on program
exit.
The format of these special function names is:
void _INIT[_<pri>][_<name>](void) void _EXIT[_<pri>][_<name>](void) |
The optional priority <pri>
may be a digit between 1 and 9, where
a constructor with a priority of 1 is executed first while a destructor
with a priority of 1 is executed last. <name>
is an optional name,
used to differentiate functions of the same level.
The following macros are defined by the compiler.
#define __VBCC__ #define __entry __vattr("entry") #define __str(x) #x #define __asm(x) do{static void inline_assembly()=x;inline_assembly();while(0) #define __regsused(x) __vattr("regused("x")") #define __varsused(x) __vattr("varused("x")") #define __varsmodified(x) __vattr("varchanged("x")") #define __noreturn __vattr("noreturn()") #define __alwaysreturn __vattr("alwaysreturn()") #define __nosidefx __vattr("nosidefx()") #define __stack(x) __vattr(__str(stack1(x))) #define __stack2(x) __vattr(__str(stack2(x))) #define __STDC_VERSION__ 199901L |
__STDC_VERSION__
is defined in C99-mode only.
Some known target-independent problems of vbcc
at the moment:
All those who wrote parts of the vbcc
distribution, made suggestions,
answered my questions, tested vbcc
, reported errors or were otherwise
involved in the development of vbcc
(in descending alphabetical order,
under work, not complete):
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated by vb on January 3, 2015 using texi2html 1.82.