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
Expand Up @@ -17,10 +17,10 @@
*/
public class ChaitinGraphColoringRegisterAllocator {

public Map<Integer, Integer> assignRegisters(CompiledFunction function, int numRegisters) {
public Map<Integer, Integer> assignRegisters(CompiledFunction function, int numRegisters, EnumSet<Options> options) {
if (function.isSSA) throw new IllegalStateException("Register allocation should be done after exiting SSA");
// Remove useless copy operations
InterferenceGraph g = coalesce(function);
InterferenceGraph g = coalesce(function, options);
// Get used registers
Set<Integer> registers = registersInIR(function);
// Create color set
Expand All @@ -36,6 +36,8 @@ public Map<Integer, Integer> assignRegisters(CompiledFunction function, int numR
updateInstructions(function, assignments);
// Compute and set the new framesize
function.setFrameSize(computeFrameSize(assignments));
if (options.contains(Options.DUMP_POST_CHAITIN_IR))
function.dumpIR(false, "Post Chaitin Register Allocation");
return assignments;
}

Expand Down Expand Up @@ -83,13 +85,17 @@ private void updateInstructions(CompiledFunction function, Map<Integer, Integer>
/**
* Chaitin: coalesce_nodes - coalesce away copy operations
*/
public InterferenceGraph coalesce(CompiledFunction function) {
public InterferenceGraph coalesce(CompiledFunction function, EnumSet<Options> options) {
boolean changed = true;
InterferenceGraph igraph = null;
while (changed) {
igraph = new InterferenceGraphBuilder().build(function);
changed = coalesceCopyOperations(function, igraph);
}
if (options.contains(Options.DUMP_CHAITIN_COALESCE)) {
System.out.println("Post Chaitin Coalesce Registers");
System.out.println(function.toStr(new StringBuilder(), false));
}
return igraph;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,11 @@ public StringBuilder toStr(StringBuilder sb, boolean verbose) {
return sb;
}

public void dumpIR(boolean verbose, String title) {
System.out.println(title);
System.out.println(toStr(new StringBuilder(), verbose));
}

public void livenessAnalysis() {
new Liveness(this);
this.hasLiveness = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,34 @@
import com.compilerprogramming.ezlang.types.Type;
import com.compilerprogramming.ezlang.types.TypeDictionary;

import java.util.EnumSet;

public class Compiler {

private void compile(TypeDictionary typeDictionary, boolean opt) {
private void compile(TypeDictionary typeDictionary, EnumSet<Options> options) {
for (Symbol symbol: typeDictionary.getLocalSymbols()) {
if (symbol instanceof Symbol.FunctionTypeSymbol functionSymbol) {
Type.TypeFunction functionType = (Type.TypeFunction) functionSymbol.type;
var function = new CompiledFunction(functionSymbol);
if (options.contains(Options.DUMP_INITIAL_IR))
function.dumpIR(false, "Initial IR");
functionType.code = function;
if (opt) {
new Optimizer().optimize(function);
}
new Optimizer().optimize(function, options);
}
}
}
public TypeDictionary compileSrc(String src) {
return compileSrc(src, false);
return compileSrc(src, EnumSet.noneOf(Options.class));
}
public TypeDictionary compileSrc(String src, boolean opt) {
public TypeDictionary compileSrc(String src, EnumSet<Options> options) {
Parser parser = new Parser();
var program = parser.parse(new Lexer(src));
var typeDict = new TypeDictionary();
var sema = new SemaDefineTypes(typeDict);
sema.analyze(program);
var sema2 = new SemaAssignTypes(typeDict);
sema2.analyze(program);
compile(typeDict, opt);
compile(typeDict, options);
return typeDict;
}
public static String dumpIR(TypeDictionary typeDictionary) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,21 @@ public class EnterSSA {
int[] counters;
VersionStack[] stacks;

public EnterSSA(CompiledFunction bytecodeFunction) {
public EnterSSA(CompiledFunction bytecodeFunction, EnumSet<Options> options) {
this.function = bytecodeFunction;
setupGlobals();
computeDomTreeAndDominanceFrontiers();
if (options.contains(Options.DUMP_PRE_SSA_DOMTREE)) {
System.out.println("Pre SSA Dominator Tree");
System.out.println(domTree.generateDotOutput());
}
this.blocks = domTree.blocks; // the blocks are ordered reverse post order
findNonLocalNames();
insertPhis();
renameVars();
bytecodeFunction.isSSA = true;
bytecodeFunction.hasLiveness = false;
if (options.contains(Options.DUMP_SSA_IR)) bytecodeFunction.dumpIR(false, "Post SSA IR");
}

private void computeDomTreeAndDominanceFrontiers() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,21 @@ public class ExitSSA {
NameStack[] stacks;
DominatorTree tree;

public ExitSSA(CompiledFunction function) {
public ExitSSA(CompiledFunction function, EnumSet<Options> options) {
this.function = function;
if (!function.isSSA) throw new IllegalStateException();
function.livenessAnalysis();
System.out.println(function.toStr(new StringBuilder(), true));
if (options.contains(Options.DUMP_SSA_LIVENESS)) function.dumpIR(true, "SSA Liveness Analysis");
tree = new DominatorTree(function.entry);
if (options.contains(Options.DUMP_SSA_DOMTREE)) {
System.out.println("Pre SSA Dominator Tree");
System.out.println(tree.generateDotOutput());
}
initStack();
insertCopies(function.entry);
removePhis();
function.isSSA = false;
if (options.contains(Options.DUMP_POST_SSA_IR)) function.dumpIR(false, "After exiting SSA");
}

private void removePhis() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package com.compilerprogramming.ezlang.compiler;

import java.util.EnumSet;

public class Optimizer {

public void optimize(CompiledFunction function) {
new EnterSSA(function);
new SparseConditionalConstantPropagation().constantPropagation(function).apply();
new ExitSSA(function);
new ChaitinGraphColoringRegisterAllocator().assignRegisters(function, 64);
public void optimize(CompiledFunction function, EnumSet<Options> options) {
if (options.contains(Options.OPTIMIZE)) {
new EnterSSA(function, options);
if (options.contains(Options.SCCP))
new SparseConditionalConstantPropagation().constantPropagation(function).apply(options);
new ExitSSA(function, options);
}
if (options.contains(Options.REGALLOC))
new ChaitinGraphColoringRegisterAllocator().assignRegisters(function, 64, options);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.compilerprogramming.ezlang.compiler;

import java.util.EnumSet;

public enum Options {
OPTIMIZE,
SCCP,
REGALLOC,
DUMP_INITIAL_IR,
DUMP_PRE_SSA_DOMTREE,
DUMP_SSA_IR,
DUMP_SCCP_PREAPPLY,
DUMP_SCCP_POSTAPPLY,
DUMP_SSA_LIVENESS,
DUMP_SSA_DOMTREE,
DUMP_POST_SSA_IR,
DUMP_INTERFERENCE_GRAPH,
DUMP_CHAITIN_COALESCE,
DUMP_POST_CHAITIN_IR;

public static final EnumSet<Options> NONE = EnumSet.noneOf(Options.class);
public static final EnumSet<Options> OPT = EnumSet.of(Options.OPTIMIZE,Options.SCCP,Options.REGALLOC);
public static final EnumSet<Options> OPT_VERBOSE = EnumSet.allOf(Options.class);
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ private void init(CompiledFunction function) {
visited = new BitSet();
}

public SparseConditionalConstantPropagation apply() {
public SparseConditionalConstantPropagation apply(EnumSet<Options> options) {
/*
The constant propagation algorithm does not change the flow graph - it computes
information about the flow graph. The compiler now uses this information to improve
Expand All @@ -137,10 +137,15 @@ public SparseConditionalConstantPropagation apply() {

Bob Morgan. Building an Optimizing Compiler
*/
if (options.contains(Options.DUMP_SCCP_PREAPPLY)) {
System.out.println("SCCP analysis\n");
System.out.println(toString());
}
markExecutableBlocks();
removeBranchesThatAreNotExecutable();
replaceVarsWithConstants();
// Unreachable blocks are eliminated as there are no paths to them
if (options.contains(Options.DUMP_SCCP_POSTAPPLY)) function.dumpIR(false, "Post SCCP\n");
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public void test4() {
Assert.assertEquals(2, edges.size());
Assert.assertTrue(edges.contains(new InterferenceGraph.Edge(0, 1)));
Assert.assertTrue(edges.contains(new InterferenceGraph.Edge(0, 2)));
var regAssignments = new ChaitinGraphColoringRegisterAllocator().assignRegisters(function, 64);
var regAssignments = new ChaitinGraphColoringRegisterAllocator().assignRegisters(function, 64, Options.OPT);
String result = function.toStr(new StringBuilder(), false).toString();
Assert.assertEquals("""
L0:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,24 @@
import org.junit.Test;

import java.util.BitSet;
import java.util.EnumSet;

public class TestSCCP {

String compileSrc(String src) {
var compiler = new Compiler();
var typeDict = compiler.compileSrc(src);
StringBuilder sb = new StringBuilder();
var options = Options.NONE;
for (Symbol s : typeDict.bindings.values()) {
if (s instanceof Symbol.FunctionTypeSymbol f) {
var functionBuilder = (CompiledFunction) f.code();
new EnterSSA(functionBuilder);
new EnterSSA(functionBuilder, options);
BasicBlock.toStr(sb, functionBuilder.entry, new BitSet(), false);
//functionBuilder.toDot(sb, false);
var sccp = new SparseConditionalConstantPropagation().constantPropagation(functionBuilder);
sb.append(sccp.toString());
sccp.apply();
sccp.apply(options);
sb.append("After SCCP changes:\n");
functionBuilder.toStr(sb, false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import java.util.Arrays;
import java.util.BitSet;
import java.util.EnumSet;

public class TestSSATransform {

Expand All @@ -23,11 +24,11 @@ String compileSrc(String src) {
sb.append("Before SSA\n");
sb.append("==========\n");
BasicBlock.toStr(sb, functionBuilder.entry, new BitSet(), false);
new EnterSSA(functionBuilder);
new EnterSSA(functionBuilder, Options.NONE);
sb.append("After SSA\n");
sb.append("=========\n");
BasicBlock.toStr(sb, functionBuilder.entry, new BitSet(), false);
new ExitSSA(functionBuilder);
new ExitSSA(functionBuilder, Options.NONE);
sb.append("After exiting SSA\n");
sb.append("=================\n");
BasicBlock.toStr(sb, functionBuilder.entry, new BitSet(), false);
Expand Down Expand Up @@ -680,7 +681,7 @@ public void testLostCopyProblem() {
ret x2
""";
Assert.assertEquals(expected, function.toStr(new StringBuilder(), false).toString());
new ExitSSA(function);
new ExitSSA(function, EnumSet.noneOf(Options.class));
expected = """
L0:
arg p
Expand Down Expand Up @@ -748,7 +749,7 @@ public void testSwapProblem() {
L1:
""";
Assert.assertEquals(expected, function.toStr(new StringBuilder(), false).toString());
new ExitSSA(function);
new ExitSSA(function, EnumSet.noneOf(Options.class));
expected = """
L0:
arg p
Expand Down
Loading
Loading