Transcript
Page 1: Annotating Abstract Syntax Tree

AnnotatingAbstract Syntax Tree

Professor Yihjia Tsai

Tamkang University

Page 2: Annotating Abstract Syntax Tree

Overview

• context handling

• annotating the AST• attribute grammars

• manual methods

• symbolic interpretation

• data-flow equations

program text

lexical analysis

syntax analysis

context handling

annotated AST

tokens

AST

Page 3: Annotating Abstract Syntax Tree

Manual methods for analyzing the AST

• preparing the grounds for code generation• constant propagation

• last-def analysis (reaching definitions)

• live analysis

• common subexpression elimination

• dead-code elimination

• ...

• we need flow-of-control information

Page 4: Annotating Abstract Syntax Tree

Threading the AST

• determine the control flow graph that records the successor(s) of AST nodes

-

*

‘c’

‘4’

*

‘a’

‘b’

*

‘b’

first

last• intermediate code

PUSH b

PUSH b

MUL

PUSH 4

PUSH a

MUL

PUSH c

MUL

SUB

Page 5: Annotating Abstract Syntax Tree

Threading the AST

• result is a post-order traversal of the AST

• global variable: Last node pointer

PROCEDURE Thread binary expression (Expr node pointer):

Thread expression (Expr node pointer .left operand);

Thread expression (Expr node pointer .right operand);

// link this node to the dynamically last node

SET Last node pointer .successor TO Expr node pointer;

// make this node the new dynamically last node

SET Last node pointer TO Expr node pointer;

*

‘c’

‘4’

*

‘a’

Page 6: Annotating Abstract Syntax Tree

Multiple successors

• problem: threading is built around single Last node pointer

IF

condition THEN ELSE

first

last

Page 7: Annotating Abstract Syntax Tree

Multiple successors

• problem: threading is built around single Last node pointer

• solution: introduce join node

IF

condition THEN ELSE

first

last

FI

Page 8: Annotating Abstract Syntax Tree

Symbolic interpretation

• behaviour of code is determined by (the values of) variables

• simulate run-time execution at compile time

• attach a stack representation to each arrow in the control flow graph

• an entry summarizes all compile-time knowledge about the variable/constant

Page 9: Annotating Abstract Syntax Tree

Symbolic interpretation

condition

IF

THEN ELSE

FI

Page 10: Annotating Abstract Syntax Tree

Symbolic interpretation

condition

IF

THEN ELSE

>

y 0yx

5

yx

5

5

yx

5

50

yx

5

T

yx

5

yx

5

yx

5

x = 7;

yx

57

yx

5

dead

code

FI

merge

Page 11: Annotating Abstract Syntax Tree

Exercise (5 min.)

• draw the control flow graph for

while C do S od

• propagate initial stack

when C represents y>x

and S stands for x:=7

yx

5

Page 12: Annotating Abstract Syntax Tree

Answers

Page 13: Annotating Abstract Syntax Tree

Answers

condition

WHILE

BODY

yx

5

yx

5

yx

5yx

5

b

yx

57

Page 14: Annotating Abstract Syntax Tree

Simple symbolic interpretation

• used in narrow compiler

• simple properties + simple control-flow

• example: detecting the use of uninitialized variables

• maintain property list

• advance list through

control flow graph

int foo(int n)

{ int first;

while (n-- > 0) {

if (glob[n] == KEY)

first = n;

}

return first;

}

Page 15: Annotating Abstract Syntax Tree

Trackinguninitialized variables

• parameter declaration:

• variable declaration:

• expression:

• assignment:

• control statement

• fork nodes:

• join nodes:

add (ID:Initialized) tuple

add (ID:Uninitialized) tuple

check status of used variables

set tuple to (ID:Initialized)

copy list

merge lists

merge( Init, Init) = Init

merge( Uninit, Uninit) = Uninit

merge( x, x) = Maybe

int foo(int n)

{ int first;

while (n-- > 0) {

if (glob[n] == KEY)

first = n;

}

return first;

}

Page 16: Annotating Abstract Syntax Tree

Simple symbolic interpretation

• flow-of-control structures with one entry and one exit point (no GOTOs)

