diff --git a/src/main/java/codegen/analysis/dataflow/DataFlowGraph.java b/src/main/java/codegen/analysis/dataflow/DataFlowGraph.java index 80a3090..dc03220 100644 --- a/src/main/java/codegen/analysis/dataflow/DataFlowGraph.java +++ b/src/main/java/codegen/analysis/dataflow/DataFlowGraph.java @@ -3,7 +3,6 @@ package codegen.analysis.dataflow; import codegen.flowgraph.FlowBasicBlock; import codegen.flowgraph.FlowGraph; import codegen.flowgraph.FlowInstruction; -import util.Logger; import java.io.IOException; import java.nio.file.Files; @@ -13,73 +12,86 @@ import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; +/** + * Die Instruktionen repräsentiert durch einen Graphen. + */ public final class DataFlowGraph implements Iterable { - // TODO: Why use list, its a graph - private final List graph; + // List for easy indexing + private final List dataFlowNodes; - private DataFlowGraph(List graph) { - this.graph = Collections.unmodifiableList(graph); - Logger.call(this::printToImage); + private DataFlowGraph(List dataFlowNodes) { + this.dataFlowNodes = Collections.unmodifiableList(dataFlowNodes); } - public static DataFlowGraph fromSourceGraph(FlowGraph srcGraph) { - final List graph = new LinkedList<>(); + public static DataFlowGraph fromFlowGraph(FlowGraph flowGraph) { + final List dataFlowNodes = new LinkedList<>(); - for (FlowBasicBlock block : srcGraph) { - for (FlowInstruction inst : block) { - graph.add(DataFlowNode.fromFlowNode(inst, block)); + // Initialize all DataFlowNodes + for (FlowBasicBlock basicBlock : flowGraph) { + for (FlowInstruction instruction : basicBlock) { + dataFlowNodes.add(DataFlowNode.fromFlowNode(instruction)); } } - initSuccPred(srcGraph, graph); + final DataFlowGraph dataFlowGraph = new DataFlowGraph(dataFlowNodes); + initNodePosition(flowGraph, dataFlowGraph); - return new DataFlowGraph(graph); + return dataFlowGraph; } - private static void initSuccPred(FlowGraph srcGraph, List graph) { - for (FlowBasicBlock block : srcGraph) { - for (FlowInstruction inst : block) { - final DataFlowNode current = getNodeByInstruction(inst, graph); + /** + * Jeder {@link DataFlowNode} im {@link DataFlowGraph} wird anhand des {@link FlowGraph} positioniert. + * Dabei werden für den Node die Predecessors und Successors gesetzt. + */ + private static void initNodePosition(FlowGraph flowGraph, DataFlowGraph dataFlowGraph) { + for (FlowBasicBlock basicBlock : flowGraph) { + for (FlowInstruction instruction : basicBlock) { - for (FlowInstruction pred : block.getPredecessors(inst)) { - final DataFlowNode currentPred = getNodeByInstruction(pred, graph); + final Optional currentNode = getNodeByInstructionId(instruction, dataFlowGraph); - current.addPredecessor(currentPred); - currentPred.addSuccessor(current); + if (currentNode.isEmpty()) { + continue; } - for (FlowInstruction succ : block.getSuccessors(inst)) { - final DataFlowNode currentSucc = getNodeByInstruction(succ, graph); + for (FlowInstruction predecessor : basicBlock.getInstructionPredecessorSet(instruction)) { + final Optional currentPredecessor = getNodeByInstructionId(predecessor, dataFlowGraph); + currentPredecessor.ifPresent(dataFlowNode -> currentNode.get().addPredecessor(dataFlowNode)); + } - Logger.log("INST: " + current.getInst() + ", SUCC: " + currentSucc.getInst()); - current.addSuccessor(currentSucc); - currentSucc.addPredecessor(current); + for (FlowInstruction successor : basicBlock.getInstructionSuccessorSet(instruction)) { + final Optional currentSuccessor = getNodeByInstructionId(successor, dataFlowGraph); + currentSuccessor.ifPresent(dataFlowNode -> currentNode.get().addSuccessor(dataFlowNode)); } } } } - private static DataFlowNode getNodeByInstruction(FlowInstruction inst, List graph) { - return graph.stream() - .filter(node -> node.getId().equals(inst.getId())) - .findFirst() - .orElse(null); + private static Optional getNodeByInstructionId(FlowInstruction instruction, DataFlowGraph dataFlowGraph) { + return dataFlowGraph.stream() + .filter(node -> node.getId().equals(instruction.getId())) + .findFirst(); } public int indexOf(DataFlowNode node) { - return this.graph.indexOf(node); + return this.dataFlowNodes.indexOf(node); } public int size() { - return this.graph.size(); + return this.dataFlowNodes.size(); + } + + private Stream stream() { + return this.dataFlowNodes.stream(); } // Printing public String printToImage() { - if (this.graph.isEmpty()) { + if (this.dataFlowNodes.isEmpty()) { return "Empty Graph"; } @@ -88,10 +100,10 @@ public final class DataFlowGraph implements Iterable { dot.append("digraph dfd {\n") .append("node[shape=Mrecord]\n"); - for (DataFlowNode node : this.graph) { + for (DataFlowNode node : this.dataFlowNodes) { dot.append(node.getId()) .append(" [label=\"{ ") - .append(this.graph.indexOf(node)) + .append(this.dataFlowNodes.indexOf(node)) .append("| ") .append(node.getInst()) .append("}\"];\n"); @@ -100,26 +112,13 @@ public final class DataFlowGraph implements Iterable { dot.append("START[label=\"START\"];\n") .append("END[label=\"END\"];\n"); - dot.append("START -> ").append(this.graph.get(0).getId()).append(";\n"); - dot.append(this.graph.get(this.graph.size() - 1).getId()).append(" -> END;\n"); + dot.append("START -> ").append(this.dataFlowNodes.get(0).getId()).append(";\n"); + dot.append(this.dataFlowNodes.get(this.dataFlowNodes.size() - 1).getId()).append(" -> END;\n"); - for (DataFlowNode node : this.graph) { - // Successors - for (DataFlowNode succ : node.getSuccessors()) { - if (!dot.toString().contains(node.getId() + " -> " + succ.getId())) { - // No duplicate arrows + for (DataFlowNode node : this.dataFlowNodes) { + for (DataFlowNode successor : node.getSuccessorSet()) { - dot.append(node.getId()).append(" -> ").append(succ.getId()).append(";\n"); - } - } - - // Predecessors - for (DataFlowNode pred : node.getPredecessors()) { - if (!dot.toString().contains(pred.getId() + " -> " + node.getId())) { - // No duplicates - - dot.append(pred.getId()).append(" -> ").append(node.getId()).append(";\n"); - } + dot.append(node.getId()).append(" -> ").append(successor.getId()).append(";\n"); } } @@ -148,6 +147,6 @@ public final class DataFlowGraph implements Iterable { @Override public Iterator iterator() { - return this.graph.iterator(); + return this.dataFlowNodes.iterator(); } } diff --git a/src/main/java/codegen/analysis/dataflow/DataFlowNode.java b/src/main/java/codegen/analysis/dataflow/DataFlowNode.java index e53d253..b660acc 100644 --- a/src/main/java/codegen/analysis/dataflow/DataFlowNode.java +++ b/src/main/java/codegen/analysis/dataflow/DataFlowNode.java @@ -1,26 +1,53 @@ package codegen.analysis.dataflow; -import codegen.flowgraph.FlowBasicBlock; import codegen.flowgraph.FlowInstruction; +import java.util.Collection; +import java.util.Collections; import java.util.HashSet; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; +/** + * Die Datenflussrepräsentation einer Instruktion. + */ public final class DataFlowNode { + // General graph structure information private final String id; - private final String blockId; - private final String inst; - private final String use; - private final String def; - private final Set in; - private final Set out; private final Set predecessors; private final Set successors; - private DataFlowNode(String id, String blockId, String inst, String use, String def) { + /** + * Die Instruction, welche auch die zugehörige {@link FlowInstruction} enthält. + */ + private final String inst; + + /** + * Die Variable, die von diesem Block verwendet wird. + * Da wir keinen 3-Address-Code, sondern Jasmin-Assembler haben, ist das maximal eine. + */ + private final String use; + + /** + * Die Variable, die von diesem Block definiert wird. + * Da wir keinen 3-Address-Code, sondern Jasmin-Assembler haben, ist das maximal eine. + */ + private final String def; + + /** + * Alle Variablen, welche live in diesem Node ankommen. + */ + private final Set in; + + /** + * Alle Variablen , welche diesen Node live verlassen. + */ + private final Set out; + + private DataFlowNode(String id, String inst, String use, String def) { this.id = id; - this.blockId = blockId; this.inst = inst; this.use = use; this.def = def; @@ -30,7 +57,7 @@ public final class DataFlowNode { this.successors = new HashSet<>(); } - public static DataFlowNode fromFlowNode(FlowInstruction srcInst, FlowBasicBlock block) { + public static DataFlowNode fromFlowNode(FlowInstruction srcInst) { final String instType = switch (srcInst.getInstruction()) { case "aload", "iload" -> "use"; case "astore", "istore" -> "def"; @@ -48,74 +75,95 @@ public final class DataFlowNode { def = srcInst.getArgs()[0]; } - return new DataFlowNode(srcInst.getId(), block.getId(), srcInst.getInstruction(), use, def); + return new DataFlowNode(srcInst.getId(), srcInst.getInstruction(), use, def); } + // Getters, Setters + public String getId() { return this.id; } - public String getBlockId() { - return this.blockId; - } - - public Set getUse() { - return Set.of(this.use); - } - - public Set getDef() { - return Set.of(this.def); - } - - public Set getIn() { - return this.in; - } - - public Set getOut() { - return this.out; - } - public String getInst() { return this.inst; } + public Set getPredecessorSet() { + return Collections.unmodifiableSet(this.predecessors); + } + public void addPredecessor(DataFlowNode node) { this.predecessors.add(node); } - public Set getPredecessors() { - return this.predecessors; - } - - public Set getSuccessors() { - return this.successors; + public Set getSuccessorSet() { + return Collections.unmodifiableSet(this.successors); } public void addSuccessor(DataFlowNode node) { this.successors.add(node); } - public void addOut(Set out) { - if (out.isEmpty()) { - return; - } - - if (out.stream().allMatch(String::isEmpty)) { - return; - } - - this.out.addAll(out); + public Set getUseSet() { + return Set.of(this.use); } - public boolean addIn(Set in) { + public Set getDefSet() { + return Set.of(this.def); + } + + public Set getInSet() { + return Collections.unmodifiableSet(this.in); + } + + public boolean addIn(Collection in) { if (in.isEmpty()) { return false; } - if (in.stream().allMatch(String::isEmpty)) { + if (in.stream().allMatch(String::isBlank)) { return false; } - return this.in.addAll(in); + return this.in.addAll(in.stream() + .filter(string -> !string.isBlank()) + .collect(Collectors.toSet())); + } + + public Set getOutSet() { + return Collections.unmodifiableSet(this.out); + } + + public void addOut(Collection out) { + if (out.isEmpty()) { + return; + } + + if (out.stream().allMatch(String::isBlank)) { + return; + } + + this.out.addAll(out.stream() + .filter(string -> !string.isBlank()) + .collect(Collectors.toSet())); + } + + // Overrides + + @Override + public int hashCode() { + return Objects.hash(this.id, this.inst); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || this.getClass() != o.getClass()) { + return false; + } + final DataFlowNode that = (DataFlowNode) o; + return this.id.equals(that.id) && this.inst.equals(that.inst); } } diff --git a/src/main/java/codegen/analysis/liveness/InterferenceGraph.java b/src/main/java/codegen/analysis/liveness/InterferenceGraph.java index f746048..7453298 100644 --- a/src/main/java/codegen/analysis/liveness/InterferenceGraph.java +++ b/src/main/java/codegen/analysis/liveness/InterferenceGraph.java @@ -15,7 +15,6 @@ import java.util.Map; public final class InterferenceGraph implements Iterable { - // TODO: Why use list, its a graph private final List nodes; private InterferenceGraph(List nodes) { @@ -32,14 +31,14 @@ public final class InterferenceGraph implements Iterable { // Determine neighbours for (DataFlowNode node : graph) { - Logger.log("NODE " + node.getInst() + " - OUT: " + node.getOut()); + Logger.log("NODE " + node.getInst() + " - OUT: " + node.getOutSet()); - for (String left : node.getOut()) { + for (String left : node.getOutSet()) { if (left.isBlank()) { continue; } - for (String right : node.getOut()) { + for (String right : node.getOutSet()) { if (right.isBlank()) { continue; } diff --git a/src/main/java/codegen/analysis/liveness/LivenessAnalysis.java b/src/main/java/codegen/analysis/liveness/LivenessAnalysis.java index 03d4167..98b4216 100644 --- a/src/main/java/codegen/analysis/liveness/LivenessAnalysis.java +++ b/src/main/java/codegen/analysis/liveness/LivenessAnalysis.java @@ -43,8 +43,8 @@ public final class LivenessAnalysis { // TODO: Indexof mega unnötig Logger.log("IN, OUT Sets:"); for (DataFlowNode node : graph) { - Logger.log(graph.indexOf(node) + ": " + node.getInst() + " IN: " + node.getIn()); - Logger.log(graph.indexOf(node) + ": " + node.getInst() + " OUT: " + node.getOut()); + Logger.log(graph.indexOf(node) + ": " + node.getInst() + " IN: " + node.getInSet()); + Logger.log(graph.indexOf(node) + ": " + node.getInst() + " OUT: " + node.getOutSet()); } Logger.log("\n"); } @@ -52,16 +52,16 @@ public final class LivenessAnalysis { private static boolean updateInOut(DataFlowNode node) { boolean change; - for (DataFlowNode succ : node.getSuccessors()) { + for (DataFlowNode succ : node.getSuccessorSet()) { // A variable going live into the successor implies it going live out of the predecessor - node.addOut(succ.getIn()); + node.addOut(succ.getInSet()); } - final Set addIN = new HashSet<>(node.getOut()); // Copy important - addIN.removeAll(node.getDef()); // If a variable that is live-out is defined in the node, it doesn't have to be live-in + final Set addIN = new HashSet<>(node.getOutSet()); // Copy important + addIN.removeAll(node.getDefSet()); // 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()); // A variable being used implies it going in live + change = node.addIn(node.getUseSet()); // 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; diff --git a/src/test/java/codegen/analysis/liveness/LivenessAnalysisTest.java b/src/test/java/codegen/analysis/liveness/LivenessAnalysisTest.java index 9e5ff73..3d1fcfb 100644 --- a/src/test/java/codegen/analysis/liveness/LivenessAnalysisTest.java +++ b/src/test/java/codegen/analysis/liveness/LivenessAnalysisTest.java @@ -54,7 +54,7 @@ class LivenessAnalysisTest { final Map nodeTable = TypeChecker.validate(tree); final FlowGraphGenerator gen = FlowGraphGenerator.fromAST(tree, nodeTable, "TestOutput"); final FlowGraph graph = gen.generateGraph(); - final DataFlowGraph dataGraph = DataFlowGraph.fromSourceGraph(graph); + final DataFlowGraph dataGraph = DataFlowGraph.fromFlowGraph(graph); return LivenessAnalysis.fromDataFlowGraph(dataGraph, gen.getVarMap()); }