rework DataFlowGraph
This commit is contained in:
@ -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<DataFlowNode> {
|
||||
|
||||
// TODO: Why use list, its a graph
|
||||
private final List<DataFlowNode> graph;
|
||||
// List for easy indexing
|
||||
private final List<DataFlowNode> dataFlowNodes;
|
||||
|
||||
private DataFlowGraph(List<DataFlowNode> graph) {
|
||||
this.graph = Collections.unmodifiableList(graph);
|
||||
Logger.call(this::printToImage);
|
||||
private DataFlowGraph(List<DataFlowNode> dataFlowNodes) {
|
||||
this.dataFlowNodes = Collections.unmodifiableList(dataFlowNodes);
|
||||
}
|
||||
|
||||
public static DataFlowGraph fromSourceGraph(FlowGraph srcGraph) {
|
||||
final List<DataFlowNode> graph = new LinkedList<>();
|
||||
public static DataFlowGraph fromFlowGraph(FlowGraph flowGraph) {
|
||||
final List<DataFlowNode> 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<DataFlowNode> 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<DataFlowNode> 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<DataFlowNode> 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<DataFlowNode> currentSuccessor = getNodeByInstructionId(successor, dataFlowGraph);
|
||||
currentSuccessor.ifPresent(dataFlowNode -> currentNode.get().addSuccessor(dataFlowNode));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static DataFlowNode getNodeByInstruction(FlowInstruction inst, List<DataFlowNode> graph) {
|
||||
return graph.stream()
|
||||
.filter(node -> node.getId().equals(inst.getId()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
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.graph.indexOf(node);
|
||||
return this.dataFlowNodes.indexOf(node);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.graph.size();
|
||||
return this.dataFlowNodes.size();
|
||||
}
|
||||
|
||||
private Stream<DataFlowNode> 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<DataFlowNode> {
|
||||
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=\"{<f0> ")
|
||||
.append(this.graph.indexOf(node))
|
||||
.append(this.dataFlowNodes.indexOf(node))
|
||||
.append("|<f1> ")
|
||||
.append(node.getInst())
|
||||
.append("}\"];\n");
|
||||
@ -100,26 +112,13 @@ public final class DataFlowGraph implements Iterable<DataFlowNode> {
|
||||
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<DataFlowNode> {
|
||||
|
||||
@Override
|
||||
public Iterator<DataFlowNode> iterator() {
|
||||
return this.graph.iterator();
|
||||
return this.dataFlowNodes.iterator();
|
||||
}
|
||||
}
|
||||
|
@ -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<String> in;
|
||||
private final Set<String> out;
|
||||
private final Set<DataFlowNode> predecessors;
|
||||
private final Set<DataFlowNode> 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<String> in;
|
||||
|
||||
/**
|
||||
* Alle Variablen , welche diesen Node live verlassen.
|
||||
*/
|
||||
private final Set<String> 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<String> getUse() {
|
||||
return Set.of(this.use);
|
||||
}
|
||||
|
||||
public Set<String> getDef() {
|
||||
return Set.of(this.def);
|
||||
}
|
||||
|
||||
public Set<String> getIn() {
|
||||
return this.in;
|
||||
}
|
||||
|
||||
public Set<String> getOut() {
|
||||
return this.out;
|
||||
}
|
||||
|
||||
public String getInst() {
|
||||
return this.inst;
|
||||
}
|
||||
|
||||
public Set<DataFlowNode> getPredecessorSet() {
|
||||
return Collections.unmodifiableSet(this.predecessors);
|
||||
}
|
||||
|
||||
public void addPredecessor(DataFlowNode node) {
|
||||
this.predecessors.add(node);
|
||||
}
|
||||
|
||||
public Set<DataFlowNode> getPredecessors() {
|
||||
return this.predecessors;
|
||||
}
|
||||
|
||||
public Set<DataFlowNode> getSuccessors() {
|
||||
return this.successors;
|
||||
public Set<DataFlowNode> getSuccessorSet() {
|
||||
return Collections.unmodifiableSet(this.successors);
|
||||
}
|
||||
|
||||
public void addSuccessor(DataFlowNode node) {
|
||||
this.successors.add(node);
|
||||
}
|
||||
|
||||
public void addOut(Set<String> out) {
|
||||
if (out.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (out.stream().allMatch(String::isEmpty)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.out.addAll(out);
|
||||
public Set<String> getUseSet() {
|
||||
return Set.of(this.use);
|
||||
}
|
||||
|
||||
public boolean addIn(Set<String> in) {
|
||||
public Set<String> getDefSet() {
|
||||
return Set.of(this.def);
|
||||
}
|
||||
|
||||
public Set<String> getInSet() {
|
||||
return Collections.unmodifiableSet(this.in);
|
||||
}
|
||||
|
||||
public boolean addIn(Collection<String> 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<String> getOutSet() {
|
||||
return Collections.unmodifiableSet(this.out);
|
||||
}
|
||||
|
||||
public void addOut(Collection<String> 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);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import java.util.Map;
|
||||
|
||||
public final class InterferenceGraph implements Iterable<InterferenceNode> {
|
||||
|
||||
// TODO: Why use list, its a graph
|
||||
private final List<InterferenceNode> nodes;
|
||||
|
||||
private InterferenceGraph(List<InterferenceNode> nodes) {
|
||||
@ -32,14 +31,14 @@ public final class InterferenceGraph implements Iterable<InterferenceNode> {
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
@ -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<String> 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<String> 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;
|
||||
|
@ -54,7 +54,7 @@ class LivenessAnalysisTest {
|
||||
final Map<ASTNode, String> 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());
|
||||
}
|
||||
|
Reference in New Issue
Block a user