From 3ec67234f3db331d0fac860a3094288860eb0cea Mon Sep 17 00:00:00 2001 From: ChUrl Date: Fri, 29 Jan 2021 21:54:32 +0100 Subject: [PATCH] horrible messy liveness analysis, will be redone --- src/main/java/StupsCompiler.java | 48 +++++ .../analysis/liveness/InterferenceGraph.java | 4 + .../analysis/liveness/InterferenceNode.java | 62 ++++++ .../analysis/liveness/LivenessAnalysis.java | 178 ++++++++++++++++++ 4 files changed, 292 insertions(+) create mode 100644 src/main/java/codegen/analysis/liveness/InterferenceGraph.java create mode 100644 src/main/java/codegen/analysis/liveness/InterferenceNode.java create mode 100644 src/main/java/codegen/analysis/liveness/LivenessAnalysis.java diff --git a/src/main/java/StupsCompiler.java b/src/main/java/StupsCompiler.java index fb75041..2bfca0b 100644 --- a/src/main/java/StupsCompiler.java +++ b/src/main/java/StupsCompiler.java @@ -1,4 +1,8 @@ import codegen.CodeGenerator; +import codegen.analysis.dataflow.DataFlowGraph; +import codegen.analysis.liveness.LivenessAnalysis; +import codegen.flowgraph.FlowGraph; +import codegen.flowgraph.FlowGraphGenerator; import lexer.StupsLexer; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.Lexer; @@ -102,5 +106,49 @@ public final class StupsCompiler { private static void liveness(String filename) { System.out.println("Liveness-Analyse für " + filename); + + // File opening + Lexing + Lexer lexer; + try { + // Relativer Pfad + + final Path programPath = Paths.get(System.getProperty("user.dir") + "/" + filename); + lexer = new StupsLexer(CharStreams.fromPath(programPath)); + } catch (IOException e) { + + try { + // Absoluter Pfad + + final Path programPath = Paths.get(filename); + lexer = new StupsLexer(CharStreams.fromPath(programPath)); + } catch (IOException ee) { + System.out.println("Das Programm konnte nicht gelesen werden."); + return; + } + } + + // Grammar parsing from file + final Grammar grammar; + try { + final Path grammarFile = Paths.get(System.getProperty("user.dir") + "/stups.grammar"); + grammar = Grammar.fromFile(grammarFile); + } catch (IOException e) { + System.out.println("Die Grammatik konnte nicht geöffnet werden."); + return; + } + + // Parser from Grammar + final StupsParser stupsParser = StupsParser.fromGrammar(grammar); + + // Parsing + Typechecking of program + final AST tree = stupsParser.parse(lexer.getAllTokens(), lexer.getVocabulary()); + tree.postprocess(grammar); + final Map nodeTable = TypeChecker.validate(tree); + + final FlowGraphGenerator gen = FlowGraphGenerator.fromAST(tree, nodeTable, filename); + final FlowGraph graph = gen.generateGraph(); + final DataFlowGraph dataFlowGraph = DataFlowGraph.fromSourceGraph(graph); + + LivenessAnalysis.doLivenessAnalysis(dataFlowGraph, gen.getVarMap()); } } diff --git a/src/main/java/codegen/analysis/liveness/InterferenceGraph.java b/src/main/java/codegen/analysis/liveness/InterferenceGraph.java new file mode 100644 index 0000000..327b91d --- /dev/null +++ b/src/main/java/codegen/analysis/liveness/InterferenceGraph.java @@ -0,0 +1,4 @@ +package codegen.analysis.liveness; + +public class InterferenceGraph { +} diff --git a/src/main/java/codegen/analysis/liveness/InterferenceNode.java b/src/main/java/codegen/analysis/liveness/InterferenceNode.java new file mode 100644 index 0000000..9a8c503 --- /dev/null +++ b/src/main/java/codegen/analysis/liveness/InterferenceNode.java @@ -0,0 +1,62 @@ +package codegen.analysis.liveness; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +public class InterferenceNode { + + private final String symbol; + private final Set neighbours; + private int color; + + public InterferenceNode(String symbol) { + this.symbol = symbol; + this.color = 0; + this.neighbours = new HashSet<>(); + } + + public String getSymbol() { + return this.symbol; + } + + public void addNeighbour(InterferenceNode node) { + if (!node.equals(this)) { + this.neighbours.add(node); + } + } + + public Set getNeighbours() { + return this.neighbours; + } + + @Override + public int hashCode() { + return Objects.hash(this.symbol); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || this.getClass() != o.getClass()) { + return false; + } + final InterferenceNode that = (InterferenceNode) o; + return this.symbol.equals(that.symbol); + } + + @Override + 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 new file mode 100644 index 0000000..035d63e --- /dev/null +++ b/src/main/java/codegen/analysis/liveness/LivenessAnalysis.java @@ -0,0 +1,178 @@ +package codegen.analysis.liveness; + +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() {} + + public static void doLivenessAnalysis(DataFlowGraph graph, Map varMap) { + + // Calculate IN, OUT + boolean change; + do { + change = false; + + for (DataFlowNode node : graph.getNodes()) { + if (graph.getNodes().indexOf(node) == graph.getNodes().size() - 1) { + // Skip END + + continue; + } + + change = change || updateInOut(node); + } + } while (change); + + Logger.log("IN, OUT Sets:"); + for (DataFlowNode node : graph.getNodes()) { + Logger.log(graph.getNodes().indexOf(node) + ": " + node.getInst() + " IN: " + node.getIn()); + 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()) { + node.addOut(succ.getIn()); + } + + final Set addIN = new HashSet<>(node.getOut()); // Copy important + addIN.removeAll(node.getDef()); + + change = node.addIn(node.getUse()); + change = change || node.addIn(addIN); + + return change; + } + + private static void doInterference(List nodes, Map varMap) { + final List interferenceGraph = new ArrayList<>(); + + // Init graph + for (Map.Entry var : varMap.entrySet()) { + interferenceGraph.add(new InterferenceNode(var.getValue().toString())); + } + System.out.println("Interference nodes: " + interferenceGraph); + + // 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) { + currentColor = 1; + 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()); + } + + while (neighbourColors.contains(currentColor)) { + currentColor++; + } + + node.setColor(currentColor); + + if (currentColor > colors) { + colors = currentColor; + } + } + + printInterferenceGraphToPicture(interferenceGraph); + + System.out.println("\nLiveness: " + colors + " register nötig."); + } + + // 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); + } + +}