diff options
Diffstat (limited to 'cfg/ControlFlowGraph.java')
-rw-r--r-- | cfg/ControlFlowGraph.java | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/cfg/ControlFlowGraph.java b/cfg/ControlFlowGraph.java new file mode 100644 index 0000000..c8a7f16 --- /dev/null +++ b/cfg/ControlFlowGraph.java @@ -0,0 +1,125 @@ +package cfg; + +import cs132.vapor.ast.*; +import misc.*; + +import java.util.ArrayList; +import java.util.Arrays; + +public class ControlFlowGraph { + + private VFunction f; // the function represented by this CFG + private ArrayList<CFGNode> nodes; + + public ControlFlowGraph(VFunction f) { + this.f = f; + this.nodes = new ArrayList<>(); + } + + public CFGNode getNode(Object a) { + CFGNode ret = null; + for (CFGNode n : this.nodes) { + if (n.equals(a)) { + ret = n; + break; + } + } + + if (ret == null) { + String str = (a instanceof Node) ? ((Node) a).sourcePos.toString() : + a.toString(); + MinimalLogger.severe(String.format("Could not find a node matching %s", + str)); + } + return ret; + } + + public CFGNode getNextNode(CFGNode a) { + CFGNode ret = null; + // we return null if the passed node is the last in the list + for (int i = 0; i < this.nodes.size()-1; ++i) { + if (this.nodes.get(i).equals(a)) { + ret = this.nodes.get(i+1); + break; + } + } + + if (ret == null) + MinimalLogger.severe(String.format("Could not find the next node for %s", + a.toString())); + + return ret; + + } + + public void addNode(CFGNode n) { + MinimalLogger.info(String.format("Node + %s", + n.toString())); + this.nodes.add(n); + } + + public String addEdge(CFGNode source, CFGNode dest) { + /** + * Iff the CFGNodes are different, construct an edge between them. + * All variables reaching the parent also reach the children. + * + * Returns a string capable of being manipulated by graphviz. + */ + String ret = ""; + if (!source.equals(dest)) { + ret = String.format("%s -> %s", + source.toString(), + dest.toString()); + MinimalLogger.info(String.format("Edge %s", + ret)); + + source.addDest(dest); + dest.addSource(source); + + ret += ";"; + } else { + MinimalLogger.info(String.format("Skipping duplicate edge for %s", + source.toString())); + } + + MinimalLogger.info(String.format("Spilling variables: %s", + source.getReaching().toString())); + dest.reaching.addAll(source.reaching); + + return ret; + } + + public void addReaching(CFGNode n, String s) { + MinimalLogger.info(String.format("Def \"%s\" at %s", + s, + n.toString())); + n.reaching.add(s); + } + + public void addLiveness(CFGNode n, String s) { + if (this.isKnownVar(s)) { + MinimalLogger.info(String.format("Use \"%s\" at %s", + s, + n.toString())); + n.liveness.add(s); + } else + MinimalLogger.info(String.format("Use \"%s\" not a known variable!", + s)); + } + + public ArrayList<CFGNode> getNodes() { + return this.nodes; + } + + protected boolean isKnownVar(String str) { + /** + * Returns true if the variable belongs to the current function. + * Required when matching liveness in certain instructions. + * + * Helper for addLivenessi + */ + return Arrays.asList(f.vars).contains(str) || + Arrays.asList(f.params).contains(str); + } + +} |