mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-22 21:29:50 +00:00
Added naive register allocation
This commit is contained in:
parent
c58a999a42
commit
4ca3fe0787
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
25
src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java
Normal file
25
src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
73
src/dk/camelot64/kickc/icl/RegisterAllocation.java
Normal file
73
src/dk/camelot64/kickc/icl/RegisterAllocation.java
Normal 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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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");
|
||||
|
111
src/dk/camelot64/kickc/test/codegen.txt
Normal file
111
src/dk/camelot64/kickc/test/codegen.txt
Normal 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:
|
Loading…
Reference in New Issue
Block a user