1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-08-02 09:29:35 +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:
Jesper Gravgaard 2017-09-04 22:15:18 +02:00
parent eb6cf1188c
commit 99088aef58
7 changed files with 105 additions and 33 deletions

View File

@ -135,8 +135,8 @@ public class Compiler {
public void pass2OptimizeSSA(Program program) {
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
optimizations.add(new Pass2CullEmptyBlocks(program));
//optimizations.add(new Pass2ConstantPropagation(program));
//optimizations.add(new Pass2ConstantAdditionElimination(program));
optimizations.add(new Pass2ConstantPropagation(program));
optimizations.add(new Pass2ConstantAdditionElimination(program));
optimizations.add(new Pass2UnaryNotSimplification(program));
optimizations.add(new Pass2AliasElimination(program));
optimizations.add(new Pass2RedundantPhiElimination(program));
@ -177,7 +177,7 @@ public class Compiler {
program.getLog().append("CALL GRAPH");
program.getLog().append(program.getCallGraph().toString());
program.getLog().setVerboseLiveRanges(true);
//program.getLog().setVerboseLiveRanges(true);
new Pass3LiveRangesAnalysis(program).findLiveRanges();
program.getLog().append("CONTROL FLOW GRAPH - LIVE RANGES FOUND");
@ -242,7 +242,7 @@ public class Compiler {
program.getLog().append(program.getRegisterUpliftProgram().toString((program.getVariableRegisterWeights())));
// Attempt uplifting registers through a lot of combinations
program.getLog().setVerboseUplift(true);
//program.getLog().setVerboseUplift(true);
new Pass4RegisterUpliftCombinations(program).performUplift(10_000);
//new Pass4RegisterUpliftStatic(program).performUplift();

View File

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

View File

@ -76,15 +76,27 @@ public class AsmFragmentManager {
}
}
if(signature.startsWith("zpby1=")) {
if(signature.contains("{zpby2}")) {
String subSignature = "aby="+signature.substring(6).replace("zpby2", "zpby1");
CharStream subCharStream = loadOrSynthesizeFragment(subSignature);
if(subCharStream!=null) {
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;
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_xby_then_(.*)", "xby_lt_$1_then_$2");
sigNew = regexpRewriteSignature(sigNew, "(.*)_ge_yby_then_(.*)", "yby_lt_$1_then_$2");

View File

@ -0,0 +1,3 @@
lda {zpby1}
clc
adc #{coby1}

View File

@ -8,7 +8,6 @@ import dk.camelot64.kickc.icl.ProgramScope;
/** Base class for a compiler pass */
public class Pass2Base {
private Program program;
public Pass2Base(Program program) {

View File

@ -5,9 +5,7 @@ import dk.camelot64.kickc.asm.AsmProgram;
import dk.camelot64.kickc.asm.AsmSegment;
import dk.camelot64.kickc.icl.*;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
/*** Attempt to uplift live range equivalence classes to registers (instead of ZP) in each scope */
public class Pass4RegisterUpliftCombinations extends Pass2Base {
@ -115,7 +113,7 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
// Apply the uplift combination
combination.allocate(program.getScope());
// 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()) {
StringBuilder msg = new StringBuilder();
msg.append("Uplift attempt [" + (scope == null ? "" : scope) + "] ");
@ -197,27 +195,64 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
* @param program The program
* @return true if the register allocation contains an overlapping allocation. false otherwise.
*/
private static boolean isAllocationOverlapping(Program program) {
LiveRangeVariables liveRangeVariables = program.getLiveRangeVariables();
ProgramScope programScope = program.getScope();
public static boolean isAllocationOverlapping(Program program) {
for (ControlFlowBlock block : program.getGraph().getAllBlocks()) {
for (Statement statement : block.getStatements()) {
LinkedHashMap<Registers.Register, LiveRangeEquivalenceClass> usedRegisters = new LinkedHashMap<>();
if (isStatementAllocationOverlapping(program, statement, usedRegisters)) {
return true;
}
}
}
return false;
}
/**
* Determine if a statement has an overlapping register allocation
*
* @param program The program
* @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);
LinkedHashSet<Registers.Register> usedRegisters = new LinkedHashSet<>();
for (VariableRef varRef : alive) {
Variable var = programScope.getVariable(varRef);
Registers.Register allocation = var.getAllocation();
if(usedRegisters.contains(allocation)) {
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));
msg.append("Overlap register " + allocation + " in " + statement.toString(program));
program.getLog().append(msg.toString());
}
return true;
}
usedRegisters.add(allocation);
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;

View File

@ -36,6 +36,8 @@ public class Pass4ZeroPageCoalesce extends Pass2Base {
getLog().append("Coalescing zero page register [ "+myEquivalenceClass+" ] with [ "+otherEquivalenceClass+" ]" );
myEquivalenceClass.addAll(otherEquivalenceClass);
liveRangeEquivalenceClassSet.remove(otherEquivalenceClass);
// Reset the program register allocation
getProgram().getLiveRangeEquivalenceClassSet().storeRegisterAllocation();
return true;
}
}
@ -53,7 +55,15 @@ public class Pass4ZeroPageCoalesce extends Pass2Base {
// Types match
if (myEquivalenceClass.getRegister().isZp() && otherEquivalenceClass.getRegister().isZp()) {
// 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
// Perform coalesce!
return true;