Procedure Optimizations and Interprocedural Analysis Chapter 15 19

  • Slides: 28
Download presentation
Procedure Optimizations and Interprocedural Analysis Chapter 15, 19 Mooly Sagiv

Procedure Optimizations and Interprocedural Analysis Chapter 15, 19 Mooly Sagiv

Outline • • Modularity Issues Procedure optimizations Interprocedural Optimizations Challenges The Call Graph Flow

Outline • • Modularity Issues Procedure optimizations Interprocedural Optimizations Challenges The Call Graph Flow insensitive information Flow sensitive information Conclusions

Modularity Issues • • • Procedures provide a mechanism for modularity Procedure bodies become

Modularity Issues • • • Procedures provide a mechanism for modularity Procedure bodies become smaller Machines becomes stronger Often procedures implement general algorithms How to achieve performance of a single procedure in a complex software? • Two solutions: – procedure integration/inline/tail call elimination – interprocedural analysis

Procedure Optimizations • Improve the code of a procedure – Reduce procedure overhead –

Procedure Optimizations • Improve the code of a procedure – Reduce procedure overhead – Enables other intraprocedural optimizations • Examples – Tail-call elimination and Tail-Recursion elimination – Procedure integration – In-Line Expansion – Leaf-Routine Optimization – Shrink Wrapping

Tail-Call and Tail-Recursive Elimination void make_node(p, n) void insert_node(n, l) int n; struct node

Tail-Call and Tail-Recursive Elimination void make_node(p, n) void insert_node(n, l) int n; struct node *p; struct node *l; int n; { { if (n>l->value) struct node *q; if (l->next==nil) make_node(l, n); q = malloc(sizeof(struct node)); else insert_node(n, l->next); q->next=nil; q->value=n; p->next=q; } }

Procedure Integration • Some programming languages allow user annotations (C++, ada) • How to

Procedure Integration • Some programming languages allow user annotations (C++, ada) • How to decide when to inline: – Single vs multiple compilation units • Multiple programming languages – Intermediate level – Code improvement criteria • Call cites in nested loops – Enables other optimizations • Profiling • Constant parameters – – What about recursive procedures? Code size Cache effect and register pressure Other compiler assumptions

Typical Heuristics for Procedure Integration • • • The size of procedure body The

Typical Heuristics for Procedure Integration • • • The size of procedure body The number of calls to this procedure Is the procedure is called inside loop? Whether a call includes constant parameters? Use both static analysis and profiling (if available) • Interprcedural analysis will lead to better results

