1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-17 01:55:22 +00:00

Implemented coalescing for main memory PHI registers.

This commit is contained in:
jespergravgaard 2019-10-19 23:08:30 +02:00
parent 40ade8e60e
commit fcc48de855
11 changed files with 127 additions and 61 deletions

View File

@ -589,14 +589,14 @@ public class Compiler {
} }
// Register coalesce on assignment (saving bytes & cycles) // Register coalesce on assignment (saving bytes & cycles)
new Pass4ZeroPageCoalesceAssignment(program).coalesce(); new Pass4MemoryCoalesceAssignment(program).coalesce();
// Register coalesce on call graph (saving ZP) // Register coalesce on call graph (saving ZP)
new Pass4ZeroPageCoalesceCallGraph(program).coalesce(); new Pass4MemoryCoalesceCallGraph(program).coalesce();
if(enableZeroPageCoalasce) { if(enableZeroPageCoalasce) {
// Register coalesce using exhaustive search (saving even more ZP - but slow) // Register coalesce using exhaustive search (saving even more ZP - but slow)
new Pass4ZeroPageCoalesceExhaustive(program).coalesce(); new Pass4MemoryCoalesceExhaustive(program).coalesce();
} }
new Pass4RegistersFinalize(program).allocate(true); new Pass4RegistersFinalize(program).allocate(true);
new Pass4AssertZeropageAllocation(program).check(); new Pass4AssertZeropageAllocation(program).check();

View File

