1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-06-03 07:29:37 +00:00

Added naive register allocation

This commit is contained in:
jespergravgaard 2017-05-15 08:40:47 +02:00
parent c58a999a42
commit 4ca3fe0787
9 changed files with 281 additions and 27 deletions

View File

@ -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");

View File

@ -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<Symbol, ControlFlowBlock> 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);
}

View File

@ -14,7 +14,7 @@ public class Pass2CullEmptyBlocks extends Pass2Optimization {
List<ControlFlowBlock> remove = new ArrayList<>();
Map<Label, Label> 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);

View File

@ -116,10 +116,10 @@ public abstract class Pass2Optimization {
* @param replacements Variables that have alias values.
*/
public void replaceLabels(final Map<Label, Label> replacements) {
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor() {
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
@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) {

View File

@ -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);
}
}

View File

@ -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<Variable, Register> 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();
}
}

View File

@ -10,11 +10,22 @@ public class SymbolTable {
private Map<String, Symbol> symbols;
private int intermediateVarCount = 0;
private int intermediateLabelCount = 1;
private RegisterAllocation allocation;
public SymbolTable() {
this.symbols = new LinkedHashMap<>();
}
public Collection<Variable> getAllVariables() {
Collection<Variable> 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<String> names = symbols.keySet();
List<String> 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<String> names = symbols.keySet();
List<String> 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();
}
}

View File

@ -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");

View File

@ -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: