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