1f08c3bdfSopenharmony_ci#!/usr/bin/gvpr -f
2f08c3bdfSopenharmony_ci// Compute the forward partition of the chosen function
3f08c3bdfSopenharmony_ci//
4f08c3bdfSopenharmony_ci// Run with graph ... | return-paths | subg-fwd -a functionname
5f08c3bdfSopenharmony_ci//       or graph ... | subg-fwd
6f08c3bdfSopenharmony_ci
7f08c3bdfSopenharmony_ci
8f08c3bdfSopenharmony_ciBEGIN {
9f08c3bdfSopenharmony_ci	// Find the immediate parent subgraph of this object
10f08c3bdfSopenharmony_ci	graph_t find_owner(obj_t o, graph_t g)
11f08c3bdfSopenharmony_ci	{
12f08c3bdfSopenharmony_ci		graph_t g1;
13f08c3bdfSopenharmony_ci		for (g1 = fstsubg(g); g1; g1 = nxtsubg(g1))
14f08c3bdfSopenharmony_ci			if(isIn(g1,o)) return g1;
15f08c3bdfSopenharmony_ci		return NULL;
16f08c3bdfSopenharmony_ci	}
17f08c3bdfSopenharmony_ci}
18f08c3bdfSopenharmony_ci
19f08c3bdfSopenharmony_ciBEG_G {
20f08c3bdfSopenharmony_ci	graph_t sg = subg ($, sprintf("incoming-%s", ARGV[0]));
21f08c3bdfSopenharmony_ci	graph_t returns = graph("return-edges", ""); // Temporary graph to hold return edges
22f08c3bdfSopenharmony_ci	graph_t target, g, g2;
23f08c3bdfSopenharmony_ci	node_t n;
24f08c3bdfSopenharmony_ci	edge_t e;
25f08c3bdfSopenharmony_ci	int i;
26f08c3bdfSopenharmony_ci
27f08c3bdfSopenharmony_ci	$tvtype = TV_fwd;
28f08c3bdfSopenharmony_ci
29f08c3bdfSopenharmony_ci	// find the ep corresponding to ARG[0]
30f08c3bdfSopenharmony_ci	for (g = fstsubg($G); g; g = nxtsubg(g)) {
31f08c3bdfSopenharmony_ci		if(g.fun == ARGV[0]) {
32f08c3bdfSopenharmony_ci			n = node($,g.ep);
33f08c3bdfSopenharmony_ci			$tvroot = n;
34f08c3bdfSopenharmony_ci			n.style = "filled";
35f08c3bdfSopenharmony_ci			target = g;
36f08c3bdfSopenharmony_ci			break;
37f08c3bdfSopenharmony_ci		}
38f08c3bdfSopenharmony_ci	}
39f08c3bdfSopenharmony_ci	if(!target) {
40f08c3bdfSopenharmony_ci		printf(2, "Function %s not found\n", ARGV[0]);
41f08c3bdfSopenharmony_ci		exit(1);
42f08c3bdfSopenharmony_ci	}
43f08c3bdfSopenharmony_ci}
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_ci// Preserve external functions
46f08c3bdfSopenharmony_ciE [op == "extern"] {
47f08c3bdfSopenharmony_ci	subnode (sg, head);
48f08c3bdfSopenharmony_ci}
49f08c3bdfSopenharmony_ci
50f08c3bdfSopenharmony_ci// Move unused return edges into a separate graph so they don't get followed
51f08c3bdfSopenharmony_ciN [op == "ret"] {
52f08c3bdfSopenharmony_ci	for (e = fstout($); e; e = nxtout(e))
53f08c3bdfSopenharmony_ci		if (e.op == "ret" && !isIn(sg, e.head)) {
54f08c3bdfSopenharmony_ci			clone(returns, e);
55f08c3bdfSopenharmony_ci			delete($G, e);
56f08c3bdfSopenharmony_ci		}
57f08c3bdfSopenharmony_ci}
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_ci// Recover elided return edge for this target node
60f08c3bdfSopenharmony_ciN [op == "target" && indegree == 1] {
61f08c3bdfSopenharmony_ci	n = copy(returns, $);
62f08c3bdfSopenharmony_ci	e = fstin(n); // each target node can only have one return edge
63f08c3bdfSopenharmony_ci	e = edge(copy(sg, e.tail), $, "recovered"); // clone should work here, but doesn't
64f08c3bdfSopenharmony_ci	copyA(fstin(n), e);
65f08c3bdfSopenharmony_ci}
66f08c3bdfSopenharmony_ci
67f08c3bdfSopenharmony_ci// Copy relevant nodes
68f08c3bdfSopenharmony_ciN {
69f08c3bdfSopenharmony_ci	$tvroot = NULL;
70f08c3bdfSopenharmony_ci
71f08c3bdfSopenharmony_ci	g = find_owner($, $G);
72f08c3bdfSopenharmony_ci	if(g && g != sg)
73f08c3bdfSopenharmony_ci		subnode (copy(sg, g), $);
74f08c3bdfSopenharmony_ci}
75f08c3bdfSopenharmony_ci
76f08c3bdfSopenharmony_ciEND_G {
77f08c3bdfSopenharmony_ci	induce(sg);
78f08c3bdfSopenharmony_ci	write(sg);
79f08c3bdfSopenharmony_ci}
80