@ -134,8 +134,10 @@ public class DirectiveParserContext {
this.registerImpliesDirectives = new ArrayList<>(); this.registerImpliesDirectives = new ArrayList<>();
this.typeDirectives = new HashMap<>(); this.typeDirectives = new HashMap<>();
this.typeDirectives.put(DirectiveType.ARRAY, Arrays.asList(new Directive.Const(), new Directive.MemoryArea(SymbolVariable.MemoryArea.MAIN_MEMORY, null), new Directive.Register(false, null))); this.typeDirectives.put(DirectiveType.ARRAY, Arrays.asList(new Directive.Const(), new Directive.MemoryArea(SymbolVariable.MemoryArea.MAIN_MEMORY, null), new Directive.Register(false, null)));
//this.typeDirectives.put(DirectiveType.POINTER, Arrays.asList(new Directive.MemoryArea(SymbolVariable.MemoryArea.ZEROPAGE_MEMORY, null)));
this.scopeDirectives = new HashMap<>(); this.scopeDirectives = new HashMap<>();
this.scopeTypeDirectives = new HashMap<>(); this.scopeTypeDirectives = new HashMap<>();
//this.scopeDirectives.put(DirectiveScope.GLOBAL, Arrays.asList(new Directive.MemoryArea(SymbolVariable.MemoryArea.MAIN_MEMORY, null)));
} }
/** /**

View File

@ -25,6 +25,8 @@ public class ZeroConstantValues {
zeroValues.put(memberVar.getRef(), zeroValue(memberVar.getType(), programScope)); zeroValues.put(memberVar.getRef(), zeroValue(memberVar.getType(), programScope));
} }
return new ConstantStructValue(typeStruct, zeroValues); return new ConstantStructValue(typeStruct, zeroValues);
} else if(type.equals(SymbolType.BOOLEAN)) {
return new ConstantBool(false);
} else if(type instanceof SymbolTypeIntegerFixed) { } else if(type instanceof SymbolTypeIntegerFixed) {
return new ConstantInteger(0L, type); return new ConstantInteger(0L, type);
} else if(type instanceof SymbolTypePointer) { } else if(type instanceof SymbolTypePointer) {

View File

@ -6,6 +6,7 @@ import dk.camelot64.kickc.model.LiveRangeEquivalenceClassSet;
import dk.camelot64.kickc.model.Program; import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.statements.StatementAssignment; import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.statements.StatementPhiBlock; import dk.camelot64.kickc.model.statements.StatementPhiBlock;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.ConstantValue; import dk.camelot64.kickc.model.values.ConstantValue;
import dk.camelot64.kickc.model.values.VariableRef; import dk.camelot64.kickc.model.values.VariableRef;
@ -72,10 +73,16 @@ public class Pass3PhiMemCoalesce extends Pass2SsaOptimization {
VariableRef phiRVar = (VariableRef) phiRValue.getrValue(); VariableRef phiRVar = (VariableRef) phiRValue.getrValue();
LiveRangeEquivalenceClass rValEquivalenceClass = phiEquivalenceClasses.getOrCreateEquivalenceClass(phiRVar); LiveRangeEquivalenceClass rValEquivalenceClass = phiEquivalenceClasses.getOrCreateEquivalenceClass(phiRVar);
if(!rValEquivalenceClass.equals(equivalenceClass)) { if(!rValEquivalenceClass.equals(equivalenceClass)) {
SymbolType varType = program.getScope().getVariable(variable).getType(); Variable var = program.getScope().getVariable(variable);
SymbolType rVarType = program.getScope().getVariable(phiRVar).getType(); Variable rVar = program.getScope().getVariable(phiRVar);
SymbolType varType = var.getType();
SymbolType rVarType = rVar.getType();
if(varType.getSizeBytes()==rVarType.getSizeBytes()) { if(varType.getSizeBytes()==rVarType.getSizeBytes()) {
phiEquivalenceClasses.consolidate(equivalenceClass, rValEquivalenceClass); if(var.getMemoryArea().equals(rVar.getMemoryArea())) {
phiEquivalenceClasses.consolidate(equivalenceClass, rValEquivalenceClass);
} else {
program.getLog().append("Not consolidating phi with different storage strategy "+variable.toString()+" "+phiRVar.toString());
}
} else { } else {
program.getLog().append("Not consolidating phi with different size "+variable.toString()+" "+phiRVar.toString()); program.getLog().append("Not consolidating phi with different size "+variable.toString()+" "+phiRVar.toString());
} }

View File

@ -465,27 +465,46 @@ public class Pass4CodeGeneration {
// Add all memory variables // Add all memory variables
Collection<Variable> scopeVariables = scope.getAllVariables(false); Collection<Variable> scopeVariables = scope.getAllVariables(false);
for(Variable variable : scopeVariables) { for(Variable variable : scopeVariables) {
if(variable.isStorageLoadStore() && variable.isMemoryAreaMain()) { if(variable.isMemoryAreaMain()) {
// Skip PHI masters
if(variable.isStoragePhiMaster())
continue;
// Skip if already added // Skip if already added
String asmName = variable.getAsmName() == null ? variable.getLocalName() : variable.getAsmName(); String asmName = variable.getAsmName() == null ? variable.getLocalName() : variable.getAsmName();
if(added.contains(asmName)) { if(added.contains(asmName)) {
continue; continue;
} }
if(variable.getDeclaredMemoryAddress() == null) { if(variable.isStorageLoadStore() || variable.isStoragePhiVersion() || variable.isStorageIntermediate()){
// Generate into the data segment if(variable.getDeclaredMemoryAddress() == null) {
// Set segment
setCurrentSegment(variable.getDataSegment(), asm); Registers.Register allocation = variable.getAllocation();
// Add any comments if(!(allocation instanceof Registers.RegisterMainMem)) {
generateComments(asm, variable.getComments()); throw new InternalError("Expected main memory allocation "+variable.toString(program));
// Add any alignment }
Integer declaredAlignment = variable.getDeclaredAlignment(); Registers.RegisterMainMem registerMainMem = (Registers.RegisterMainMem) allocation;
if(declaredAlignment != null) { if(!((Registers.RegisterMainMem) allocation).getVariableRef().equals(variable.getRef())) {
String alignment = AsmFormat.getAsmNumber(declaredAlignment); continue;
asm.addDataAlignment(alignment); }
// Generate into the data segment
// Set segment
setCurrentSegment(variable.getDataSegment(), asm);
// Add any comments
generateComments(asm, variable.getComments());
// Add any alignment
Integer declaredAlignment = variable.getDeclaredAlignment();
if(declaredAlignment != null) {
String alignment = AsmFormat.getAsmNumber(declaredAlignment);
asm.addDataAlignment(alignment);
}
AsmDataChunk asmDataChunk = new AsmDataChunk();
addChunkData(asmDataChunk, ZeroConstantValues.zeroValue(variable.getType(), getScope()), variable.getType(), scopeRef);
asmDataChunk.addToAsm(AsmFormat.asmFix(asmName), asm);
} }
AsmDataChunk asmDataChunk = new AsmDataChunk(); } else {
addChunkData(asmDataChunk, ZeroConstantValues.zeroValue(variable.getType(), getScope()), variable.getType(), scopeRef); throw new InternalError("Not handled variable storage "+variable.toString());
asmDataChunk.addToAsm(AsmFormat.asmFix(asmName), asm);
} }
added.add(asmName); added.add(asmName);
} }
@ -632,6 +651,8 @@ public class Pass4CodeGeneration {
dataChunk.addDataNumeric(AsmDataNumeric.Type.DWORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef), getEncoding(value)); dataChunk.addDataNumeric(AsmDataNumeric.Type.DWORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef), getEncoding(value));
} else if(valueType instanceof SymbolTypePointer) { } else if(valueType instanceof SymbolTypePointer) {
dataChunk.addDataNumeric(AsmDataNumeric.Type.WORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef), getEncoding(value)); dataChunk.addDataNumeric(AsmDataNumeric.Type.WORD, AsmFormat.getAsmConstant(program, value, 99, scopeRef), getEncoding(value));
} else if(SymbolType.BOOLEAN.equals(valueType)) {
dataChunk.addDataNumeric(AsmDataNumeric.Type.BYTE, AsmFormat.getAsmConstant(program, value, 99, scopeRef), getEncoding(value));
} else { } else {
throw new InternalError("Unhandled array element type " + valueType.toString() + " value " + value.toString(program)); throw new InternalError("Unhandled array element type " + valueType.toString() + " value " + value.toString(program));
} }
@ -688,6 +709,20 @@ public class Pass4CodeGeneration {
asm.addLabelDecl(AsmFormat.asmFix(asmName), AsmFormat.getAsmNumber(scopeVar.getDeclaredMemoryAddress())); asm.addLabelDecl(AsmFormat.asmFix(asmName), AsmFormat.getAsmNumber(scopeVar.getDeclaredMemoryAddress()));
added.add(asmName); added.add(asmName);
} }
} else if(register instanceof Registers.RegisterMainMem && !((Registers.RegisterMainMem) register).getVariableRef().equals(scopeVar.getRef())) {
// Memory variable is not main var in the equivalence class - add a reference
String asmName = scopeVar.getAsmName();
Registers.RegisterMainMem memAllocation = (Registers.RegisterMainMem) register;
VariableRef memAllocationVarRef = memAllocation.getVariableRef();
Variable memAllocationVar = getScope().getVariable(memAllocationVarRef);
// Add the label declaration
String asmNameMemAllocVar = AsmFormat.getAsmParamName(memAllocationVar, scope);
if(!asmName.equals(asmNameMemAllocVar)) {
// Add any comments
generateComments(asm, scopeVar.getComments());
asm.addLabelDecl(AsmFormat.asmFix(asmName), asmNameMemAllocVar);
added.add(asmName);
}
} }
} }
} }

View File

@ -14,12 +14,12 @@ import java.util.List;
import java.util.Set; import java.util.Set;
/** /**
* Coalesces zero page registers where their live ranges do not overlap. * Coalesces memory registers where their live ranges do not overlap.
* A final step done after all other register optimizations and before ASM generation. * A final step done after all other register optimizations and before ASM generation.
*/ */
public abstract class Pass4ZeroPageCoalesce extends Pass2Base { public abstract class Pass4MemoryCoalesce extends Pass2Base {
public Pass4ZeroPageCoalesce(Program program) { public Pass4MemoryCoalesce(Program program) {
super(program); super(program);
} }
@ -57,6 +57,7 @@ public abstract class Pass4ZeroPageCoalesce extends Pass2Base {
static boolean canCoalesce(LiveRangeEquivalenceClass ec1, LiveRangeEquivalenceClass ec2, Collection<ScopeRef> threadHeads, Set<String> unknownFragments, Program program) { static boolean canCoalesce(LiveRangeEquivalenceClass ec1, LiveRangeEquivalenceClass ec2, Collection<ScopeRef> threadHeads, Set<String> unknownFragments, Program program) {
return return
canCoalesceNotEqual(ec1, ec2) && canCoalesceNotEqual(ec1, ec2) &&
canCoalesceCompatible(ec1, ec2, program) &&
canCoalesceVolatile(ec1, ec2, program) && canCoalesceVolatile(ec1, ec2, program) &&
canCoalesceThreads(ec1, ec2, threadHeads, program) && canCoalesceThreads(ec1, ec2, threadHeads, program) &&
canCoalesceClobber(ec1, ec2, unknownFragments, program); canCoalesceClobber(ec1, ec2, unknownFragments, program);
@ -129,6 +130,30 @@ public abstract class Pass4ZeroPageCoalesce extends Pass2Base {
return threads; return threads;
} }
/**
* Determines if two live range equivalence classes have compatible registers.
* The registers are compatible if they are in memory and have the same type and size.
*
* @param ec1 One equivalence class
* @param ec2 Another equivalence class
* @param program The program
* @return True if the two equivalence classes can be coalesced into one without problems.
*/
private static boolean canCoalesceCompatible(LiveRangeEquivalenceClass ec1, LiveRangeEquivalenceClass ec2, Program program) {
Registers.Register register1 = ec1.getRegister();
Registers.Register register2 = ec2.getRegister();
// Check the both registers are in memory
if(!register1.isMem() || !register2.isMem())
return false;
// Check the both registers have the same type
if(!register1.getType().equals(register2.getType()))
return false;
// Check the both registers have the same size
if(register1.getBytes() != register2.getBytes())
return false;
return true;
}
/** /**
* Determines if two live range equivalence classes can be coalesced without clobber. * Determines if two live range equivalence classes can be coalesced without clobber.
* This is possible if they are both allocated to zero page, have the same size and the resulting ASM has no live range overlaps or clobber issues. * This is possible if they are both allocated to zero page, have the same size and the resulting ASM has no live range overlaps or clobber issues.
@ -141,15 +166,10 @@ public abstract class Pass4ZeroPageCoalesce extends Pass2Base {
*/ */
private static boolean canCoalesceClobber(LiveRangeEquivalenceClass ec1, LiveRangeEquivalenceClass ec2, Set<String> unknownFragments, Program program) { private static boolean canCoalesceClobber(LiveRangeEquivalenceClass ec1, LiveRangeEquivalenceClass ec2, Set<String> unknownFragments, Program program) {
Registers.Register register1 = ec1.getRegister(); Registers.Register register1 = ec1.getRegister();
Registers.Register register2 = ec2.getRegister(); // Try out the coalesce to test if it works
if(register1.isZp() && register2.isZp() && register1.getBytes()==register2.getBytes()) { RegisterCombination combination = new RegisterCombination();
// Both registers are on Zero Page & have the same zero page size combination.setRegister(ec2, register1);
// Try out the coalesce to test if it works return Pass4RegisterUpliftCombinations.generateCombinationAsm(combination, program, unknownFragments, ScopeRef.ROOT);
RegisterCombination combination = new RegisterCombination();
combination.setRegister(ec2, register1);
return Pass4RegisterUpliftCombinations.generateCombinationAsm(combination, program, unknownFragments, ScopeRef.ROOT);
}
return false;
} }
/** /**
@ -192,7 +212,7 @@ public abstract class Pass4ZeroPageCoalesce extends Pass2Base {
List<LiveRangeEquivalenceClass> equivalenceClasses = liveRangeEquivalenceClassSet.getEquivalenceClasses(); List<LiveRangeEquivalenceClass> equivalenceClasses = liveRangeEquivalenceClassSet.getEquivalenceClasses();
if(equivalenceClasses.contains(candidate.getEc1()) && equivalenceClasses.contains(candidate.getEc2())) { if(equivalenceClasses.contains(candidate.getEc1()) && equivalenceClasses.contains(candidate.getEc2())) {
// Both equivalence classes still exist // Both equivalence classes still exist
if(Pass4ZeroPageCoalesce.canCoalesce(candidate.getEc1(), candidate.getEc2(), threadHeads, unknownFragments, program)) { if(Pass4MemoryCoalesce.canCoalesce(candidate.getEc1(), candidate.getEc2(), threadHeads, unknownFragments, program)) {
String scoreString = (candidate.getScore() == null) ? "" : (" - score: " + candidate.getScore()); String scoreString = (candidate.getScore() == null) ? "" : (" - score: " + candidate.getScore());
program.getLog().append("Coalescing zero page register [ " + candidate.getEc1() + " ] with [ " + candidate.getEc2() + " ]" + scoreString); program.getLog().append("Coalescing zero page register [ " + candidate.getEc1() + " ] with [ " + candidate.getEc2() + " ]" + scoreString);
liveRangeEquivalenceClassSet.consolidate(candidate.getEc1(), candidate.getEc2()); liveRangeEquivalenceClassSet.consolidate(candidate.getEc1(), candidate.getEc2());

View File

@ -8,29 +8,29 @@ import dk.camelot64.kickc.model.statements.Statement;
import java.util.*; import java.util.*;
/** /**
* Coalesces zero page registers where their live ranges do not overlap. * Coalesces memory registers where their live ranges do not overlap.
* This step tries to coalesce lvalues with rvalues for all assignments - saving both cycles & bytes if successful. * This step tries to coalesce lvalues with rvalues for all assignments - saving both cycles & bytes if successful.
*/ */
public class Pass4ZeroPageCoalesceAssignment extends Pass2Base { public class Pass4MemoryCoalesceAssignment extends Pass2Base {
public Pass4ZeroPageCoalesceAssignment(Program program) { public Pass4MemoryCoalesceAssignment(Program program) {
super(program); super(program);
} }
public void coalesce() { public void coalesce() {
CoalesceVarScores coalesceVarScores = new CoalesceVarScores(getProgram()); CoalesceVarScores coalesceVarScores = new CoalesceVarScores(getProgram());
LinkedHashSet<String> unknownFragments = new LinkedHashSet<>(); LinkedHashSet<String> unknownFragments = new LinkedHashSet<>();
Collection<ScopeRef> threadHeads = Pass4ZeroPageCoalesce.getThreadHeads(getProgram()); Collection<ScopeRef> threadHeads = Pass4MemoryCoalesce.getThreadHeads(getProgram());
boolean change; boolean change;
do { do {
change = false; change = false;
CoalesceLiveRangeEquivalenceClassScores equivalenceClassScores = CoalesceLiveRangeEquivalenceClassScores equivalenceClassScores =
new CoalesceLiveRangeEquivalenceClassScores(getProgram(), coalesceVarScores); new CoalesceLiveRangeEquivalenceClassScores(getProgram(), coalesceVarScores);
List<Pass4ZeroPageCoalesce.LiveRangeEquivalenceClassCoalesceCandidate> coalesceCandidates = List<Pass4MemoryCoalesce.LiveRangeEquivalenceClassCoalesceCandidate> coalesceCandidates =
equivalenceClassScores.getCoalesceCandidates(); equivalenceClassScores.getCoalesceCandidates();
for(Pass4ZeroPageCoalesce.LiveRangeEquivalenceClassCoalesceCandidate candidate : coalesceCandidates) { for(Pass4MemoryCoalesce.LiveRangeEquivalenceClassCoalesceCandidate candidate : coalesceCandidates) {
change |= Pass4ZeroPageCoalesce.attemptCoalesce(candidate, threadHeads, unknownFragments, getProgram()); change |= Pass4MemoryCoalesce.attemptCoalesce(candidate, threadHeads, unknownFragments, getProgram());
} }
} while(change); } while(change);
@ -147,14 +147,14 @@ public class Pass4ZeroPageCoalesceAssignment extends Pass2Base {
* *
* @return candidate pairs of live range equivalence classes for coalescing with a positive score * @return candidate pairs of live range equivalence classes for coalescing with a positive score
*/ */
public List<Pass4ZeroPageCoalesce.LiveRangeEquivalenceClassCoalesceCandidate> getCoalesceCandidates() { public List<Pass4MemoryCoalesce.LiveRangeEquivalenceClassCoalesceCandidate> getCoalesceCandidates() {
ArrayList<Pass4ZeroPageCoalesce.LiveRangeEquivalenceClassCoalesceCandidate> candidates = new ArrayList<>(); ArrayList<Pass4MemoryCoalesce.LiveRangeEquivalenceClassCoalesceCandidate> candidates = new ArrayList<>();
for(LiveRangeEquivalenceClass ec1 : scores.keySet()) { for(LiveRangeEquivalenceClass ec1 : scores.keySet()) {
Map<LiveRangeEquivalenceClass, Integer> ec1Scores = scores.get(ec1); Map<LiveRangeEquivalenceClass, Integer> ec1Scores = scores.get(ec1);
for(LiveRangeEquivalenceClass ec2 : ec1Scores.keySet()) { for(LiveRangeEquivalenceClass ec2 : ec1Scores.keySet()) {
Integer score = ec1Scores.get(ec2); Integer score = ec1Scores.get(ec2);
Pass4ZeroPageCoalesce.LiveRangeEquivalenceClassCoalesceCandidate candidate = Pass4MemoryCoalesce.LiveRangeEquivalenceClassCoalesceCandidate candidate =
new Pass4ZeroPageCoalesce.LiveRangeEquivalenceClassCoalesceCandidate(ec1, ec2, score); new Pass4MemoryCoalesce.LiveRangeEquivalenceClassCoalesceCandidate(ec1, ec2, score);
if(!candidates.contains(candidate)) { if(!candidates.contains(candidate)) {
candidates.add(candidate); candidates.add(candidate);
} }

View File

@ -10,22 +10,22 @@ import dk.camelot64.kickc.model.values.VariableRef;
import java.util.*; import java.util.*;
/** /**
* Use the call graph to coalesce zero page registers. * Use the call graph to coalesce memory registers.
* For each live range equivalence class: * For each live range equivalence class:
* - Look up through the call graph and avoid all variables declared in the scopes there * - Look up through the call graph and avoid all variables declared in the scopes there
* - Go through already handled live range equivalence classes and if any exist with no scope overlap with the call graph - try to coalesce * - Go through already handled live range equivalence classes and if any exist with no scope overlap with the call graph - try to coalesce
* - Add to the list of already handled live range equivalence classes * - Add to the list of already handled live range equivalence classes
*/ */
public class Pass4ZeroPageCoalesceCallGraph extends Pass2Base { public class Pass4MemoryCoalesceCallGraph extends Pass2Base {
public Pass4ZeroPageCoalesceCallGraph(Program program) { public Pass4MemoryCoalesceCallGraph(Program program) {
super(program); super(program);
} }
public void coalesce() { public void coalesce() {
LinkedHashSet<String> unknownFragments = new LinkedHashSet<>(); LinkedHashSet<String> unknownFragments = new LinkedHashSet<>();
LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet = getProgram().getLiveRangeEquivalenceClassSet(); LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet = getProgram().getLiveRangeEquivalenceClassSet();
Collection<ScopeRef> threads = Pass4ZeroPageCoalesce.getThreadHeads(getProgram()); Collection<ScopeRef> threads = Pass4MemoryCoalesce.getThreadHeads(getProgram());
boolean modified; boolean modified;
do { do {
modified = coalesce(liveRangeEquivalenceClassSet, threads, unknownFragments); modified = coalesce(liveRangeEquivalenceClassSet, threads, unknownFragments);
@ -66,8 +66,8 @@ public class Pass4ZeroPageCoalesceCallGraph extends Pass2Base {
if(isScopeOverlap(otherEC, allCallingScopes)) if(isScopeOverlap(otherEC, allCallingScopes))
continue; continue;
// No scope overlap - attempt to coalesce // No scope overlap - attempt to coalesce
Pass4ZeroPageCoalesce.LiveRangeEquivalenceClassCoalesceCandidate candidate = new Pass4ZeroPageCoalesce.LiveRangeEquivalenceClassCoalesceCandidate(thisEC, otherEC, null); Pass4MemoryCoalesce.LiveRangeEquivalenceClassCoalesceCandidate candidate = new Pass4MemoryCoalesce.LiveRangeEquivalenceClassCoalesceCandidate(thisEC, otherEC, null);
if(Pass4ZeroPageCoalesce.attemptCoalesce(candidate, threadHeads, unknownFragments, getProgram())) { if(Pass4MemoryCoalesce.attemptCoalesce(candidate, threadHeads, unknownFragments, getProgram())) {
// Succesfully coalesced with already handled EC - move on to the next one! // Succesfully coalesced with already handled EC - move on to the next one!
coalesced = true; coalesced = true;
modified = true; modified = true;

View File

@ -10,20 +10,20 @@ import java.util.LinkedHashSet;
import java.util.Set; import java.util.Set;
/** /**
* Exhaustive attempt to coalesces zero page registers where live ranges do not overlap. * Exhaustive attempt to coalesces memory registers where live ranges do not overlap.
* An optional final step done after all other register optimizations and before ASM generation. * An optional final step done after all other register optimizations and before ASM generation.
* Performs an exhaustive search - so it can take a lot of time! * Performs an exhaustive search - so it can take a lot of time!
*/ */
public class Pass4ZeroPageCoalesceExhaustive extends Pass2Base { public class Pass4MemoryCoalesceExhaustive extends Pass2Base {
public Pass4ZeroPageCoalesceExhaustive(Program program) { public Pass4MemoryCoalesceExhaustive(Program program) {
super(program); super(program);
} }
public void coalesce() { public void coalesce() {
LinkedHashSet<String> unknownFragments = new LinkedHashSet<>(); LinkedHashSet<String> unknownFragments = new LinkedHashSet<>();
LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet = getProgram().getLiveRangeEquivalenceClassSet(); LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet = getProgram().getLiveRangeEquivalenceClassSet();
Collection<ScopeRef> threads = Pass4ZeroPageCoalesce.getThreadHeads(getProgram()); Collection<ScopeRef> threads = Pass4MemoryCoalesce.getThreadHeads(getProgram());
boolean change; boolean change;
do { do {
change = coalesce(liveRangeEquivalenceClassSet, threads, unknownFragments); change = coalesce(liveRangeEquivalenceClassSet, threads, unknownFragments);
@ -48,8 +48,8 @@ public class Pass4ZeroPageCoalesceExhaustive extends Pass2Base {
private boolean coalesce(LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet, Collection<ScopeRef> threadHeads, Set<String> unknownFragments) { private boolean coalesce(LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet, Collection<ScopeRef> threadHeads, Set<String> unknownFragments) {
for(LiveRangeEquivalenceClass thisEquivalenceClass : liveRangeEquivalenceClassSet.getEquivalenceClasses()) { for(LiveRangeEquivalenceClass thisEquivalenceClass : liveRangeEquivalenceClassSet.getEquivalenceClasses()) {
for(LiveRangeEquivalenceClass otherEquivalenceClass : liveRangeEquivalenceClassSet.getEquivalenceClasses()) { for(LiveRangeEquivalenceClass otherEquivalenceClass : liveRangeEquivalenceClassSet.getEquivalenceClasses()) {
Pass4ZeroPageCoalesce.LiveRangeEquivalenceClassCoalesceCandidate candidate = new Pass4ZeroPageCoalesce.LiveRangeEquivalenceClassCoalesceCandidate(thisEquivalenceClass, otherEquivalenceClass, null); Pass4MemoryCoalesce.LiveRangeEquivalenceClassCoalesceCandidate candidate = new Pass4MemoryCoalesce.LiveRangeEquivalenceClassCoalesceCandidate(thisEquivalenceClass, otherEquivalenceClass, null);
boolean modified = Pass4ZeroPageCoalesce.attemptCoalesce(candidate, threadHeads, unknownFragments, getProgram()); boolean modified = Pass4MemoryCoalesce.attemptCoalesce(candidate, threadHeads, unknownFragments, getProgram());
if(modified) { if(modified) {
return true; return true;
} }

View File

@ -77,7 +77,7 @@ public class Pass4RegistersFinalize extends Pass2Base {
if(reallocateZp) { if(reallocateZp) {
reallocateZpRegisters(liveRangeEquivalenceClassSet); reallocateMemRegisters(liveRangeEquivalenceClassSet);
} }
liveRangeEquivalenceClassSet.storeRegisterAllocation(); liveRangeEquivalenceClassSet.storeRegisterAllocation();
if(reallocateZp) { if(reallocateZp) {
@ -160,11 +160,11 @@ public class Pass4RegistersFinalize extends Pass2Base {
} }
/** /**
* Reallocate all ZP registers to minimize ZP usage * Reallocate all memory registers. Minimizes zeropage usage.
* *
* @param liveRangeEquivalenceClassSet The * @param liveRangeEquivalenceClassSet The
*/ */
private void reallocateZpRegisters(LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet) { private void reallocateMemRegisters(LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet) {
for(LiveRangeEquivalenceClass equivalenceClass : liveRangeEquivalenceClassSet.getEquivalenceClasses()) { for(LiveRangeEquivalenceClass equivalenceClass : liveRangeEquivalenceClassSet.getEquivalenceClasses()) {
Registers.Register register = equivalenceClass.getRegister(); Registers.Register register = equivalenceClass.getRegister();
boolean reallocate = true; boolean reallocate = true;

View File

@ -3369,7 +3369,7 @@ public class TestPrograms {
tester.testFile(filename, upliftCombinations, null); tester.testFile(filename, upliftCombinations, null);
} }
private void compileAndCompare(String filename, CompileLog log, int upliftCombinations) throws IOException, URISyntaxException { private void compileAndCompare(String filename, int upliftCombinations, CompileLog log) throws IOException, URISyntaxException {
TestPrograms tester = new TestPrograms(); TestPrograms tester = new TestPrograms();
tester.testFile(filename, upliftCombinations, log); tester.testFile(filename, upliftCombinations, log);
} }