GNU C Compiler Internals/Compilation of a function 4 1

Function Prolog and Epilog


A prolog is used to initialize the function, for example set up its stack frame. A function epilog is used to finalize execution. At each level of compilation, there are common actions performed for each function. Therefore, a number of prolog/epilog generation functions exist in GCC.

At the GIMPLE level prolog is generated in function gimplify_function_tree. It adds profiling hooks if instructed so using -finstrument-functions.

At the RTL level, function expand_function_start is used. It starts the RTL for a new function, and set variables used for emitting RTL. It also makes the label for return statements to jump to and decides whether to return the value in memory or in a register. After this, it calls assign_parms which maps the formal-ins to the actual-ins.

Machine-level prolog and epilog are added in pass flow2, function thread_prologue_and_epilogue_insns which relies upon machine description file, for example i386.md. The description has a number of entries. The prolog and epilog entries is used in this case. They are set to ix86_expand_prologue and ix86_expand_epilogue respectively that generate RTL prologue and epilog for i386 architecture. The machine-specific code takes care of registered used in the function so that they are preserved between function calls. The push instructions are added as the very first instructions of a function.

The machine-specific code is generated as an RTL expression rather than assembly because this is the representation used at this pass of the compiler. The RTL representation is the most general across various targets. Therefore, a push instruction of i386 corresponds to a number of RTL expressions:

static rtx gen_push (rtx arg) {  return gen_rtx_SET (VOIDmode,                     gen_rtx_MEM (Pmode, gen_rtx_PRE_DEC (Pmode,                                                  stack_pointer_rtx)),                     arg); }

At the assembly output level, prolog is generated in functions assemble_start_function and final_start_function. Their output is mostly related to debugging.

One should note that the prolog functions are executed from the higher-level representation to the lower-level ones. At the run-time, the execution order of the added code is opposite. That is, the machine-level prolog is executed first. In case of i386, it saves the registers used in the function and sets up a new stack frame. Then the parameters are received and the profiling hooks are called.

Local Control Flow Analysis
A control-flow graph is built up of basic blocks which is a sequence of instructions with only one entry and one exit. Type struct basic_block describes it. There is a pointer to the statement list that defines the basic block. Each basic block also has a pointer to the previous and next BB. Therefore, it is possible to link them in a list. Fields preds and succs give access to control/data flow edges into and out of the block.

Function create_basic_block takes the first and the last statements and inserts the new BB after a given one. make_edge links the two BBs.

Use macro FOR_EACH_BB to traverse a CFG. Each function flow graph has an entry and an exit block accessed using ENTRY_BLOCK_PTR and EXIT_BLOCK_PTR respectively.

Function build_tree_cfg takes a GIMPLE tree and generates the CFG. First, it initializes the CFG with two BBs: ENTRY_BLOCK and EXIT_BLOCK. It calls make_blocks, then make_edges.