#!/usr/bin/gvpr -f
// Compute the forward partition of the chosen function
//
// Run with graph ... | return-paths | subg-fwd -a functionname
//       or graph ... | subg-fwd


BEGIN {
	// Find the immediate parent subgraph of this object
	graph_t find_owner(obj_t o, graph_t g)
	{
		graph_t g1;
		for (g1 = fstsubg(g); g1; g1 = nxtsubg(g1))
			if(isIn(g1,o)) return g1;
		return NULL;
	}
}

BEG_G {
	graph_t sg = subg ($, sprintf("incoming-%s", ARGV[0]));
	graph_t returns = graph("return-edges", ""); // Temporary graph to hold return edges
	graph_t target, g, g2;
	node_t n;
	edge_t e;
	int i;

	$tvtype = TV_fwd;

	// find the ep corresponding to ARG[0]
	for (g = fstsubg($G); g; g = nxtsubg(g)) {
		if(g.fun == ARGV[0]) {
			n = node($,g.ep);
			$tvroot = n;
			n.style = "filled";
			target = g;
			break;
		}
	}
	if(!target) {
		printf(2, "Function %s not found\n", ARGV[0]);
		exit(1);
	}
}

// Preserve external functions
E [op == "extern"] {
	subnode (sg, head);
}

// Move unused return edges into a separate graph so they don't get followed
N [op == "ret"] {
	for (e = fstout($); e; e = nxtout(e))
		if (e.op == "ret" && !isIn(sg, e.head)) {
			clone(returns, e);
			delete($G, e);
		}
}

// Recover elided return edge for this target node
N [op == "target" && indegree == 1] {
	n = copy(returns, $);
	e = fstin(n); // each target node can only have one return edge
	e = edge(copy(sg, e.tail), $, "recovered"); // clone should work here, but doesn't
	copyA(fstin(n), e);
}

// Copy relevant nodes
N {
	$tvroot = NULL;

	g = find_owner($, $G);
	if(g && g != sg)
		subnode (copy(sg, g), $);
}

END_G {
	induce(sg);
	write(sg);
}