Name Capture in Procedure integration g(b, c) int b, c; { int a, d;

Name Capture in Procedure integration g(b, c) int b, c; { int a, d; a = b + c; f() { int a, e, d; d= b * c; a = 2; return d; a = b + c; } d = b * c; f() e = d; { int a, e; a = 2; e = g(3, 4); printf(“%dn”, a); }

In-Line Expansion • Substitute low level code (assembly level) • Increase opportunity for using

In-Line Expansion • Substitute low level code (assembly level) • Increase opportunity for using machine capabilities • Poor man’s procedure integration • Two essential mechanisms: – Define templates of machine sequences – A compiler inliner

Leaf-Routine Optimization • Do not call other routines • In practice half of the

Leaf-Routine Optimization • Do not call other routines • In practice half of the routines! • Eliminate prolog and epilog

Shrink Wrapping • Move prolog and epilog into the place where it is necessary

Shrink Wrapping • Move prolog and epilog into the place where it is necessary or remove • The general idea – Move prolog forward – Move epilog backward • Requires data-flow analysis

Shrink Wrapping (Example) save r 8 -r 15 r 2 <= 10 Y N

Shrink Wrapping (Example) save r 8 -r 15 r 2 <= 10 Y N r 1 + 1 r 8 r 2 – 1 r 8 + 2 r 1 + r 2 restore r 8 -r 15

Wrap-Up (Chapter 15) • • Whole procedure optimization Applied early Allows other optimization Most

Wrap-Up (Chapter 15) • • Whole procedure optimization Applied early Allows other optimization Most do not require data-flow analysis

Interprocedural Optimizations • Can be used for procedure integration • Constant propagation can be

Interprocedural Optimizations • Can be used for procedure integration • Constant propagation can be used to optimize procedure bodies • Constant propagation can be used to “clone” procedures • Call-by-value parameters can be passed by reference (if they don’t change) • Register allocation • Improve intraprocedural information

char * Red = “red”; char * Yellow = “yellow”; char * Orange =

char * Red = “red”; char * Yellow = “yellow”; char * Orange = “orange”; char * color(FRUIT Current. Fruit); { switch (current. Fruit->variety) { main() { FRUIT snack; case APPLE: return Red; VARIETY t 1; SHAPE t 2; COLOR t 3; break; t 1 = APPLE; case BANANA: return Yellow; t 2 = ROUND; break; switch (t 1) { case ORANGE: return Orange; }} case APPLE: t 3= Red; main() { FRUIT snack; break; case BANANA: t 3=Yellow; snack. variety = APPLE; snack. shape = ROUND; printf(“%sn”, color(&snack)); } break; case ORANGE: t 3=Orange; }} printf(“%sn”, t 3); }

Pascal Example with value parameters type vector = array[1… 1000] of integer procedure p(v:

Pascal Example with value parameters type vector = array[1… 1000] of integer procedure p(v: vector); procedure q; var a: vector; p(a);

C Example For Constant Propagation int g; p() { … } q(){ … g=100;

C Example For Constant Propagation int g; p() { … } q(){ … g=100; p(); y = g;

Challenges in Interprocedral Analysis • Handling recursion • Parameter passing mechanisms • Hidden calls

Challenges in Interprocedral Analysis • Handling recursion • Parameter passing mechanisms • Hidden calls – – Virtual methods Function pointers Procedural parameters Higher order functions • Scalability • Supporting separate compilation mode

The Call Graph • • A finite directed multi-graph A node per procedure A

The Call Graph • • A finite directed multi-graph A node per procedure A labeled edge per call site Can be constructed incrementally to support separate compilation mode • Difficult to construct in the presence of hidden calls

Example for Call Graph Construction 1: void f() { 2: g(); 3: g(); 4:

Example for Call Graph Construction 1: void f() { 2: g(); 3: g(); 4: h(); } 5: void g() { 6: h(); 7: i(); } 8: void h() {} 9: void i() { 10: g() ; }

Obstacles • • Procedural parameters (P-SPACE hard) Higher order functions Virtual methods Solutions –

Obstacles • • Procedural parameters (P-SPACE hard) Higher order functions Virtual methods Solutions – Conservative approximation – Data-Flow information – Specialization

Flow insensitive side effect analysis • Ignore control flow • Compute for every call

Flow insensitive side effect analysis • Ignore control flow • Compute for every call site: – MOD - the variables that may be modified – DEF - the variables must be defined – USE - the set of variables that may be used before set • Can be computed efficiently for programs with small number of parameters (Cooper & Kennedy) • Can be used for: – program understanding – replacing value by reference parameter – improving intraprocedural information • Becomes tricky with nesting and aliases

program test; var a. b: integer; procedure g(var f 1: integer) begin 1: f

program test; var a. b: integer; procedure g(var f 1: integer) begin 1: f 1 : = f 1 + 1; end procedure f(var f 2, f 3: integer) begin 2: g(f 2); 3: f 3 : = f 2 ; 4: g(f 3); end begin (* main) 5: a : = 5; 6: f(a, b); end.

program test; var a. b: integer; procedure g(var f 1: integer) begin 1: f

program test; var a. b: integer; procedure g(var f 1: integer) begin 1: f 1 : = f 1 + 1; end procedure f(var f 2, f 3: integer) begin 2: g(f 2); 3: f 3 : = f 2 ; 4: g(f 3); end begin (* main) 5: a : = 5; 6: f(a, b); end.

Flow insensitive “points-to” analysis • Analyze C pointers • Find if a pointer “a”

Flow insensitive “points-to” analysis • Analyze C pointers • Find if a pointer “a” may-point to a pointer “b” • Efficient conservative solutions exit a = &x; b = & y; if (…) y = & z; else y = &x; c = &y ; *c = t ;

Flow Sensitive Data-Flow Information • Integrate control flow graph and call graph (the program

Flow Sensitive Data-Flow Information • Integrate control flow graph and call graph (the program supergraph) • In the presence of reference parameters even bit vector problems are hard • Two main solutions: – call strings – functional • Scaling is an issue

Non trivial constants int x void p(int a) { int c; scanf(“%d”, &c); if

Non trivial constants int x void p(int a) { int c; scanf(“%d”, &c); if (c > 0) { a = a -2; p(a); a : = a +2; } x : = -2 * a + 5 printf(“%sn”, x); } void main() { p(7); printf(“%sn”, x) ; }

Conclusion • Interprocedural analysis will be integrated into future compilers • Can be implemented

Conclusion • Interprocedural analysis will be integrated into future compilers • Can be implemented at link time – Register allocation • Will lead to simpler programming • Flow insensitive analysis scales • But what about flow sensitive?