Skip to content

Commit da25d7d

Browse files
Merge pull request #13 from CompilerProgramming/chaitin
WIP Graph Coloring Register Allocator
2 parents fc51c22 + e77b0fa commit da25d7d

File tree

22 files changed

+675
-567
lines changed

22 files changed

+675
-567
lines changed

README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ The language is intentionally very simple and is meant to have just enough funct
2020

2121
The project is under development and subject to change. At this point in time, we have following initial implementations:
2222

23-
* lexer - a simple tokenizer
24-
* parser - a recursive descent parser and AST
25-
* types - the type definitions
26-
* semantic - semantic analyzer
27-
* stackvm - a bytecode compiler that generates stack IR (bytecode interpreter not yet available)
28-
* registervm - a bytecode compiler that generates a linear register IR and a bytecode interpreter that can execute the IR
29-
* optvm - WIP this will use an optimization pipeline, making usa of SSA transformation
23+
* [lexer](./lexer/README.md) - a simple tokenizer
24+
* [parser](./parser/README.md) - a recursive descent parser and AST
25+
* [types](/types/README.md) - the type definitions
26+
* [semantic](./semantic/README.md) - semantic analyzer
27+
* [stackvm](./stackvm/README.md) - a compiler that generates IR for a stack based virtual machine
28+
* [registervm](./registervm/README.md) - a compiler that generates a so called three-address IR and an interpreter that can execute the IR
29+
* [optvm](./optvm/README.md) - an optimizing compiler (WIP) that supports SSA.
30+
* seaofnodes - a compiler that will generate Sea of Nodes IR (planned)
3031

3132
## How can you contribute?
3233

lexer/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Lexer
2+
3+
For now please checkout the code. Docs to follow.

