This chapter describes both the CodeWarrior® back-end compiler and linker for Win32.
The sections in this chapter are:
However, this chapter does not discuss several important topics with respect to code generation, including front-end compiler issues, compiler and linker errors, controlling the size of C++ code, and so forth. These topics are covered in other CodeWarrior documentation, as outlined in Table 9.1.
Other compiler/linker documentation:
| For this topic... |
See... |
|---|---|
NOTE Some of the items discussed in this chapter may actually be implemented in the front-end compiler. However, whether the actual implementation of a feature occurs in the front-end or back-end compiler is irrelevant. From the programmer's point of view, it is all one compiler.
This section describes how the CodeWarrior C/C++ compilers implement
integer and floating-point types for Win32/x86 processors. You
can also read limits.h for more information on integer types, and float.h for more information on floating-point types. Both of these files
are installed with the CodeWarrior IDE and can easily be found
using the Find feature of Windows®.
The topics in this section are:
The Win32/x86 back-end compiler does not let you change the size
of integers. The size of a short int is always 2 bytes and the size of an int or long int is always 4 bytes.
Table 9.2 shows the size and range of the integer types for the Win32/x86 compiler.
| For this type |
Option setting |
Size is |
and its range is |
|---|---|---|---|
Table 9.3 shows the sizes and ranges of the floating point types for the Win32/x86 compiler.
Win32/x86 floating point types:
| Type |
Size |
Range |
|---|---|---|
This section describes the C/C++ calling conventions for Win32/x86 development.
The Win32/x86 back-end compiler supports four calling conventions:
Unless you specify otherwise, the compiler uses the default calling convention. You may choose another calling convention with these declaration specifiers:
NOTE __thiscall is not a supported keyword; it is only available as the default calling convention for C++ methods.
The default calling convention pushes all parameters onto the stack in right to left order, so the first parameter in the list is on top of the stack when the call is made. It expands each parameter to at least 32 bits on the stack and pads structs to an even number of 32 bit longwords.
When the function call returns, the caller removes the parameters from the stack.
The compiler returns the value of a function in one of three ways:
EAX register
The default calling convention is also known as the __cdecl calling convention.
The standard calling convention is the same as the default calling
convention, except that the callee removes parameters from the stack. If you are declaring a function
for an API, specify the standard calling convention with __stdcall.
The __thiscall calling convention is the same as the standard calling convention,
except that it passes the this pointer in the ECX register.
If you're declaring a non-static member function, the compiler
automatically uses the __thiscall calling convention unless you explicitly specify the standard
calling convention with __stdcall.
The __fastcall calling convention passes the first two arguments that are 4 bytes or smaller in the x86 processor registers ECX and EDX.
(K&R, §A4.3, §A8.3, §A8.6.2) The Win32/x86 back-end compiler places no limits on how large variables can be or how you may allocate them.
(K&R, §A4.1, §A8.1) This section describes how the C/C++ compilers allocate variables to registers.
The Win32/x86 back-end compiler automatically allocates local variables and parameters to registers according to how frequently they're used and how many registers are available. If you're optimizing for speed, the compiler gives preference to variables used in loops.
The Win32/x86 compiler ignores the register declaration and decides on its own which variables to place in
registers.
The compiler will also use the floating point stack (ST(0) through ST(7)) for local variables.
The Win32/x86 compiler can use these registers for local variables:
This section discusses optimizations that are specific to Win32/x86 development with CodeWarrior. These are:
More optimizations are available through the Global Optimizations target settings panel. Refer to the IDE User Guide for more information on optimizations and this panel.
The C/C++ compiler can perform an optimization called register coloring. In this optimization, the compiler assigns two or more variables
to the same register. It does this if the code does not use the
variables at the same time. In this example, the compiler could
place i and j in the same register:
short i;
int j;
for (i=0; i<100; i++) { MyFunc(i); }
for (j=0; j<100; j++) { MyFunc(j); }
However, if a line of code like the one below appears anywhere
in the function, the compiler would realize that you are using
i and j at the same time, and place them in different registers.
MyFunc (i + j);
Register coloring reduces code size and has no effect on execution time.
If register coloring is on while you debug your code, it may appear
as though there's something wrong with the variables that share
a single register. In the example above, i and j would always have the same value. When i changes, j changes in the same way, and vice versa.
The compiler uses the instruction scheduling optimization to increase the speed of execution. This optimization rearranges processor instructions so that the execution of one instruction doesn't hold up the execution of others, whenever possible. This optimization only has an effect on Win32/x86 processors that are able to process more than one instruction at a time. Namely, Intel Pentium (and compatible) processors have multiple execution units that handle more than one type of instruction at a time.
To turn on instruction scheduling, slide the dial on the Global Optimizations target settings panel to Level 3 or Level 4. To learn more about the Global Optimizations panel, see the IDE User Guide.
The setting you select the Target Processor list-box in the x86 Processor panel controls the scheduling heuristics for a particular processor. For more information about this panel, see "x86 Processor."
To turn off register coloring, disable the SYM Format option in the x86 Processor settings panel.
For specific optimization information regarding AMD® processors, refer to "Targeting AMD Processors."
Alias Analysis is a facility that allows the compiler to track pointer values during compilation. By gathering extra information about pointer use, the compiler can apply more intelligent optimizations. Optimizations that were not possible before this improvement are now enabled, with the effect that pointer-based code runs faster.
To illustrate how this can improve your code, we examine some
code containing a common sub-expression that can be eliminated.
Common sub-expression elimination (CSE) is just one of the optimizations
that the CodeWarrior IDE can perform. If your code contains the
expression a*b*c multiple times, CSE allows the compiler to generate a temporary
value and then replace each occurrence of the expression with
this temporary value.
The example in Listing 9.1 demonstrates how CSE works across an assignment through a pointer.
void TestFunction2( int *int1, int *int2, int *int3, int *int4 )
{
*int1 = *int3/*int4; // the RHS is the CSE here
int1 = GetGobalIntPtr(NULL);
*int1 = 0;
*int2 = *int3/*int4; // the CSE again
}
Note that *int3/*int4 is a CSE, but involves pointers. Through the use of alias analysis
this CSE is optimizable even though it involves pointers.
This section discusses the background information on the Win32/x86 linker and how it works. The topics in this section are:
The Win32/x86 linker deadstrips unused code and data only from files compiled by the CodeWarrior C/C++ compiler. Assembler relocatable files and C/C++ object files built by other compilers are never deadstripped. Deadstripping is particularly useful for C++ programs. Libraries (archives) built with the CodeWarrior C/C++ compiler only contribute the used objects to the linked program. If a library has assembly or other C/C++ compiler built files, only those files that have at least one referenced object contribute to the linked program. Completely unreferenced object files are always ignored.
Link order is generally specified in the Link Order view of the project window. For general information on setting link order, refer to the IDE User Guide.
Regardless of the link order specified in the Link Order view of the project window, the Win32/x86 linker always processes C/C++ or assembler source files before it processes relocatable files (.obj) or archive files (.lib), which are treated as libraries. Therefore, if a symbol is defined in a source file, the linker will use that definition in preference to a definition in a library.
To learn more about pragmas supported for Win32 code generation, refer to the C Compiler Reference.