Optimizing Procedure Calls Inlining Procedure calls can be costly (A.k.a. procedure integration, unfolding, beta-reduction, ...) • direct costs of call, return, argument & result passing, stack frame maintainance Replace call with body of callee • indirect cost of damage to intraprocedural analysis • insert assignments for actual/formal mapping, of caller and callee return/result mapping • do copy propagation to eliminate copies Optimization techniques: • manage variable scoping correctly • e.g. α -rename local variables, or tag names with scopes, ... • hardware support • inlining • tail call optimization Pros & Cons: + eliminate overhead of call/return sequence • interprocedural analysis + eliminate overhead of passing arguments and returning • procedure specialization results + can optimize callee in context of caller, and vice versa − can increase compiled code space requirements − can slow down compilation In what part of compiler to implement inlining? front-end? back-end? linker? Craig Chambers 142 CSE 501 Craig Chambers 143 CSE 501 What/where to inline? Program representation for inlining Inline where highest benefit for the cost Weighted call graph: directed multigraph E.g.: • nodes are procedures • most frequently executed call sites • edges are calls, weighted by invocation counts/frequency • call sites with small callees A • call sites with callees that benefit most from optimization 25 25 Can be chosen by: B C 100 • explicit programmer annotations 60 50 5 • annotate procedure or call site? D E • automatically • get execution frequencies from 1000 static estimates or dynamic profiles 800 F 10 G Hard cases for building call graph: • calls to/from external routines • calls through pointers, function values, messages Craig Chambers 144 CSE 501 Craig Chambers 145 CSE 501
Inlining using a weighted call graph Assessing costs and benefits of inlining What order to do inlining? Strategy 1: superficial analysis • top-down: local decision during compilation of caller ⇒ easy • examine source code of callee to estimate space costs − doesn’t account for recursive inlining, • bottom-up: avoids repeated work post-inlining optimizations • highest-weight first: exploits profile data • but highest-benefit first would be better... Strategy 2: deep analysis, “optimal inlining” • perform inlining Avoid infinite inlining of recursive calls • perform post-inlining optimizations, estimate benefits from optimizations performed • measure code space after optimizations • undo inlining if costs exceed benefits + better accounts for post-inlining effects − much more expensive in compile-time Strategy 3: amortized version of strategy 2 [Dean & Chambers 94] • perform strategy 2: an “inlining trial” • record cost/benefit trade-offs in persistent database • reuse previous cost/benefit results for “similar” call sites + faster compiles than superficial approach, in Self compiler Craig Chambers 146 CSE 501 Craig Chambers 147 CSE 501 Tail call optimization Tail recursion elimination Tail call: last thing before return is a call If last operation is self-recursive call, turns recursion into loop ⇒ tail recursion elimination • callee returns, then caller immediate returns • common optimization in compilers for functional languages int f(...) { • required in Scheme language specification ... if (...) return g (...); bool isMember(List lst, Elem x) { ... if (lst == null) return false; return h (i(...), j(...)); if (lst.elem == x) return true; } return isMember (lst.next, x); } Can splice out one stack frame creation and tear-down, by jumping to callee rather than calling Works for mutually recursive tail calls, too; e.g. FSM’s: + callee reuses caller’s stack frame & return address void state0(...) { − effect on debugging? if (...) state1 (...) else state2 (...); } void state1(...) { if (...) state0 (...) else state2 (...); } void state2(...) { if (...) state1 (...) else state2 (...); } Craig Chambers 148 CSE 501 Craig Chambers 149 CSE 501
Interprocedural Analysis Interprocedural analysis algorithm #1: supergraph Extend intraprocedural analyses to work across calls Given call graph and CFG’s of procedures, + avoid making conservative assumptions about: create single CFG (“control flow supergraph”) by • connecting call sites to entry nodes of callees • effect of callee on caller • connecting return nodes of callees back to calls • context of caller (e.g. inputs) on callee + no (direct) code increase + simple − doesn’t eliminate direct costs of call + intraprocedural analysis algorithms work on larger graph − may not be as effective as inlining at cutting indirect costs + decent effectiveness (but not as good as inlining) − speed? − separate compilation? − imprecision due to "unrealizable paths" Craig Chambers 150 CSE 501 Craig Chambers 151 CSE 501 Interprocedural analysis algorithm #2: summaries Examples of callee summaries Compute summary info for each procedure MOD • callee summary: • the set of variables possibly modified by a call to a proc summarizes effect/result of callee procedure for callers • caller summaries: USE summarizes context of all callers for callee procedure • the set of variables possibly read by a call to a proc Store summaries in database Use summaries when compiling & optimizing procedures later MOD-BEFORE-USE • the set of variables definitely modified before use For simple summaries: + compact CONST-RESULT + compute & use summaries quickly • the constant result of a procedure, if it’s a constant + separate compilation practical (once summaries computed) − less precise analysis PURE • a pure, terminating function, without side-effects A continuum in the design of summaries: • as small as a single bit • as large as the full source code of the callee Craig Chambers 152 CSE 501 Craig Chambers 153 CSE 501
Computing callee summaries within a procedure Computing callee summaries across procedures Flow-insensitive summaries can be computed If procedure includes calls, then without regard to control flow its callee summary depends on its callees’ summaries, + often can be calculated in linear time transitively − limited kinds of information Therefore, compute callee summaries bottom-up in call graph • cannot compute anything that depends on the relative order of execution of statements Flow-sensitive summaries must take control flow into account What about recursion? − may require iterative dfa What about calls to external, unknown library functions? + more precise info possible What about calls from external, unknown library functions? What about program changes? Converting to SSA form and then doing a flow-insensitive analysis is often as precise as doing a flow-sensitive analysis Craig Chambers 154 CSE 501 Craig Chambers 155 CSE 501 Examples of caller summaries Computing caller summaries across procedures CONST-ARGS Caller summary depends on all callers • the constant values of the formal parameters of a • requires knowledge of all call sites, e.g. whole-program info procedure, for those that are constant Therefore, compute caller summaries top-down in call graph ARGS-MAY-POINT-TO If procedure contains a call, • may-point-to info for formal parameters merge info at call site with caller summary of callee LIVE-RESULT What about recursion? • whether result may be live in caller What about calls to external, unknown library functions? What about calls from external, unknown library functions? What about program changes? Craig Chambers 156 CSE 501 Craig Chambers 157 CSE 501
Recommend
More recommend