1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-08-02 09:29:35 +00:00

Fixed problem with nested do loops being mixed up during empty block culling. Improved flipper implementation.

This commit is contained in:
Jesper Gravgaard 2017-07-13 20:41:16 +02:00
parent d41f762a8b
commit 2e90516f34
9 changed files with 123 additions and 54 deletions

View File

@ -3,9 +3,11 @@ Features
- Implement Register Allocation (that utilize real registers - and non-zeropage memory)
- Add Fixed Point number types
- Create a proper main function for the compiler
- Add for loop
- Add a for loop for(init;condition;increment) {stmt} -> { init; do { stmt; increment } while (condition) }
- Add imports
- Add structs
- Add ++/-- incrementing/decrementing operators.
- Let { stmt } introduce a new anonymous scope.
- Add preprocessing / find a way to allow some functions to run at compile time
- Implement inline compilation of functions (and a mechanism for choosing which methods / calls to inline)
- Add ability to call ASM code from KC.
@ -13,7 +15,7 @@ Features
- Add inline ASM (maybe?)
Process/Code Structure Improvement
- Make each phase return a separate object graph (allowing for keeping the history in memory & performing rollbacks)
- Make each phase return a separate object graph (allowing for keeeping the history in memory & performing rollbacks)
- Implemenent Assertions for the output of different phases (ensuring that the result of the phase is consistent)
- Refactor Expression Operator Implementation & Evaluation into one class per operator
@ -25,6 +27,7 @@ Testing
- Add assert statements to the language. Create KC programs that test the compiler by compiling, running and testing assertions.
Optimizations
- Optimize phi transitions by ensuring that identical phi-transitions with regards to register allocation are collected into a single transition.
- Optimize register allocation by combining with knowledge of ASM program cost (bytes/cycles) and different ASM fragments with different clobbering.
- Optimize by finding optimal sequence for multiple phi assignments in entry-segments.
- Optimize by allowing resequencing of statements and phi assignemtns in a final phase. Perhaps by converting phi statements to "normal" statements and using some optimization step.

View File

@ -0,0 +1 @@
lda {cowo1}

View File

@ -0,0 +1,2 @@
cmp #{coby1}
bne {la1}

View File

@ -0,0 +1 @@
dec {zpby1}

View File

@ -61,7 +61,9 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
@Override
public Void visitStmtBlock(KickCParser.StmtBlockContext ctx) {
this.visit(ctx.stmtSeq());
if(ctx.stmtSeq()!=null) {
this.visit(ctx.stmtSeq());
}
return null;
}
@ -127,7 +129,9 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
Label beginJumpLabel = getCurrentSymbols().addLabelIntermediate();
StatementLabel beginJumpTarget = new StatementLabel(beginJumpLabel);
sequence.addStatement(beginJumpTarget);
this.visit(ctx.stmt());
if(ctx.stmt()!=null) {
this.visit(ctx.stmt());
}
RValue rValue = (RValue) this.visit(ctx.expr());
Statement doJmpStmt = new StatementConditionalJump(rValue, beginJumpLabel);
sequence.addStatement(doJmpStmt);

View File

@ -11,17 +11,20 @@ public class Pass2CullEmptyBlocks extends Pass2SsaOptimization {
@Override
public boolean optimize() {
List<ControlFlowBlock> remove = new ArrayList<>();
Map<Label, Label> replace = new HashMap<>();
final List<ControlFlowBlock> remove = new ArrayList<>();
for (ControlFlowBlock block : getGraph().getAllBlocks()) {
if (block.getStatements().isEmpty() && block.getLabel().isIntermediate()) {
remove.add(block);
}
}
for (ControlFlowBlock removeBlock : remove) {
for (final ControlFlowBlock removeBlock : remove) {
ControlFlowBlock successor = getGraph().getDefaultSuccessor(removeBlock);
for (ControlFlowBlock predecessor : getGraph().getPredecessors(removeBlock)) {
replace.put(removeBlock.getLabel(), predecessor.getLabel());
// Replace all jumps (default/conditional/call) to @removeBlock with a jump to the default successor
final List<ControlFlowBlock> predecessors = getGraph().getPredecessors(removeBlock);
for (ControlFlowBlock predecessor : predecessors) {
Map<Label, Label> replace = new HashMap<>();
replace.put(removeBlock.getLabel(), successor.getLabel());
if (removeBlock.getLabel().equals(predecessor.getDefaultSuccessor())) {
predecessor.setDefaultSuccessor(successor.getLabel());
}
@ -31,12 +34,35 @@ public class Pass2CullEmptyBlocks extends Pass2SsaOptimization {
if (removeBlock.getLabel().equals(predecessor.getCallSuccessor())) {
predecessor.setCallSuccessor(successor.getLabel());
}
replaceLabels(predecessor, replace);
}
// In all phi functions of a successor blocks make a copy of the phi assignment for each predecessor
ControlFlowGraphBaseVisitor<Void> phiFixVisitor = new ControlFlowGraphBaseVisitor<Void>() {
@Override
public Void visitPhi(StatementPhi phi) {
for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) {
if(previousSymbol.getBlock().equals(removeBlock.getLabel())) {
// Found a phi function referencing the remove block - add copies for each predecessor
RValue previousRValue = previousSymbol.getRValue();
for (ControlFlowBlock predecessor : predecessors) {
if(previousSymbol!=null) {
previousSymbol.setBlock(predecessor.getLabel());
previousSymbol = null;
} else {
phi.addPreviousVersion(predecessor.getLabel(), previousRValue);
}
}
break;
}
}
return null;
}
};
phiFixVisitor.visitBlock(successor);
getGraph().getAllBlocks().remove(removeBlock);
getSymbols().remove(removeBlock.getLabel());
System.out.println("Culled Empty Block " + removeBlock.getLabel());
}
replaceLabels(replace);
return remove.size()>0;
}

View File

@ -171,38 +171,53 @@ public abstract class Pass2SsaOptimization {
* @param replacements Variables that have alias values.
*/
public void replaceLabels(final Map<Label, Label> replacements) {
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
@Override
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
if (getReplacement(replacements, conditionalJump.getDestination()) != null) {
conditionalJump.setDestination(getReplacement(replacements, conditionalJump.getDestination()));
}
return null;
}
@Override
public Void visitJump(StatementJump jump) {
if (getReplacement(replacements, jump.getDestination()) != null) {
jump.setDestination(getReplacement(replacements, jump.getDestination()));
}
return null;
}
@Override
public Void visitPhi(StatementPhi phi) {
for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) {
Label replacement = getReplacement(replacements, previousSymbol.getBlock());
if (replacement != null) {
previousSymbol.setBlock(replacement);
}
}
return null;
}
};
ControlFlowGraphBaseVisitor<Void> visitor = getLabelReplaceVisitor(replacements);
visitor.visitGraph(graph);
}
/**
* Replace all usages of a label in statements with another label.
*
* @param replacements Variables that have alias values.
*/
public void replaceLabels(ControlFlowBlock block, final Map<Label, Label> replacements) {
ControlFlowGraphBaseVisitor<Void> visitor = getLabelReplaceVisitor(replacements);
visitor.visitBlock(block);
}
/** Creates a visitor that can replace labels. */
private ControlFlowGraphBaseVisitor<Void> getLabelReplaceVisitor(final Map<Label, Label> replacements) {
return new ControlFlowGraphBaseVisitor<Void>() {
@Override
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
if (getReplacement(replacements, conditionalJump.getDestination()) != null) {
conditionalJump.setDestination(getReplacement(replacements, conditionalJump.getDestination()));
}
return null;
}
@Override
public Void visitJump(StatementJump jump) {
if (getReplacement(replacements, jump.getDestination()) != null) {
jump.setDestination(getReplacement(replacements, jump.getDestination()));
}
return null;
}
@Override
public Void visitPhi(StatementPhi phi) {
for (StatementPhi.PreviousSymbol previousSymbol : phi.getPreviousVersions()) {
Label replacement = getReplacement(replacements, previousSymbol.getBlock());
if (replacement != null) {
previousSymbol.setBlock(replacement);
}
}
return null;
}
};
}
/**
* Get the label to use as replacement for another label.
*
@ -244,13 +259,13 @@ public abstract class Pass2SsaOptimization {
}
/**
* Remove variables from the symbol table
* Remove symbols from the symbol table
*
* @param variables The variables to remove
* @param symbols The symbols to remove
*/
public void deleteSymbols(Collection<? extends LValue> variables) {
for (LValue variable : variables) {
scope.remove((Symbol) variable);
public void deleteSymbols(Collection<? extends Symbol> symbols) {
for (Symbol symbol : symbols) {
symbol.getScope().remove(symbol);
}
}

View File

@ -119,6 +119,13 @@ public class Pass3RegisterAllocation {
allocation.allocate(symbols.getVariable("flip::i#2"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("flip::$0"), RegisterAllocation.getRegisterA());
allocation.allocate(symbols.getVariable("flip::$8"), RegisterAllocation.getRegisterA());
allocation.allocate(symbols.getVariable("$1"), RegisterAllocation.getRegisterA());
allocation.allocate(symbols.getVariable("$3"), RegisterAllocation.getRegisterA());
allocation.allocate(symbols.getVariable("c#0"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("c#1"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("c#2"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("c#3"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("c#4"), RegisterAllocation.getRegisterX());
symbols.setAllocation(allocation);
@ -137,6 +144,8 @@ public class Pass3RegisterAllocation {
currentZp = currentZp + 2;
} else if (symbol.getType().equals(SymbolTypeBasic.BOOLEAN)) {
allocation.allocate(var, new RegisterAllocation.RegisterZpBool(currentZp++));
} else if (symbol.getType().equals(SymbolTypeBasic.VOID)) {
// No need to allocate register for VOID value
} else if (symbol.getType() instanceof SymbolTypePointer) {
allocation.allocate(var, new RegisterAllocation.RegisterZpPointerByte(currentZp));
currentZp = currentZp + 2;

View File

@ -2,10 +2,18 @@ byte[1000] SCREEN = $0400;
byte[16*16] buffer = $1000;
byte[16*16] buffer2 = $1100;
byte *RASTER = $d012;
prepare();
do {
plot();
byte c = 25;
do{
do { } while(*RASTER!=254)
do { } while(*RASTER!=255)
c=c-1;
} while(c!=0)
flip();
plot();
} while(true)
// Prepare buffer
@ -21,18 +29,18 @@ void prepare() {
void flip() {
byte srcIdx = 0;
byte dstIdx = 15;
byte r=0;
byte r=16;
do {
byte c = 0;
byte c = 16;
do {
buffer2[dstIdx] = buffer[srcIdx];
srcIdx = srcIdx+1;
dstIdx = dstIdx+16;
c=c+1;
} while(c<16)
r=r+1;
c=c-1;
} while(c!=0)
dstIdx = dstIdx-1;
} while(r<16)
r=r-1;
} while(r!=0)
byte i=0;
do {
buffer[i] = buffer2[i];
@ -43,7 +51,7 @@ void flip() {
// Plot buffer on screen
void plot() {
byte* line = SCREEN+5*40+12;
byte y=0;
byte y=16;
byte i=0;
do {
byte x=0;
@ -53,6 +61,6 @@ void plot() {
i=i+1;
} while(x<16)
line = line+40;
y=y+1;
} while(y<16)
y=y-1;
} while(y!=0)
}