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
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.compilerprogramming.ezlang.compiler;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.function.Consumer;

public class BBHelper {
/**
* Utility to locate all the basic blocks, order does not matter.
*/
public static List<BasicBlock> findAllBlocks(BasicBlock root) {
List<BasicBlock> nodes = new ArrayList<>();
postOrderWalk(root, (n) -> nodes.add(n), new HashSet<>());
return nodes;
}

static void postOrderWalk(BasicBlock n, Consumer<BasicBlock> consumer, HashSet<BasicBlock> visited) {
visited.add(n);
/* For each successor node */
for (BasicBlock s : n.successors) {
if (!visited.contains(s))
postOrderWalk(s, consumer, visited);
}
consumer.accept(n);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,25 @@ public class BasicBlock {
*/
public LoopNest loop;

// Liveness computation
/**
* VarKill contains all the variables that are defined
* in the block.
*/
BitSet varKill;
/**
* UEVar contains upward-exposed variables in the block,
* i.e. those variables that are used in the block prior to
* any redefinition in the block.
*/
BitSet UEVar;
/**
* LiveOut is the union of variables that are live at the
* head of some block that is a successor of this block.
*/
BitSet liveOut;
// -----------------------

public BasicBlock(int bid, boolean loopHead) {
this.bid = bid;
this.loopHead = loopHead;
Expand Down Expand Up @@ -94,7 +113,7 @@ public List<Instruction.Phi> phis() {
}
return list;
}
public static StringBuilder toStr(StringBuilder sb, BasicBlock bb, BitSet visited)
public static StringBuilder toStr(StringBuilder sb, BasicBlock bb, BitSet visited, boolean dumpLiveness)
{
if (visited.get(bb.bid))
return sb;
Expand All @@ -104,8 +123,13 @@ public static StringBuilder toStr(StringBuilder sb, BasicBlock bb, BitSet visite
sb.append(" ");
n.toStr(sb).append("\n");
}
if (dumpLiveness) {
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.liveOut != null) sb.append(" #LIVEOUT = ").append(bb.liveOut.toString()).append("\n");
}
for (BasicBlock succ: bb.successors) {
toStr(sb, succ, visited);
toStr(sb, succ, visited, dumpLiveness);
}
return sb;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.compilerprogramming.ezlang.types.Type;

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

public class CompiledFunction {
Expand Down Expand Up @@ -536,4 +537,12 @@ else if (indexed instanceof Operand.LoadFieldOperand loadFieldOperand) {
private boolean vstackEmpty() {
return virtualStack.isEmpty();
}

public void toStr(StringBuilder sb, boolean verbose) {
if (verbose) {
sb.append(this.functionType.describe()).append("\n");
registerPool.toStr(sb);
}
BasicBlock.toStr(sb, entry, new BitSet(), verbose);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,17 @@ public TypeDictionary compileSrc(String src) {
compile(typeDict);
return typeDict;
}
public String dumpIR(TypeDictionary typeDictionary) {
public static String dumpIR(TypeDictionary typeDictionary) {
return dumpIR(typeDictionary, false);
}
public static String dumpIR(TypeDictionary typeDictionary, boolean verbose) {
StringBuilder sb = new StringBuilder();
for (Symbol s: typeDictionary.bindings.values()) {
if (s instanceof Symbol.FunctionTypeSymbol f) {
var functionBuilder = (CompiledFunction) f.code();
BasicBlock.toStr(sb, functionBuilder.entry, new BitSet());
var function = (CompiledFunction) f.code();
function.toStr(sb, verbose);
}
}
return sb.toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,32 +29,13 @@ public class DominatorTree {
*/
public DominatorTree(BasicBlock entry) {
this.entry = entry;
blocks = findAllBlocks(entry);
blocks = BBHelper.findAllBlocks(entry);
calculateDominatorTree();
populateTree();
setDepth();
calculateDominanceFrontiers();
}

/**
* Utility to locate all the basic blocks, order does not matter.
*/
private static List<BasicBlock> findAllBlocks(BasicBlock root) {
List<BasicBlock> nodes = new ArrayList<>();
postOrderWalk(root, (n) -> nodes.add(n), new HashSet<>());
return nodes;
}

static void postOrderWalk(BasicBlock n, Consumer<BasicBlock> consumer, HashSet<BasicBlock> visited) {
visited.add(n);
/* For each successor node */
for (BasicBlock s : n.successors) {
if (!visited.contains(s))
postOrderWalk(s, consumer, visited);
}
consumer.accept(n);
}

private void calculateDominatorTree() {
resetDomInfo();
annotateBlocksWithRPO();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.compilerprogramming.ezlang.compiler;

import java.util.BitSet;
import java.util.List;

/**
* Compute LiveOut for each Basic Block
* Implementation is based on description in 'Engineering a Compiler' 2nd ed.
* pages 446-447.
*/
public class Liveness {

public void computeLiveness(CompiledFunction function) {
List<BasicBlock> blocks = BBHelper.findAllBlocks(function.entry);
RegisterPool regPool = function.registerPool;
init(regPool, blocks);
computeLiveness(blocks);
}

private void init(RegisterPool regPool, List<BasicBlock> blocks) {
int numRegisters = regPool.numRegisters();
for (BasicBlock block : blocks) {
block.UEVar = new BitSet(numRegisters);
block.varKill = new BitSet(numRegisters);
block.liveOut = new BitSet(numRegisters);
for (Instruction instruction : block.instructions) {
if (instruction.usesVars()) {
for (Register use : instruction.uses()) {
if (!block.varKill.get(use.id))
block.UEVar.set(use.id);
}
}
if (instruction.definesVar()) {
Register def = instruction.def();
block.varKill.set(def.id);
}
}
}
}

private void computeLiveness(List<BasicBlock> blocks) {
boolean changed = true;
while (changed) {
changed = false;
for (BasicBlock block : blocks) {
if (recomputeLiveOut(block))
changed = true;
}
}
}

private boolean recomputeLiveOut(BasicBlock block) {
BitSet oldLiveOut = (BitSet) block.liveOut.clone();
for (BasicBlock m: block.successors) {
BitSet mLiveIn = (BitSet) m.liveOut.clone();
// LiveOut(m) intersect not VarKill(m)
mLiveIn.andNot(m.varKill);
// UEVar(m) union (LiveOut(m) intersect not VarKill(m))
mLiveIn.or(m.UEVar);
// LiveOut(block) =union (UEVar(m) union (LiveOut(m) intersect not VarKill(m)))
block.liveOut.or(mLiveIn);
}
return !oldLiveOut.equals(block.liveOut);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class Register {
/**
* Unique virtual ID
*/
private final int id;
public final int id;
/**
* The base name - for local variables and function params this should be the name
* in the source program. For temps this is a made up name.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import java.util.ArrayList;

/**
* The RegisterPool is ued when compiling functions
* The RegisterPool is used when compiling functions
* to assign IDs to registers. Initially the registers get
* sequential IDs. For SSA registers we assign new IDs but also
* retain the old ID and attach a version number - the old ID is
Expand Down Expand Up @@ -48,4 +48,10 @@ public Register.SSARegister ssaReg(Register original, int version) {
public int numRegisters() {
return registers.size();
}

public void toStr(StringBuilder sb) {
for (Register reg : registers) {
sb.append("Reg #").append(reg.id).append(" ").append(reg.name()).append("\n");
}
}
}
Loading
Loading