mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-09-08 17:54:40 +00:00
Implemented switchable effective live ranges. Started on "simple" which works for most programs - but fail for tetris, clearscreen and more.
This commit is contained in:
parent
7726c1d43f
commit
c0b0f063cc
@ -89,6 +89,10 @@ public class Compiler {
|
||||
this.enableLoopHeadConstant = false;
|
||||
}
|
||||
|
||||
public void setEnableLiveRangeCallPath(boolean enableLiveRangeCallPath) {
|
||||
this.program.setEnableLiveRangeCallPath(enableLiveRangeCallPath);
|
||||
}
|
||||
|
||||
void setTargetPlatform(TargetPlatform targetPlatform) {
|
||||
program.setTargetPlatform(targetPlatform);
|
||||
}
|
||||
|
@ -79,6 +79,9 @@ public class KickC implements Callable<Void> {
|
||||
@CommandLine.Option(names = {"-Ocache"}, description = "Optimization Option. Enables a fragment cache file.")
|
||||
private boolean optimizeFragmentCache = false;
|
||||
|
||||
//@CommandLine.Option(names = {"-Oliverangecallpath"}, description = "Optimization Option. Enables live ranges per call path optimization, which limits memory usage and code, but takes a lot of compile time.")
|
||||
private boolean optimizeLiveRangeCallPath = true;
|
||||
|
||||
@CommandLine.Option(names = {"-v"}, description = "Verbose output describing the compilation process")
|
||||
private boolean verbose = false;
|
||||
|
||||
@ -163,10 +166,10 @@ public class KickC implements Callable<Void> {
|
||||
|
||||
Compiler compiler = new Compiler();
|
||||
|
||||
if(target!=null) {
|
||||
if(target != null) {
|
||||
TargetPlatform targetPlatform = TargetPlatform.getTargetPlatform(target);
|
||||
if(targetPlatform==null) {
|
||||
System.err.println("Unknown target platform "+target);
|
||||
if(targetPlatform == null) {
|
||||
System.err.println("Unknown target platform " + target);
|
||||
StringBuffer supported = new StringBuffer();
|
||||
supported.append("The supported target platforms are: ");
|
||||
for(TargetPlatform value : TargetPlatform.values()) {
|
||||
@ -178,10 +181,10 @@ public class KickC implements Callable<Void> {
|
||||
compiler.setTargetPlatform(targetPlatform);
|
||||
}
|
||||
|
||||
if(cpu!=null) {
|
||||
if(cpu != null) {
|
||||
TargetCpu targetCpu = TargetCpu.getTargetCpu(cpu);
|
||||
if(targetCpu==null) {
|
||||
System.err.println("Unknown target CPU "+cpu);
|
||||
if(targetCpu == null) {
|
||||
System.err.println("Unknown target CPU " + cpu);
|
||||
StringBuffer supported = new StringBuffer();
|
||||
supported.append("The supported target CPUs are: ");
|
||||
for(TargetCpu value : TargetCpu.values()) {
|
||||
@ -252,7 +255,7 @@ public class KickC implements Callable<Void> {
|
||||
if(optimizeNoUplift) {
|
||||
compiler.setDisableUplift(true);
|
||||
}
|
||||
|
||||
|
||||
if(optimizeUpliftCombinations != null) {
|
||||
compiler.setUpliftCombinations(optimizeUpliftCombinations);
|
||||
}
|
||||
@ -267,15 +270,17 @@ public class KickC implements Callable<Void> {
|
||||
compiler.disableLoopHeadConstant();
|
||||
}
|
||||
|
||||
compiler.setEnableLiveRangeCallPath(optimizeLiveRangeCallPath);
|
||||
|
||||
if(warnFragmentMissing) {
|
||||
compiler.setWarnFragmentMissing(true);
|
||||
}
|
||||
|
||||
if(linkScript!=null) {
|
||||
if(linkScript != null) {
|
||||
compiler.setLinkScriptFileName(linkScript);
|
||||
}
|
||||
|
||||
if(varModel!=null) {
|
||||
if(varModel != null) {
|
||||
List<String> settings = Arrays.asList(varModel.split(","));
|
||||
settings = settings.stream().map(String::trim).collect(Collectors.toList());
|
||||
try {
|
||||
@ -287,10 +292,10 @@ public class KickC implements Callable<Void> {
|
||||
}
|
||||
}
|
||||
|
||||
if(calling!=null) {
|
||||
if(calling != null) {
|
||||
Procedure.CallingConvention callingConvention = Procedure.CallingConvention.getCallingConvension(calling);
|
||||
if(callingConvention ==null) {
|
||||
System.err.println("Unknown calling convention "+calling);
|
||||
if(callingConvention == null) {
|
||||
System.err.println("Unknown calling convention " + calling);
|
||||
StringBuffer supported = new StringBuffer();
|
||||
supported.append("The supported calling conventions are: ");
|
||||
for(Procedure.CallingConvention value : Procedure.CallingConvention.values()) {
|
||||
@ -392,8 +397,6 @@ public class KickC implements Callable<Void> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -131,14 +131,14 @@ public class CallGraph {
|
||||
/**
|
||||
* Get all calls of a specific procedure
|
||||
*
|
||||
* @param label The label of the procedure
|
||||
* @param procedureRef The label of the procedure
|
||||
* @return All calls
|
||||
*/
|
||||
public Collection<CallBlock.Call> getCallers(ScopeRef label) {
|
||||
public Collection<CallBlock.Call> getCallers(ProcedureRef procedureRef) {
|
||||
Collection<CallBlock.Call> callers = new ArrayList<>();
|
||||
for(CallBlock callBlock : callBlocks) {
|
||||
for(CallBlock.Call call : callBlock.getCalls()) {
|
||||
if(call.getProcedure().equals(label)) {
|
||||
if(call.getProcedure().equals(procedureRef)) {
|
||||
callers.add(call);
|
||||
}
|
||||
}
|
||||
@ -147,11 +147,36 @@ public class CallGraph {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all procedures containing calls of a specific procedure
|
||||
* Get all calls of a specific procedure
|
||||
*
|
||||
* @param label The label of the procedure
|
||||
* @return All calls
|
||||
*/
|
||||
public Collection<CallBlock.Call> getRecursiveCallers(ProcedureRef procedureRef) {
|
||||
final LinkedList<CallBlock.Call> callers = new LinkedList<>();
|
||||
Deque<ProcedureRef> todo = new LinkedList<>();
|
||||
todo.add(procedureRef);
|
||||
Collection<ProcedureRef> visited = new LinkedList<>();
|
||||
while(!todo.isEmpty()) {
|
||||
final ProcedureRef procRef = todo.pop();
|
||||
if(visited.contains(procRef))
|
||||
continue;
|
||||
visited.add(procRef);
|
||||
final Collection<CallBlock.Call> procCallers = getCallers(procRef);
|
||||
callers.addAll(procCallers);
|
||||
for(CallBlock.Call caller : procCallers) {
|
||||
todo.add(caller.getProcedure());
|
||||
}
|
||||
}
|
||||
return callers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all procedures containing calls of a specific procedure
|
||||
*
|
||||
* @param label The label of the procedure
|
||||
* @return All calls
|
||||
*/
|
||||
public Collection<ScopeRef> getCallerProcs(ScopeRef label) {
|
||||
Collection<ScopeRef> callers = new ArrayList<>();
|
||||
for(CallBlock callBlock : callBlocks) {
|
||||
@ -170,9 +195,9 @@ public class CallGraph {
|
||||
* @param scopeRef The scope (procedure/root) to examine
|
||||
* @return All scopes calling the passed scope (potentially through other callers)
|
||||
*/
|
||||
public Collection<ScopeRef> getRecursiveCallers(ScopeRef scopeRef) {
|
||||
public Collection<ScopeRef> getRecursiveCallerProcs(ScopeRef scopeRef) {
|
||||
ArrayList<ScopeRef> closure = new ArrayList<>();
|
||||
addRecursiveCallers(scopeRef, closure);
|
||||
addRecursiveCallerProcs(scopeRef, closure);
|
||||
return closure;
|
||||
}
|
||||
|
||||
@ -182,7 +207,7 @@ public class CallGraph {
|
||||
* @param scopeRef The scope (procedure/root) to examine
|
||||
* @param found The scopes already found
|
||||
* */
|
||||
private void addRecursiveCallers(ScopeRef scopeRef, Collection<ScopeRef> found) {
|
||||
private void addRecursiveCallerProcs(ScopeRef scopeRef, Collection<ScopeRef> found) {
|
||||
if(found.contains(scopeRef)) {
|
||||
// Recursion detected - stop here
|
||||
return;
|
||||
@ -190,7 +215,7 @@ public class CallGraph {
|
||||
found.add(scopeRef);
|
||||
Collection<ScopeRef> callerProcs = getCallerProcs(scopeRef);
|
||||
for(ScopeRef callerProc : callerProcs) {
|
||||
addRecursiveCallers(callerProc, found);
|
||||
addRecursiveCallerProcs(callerProc, found);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,8 @@ public interface LiveRangeVariablesEffective {
|
||||
|
||||
AliveCombinations getAliveCombinations(Statement statement);
|
||||
|
||||
String getSizeInfo();
|
||||
|
||||
/**
|
||||
* Combinations of variables effectively alive at a specific statement.
|
||||
*/
|
||||
|
@ -8,7 +8,7 @@ import dk.camelot64.kickc.model.values.ProcedureRef;
|
||||
import dk.camelot64.kickc.model.values.ScopeRef;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
import dk.camelot64.kickc.passes.Pass2AliasElimination;
|
||||
import dk.camelot64.kickc.passes.calcs.PassNCalcLiveRangesEffective;
|
||||
import dk.camelot64.kickc.passes.calcs.PassNCalcLiveRangesEffectiveCallPaths;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@ -16,7 +16,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
/**
|
||||
* Effective variable live ranges for all statements.
|
||||
* (Including variables alive in calling methods).
|
||||
* Created by {@link PassNCalcLiveRangesEffective}
|
||||
* Created by {@link PassNCalcLiveRangesEffectiveCallPaths}
|
||||
*/
|
||||
public class LiveRangeVariablesEffectiveCallPaths implements LiveRangeVariablesEffective {
|
||||
|
||||
@ -94,7 +94,7 @@ public class LiveRangeVariablesEffectiveCallPaths implements LiveRangeVariablesE
|
||||
* @return All combinations of variables alive at the statement
|
||||
*/
|
||||
@Override
|
||||
public AliveCombinationsCallPath getAliveCombinations(Statement statement) {
|
||||
public AliveCombinations getAliveCombinations(Statement statement) {
|
||||
AliveCombinationsCallPath stmtCombinations = this.statementAliveCombinations.get(statement.getIndex());
|
||||
if(stmtCombinations == null) {
|
||||
Collection<VariableRef> aliveAtStmt = statementLiveVariables.get(statement.getIndex());
|
||||
@ -150,7 +150,7 @@ public class LiveRangeVariablesEffectiveCallPaths implements LiveRangeVariablesE
|
||||
}
|
||||
|
||||
|
||||
String getSizeInfo() {
|
||||
public String getSizeInfo() {
|
||||
StringBuilder sizeInfo = new StringBuilder();
|
||||
if(this.procedureCallPaths != null) {
|
||||
AtomicInteger numCallPaths = new AtomicInteger();
|
||||
|
@ -0,0 +1,105 @@
|
||||
package dk.camelot64.kickc.model;
|
||||
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
import dk.camelot64.kickc.passes.Pass2AliasElimination;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Simple and fast implementation of effective alive variables that combines all call-path combinations into a single set and callpath aliases are not handled
|
||||
*/
|
||||
public class LiveRangeVariablesEffectiveSimple implements LiveRangeVariablesEffective {
|
||||
|
||||
/** All variables potentially effective alive by statement index. */
|
||||
private Map<Integer, Collection<VariableRef>> statementAliveEffective;
|
||||
|
||||
public LiveRangeVariablesEffectiveSimple(Map<Integer, Collection<VariableRef>> statementAliveEffective) {
|
||||
this.statementAliveEffective = statementAliveEffective;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all variables potentially alive at a statement.
|
||||
* If the statement is inside a method this also includes all variables alive at the exit of any call.
|
||||
* </p>
|
||||
*
|
||||
* @param statement The statement to examine
|
||||
* @return All variables potentially alive at the statement
|
||||
*/
|
||||
@Override
|
||||
public Collection<VariableRef> getAliveEffective(Statement statement) {
|
||||
return statementAliveEffective.get(statement.getIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AliveCombinations getAliveCombinations(Statement statement) {
|
||||
return new AliveCombinationsSimple(getAliveEffective(statement));
|
||||
}
|
||||
|
||||
public class AliveCombinationsSimple implements AliveCombinations {
|
||||
|
||||
private Collection<VariableRef> alive;
|
||||
|
||||
public AliveCombinationsSimple(Collection<VariableRef> alive) {
|
||||
this.alive = alive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<AliveCombination> getAll() {
|
||||
final ArrayList<AliveCombination> aliveCombinations = new ArrayList<>();
|
||||
aliveCombinations.add(new AliveCombinationSimple(alive));
|
||||
return aliveCombinations;
|
||||
}
|
||||
}
|
||||
|
||||
public class AliveCombinationSimple implements AliveCombination {
|
||||
|
||||
private Collection<VariableRef> alive;
|
||||
|
||||
public AliveCombinationSimple(Collection<VariableRef> alive) {
|
||||
this.alive = alive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<VariableRef> getEffectiveAliveAtStmt() {
|
||||
return alive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pass2AliasElimination.Aliases getEffectiveAliasesAtStmt() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getAliveString(alive);
|
||||
}
|
||||
|
||||
private String getAliveString(Collection<VariableRef> alive) {
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append(" [ ");
|
||||
for(VariableRef variableRef : alive) {
|
||||
str.append(variableRef.getFullName());
|
||||
str.append(" ");
|
||||
}
|
||||
str.append("]");
|
||||
return str.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSizeInfo() {
|
||||
StringBuilder sizeInfo = new StringBuilder();
|
||||
if(this.statementAliveEffective != null) {
|
||||
sizeInfo.append("SIZE statementAliveEffective ").append(statementAliveEffective.size()).append(" statements ");
|
||||
int sub = 0;
|
||||
for(Collection<VariableRef> variableRefs : statementAliveEffective.values()) {
|
||||
sub += variableRefs.size();
|
||||
}
|
||||
sizeInfo.append(" ").append(sub).append(" varrefs").append("\n");
|
||||
}
|
||||
return sizeInfo.toString();
|
||||
}
|
||||
}
|
@ -89,7 +89,7 @@ public class Program {
|
||||
/** The live ranges of all variables. PASS 3-4 (CACHED ON-DEMAND) */
|
||||
private LiveRangeVariables liveRangeVariables;
|
||||
/** The effective live ranges of all variables. PASS 3-4 (CACHED ON-DEMAND) */
|
||||
private LiveRangeVariablesEffectiveCallPaths liveRangeVariablesEffective;
|
||||
private LiveRangeVariablesEffective liveRangeVariablesEffective;
|
||||
/** Separation of live range equivalence classes into scopes - used for register uplift. PASS 4 (CACHED ON-DEMAND) */
|
||||
private RegisterUpliftProgram registerUpliftProgram;
|
||||
/** Cached information about which block is each statement a part of. PASS 2U-5 (CACHED ON-DEMAND) */
|
||||
@ -98,6 +98,8 @@ public class Program {
|
||||
private NaturalLoopSet loopSet;
|
||||
/** The register weight of all variables describing how much the variable would theoretically gain from being in a register. PASS 3-5 (CACHED ON-DEMAND) */
|
||||
private VariableRegisterWeights variableRegisterWeights;
|
||||
/** Enable live ranges per call path optimization, which limits memory usage and code, but takes a lot of compile time. */
|
||||
private boolean enableLiveRangeCallPath = true;
|
||||
|
||||
public Program() {
|
||||
this.scope = new ProgramScope();
|
||||
@ -165,6 +167,10 @@ public class Program {
|
||||
this.asm = null;
|
||||
}
|
||||
|
||||
public void setEnableLiveRangeCallPath(boolean enableLiveRangeCallPath) {
|
||||
this.enableLiveRangeCallPath = enableLiveRangeCallPath;
|
||||
}
|
||||
|
||||
public boolean isWarnFragmentMissing() {
|
||||
return warnFragmentMissing;
|
||||
}
|
||||
@ -200,6 +206,7 @@ public class Program {
|
||||
public void initAsmFragmentSynthesizer(AsmFragmentTemplateSynthesizer synthesizer) {
|
||||
this.asmFragmentSynthesizer = synthesizer;
|
||||
}
|
||||
|
||||
public TargetCpu getTargetCpu() {
|
||||
return targetCpu;
|
||||
}
|
||||
@ -290,6 +297,7 @@ public class Program {
|
||||
|
||||
/**
|
||||
* Get the call-graph for the program. Calculates the call-graph if it has not already been calculated.
|
||||
*
|
||||
* @return The call-graph
|
||||
*/
|
||||
public CallGraph getCallGraph() {
|
||||
@ -306,7 +314,7 @@ public class Program {
|
||||
}
|
||||
|
||||
public VariableReferenceInfos getVariableReferenceInfos() {
|
||||
if(variableReferenceInfos==null)
|
||||
if(variableReferenceInfos == null)
|
||||
this.variableReferenceInfos = new PassNCalcVariableReferenceInfos(this).calculate();
|
||||
return variableReferenceInfos;
|
||||
}
|
||||
@ -316,7 +324,7 @@ public class Program {
|
||||
}
|
||||
|
||||
public DominatorsGraph getDominators() {
|
||||
if(dominators==null)
|
||||
if(dominators == null)
|
||||
this.dominators = new PassNCalcDominators(this).calculate();
|
||||
return dominators;
|
||||
}
|
||||
@ -326,7 +334,7 @@ public class Program {
|
||||
}
|
||||
|
||||
public Map<LabelRef, PhiTransitions> getPhiTransitions() {
|
||||
if(phiTransitions==null)
|
||||
if(phiTransitions == null)
|
||||
this.phiTransitions = new PassNCalcPhiTransitions(this).calculate();
|
||||
return phiTransitions;
|
||||
}
|
||||
@ -336,7 +344,7 @@ public class Program {
|
||||
}
|
||||
|
||||
public LiveRangeVariables getLiveRangeVariables() {
|
||||
if(liveRangeVariables==null)
|
||||
if(liveRangeVariables == null)
|
||||
this.liveRangeVariables = new PassNCalcLiveRangeVariables(this).calculate();
|
||||
return liveRangeVariables;
|
||||
}
|
||||
@ -354,7 +362,7 @@ public class Program {
|
||||
}
|
||||
|
||||
public StatementInfos getStatementInfos() {
|
||||
if(statementInfos==null)
|
||||
if(statementInfos == null)
|
||||
this.statementInfos = new PassNCalcStatementInfos(this).calculate();
|
||||
return statementInfos;
|
||||
}
|
||||
@ -375,18 +383,22 @@ public class Program {
|
||||
}
|
||||
|
||||
public SymbolInfos getSymbolInfos() {
|
||||
if(symbolInfos==null)
|
||||
if(symbolInfos == null)
|
||||
this.symbolInfos = new PassNCalcSymbolInfos(this).calculate();
|
||||
return symbolInfos;
|
||||
}
|
||||
|
||||
public boolean hasLiveRangeVariablesEffective() {
|
||||
return liveRangeVariablesEffective!=null;
|
||||
return liveRangeVariablesEffective != null;
|
||||
}
|
||||
|
||||
public LiveRangeVariablesEffective getLiveRangeVariablesEffective() {
|
||||
if(liveRangeVariablesEffective==null) {
|
||||
this.liveRangeVariablesEffective = new PassNCalcLiveRangesEffective(this).calculate();
|
||||
if(liveRangeVariablesEffective == null) {
|
||||
if(enableLiveRangeCallPath) {
|
||||
this.liveRangeVariablesEffective = new PassNCalcLiveRangesEffectiveCallPaths(this).calculate();
|
||||
} else {
|
||||
this.liveRangeVariablesEffective = new PassNCalcLiveRangesEffectiveSimple(this).calculate();
|
||||
}
|
||||
}
|
||||
return liveRangeVariablesEffective;
|
||||
}
|
||||
@ -396,13 +408,13 @@ public class Program {
|
||||
}
|
||||
|
||||
public RegisterUpliftProgram getRegisterUpliftProgram() {
|
||||
if(registerUpliftProgram==null)
|
||||
if(registerUpliftProgram == null)
|
||||
this.registerUpliftProgram = new PassNCalcRegisterUpliftProgram(this).calculate();
|
||||
return registerUpliftProgram;
|
||||
}
|
||||
|
||||
public NaturalLoopSet getLoopSet() {
|
||||
if(loopSet==null)
|
||||
if(loopSet == null)
|
||||
this.loopSet = new PassNCalcLoopSet(this).calculate();
|
||||
return loopSet;
|
||||
}
|
||||
@ -412,7 +424,7 @@ public class Program {
|
||||
}
|
||||
|
||||
public VariableRegisterWeights getVariableRegisterWeights() {
|
||||
if(variableRegisterWeights==null)
|
||||
if(variableRegisterWeights == null)
|
||||
this.variableRegisterWeights = new PassNCalcVariableRegisterWeight(this).calculate();
|
||||
return variableRegisterWeights;
|
||||
}
|
||||
@ -499,19 +511,20 @@ public class Program {
|
||||
|
||||
/**
|
||||
* Get information about the size of the program
|
||||
*
|
||||
* @return Size information
|
||||
*/
|
||||
public String getSizeInfo() {
|
||||
StringBuilder sizeInfo = new StringBuilder();
|
||||
sizeInfo.append(getScope().getSizeInfo());
|
||||
sizeInfo.append(getGraph().getSizeInfo());
|
||||
if(variableReferenceInfos!=null)
|
||||
if(variableReferenceInfos != null)
|
||||
sizeInfo.append(variableReferenceInfos.getSizeInfo());
|
||||
if(getLiveRangeEquivalenceClassSet()!=null)
|
||||
if(getLiveRangeEquivalenceClassSet() != null)
|
||||
sizeInfo.append(getLiveRangeEquivalenceClassSet().getSizeInfo());
|
||||
if(liveRangeVariablesEffective!=null)
|
||||
if(liveRangeVariablesEffective != null)
|
||||
sizeInfo.append(liveRangeVariablesEffective.getSizeInfo());
|
||||
if(getAsm()!=null)
|
||||
if(getAsm() != null)
|
||||
sizeInfo.append(getAsm().getSizeInfo());
|
||||
return sizeInfo.toString();
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ public abstract class Pass4MemoryCoalesce extends Pass2Base {
|
||||
threads.add(mainThreadHead);
|
||||
}
|
||||
} else {
|
||||
Collection<ScopeRef> recursiveCallers = callGraph.getRecursiveCallers(scopeRef);
|
||||
Collection<ScopeRef> recursiveCallers = callGraph.getRecursiveCallerProcs(scopeRef);
|
||||
for(ScopeRef threadHead : threadHeads) {
|
||||
if(recursiveCallers.contains(threadHead)) {
|
||||
if(!threads.contains(threadHead)) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.values.ProcedureRef;
|
||||
import dk.camelot64.kickc.model.values.ScopeRef;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
|
||||
@ -55,9 +56,9 @@ public class Pass4MemoryCoalesceCallGraph extends Pass2Base {
|
||||
if(Registers.RegisterType.MAIN_MEM.equals(thisEC.getRegister().getType()))
|
||||
continue;
|
||||
// Find all calling scopes - since we want to avoid coalescing with variables in these
|
||||
Set<ScopeRef> allCallingScopes = new LinkedHashSet<>();
|
||||
Set<ProcedureRef> allCallingScopes = new LinkedHashSet<>();
|
||||
for(ScopeRef ecScope : getEquivalenceClassScopes(thisEC)) {
|
||||
allCallingScopes.addAll(getAllCallingScopes(ecScope, callGraph));
|
||||
allCallingScopes.addAll(getAllCallingScopes(new ProcedureRef(ecScope.getFullName()), callGraph));
|
||||
}
|
||||
// Go through the already handled equivalence classes - and try to coalesce with any that does not have variables from the calling scopes
|
||||
boolean coalesced = false;
|
||||
@ -66,7 +67,7 @@ public class Pass4MemoryCoalesceCallGraph extends Pass2Base {
|
||||
if(Registers.RegisterType.MAIN_MEM.equals(otherEC.getRegister().getType()))
|
||||
continue;
|
||||
// Skip if there is a scope overlap
|
||||
if(isScopeOverlap(otherEC, allCallingScopes))
|
||||
if(isProcedureOverlap(otherEC, allCallingScopes))
|
||||
continue;
|
||||
// No scope overlap - attempt to coalesce
|
||||
Pass4MemoryCoalesce.LiveRangeEquivalenceClassCoalesceCandidate candidate = new Pass4MemoryCoalesce.LiveRangeEquivalenceClassCoalesceCandidate(thisEC, otherEC, null);
|
||||
@ -86,33 +87,33 @@ public class Pass4MemoryCoalesceCallGraph extends Pass2Base {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if any variable in a live range equivalence class has a scope from the passed set of scopes.
|
||||
* Determine if any variable in a live range equivalence class has a scope from the passed set of procedures.
|
||||
* @param equivalenceClass The live range equivalence class
|
||||
* @param scopeRefSet The set of scopes
|
||||
* @param procedureRefs The set of procedures
|
||||
* @return true if there is a scope overlap
|
||||
*/
|
||||
private boolean isScopeOverlap(LiveRangeEquivalenceClass equivalenceClass, Collection<ScopeRef> scopeRefSet) {
|
||||
private boolean isProcedureOverlap(LiveRangeEquivalenceClass equivalenceClass, Collection<ProcedureRef> procedureRefs) {
|
||||
boolean scopeOverlap = false;
|
||||
for(VariableRef otherVarRef : equivalenceClass.getVariables()) {
|
||||
ScopeRef otherScopeRef = new ScopeRef(otherVarRef.getScopeNames());
|
||||
if(scopeRefSet.contains(otherScopeRef))
|
||||
ProcedureRef otherProcedureRef = new ProcedureRef(otherVarRef.getScopeNames());
|
||||
if(procedureRefs.contains(otherProcedureRef))
|
||||
scopeOverlap = true;
|
||||
}
|
||||
return scopeOverlap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all scopes call into a specific scope. Recursively includes callers of callers. Also includes the scope itself.
|
||||
* @param scopeRef The scope to examine
|
||||
* Get all procedures calling into a specific procedure. Recursively includes callers of callers. Also includes the procedure itself.
|
||||
* @param procedureRef The scope to examine
|
||||
* @param callGraph The call graph
|
||||
* @return All scopes that call into this one (potentially )
|
||||
* @return All procedures that call into this one (potentially )
|
||||
*/
|
||||
private Set<ScopeRef> getAllCallingScopes(ScopeRef scopeRef, CallGraph callGraph) {
|
||||
LinkedHashSet<ScopeRef> allCallers = new LinkedHashSet<>();
|
||||
private Set<ProcedureRef> getAllCallingScopes(ProcedureRef procedureRef, CallGraph callGraph) {
|
||||
LinkedHashSet<ProcedureRef> allCallers = new LinkedHashSet<>();
|
||||
// Add the scope itself
|
||||
allCallers.add(scopeRef);
|
||||
allCallers.add(procedureRef);
|
||||
// Recursively add the scopes of all callers
|
||||
for(CallGraph.CallBlock.Call caller : callGraph.getCallers(scopeRef)) {
|
||||
for(CallGraph.CallBlock.Call caller : callGraph.getCallers(procedureRef)) {
|
||||
if(!allCallers.contains(caller.getProcedure()))
|
||||
allCallers.addAll(getAllCallingScopes(caller.getProcedure(), callGraph));
|
||||
}
|
||||
|
@ -201,20 +201,22 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
||||
LiveRangeVariablesEffective.AliveCombinations aliveCombinations = program.getLiveRangeVariablesEffective().getAliveCombinations(statement);
|
||||
for(LiveRangeVariablesEffective.AliveCombination combination : aliveCombinations.getAll()) {
|
||||
LinkedHashMap<Registers.Register, LiveRangeEquivalenceClass> usedRegisters = new LinkedHashMap<>();
|
||||
Collection<VariableRef> alive = combination.getEffectiveAliveAtStmt();
|
||||
Pass2AliasElimination.Aliases callPathAliases = combination.getEffectiveAliasesAtStmt();
|
||||
for(VariableRef varRef : alive) {
|
||||
Collection<VariableRef> aliveAtStmt = combination.getEffectiveAliveAtStmt();
|
||||
Pass2AliasElimination.Aliases aliasesAtStmt = combination.getEffectiveAliasesAtStmt();
|
||||
for(VariableRef varRef : aliveAtStmt) {
|
||||
Variable var = program.getSymbolInfos().getVariable(varRef);
|
||||
Registers.Register allocation = var.getAllocation();
|
||||
LiveRangeEquivalenceClass allocationClass = usedRegisters.get(allocation);
|
||||
if(allocationClass != null && !allocationClass.contains(varRef)) {
|
||||
// Examine if the var is an alias of a var in the allocation class
|
||||
boolean overlap = true;
|
||||
Pass2AliasElimination.AliasSet aliasSet = callPathAliases.findAliasSet(varRef);
|
||||
if(aliasSet != null) {
|
||||
for(VariableRef aliasVar : aliasSet.getVars()) {
|
||||
if(allocationClass.contains(aliasVar)) {
|
||||
overlap = false;
|
||||
if(aliasesAtStmt!=null) {
|
||||
Pass2AliasElimination.AliasSet aliasSet = aliasesAtStmt.findAliasSet(varRef);
|
||||
if(aliasSet != null) {
|
||||
for(VariableRef aliasVar : aliasSet.getVars()) {
|
||||
if(allocationClass.contains(aliasVar)) {
|
||||
overlap = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ public class PassNCalcLiveRangeVariables extends PassNCalcBase<LiveRangeVariable
|
||||
ControlFlowBlock block = getProgram().getStatementInfos().getBlock(statement);
|
||||
if(block.isProcedureEntry(getProgram())) {
|
||||
// Current is first statement of a call - add the statement preceding the call.
|
||||
Collection<CallGraph.CallBlock.Call> callers = getProgram().getCallGraph().getCallers(block.getScope());
|
||||
Collection<CallGraph.CallBlock.Call> callers = getProgram().getCallGraph().getCallers((ProcedureRef) block.getScope());
|
||||
for(CallGraph.CallBlock.Call call : callers) {
|
||||
Statement callStmt = getProgram().getStatementInfos().getStatement(call.getCallStatementIdx());
|
||||
Collection<Statement> precedingCallStmt = getPrecedingStatement(callStmt);
|
||||
|
@ -16,9 +16,9 @@ import java.util.*;
|
||||
/**
|
||||
* Find effective alive intervals for all variables in all statements. Add the intervals to the Program.
|
||||
*/
|
||||
public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariablesEffectiveCallPaths> {
|
||||
public class PassNCalcLiveRangesEffectiveCallPaths extends PassNCalcBase<LiveRangeVariablesEffectiveCallPaths> {
|
||||
|
||||
public PassNCalcLiveRangesEffective(Program program) {
|
||||
public PassNCalcLiveRangesEffectiveCallPaths(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
package dk.camelot64.kickc.passes.calcs;
|
||||
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.values.ProcedureRef;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Find effective alive intervals for all variables in all statements. Add the intervals to the Program.
|
||||
*/
|
||||
public class PassNCalcLiveRangesEffectiveSimple extends PassNCalcBase<LiveRangeVariablesEffectiveSimple> {
|
||||
|
||||
public PassNCalcLiveRangesEffectiveSimple(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveRangeVariablesEffectiveSimple calculate() {
|
||||
final LiveRangeVariables liveRangeVariables = getProgram().getLiveRangeVariables();
|
||||
final CallGraph callGraph = getProgram().getCallGraph();
|
||||
final LiveRangeVariables.LiveRangeVariablesByStatement liveRangeVariablesByStatement = liveRangeVariables.getLiveRangeVariablesByStatement();
|
||||
|
||||
// Find all alive vars from the recursive callers of each procedure
|
||||
Map<ProcedureRef, Collection<VariableRef>> callersAlive = new LinkedHashMap<>();
|
||||
Collection<Procedure> procedures = getProgram().getScope().getAllProcedures(true);
|
||||
for(Procedure procedure : procedures) {
|
||||
Collection<VariableRef> procCallersAlive = new LinkedHashSet<>();
|
||||
final Collection<CallGraph.CallBlock.Call> callers = callGraph.getRecursiveCallers(procedure.getRef());
|
||||
for(CallGraph.CallBlock.Call caller : callers) {
|
||||
final Integer callStatementIdx = caller.getCallStatementIdx();
|
||||
final List<VariableRef> callStatementAlive = liveRangeVariables.getAlive(callStatementIdx);
|
||||
procCallersAlive.addAll(callStatementAlive);
|
||||
}
|
||||
callersAlive.put(procedure.getRef(), procCallersAlive);
|
||||
}
|
||||
|
||||
// Find all alive variables for all statements by adding the alive from all recursive callers
|
||||
final LinkedHashMap<Integer, Collection<VariableRef>> statementAliveEffective = new LinkedHashMap<>();
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
final Procedure procedure = block.getProcedure(getProgram());
|
||||
for(Statement statement : block.getStatements()) {
|
||||
final Collection<VariableRef> aliveStmt = new LinkedHashSet<>();
|
||||
aliveStmt.addAll(liveRangeVariablesByStatement.getAlive(statement.getIndex()));
|
||||
if(procedure!=null) {
|
||||
aliveStmt.addAll(callersAlive.get(procedure.getRef()));
|
||||
}
|
||||
statementAliveEffective.put(statement.getIndex(), aliveStmt);
|
||||
}
|
||||
}
|
||||
return new LiveRangeVariablesEffectiveSimple(statementAliveEffective);
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user