Interprocedural Analysis: Computing Jump Functions

Contents

Overview

The ideas presented here are from a paper called Interprocedural constant propagation, by D. Callahan, K. Cooper, K. Kennedy, and L. Torczon, published in the Proceedings of the Symposium on Compiler Construction in 1986. The basic idea is to compute a jump function Js,f for each call site s and each formal f of the called procedure. Each jump function summarizes the (dataflow) effects of all paths from the start of the procedure that contains the call to call site s. The paper by Callahan et al assumes that the problem of interest is constant propagation.

For example, given the following call to p and header of p:

    call site s in proc q                  called proc p
    s: call p(a1, a2, ..., an)           procedure p(f1, f2, ..., fn)
there would be n jump functions: Js,f1 Js,f2 ... Js,fn. Jump function Js,fk takes as inputs the values that q's formals are guaranteed to have at the start of procedure q, and produces as output the (single) value that p's formal fk will have for this call (i.e., the value of actual parameter ak).

Jump functions are used to determine what is true at procedure entry (not how a procedure call affects dataflow information) by combining values from all call sites.

Example

For this example, the best jump functions would be:

A single, general algorithm can be defined that uses jump functions to determine what value each formal f must have at procedure entry (for all procedures). Code for this algorithm is given below. Then we will talk about three different ways to compute the jump functions. Note that the possible values for each formal form the following lattice:

                          Top
                        / | | \
                   ... -1 0 1 2 ...
                        \ | | /
                         Bottom
A formal that is determined to have value "bottom" is not constant. The "Top" value is used for initialization; a formal will only end up with value "Top" if its procedure is never called. Here's the general algorithm: Note that if the program has no recursive procedures, then the "iterate" loop is not needed. Formals can be given values by handling procedures in topological order on the call graph (give values to procedure p's formals only after giving values to the formals of all procedures that call p). For the example given above, the formals' values would be:

Jump Functions

Now we'll consider three ways to compute jump functions:

  1. All or Nothing
  2. Pass Through
  3. Symbolic Execution
In each case, the examples will be based on constant propagation; however it should be clear how to use the same techniques for other dataflow problems.

Note: The Callahan et al paper on which these notes are based seems to assume that alias analysis (to determine the possible aliases of reference formals and globals) has already been done. Thus, we know, for every definition and use of a variable x what other variables might be defined or used, and we assume that use/def information is used when appropriate (e.g., when doing constant propagation or reaching defs analysis).

All or Nothing

For our example program, if we do constant propagation on procedure q, the dataflow fact just before call site s3 is: So the jump function Js3,f4(f1, f2, f3) = 0, while the jump functions for f5 and f6 at this call site just return bottom.

Pass Through

The pass-through approach is a way to enhance the results of the "all or nothing" approach, by taking into account cases where a procedure's formal parameter is "passed through" unchanged to another procedure (e.g., procedure p has a formal parameter f, which is not modified by p and is passed as an actual parameter in a call to q).

The pass-through approach involves using the results of reaching-definitions analysis (as well as the constant propagation used for the all-or-nothing approach):

For each procedure, do reaching definitions analysis.

For each call site s, for each actual a:

In our example, at call site s3 the second actual parameter (f2) is only reached by the definition at the start of q; therefore, the corresponding jump function is: Js3,f5(f1, f2, f3) = f2

Symbolic Execution

For each call site s:

In our example, the slice of procedure q with respect to actual y at call site s3 is:

so Js3,f6(f1,f2,f3) = f3*2

Improving Jump Functions by Using Summary Information

It is sometimes possible to get better jump functions by taking GMOD information into account. The idea is to consider a call like "call p(a1, a2, ..., an)" a definition of actual ak or global g only if it is in the GMOD set for that call site.

Return Jump Functions

A return jump function is similar to a jump function, but instead of summarizing the effects of paths from procedure entry to a call site, it summarizes the effects of paths from procedure entry to procedure exit. Therefore, the return jump function for procedure p can be used to define a better dataflow function for each call to p than can be done just using GMOD.

Like jump functions, return jump functions can be computed using any of the three approaches (all-or-nothing, pass-through, or symbolic execution). For our example program, if we assume that procedure p does not modify any of its formals, then the return jump functions for the formals of q would be as shown in the table below for the three different approaches (always assuming that summary information is used to determine that the call at s3 has no effect on q's formals). Note that the return jump function for formal f of procedure p is called Rp,f.

Return Jump Function All-or-Nothing Pass-Through Symbolic Execution
Rq,f1(f1,f2,f3) 0
Rq,f2(f1,f2,f3) bottom bottom f3*2
Rq,f3(f1,f2,f3) bottom f3


Return to Interprocedural Analysis table of contents.

Go to the previous section.