1*1f5207b7SJohn Levon#!/usr/bin/gvpr -f
2*1f5207b7SJohn Levon// Split call sites into call site and return site nodes and add
3*1f5207b7SJohn Levon// return edges
4*1f5207b7SJohn Levon//
5*1f5207b7SJohn Levon// Run with graph ... | return-paths
6*1f5207b7SJohn Levon
7*1f5207b7SJohn LevonBEGIN {
8*1f5207b7SJohn Levon	// Find the immediate parent subgraph of this object
9*1f5207b7SJohn Levon	graph_t find_owner(obj_t o, graph_t g)
10*1f5207b7SJohn Levon	{
11*1f5207b7SJohn Levon		graph_t g1;
12*1f5207b7SJohn Levon		for (g1 = fstsubg(g); g1; g1 = nxtsubg(g1))
13*1f5207b7SJohn Levon			if(isIn(g1,o)) return g1;
14*1f5207b7SJohn Levon		return NULL;
15*1f5207b7SJohn Levon	}
16*1f5207b7SJohn Levon}
17*1f5207b7SJohn Levon
18*1f5207b7SJohn LevonBEG_G {
19*1f5207b7SJohn Levon	node_t calls[]; // Crude hash table for tracking who calls what
20*1f5207b7SJohn Levon	graph_t g,g2;
21*1f5207b7SJohn Levon	edge_t e,e2;
22*1f5207b7SJohn Levon	string idx;
23*1f5207b7SJohn Levon	node_t n, n2;
24*1f5207b7SJohn Levon	int i;
25*1f5207b7SJohn Levon
26*1f5207b7SJohn Levon	$tvtype = TV_en;
27*1f5207b7SJohn Levon}
28*1f5207b7SJohn Levon
29*1f5207b7SJohn Levon// Each call edge which hasn't already been seen
30*1f5207b7SJohn LevonE [op == "call" && tail.split != 1] {
31*1f5207b7SJohn Levon	int offset=0;
32*1f5207b7SJohn Levon
33*1f5207b7SJohn Levon	// Clear the label of this call
34*1f5207b7SJohn Levon	label = "";
35*1f5207b7SJohn Levon	g = find_owner(tail, $G);
36*1f5207b7SJohn Levon
37*1f5207b7SJohn Levon	// Consider each outgoing call. Split the node accordingly
38*1f5207b7SJohn Levon	n = tail;
39*1f5207b7SJohn Levon	for (e = fstout(tail); e; e = nxtout(e)) {
40*1f5207b7SJohn Levon		if (e.op == "call") {
41*1f5207b7SJohn Levon
42*1f5207b7SJohn Levon			// Split node
43*1f5207b7SJohn Levon			n2 = node(g, sprintf("%s%s%d", tail.name, "x", offset++));
44*1f5207b7SJohn Levon			copyA(tail, n2);
45*1f5207b7SJohn Levon			n2.line = e.line;
46*1f5207b7SJohn Levon			n2.label = e.line;
47*1f5207b7SJohn Levon			n2.col = e.col;
48*1f5207b7SJohn Levon			n2.split = 1;
49*1f5207b7SJohn Levon			n2.op = "target";
50*1f5207b7SJohn Levon
51*1f5207b7SJohn Levon			// Record this call
52*1f5207b7SJohn Levon			g2 = find_owner(e.head, $G);
53*1f5207b7SJohn Levon			i = 0;
54*1f5207b7SJohn Levon			while(calls[sprintf("%s%d", g2.name, ++i)]) {
55*1f5207b7SJohn Levon			}
56*1f5207b7SJohn Levon			calls[sprintf("%s%d", g2.name, i)] = n2;
57*1f5207b7SJohn Levon
58*1f5207b7SJohn Levon			// Connect original to split
59*1f5207b7SJohn Levon			e2 = edge(n, n2, "call");
60*1f5207b7SJohn Levon			e2.style = "dotted";
61*1f5207b7SJohn Levon			e2.weight = 50;
62*1f5207b7SJohn Levon
63*1f5207b7SJohn Levon			// Replace this outedge
64*1f5207b7SJohn Levon			if (n != tail) {
65*1f5207b7SJohn Levon				e2 = edge(n, e.head, "transformed-call");
66*1f5207b7SJohn Levon				copyA(e,e2);
67*1f5207b7SJohn Levon				e2.label = "";
68*1f5207b7SJohn Levon				delete($G,e);
69*1f5207b7SJohn Levon			}
70*1f5207b7SJohn Levon
71*1f5207b7SJohn Levon			// Record where we were
72*1f5207b7SJohn Levon			n = n2;
73*1f5207b7SJohn Levon		}
74*1f5207b7SJohn Levon	}
75*1f5207b7SJohn Levon
76*1f5207b7SJohn Levon	// Consider the outgoing control flow: move down to the bottom of
77*1f5207b7SJohn Levon	// the call sequence nodes
78*1f5207b7SJohn Levon	for (e = fstout(tail); e; e = nxtout(e)) {
79*1f5207b7SJohn Levon		if (e.op == "br") {
80*1f5207b7SJohn Levon			// Replace this outedge
81*1f5207b7SJohn Levon			e2 = edge(n,e.head,"transformed");
82*1f5207b7SJohn Levon			copyA(e,e2);
83*1f5207b7SJohn Levon			delete($G,e);
84*1f5207b7SJohn Levon		}
85*1f5207b7SJohn Levon	}
86*1f5207b7SJohn Levon}
87*1f5207b7SJohn Levon
88*1f5207b7SJohn Levon// Each return node: add edges back to the caller
89*1f5207b7SJohn LevonN [op == "ret"] {
90*1f5207b7SJohn Levon	for (g = fstsubg($G); g; g = nxtsubg(g)) {
91*1f5207b7SJohn Levon		if(isIn(g,$)) {
92*1f5207b7SJohn Levon			i = 0;
93*1f5207b7SJohn Levon			while(calls[sprintf("%s%d", g.name, ++i)]) {
94*1f5207b7SJohn Levon				e = edge($, calls[sprintf("%s%d", g.name, i)], "return");
95*1f5207b7SJohn Levon				e.style = "dotted";
96*1f5207b7SJohn Levon				e.op = "ret";
97*1f5207b7SJohn Levon				e.line = e.tail.line;
98*1f5207b7SJohn Levon				e.weight = 5;
99*1f5207b7SJohn Levon			}
100*1f5207b7SJohn Levon		}
101*1f5207b7SJohn Levon	}
102*1f5207b7SJohn Levon}
103*1f5207b7SJohn Levon
104*1f5207b7SJohn Levon
105*1f5207b7SJohn LevonEND_G {
106*1f5207b7SJohn Levon	write($);
107*1f5207b7SJohn Levon}
108