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