• the values of the property are severely constrained (see book)

• example: constant propagation

Page 17: Annotating Abstract Syntax Tree

Constant propagation

• record the exact value iso Initializedint i = 0;

while (condition) {

if (i>0) printf("loop reentered\n");

i++;

}

• simple symbolic interpretation fails

// i == 0

// i == 0

// i == 1

// i == {0,1}

Page 18: Annotating Abstract Syntax Tree

Full symbolic interpretation

• maintain a property list for each entry point (label), initially set to empty

• traverse flow of control graphL: merge current-list into list-L

continue with list-L

jump L;merge current-list into list-L

continue with the empty list

• repeat until nothing changedguarantee termination – select suitable property

Page 19: Annotating Abstract Syntax Tree

int i = 0;

while (condition) {

if (i>0) printf("loop reentered\n");

i++;

}

int i = 0;

L:

if (condition) {

if (i>0) printf("loop reentered\n");

i++;

goto L;

}

Constant propagation

• full symbolic interpretation

• property: unknown < value < any

// i == 0

// i == 1// empty

// i == ANY

// i == ANY

// i == 0

// i == 0// i == ANY

// i == ANY

Page 20: Annotating Abstract Syntax Tree

Data flow equations

• “automated” full symbolic interpretation• stack replaced by collection of sets

• IN(N)• OUT(N)

• semantics are expressed by constant sets• KILL(N)• GEN(N)

• equations• IN(N) = M predecessor[N] OUT(M)

• OUT(N) = IN(N) \ KILL(N) GEN(N)

n = n-1;

IN

OUT

Page 21: Annotating Abstract Syntax Tree

Data flow equations

• solved through iteration (closure algorithm)• data-flow nodes may not change the stack

• individual statements• basic blocks

• example: trackinguninitialized variables• properties: I x, M x, U x• GEN(x = expr ;) =• KILL(x = expr ;) =

int foo(int n)

{ int first;

while (n-- > 0) {

if (glob[n] == KEY)

first = n;

}

return first;

}{I x}{U x, M x}

int foo(int n)

{ int first;

L: n = n-1;

if (n >= 0) {

if (glob[n] == KEY)

first = n;

goto L;

}

return first;

}

Page 22: Annotating Abstract Syntax Tree

T

T

Data flow equations

• solved through iteration (closure algorithm)• data-flow nodes may not change the stack

• individual statements• basic blocks

• example: trackinguninitialized variables• properties: I x, M x, U x• GEN(x = expr ;) =• KILL(x = expr ;) =

{I x}{U x, M x}

if (glob[n] == KEY)

first = n;

goto L;

return first;

L: n = n-1;

if (n >= 0)

F

F

1

2

3

4

5

6

Page 23: Annotating Abstract Syntax Tree

{}

{}

{}

{}

{}

{}

IN(N) = M predecessor[N] OUT(M)

OUT(N) = IN(N) \ KILL(N) GEN(N)

Iterative solution

• initialization: set all sets to empty

• iterate from top to bottom

{I n, U f}

{I n, U f}

{I n, U f}

{I n, U f}

{I n, I f}

{I n, M f}

{I n, M f}

{I n, M f}

T

T F

return first;6

F

first = n;4

goto L;5

L: n = n-1;1

int foo(int n)

