mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-09-08 17:54:40 +00:00
Implemented call-path based effective alive analysis with call-path specific aliases.
This commit is contained in:
parent
b20327590f
commit
0026676080
@ -209,6 +209,8 @@ public class Compiler {
|
||||
new Pass3StatementIndices(program).generateStatementIndices();
|
||||
new Pass3CallGraphAnalysis(program).findCallGraph();
|
||||
new Pass3LiveRangesAnalysis(program).findLiveRanges();
|
||||
program.getLog().append("CONTROL FLOW GRAPH - BEFORE EFFECTIVE LIVE RANGES");
|
||||
program.getLog().append(program.getGraph().toString(program));
|
||||
new Pass3LiveRangesEffectiveAnalysis(program).findLiveRangesEffective();
|
||||
program.getLog().append("CONTROL FLOW GRAPH - PHI MEM COALESCED");
|
||||
program.getLog().append(program.getGraph().toString(program));
|
||||
@ -262,9 +264,9 @@ public class Compiler {
|
||||
//program.getLog().setVerboseUplift(true);
|
||||
new Pass4RegisterUpliftCombinations(program).performUplift(10_000);
|
||||
|
||||
program.getLog().setVerboseUplift(true);
|
||||
new Pass4RegisterUpliftStatic(program).performUplift();
|
||||
program.getLog().setVerboseUplift(false);
|
||||
//program.getLog().setVerboseUplift(true);
|
||||
//new Pass4RegisterUpliftStatic(program).performUplift();
|
||||
//program.getLog().setVerboseUplift(false);
|
||||
|
||||
// Attempt uplifting registers one at a time to catch remaining potential not realized by combination search
|
||||
new Pass4RegisterUpliftRemains(program).performUplift(10_000);
|
||||
|
@ -0,0 +1 @@
|
||||
jmp {la1}
|
@ -1,31 +1,139 @@
|
||||
package dk.camelot64.kickc.model;
|
||||
|
||||
import dk.camelot64.kickc.passes.Pass2AliasElimination;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/** Effective variable live ranges for all statements. (Including variables alive in calling methods)
|
||||
* Created by {@link dk.camelot64.kickc.passes.Pass3CallGraphAnalysis}
|
||||
/**
|
||||
* Effective variable live ranges for all statements.
|
||||
* (Including variables alive in calling methods).
|
||||
* Created by {@link dk.camelot64.kickc.passes.Pass3LiveRangesEffectiveAnalysis}
|
||||
*/
|
||||
public class LiveRangeVariablesEffective {
|
||||
|
||||
/** Effectively alive variables by statement index. */
|
||||
Map<Integer, AliveCombinations> effectiveLiveCombinations;
|
||||
/**
|
||||
* The program.
|
||||
*/
|
||||
private Program program;
|
||||
|
||||
public LiveRangeVariablesEffective(Map<Integer, AliveCombinations> effectiveLiveCombinations) {
|
||||
this.effectiveLiveCombinations = effectiveLiveCombinations;
|
||||
/**
|
||||
* Call-paths for all procedures.
|
||||
*/
|
||||
private Map<ProcedureRef, CallPaths> procedureCallPaths;
|
||||
|
||||
/**
|
||||
* Normal variable live ranges.
|
||||
*/
|
||||
private LiveRangeVariables liveRangeVariables;
|
||||
|
||||
/**
|
||||
* Information about which procedures reference which variables.
|
||||
*/
|
||||
private VariableReferenceInfo referenceInfo;
|
||||
|
||||
public LiveRangeVariablesEffective(Program program, Map<ProcedureRef, CallPaths> procedureCallPaths, LiveRangeVariables liveRangeVariables, VariableReferenceInfo referenceInfo) {
|
||||
this.program = program;
|
||||
this.procedureCallPaths = procedureCallPaths;
|
||||
this.liveRangeVariables = liveRangeVariables;
|
||||
this.referenceInfo = referenceInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* All call-paths leading into a specific procedure.
|
||||
*/
|
||||
public static class CallPaths {
|
||||
/**
|
||||
* The procedure
|
||||
*/
|
||||
private ProcedureRef procedure;
|
||||
/**
|
||||
* All call-paths leading into the procedure from the main() procedure.
|
||||
*/
|
||||
private Collection<CallPath> callPaths;
|
||||
|
||||
public CallPaths(ProcedureRef procedure) {
|
||||
this.procedure = procedure;
|
||||
this.callPaths = new ArrayList<>();
|
||||
}
|
||||
|
||||
public ProcedureRef getProcedure() {
|
||||
return procedure;
|
||||
}
|
||||
|
||||
public Collection<CallPath> getCallPaths() {
|
||||
return callPaths;
|
||||
}
|
||||
|
||||
public void add(CallPath callPath) {
|
||||
this.callPaths.add(callPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All variables alive in a specific procedure at a specific call-path.
|
||||
* The call-path is th path from the main()-procedure to the procedure in question.
|
||||
*/
|
||||
public static class CallPath {
|
||||
|
||||
/**
|
||||
* The path from main() to the procedure. First element is the call to main(), last element is the call to the procedure.
|
||||
*/
|
||||
private List<CallGraph.CallBlock.Call> path;
|
||||
/**
|
||||
* Alive variables on the call-path. Based on alive vars at each call in the path.
|
||||
*/
|
||||
private Collection<VariableRef> alive;
|
||||
/**
|
||||
* Alias variables on the call-path. All global aliases plus any variables alias-assigned in a phi-block on the path.
|
||||
*/
|
||||
private Pass2AliasElimination.Aliases aliases;
|
||||
|
||||
public CallPath(List<CallGraph.CallBlock.Call> path, Collection<VariableRef> alive, Pass2AliasElimination.Aliases aliases) {
|
||||
this.path = path;
|
||||
this.alive = alive;
|
||||
this.aliases = aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* The path from main() to the procedure. First element is the call to main(), last element is the call to the procedure.
|
||||
* @return Tha call path
|
||||
*/
|
||||
public List<CallGraph.CallBlock.Call> getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alive variables on the call-path. Based on alive vars at each call in the path.
|
||||
* @return The alive variables
|
||||
*/
|
||||
public Collection<VariableRef> getAlive() {
|
||||
return alive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias variables on the call-path. All global aliases plus any variables alias-assigned in a phi-block on the path.
|
||||
* @return The aliases
|
||||
*/
|
||||
public Pass2AliasElimination.Aliases getAliases() {
|
||||
return aliases;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public Collection<VariableRef> getAliveEffective(Statement statement) {
|
||||
Set<VariableRef> effectiveAliveTotal = new LinkedHashSet<>();
|
||||
AliveCombinations aliveCombinations = effectiveLiveCombinations.get(statement.getIndex());
|
||||
for (AliveCombination aliveCombination : aliveCombinations.getCombinations()) {
|
||||
effectiveAliveTotal.addAll(aliveCombination.getAlive());
|
||||
AliveCombinations aliveCombinations = getAliveCombinations(statement);
|
||||
for (CallPath callPath : aliveCombinations.getCallPaths().getCallPaths()) {
|
||||
Collection<VariableRef> alive = aliveCombinations.getEffectiveAliveAtStmt(callPath);
|
||||
effectiveAliveTotal.addAll(alive);
|
||||
}
|
||||
return effectiveAliveTotal;
|
||||
}
|
||||
@ -36,46 +144,80 @@ public class LiveRangeVariablesEffective {
|
||||
* (recursively up til the main()-method.
|
||||
* Each combination includes all variables alive at the exit of any surrounding call.
|
||||
* </p>
|
||||
*
|
||||
* @param statement The statement to examine
|
||||
* @return All combinations of variables alive at the statement
|
||||
*/
|
||||
public AliveCombinations getAliveCombinations(Statement statement) {
|
||||
return effectiveLiveCombinations.get(statement.getIndex());
|
||||
List<VariableRef> aliveAtStmt = liveRangeVariables.getAlive(statement);
|
||||
CallPaths callPaths;
|
||||
Collection<VariableRef> referencedInProcedure;
|
||||
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;
|
||||
callPaths = procedureCallPaths.get(procedure.getRef());
|
||||
referencedInProcedure = referenceInfo.getReferenced(procedure.getRef().getLabelRef());
|
||||
} else {
|
||||
callPaths = new CallPaths(Procedure.ROOT);
|
||||
referencedInProcedure = new ArrayList<>();
|
||||
}
|
||||
return new AliveCombinations(callPaths, referencedInProcedure, aliveAtStmt);
|
||||
}
|
||||
|
||||
/** Combinations of variables effectively alive at a specific statement.
|
||||
/**
|
||||
* Combinations of variables effectively alive at a specific statement.
|
||||
* If the statement is inside a method the combinations are the live variables inside the method combined with each calling statements alive vars.
|
||||
* As each caller might also be inside a methos there may be a large amount of combinations.
|
||||
*/
|
||||
public static class AliveCombinations {
|
||||
|
||||
private Collection<AliveCombination> combinations;
|
||||
/**
|
||||
* All call-paths to the procedure containing the statement.
|
||||
*/
|
||||
private CallPaths callPaths;
|
||||
/**
|
||||
* All variables referenced in the procedure containing the statement.
|
||||
*/
|
||||
private Collection<VariableRef> referencedInProcedure;
|
||||
/**
|
||||
* Variables alive at the statement inside the procedure.
|
||||
*/
|
||||
private Collection<VariableRef> aliveAtStmt;
|
||||
|
||||
public AliveCombinations(Collection<Collection<VariableRef>> aliveCombinations) {
|
||||
ArrayList<AliveCombination> combinations = new ArrayList<>();
|
||||
for (Collection<VariableRef> aliveCombination : aliveCombinations) {
|
||||
combinations.add(new AliveCombination(aliveCombination));
|
||||
}
|
||||
this.combinations = combinations;
|
||||
public AliveCombinations(CallPaths callPaths, Collection<VariableRef> referencedInProcedure, Collection<VariableRef> aliveAtStmt) {
|
||||
this.callPaths = callPaths;
|
||||
this.referencedInProcedure = referencedInProcedure;
|
||||
this.aliveAtStmt = aliveAtStmt;
|
||||
}
|
||||
|
||||
public Collection<AliveCombination> getCombinations() {
|
||||
return combinations;
|
||||
public CallPaths getCallPaths() {
|
||||
return callPaths;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** One single combinations of variables effectively alive at a specific statement. */
|
||||
public static class AliveCombination {
|
||||
|
||||
private Collection<VariableRef> alive;
|
||||
|
||||
public AliveCombination(Collection<VariableRef> alive) {
|
||||
this.alive = alive;
|
||||
public Collection<VariableRef> getReferencedInProcedure() {
|
||||
return referencedInProcedure;
|
||||
}
|
||||
|
||||
public Collection<VariableRef> getAlive() {
|
||||
return alive;
|
||||
public Collection<VariableRef> getAliveAtStmt() {
|
||||
return aliveAtStmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all variables effective alive at the statement for a specific call path.
|
||||
* @param callPath The call path (returned from getCallPaths)
|
||||
* @return All variables effectively alive at the statement on the call-path
|
||||
*/
|
||||
public Collection<VariableRef> getEffectiveAliveAtStmt(CallPath callPath) {
|
||||
LinkedHashSet<VariableRef> effectiveAlive = new LinkedHashSet<>();
|
||||
// Add alive at call
|
||||
effectiveAlive.addAll(callPath.getAlive());
|
||||
// Clear out any variables referenced in the method
|
||||
effectiveAlive.removeAll(referencedInProcedure);
|
||||
// Add alive at statement
|
||||
effectiveAlive.addAll(aliveAtStmt);
|
||||
return effectiveAlive;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ public class Procedure extends Scope {
|
||||
private final SymbolType returnType;
|
||||
private List<String> parameterNames;
|
||||
|
||||
public static final ProcedureRef ROOT = new ProcedureRef("");
|
||||
|
||||
public Procedure(String name, SymbolType returnType, Scope parentScope) {
|
||||
super(name, parentScope);
|
||||
this.returnType = returnType;
|
||||
|
@ -55,8 +55,8 @@ public abstract class StatementBase implements Statement {
|
||||
if(liveRangeVariablesEffective!=null) {
|
||||
LiveRangeVariablesEffective.AliveCombinations aliveCombinations = liveRangeVariablesEffective.getAliveCombinations(this);
|
||||
alive.append(" ( ");
|
||||
for (LiveRangeVariablesEffective.AliveCombination aliveCombination : aliveCombinations.getCombinations()) {
|
||||
alive.append(getAliveString(aliveCombination.getAlive()));
|
||||
for (LiveRangeVariablesEffective.CallPath callPath : aliveCombinations.getCallPaths().getCallPaths()) {
|
||||
alive.append(getAliveString(aliveCombinations.getEffectiveAliveAtStmt(callPath)));
|
||||
alive.append(" ");
|
||||
}
|
||||
alive.append(")");
|
||||
|
@ -19,7 +19,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
||||
*/
|
||||
@Override
|
||||
public boolean optimize() {
|
||||
final Aliases aliases = findAliases();
|
||||
final Aliases aliases = findAliases(getProgram(), false);
|
||||
removeAliasAssignments(aliases);
|
||||
replaceVariables(aliases.getReplacements());
|
||||
for (AliasSet aliasSet : aliases.getAliasSets()) {
|
||||
@ -88,6 +88,14 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
||||
this.aliases = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Aliases(Aliases aliases) {
|
||||
this.aliases = new ArrayList<>();
|
||||
for (AliasSet aliasSet : aliases.getAliasSets()) {
|
||||
AliasSet copySet = new AliasSet(aliasSet);
|
||||
this.aliases.add(copySet);
|
||||
}
|
||||
}
|
||||
|
||||
public List<VariableRef> getSymbolsToRemove() {
|
||||
ArrayList<VariableRef> eliminates = new ArrayList<>();
|
||||
for (AliasSet alias : aliases) {
|
||||
@ -159,6 +167,10 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
||||
this.vars = new ArrayList<>();
|
||||
}
|
||||
|
||||
public AliasSet(AliasSet aliasSet) {
|
||||
this.vars = new ArrayList<>(aliasSet.getVars());
|
||||
}
|
||||
|
||||
public void add(VariableRef variable) {
|
||||
vars.add(variable);
|
||||
}
|
||||
@ -226,16 +238,16 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
||||
}
|
||||
|
||||
|
||||
private Aliases findAliases() {
|
||||
Aliases candidates = findAliasesCandidates(false, getProgram());
|
||||
cleanupCandidates(candidates);
|
||||
public static Aliases findAliases(Program program, boolean allowCrossScope) {
|
||||
Aliases candidates = findAliasesCandidates(allowCrossScope, program);
|
||||
cleanupCandidates(candidates, program);
|
||||
return candidates;
|
||||
}
|
||||
|
||||
// Remove all candidates that are used after assignment in phi blocks
|
||||
private void cleanupCandidates(Aliases candidates) {
|
||||
private static void cleanupCandidates(Aliases candidates, Program program) {
|
||||
for (final AliasSet aliasSet : candidates.aliases) {
|
||||
for (ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for (ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
if(block.hasPhiBlock()) {
|
||||
StatementPhiBlock phi = block.getPhiBlock();
|
||||
boolean lMatch = false;
|
||||
@ -244,7 +256,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
||||
for (StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
|
||||
RValue rValue = phiRValue.getrValue();
|
||||
if (aliasSet.contains(rValue)) {
|
||||
getLog().append("Alias candidate removed " + rValue.toString(getProgram()));
|
||||
program.getLog().append("Alias candidate removed " + rValue.toString(program));
|
||||
aliasSet.remove(rValue);
|
||||
break;
|
||||
}
|
||||
@ -265,7 +277,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
|
||||
*
|
||||
* @return Map from Variable to the Constant value
|
||||
*/
|
||||
public static Aliases findAliasesCandidates(final boolean allowCrossScope, final Program program) {
|
||||
private static Aliases findAliasesCandidates(final boolean allowCrossScope, final Program program) {
|
||||
final Aliases aliases = new Aliases();
|
||||
final ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
@Override
|
||||
|
@ -9,29 +9,36 @@ import java.util.*;
|
||||
*/
|
||||
public class Pass3LiveRangesEffectiveAnalysis extends Pass2Base {
|
||||
|
||||
/**
|
||||
* Call-paths for all procedures.
|
||||
*/
|
||||
private Map<ProcedureRef, LiveRangeVariablesEffective.CallPaths> procedureCallPaths;
|
||||
|
||||
/**
|
||||
* Normal variable live ranges.
|
||||
*/
|
||||
private LiveRangeVariables liveRangeVariables;
|
||||
|
||||
/**
|
||||
* Information about which procedures reference which variables.
|
||||
*/
|
||||
private VariableReferenceInfo referenceInfo;
|
||||
|
||||
|
||||
public Pass3LiveRangesEffectiveAnalysis(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
public void findLiveRangesEffective() {
|
||||
LiveRangeVariablesEffective aliveEffective = findAliveEffective(getProgram());
|
||||
this.liveRangeVariables = getProgram().getLiveRangeVariables();
|
||||
this.referenceInfo = new VariableReferenceInfo(getProgram());
|
||||
this.procedureCallPaths = new LinkedHashMap<>();
|
||||
populateProcedureCallPaths();
|
||||
LiveRangeVariablesEffective aliveEffective = new LiveRangeVariablesEffective(getProgram(), procedureCallPaths, liveRangeVariables, referenceInfo);
|
||||
getProgram().setLiveRangeVariablesEffective(aliveEffective);
|
||||
//getLog().append("Calculated effective variable live ranges");
|
||||
}
|
||||
|
||||
private LiveRangeVariablesEffective findAliveEffective(Program program) {
|
||||
LiveRangeVariables liveRangeVariables = program.getLiveRangeVariables();
|
||||
Map<Integer, LiveRangeVariablesEffective.AliveCombinations> effectiveLiveVariablesCombinations = new HashMap<>();
|
||||
for (ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
for (Statement statement : block.getStatements()) {
|
||||
Collection<Collection<VariableRef>> statementAliveCombinations = findAliveEffective(liveRangeVariables, statement);
|
||||
LiveRangeVariablesEffective.AliveCombinations aliveCombinations = new LiveRangeVariablesEffective.AliveCombinations(statementAliveCombinations);
|
||||
effectiveLiveVariablesCombinations.put(statement.getIndex(), aliveCombinations);
|
||||
}
|
||||
}
|
||||
return new LiveRangeVariablesEffective(effectiveLiveVariablesCombinations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all variables alive at a statement.
|
||||
* If the statement is inside a method this also includes all variables alive at the exit of the calls.
|
||||
@ -54,7 +61,6 @@ public class Pass3LiveRangesEffectiveAnalysis extends Pass2Base {
|
||||
Procedure procedure = (Procedure) scope;
|
||||
Collection<CallGraph.CallBlock.Call> callers =
|
||||
getProgram().getCallGraph().getCallers(procedure.getLabel().getRef());
|
||||
VariableReferenceInfo referenceInfo = new VariableReferenceInfo(getProgram());
|
||||
Collection<VariableRef> referencedInProcedure = referenceInfo.getReferenced(procedure.getRef().getLabelRef());
|
||||
for (CallGraph.CallBlock.Call caller : callers) {
|
||||
// Each caller creates its own combinations
|
||||
@ -81,4 +87,76 @@ public class Pass3LiveRangesEffectiveAnalysis extends Pass2Base {
|
||||
return combinations;
|
||||
}
|
||||
|
||||
private void populateProcedureCallPaths() {
|
||||
this.procedureCallPaths = new LinkedHashMap<>();
|
||||
Collection<Procedure> procedures = getProgram().getScope().getAllProcedures(true);
|
||||
for (Procedure procedure : procedures) {
|
||||
populateProcedureCallPaths(procedure);
|
||||
}
|
||||
}
|
||||
|
||||
private void populateProcedureCallPaths(Procedure procedure) {
|
||||
ProcedureRef procedureRef = procedure.getRef();
|
||||
LiveRangeVariablesEffective.CallPaths callPaths = procedureCallPaths.get(procedureRef);
|
||||
if (callPaths == null) {
|
||||
callPaths = new LiveRangeVariablesEffective.CallPaths(procedureRef);
|
||||
Collection<CallGraph.CallBlock.Call> callers =
|
||||
getProgram().getCallGraph().getCallers(procedure.getLabel().getRef());
|
||||
ControlFlowBlock procedureBlock = getProgram().getGraph().getBlock(procedure.getLabel().getRef());
|
||||
StatementPhiBlock procedurePhiBlock = null;
|
||||
if(procedureBlock.hasPhiBlock()) {
|
||||
procedurePhiBlock = procedureBlock.getPhiBlock();
|
||||
}
|
||||
for (CallGraph.CallBlock.Call caller : callers) {
|
||||
// Each caller creates its own call-paths
|
||||
StatementCall callStatement =
|
||||
(StatementCall) getProgram().getGraph().getStatementByIndex(caller.getCallStatementIdx());
|
||||
ControlFlowBlock callBlock = getProgram().getGraph().getBlockFromStatementIdx(callStatement.getIndex());
|
||||
ScopeRef callScopeRef = callBlock.getScope();
|
||||
Scope callScope = getProgram().getScope().getScope(callScopeRef);
|
||||
if (callScope instanceof Procedure) {
|
||||
// Found calling procedure!
|
||||
Procedure callerProcedure = (Procedure) callScope;
|
||||
// Make sure we have populated the call-paths of the calling procedure
|
||||
populateProcedureCallPaths(callerProcedure);
|
||||
// Find variables referenced in caller procedure
|
||||
Collection<VariableRef> referencedInCaller = referenceInfo.getReferenced(callerProcedure.getRef().getLabelRef());
|
||||
// For each caller path - create a new call-path
|
||||
LiveRangeVariablesEffective.CallPaths callerPaths = procedureCallPaths.get(callerProcedure.getRef());
|
||||
for (LiveRangeVariablesEffective.CallPath callerPath : callerPaths.getCallPaths()) {
|
||||
ArrayList<CallGraph.CallBlock.Call> path = new ArrayList<>(callerPath.getPath());
|
||||
path.add(caller);
|
||||
Collection<VariableRef> alive = new LinkedHashSet<>();
|
||||
alive.addAll(callerPath.getAlive());
|
||||
alive.removeAll(referencedInCaller);
|
||||
alive.addAll(liveRangeVariables.getAlive(callStatement));
|
||||
Pass2AliasElimination.Aliases aliases = new Pass2AliasElimination.Aliases(callerPath.getAliases());
|
||||
if(procedurePhiBlock!=null) {
|
||||
for (StatementPhiBlock.PhiVariable phiVariable : procedurePhiBlock.getPhiVariables()) {
|
||||
RValue phiRvalue = phiVariable.getrValue(callBlock.getLabel());
|
||||
if (phiRvalue instanceof VariableRef) {
|
||||
aliases.add(phiVariable.getVariable(), (VariableRef) phiRvalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
LiveRangeVariablesEffective.CallPath callPath = new LiveRangeVariablesEffective.CallPath(path, alive, aliases);
|
||||
callPaths.add(callPath);
|
||||
}
|
||||
} else {
|
||||
// main() call outside procedure scope - create initial call-path.
|
||||
ArrayList<CallGraph.CallBlock.Call> rootPath = new ArrayList<>();
|
||||
rootPath.add(caller);
|
||||
ArrayList<VariableRef> rootAlive = new ArrayList<>();
|
||||
// Initialize with global cross-scope aliases
|
||||
Pass2AliasElimination.Aliases rootAliases = Pass2AliasElimination.findAliases(getProgram(), true);
|
||||
LiveRangeVariablesEffective.CallPath rootCallPath = new LiveRangeVariablesEffective.CallPath(rootPath, rootAlive, rootAliases);
|
||||
callPaths.add(rootCallPath);
|
||||
}
|
||||
}
|
||||
procedureCallPaths.put(procedureRef, callPaths);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -198,10 +198,9 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
||||
* @return true if the register allocation contains an overlapping allocation. false otherwise.
|
||||
*/
|
||||
public static boolean isAllocationOverlapping(Program program) {
|
||||
Pass2AliasElimination.Aliases aliases = Pass2AliasElimination.findAliasesCandidates(true, program);
|
||||
for (ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
for (Statement statement : block.getStatements()) {
|
||||
if (isStatementAllocationOverlapping(program, statement, aliases)) {
|
||||
if (isStatementAllocationOverlapping(program, statement)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -214,15 +213,15 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
||||
*
|
||||
* @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, Pass2AliasElimination.Aliases aliases) {
|
||||
private static boolean isStatementAllocationOverlapping(Program program, Statement statement) {
|
||||
ProgramScope programScope = program.getScope();
|
||||
LiveRangeVariablesEffective.AliveCombinations aliveCombinations = program.getLiveRangeVariablesEffective().getAliveCombinations(statement);
|
||||
for (LiveRangeVariablesEffective.AliveCombination aliveCombination : aliveCombinations.getCombinations()) {
|
||||
for (LiveRangeVariablesEffective.CallPath callPath : aliveCombinations.getCallPaths().getCallPaths()) {
|
||||
LinkedHashMap<Registers.Register, LiveRangeEquivalenceClass> usedRegisters = new LinkedHashMap<>();
|
||||
Collection<VariableRef> alive = aliveCombination.getAlive();
|
||||
Collection<VariableRef> alive = aliveCombinations.getEffectiveAliveAtStmt(callPath);
|
||||
Pass2AliasElimination.Aliases callPathAliases = callPath.getAliases();
|
||||
for (VariableRef varRef : alive) {
|
||||
Variable var = programScope.getVariable(varRef);
|
||||
Registers.Register allocation = var.getAllocation();
|
||||
@ -230,7 +229,7 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
||||
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 = aliases.findAliasSet(varRef);
|
||||
Pass2AliasElimination.AliasSet aliasSet = callPathAliases.findAliasSet(varRef);
|
||||
if(aliasSet!=null) {
|
||||
for (VariableRef aliasVar : aliasSet.getVars()) {
|
||||
if(allocationClass.contains(aliasVar)) {
|
||||
|
@ -28,9 +28,6 @@ public class TestErrors extends TestCase {
|
||||
compileAndCompare("inline-asm-param");
|
||||
}
|
||||
|
||||
public void testOverlapAllocation() throws IOException, URISyntaxException {
|
||||
compileAndCompare("overlap-allocation");
|
||||
}
|
||||
|
||||
public void testIncD020() throws IOException, URISyntaxException {
|
||||
compileAndCompare("incd020");
|
||||
|
@ -24,6 +24,10 @@ public class TestPrograms extends TestCase {
|
||||
helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/");
|
||||
}
|
||||
|
||||
public void testOverlapAllocation() throws IOException, URISyntaxException {
|
||||
compileAndCompare("overlap-allocation");
|
||||
}
|
||||
|
||||
public void testBitmapBresenham() throws IOException, URISyntaxException {
|
||||
compileAndCompare("bitmap-bresenham");
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.const SCREEN = $400
|
||||
jsr main
|
||||
main: {
|
||||
ldx #0
|
||||
b1:
|
||||
jsr plot
|
||||
inx
|
||||
cpx #$b
|
||||
bne b1
|
||||
ldx #0
|
||||
b2:
|
||||
jsr plot
|
||||
inx
|
||||
cpx #$b
|
||||
bne b2
|
||||
ldx #0
|
||||
b3:
|
||||
jsr plot
|
||||
inx
|
||||
cpx #$b
|
||||
bne b3
|
||||
rts
|
||||
}
|
||||
plot: {
|
||||
lda #'*'
|
||||
sta SCREEN,x
|
||||
rts
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
@begin: scope:[] from
|
||||
to:@2
|
||||
@2: scope:[] from @begin
|
||||
[0] call main param-assignment [ ] ( )
|
||||
to:@end
|
||||
@end: scope:[] from @2
|
||||
main: scope:[main] from @2
|
||||
[1] phi() [ ] ( [ ] )
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@7
|
||||
[2] (byte) main::i#2 ← phi( main/(byte) 0 main::@7/(byte) main::i#1 ) [ main::i#2 ] ( [ main::i#2 ] )
|
||||
[3] (byte) plot::x#0 ← (byte) main::i#2 [ main::i#2 plot::x#0 ] ( [ main::i#2 plot::x#0 ] )
|
||||
[4] call plot param-assignment [ main::i#2 ] ( [ main::i#2 ] )
|
||||
to:main::@7
|
||||
main::@7: scope:[main] from main::@1
|
||||
[5] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 ] ( [ main::i#1 ] )
|
||||
[6] if((byte) main::i#1!=(byte) 11) goto main::@1 [ main::i#1 ] ( [ main::i#1 ] )
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@7 main::@8
|
||||
[7] (byte) main::j#2 ← phi( main::@7/(byte) 0 main::@8/(byte) main::j#1 ) [ main::j#2 ] ( [ main::j#2 ] )
|
||||
[8] (byte) plot::x#1 ← (byte) main::j#2 [ main::j#2 plot::x#1 ] ( [ main::j#2 plot::x#1 ] )
|
||||
[9] call plot param-assignment [ main::j#2 ] ( [ main::j#2 ] )
|
||||
to:main::@8
|
||||
main::@8: scope:[main] from main::@2
|
||||
[10] (byte) main::j#1 ← ++ (byte) main::j#2 [ main::j#1 ] ( [ main::j#1 ] )
|
||||
[11] if((byte) main::j#1!=(byte) 11) goto main::@2 [ main::j#1 ] ( [ main::j#1 ] )
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@8 main::@9
|
||||
[12] (byte) main::k#2 ← phi( main::@8/(byte) 0 main::@9/(byte) main::k#1 ) [ main::k#2 ] ( [ main::k#2 ] )
|
||||
[13] (byte) plot::x#2 ← (byte) main::k#2 [ main::k#2 plot::x#2 ] ( [ main::k#2 plot::x#2 ] )
|
||||
[14] call plot param-assignment [ main::k#2 ] ( [ main::k#2 ] )
|
||||
to:main::@9
|
||||
main::@9: scope:[main] from main::@3
|
||||
[15] (byte) main::k#1 ← ++ (byte) main::k#2 [ main::k#1 ] ( [ main::k#1 ] )
|
||||
[16] if((byte) main::k#1!=(byte) 11) goto main::@3 [ main::k#1 ] ( [ main::k#1 ] )
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@9
|
||||
[17] return [ ] ( [ ] )
|
||||
to:@return
|
||||
plot: scope:[plot] from main::@1 main::@2 main::@3
|
||||
[18] (byte) plot::x#3 ← phi( main::@1/(byte) plot::x#0 main::@2/(byte) plot::x#1 main::@3/(byte) plot::x#2 ) [ plot::x#3 ] ( [ main::i#2 plot::x#3 ] [ main::j#2 plot::x#3 ] [ main::k#2 plot::x#3 ] )
|
||||
[19] *((const byte*) SCREEN#0 + (byte) plot::x#3) ← (byte) '*' [ ] ( [ main::i#2 ] [ main::j#2 ] [ main::k#2 ] )
|
||||
to:plot::@return
|
||||
plot::@return: scope:[plot] from plot
|
||||
[20] return [ ] ( [ main::i#2 ] [ main::j#2 ] [ main::k#2 ] )
|
||||
to:@return
|
2039
src/main/java/dk/camelot64/kickc/test/ref/overlap-allocation.log
Normal file
2039
src/main/java/dk/camelot64/kickc/test/ref/overlap-allocation.log
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,34 @@
|
||||
(label) @2
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(byte*) SCREEN
|
||||
(const byte*) SCREEN#0 SCREEN = (word) 1024
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@7
|
||||
(label) main::@8
|
||||
(label) main::@9
|
||||
(label) main::@return
|
||||
(byte) main::i
|
||||
(byte) main::i#1 reg byte x 16.5
|
||||
(byte) main::i#2 reg byte x 11.0
|
||||
(byte) main::j
|
||||
(byte) main::j#1 reg byte x 16.5
|
||||
(byte) main::j#2 reg byte x 11.0
|
||||
(byte) main::k
|
||||
(byte) main::k#1 reg byte x 16.5
|
||||
(byte) main::k#2 reg byte x 11.0
|
||||
(void()) plot((byte) plot::x)
|
||||
(label) plot::@return
|
||||
(byte) plot::x
|
||||
(byte) plot::x#0 reg byte x 22.0
|
||||
(byte) plot::x#1 reg byte x 22.0
|
||||
(byte) plot::x#2 reg byte x 22.0
|
||||
(byte) plot::x#3 reg byte x 35.0
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
||||
reg byte x [ main::j#2 main::j#1 ]
|
||||
reg byte x [ main::k#2 main::k#1 ]
|
||||
reg byte x [ plot::x#3 plot::x#0 plot::x#1 plot::x#2 ]
|
Loading…
Reference in New Issue
Block a user