270 likes | 384 Vues
This document delves into the intricate details of interprocedural analysis, focusing on the challenges, simplifying assumptions, and various solutions available. It discusses the inadequacies of trivial solutions, modular programming, and optimization issues in real-world scenarios. The analysis covers techniques like the join over valid paths and the call-string approach. Special case studies, including linear constant propagation and methods for handling recursion and parameter passing, are explored to provide a comprehensive understanding of interprocedural analysis in programming.
E N D
Interprocedural Analysis NoamRinetzky Mooly Sagiv http://www.math.tau.ac.il/~sagiv/courses/pa04.html Tel Aviv University 640-6706 Textbook Chapter 2.5
Outline • The trivial solution • Why isn’t it adequate • Challenges in interprocedural analysis • Simplifying assumptions • A naive solution • Join over valid paths • The functional approach • A case study linear constant propagation • Context free reachability • The call-string approach • Modularity issues • Other solutions
A Trivial treatment of procedures • Analyze a single procedure • After every call continue with conservative information • Global variables and local variables which “may be modified by the call” are mapped to • Can be easily implemented • Procedures can be written in different languages • Procedure inline can help • Side-effect analysis can help
Disadvantages of the trivial solution • Modular (object oriented and functional) programming encourages small frequently called procedures • Optimization • Modern machines allows the compiler to schedule many instructions in parallel • Need to optimize many instructions • Inline can be a bad solution • Software engineering • Many bugs result from interface misuse • Procedures define partial functions
Challenges in Interprocedural Analysis • Procedure nesting • Respect call-return mechanism • Handling recursion • Local variables • Parameter passing mechanisms: value, value-result, reference, by name • The called procedure is not always known • The source code of the called procedure is not always available • separate compilation • vendor code • ...
Simplifying Assumptions • All the code is available • Simple parameter passing • The called procedure is syntactically known • No nesting • Procedure names are syntactically different from variables • Procedures are uniquely defined • Recursion is supported
Extended Syntax of While P := begin D S end D := proc id(val id*, res id*) isl S endl’ | D D S := [x := a]l | [call p(a, z)]ll’ | [skip]l | S1 ; S2| if [b]l then S1 elseS2 | while [b]ldo S b := true | false | not b | b1 opb b2 | a1 opr a2 a := x | n | a1 opa a2
Fibonacci Example 0 begin proc fib 1 begin proc fib(val z, u, res v) is1 if [z <3]2 then [v := u + 1]3 else ( [call fib(z-1, u, v)]45 [call fib(z-2, v, v)]67 ) end8 [call fib(x, 0, y)]910 end11 2 9 call fib(x, 0, y) if z <3 3 3 v:=u+1 call fib(z-1, u, v) 4 call fib(z-1, u, v) 5 10 call fib(x, 0, y) call fib(z-2, v, v) 6 call fib(z-2, v, v) 7 11 end 8 end
Constant Example begin proc p(val a) is1 if [b]2 then ( [a := a -1]3 [call p(a)]45 [a := a + 1]6 ) [x := -2* a + 5]7 end8 [call p(7)]910 end
A naive Interprocedural solution • Treat procedure calls as gotos • Obtain a conservative solution • Find the least fixed point of the system: • Use Chaotic iterations DFentry(s) = DFentry(v) = {f(e)(DFentry(u) : (u, v) E}
Simple Example begin proc p(val a) is1 [x := a + 1]2 end3 [call p(7)]45 [print x]6 [call p(9)]78 [print x]9 end
Constant Example begin proc p(val a) is1 if [b]2 then ( [a := a -1]3 [call p(a)]45 [a := a + 1]6 ) [x := -2* a + 5]7 end8 [call p(7)]910 end
A More Precise Solution • Only considers matching calls and returns (valid) • Can be defined via context free grammar • Every call is a different letter • Matching calls and returns • The control flow graph can also be defined via context free grammar
Simple Example begin proc p(val a) is1 [x := a + 1]2 end3 [call p(7)]45 [print x]6 [call p(9)]78 [print x]9 end
Constant Example begin proc p(val a) is1 if [b]2 then ( [a := a -1]3 [call p(a)]45 [a := a + 1]6 ) [x := -2* a + 5]7 end8 [call p(7)]910 end
The Join-Over-Valid-Paths (JVP) • For a sequence of labels [l1, l2, …, ln] definef [l1, l2, …, ln]: L L by composing the effects of basic blocks • f[l](s)=s • f[l, p](s) = f[p](fl(s)) • JVPl = {f[l1, l2, …, l]() [l1, l2, …, l] vpaths(l)} • Compute a safe approximation to JVP • In some cases the JVP can be computed • Distributivity of f • Functional representation
The Call String Approach for Approximating JVP • No assumptions • Record at every node a pair (l, c) where l L is the dataflow information and c is a suffix of unmatched calls • Use Chaotic iterations • To guarantee termination limit the size of c (typically 1 or 2) • Emulates inline (but no code growth) • Exponential in C • For a finite lattice there exists a C which leads to join over all valid paths
Simple Example begin proc p(val a) is1 [x := a + 1]2 end3 [call p(7)]45 [print x]6 [call p(9)]78 [print x]9 end
Constant Example begin proc p(val a) is1 if [b]2 then ( [a := a -1]3 [call p(a)]45 [a := a + 1]6 ) [x := -2* a + 5]7 end8 [call p(7)]910 print x end
The Functional Approach • The meaning of a function is mapping from values of actual variables into states • The abstract meaning of a function is function from the abstract values of the numbers to abstract stores • Iterate on the abstract domain of functions from L to L
Motivating Example 0 begin proc p 1 2 call p(7) if … 9 a:=a-1 3 call p(a) 4 call p(7) 5 10 call p(a) 6 a:=a-1 11 print x 7 x:=-2*a+5 8 end end
Motivating Example(2) 0 begin proc p 1 2 call p(7) if … 9 3 a:=a-1 call p(a) 4 call p(7) 5 10 call p(a) 6 a:=a-1 11 print x 7 x:=-2*a+5 8 end end
Issues in Functional Approach • How to guarantee that finite height for functional lattice? • It may happen that L has finite height and yet the lattice of monotonic function from L to L do not • Efficiently represent functions • Functional join • Functional composition • Testing equality • Usually non-trivial • But can be done for distributive functions
Example Linear Constant Propagation • Consider the constant propagation lattice • The value of every variable y at the program exit can be represented by: y = {(axx + bx )| x Var* } c ax ,c Z {, } bx Z • Supports efficient composition and “functional” join • [z := a * y + b] • Computes JVP
Constant Example a=a. (a *1 + 0) begin proc p(val a) is1 if [b]2 then ( [a := a -1]3 [call p(a)]45 [a := a + 1]6 ) [x := -2* a + 5]7 end8 [call p(7)]910 end a. (a -1 + 0) a. (a -1 + 0) a. (a + 0) a. a
Functional Approach via Context Free Reachablity • The problem of computing reachability in a graph restricted by a context free grammar can be solved in cubic time • Can be used to compute JVP in arbitrary finite distributive data flow problems (not just bitvector) • Nodes in the graph correspond to individual facts • Efficient implementations exit (MOPED)
Conclusion • Handling functions is crucial for abstract interpretation • Virtual functions and exceptions complicate thinks • But scalability is an issue • Assume-guarantee helps • But relies on specifications