Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ The language is intentionally very simple and is meant to have just enough funct

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

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

## How can you contribute?

Expand Down
3 changes: 3 additions & 0 deletions lexer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Lexer

For now please checkout the code. Docs to follow.
7 changes: 7 additions & 0 deletions optvm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Optimizing Compiler for Register VM

This module implements various compiler optimization techniques such as:

* Static Single Assignment
* Liveness Analysis
* WIP Graph Coloring Register Allocator (Chaitin)
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@ public class BasicBlock {
* head of some block that is a successor of this block.
*/
LiveSet liveOut;

/**
* Inputs to successor block's phi function
*/
LiveSet phiUses;
/**
* Phi definitions in this block
*/
LiveSet phiDefs;
/**
* Live in set
*/
LiveSet liveIn;
// -----------------------

public BasicBlock(int bid, boolean loopHead) {
Expand Down Expand Up @@ -92,7 +105,7 @@ public void addSuccessor(BasicBlock successor) {
public void insertPhiFor(Register var) {
for (Instruction i: instructions) {
if (i instanceof Instruction.Phi phi) {
if (phi.def().nonSSAId() == var.nonSSAId())
if (phi.value().nonSSAId() == var.nonSSAId())
// already added
return;
}
Expand Down Expand Up @@ -124,8 +137,11 @@ public static StringBuilder toStr(StringBuilder sb, BasicBlock bb, BitSet visite
n.toStr(sb).append("\n");
}
if (dumpLiveness) {
if (bb.phiDefs != null) sb.append(" #PHIDEFS = ").append(bb.phiDefs.toString()).append("\n");
if (bb.phiUses != null) sb.append(" #PHIUSES = ").append(bb.phiUses.toString()).append("\n");
if (bb.UEVar != null) sb.append(" #UEVAR = ").append(bb.UEVar.toString()).append("\n");
if (bb.varKill != null) sb.append(" #VARKILL = ").append(bb.varKill.toString()).append("\n");
if (bb.liveIn != null) sb.append(" #LIVEIN = ").append(bb.liveIn.toString()).append("\n");
if (bb.liveOut != null) sb.append(" #LIVEOUT = ").append(bb.liveOut.toString()).append("\n");
}
for (BasicBlock succ: bb.successors) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.compilerprogramming.ezlang.compiler;

import java.util.ArrayList;
import java.util.List;

public class ChaitinGraphColoringRegisterAllocator {

public ChaitinGraphColoringRegisterAllocator(CompiledFunction function) {
coalesce(function);
}

private void coalesce(CompiledFunction function) {
boolean changed = true;
while (changed) {
var igraph = new InterferenceGraphBuilder().build(function);
changed = coalesceRegisters(function, igraph);
}
}

private boolean coalesceRegisters(CompiledFunction function, InterferenceGraph igraph) {
boolean changed = false;
for (var block: function.getBlocks()) {
List<Integer> instructionsToRemove = new ArrayList<>();
for (int j = 0; j < block.instructions.size(); j++) {
Instruction i = block.instructions.get(j);
if (i instanceof Instruction.Move move
&& move.from() instanceof Operand.RegisterOperand targetOperand) {
Register source = move.def();
Register target = targetOperand.reg;
if (source.id != target.id &&
!igraph.interfere(target.id, source.id)) {
igraph.rename(source.id, target.id);
rewriteInstructions(function, i, source, target);
instructionsToRemove.add(j);
changed = true;
}
}
}
for (var j: instructionsToRemove) {
block.instructions.set(j, new Instruction.NoOp());
}
}
return changed;
}

private void rewriteInstructions(CompiledFunction function, Instruction notNeeded, Register source, Register target) {
for (var block: function.getBlocks()) {
for (Instruction i: block.instructions) {
if (i == notNeeded)
continue;
if (i.definesVar() && source.id == i.def().id)
i.replaceDef(target);
i.replaceUse(source, target);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -565,4 +565,8 @@ public void livenessAnalysis() {
new Liveness(this);
this.hasLiveness = true;
}

public List<BasicBlock> getBlocks() {
return BBHelper.findAllBlocks(entry);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public ExitSSA(CompiledFunction function) {
this.function = function;
if (!function.isSSA) throw new IllegalStateException();
function.livenessAnalysis();
System.out.println(function.toStr(new StringBuilder(), true));
tree = new DominatorTree(function.entry);
initStack();
insertCopies(function.entry);
Expand All @@ -35,9 +36,7 @@ private void insertCopies(BasicBlock block) {
List<Integer> pushed = new ArrayList<>();
for (Instruction i: block.instructions) {
// replace all uses u with stacks[i]
if (i.usesVars()) {
replaceUses(i);
}
replaceUses(i);
}
scheduleCopies(block, pushed);
for (BasicBlock c: block.dominatedChildren) {
Expand Down Expand Up @@ -85,8 +84,8 @@ private void scheduleCopies(BasicBlock block, List<Integer> pushed) {
for (BasicBlock s: block.successors) {
int j = SSATransform.whichPred(s, block);
for (Instruction.Phi phi: s.phis()) {
Register dst = phi.def();
Register src = phi.inputs.get(j).reg; // jth operand of phi node
Register dst = phi.value();
Register src = phi.input(j); // jth operand of phi node
copySet.add(new CopyItem(src, dst));
map.put(src.id, src);
map.put(dst.id, dst);
Expand Down Expand Up @@ -167,7 +166,7 @@ private void insertAfterPhi(BasicBlock bb, Register phiDef, Instruction newInst)
for (int pos = 0; pos < bb.instructions.size(); pos++) {
Instruction i = bb.instructions.get(pos);
if (i instanceof Instruction.Phi phi) {
if (phi.def().id == phiDef.id) {
if (phi.value().id == phiDef.id) {
insertionPos = pos+1; // After phi
break;
}
Expand Down
Loading
Loading