optvm/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Optimizing Compiler for Register VM
2+
3+
This module implements various compiler optimization techniques such as:
4+
5+
* Static Single Assignment
6+
* Liveness Analysis
7+
* WIP Graph Coloring Register Allocator (Chaitin)

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,19 @@ public class BasicBlock {
6161
* head of some block that is a successor of this block.
6262
*/
6363
LiveSet liveOut;
64+
65+
/**
66+
* Inputs to successor block's phi function
67+
*/
68+
LiveSet phiUses;
69+
/**
70+
* Phi definitions in this block
71+
*/
72+
LiveSet phiDefs;
73+
/**
74+
* Live in set
75+
*/
76+
LiveSet liveIn;
6477
// -----------------------
6578

6679
public BasicBlock(int bid, boolean loopHead) {
@@ -92,7 +105,7 @@ public void addSuccessor(BasicBlock successor) {
92105
public void insertPhiFor(Register var) {
93106
for (Instruction i: instructions) {
94107
if (i instanceof Instruction.Phi phi) {
95-
if (phi.def().nonSSAId() == var.nonSSAId())
108+
if (phi.value().nonSSAId() == var.nonSSAId())
96109
// already added
97110
return;
98111
}
@@ -124,8 +137,11 @@ public static StringBuilder toStr(StringBuilder sb, BasicBlock bb, BitSet visite
124137
n.toStr(sb).append("\n");
125138
}
126139
if (dumpLiveness) {
140+
if (bb.phiDefs != null) sb.append(" #PHIDEFS = ").append(bb.phiDefs.toString()).append("\n");
141+
if (bb.phiUses != null) sb.append(" #PHIUSES = ").append(bb.phiUses.toString()).append("\n");
127142
if (bb.UEVar != null) sb.append(" #UEVAR = ").append(bb.UEVar.toString()).append("\n");
128143
if (bb.varKill != null) sb.append(" #VARKILL = ").append(bb.varKill.toString()).append("\n");
144+
if (bb.liveIn != null) sb.append(" #LIVEIN = ").append(bb.liveIn.toString()).append("\n");
129145
if (bb.liveOut != null) sb.append(" #LIVEOUT = ").append(bb.liveOut.toString()).append("\n");
130146
}
131147
for (BasicBlock succ: bb.successors) {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.compilerprogramming.ezlang.compiler;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
public class ChaitinGraphColoringRegisterAllocator {
7+
8+
public ChaitinGraphColoringRegisterAllocator(CompiledFunction function) {
9+
coalesce(function);
10+
}
11+
12+
private void coalesce(CompiledFunction function) {
13+
boolean changed = true;
14+
while (changed) {
15+
var igraph = new InterferenceGraphBuilder().build(function);
16+
changed = coalesceRegisters(function, igraph);
17+
}
18+
}
19+
20+
private boolean coalesceRegisters(CompiledFunction function, InterferenceGraph igraph) {
21+
boolean changed = false;
22+
for (var block: function.getBlocks()) {
23+
List<Integer> instructionsToRemove = new ArrayList<>();
24+
for (int j = 0; j < block.instructions.size(); j++) {
25+
Instruction i = block.instructions.get(j);
26+
if (i instanceof Instruction.Move move
27+
&& move.from() instanceof Operand.RegisterOperand targetOperand) {
28+
Register source = move.def();
29+
Register target = targetOperand.reg;
30+
if (source.id != target.id &&
31+
!igraph.interfere(target.id, source.id)) {
32+
igraph.rename(source.id, target.id);
33+
rewriteInstructions(function, i, source, target);
34+
instructionsToRemove.add(j);
35+
changed = true;
36+
}
37+
}
38+
}
39+
for (var j: instructionsToRemove) {
40+
block.instructions.set(j, new Instruction.NoOp());
41+
}
42+
}
43+
return changed;
44+
}
45+
46+
private void rewriteInstructions(CompiledFunction function, Instruction notNeeded, Register source, Register target) {
47+
for (var block: function.getBlocks()) {
48+
for (Instruction i: block.instructions) {
49+
if (i == notNeeded)
50+
continue;
51+
if (i.definesVar() && source.id == i.def().id)
52+
i.replaceDef(target);
53+
i.replaceUse(source, target);
54+
}
55+
}
56+
}
57+
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,4 +565,8 @@ public void livenessAnalysis() {
565565
new Liveness(this);
566566
this.hasLiveness = true;
567567
}
568+
569+
public List<BasicBlock> getBlocks() {
570+
return BBHelper.findAllBlocks(entry);
571+
}
568572
}

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public ExitSSA(CompiledFunction function) {
1818
this.function = function;
1919
if (!function.isSSA) throw new IllegalStateException();
2020
function.livenessAnalysis();
21+
System.out.println(function.toStr(new StringBuilder(), true));
2122
tree = new DominatorTree(function.entry);
2223
initStack();
2324
insertCopies(function.entry);
@@ -35,9 +36,7 @@ private void insertCopies(BasicBlock block) {
3536
List<Integer> pushed = new ArrayList<>();
3637
for (Instruction i: block.instructions) {
3738
// replace all uses u with stacks[i]
38-
if (i.usesVars()) {
39-
replaceUses(i);
40-
}
39+
replaceUses(i);
4140
}
4241
scheduleCopies(block, pushed);
4342
for (BasicBlock c: block.dominatedChildren) {
@@ -85,8 +84,8 @@ private void scheduleCopies(BasicBlock block, List<Integer> pushed) {
8584
for (BasicBlock s: block.successors) {
8685
int j = SSATransform.whichPred(s, block);
8786
for (Instruction.Phi phi: s.phis()) {
88-
Register dst = phi.def();
89-
Register src = phi.inputs.get(j).reg; // jth operand of phi node
87+
Register dst = phi.value();
88+
Register src = phi.input(j); // jth operand of phi node
9089
copySet.add(new CopyItem(src, dst));
9190
map.put(src.id, src);
9291
map.put(dst.id, dst);
@@ -167,7 +166,7 @@ private void insertAfterPhi(BasicBlock bb, Register phiDef, Instruction newInst)
167166
for (int pos = 0; pos < bb.instructions.size(); pos++) {
168167
Instruction i = bb.instructions.get(pos);
169168
if (i instanceof Instruction.Phi phi) {
170-
if (phi.def().id == phiDef.id) {
169+
if (phi.value().id == phiDef.id) {
171170
insertionPos = pos+1; // After phi
172171
break;
173172
}

0 commit comments

Comments
 (0)