mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-19 00:29:29 +00:00
Fixed problem with nested do loops being mixed up during empty block culling. Improved flipper implementation.
This commit is contained in:
parent
d41f762a8b
commit
2e90516f34
@ -3,9 +3,11 @@ Features
|
|||||||
- Implement Register Allocation (that utilize real registers - and non-zeropage memory)
|
- Implement Register Allocation (that utilize real registers - and non-zeropage memory)
|
||||||
- Add Fixed Point number types
|
- Add Fixed Point number types
|
||||||
- Create a proper main function for the compiler
|
- 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 imports
|
||||||
- Add structs
|
- 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
|
- 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)
|
- Implement inline compilation of functions (and a mechanism for choosing which methods / calls to inline)
|
||||||
- Add ability to call ASM code from KC.
|
- Add ability to call ASM code from KC.
|
||||||
@ -13,7 +15,7 @@ Features
|
|||||||
- Add inline ASM (maybe?)
|
- Add inline ASM (maybe?)
|
||||||
|
|
||||||
Process/Code Structure Improvement
|
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)
|
- 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
|
- 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.
|
- Add assert statements to the language. Create KC programs that test the compiler by compiling, running and testing assertions.
|
||||||
|
|
||||||
Optimizations
|
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 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 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.
|
- 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.
|
||||||
|
1
src/dk/camelot64/kickc/asm/fragment/aby=_star_cowo1.asm
Normal file
1
src/dk/camelot64/kickc/asm/fragment/aby=_star_cowo1.asm
Normal file
@ -0,0 +1 @@
|
|||||||
|
lda {cowo1}
|
@ -0,0 +1,2 @@
|
|||||||
|
cmp #{coby1}
|
||||||
|
bne {la1}
|
@ -0,0 +1 @@
|
|||||||
|
dec {zpby1}
|
@ -61,7 +61,9 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitStmtBlock(KickCParser.StmtBlockContext ctx) {
|
public Void visitStmtBlock(KickCParser.StmtBlockContext ctx) {
|
||||||
|
if(ctx.stmtSeq()!=null) {
|
||||||
this.visit(ctx.stmtSeq());
|
this.visit(ctx.stmtSeq());
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +129,9 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
|||||||
Label beginJumpLabel = getCurrentSymbols().addLabelIntermediate();
|
Label beginJumpLabel = getCurrentSymbols().addLabelIntermediate();
|
||||||
StatementLabel beginJumpTarget = new StatementLabel(beginJumpLabel);
|
StatementLabel beginJumpTarget = new StatementLabel(beginJumpLabel);
|
||||||
sequence.addStatement(beginJumpTarget);
|
sequence.addStatement(beginJumpTarget);
|
||||||
|
if(ctx.stmt()!=null) {
|
||||||
this.visit(ctx.stmt());
|
this.visit(ctx.stmt());
|
||||||
|
}
|
||||||
RValue rValue = (RValue) this.visit(ctx.expr());
|
RValue rValue = (RValue) this.visit(ctx.expr());
|
||||||
Statement doJmpStmt = new StatementConditionalJump(rValue, beginJumpLabel);
|
Statement doJmpStmt = new StatementConditionalJump(rValue, beginJumpLabel);
|
||||||
sequence.addStatement(doJmpStmt);
|
sequence.addStatement(doJmpStmt);
|
||||||
|
@ -11,17 +11,20 @@ public class Pass2CullEmptyBlocks extends Pass2SsaOptimization {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean optimize() {
|
public boolean optimize() {
|
||||||
List<ControlFlowBlock> remove = new ArrayList<>();
|
final List<ControlFlowBlock> remove = new ArrayList<>();
|
||||||
Map<Label, Label> replace = new HashMap<>();
|
|
||||||
for (ControlFlowBlock block : getGraph().getAllBlocks()) {
|
for (ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||||
if (block.getStatements().isEmpty() && block.getLabel().isIntermediate()) {
|
if (block.getStatements().isEmpty() && block.getLabel().isIntermediate()) {
|
||||||
remove.add(block);
|
remove.add(block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (ControlFlowBlock removeBlock : remove) {
|
|
||||||
|
for (final ControlFlowBlock removeBlock : remove) {
|
||||||
ControlFlowBlock successor = getGraph().getDefaultSuccessor(removeBlock);
|
ControlFlowBlock successor = getGraph().getDefaultSuccessor(removeBlock);
|
||||||
for (ControlFlowBlock predecessor : getGraph().getPredecessors(removeBlock)) {
|
// Replace all jumps (default/conditional/call) to @removeBlock with a jump to the default successor
|
||||||
replace.put(removeBlock.getLabel(), predecessor.getLabel());
|
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())) {
|
if (removeBlock.getLabel().equals(predecessor.getDefaultSuccessor())) {
|
||||||
predecessor.setDefaultSuccessor(successor.getLabel());
|
predecessor.setDefaultSuccessor(successor.getLabel());
|
||||||
}
|
}
|
||||||
@ -31,12 +34,35 @@ public class Pass2CullEmptyBlocks extends Pass2SsaOptimization {
|
|||||||
if (removeBlock.getLabel().equals(predecessor.getCallSuccessor())) {
|
if (removeBlock.getLabel().equals(predecessor.getCallSuccessor())) {
|
||||||
predecessor.setCallSuccessor(successor.getLabel());
|
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);
|
getGraph().getAllBlocks().remove(removeBlock);
|
||||||
getSymbols().remove(removeBlock.getLabel());
|
getSymbols().remove(removeBlock.getLabel());
|
||||||
System.out.println("Culled Empty Block " + removeBlock.getLabel());
|
System.out.println("Culled Empty Block " + removeBlock.getLabel());
|
||||||
}
|
}
|
||||||
replaceLabels(replace);
|
|
||||||
return remove.size()>0;
|
return remove.size()>0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +171,23 @@ public abstract class Pass2SsaOptimization {
|
|||||||
* @param replacements Variables that have alias values.
|
* @param replacements Variables that have alias values.
|
||||||
*/
|
*/
|
||||||
public void replaceLabels(final Map<Label, Label> replacements) {
|
public void replaceLabels(final Map<Label, Label> replacements) {
|
||||||
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
|
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
|
@Override
|
||||||
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
|
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
|
||||||
@ -200,7 +216,6 @@ public abstract class Pass2SsaOptimization {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
visitor.visitGraph(graph);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -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) {
|
public void deleteSymbols(Collection<? extends Symbol> symbols) {
|
||||||
for (LValue variable : variables) {
|
for (Symbol symbol : symbols) {
|
||||||
scope.remove((Symbol) variable);
|
symbol.getScope().remove(symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,6 +119,13 @@ public class Pass3RegisterAllocation {
|
|||||||
allocation.allocate(symbols.getVariable("flip::i#2"), RegisterAllocation.getRegisterX());
|
allocation.allocate(symbols.getVariable("flip::i#2"), RegisterAllocation.getRegisterX());
|
||||||
allocation.allocate(symbols.getVariable("flip::$0"), RegisterAllocation.getRegisterA());
|
allocation.allocate(symbols.getVariable("flip::$0"), RegisterAllocation.getRegisterA());
|
||||||
allocation.allocate(symbols.getVariable("flip::$8"), 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);
|
symbols.setAllocation(allocation);
|
||||||
|
|
||||||
@ -137,6 +144,8 @@ public class Pass3RegisterAllocation {
|
|||||||
currentZp = currentZp + 2;
|
currentZp = currentZp + 2;
|
||||||
} else if (symbol.getType().equals(SymbolTypeBasic.BOOLEAN)) {
|
} else if (symbol.getType().equals(SymbolTypeBasic.BOOLEAN)) {
|
||||||
allocation.allocate(var, new RegisterAllocation.RegisterZpBool(currentZp++));
|
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) {
|
} else if (symbol.getType() instanceof SymbolTypePointer) {
|
||||||
allocation.allocate(var, new RegisterAllocation.RegisterZpPointerByte(currentZp));
|
allocation.allocate(var, new RegisterAllocation.RegisterZpPointerByte(currentZp));
|
||||||
currentZp = currentZp + 2;
|
currentZp = currentZp + 2;
|
||||||
|
@ -2,10 +2,18 @@ byte[1000] SCREEN = $0400;
|
|||||||
byte[16*16] buffer = $1000;
|
byte[16*16] buffer = $1000;
|
||||||
byte[16*16] buffer2 = $1100;
|
byte[16*16] buffer2 = $1100;
|
||||||
|
|
||||||
|
byte *RASTER = $d012;
|
||||||
|
|
||||||
prepare();
|
prepare();
|
||||||
do {
|
do {
|
||||||
plot();
|
byte c = 25;
|
||||||
|
do{
|
||||||
|
do { } while(*RASTER!=254)
|
||||||
|
do { } while(*RASTER!=255)
|
||||||
|
c=c-1;
|
||||||
|
} while(c!=0)
|
||||||
flip();
|
flip();
|
||||||
|
plot();
|
||||||
} while(true)
|
} while(true)
|
||||||
|
|
||||||
// Prepare buffer
|
// Prepare buffer
|
||||||
@ -21,18 +29,18 @@ void prepare() {
|
|||||||
void flip() {
|
void flip() {
|
||||||
byte srcIdx = 0;
|
byte srcIdx = 0;
|
||||||
byte dstIdx = 15;
|
byte dstIdx = 15;
|
||||||
byte r=0;
|
byte r=16;
|
||||||
do {
|
do {
|
||||||
byte c = 0;
|
byte c = 16;
|
||||||
do {
|
do {
|
||||||
buffer2[dstIdx] = buffer[srcIdx];
|
buffer2[dstIdx] = buffer[srcIdx];
|
||||||
srcIdx = srcIdx+1;
|
srcIdx = srcIdx+1;
|
||||||
dstIdx = dstIdx+16;
|
dstIdx = dstIdx+16;
|
||||||
c=c+1;
|
c=c-1;
|
||||||
} while(c<16)
|
} while(c!=0)
|
||||||
r=r+1;
|
|
||||||
dstIdx = dstIdx-1;
|
dstIdx = dstIdx-1;
|
||||||
} while(r<16)
|
r=r-1;
|
||||||
|
} while(r!=0)
|
||||||
byte i=0;
|
byte i=0;
|
||||||
do {
|
do {
|
||||||
buffer[i] = buffer2[i];
|
buffer[i] = buffer2[i];
|
||||||
@ -43,7 +51,7 @@ void flip() {
|
|||||||
// Plot buffer on screen
|
// Plot buffer on screen
|
||||||
void plot() {
|
void plot() {
|
||||||
byte* line = SCREEN+5*40+12;
|
byte* line = SCREEN+5*40+12;
|
||||||
byte y=0;
|
byte y=16;
|
||||||
byte i=0;
|
byte i=0;
|
||||||
do {
|
do {
|
||||||
byte x=0;
|
byte x=0;
|
||||||
@ -53,6 +61,6 @@ void plot() {
|
|||||||
i=i+1;
|
i=i+1;
|
||||||
} while(x<16)
|
} while(x<16)
|
||||||
line = line+40;
|
line = line+40;
|
||||||
y=y+1;
|
y=y-1;
|
||||||
} while(y<16)
|
} while(y!=0)
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user