{ int first;0

if (glob[n] == KEY)3

if (n >= 0)2

statement KILL GEN

0 In Uf

1 Un Mn In

4 Uf Mf If

Page 24: Annotating Abstract Syntax Tree

Iterative solution

statement

iteration 1 iteration 2

KILL GEN IN OUT IN OUT

0 In Uf In Uf In Uf

1 Un Mn In In Uf In Uf In Uf In Uf

2 In Uf In Uf In Mf In Mf

3 In Uf In Uf In Mf In Mf

4 Uf Mf If In Uf In If In Mf In If

5 In Mf In Mf In Mf In Mf

6 In Uf In Uf In Mf In Mf

Page 25: Annotating Abstract Syntax Tree

Efficient data-flow equations

• limit to (set of) on/off properties• set union = bitwise OR• set difference = bitwise AND NOT

• combine statements into basic blocks• KILL[S1;S2] = KILL[S1] KILL[S2]

• GEN[S1;S2] = GEN[S2] (GEN[S1] \ KILL[S2])

• sort data-flow graph• depth-first traversal (break cycles!)

Page 26: Annotating Abstract Syntax Tree

Live analysis

• a variable is live at node N if the value it holds is used on some path further down the control-flow graph; otherwise it is dead

• useful information for register allocation

• information must flow “backwards” (up) through the control-flow graph• difficult for symbolic interpretation• easy for data flow equations

Page 27: Annotating Abstract Syntax Tree

Solving data-flow equations

• forwards

• backwards

IN(N) = M predecessor[N] OUT(M)

OUT(N) = IN(N) \ KILL(N) GEN(N)

if (cond)

IN

OUT

OUT(N) = M successor[N] IN(M)

IN(N) = OUT(N) \ KILL(N) GEN(N)

Page 28: Annotating Abstract Syntax Tree

Exercise (5 min.)

• determine the KILL and GEN sets for the property “V is live here” for the following statements

statement S KILL GEN

v = a b

v = M[i]

M[i] = v

f(a1, ... ,an)

v = f(a1, ... ,an)

if a>b then goto L1 else goto L2

L:

goto L

Page 29: Annotating Abstract Syntax Tree

Answers

• determine the KILL and GEN sets for the property “V is live here” for the following statements

statement S KILL GEN

v = a b

v = M[i]

M[i] = v

f(a1, ... ,an)

v = f(a1, ... ,an)

if a>b then goto L1 else goto L2

L:

goto L

{v} {a,b} \ KILLS[S]

{v} {i} \ KILLS[S]

{} {i,v}

{} {a1, ... ,an}

{v} {a1, ... ,an} \ KILLS[S]{} {a,b}

{} {}

{} {}

Page 30: Annotating Abstract Syntax Tree

Exercise (7 min.)

• draw the control-flow graph for the following code fragment

• perform backwards live analysis using the KILL and GEN sets from the previous exercise

double average(int n, double v[])

{ int i;

double sum = 0.0;

for (i=0; i<n; i++) {

sum += v[i];

}

return sum/n;

}

Page 31: Annotating Abstract Syntax Tree

Answers

OUT(N) = M successor[N] IN(M)

IN(N) = OUT(N) \ KILL(N) GEN(N)

statement KILL GEN

1

2

3

4

2

3

1

4

Page 32: Annotating Abstract Syntax Tree

Answers

OUT(N) = M successor[N] IN(M)

IN(N) = OUT(N) \ KILL(N) GEN(N)

statement KILL GEN

1

2

3

4

sum = 0.0;

i = 0;

if (i<n)

sum += v[i];

i++;

return sum/n;

2

3

1

4

Page 33: Annotating Abstract Syntax Tree

Answers

sum = 0.0;

i = 0;

if (i<n)

sum += v[i];

i++;

return sum/n;

live: n

live: n, i, sum

live: n, i, sum

live: n, sum

live: n, i, sum

OUT(N) = M successor[N] IN(M)

IN(N) = OUT(N) \ KILL(N) GEN(N)

statement KILL GEN

1 sum, i

2 i, n

3 sum, i sum, i

4 sum, n

2

3

1

4

Page 34: Annotating Abstract Syntax Tree

Answers

statement

iteration 1 iteration 2 iteration 3

KILL GEN OUT IN OUT IN OUT IN

0 n

1 sum, i i, n n i, n, sum n

2 i, n i, n i, n, sum i, n, sum i, n, sum i, n, sum

3 sum, i sum, i i, n i, n, sum i, n, sum i, n, sum i, n, sum i, n, sum

4 sum, n n, sum i, n, sum i, n, sum

process nodes top to bottom (from 0 to 4)

processing nodes in reverse (from 4 to 0) requires only two iterations

Page 35: Annotating Abstract Syntax Tree

Summary

manual methods for annotating the AST• threading

• symbolic interpretation

• data-flow equations

symbolic interpretationdata-flow equations

simple full

method stack-based simulation IN, OUT, GEN, KILL sets

granularity AST node basic block

algorithm one-pass iterative iterative

direction forwards forwards & backwards


Top Related