diff --git a/src/main/java/StupsCompiler.java b/src/main/java/StupsCompiler.java index 6f2813a..50d0eec 100644 --- a/src/main/java/StupsCompiler.java +++ b/src/main/java/StupsCompiler.java @@ -72,10 +72,11 @@ public final class StupsCompiler { System.out.println("Liveness-Analyse für " + filename); final FlowGraphGenerator gen = getFlowGraphGen(filename); - final FlowGraph graph = gen.generateGraph(); final DataFlowGraph dataFlowGraph = DataFlowGraph.fromSourceGraph(graph); - LivenessAnalysis.doLivenessAnalysis(dataFlowGraph, gen.getVarMap()); + + final LivenessAnalysis liveness = LivenessAnalysis.fromDataFlowGraph(dataFlowGraph, gen.getVarMap()); + liveness.doLivenessAnalysis(); } private static FlowGraphGenerator getFlowGraphGen(String filename) { diff --git a/src/main/java/codegen/analysis/liveness/InterferenceGraph.java b/src/main/java/codegen/analysis/liveness/InterferenceGraph.java index 327b91d..c2b52ad 100644 --- a/src/main/java/codegen/analysis/liveness/InterferenceGraph.java +++ b/src/main/java/codegen/analysis/liveness/InterferenceGraph.java @@ -1,4 +1,116 @@ package codegen.analysis.liveness; -public class InterferenceGraph { +import codegen.analysis.dataflow.DataFlowGraph; +import codegen.analysis.dataflow.DataFlowNode; +import util.Logger; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public final class InterferenceGraph { + + private final List nodes; + + private InterferenceGraph(List nodes) { + this.nodes = nodes; + } + + public static InterferenceGraph fromDataFlowGraph(DataFlowGraph graph, Map varMap) { + final List interferenceGraph = new ArrayList<>(); + + // Init graph + for (Map.Entry var : varMap.entrySet()) { + interferenceGraph.add(new InterferenceNode(var.getValue().toString())); + } + + // Determine neighbours + for (DataFlowNode node : graph.getNodes()) { + Logger.log("NODE " + node.getInst() + " - OUT: " + node.getOut()); + + for (String left : node.getOut()) { + if (left.isBlank()) { + continue; + } + + for (String right : node.getOut()) { + if (right.isBlank()) { + continue; + } + + getNodeBySymbol(left, interferenceGraph).addNeighbour(getNodeBySymbol(right, interferenceGraph)); + Logger.log("Add interference neighbour: " + left + " <-> " + right); + } + } + } + + return new InterferenceGraph(interferenceGraph); + } + + private static InterferenceNode getNodeBySymbol(String symbol, List interferenceGraph) { + return interferenceGraph.stream() + .filter(node -> node.getSymbol().equals(symbol)) + .findFirst() + .orElse(null); + } + + // Getters, Setters + + public List getNodes() { + return this.nodes; + } + + // Printing + + public String printToImage() { + if (this.nodes.isEmpty()) { + return "Empty Graph"; + } + + final StringBuilder dot = new StringBuilder(); + + dot.append("digraph dfd {\n") + .append("node[shape=Mrecord]\n"); + + for (InterferenceNode node : this.nodes) { + dot.append(node.getSymbol()) + .append(" [label=\"{ Symbol: ") + .append(node.getSymbol()) + .append("| Color: ") + .append(node.getColor()) + .append("}\"];\n"); + } + + for (InterferenceNode node : this.nodes) { + for (InterferenceNode neigh : node.getNeighbours()) { + if (!dot.toString().contains(neigh.getSymbol() + " -> " + node.getSymbol())) { // No double lines + dot.append(node.getSymbol()).append(" -> ").append(neigh.getSymbol()).append(" [arrowhead=\"none\"];\n"); + } + } + } + + dot.append("}"); + + final String dotOut = dot.toString(); + + final Path dotFile = Paths.get(System.getProperty("user.dir") + "/InterferenceGraph.dot"); + try { + Files.writeString(dotFile, dotOut); + } catch (IOException e) { + e.printStackTrace(); + } + + final ProcessBuilder dotCompile = new ProcessBuilder("dot", "-Tsvg", "-oInterferenceGraph.svg", "InterferenceGraph.dot"); + try { + dotCompile.start(); + } catch (IOException e) { + e.printStackTrace(); + } + + return "Finished."; + } } diff --git a/src/main/java/codegen/analysis/liveness/InterferenceNode.java b/src/main/java/codegen/analysis/liveness/InterferenceNode.java index 9a8c503..6f82f28 100644 --- a/src/main/java/codegen/analysis/liveness/InterferenceNode.java +++ b/src/main/java/codegen/analysis/liveness/InterferenceNode.java @@ -16,10 +16,20 @@ public class InterferenceNode { this.neighbours = new HashSet<>(); } + // Getters, Setters + public String getSymbol() { return this.symbol; } + public Integer getColor() { + return this.color; + } + + public void setColor(int color) { + this.color = color; + } + public void addNeighbour(InterferenceNode node) { if (!node.equals(this)) { this.neighbours.add(node); @@ -30,6 +40,8 @@ public class InterferenceNode { return this.neighbours; } + // Overrides + @Override public int hashCode() { return Objects.hash(this.symbol); @@ -51,12 +63,4 @@ public class InterferenceNode { public String toString() { return this.symbol; } - - public Integer getColor() { - return this.color; - } - - public void setColor(int color) { - this.color = color; - } } diff --git a/src/main/java/codegen/analysis/liveness/LivenessAnalysis.java b/src/main/java/codegen/analysis/liveness/LivenessAnalysis.java index b38ae68..9f04ad0 100644 --- a/src/main/java/codegen/analysis/liveness/LivenessAnalysis.java +++ b/src/main/java/codegen/analysis/liveness/LivenessAnalysis.java @@ -4,25 +4,27 @@ import codegen.analysis.dataflow.DataFlowGraph; import codegen.analysis.dataflow.DataFlowNode; import util.Logger; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; -// TODO: This is just terrible public final class LivenessAnalysis { - private LivenessAnalysis() {} + private final InterferenceGraph interferenceGraph; - public static void doLivenessAnalysis(DataFlowGraph graph, Map varMap) { + private LivenessAnalysis(InterferenceGraph interferenceGraph) { + this.interferenceGraph = interferenceGraph; + } - // Calculate IN, OUT + public static LivenessAnalysis fromDataFlowGraph(DataFlowGraph graph, Map varMap) { + calculateLivenessInOut(graph); // TODO: Copy the graph + + return new LivenessAnalysis(InterferenceGraph.fromDataFlowGraph(graph, varMap)); + } + + private static void calculateLivenessInOut(DataFlowGraph graph) { boolean change; + do { change = false; @@ -43,70 +45,49 @@ public final class LivenessAnalysis { Logger.log(graph.getNodes().indexOf(node) + ": " + node.getInst() + " OUT: " + node.getOut()); } Logger.log("\n"); - - doInterference(graph.getNodes(), varMap); } private static boolean updateInOut(DataFlowNode node) { boolean change; for (DataFlowNode succ : node.getSuccessors()) { + // A variable going live into the successor implies it going live out of the predecessor + node.addOut(succ.getIn()); } final Set addIN = new HashSet<>(node.getOut()); // Copy important - addIN.removeAll(node.getDef()); + addIN.removeAll(node.getDef()); // If a variable that is live-out is defined in the node, it doesn't have to be live-in - change = node.addIn(node.getUse()); - change = change || node.addIn(addIN); + change = node.addIn(node.getUse()); // A variable being used implies it going in live + change = change || node.addIn(addIN); // A variable that is live-out and isn't defined in the node must be live-in return change; } - private static void doInterference(List nodes, Map varMap) { - final List interferenceGraph = new ArrayList<>(); + public void doLivenessAnalysis() { + final int registers = this.colorInterferenceGraph(); - // Init graph - for (Map.Entry var : varMap.entrySet()) { - interferenceGraph.add(new InterferenceNode(var.getValue().toString())); - } + System.out.println("\nRegisters: " + registers); + } - Logger.log("Interference nodes: " + interferenceGraph); + private int colorInterferenceGraph() { + Logger.log("Coloring Interference Graph\n"); - // Determine neighbours - for (DataFlowNode node : nodes) { - Logger.log("NODE " + node.getInst() + " - OUT: " + node.getOut()); - for (String left : node.getOut()) { - if (left.isBlank()) { - continue; - } - - for (String right : node.getOut()) { - if (right.isBlank()) { - continue; - } - - Logger.log("LEFT: " + left + ", RIGHT: " + right); - getNodeBySymbol(left, interferenceGraph).addNeighbour(getNodeBySymbol(right, interferenceGraph)); - Logger.log("Add interference neighbour: " + left + ": " + right); - Logger.log("Neighbours of " + left + ": " + getNodeBySymbol(left, interferenceGraph).getNeighbours()); - } - } - } - - // Color graph int colors = 0; int currentColor; - Logger.log("\n"); - for (InterferenceNode node : interferenceGraph) { + + for (InterferenceNode node : this.interferenceGraph.getNodes()) { + currentColor = 1; + + // Get all colors that can't be used final Set neighbourColors = new HashSet<>(); - Logger.log("Interference node " + node + ", Color = " + node.getColor() + ": Neighbours - " - + node.getNeighbours() + ", NColors - " + neighbourColors); for (InterferenceNode neighbour : node.getNeighbours()) { neighbourColors.add(neighbour.getColor()); } + // Find a color that can be used while (neighbourColors.contains(currentColor)) { currentColor++; } @@ -118,62 +99,8 @@ public final class LivenessAnalysis { } } - Logger.call(() -> printInterferenceGraphToPicture(interferenceGraph)); + Logger.call(this.interferenceGraph::printToImage); - System.out.println("\nRegisters: " + colors); + return colors; } - - // Printing - - private static String printInterferenceGraphToPicture(List graph) { - final StringBuilder dot = new StringBuilder(); - - dot.append("digraph dfd {\n") - .append("node[shape=Mrecord]\n"); - - for (InterferenceNode node : graph) { - dot.append(node.getSymbol()) - .append(" [label=\"{ Symbol: ") - .append(node.getSymbol()) - .append("| Color: ") - .append(node.getColor()) - .append("}\"];\n"); - } - - for (InterferenceNode node : graph) { - for (InterferenceNode neigh : node.getNeighbours()) { - if (!dot.toString().contains(neigh.getSymbol() + " -> " + node.getSymbol())) { // No double lines - dot.append(node.getSymbol()).append(" -> ").append(neigh.getSymbol()).append(" [arrowhead=\"none\"];\n"); - } - } - } - - dot.append("}"); - - final String dotOut = dot.toString(); - - final Path dotFile = Paths.get(System.getProperty("user.dir") + "/InterferenceGraph.dot"); - try { - Files.writeString(dotFile, dotOut); - } catch (IOException e) { - e.printStackTrace(); - } - - final ProcessBuilder dotCompile = new ProcessBuilder("dot", "-Tsvg", "-oInterferenceGraph.svg", "InterferenceGraph.dot"); - try { - dotCompile.start(); - } catch (IOException e) { - e.printStackTrace(); - } - - return "Finished."; - } - - private static InterferenceNode getNodeBySymbol(String symbol, List interferenceGraph) { - return interferenceGraph.stream() - .filter(node -> node.getSymbol().equals(symbol)) - .findFirst() - .orElse(null); - } - }