Download presentation
Presentation is loading. Please wait.
1
inline substitution algorithm
Kei Hasegawa
2
When inline substitution is performed? (1)
If function call operator is applied to inline function which is already defined, generate 3 address code using call3ac at once, and then immediately perform inline substitution. If inline substitution is performed at this timing, it's enough to apply optimization routine at once.
3
When inline substitution is performed? (2)
If function call operator is applied to inline function which is not defined but just declared, generate 3 address code using call3ac. Described the inline function as f . For function g which calls f, defer assembly code generation of g until f is defined. When f is defined, perform inline substitution for calling f of function g. If no inline function call at code of g and g is not either static or inline, finish generating assembly code of g. If g is declared with static or inline, code generation of g is skipped because of not referencing to g. After this, when g is referenced, enable it to generate inline substituted code. Optimization routine is applied to 3 address code of g before inline substitution of f. After inline substitution of f, it is possible for the same optimization routine to generate better code.
4
Data structure for inline function substitution, where the function is defined after referenced.
namespace defer { map<inline function name, (inline function, use location)> refs; map<inline function name, set<caller function> > callers; map<caller function, vector<int> > positions; }
5
Example 1 inline into f(int a, int b, int c){ if (a) return (b+c)/a; return b-c; } inline void g1(int, int); inline int g2(int, int); int h(int i, int j, int k){ g1(j,k); return f(i,j,k) – g2(k,i); } inline void g1(int d, int e){ if (!e) return; if (d) printf("%d\n", e); } inline int g2(int x, int y){ if (x) return x+y; return y * y; }
6
Calling function `f' from function `h' is converted like bellow:
param i => a := i param j => b := j param k => c := k t3 := call f => if a == 0 goto label0 t0 := b + c t1 := t0 / a return t1 => t3 := t1 goto label1 label0: t2 := b - c return t2 => t3 := t2 goto label2 => label1: (added) => label2: (added)
7
inline int f(int a, int b, int c){ if ( a ) return (b+c)/a : b-c; }
skip::table[f] is created which contains `f', parameter scope of `f' and 3 address code of `f': if a == 0 goto label0 t0 := b + c t1 := t0 / a return t1 label0: t2 := b - c return t2
8
inline substituted code
int h(int i, int j, int k){ g1(j,k); return f(i,j,k) – g2(k,i); } param j param k call g1 a := i b := j c := k if a == 0 goto label0 t0 := b + c t1 := t0 / a t3 := t1 goto label1 label0: t2 := b - c t3 := t2 goto label2 label1: label2: param i t4 := call g2 t5 := t3 - t4 return t5 defer::position[h] inline substituted code defer::position[h]
9
Added block scope scope::root parameter scope of h m_usrs : i, j, k
m_usrs : f, g1, g2 body (block scope) of h m_vars : t4, t5 Added block scope Let operands of inline substituted 3 address code reference the entry of added block scope m_vars : a, b, c Added block scope m_vars : t0, t1, t2, t3
10
Defer assembly code generation of h
skip::table[h] is created and register parameter scope of `h’ and 3 address code of `h’ defer::callers[g1].insert(h) Register position of call g1 at 3 address code of `h’ into defer::positions[h]. defer::callers[g2].insert(h) Samely as `g1’ register position of call g2 at 3 address code of `h’ into defer::positions[h].
11
inline void g1(int d, int e){ if (
inline void g1(int d, int e){ if (!e) return; if (d) printf("%d\n", e); } skip::table[g1] is created which contains g1, parameter scope of g1 and 3 address code of g1: if e != 0 goto label4 return label4: if d == 0 goto label5 t6 := &"%d\n" param t6 param e call printf label5:
12
By referencing to defer::callers[g1] and defer::position[h], perform inline substitution of g1 to 3 address code of h: param j => d := j param k => e := k call g1 => if e != 0 goto label4 reurn => goto label6 label4: if d == 0 goto label5 t6 := &"%d\n" param t6 param e call printf label5: label6:
13
position of call g1 at defer::positions[h]
defer::callers[g1] position of call g1 at defer::positions[h] erased. defer::positions[h] is remained. Because position of call g2 at defer::position[h] is still remained. Defer assembly code generation of h.
14
inline int g2(int x, int y){ if ( x ) return x+y; return y * y; }
skip::table[g2] is created which contains g2, parameter scope of g2 and 3 address code of g2: if x == 0 goto label7 t7 := x + y return t7 label7: t8 := y * y return t8 By referencing defer::caller[g2] and defer::positions[h], perform inline substitution of g2 to 3 address code of h:
15
param k => x := k param i => y := i t4 := call g2 =>
if x == 0 goto label7 t7 := x + y return t7 => t4 := t7 goto label8 label7: t8 := y * y return t8 => t4 := t8 goto label9 label8: (added) label9: (added)
16
inline substitution algorithm
Input 3 address code and position of calling inline function inline function, parameter scope of inline function and 3 address code of inline function Output inline substituted 3 address code Number of 3 address code which replaces for each call3ac
17
param a1 ... param an x := call f
If inline function f takes n arguments, there are n param3ac before calling f. These param3ac are converted to: pi := ai where, pi is a copy of i'th parameter of f. Register p1, ..., pn to added block scope.
18
Replace x := call f or call f
to copies of 3 address code of f Operands of replaced 3 address code may be local variables except for p1, ..., pn, or medium variables. Register these to added block scope. return y of replaced 3 address code of `f' is converted to: x := y goto end where, `end' is a new label and is placed to the end of 3 address code replaced for x := call f. If y is null pointer ( i.e. just return ) , not generate x := y If y is not null pointer but x is null pointer ( i.e. just call f ) , not generate x := y Number of 3 address code which replaces for call3ac is a sum of: number of 3 address code of `f'. number of return y of 3 address code of `f', where y is none-zero.
19
Inline function which takes variable number of arguments
Give up Inline substitution example inline int printf(const char* fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(fmt, ap); ... } void f(int a, double b) { printf(“%d %f\n”, a, b); }
20
Inline function which takes variable number of arguments(2)
3 address code of previous page printf: ap := va_start fmt param fmt param ap call vfprintf ... f: t0 := &”%d %f\n” param a param b call printf 3 address code afeter inline substitution f: t0 := “%d %f\n” fmt := t0 param a param b call vfprintf ...
21
Inline function which takes variable number of arguments (3)
difficult inline substitution example inline int printf(const char* fmt, ...) { va_list ap; va_start(ap, fmt); ... int n = va_arg(ap, int); }
22
Example 2 inline int h(int, int); int main(){ call h }
inline int f0(int a, int b){ ... } inline int f1(int a, int b){ ... } inline int g0(int, int); inline int g1(int, int); int h(int a, int b){ call f0, f1, g0 and g1 } inline int g0(int a, int b){ ...} inline int g1(int a, int b){ ... }
23
After `main’ Before `h’ After `h’ After `g0’ After `g1’
`main’ is registered into skip::table Because of inline function call `h’ from `main’ Before `h’ f0 and f1 are registered into skip::table normally. After `h’ h is registered into skip::table Because `h’ is declared as inline function For function call `h’ of `main’, inline substitution is performed because `main’ exists at callers[h]. While code generation of `main’ Because inline function call g0 and g1 still remain at 3 address code of `main’ , `main’ is registered into skip::table again. After `g0’ g0 is registered into skip::table normally. Perform inline substitution of `g0’ because `main’ exists at callers[g0] Because inline function call g1 still remains at 3 address code of `main’, `main’ is not erased from skip::table. After `g1’ g1 is registered into skip::table normally. Because `main’ exists at callers[g1] , perform inline substitution of `g1’ Because no inline function call at 3 address code of `main’, finish generating assembly code of `main’. Of cause, `main’ is erased from skip::table.
24
How to give up inline substitution
inline int fact(int n){ return n ? n * fact(n-1) : 1; } int main(){ ...; fact(10); ... }
25
For calling fact at `main’ After `main’
After `fact’ `fact’ is registerd into skip::table. For calling fact at `main’ Perform inline substitution as usual. After `main’ While generating code of `main’ inline function `fact’ call exists But `fact’ exists in skip::table Generate code of `fact’ ( and finish it). Finish generating code of `main’. A inline function exists in skip::table, but still exists function call Give up inline substitution.
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.