summaryrefslogtreecommitdiff
path: root/cfg/ControlFlowGraph.java
diff options
context:
space:
mode:
Diffstat (limited to 'cfg/ControlFlowGraph.java')
-rw-r--r--cfg/ControlFlowGraph.java125
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);
+ }
+
+}