Compilers are generally used to transform one representation of a computer program into another representation. Typically, but not exclusively, compilers are used to transform a human readable form of a program such as source code into a machine readable form such as object code.
A computer program suitable for compilation by a compiler is composed of a series of "statements". Some statements generate, modify, retrieve or store information. Other statements may control the flow of the program, for example, by testing the value of a variable and causing program flow to continue in different directions based on the value of the variable. In most programs of any significant length, the statements are collected into "procedures", which perform well-defined functions and can be used in potentially multiple places with the program. Frequently, the procedures in a large program are further collected into "modules", each of which is responsible for a particular major subset of the functions of the program. In a program structure of this kind, the compiler is used to compile the modules individually, after which the compiled modules are "linked" together to form a single, cohesive computer program. This approach allows the programmer to upgrade or debug, and then recompile, each module separately, without need for recompiling the other modules.
One type of compiler is an optimizing compiler which includes an optimizer for enhancing the performance of the machine readable representation of a program. Some optimizing compilers are separate from a primary compiler, while others are built into a primary compiler to form a multi-pass compiler. Both types of compilers may operate either on a human readable form, a machine readable form, or any intermediate representation between these forms.
One optimization technique is known as "profiling" the program. A program is profiled by compiling the program, and delivering it to a test environment which simulates actual field operation of the program. While the program operates in the test environment, records are kept on the extent to which certain sections of the program are used. After the test has been completed, the profile records are used by an optimizing compiler, to recompile the program in a manner which enhances the efficiency of the program. For example, one known technique is to place sections of the program which are used at approximately the same time, in nearby memory locations, so as to speed access to the program.
A common computer programming approach is known as procedural programming. In procedural programming, a program is broken into many small procedures, each including a sequence of statements (and in some cases, data), and each of which is responsible for particular well-defined activities. The procedures are invoked when particular actions are needed. Typically, procedures can invoke each other, as part of operation of the program. In such a situation, the procedure which is invoked is typically referred to as the "child" procedure, and the procedure which invokes the child procedure is referred to as the "parent" procedure.
While procedural programming can simplify programming effort and reduce complexity, one of the unfortunate results of a highly procedural computer program, is that the program, when operating, frequently transfers control between the various procedures (executes "procedure calls"). This creates a substantial overhead, in that each transfer of control between procedures requires multiple computer operations, both to transfer flow control to a procedure and to return flow control from the procedure.
A similar unfortunate result occurs in so-called "object oriented" programming. In object oriented programming, data and a set of procedures (called "methods") are encapsulated together, and only the procedures encapsulated with data are permitted to modify that data. This style of programming naturally causes procedure calls to proliferate, typically to a greater extent than procedural programming.
To address the problem of high procedure call overhead, modern compilers optimize programs so as to avoid procedure calls. One optimization approach is to "inline" procedures, that is, to copy the entire body of the child procedure, into the body of the parent procedure, at each location in the parent procedure where the child procedure is referenced. This is usually done only when the child procedure is relatively small and is called from relatively few locations, in order to minimize the extent to which the overall compiled program size is increased due to inlining.