From 4ca3fe0787dbe0c79933f16f8e67221259a9e9ad Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Mon, 15 May 2017 08:40:47 +0200 Subject: [PATCH] Added naive register allocation --- .../camelot64/kickc/icl/ControlFlowBlock.java | 10 +- .../icl/Pass1GenerateControlFlowGraph.java | 7 +- .../kickc/icl/Pass2CullEmptyBlocks.java | 8 +- .../kickc/icl/Pass2Optimization.java | 8 +- .../kickc/icl/Pass3RegisterAllocation.java | 25 ++++ .../kickc/icl/RegisterAllocation.java | 73 ++++++++++++ src/dk/camelot64/kickc/icl/SymbolTable.java | 57 +++++++-- src/dk/camelot64/kickc/test/Main.java | 9 ++ src/dk/camelot64/kickc/test/codegen.txt | 111 ++++++++++++++++++ 9 files changed, 281 insertions(+), 27 deletions(-) create mode 100644 src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java create mode 100644 src/dk/camelot64/kickc/icl/RegisterAllocation.java create mode 100644 src/dk/camelot64/kickc/test/codegen.txt diff --git a/src/dk/camelot64/kickc/icl/ControlFlowBlock.java b/src/dk/camelot64/kickc/icl/ControlFlowBlock.java index fe3222fc0..07beaf984 100644 --- a/src/dk/camelot64/kickc/icl/ControlFlowBlock.java +++ b/src/dk/camelot64/kickc/icl/ControlFlowBlock.java @@ -73,16 +73,18 @@ public class ControlFlowBlock { public String toString() { StringBuffer out = new StringBuffer(); out.append(label.getName() + ":" ); - out.append(" from"); - for (ControlFlowBlock predecessor : predecessors) { - out.append(" "+predecessor.getLabel().getName()); + if(predecessors.size()>0) { + out.append(" from"); + for (ControlFlowBlock predecessor : predecessors) { + out.append(" " + predecessor.getLabel().getName()); + } } out.append("\n"); for (Statement statement : statements) { out.append(" "+statement+"\n"); } - out.append(" to:"); if(defaultSuccessor!=null) { + out.append(" to:"); out.append(defaultSuccessor.getLabel().getName()); } out.append("\n"); diff --git a/src/dk/camelot64/kickc/icl/Pass1GenerateControlFlowGraph.java b/src/dk/camelot64/kickc/icl/Pass1GenerateControlFlowGraph.java index cce903fc4..0449dd22e 100644 --- a/src/dk/camelot64/kickc/icl/Pass1GenerateControlFlowGraph.java +++ b/src/dk/camelot64/kickc/icl/Pass1GenerateControlFlowGraph.java @@ -8,7 +8,8 @@ import java.util.Map; /** Pass that generates a control flow graph for the program */ public class Pass1GenerateControlFlowGraph { - public static final String FIRST_BLOCK_NAME = "@0"; + public static final String BEGIN_BLOCK_NAME = "@BEGIN"; + public static final String END_BLOCK_NAME = "@END"; private SymbolTable symbolTable; private Map blocks; private ControlFlowBlock firstBlock; @@ -19,8 +20,9 @@ public class Pass1GenerateControlFlowGraph { } public ControlFlowGraph generate(StatementSequence sequence) { - this.firstBlock = getOrCreateBlock(symbolTable.newNamedJumpLabel(FIRST_BLOCK_NAME)); + this.firstBlock = getOrCreateBlock(symbolTable.newNamedJumpLabel(BEGIN_BLOCK_NAME)); ControlFlowBlock currentBlock = this.firstBlock; + sequence.addStatement(new StatementJumpTarget(symbolTable.newNamedJumpLabel(END_BLOCK_NAME))); for (Statement statement : sequence.getStatements()) { if(statement instanceof StatementJumpTarget) { StatementJumpTarget statementJumpTarget = (StatementJumpTarget) statement; @@ -49,6 +51,7 @@ public class Pass1GenerateControlFlowGraph { currentBlock.addStatement(statement); } } + return new ControlFlowGraph(blocks, firstBlock); } diff --git a/src/dk/camelot64/kickc/icl/Pass2CullEmptyBlocks.java b/src/dk/camelot64/kickc/icl/Pass2CullEmptyBlocks.java index 8b6d5cef0..576d36452 100644 --- a/src/dk/camelot64/kickc/icl/Pass2CullEmptyBlocks.java +++ b/src/dk/camelot64/kickc/icl/Pass2CullEmptyBlocks.java @@ -14,7 +14,7 @@ public class Pass2CullEmptyBlocks extends Pass2Optimization { List remove = new ArrayList<>(); Map replace = new HashMap<>(); for (ControlFlowBlock block : getGraph().getAllBlocks()) { - if (block.getStatements().isEmpty()) { + if (block.getStatements().isEmpty() && block.getLabel().isIntermediate()) { remove.add(block); } } @@ -22,20 +22,20 @@ public class Pass2CullEmptyBlocks extends Pass2Optimization { ControlFlowBlock successor = block.getDefaultSuccessor(); for (ControlFlowBlock predecessor : block.getPredecessors()) { replace.put(block.getLabel(), predecessor.getLabel()); - if (predecessor.getDefaultSuccessor().equals(block)) { + if (block.equals(predecessor.getDefaultSuccessor())) { predecessor.setDefaultSuccessor(successor); if (successor != null) { successor.addPredecessor(predecessor); } } - if (predecessor.getConditionalSuccessor().equals(block)) { + if (block.equals(predecessor.getConditionalSuccessor())) { predecessor.setConditionalSuccessor(successor); if (successor != null) { successor.addPredecessor(predecessor); } } } - if (successor != null) { + if (successor != null && block.getLabel().isIntermediate()) { successor.removePredecessor(block); } getGraph().getAllBlocks().remove(block); diff --git a/src/dk/camelot64/kickc/icl/Pass2Optimization.java b/src/dk/camelot64/kickc/icl/Pass2Optimization.java index 15cc1ef34..f7e302705 100644 --- a/src/dk/camelot64/kickc/icl/Pass2Optimization.java +++ b/src/dk/camelot64/kickc/icl/Pass2Optimization.java @@ -116,10 +116,10 @@ public abstract class Pass2Optimization { * @param replacements Variables that have alias values. */ public void replaceLabels(final Map replacements) { - ControlFlowGraphBaseVisitor visitor = new ControlFlowGraphBaseVisitor() { + ControlFlowGraphBaseVisitor visitor = new ControlFlowGraphBaseVisitor() { @Override - public Object visitConditionalJump(StatementConditionalJump conditionalJump) { + public Void visitConditionalJump(StatementConditionalJump conditionalJump) { if(getReplacement(replacements, conditionalJump.getDestination())!=null) { conditionalJump.setDestination(getReplacement(replacements, conditionalJump.getDestination())); } @@ -127,7 +127,7 @@ public abstract class Pass2Optimization { } @Override - public Object visitJump(StatementJump jump) { + public Void visitJump(StatementJump jump) { if(getReplacement(replacements, jump.getDestination())!=null) { jump.setDestination(getReplacement(replacements, jump.getDestination())); } @@ -135,7 +135,7 @@ public abstract class Pass2Optimization { } @Override - public Object visitPhi(StatementPhi phi) { + public Void visitPhi(StatementPhi phi) { for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) { Label replacement = getReplacement(replacements, previousSymbol.getBlock().getLabel()); if(replacement !=null) { diff --git a/src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java b/src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java new file mode 100644 index 000000000..d025adc7f --- /dev/null +++ b/src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java @@ -0,0 +1,25 @@ +package dk.camelot64.kickc.icl; + +/** Register Allocation for variables */ +public class Pass3RegisterAllocation { + + private ControlFlowGraph graph; + private SymbolTable symbols; + + public Pass3RegisterAllocation(ControlFlowGraph graph, SymbolTable symbols) { + this.graph = graph; + this.symbols = symbols; + } + + public void allocate() { + RegisterAllocation allocation = new RegisterAllocation(); + int currentZp = 2; + for (Variable var : symbols.getAllVariables()) { + if(var instanceof VariableIntermediate || var instanceof VariableVersion) + allocation.allocate(var, new RegisterAllocation.RegisterZp(currentZp++)); + } + symbols.setAllocation(allocation); + } + + +} diff --git a/src/dk/camelot64/kickc/icl/RegisterAllocation.java b/src/dk/camelot64/kickc/icl/RegisterAllocation.java new file mode 100644 index 000000000..06f52bad0 --- /dev/null +++ b/src/dk/camelot64/kickc/icl/RegisterAllocation.java @@ -0,0 +1,73 @@ +package dk.camelot64.kickc.icl; + + +import java.util.HashMap; +import java.util.Map; + +/** Register Allocation for Variable Symbols */ +public class RegisterAllocation { + + private Map allocation; + + public RegisterAllocation() { + this.allocation = new HashMap<>(); + } + + /** + * Get the register allocated for a specific variable + * + * @param variable The variable + * @return The allocated register. + */ + public Register getRegister(Variable variable) { + return allocation.get(variable); + } + + public void allocate(Variable variable, Register register) { + allocation.put(variable, register); + } + + /** A register used for storing a single variable. */ + public interface Register { + + RegisterType getType(); + + } + + /** The register type. */ + public enum RegisterType { ZP }; + + /** A zero page address used as a register for a single byte variable. */ + public static class RegisterZp implements Register { + + private int zp; + + public RegisterZp(int zp) { + this.zp = zp; + } + + public int getZp() { + return zp; + } + + @Override + public RegisterType getType() { + return RegisterType.ZP; + } + + @Override + public String toString() { + return "zp:"+zp; + } + } + + @Override + public String toString() { + StringBuffer out = new StringBuffer(); + for (Variable variable : allocation.keySet()) { + Register register = getRegister(variable); + out.append(variable+" : "+register+"\n"); + } + return out.toString(); + } +} diff --git a/src/dk/camelot64/kickc/icl/SymbolTable.java b/src/dk/camelot64/kickc/icl/SymbolTable.java index db2574acd..16a568ea6 100644 --- a/src/dk/camelot64/kickc/icl/SymbolTable.java +++ b/src/dk/camelot64/kickc/icl/SymbolTable.java @@ -10,11 +10,22 @@ public class SymbolTable { private Map symbols; private int intermediateVarCount = 0; private int intermediateLabelCount = 1; + private RegisterAllocation allocation; public SymbolTable() { this.symbols = new LinkedHashMap<>(); } + public Collection getAllVariables() { + Collection vars = new ArrayList<>(); + for (Symbol symbol : symbols.values()) { + if(symbol instanceof Variable) { + vars.add((Variable) symbol); + } + } + return vars; + } + private Symbol addSymbol(Symbol symbol) { if(symbols.get(symbol.getName())!=null) { throw new RuntimeException("Symbol already declared "+symbol.getName()); @@ -54,19 +65,6 @@ public class SymbolTable { return symbol; } - @Override - public String toString() { - StringBuffer out = new StringBuffer(); - Set names = symbols.keySet(); - List sortedNames = new ArrayList<>(names); - Collections.sort(sortedNames); - for (String name : sortedNames) { - Symbol symbol = symbols.get(name); - out.append(symbol.toString() + "\n"); - } - return out.toString(); - } - public void remove(Symbol symbol) { symbols.remove(symbol.getName()); } @@ -76,4 +74,37 @@ public class SymbolTable { symbols.put(version.getName(), version); return version; } + + public void setAllocation(RegisterAllocation allocation) { + this.allocation = allocation; + } + + public RegisterAllocation.Register getRegister(Variable variable) { + RegisterAllocation.Register register = null; + if(allocation!=null) { + register = allocation.getRegister(variable); + } + return register; + } + + @Override + public String toString() { + StringBuffer out = new StringBuffer(); + Set names = symbols.keySet(); + List sortedNames = new ArrayList<>(names); + Collections.sort(sortedNames); + for (String name : sortedNames) { + Symbol symbol = symbols.get(name); + out.append(symbol.toString()); + if(symbol instanceof Variable) { + RegisterAllocation.Register register = getRegister((Variable) symbol); + if(register!=null) { + out.append(" "+register); + } + } + out.append("\n"); + } + return out.toString(); + } + } diff --git a/src/dk/camelot64/kickc/test/Main.java b/src/dk/camelot64/kickc/test/Main.java index 88e3ab2ac..4619fb11c 100644 --- a/src/dk/camelot64/kickc/test/Main.java +++ b/src/dk/camelot64/kickc/test/Main.java @@ -33,6 +33,12 @@ public class Main { Pass1GenerateControlFlowGraph pass1GenerateControlFlowGraph = new Pass1GenerateControlFlowGraph(symbolTable); ControlFlowGraph controlFlowGraph = pass1GenerateControlFlowGraph.generate(statementSequence); + System.out.println("SYMBOLS"); + System.out.println(symbolTable.toString()); + System.out.println("CONTROL FLOW GRAPH"); + System.out.println(controlFlowGraph.toString()); + + Pass1GenerateSingleStaticAssignmentForm pass1GenerateSingleStaticAssignmentForm = new Pass1GenerateSingleStaticAssignmentForm(symbolTable, controlFlowGraph); pass1GenerateSingleStaticAssignmentForm.generate(); @@ -56,6 +62,9 @@ public class Main { } } + Pass3RegisterAllocation pass3RegisterAllocation = new Pass3RegisterAllocation(controlFlowGraph, symbolTable); + pass3RegisterAllocation.allocate(); + System.out.println("SYMBOLS"); System.out.println(symbolTable.toString()); System.out.println("CONTROL FLOW GRAPH"); diff --git a/src/dk/camelot64/kickc/test/codegen.txt b/src/dk/camelot64/kickc/test/codegen.txt new file mode 100644 index 000000000..bdd6049ce --- /dev/null +++ b/src/dk/camelot64/kickc/test/codegen.txt @@ -0,0 +1,111 @@ +@1: from @BEGIN @5 b#3 a#7 $2 b#4 $4 b#2 b#8 a#1 + (word) b#3 ← phi( @BEGIN/(byte) 0 @5/(word) b#8 ) L . . . . . R + + (byte) a#7 ← phi( @BEGIN/(byte) 0 @5/(byte) a#1 ) + L . . . . . R + (boolean*) $2 ← (byte) a#7 < (byte) 10 + R L . . . . . + if((boolean*) $2) goto @2 + + R . . . . . + to: @END . . . . . . . . +@2: from @1 ---------------------------------------------------------------------------- + (word) b#4 ← (word) b#3 + (byte) a#7 R R . L . . . . + (boolean*) $4 ← (word) b#4 > (byte) 10 . + . R L . . . + if((boolean*) $4) goto @4 . + . + R . . . + to:@5 . . . + . . . . +@4: from @2 ---------------------------------------------------------------------------- + (word) b#2 ← (word) b#4 - (byte) 10 . + . R . L . . + to:@5 . + . . . + . . +@5: from @4 @2 ------------------------------------------------------------------------- + (word) b#8 ← phi( @2/(word) b#4 @4/(word) b#2 ) . + . R . R L . + (byte) a#1 ← (byte) a#7 + (byte) 1 . R . . . . + L + to:@1 + +@BEGIN: +@1_from_@0: + ldx #0 //X=a + lda #0 //A=b +@1: // A=b, X=a + cpx #10 // $2 (C) + bcs @END +@2: // A=b, X=a + stx $2 // tmp + adc $2 // tmp + cmp #11 // $4 (C) + bcc @5 +@4: // A=b, X=a + sec + sbc #10 +@5: // A=b, X=a + inx // a + jmp @1 +@END: + +@BEGIN: +@1_from_@0: + lda #0 + sta $2 // b + sta $3 // a +@1: + lda $3 // a + cmp #10 // $2 (C) + bcs @END +@2: + adc $2 // b + sta $2 // b + lda #10 // (b#4 > 10) -> (10 < b#4) + cmp $2 // $4 (C) + bcs @5 +@4: + lda $2 // b + sec + sbc #10 + sta $2 // b +@5: + inc $3 // a + jmp @1 +@END: + + +@BEGIN: +@1_from_@0: + lda #0 + sta $2 // b#3 + lda #0 + sta $3 // a#7 + jmp @1 +@1_from_@5: + lda $5 // b#8 + sta $2 // b#3 + lda $6 // a#1 + sta $3 // a#7 +@1: + lda $3 // a#7 + cmp #10 // $2 (C) + bcc @2 + jmp @END +@2: + lda $2 // b#3 + clc + adc $3 // a#7 + sta $4 // b#4 + lda #10 // (b#4 > 10) -> (10 < b#4) + cmp $4 // $4 (C) + bcc @4 + jmp @5_from_@2 +@4: + lda $4 // b#4 + sec + sbc #10 + sta $7 // b#2 + jmp @5_from_@4 +@5_from_@2: + lda $4 // b#4 + sta $5 // b#8 + jmp @5 +@5_from_@4: + lda $7 // b#2 + sta $5 // b#8 +@5: + lda $3 // a#7 + clc + adc 1 + sta $6 // a#1 + jmp @1_from_@5 +@END: