Skip to content

Commit a95af9b

Browse files
WIP interference graph
WIP interference graph WIP interference graph
1 parent c3853df commit a95af9b

File tree

9 files changed

+370
-25
lines changed

9 files changed

+370
-25
lines changed

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/BasicBlock.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,18 @@ public class BasicBlock {
4949
* VarKill contains all the variables that are defined
5050
* in the block.
5151
*/
52-
BitSet varKill;
52+
LiveSet varKill;
5353
/**
5454
* UEVar contains upward-exposed variables in the block,
5555
* i.e. those variables that are used in the block prior to
5656
* any redefinition in the block.
5757
*/
58-
BitSet UEVar;
58+
LiveSet UEVar;
5959
/**
6060
* LiveOut is the union of variables that are live at the
6161
* head of some block that is a successor of this block.
6262
*/
63-
BitSet liveOut;
63+
LiveSet liveOut;
6464
// -----------------------
6565

6666
public BasicBlock(int bid, boolean loopHead) {

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,4 +560,9 @@ public StringBuilder toStr(StringBuilder sb, boolean verbose) {
560560
BasicBlock.toStr(sb, entry, new BitSet(), verbose);
561561
return sb;
562562
}
563+
564+
public void livenessAnalysis() {
565+
new Liveness(this);
566+
this.hasLiveness = true;
567+
}
563568
}

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/ExitSSA.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@ public class ExitSSA {
1717
public ExitSSA(CompiledFunction function) {
1818
this.function = function;
1919
if (!function.isSSA) throw new IllegalStateException();
20-
if (!function.hasLiveness) {
21-
new Liveness().computeLiveness(function);
22-
}
20+
function.livenessAnalysis();
2321
tree = new DominatorTree(function.entry);
2422
initStack();
2523
insertCopies(function.entry);
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.compilerprogramming.ezlang.compiler;
2+
3+
import java.util.*;
4+
5+
public class InterferenceGraph {
6+
Map<Integer, Set<Integer>> edges = new HashMap<>();
7+
8+
private Set<Integer> addNode(Integer node) {
9+
var set = edges.get(node);
10+
if (set == null) {
11+
set = new HashSet<>();
12+
edges.put(node, set);
13+
}
14+
return set;
15+
}
16+
17+
public void addEdge(Integer from, Integer to) {
18+
if (from == to) {
19+
return;
20+
}
21+
var set1 = addNode(from);
22+
var set2 = addNode(to);
23+
set1.add(to);
24+
set2.add(from);
25+
}
26+
27+
public boolean containsEdge(Integer from, Integer to) {
28+
var set = edges.get(from);
29+
return set != null && set.contains(to);
30+
}
31+
32+
public Set<Integer> adjacents(Integer node) {
33+
return edges.get(node);
34+
}
35+
36+
public static final class Edge {
37+
public final int from;
38+
public final int to;
39+
public Edge(int from, int to) {
40+
this.from = from;
41+
this.to = to;
42+
}
43+
44+
@Override
45+
public boolean equals(Object o) {
46+
if (this == o) return true;
47+
if (o == null || getClass() != o.getClass()) return false;
48+
Edge edge = (Edge) o;
49+
return (from == edge.from && to == edge.to)
50+
|| (from == edge.to && to == edge.from);
51+
}
52+
53+
@Override
54+
public int hashCode() {
55+
return from+to;
56+
}
57+
}
58+
59+
public Set<Edge> getEdges() {
60+
Set<Edge> all = new HashSet<>();
61+
for (Integer from: edges.keySet()) {
62+
var set = edges.get(from);
63+
for (Integer to: set) {
64+
all.add(new Edge(from, to));
65+
}
66+
}
67+
return all;
68+
}
69+
70+
public String generateDotOutput() {
71+
StringBuilder sb = new StringBuilder();
72+
sb.append("digraph IGraph {\n");
73+
for (var edge: getEdges()) {
74+
sb.append(edge.from).append("->").append(edge.to).append(";\n");
75+
}
76+
sb.append("}\n");
77+
return sb.toString();
78+
}
79+
80+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.compilerprogramming.ezlang.compiler;
2+
3+
public class InterferenceGraphBuilder {
4+
5+
public InterferenceGraph build(CompiledFunction function) {
6+
InterferenceGraph graph = new InterferenceGraph();
7+
// Calculate liveOut for all basic blocks
8+
function.livenessAnalysis();
9+
System.out.println(function.toStr(new StringBuilder(), true));
10+
var blocks = BBHelper.findAllBlocks(function.entry);
11+
for (var b : blocks) {
12+
// Start with the set of live vars at the end of the block
13+
// This liveness will be updated as we look through the
14+
// instructions in the block
15+
var liveNow = b.liveOut.dup();
16+
// liveNow is initially the set of values that are live (and avail?) at the
17+
// end of the block.
18+
// Process each instruction in the block in reverse order
19+
for (var i: b.instructions.reversed()) {
20+
if (i instanceof Instruction.Move ||
21+
i instanceof Instruction.Phi) {
22+
// Move(copy) instructions are handled specially to avoid
23+
// adding an undesirable interference between the source and
24+
// destination (section 2.2.2 in Briggs thesis)
25+
// Engineering a Compiler: The copy operation does not
26+
// create an interference cause both values can occupy the
27+
// same register
28+
// Same argument applies to phi.
29+
liveNow.remove(i.uses());
30+
}
31+
if (i.definesVar()) {
32+
var def = i.def();
33+
// Defined vars interfere with all members of the live set
34+
addInterference(graph, def, liveNow);
35+
// Defined vars are removed from the live set
36+
liveNow.dead(def);
37+
}
38+
// All used vars are added to the live set
39+
liveNow.live(i.uses());
40+
}
41+
}
42+
return graph;
43+
}
44+
45+
private static void addInterference(InterferenceGraph graph, Register def, LiveSet liveSet) {
46+
for (int regNum = liveSet.nextSetBit(0); regNum >= 0; regNum = liveSet.nextSetBit(regNum+1)) {
47+
if (regNum != def.id)
48+
graph.addEdge(regNum, def.id);
49+
}
50+
}
51+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.compilerprogramming.ezlang.compiler;
2+
3+
import java.util.BitSet;
4+
import java.util.List;
5+
6+
public class LiveSet extends BitSet {
7+
public LiveSet(int numRegs) {
8+
super(numRegs);
9+
}
10+
public LiveSet dup() {
11+
return (LiveSet) clone();
12+
}
13+
public void live(Register r) {
14+
set(r.id, true);
15+
}
16+
public void dead(Register r) {
17+
set(r.id, false);
18+
}
19+
public void live(List<Register> regs) {
20+
for (Register r : regs) {
21+
live(r);
22+
}
23+
}
24+
public void add(Register r) {
25+
set(r.id, true);
26+
}
27+
public void remove(Register r) {
28+
set(r.id, false);
29+
}
30+
public void remove(List<Register> regs) {
31+
for (Register r : regs) {
32+
remove(r);
33+
}
34+
}
35+
public boolean isMember(Register r) {
36+
return get(r.id);
37+
}
38+
public LiveSet intersect(LiveSet other) {
39+
and(other);
40+
return this;
41+
}
42+
public LiveSet union(LiveSet other) {
43+
or(other);
44+
return this;
45+
}
46+
public LiveSet intersectNot(LiveSet other) {
47+
andNot(other);
48+
return this;
49+
}
50+
}

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Liveness.java

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*/
1111
public class Liveness {
1212

13-
public void computeLiveness(CompiledFunction function) {
13+
public Liveness(CompiledFunction function) {
1414
List<BasicBlock> blocks = BBHelper.findAllBlocks(function.entry);
1515
RegisterPool regPool = function.registerPool;
1616
init(regPool, blocks);
@@ -21,19 +21,17 @@ public void computeLiveness(CompiledFunction function) {
2121
private void init(RegisterPool regPool, List<BasicBlock> blocks) {
2222
int numRegisters = regPool.numRegisters();
2323
for (BasicBlock block : blocks) {
24-
block.UEVar = new BitSet(numRegisters);
25-
block.varKill = new BitSet(numRegisters);
26-
block.liveOut = new BitSet(numRegisters);
24+
block.UEVar = new LiveSet(numRegisters);
25+
block.varKill = new LiveSet(numRegisters);
26+
block.liveOut = new LiveSet(numRegisters);
2727
for (Instruction instruction : block.instructions) {
28-
if (instruction.usesVars()) {
29-
for (Register use : instruction.uses()) {
30-
if (!block.varKill.get(use.id))
31-
block.UEVar.set(use.id);
32-
}
28+
for (Register use : instruction.uses()) {
29+
if (!block.varKill.isMember(use))
30+
block.UEVar.add(use);
3331
}
3432
if (instruction.definesVar()) {
3533
Register def = instruction.def();
36-
block.varKill.set(def.id);
34+
block.varKill.add(def);
3735
}
3836
}
3937
}
@@ -51,15 +49,15 @@ private void computeLiveness(List<BasicBlock> blocks) {
5149
}
5250

5351
private boolean recomputeLiveOut(BasicBlock block) {
54-
BitSet oldLiveOut = (BitSet) block.liveOut.clone();
52+
LiveSet oldLiveOut = block.liveOut.dup();
5553
for (BasicBlock m: block.successors) {
56-
BitSet mLiveIn = (BitSet) m.liveOut.clone();
54+
LiveSet mLiveIn = m.liveOut.dup();
5755
// LiveOut(m) intersect not VarKill(m)
58-
mLiveIn.andNot(m.varKill);
56+
mLiveIn.intersectNot(m.varKill);
5957
// UEVar(m) union (LiveOut(m) intersect not VarKill(m))
60-
mLiveIn.or(m.UEVar);
58+
mLiveIn.union(m.UEVar);
6159
// LiveOut(block) =union (UEVar(m) union (LiveOut(m) intersect not VarKill(m)))
62-
block.liveOut.or(mLiveIn);
60+
block.liveOut.union(mLiveIn);
6361
}
6462
return !oldLiveOut.equals(block.liveOut);
6563
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.compilerprogramming.ezlang.compiler;
2+
3+
import com.compilerprogramming.ezlang.types.Symbol;
4+
import com.compilerprogramming.ezlang.types.Type;
5+
import com.compilerprogramming.ezlang.types.TypeDictionary;
6+
import org.junit.Assert;
7+
import org.junit.Test;
8+
9+
public class TestInterferenceGraph {
10+
11+
private CompiledFunction buildTest1() {
12+
TypeDictionary typeDictionary = new TypeDictionary();
13+
Type.TypeFunction functionType = new Type.TypeFunction("foo");
14+
functionType.addArg(new Symbol.ParameterSymbol("a", typeDictionary.INT));
15+
functionType.setReturnType(typeDictionary.INT);
16+
CompiledFunction function = new CompiledFunction(functionType);
17+
RegisterPool regPool = function.registerPool;
18+
Register a = regPool.newReg("a", typeDictionary.INT);
19+
Register b = regPool.newReg("b", typeDictionary.INT);
20+
Register c = regPool.newReg("c", typeDictionary.INT);
21+
Register d = regPool.newReg("d", typeDictionary.INT);
22+
function.code(new Instruction.ArgInstruction(new Operand.LocalRegisterOperand(a)));
23+
function.code(new Instruction.Binary(
24+
"+",
25+
new Operand.RegisterOperand(a),
26+
new Operand.RegisterOperand(b),
27+
new Operand.ConstantOperand(1, typeDictionary.INT)));
28+
function.code(new Instruction.Binary(
29+
"*",
30+
new Operand.RegisterOperand(c),
31+
new Operand.RegisterOperand(b),
32+
new Operand.RegisterOperand(b)));
33+
function.code(new Instruction.Binary(
34+
"+",
35+
new Operand.RegisterOperand(b),
36+
new Operand.RegisterOperand(c),
37+
new Operand.ConstantOperand(1, typeDictionary.INT)));
38+
function.code(new Instruction.Binary(
39+
"*",
40+
new Operand.RegisterOperand(d),
41+
new Operand.RegisterOperand(b),
42+
new Operand.RegisterOperand(a)));
43+
function.code(new Instruction.Ret(new Operand.RegisterOperand(d)));
44+
function.startBlock(function.exit);
45+
function.isSSA = false;
46+
47+
System.out.println(function.toStr(new StringBuilder(), true));
48+
49+
return function;
50+
}
51+
52+
@Test
53+
public void test1() {
54+
CompiledFunction function = buildTest1();
55+
var graph = new InterferenceGraphBuilder().build(function);
56+
System.out.println(graph.generateDotOutput());
57+
var edges = graph.getEdges();
58+
Assert.assertEquals(2, edges.size());
59+
Assert.assertTrue(edges.contains(new InterferenceGraph.Edge(0,1)));
60+
Assert.assertTrue(edges.contains(new InterferenceGraph.Edge(0,2)));
61+
}
62+
63+
64+
65+
}

0 commit comments

Comments
 (0)