refactor liveness analysis
This commit is contained in:
@ -72,10 +72,11 @@ public final class StupsCompiler {
|
|||||||
System.out.println("Liveness-Analyse für " + filename);
|
System.out.println("Liveness-Analyse für " + filename);
|
||||||
|
|
||||||
final FlowGraphGenerator gen = getFlowGraphGen(filename);
|
final FlowGraphGenerator gen = getFlowGraphGen(filename);
|
||||||
|
|
||||||
final FlowGraph graph = gen.generateGraph();
|
final FlowGraph graph = gen.generateGraph();
|
||||||
final DataFlowGraph dataFlowGraph = DataFlowGraph.fromSourceGraph(graph);
|
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) {
|
private static FlowGraphGenerator getFlowGraphGen(String filename) {
|
||||||
|
@ -1,4 +1,116 @@
|
|||||||
package codegen.analysis.liveness;
|
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<InterferenceNode> nodes;
|
||||||
|
|
||||||
|
private InterferenceGraph(List<InterferenceNode> nodes) {
|
||||||
|
this.nodes = nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InterferenceGraph fromDataFlowGraph(DataFlowGraph graph, Map<String, Integer> varMap) {
|
||||||
|
final List<InterferenceNode> interferenceGraph = new ArrayList<>();
|
||||||
|
|
||||||
|
// Init graph
|
||||||
|
for (Map.Entry<String, Integer> 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<InterferenceNode> interferenceGraph) {
|
||||||
|
return interferenceGraph.stream()
|
||||||
|
.filter(node -> node.getSymbol().equals(symbol))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters, Setters
|
||||||
|
|
||||||
|
public List<InterferenceNode> 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=\"{<f0> Symbol: ")
|
||||||
|
.append(node.getSymbol())
|
||||||
|
.append("|<f1> 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.";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,20 @@ public class InterferenceNode {
|
|||||||
this.neighbours = new HashSet<>();
|
this.neighbours = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Getters, Setters
|
||||||
|
|
||||||
public String getSymbol() {
|
public String getSymbol() {
|
||||||
return this.symbol;
|
return this.symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getColor() {
|
||||||
|
return this.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(int color) {
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
public void addNeighbour(InterferenceNode node) {
|
public void addNeighbour(InterferenceNode node) {
|
||||||
if (!node.equals(this)) {
|
if (!node.equals(this)) {
|
||||||
this.neighbours.add(node);
|
this.neighbours.add(node);
|
||||||
@ -30,6 +40,8 @@ public class InterferenceNode {
|
|||||||
return this.neighbours;
|
return this.neighbours;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Overrides
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(this.symbol);
|
return Objects.hash(this.symbol);
|
||||||
@ -51,12 +63,4 @@ public class InterferenceNode {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return this.symbol;
|
return this.symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getColor() {
|
|
||||||
return this.color;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setColor(int color) {
|
|
||||||
this.color = color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,25 +4,27 @@ import codegen.analysis.dataflow.DataFlowGraph;
|
|||||||
import codegen.analysis.dataflow.DataFlowNode;
|
import codegen.analysis.dataflow.DataFlowNode;
|
||||||
import util.Logger;
|
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.HashSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
// TODO: This is just terrible
|
|
||||||
public final class LivenessAnalysis {
|
public final class LivenessAnalysis {
|
||||||
|
|
||||||
private LivenessAnalysis() {}
|
private final InterferenceGraph interferenceGraph;
|
||||||
|
|
||||||
public static void doLivenessAnalysis(DataFlowGraph graph, Map<String, Integer> varMap) {
|
private LivenessAnalysis(InterferenceGraph interferenceGraph) {
|
||||||
|
this.interferenceGraph = interferenceGraph;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate IN, OUT
|
public static LivenessAnalysis fromDataFlowGraph(DataFlowGraph graph, Map<String, Integer> varMap) {
|
||||||
|
calculateLivenessInOut(graph); // TODO: Copy the graph
|
||||||
|
|
||||||
|
return new LivenessAnalysis(InterferenceGraph.fromDataFlowGraph(graph, varMap));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void calculateLivenessInOut(DataFlowGraph graph) {
|
||||||
boolean change;
|
boolean change;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
change = false;
|
change = false;
|
||||||
|
|
||||||
@ -43,70 +45,49 @@ public final class LivenessAnalysis {
|
|||||||
Logger.log(graph.getNodes().indexOf(node) + ": " + node.getInst() + " OUT: " + node.getOut());
|
Logger.log(graph.getNodes().indexOf(node) + ": " + node.getInst() + " OUT: " + node.getOut());
|
||||||
}
|
}
|
||||||
Logger.log("\n");
|
Logger.log("\n");
|
||||||
|
|
||||||
doInterference(graph.getNodes(), varMap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean updateInOut(DataFlowNode node) {
|
private static boolean updateInOut(DataFlowNode node) {
|
||||||
boolean change;
|
boolean change;
|
||||||
|
|
||||||
for (DataFlowNode succ : node.getSuccessors()) {
|
for (DataFlowNode succ : node.getSuccessors()) {
|
||||||
|
// A variable going live into the successor implies it going live out of the predecessor
|
||||||
|
|
||||||
node.addOut(succ.getIn());
|
node.addOut(succ.getIn());
|
||||||
}
|
}
|
||||||
|
|
||||||
final Set<String> addIN = new HashSet<>(node.getOut()); // Copy important
|
final Set<String> 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 = node.addIn(node.getUse()); // A variable being used implies it going in live
|
||||||
change = change || node.addIn(addIN);
|
change = change || node.addIn(addIN); // A variable that is live-out and isn't defined in the node must be live-in
|
||||||
|
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void doInterference(List<DataFlowNode> nodes, Map<String, Integer> varMap) {
|
public void doLivenessAnalysis() {
|
||||||
final List<InterferenceNode> interferenceGraph = new ArrayList<>();
|
final int registers = this.colorInterferenceGraph();
|
||||||
|
|
||||||
// Init graph
|
System.out.println("\nRegisters: " + registers);
|
||||||
for (Map.Entry<String, Integer> var : varMap.entrySet()) {
|
}
|
||||||
interferenceGraph.add(new InterferenceNode(var.getValue().toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
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 colors = 0;
|
||||||
int currentColor;
|
int currentColor;
|
||||||
Logger.log("\n");
|
|
||||||
for (InterferenceNode node : interferenceGraph) {
|
for (InterferenceNode node : this.interferenceGraph.getNodes()) {
|
||||||
|
|
||||||
currentColor = 1;
|
currentColor = 1;
|
||||||
|
|
||||||
|
// Get all colors that can't be used
|
||||||
final Set<Integer> neighbourColors = new HashSet<>();
|
final Set<Integer> neighbourColors = new HashSet<>();
|
||||||
Logger.log("Interference node " + node + ", Color = " + node.getColor() + ": Neighbours - "
|
|
||||||
+ node.getNeighbours() + ", NColors - " + neighbourColors);
|
|
||||||
for (InterferenceNode neighbour : node.getNeighbours()) {
|
for (InterferenceNode neighbour : node.getNeighbours()) {
|
||||||
neighbourColors.add(neighbour.getColor());
|
neighbourColors.add(neighbour.getColor());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find a color that can be used
|
||||||
while (neighbourColors.contains(currentColor)) {
|
while (neighbourColors.contains(currentColor)) {
|
||||||
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<InterferenceNode> 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=\"{<f0> Symbol: ")
|
|
||||||
.append(node.getSymbol())
|
|
||||||
.append("|<f1> 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<InterferenceNode> interferenceGraph) {
|
|
||||||
return interferenceGraph.stream()
|
|
||||||
.filter(node -> node.getSymbol().equals(symbol))
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user