mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-09-08 17:54:40 +00:00
Improved uplift test and zp coalesce test to include live ranges from calling statements in overlap testing. The new live range system is still far from perfect. Next step is getEffectiveAlive(stmt) returning alive vars + alive vars from all calling contexts.
This commit is contained in:
parent
eb6cf1188c
commit
99088aef58
@ -135,8 +135,8 @@ public class Compiler {
|
|||||||
public void pass2OptimizeSSA(Program program) {
|
public void pass2OptimizeSSA(Program program) {
|
||||||
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
|
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
|
||||||
optimizations.add(new Pass2CullEmptyBlocks(program));
|
optimizations.add(new Pass2CullEmptyBlocks(program));
|
||||||
//optimizations.add(new Pass2ConstantPropagation(program));
|
optimizations.add(new Pass2ConstantPropagation(program));
|
||||||
//optimizations.add(new Pass2ConstantAdditionElimination(program));
|
optimizations.add(new Pass2ConstantAdditionElimination(program));
|
||||||
optimizations.add(new Pass2UnaryNotSimplification(program));
|
optimizations.add(new Pass2UnaryNotSimplification(program));
|
||||||
optimizations.add(new Pass2AliasElimination(program));
|
optimizations.add(new Pass2AliasElimination(program));
|
||||||
optimizations.add(new Pass2RedundantPhiElimination(program));
|
optimizations.add(new Pass2RedundantPhiElimination(program));
|
||||||
@ -177,7 +177,7 @@ public class Compiler {
|
|||||||
program.getLog().append("CALL GRAPH");
|
program.getLog().append("CALL GRAPH");
|
||||||
program.getLog().append(program.getCallGraph().toString());
|
program.getLog().append(program.getCallGraph().toString());
|
||||||
|
|
||||||
program.getLog().setVerboseLiveRanges(true);
|
//program.getLog().setVerboseLiveRanges(true);
|
||||||
|
|
||||||
new Pass3LiveRangesAnalysis(program).findLiveRanges();
|
new Pass3LiveRangesAnalysis(program).findLiveRanges();
|
||||||
program.getLog().append("CONTROL FLOW GRAPH - LIVE RANGES FOUND");
|
program.getLog().append("CONTROL FLOW GRAPH - LIVE RANGES FOUND");
|
||||||
@ -242,7 +242,7 @@ public class Compiler {
|
|||||||
program.getLog().append(program.getRegisterUpliftProgram().toString((program.getVariableRegisterWeights())));
|
program.getLog().append(program.getRegisterUpliftProgram().toString((program.getVariableRegisterWeights())));
|
||||||
|
|
||||||
// Attempt uplifting registers through a lot of combinations
|
// Attempt uplifting registers through a lot of combinations
|
||||||
program.getLog().setVerboseUplift(true);
|
//program.getLog().setVerboseUplift(true);
|
||||||
new Pass4RegisterUpliftCombinations(program).performUplift(10_000);
|
new Pass4RegisterUpliftCombinations(program).performUplift(10_000);
|
||||||
|
|
||||||
//new Pass4RegisterUpliftStatic(program).performUplift();
|
//new Pass4RegisterUpliftStatic(program).performUplift();
|
||||||
|
@ -1,3 +1,16 @@
|
|||||||
|
TODO's for new Constant Solution
|
||||||
|
- Live range overlap analysis of register combinations inside methods must also look at registers alive at all calls.
|
||||||
|
- Examine why temp-vars are used in flipper.
|
||||||
|
- Examine why flipper is plotted in a wrong position on the screen.
|
||||||
|
- Implement constants into the symbol table and support them in code.
|
||||||
|
- Implement new constant consolidation steps.
|
||||||
|
- Look at optimizing liverange.kc's ASM further - atm. there are to many copy-operations into unnecesary registers.
|
||||||
|
- In summin.asm the result of the 2nd sum() is clobbered twice during call to sum(). jsr sum, txa, lda #$d, ldx #$9, jsr sum
|
||||||
|
- Fix by introducing "effective alive vars" which includes alive vars at all calls to containing methods and using that during clobber check.
|
||||||
|
+ In loopnest.asm x&y are used in both loops - the outer x&y are clobbered by the inner loop.
|
||||||
|
- In voronoi.asm in render() x is clobbered during call to findcol().
|
||||||
|
|
||||||
|
|
||||||
Features
|
Features
|
||||||
- Move the main code into a main() function, and disallow code outside functions. The main function per default has no parameters and exits with RTS.
|
- Move the main code into a main() function, and disallow code outside functions. The main function per default has no parameters and exits with RTS.
|
||||||
- Improve locality of block sequence for if(cond) { stmt1; } else { stmt2; } to if(!cond) goto @else stmt1; jmp @end; @else: stmt2; @end:
|
- Improve locality of block sequence for if(cond) { stmt1; } else { stmt2; } to if(!cond) goto @else stmt1; jmp @end; @else: stmt2; @end:
|
||||||
|
@ -76,15 +76,27 @@ public class AsmFragmentManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(signature.startsWith("zpby1=")) {
|
if(signature.startsWith("zpby1=")) {
|
||||||
String subSignature = "aby="+signature.substring(6).replace("zpby2", "zpby1");
|
if(signature.contains("{zpby2}")) {
|
||||||
CharStream subCharStream = loadOrSynthesizeFragment(subSignature);
|
String subSignature = "aby="+signature.substring(6).replace("zpby2", "zpby1");
|
||||||
if(subCharStream!=null) {
|
CharStream subCharStream = loadOrSynthesizeFragment(subSignature);
|
||||||
CharStream result = CharStreams.fromString(subCharStream.toString().replace("zpby1", "zpby2")+"\nsta {zpby1}\n");
|
if(subCharStream!=null) {
|
||||||
return result;
|
CharStream result = CharStreams.fromString(subCharStream.toString().replace("zpby1", "zpby2")+"\nsta {zpby1}\n");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String subSignature = "aby="+signature.substring(6);
|
||||||
|
CharStream subCharStream = loadOrSynthesizeFragment(subSignature);
|
||||||
|
if(subCharStream!=null) {
|
||||||
|
CharStream result = CharStreams.fromString(subCharStream.toString()+"\nsta {zpby1}\n");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String sigNew = signature;
|
String sigNew = signature;
|
||||||
|
sigNew = regexpRewriteSignature(sigNew, "(.*)=(.*)_plus_aby", "$1=aby_plus_$2");
|
||||||
|
sigNew = regexpRewriteSignature(sigNew, "(.*)=(.*)_plus_xby", "$1=xby_plus_$2");
|
||||||
|
sigNew = regexpRewriteSignature(sigNew, "(.*)=(.*)_plus_yby", "$1=yby_plus_$2");
|
||||||
sigNew = regexpRewriteSignature(sigNew, "(.*)_ge_aby_then_(.*)", "aby_lt_$1_then_$2");
|
sigNew = regexpRewriteSignature(sigNew, "(.*)_ge_aby_then_(.*)", "aby_lt_$1_then_$2");
|
||||||
sigNew = regexpRewriteSignature(sigNew, "(.*)_ge_xby_then_(.*)", "xby_lt_$1_then_$2");
|
sigNew = regexpRewriteSignature(sigNew, "(.*)_ge_xby_then_(.*)", "xby_lt_$1_then_$2");
|
||||||
sigNew = regexpRewriteSignature(sigNew, "(.*)_ge_yby_then_(.*)", "yby_lt_$1_then_$2");
|
sigNew = regexpRewriteSignature(sigNew, "(.*)_ge_yby_then_(.*)", "yby_lt_$1_then_$2");
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
lda {zpby1}
|
||||||
|
clc
|
||||||
|
adc #{coby1}
|
@ -8,7 +8,6 @@ import dk.camelot64.kickc.icl.ProgramScope;
|
|||||||
/** Base class for a compiler pass */
|
/** Base class for a compiler pass */
|
||||||
public class Pass2Base {
|
public class Pass2Base {
|
||||||
|
|
||||||
|
|
||||||
private Program program;
|
private Program program;
|
||||||
|
|
||||||
public Pass2Base(Program program) {
|
public Pass2Base(Program program) {
|
||||||
|
@ -5,9 +5,7 @@ import dk.camelot64.kickc.asm.AsmProgram;
|
|||||||
import dk.camelot64.kickc.asm.AsmSegment;
|
import dk.camelot64.kickc.asm.AsmSegment;
|
||||||
import dk.camelot64.kickc.icl.*;
|
import dk.camelot64.kickc.icl.*;
|
||||||
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/*** Attempt to uplift live range equivalence classes to registers (instead of ZP) in each scope */
|
/*** Attempt to uplift live range equivalence classes to registers (instead of ZP) in each scope */
|
||||||
public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
||||||
@ -115,7 +113,7 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
|||||||
// Apply the uplift combination
|
// Apply the uplift combination
|
||||||
combination.allocate(program.getScope());
|
combination.allocate(program.getScope());
|
||||||
// Check the register allocation for whether a is register being allocated to two variables with overlapping live ranges
|
// Check the register allocation for whether a is register being allocated to two variables with overlapping live ranges
|
||||||
if(isAllocationOverlapping(program)) {
|
if (isAllocationOverlapping(program)) {
|
||||||
if (program.getLog().isVerboseUplift()) {
|
if (program.getLog().isVerboseUplift()) {
|
||||||
StringBuilder msg = new StringBuilder();
|
StringBuilder msg = new StringBuilder();
|
||||||
msg.append("Uplift attempt [" + (scope == null ? "" : scope) + "] ");
|
msg.append("Uplift attempt [" + (scope == null ? "" : scope) + "] ");
|
||||||
@ -197,27 +195,64 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
|||||||
* @param program The program
|
* @param program The program
|
||||||
* @return true if the register allocation contains an overlapping allocation. false otherwise.
|
* @return true if the register allocation contains an overlapping allocation. false otherwise.
|
||||||
*/
|
*/
|
||||||
private static boolean isAllocationOverlapping(Program program) {
|
public static boolean isAllocationOverlapping(Program program) {
|
||||||
LiveRangeVariables liveRangeVariables = program.getLiveRangeVariables();
|
|
||||||
ProgramScope programScope = program.getScope();
|
|
||||||
for (ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
for (ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||||
for (Statement statement : block.getStatements()) {
|
for (Statement statement : block.getStatements()) {
|
||||||
List<VariableRef> alive = liveRangeVariables.getAlive(statement);
|
LinkedHashMap<Registers.Register, LiveRangeEquivalenceClass> usedRegisters = new LinkedHashMap<>();
|
||||||
LinkedHashSet<Registers.Register> usedRegisters = new LinkedHashSet<>();
|
if (isStatementAllocationOverlapping(program, statement, usedRegisters)) {
|
||||||
for (VariableRef varRef : alive) {
|
return true;
|
||||||
Variable var = programScope.getVariable(varRef);
|
}
|
||||||
Registers.Register allocation = var.getAllocation();
|
}
|
||||||
if(usedRegisters.contains(allocation)) {
|
}
|
||||||
if (program.getLog().isVerboseUplift()) {
|
return false;
|
||||||
StringBuilder msg = new StringBuilder();
|
}
|
||||||
msg.append("Overlap register "+allocation+" in "+statement.toString(program));
|
|
||||||
program.getLog().append(msg.toString());
|
/**
|
||||||
}
|
* Determine if a statement has an overlapping register allocation
|
||||||
return true;
|
*
|
||||||
}
|
* @param program The program
|
||||||
usedRegisters.add(allocation);
|
* @param statement The statement to check
|
||||||
|
* @param usedRegisters The used registers. Will be extended with all registers used in the statement.
|
||||||
|
* @return true if there is an overlapping register allocation
|
||||||
|
*/
|
||||||
|
private static boolean isStatementAllocationOverlapping(
|
||||||
|
Program program,
|
||||||
|
Statement statement,
|
||||||
|
LinkedHashMap<Registers.Register, LiveRangeEquivalenceClass> usedRegisters) {
|
||||||
|
LiveRangeVariables liveRangeVariables = program.getLiveRangeVariables();
|
||||||
|
ProgramScope programScope = program.getScope();
|
||||||
|
List<VariableRef> alive = liveRangeVariables.getAlive(statement);
|
||||||
|
for (VariableRef varRef : alive) {
|
||||||
|
Variable var = programScope.getVariable(varRef);
|
||||||
|
Registers.Register allocation = var.getAllocation();
|
||||||
|
LiveRangeEquivalenceClass allocationClass = usedRegisters.get(allocation);
|
||||||
|
if (allocationClass != null && !allocationClass.contains(varRef)) {
|
||||||
|
if (program.getLog().isVerboseUplift()) {
|
||||||
|
StringBuilder msg = new StringBuilder();
|
||||||
|
msg.append("Overlap register " + allocation + " in " + statement.toString(program));
|
||||||
|
program.getLog().append(msg.toString());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
LiveRangeEquivalenceClass varClass =
|
||||||
|
program.getLiveRangeEquivalenceClassSet().getEquivalenceClass(varRef);
|
||||||
|
usedRegisters.put(allocation, varClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the statement is inside a method -also check against all variables alive at the exit of the calls.
|
||||||
|
ControlFlowBlock block = program.getGraph().getBlockFromStatementIdx(statement.getIndex());
|
||||||
|
ScopeRef scopeRef = block.getScope();
|
||||||
|
Scope scope = program.getScope().getScope(scopeRef);
|
||||||
|
if (scope instanceof Procedure) {
|
||||||
|
Procedure procedure = (Procedure) scope;
|
||||||
|
Collection<CallGraph.CallBlock.Call> callers =
|
||||||
|
program.getCallGraph().getCallers(procedure.getLabel().getRef());
|
||||||
|
for (CallGraph.CallBlock.Call caller : callers) {
|
||||||
|
StatementCall callStatement =
|
||||||
|
(StatementCall) program.getGraph().getStatementByIndex(caller.getCallStatementIdx());
|
||||||
|
if (isStatementAllocationOverlapping(program, callStatement, usedRegisters)) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
// TODO: If the statement is inside a method -also check against all variables alive at the calls.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -36,6 +36,8 @@ public class Pass4ZeroPageCoalesce extends Pass2Base {
|
|||||||
getLog().append("Coalescing zero page register [ "+myEquivalenceClass+" ] with [ "+otherEquivalenceClass+" ]" );
|
getLog().append("Coalescing zero page register [ "+myEquivalenceClass+" ] with [ "+otherEquivalenceClass+" ]" );
|
||||||
myEquivalenceClass.addAll(otherEquivalenceClass);
|
myEquivalenceClass.addAll(otherEquivalenceClass);
|
||||||
liveRangeEquivalenceClassSet.remove(otherEquivalenceClass);
|
liveRangeEquivalenceClassSet.remove(otherEquivalenceClass);
|
||||||
|
// Reset the program register allocation
|
||||||
|
getProgram().getLiveRangeEquivalenceClassSet().storeRegisterAllocation();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,7 +55,15 @@ public class Pass4ZeroPageCoalesce extends Pass2Base {
|
|||||||
// Types match
|
// Types match
|
||||||
if (myEquivalenceClass.getRegister().isZp() && otherEquivalenceClass.getRegister().isZp()) {
|
if (myEquivalenceClass.getRegister().isZp() && otherEquivalenceClass.getRegister().isZp()) {
|
||||||
// Both registers are on Zero Page
|
// Both registers are on Zero Page
|
||||||
if (!myEquivalenceClass.getLiveRange().overlaps(otherEquivalenceClass.getLiveRange())) {
|
|
||||||
|
// Reset the program register allocation to the one specified in the equivalence class set
|
||||||
|
getProgram().getLiveRangeEquivalenceClassSet().storeRegisterAllocation();
|
||||||
|
// Try out the coalesce to test if it works
|
||||||
|
for (VariableRef var : otherEquivalenceClass.getVariables()) {
|
||||||
|
Variable variable = getProgram().getScope().getVariable(var);
|
||||||
|
variable.setAllocation(myEquivalenceClass.getRegister());
|
||||||
|
}
|
||||||
|
if(!Pass4RegisterUpliftCombinations.isAllocationOverlapping(getProgram())) {
|
||||||
// Live ranges do not overlap
|
// Live ranges do not overlap
|
||||||
// Perform coalesce!
|
// Perform coalesce!
|
||||||
return true;
|
return true;
|
||||||
|
Loading…
Reference in New Issue
Block a user