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) {
|
||||
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();
|
||||
|
@ -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:
|
||||
|
@ -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");
|
||||
|
@ -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 */
|
||||
public class Pass2Base {
|
||||
|
||||
|
||||
private 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.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 {
|
||||
@ -197,17 +195,38 @@ 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));
|
||||
@ -215,9 +234,25 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
||||
}
|
||||
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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user