320 likes | 474 Views
Interprocedural Optimizations. CS 671 April 8, 2008. Modularity is a Virtue. Decomposing programs into procedures aids in readability and maintainability Object-oriented languages have pushed this trend even further In a good design, procedures should be: An interface A black box.
E N D
Interprocedural Optimizations CS 671 April 8, 2008
Modularity is a Virtue • Decomposing programs into procedures aids in readability and maintainability • Object-oriented languages have pushed this trend even further • In a good design, procedures should be: • An interface • A black box
The Catch • This inhibits optimization! • The compiler must assume: • Called procedure may use or change any accessible variable • Procedure’s caller provides arbitrary values as parameters • Interprocedural optimizations – use the calling relationships between procedures to optimize one or both of them • Examples: • f(i,j,k) where i=2 … constant propagation in f! • f(i,j,k) where i={2,5} … new f_2() and f_5() clones
Interprocedural Optimizations • Until now, we’ve only considered optimizations “within a procedure” • Extending these approaches outside of the procedural space involves similar techniques: • Performing interprocedural analysis • Control flow • Data flow • Using that information to perform interprocedural optimizations
Terminology • int a, e // globals • procedure foo(var b, c) // formal args • b := c • end • program main • int d // locals • foo(a, d) // call site with • end // actual args • In procedure body • formals and/or globals may be aliased (two names refer to same location) • formals may have constant value • At procedure call • global vars may be modified or used • actual args may be modified or used
Call Graphs • 1 procedure f() { • 2 call g() • 3 call g() • 4 call h() • 5 } • 6 procedure g() { • 7 call h() • 8 call i() • 9 } • 10 procedure h { } • 11 procedure i() { • 12 call g() • 13 call j() • 14 } • 15 procedure j { } f 2,3 4 8 g h 7 12 i j 13 Invocation order – process procedure before its callees Reverse invocation order – process procedure after its callees
Partial Call Graphs • 1 procedure f() { • 2 call g() • 3 call g() • 4 call h() • 5 } • 6 procedure g() { • 7 call h() • 8 call i() • 9 } • 10 procedure h { } • 11 procedure i() { • 12 call g() • 13 call j() • 14 } • 15 procedure j { } What if we compile at different times? f 2,3 4 8 g h g 7 12 i i j 13
Dealing with Procedures • Aliasing example int a foo(a, a) ... procedure foo(var b, c) a := 1 // what is b, c? b := 2 // what is a, c? c := 3 // what is a, b? d := a + b // what is d? end • Side effect example a := 1 foo(a) // used/killed? b := a // what is b? • Constants example foo(1) ... procedure foo(a) if (a = 1) // what is a? ...
Interprocedural Compilation • Goals • enable standard optimizations even in presence of procedure calls • perform additional optimizations not possible for single procedures • reduce call overhead for procedures • Issues • compilation speed • re-engineering compiler • separate compilation • recompilation analysis • libraries (no source code) • dynamic shared objects (DSOs)
Interprocedural Analyses (IPA) • MAY-ALIAS may be aliased • MUST-ALIAS must be aliased • MOD may be modified • REF may be referenced • USE may be used before kill • KILL must be killed • AVAIL must be available • CONSTANT must be constant
Parameter Binding • At procedure boundaries, we need to translate formal arguments of procedure to actual arguments of procedure at call site int a,b program main // MOD(foo) = b foo(b) // REF(foo) = a,b end procedure foo (var c) // GMOD(foo)= b int d // GREF(foo)= a,b d := b bar(b) // MOD(bar) = b end // REF(bar) = a procedure bar (var d) if (...) // GMOD(bar)= d d := a // GREF(bar)= a end GMOD, GREF = side effect of procedure • MOD, REF = effect at call site (perhaps specific to call)
Direction of IPA • Bottom-up – summarizes call effect (MOD, REF, USE, KILL) procedure foo int a bar(a) end • Top-down – summarizes info from caller (MAY-ALIAS) int a,b procedure foo(var int b, c) ... end foo(a,a) foo(a,b) • Bi-directional – info to/from caller/callee (AVAIL, CONST) int a,b,c,d procedure foo(e) a := b + c d := e end foo(1)
Interprocedural Analyses • Flow-insensitive • interprocedural analysis summarizes all paths • what “may” happen (happens on at least one path) • Flow-sensitive • interprocedural analysis indicates what must happen on all paths
Precision of IPA • Flow-insensitive (MAY-ALIAS, MOD, REF) • result not affected by control flow in procedure • Flow-sensitive (USE, KILL, AVAIL) • result affected by control flow in procedure A A B B
Flow-Insensitive Aliases w/out Pointers • For some languages, aliases arise only due to parameter passing • We can compute solutions efficiently by separating local/global portions of solution • calculate where aliases are introduced (needs only local information) • propagate aliases • Reduce complexity further by finding global-formal and formal-formal aliases separately • Flow-insensitive alias algorithm • find global-formal aliases • find formal-formal aliases • combine
Alias Analysis • Variables x, y are aliased in procedure p if they may refer to the same memory location in p • alias pair <x,y> MAY-ALIAS • Aliases are introduced when the same variable is passed to two different locations in the same call • the formals become an alias pair procedure bar(int c) foo(c,c) end procedure foo(var a, b) ... // <a,b> in ALIAS end • There is a visible (global) variable in both the caller and callee passed as an actual parameter • global and formal become an alias pair int b foo(b) procedure foo(var a) ... // <a,b> in ALIAS end
Alias Analysis (cont) • Aliases are propagated when p calls q and two formals in p which are aliases are used as actuals in the same call q, • the formals in q become aliases p(a,a) procedure p(var b, c) q(b,c) end procedure q(var d, e) ... // <d,e> in ALIAS end • When a variable aliased to a global is passed as a parameter to q, • formal in q becomes aliased to global int a p(a) procedure p(var b) q(b) end procedure q(var c) ... // <a,c> in ALIAS end
Alias Analysis (cont) • Aliases are propagated when p calls q and when two actuals are aliased to the same global • the formals become aliases int a p(a) procedure p(var b) q(a,b) end procedure q(var c, d) ... // <c,d> in ALIAS end
Interprocedural Optimizations • Tail call & tail recursion elimination • Inlining • Leaf-routine optimization & shrink wrapping • Interprocedural constant propagation • Interprocedural register allocation • Aggregation of global references
Tail Call & Tail Recursion Elimination • Transformation that applies to calls • Reduce procedure-call overhead and enable additional optimizations • A call from procedure f() to procedure g() is a tail call if the only thing f() does, after g() returns to it, is itself return • The call is tail recursive if f() and g() are the same
Inlining • Replaces calls to procedures with copies of their bodies • Converts calls from opaque objects to local code • Exposes the “effects” of the called procedure • Extends the compilation region • Language support: the inline attribute • But the compiler can decide per call-site, rather than per procedure
Inlining Decisions • Must be based on • Heuristics, or • Profile information • Considerations • The size of the procedure body (smaller=better) • Number of call sites (1=usually wins) • If call site is in a loop (yes=more optimizations) • Constant-valued parameters
An Interesting Experiment • Cooper, Hall, Torczon (92) • Integrated 44% of call sites • Reduced dynamic calls by 98% • 8% performance degradation on MIPS R2000! • Suspect: Cache effects or register pressure in a critical loop • Culprit: Fortran 77 conventions (assumes no aliasing on procedure entry)
Leaf-Routine Optimization • Leaf routine • A procedure that is a leaf in the call graph • It calls no other procedures • Leaf routine optimization • Simplifies the way parameters are passed to a leaf routine • Removes much of the procedure prologue and epilogue • Depends on the calling convention and temporary storage requirements • How many procedures are leaf routines? (Hint: think of a binary tree)
Leaf-Routine Optimization • Determine amount of storage (registers and stack space) required • If register usage is less than caller-save and scratch registers – use them exclusively • If no stack space required, delete stack preparation code • If procedure is small, instead consider inlining
Shrink Wrapping • Generalizes leaf-routine optimization for non leaves • Moves prologue and epilogue code along CFG within a procedure • Uses anticipability and availability
Interprocedural Constant Propagation • Can be: • Site independent – same constant in every invocation • Site specific – same constant every invocation from one particular call site
Interprocedural Optimizations • Interprocedural analysis can guide inlining • Site-independent constant prop analysis can optimize procedure bodies • Site-dependent constant prop can clone procedure body copies to optimize for a call site • Tailor the calling conventions for a specific call site • Can use interprocedural dataflow information to improve intraprocedural data-flow for procedure entries, exits, calls, returns. • Procedure specialization can drive array bounds optimizations
Interprocedural Register Allocation • Link Time or Compile Time • Mainly extensions to graph coloring • Involves interprocedural live variable analysis • Tries to minimize save/restore overheads • Procedures in different subtrees of the call graph can share registers main a b e c d f g
Aggregation of Global References • Link-time optimization • Collect global data into an area that can be referenced by short offsets • Avoids need to calculate “high order” bits • Reserve global pointer (gp) register during compilation • Extension: Sort the global objects smallest to largest to maximize the number of objects accessible by the gp
IP Optimization Challenges • Name scoping – which modules are affected by changes to global variables • Recompilaton – determining when a change in one module requires recompilation of another • Linkage – shared objects and their effects on the modules that use them • See Mary Hall’s Ph.D. thesis (1991)
Summary • Interprocedural optimizations are: • Challenging • Similar in many respects to intraprocedural optimizations • Not thoroughly explored/proven/used • Next time • Test 2!