Files
lecture-compilers/src/main/java/codegen/analysis/dataflow/DataFlowGraph.java
2021-01-31 15:55:54 +01:00

153 lines
5.0 KiB
Java

package codegen.analysis.dataflow;
import codegen.flowgraph.FlowBasicBlock;
import codegen.flowgraph.FlowGraph;
import codegen.flowgraph.FlowInstruction;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
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<DataFlowNode> {
// List for easy indexing
private final List<DataFlowNode> dataFlowNodes;
private DataFlowGraph(List<DataFlowNode> dataFlowNodes) {
this.dataFlowNodes = Collections.unmodifiableList(dataFlowNodes);
}
public static DataFlowGraph fromFlowGraph(FlowGraph flowGraph) {
final List<DataFlowNode> dataFlowNodes = new LinkedList<>();
// Initialize all DataFlowNodes
for (FlowBasicBlock basicBlock : flowGraph) {
for (FlowInstruction instruction : basicBlock) {
dataFlowNodes.add(DataFlowNode.fromFlowNode(instruction));
}
}
final DataFlowGraph dataFlowGraph = new DataFlowGraph(dataFlowNodes);
initNodePosition(flowGraph, dataFlowGraph);
return dataFlowGraph;
}
/**
* 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) {
final Optional<DataFlowNode> currentNode = getNodeByInstructionId(instruction, dataFlowGraph);
if (currentNode.isEmpty()) {
continue;
}
for (FlowInstruction predecessor : basicBlock.getInstructionPredecessorSet(instruction)) {
final Optional<DataFlowNode> currentPredecessor = getNodeByInstructionId(predecessor, dataFlowGraph);
currentPredecessor.ifPresent(dataFlowNode -> currentNode.get().addPredecessor(dataFlowNode));
}
for (FlowInstruction successor : basicBlock.getInstructionSuccessorSet(instruction)) {
final Optional<DataFlowNode> currentSuccessor = getNodeByInstructionId(successor, dataFlowGraph);
currentSuccessor.ifPresent(dataFlowNode -> currentNode.get().addSuccessor(dataFlowNode));
}
}
}
}
private static Optional<DataFlowNode> getNodeByInstructionId(FlowInstruction instruction, DataFlowGraph dataFlowGraph) {
return dataFlowGraph.stream()
.filter(node -> node.getId().equals(instruction.getId()))
.findFirst();
}
public int indexOf(DataFlowNode node) {
return this.dataFlowNodes.indexOf(node);
}
public int size() {
return this.dataFlowNodes.size();
}
private Stream<DataFlowNode> stream() {
return this.dataFlowNodes.stream();
}
// Printing
public String printToImage() {
if (this.dataFlowNodes.isEmpty()) {
return "Empty Graph";
}
final StringBuilder dot = new StringBuilder();
dot.append("digraph dfd {\n")
.append("node[shape=Mrecord]\n");
for (DataFlowNode node : this.dataFlowNodes) {
dot.append(node.getId())
.append(" [label=\"{<f0> ")
.append(this.dataFlowNodes.indexOf(node))
.append("|<f1> ")
.append(node.getInst())
.append("}\"];\n");
}
dot.append("START[label=\"START\"];\n")
.append("END[label=\"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.dataFlowNodes) {
for (DataFlowNode successor : node.getSuccessorSet()) {
dot.append(node.getId()).append(" -> ").append(successor.getId()).append(";\n");
}
}
dot.append("}");
final String dotOut = dot.toString();
final Path dotFile = Paths.get(System.getProperty("user.dir") + "/DataFlowGraph.dot");
try {
Files.writeString(dotFile, dotOut);
} catch (IOException e) {
e.printStackTrace();
}
final ProcessBuilder dotCompile = new ProcessBuilder("dot", "-Tsvg", "-oDataFlowGraph.svg", "DataFlowGraph.dot");
try {
dotCompile.start();
} catch (IOException e) {
e.printStackTrace();
}
return "Finished.";
}
// Overrides
@Override
public Iterator<DataFlowNode> iterator() {
return this.dataFlowNodes.iterator();
}
}