diff options
Diffstat (limited to 'gvpr/subg-fwd')
| -rw-r--r-- | gvpr/subg-fwd | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/gvpr/subg-fwd b/gvpr/subg-fwd new file mode 100644 index 00000000..8950fa5c --- /dev/null +++ b/gvpr/subg-fwd @@ -0,0 +1,78 @@ +// Compute the forward partition of the chosen function +// +// Run with graph ... | gvpr -f return-paths | gvpr -f subg-fwd -a functionname +// or graph ... | gvpr -f 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); +} |
