interprocedural control dependence james ezick and kiri wagstaff cs 612 may 4, 1999
TRANSCRIPT
2
Outline
• Motivation• Some essential terms• Constructing the interprocedural postdominance
relation• Answering interprocedural control dependence
queries• Future work
3
Motivation
• As we have seen in class the Roman Chariots formulation for intraprocedural control dependence (Pingali & Bilardi) has allowed control dependence queries to be answered in (optimal) time proportional to the output size.
• We seek to extend that work to cover control flow graphs representing multiple procedures without the need for fully cloning each function.
4
How would that make the world better?
• Recall that control dependence (conds) is the same as the edge dominance frontier relation of the reverse graph.
• Recall that the dominance frontier relation is used in the construction of SSA form representations.
• If we could build this representation faster it would allow us perform a wide range of code optimizations in a more uniform and more efficient manner.
5
Valid Paths - Context Sensitive Analysis
• Valid path: A path from START to END in which call and return edges occur in well-nested pairs and in which these pairs correspond to call sites and the return sites specific to these call sites.
START
a
b
c
d
F
END
This is intended to exactly capture ourintuition of a call stack.
6
Other Terms
• Node w interprocedurally postdominates v if every valid path from v to end contains w.
• Node w is ip control dependent on edge (u v) if– w ip postdominates v
– w does not strictly ip postdominate u
We notice immediately that these definitions are completely analogous to their intraprocedural counterparts - they however incorporate the notionof valid paths.
7
First postdominence, then the world!
As the definitions suggest there is a tight relationship between control dependence and postdominance.
To compute control dependence we first would like to compute postdominance subject to the following criteria:
• We minimize cloning to the fullest possible extent.• We are able to parallelize the process. (One
function - one thread).• We can deal with all common code constructs
(including recursion).
8
Computing Postdominance
• In the intraprocedural case every path through the control flow graph is a valid path and the resulting postdominance relation is a tree.
• Algorithms exist to produce this tree which run in time linear in the size of the control flow graph (Rodgers, et al.).
• The introduction of non-valid paths into the CFG breaks this property - the transitive reduction is now a DAG.
9
How is this done today?
• We use iterative methods and context sensitive flow analysis to compute postdominance and control dependence.
• This involves keeping a table of inputs and outputs.
• Convergence occurs due to the finite nature of the table but it is not guaranteed to occur quickly.
10
General Description
• First, we do a generalized form of dataflow analysis in which each procedure acts as a single block box transition function.
• By keeping a table of inputs and outputs of this function for each procedure we gain efficiency and can detect termination.
• After the interprocedural relationships are understood - we compute the intraprocedural info for each procedure in the usual way.
11
Where we break down
Start
End
F-start
F-a
F-end
G-start
G-a
G-end
A
B C
D E
H I
J K
L
Call F
Call G
Call G
Call F
Ret G
Ret FRet G
Ret F
End
StartL
J K
H
G-start
G-a
G-end F-end
F-a
F-start
I
D E
B C
A
Notice the existence of an invalid path:Start-A-B-(F-Start)-(F-a)-(F-end)-K-L-End
Control Flow Graph Postdominance DAG
12
So What?
• We could ignore the invalid paths and claim that we are being “conservative”.
• However, if we do this we lose the fact that A is postdominated by both F and G - this is vital information that we can’t sacrifice and still expect to be able to compute control dependence.
• We need to construct this DAG in its full form.
13
Observations
• We notice that the postdominance relations for F and G are subgraphs of the entire postdominance relation.
• This begs the question - Can we simply compute the postdominance relation with place-holders for F and G and then simply splice the F and G graphs in later?
• What information would we need to do this?
14
First Attempt
• Is it enough to simply know the two nodes that “bookend” all the calls to a specific function?
Start
End
Call F
Ret F
Call F
Ret F
A
B C
D
E G
H I
Start
End
A
D
B C
E
H
Call FG
I Ret F
Call F
Ret F
End
StartD
B C I
G
H
E
A
We notice that these two distinct control flow graphs produce the same postdominance DAG minus the presence of the F subgraph. Further, [A,D] bookends the calls to F in each case.
15
Defeat!
• Clearly, this technique fails to capture the fact that in the first case the F subgraph should postdominate both B and C whereas in the second case it should not.
• Conclusion: we need to know more than which link to break - we need to know what to do with the ancestors of the destination.
16
Correct Solutions after Splicing
StartD
B C I
G
H
E
F
A
StartD
C
I
G
H
E
F
A
B
Case I Case II
We need more information than which connection to break to accurately do this splice.
EndEnd
17
What do we need to know?
• We can think of a tree or a DAG as a representation of a partial order. Specifically we can think of the postdominance relation as a partial order since it is reflexive, anti-symmetric and transitive.
• Given this insight, we see that we need to inject the F subgraph into the partial order. Simply knowing two bounds is not enough to do this.
18
It gets worse
• In the example provided we only needed to place B & C - singleton ancestors of D. In fact we can build CFGs where we have arbitrarily complex subgraphs feeding into D.
D
A
FWe want to “splice” F in between D and A.
UVW
X
Y
Z
19
• In order to inject F into the partial order we must also inject F into every path from a terminal to D.
100,100
0,0
F
40,7560,60
70,7050,80
90,90
65,45
We define the partial order as := (a,b) < (c,d) iff (a<c) and (b<d).
100,100
0,0
F
40,7560,60
70,7050,80
90,90
65,45
100,100
0,0
F
40,7560,60
70,70
50,80
90,90
65,45
95,5 95,9572,78
Furthermore, determining where to break each path requires a sequence of UPD queries.
20
Union Postdominance
• We say that a set T union postdominates a set S in an interprocedural control flow graph if every valid path from an element of S to end contains an element of T.
• In the preceding case we must determine for each element of the subtree if it is union postdominated by all of the calls to a specific function.
• This is clearly not promising.• This extends Generalized Dominators (Gupta 92).
21
OK, so we do that - what then?
• Our problems do not end there - consider the following CFG.
Start
End
B C
DE
I
Call F
Ret F
Call G
Ret G
Call H
Ret H
F-Start
F-End
F-A
F-B Call H
Ret H
G-Start
G-End
H-Start
H-End
H-A
Control Flow Graph for Main Control Flow Graph for F Control Flow Graph for G Control Flow Graph for H
G-A
G-C
G-D
G-E
G-B
22
• When we splice in and expand the graphs for F and G we get two copies of H!
H
H
End
Start
E
F-End
F-B
F-A
F-Start
CB
G-C
G-Start
G-D
G-E
G-B
G-End
D
A
I
Maybe this isn’t so bad - can’t we just “merge” them somehow?
G-A
23
Oh, it’s bad.
• Given the partial postdominance relation all I can recover from it about H is that H should be a child of I.
• I don’t know which link from I to break; also I again don’t know what to do with the other children of I.
• As with the previous case I can create CFGs that make this arbitrarily complicated. Further I must now do UPD queries over the entire CFG.
24
Plan “A” is a loser
• It is clear that we cannot simply compute these function DAGs independently and then splice them together since the splicing is more expensive than the original computation.
• We need to find a way to incorporate the splicing information into the original computation.
• In essence we need subgraph “placeholders” for each function.
25
A New Hope
• It is clear that in order to construct the postdominator relation componentwise we need more a priori information.
• In essence we need to understand all of the possible call sequences a program segment can initiate - then we let transitivity do the rest.
• To that end we introduce the notion of “sparse stubs”.
26
Sparse Stubs
• Given a program for which we want to construct a control flow graph we construct a sparse representation in parallel that captures only calls and branches.
• We then use this sparse representation as a “stub” which we inject into the gap between a call and return.
• This stub then captures what we need to construct a PDD into which we can inject full subgraphs.
27
An Example
HH
Start
End
F-Start
F-End
G-Start
G-End
Sparse Representation
Notice that this captures every possible sequence of calls in the program (starts and ends).
Since H is a “terminal function” we can represent it as a singleton. F, G (which are not terminal) cannot be represented this way - else we could not distinguish between “F calls H” and “call F then H”.
We can employ similar shortcuts to eliminate “repeated suffixes” (ex. “call F, call G, call F”)In the case of recursion the sparse graph will have a loop from the call back to the start node of the function - but that’s fine.
28
That’s great. What now?
• We notice immediately some interesting properties of this sparse graph. First any function that is called multiple times will have multiple representations in this graph - but they are all the same. Build them once and use pointers.
• If we inject into the “call gap” of a function the subgraph of the sparse representation between start and end we get a “plug” for the gap.
29
What about this plug?
• We notice that the plug captures exactly all of the valid paths of the program.
• Further, it contains enough information to produce in the resulting PDD placeholders for the component functions.
• The price of this good fortune is that we now have duplicate nodes in the control flow graph (these however are all start & end nodes).
30
Union Postdominance
• We now have a purely graph theoretic problem for which we need (have?) a good algorithm.
• Given a directed graph with a source and sink and a partition of the nodes P - construct the PDD consisting of the elements of the partition.
• We have a naïve quadratic algorithm to do this but we are looking at existing algorithms with better performance that solve similar problems.
31
Can’t we just see an example?
HH
Start
End
F-Start
F-End
G-Start
G-End
Sparse Representation
Start
End
B C
DE
I
Call F
Ret F
Call G
Ret G+ =
Control Flow Graph for Main
Start
End
B C
DE
I
H
F-Start
F-End
H
G-Start
G-End
CFG ready for UPD AlgorithmIn this case the partition P is the set of singletonswith the two H nodes in a single set.
32
Produce the UPDD for each function
Start
End
B C
DE
I
H
F-Start
F-End
H
G-Start
G-End
H
Notice that this is a tree - there are no invalid paths!
End
Start
B C
G-Start
G-End
F-Start
F-End
A
I
ED
H appears in this graph only once - in exactly the correct location!
UPD Algorithm
Given this UPDD and the other UPDDs for F, G & H we use the starts and ends as placeholders to splice them in.In essence, we “pattern match” to construct the full UPDD. (In practice - use pointers.)
33
Final Observations
• We notice that the only cloning which has occurred related to the functions called - not their functionality
• Once the sparse stub graph is constructed the individual UPDD can be constructed independently.
• Using pointers - splicing is now constant time.• We can deal with recursion and cyclic calls.
34
Control Dependence
• Node w is control dependent on edge (u v) if– w postdominates v
– w does not strictly postdominate u
Control Flow Graph Postdominator Tree
START
a
b
c e
d END
END
d
e
c
b
a
START
a b c d e
Control Dependence Relation
START a
b c
35
Queries on Control Dependence
• cd(e): set of nodes control dependent on edge e
• conds(v): set of edges v is control dependent on
• cdequiv(v): set of nodes with same control dependencies as node v
a b c d e
Control Dependence Relation
START a
b c
36
Roman Chariots: cd(e)• Represent cd(e) as an interval on the pdom tree• cd(u v) = [v, END] - [u, END] = [v, parent(u))
– cd(START a) = [a, END)– cd(b c) = [c, e)
a b c d e
Control Dependence Relation
START a
b c
Postdominator Tree
END
d
e
c
b
a
START
a
37
Roman Chariots: conds(v)
• Record intervals at bottom endpoints
• Variable amounts of caching
No caching
END
d
e
c
b
a a
Full caching
END
d
e
c
b
a a{1}
STARTSTART
{2} {2}
{2}
{1}
{1,2}
{1}
{}
{}
Edge Interval
1 START a [a, END)
2 b c [c, e)
38
Vertex conds(v) Size Lo
a {1} 1 a
b {1,2} 2 b
e {1} 1 a
Roman Chariots: cdequiv(v)
• Compute fingerprints for conds sets– size of conds set
– lo(conds): lowest node contained in all intervals in conds set
• Two conds sets are equal iff fingerprints matchIntervals
1 START a [a, END)
2 b c [c, e)
39
The Interprocedural Case
• Postdominance relation is a DAG, not a tree
Control Flow Graph Postdominator DAG
START
a
b f
j
END
END
ge
j
fe
i
START
c
d
g
h
ie call F
call Gcall F
call Gh
g
f
a
gsfse
d
c
b
40
Interprocedural cd Queries
• cd(u v) = [v, END] - [u, END]
• Tree: linear interval
• DAG: many paths!
• No simple parent(v) trick (v may have multiple parents)
• In fact, we want an all-paths interpretation
• Roman Aqueducts!– u is a polluted source, v is a pure source
– Emperor: “Which cities still have clean water?”
41
Intervals on the DAG
• To compute cd(u v), need [v, END] - [u, END]• Break [v, END] into aqueducts (linear intervals)• For each aqueduct, is endpoint pollutable
(reachable) by u?• If so, replace endpoint with point where flows
from u and v merge (LCA(startpoint, u))– change interval to open instead of closed to ensure
exclusion of (polluted) LCA
• Then cd(u v) = union of (modified) aqueducts
42
Example: cd(a b)
cd(a b)
= [b,b] + [c,d] + [fs,fs) +
[e, j) +[gs,gs)
= {b,c,d,e}Postdominator DAG
END
ge
j
fe
i
START
h
g
f
a
gsfse
d
c
b
Aqueduct Reachablefrom a?
LCA(startpoint,a)
ModifiedAqueduct
[b, b] N - [b, b]
[c, d] N - [c, d]
[fs, END] Y fs [fs, fs)
[e, END] Y j [e, j)
[gs, END] Y gs [gs, gs)
43
Interprocedural conds Queries
• Emperor: “Which flows pass through a certain city?”
• Search all aqueduct systems for that city
• Faster: use variable caching
Postdominator DAG
END
ge
j
fe
i
START
h
g
f
a
gsfse
d
c
b
Edge Aqueduct System
1 START a {a,fs,fe,gs,ge,j}
2 a b {b,c,d,e}
3 a f {f,g,h,i}
44
Interprocedural cdequiv Queries
• Emperor: “I know that one city is polluted. What other cities are similarly affected?”
• Compare aqueduct systems for all cities for matches
• Faster: apply ‘fingerprint’ approach
45
Final Observations II
• We can compute intervals on the DAG (viewed as Roman Aqueducts)
• We have shown procedures for answering interprocedural control dependence queries
• We may be able to extend the faster methods from the Roman Chariots approach to the interprocedural case as well
46
In Conclusion ...
• We have demonstrated a foundation on which to build an interprocedural analysis capable of dealing with modern programming constructs without resorting to iteration or extensive cloning.
• What lies ahead is to prove this foundation correct and superior to existing techniques with more rigorous proofs and a working implementation.
• At this time we are very optimistic about this formulation.