The
Role of the Compiler
The purpose of the compiler is to take the source code and produce a
functionally correct implementation, using only the information that the
developer provides either in the source code or as part of the compilation
process. It is important to recognize the constraints that the compiler is
working under—something that is obvious to the devel-oper may not be obvious to
the compiler.
Most applications have execution paths that are
rarely executed. A developer inspect-ing the code will probably be able to
identify the paths that are likely to be executed infrequently. However, the
compiler will be rarely able to extract additional contextual information from
the source code to determine which path is most common. Consider the code shown
in Listing 2.30, which has variable names that might indicate the devel-opers’
expectations of the frequency of execution of the two code paths.
Listing 2.30 Code
Where a Developer Might Guess Common Path
...
if (error) { value=0.001; }
else {
value=numerator/denominator; }
...
The use of pointer variables raises a common
problem. To the compiler, a pointer can point to any location in memory,
including the address of other variables or the addresses held by other
pointers. Hence, any memory location accessed through a pointer may modify or
have been modified by a different memory access.
If two
pointers hold the address of the same memory location, they are said to alias. The safe assumption is for the
compiler to assume that any pointer may alias with any other data. In some
cases, the compiler is able to prove that a particular memory location was not
accessed through the pointer, and then the compiler can avoid reloading or
stor-ing data. However, the presence of a pointer may mean that the compiler
cannot safely perform many optimizations. In Listing 2.31, the compiler has to
assume that the two pointers passed into the functions might alias the same
location in memory.
Listing 2.31 Code
Containing Potential Aliasing
void
func(int * a, int *b)
{
*b = *b + *a; *a = *a + 2;
}
If
pointers a and b do not alias, then the value of a needs to be loaded only a single
time. If they do, then the store to b will change the value of a. In the absence of further
information, the compiler must assume that the two pointers do alias and that
the vari-able a needs to
be loaded twice.
The
compiler can sometimes determine from the source code that two pointers do not
alias. In other cases, the compiler may be able to produce multiversion code
that, at runtime, selects either the variant of the code where it is assumed
that aliasing occurs or another variant where it is assumed that aliasing does
not occur. However, the compiler should never produce code that will generate a
wrong answer; optimizations that the compiler performs must either be provably
safe or be specifically enabled, either implic-itly or explicitly, by the user.
If the
compiler is able to inspect more of the code, it is usually able to make better
decisions. Cross-file optimization allows the compiler to combine all the
source code for an executable. If the compiler can see all the source code, it
knows how functions are called and sees the code that gets executed in the
function call so it can make better inlining decisions. It can also see all the
uses of a variable or memory region and can better optimize the use of that
variable. Allowing the compiler visibility into more of the application will
enable it to produce better-performing code.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2024 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.