1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-02-04 15:31:16 +00:00

Refactored effectively alive vars into an interface for experimenting with less memory-intensive implementation.

This commit is contained in:
jespergravgaard 2020-03-08 16:14:20 +01:00
parent afe8294cd1
commit 7726c1d43f
7 changed files with 502 additions and 398 deletions

View File

@ -0,0 +1,8 @@
lda {c1}
asl
sta {m1}
lda {c1}+1
rol
sta {m1}+1
asl {m1}
rol {m1}+1

View File

@ -1,381 +1,36 @@
package dk.camelot64.kickc.model;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.symbols.Scope;
import dk.camelot64.kickc.model.values.LabelRef;
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 java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Effective variable live ranges for all statements.
* (Including variables alive in calling methods).
* Created by {@link PassNCalcLiveRangesEffective}
*/
public class LiveRangeVariablesEffective {
public interface LiveRangeVariablesEffective {
/**
* The program.
*/
private Program program;
Collection<VariableRef> getAliveEffective(Statement statement);
/**
* Call-paths for all procedures.
*/
private Map<ProcedureRef, CallPaths> procedureCallPaths;
/** Variables (normally) alive at each statement by index. */
private Map<Integer, Collection<VariableRef>> statementLiveVariables;
/**
* Information about which procedures reference which variables.
*/
private VariableReferenceInfos referenceInfo;
public LiveRangeVariablesEffective(Program program, Map<ProcedureRef, CallPaths> procedureCallPaths, LiveRangeVariables liveRangeVariables, VariableReferenceInfos referenceInfo) {
this.program = program;
this.procedureCallPaths = procedureCallPaths;
this.referenceInfo = referenceInfo;
this.statementLiveVariables = new LinkedHashMap<>();
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
for(Statement statement : block.getStatements()) {
statementLiveVariables.put(statement.getIndex(), liveRangeVariables.getAlive(statement.getIndex()));
}
}
}
/** Cached alive effective by statement index. */
Map<Integer, Collection<VariableRef>> statementAliveEffective = new LinkedHashMap<>();
/**
* 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) {
Collection<VariableRef> effectiveAliveTotal = statementAliveEffective.get(statement.getIndex());
if(effectiveAliveTotal == null) {
effectiveAliveTotal = new LinkedHashSet<>();
AliveCombinations aliveCombinations = getAliveCombinations(statement);
for(CallPath callPath : aliveCombinations.getCallPaths().getCallPaths()) {
Collection<VariableRef> alive = aliveCombinations.getEffectiveAliveAtStmt(callPath);
effectiveAliveTotal.addAll(alive);
}
statementAliveEffective.put(statement.getIndex(), effectiveAliveTotal);
}
return effectiveAliveTotal;
}
/** Cached alive combinations. */
Map<Integer, AliveCombinations> statementAliveCombinations = new LinkedHashMap<>();
/** Special procedure reference used to represent the ROOT scope during live range analysis. */
static final ProcedureRef ROOT_PROCEDURE = new ProcedureRef("");
/**
* Get all combinations of variables alive at a statement.
* If the statement is inside a method the different combinations in the result arises from different calls of the method
* (recursively up til the main()-method.)
* Each combination includes all variables alive at the exit of any surrounding call.
* Also includes variable aliases that are part of the parameter assignments to the calls on the path.
* </p>
*
* @param statement The statement to examine
* @return All combinations of variables alive at the statement
*/
public AliveCombinations getAliveCombinations(Statement statement) {
AliveCombinations stmtCombinations = this.statementAliveCombinations.get(statement.getIndex());
if(stmtCombinations == null) {
Collection<VariableRef> aliveAtStmt = statementLiveVariables.get(statement.getIndex());
CallPaths callPaths;
Collection<VariableRef> referencedInProcedure;
ControlFlowBlock block = program.getStatementInfos().getBlock(statement);
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.getReferencedVars(procedure.getRef().getLabelRef());
} else {
callPaths = new CallPaths(ROOT_PROCEDURE);
// Interrupt is called outside procedure scope - create initial call-path.
ArrayList<CallGraph.CallBlock.Call> rootPath = new ArrayList<>();
ArrayList<VariableRef> rootAlive = new ArrayList<>();
// Initialize with global cross-scope aliases (assumed empty)
Pass2AliasElimination.Aliases rootAliases = new Pass2AliasElimination.Aliases();
LiveRangeVariablesEffective.CallPath rootCallPath = new LiveRangeVariablesEffective.CallPath(rootPath, rootAlive, rootAliases, rootAliases);
callPaths.add(rootCallPath);
referencedInProcedure = new ArrayList<>();
}
Pass2AliasElimination.Aliases callAliases = null;
// Examine if the statement is a parameter assignment before a call
LabelRef callSuccessor = block.getCallSuccessor();
if(callSuccessor != null) {
ProcedureRef calledRef = new ProcedureRef(callSuccessor.getFullName());
CallPaths calledRefs = procedureCallPaths.get(calledRef);
for(CallPath calledPath : calledRefs.getCallPaths()) {
List<CallGraph.CallBlock.Call> path = calledPath.getPath();
if(path.size() > 0) {
CallGraph.CallBlock.Call lastCall = path.get(path.size() - 1);
Integer lastCallStatementIdx = lastCall.getCallStatementIdx();
LabelRef lastCallBlockRef = program.getStatementInfos().getBlockRef(lastCallStatementIdx);
if(lastCallBlockRef.equals(block.getLabel())) {
if(callAliases == null) {
// Found a matching call!
callAliases = calledPath.getInnerAliases();
} else {
// Found another matching call!
callAliases = new Pass2AliasElimination.Aliases(callAliases);
callAliases.addAll(calledPath.getInnerAliases());
}
}
}
}
}
stmtCombinations = new AliveCombinations(callPaths, referencedInProcedure, aliveAtStmt, callAliases);
statementAliveCombinations.put(statement.getIndex(), stmtCombinations);
}
return stmtCombinations;
}
public String getSizeInfo() {
StringBuilder sizeInfo = new StringBuilder();
if(this.procedureCallPaths != null) {
AtomicInteger numCallPaths = new AtomicInteger();
this.procedureCallPaths.values().forEach(callPaths -> numCallPaths.addAndGet(callPaths.getCallPaths().size()));
sizeInfo.append("SIZE procedureCallPaths ").append(numCallPaths.get()).append("\n");
}
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");
}
if(this.statementAliveCombinations != null) {
sizeInfo.append("SIZE statementAliveCombinations ").append(statementAliveCombinations.size()).append(" statements ");
int subVarRef = 0;
int subAlias = 0;
int subCallPath = 0;
int subEffectiveVarRef = 0;
for(AliveCombinations aliveCombinations : statementAliveCombinations.values()) {
subVarRef += aliveCombinations.aliveAtStmt.size();
subVarRef += aliveCombinations.referencedInProcedure.size();
if(aliveCombinations.callAliases!=null)
subAlias += aliveCombinations.callAliases.size();
if(aliveCombinations.callPaths.callPaths!=null)
subCallPath += aliveCombinations.callPaths.callPaths.size();
if(aliveCombinations.effectiveAliveAtStmt!=null)
for(Collection<VariableRef> varRefs : aliveCombinations.effectiveAliveAtStmt.values()) {
subEffectiveVarRef += varRefs.size();
}
}
sizeInfo.append(" ").append(subVarRef).append(" varrefs ");
sizeInfo.append(" ").append(subAlias).append(" aliases ");
sizeInfo.append(" ").append(subCallPath).append(" callpaths ");
sizeInfo.append(" ").append(subEffectiveVarRef).append(" eff-varrefs ");
sizeInfo.append("\n");
}
return sizeInfo.toString();
}
/**
* 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 the 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 for the innermost call. Variables alias-assigned as part of the innermost call on the path (in parameter assignment or phi block).
*/
private Pass2AliasElimination.Aliases innerAliases;
/**
* Alias variables from the entire call-path. Any variables alias-assigned as part of a call on the path (in parameter assignment or phi block).
*/
private Pass2AliasElimination.Aliases pathAliases;
public CallPath(List<CallGraph.CallBlock.Call> path, Collection<VariableRef> alive, Pass2AliasElimination.Aliases innerAliases, Pass2AliasElimination.Aliases pathAliases) {
this.path = path;
this.alive = alive;
this.innerAliases = innerAliases;
this.pathAliases = pathAliases;
}
/**
* 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 from the entire call-path. Any variables alias-assigned as part of a call on the path (in parameter assignment or phi block).
*
* @return The aliases
*/
public Pass2AliasElimination.Aliases getPathAliases() {
return pathAliases;
}
/**
* Alias variables for the innermost call. Variables alias-assigned as part of the innermost call on the path (in parameter assignment or phi block).
*
* @return The aliases
*/
public Pass2AliasElimination.Aliases getInnerAliases() {
return innerAliases;
}
@Override
public boolean equals(Object o) {
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
CallPath callPath = (CallPath) o;
return Objects.equals(path, callPath.path);
}
@Override
public int hashCode() {
return Objects.hash(path);
}
}
AliveCombinations getAliveCombinations(Statement 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 {
interface AliveCombinations {
/**
* All call-paths to the procedure containing the statement.
* Get all effective alive combinations for a specific statement.
* @return All effective alive combinations
*/
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;
/**
* If the statement is an assignment to a call parameter this contains the aliases for that specific call.
*/
private Pass2AliasElimination.Aliases callAliases;
Collection<AliveCombination> getAll();
/** Effective alive variables for each call path. */
private Map<CallPath, Collection<VariableRef>> effectiveAliveAtStmt;
public AliveCombinations(CallPaths callPaths, Collection<VariableRef> referencedInProcedure, Collection<VariableRef> aliveAtStmt, Pass2AliasElimination.Aliases callAliases) {
this.callPaths = callPaths;
this.referencedInProcedure = referencedInProcedure;
this.aliveAtStmt = aliveAtStmt;
this.callAliases = callAliases;
// Initialize the effective alive at statment per call-path
this.effectiveAliveAtStmt = new LinkedHashMap<>();
for(CallPath callPath : callPaths.getCallPaths()) {
// Add alive at call
LinkedHashSet<VariableRef> effectiveAlive = new LinkedHashSet<>();
// Add alive through the call path
effectiveAlive.addAll(callPath.getAlive());
// Clear out any variables referenced in the method
effectiveAlive.removeAll(referencedInProcedure);
// Add alive at statement
effectiveAlive.addAll(aliveAtStmt);
// Store the effective alive vars
effectiveAliveAtStmt.put(callPath, effectiveAlive);
}
}
public CallPaths getCallPaths() {
return callPaths;
}
/**
* 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) {
return effectiveAliveAtStmt.get(callPath);
}
public Pass2AliasElimination.Aliases getEffectiveAliasesAtStmt(CallPath callPath) {
if(callAliases == null) {
return callPath.getPathAliases();
} else {
Pass2AliasElimination.Aliases aliases = new Pass2AliasElimination.Aliases();
aliases.addAll(callPath.getPathAliases());
aliases.addAll(callAliases);
return aliases;
}
}
}
/** An alive combination at a specific statement */
interface AliveCombination {
Collection<VariableRef> getEffectiveAliveAtStmt();
Pass2AliasElimination.Aliases getEffectiveAliasesAtStmt();
}
}

View File

@ -0,0 +1,453 @@
package dk.camelot64.kickc.model;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.symbols.Scope;
import dk.camelot64.kickc.model.values.LabelRef;
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 java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Effective variable live ranges for all statements.
* (Including variables alive in calling methods).
* Created by {@link PassNCalcLiveRangesEffective}
*/
public class LiveRangeVariablesEffectiveCallPaths implements LiveRangeVariablesEffective {
/**
* The program.
*/
private Program program;
/**
* Call-paths for all procedures.
*/
private Map<ProcedureRef, CallPaths> procedureCallPaths;
/** Variables (normally) alive at each statement by index. */
private Map<Integer, Collection<VariableRef>> statementLiveVariables;
/**
* Information about which procedures reference which variables.
*/
private VariableReferenceInfos referenceInfo;
public LiveRangeVariablesEffectiveCallPaths(Program program, Map<ProcedureRef, CallPaths> procedureCallPaths, LiveRangeVariables liveRangeVariables, VariableReferenceInfos referenceInfo) {
this.program = program;
this.procedureCallPaths = procedureCallPaths;
this.referenceInfo = referenceInfo;
this.statementLiveVariables = new LinkedHashMap<>();
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
for(Statement statement : block.getStatements()) {
statementLiveVariables.put(statement.getIndex(), liveRangeVariables.getAlive(statement.getIndex()));
}
}
}
/** Cached alive effective by statement index. */
private Map<Integer, Collection<VariableRef>> statementAliveEffective = new LinkedHashMap<>();
/**
* 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) {
Collection<VariableRef> effectiveAliveTotal = statementAliveEffective.get(statement.getIndex());
if(effectiveAliveTotal == null) {
effectiveAliveTotal = new LinkedHashSet<>();
AliveCombinations aliveCombinations = getAliveCombinations(statement);
for(AliveCombination combination : aliveCombinations.getAll()) {
Collection<VariableRef> alive = combination.getEffectiveAliveAtStmt();
effectiveAliveTotal.addAll(alive);
}
statementAliveEffective.put(statement.getIndex(), effectiveAliveTotal);
}
return effectiveAliveTotal;
}
/** Cached alive combinations. */
private Map<Integer, AliveCombinationsCallPath> statementAliveCombinations = new LinkedHashMap<>();
/** Special procedure reference used to represent the ROOT scope during live range analysis. */
private static final ProcedureRef ROOT_PROCEDURE = new ProcedureRef("");
/**
* Get all combinations of variables alive at a statement.
* If the statement is inside a method the different combinations in the result arises from different calls of the method
* (recursively up til the main()-method.)
* Each combination includes all variables alive at the exit of any surrounding call.
* Also includes variable aliases that are part of the parameter assignments to the calls on the path.
* </p>
*
* @param statement The statement to examine
* @return All combinations of variables alive at the statement
*/
@Override
public AliveCombinationsCallPath getAliveCombinations(Statement statement) {
AliveCombinationsCallPath stmtCombinations = this.statementAliveCombinations.get(statement.getIndex());
if(stmtCombinations == null) {
Collection<VariableRef> aliveAtStmt = statementLiveVariables.get(statement.getIndex());
CallPaths callPaths;
Collection<VariableRef> referencedInProcedure;
ControlFlowBlock block = program.getStatementInfos().getBlock(statement);
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.getReferencedVars(procedure.getRef().getLabelRef());
} else {
callPaths = new CallPaths(ROOT_PROCEDURE);
// Interrupt is called outside procedure scope - create initial call-path.
ArrayList<CallGraph.CallBlock.Call> rootPath = new ArrayList<>();
ArrayList<VariableRef> rootAlive = new ArrayList<>();
// Initialize with global cross-scope aliases (assumed empty)
Pass2AliasElimination.Aliases rootAliases = new Pass2AliasElimination.Aliases();
LiveRangeVariablesEffectiveCallPaths.CallPath rootCallPath = new LiveRangeVariablesEffectiveCallPaths.CallPath(rootPath, rootAlive, rootAliases, rootAliases);
callPaths.add(rootCallPath);
referencedInProcedure = new ArrayList<>();
}
Pass2AliasElimination.Aliases callAliases = null;
// Examine if the statement is a parameter assignment before a call
LabelRef callSuccessor = block.getCallSuccessor();
if(callSuccessor != null) {
ProcedureRef calledRef = new ProcedureRef(callSuccessor.getFullName());
CallPaths calledRefs = procedureCallPaths.get(calledRef);
for(CallPath calledPath : calledRefs.getCallPaths()) {
List<CallGraph.CallBlock.Call> path = calledPath.getPath();
if(path.size() > 0) {
CallGraph.CallBlock.Call lastCall = path.get(path.size() - 1);
Integer lastCallStatementIdx = lastCall.getCallStatementIdx();
LabelRef lastCallBlockRef = program.getStatementInfos().getBlockRef(lastCallStatementIdx);
if(lastCallBlockRef.equals(block.getLabel())) {
if(callAliases == null) {
// Found a matching call!
callAliases = calledPath.getInnerAliases();
} else {
// Found another matching call!
callAliases = new Pass2AliasElimination.Aliases(callAliases);
callAliases.addAll(calledPath.getInnerAliases());
}
}
}
}
}
stmtCombinations = new AliveCombinationsCallPath(callPaths, referencedInProcedure, aliveAtStmt, callAliases);
statementAliveCombinations.put(statement.getIndex(), stmtCombinations);
}
return stmtCombinations;
}
String getSizeInfo() {
StringBuilder sizeInfo = new StringBuilder();
if(this.procedureCallPaths != null) {
AtomicInteger numCallPaths = new AtomicInteger();
this.procedureCallPaths.values().forEach(callPaths -> numCallPaths.addAndGet(callPaths.getCallPaths().size()));
sizeInfo.append("SIZE procedureCallPaths ").append(numCallPaths.get()).append("\n");
}
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");
}
if(this.statementAliveCombinations != null) {
sizeInfo.append("SIZE statementAliveCombinations ").append(statementAliveCombinations.size()).append(" statements ");
int subVarRef = 0;
int subAlias = 0;
int subCallPath = 0;
int subEffectiveVarRef = 0;
for(AliveCombinationsCallPath aliveCombinations : statementAliveCombinations.values()) {
subVarRef += aliveCombinations.aliveAtStmt.size();
subVarRef += aliveCombinations.referencedInProcedure.size();
if(aliveCombinations.callAliases != null)
subAlias += aliveCombinations.callAliases.size();
if(aliveCombinations.callPaths.callPaths != null)
subCallPath += aliveCombinations.callPaths.callPaths.size();
if(aliveCombinations.effectiveAliveAtStmt != null)
for(Collection<VariableRef> varRefs : aliveCombinations.effectiveAliveAtStmt.values()) {
subEffectiveVarRef += varRefs.size();
}
}
sizeInfo.append(" ").append(subVarRef).append(" varrefs ");
sizeInfo.append(" ").append(subAlias).append(" aliases ");
sizeInfo.append(" ").append(subCallPath).append(" callpaths ");
sizeInfo.append(" ").append(subEffectiveVarRef).append(" eff-varrefs ");
sizeInfo.append("\n");
}
return sizeInfo.toString();
}
/**
* 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 the 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 for the innermost call. Variables alias-assigned as part of the innermost call on the path (in parameter assignment or phi block).
*/
private Pass2AliasElimination.Aliases innerAliases;
/**
* Alias variables from the entire call-path. Any variables alias-assigned as part of a call on the path (in parameter assignment or phi block).
*/
private Pass2AliasElimination.Aliases pathAliases;
public CallPath(List<CallGraph.CallBlock.Call> path, Collection<VariableRef> alive, Pass2AliasElimination.Aliases innerAliases, Pass2AliasElimination.Aliases pathAliases) {
this.path = path;
this.alive = alive;
this.innerAliases = innerAliases;
this.pathAliases = pathAliases;
}
/**
* 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 from the entire call-path. Any variables alias-assigned as part of a call on the path (in parameter assignment or phi block).
*
* @return The aliases
*/
public Pass2AliasElimination.Aliases getPathAliases() {
return pathAliases;
}
/**
* Alias variables for the innermost call. Variables alias-assigned as part of the innermost call on the path (in parameter assignment or phi block).
*
* @return The aliases
*/
Pass2AliasElimination.Aliases getInnerAliases() {
return innerAliases;
}
@Override
public boolean equals(Object o) {
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
CallPath callPath = (CallPath) o;
return Objects.equals(path, callPath.path);
}
@Override
public int hashCode() {
return Objects.hash(path);
}
}
/**
* 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 method there may be a large amount of combinations.
*/
public static class AliveCombinationsCallPath implements AliveCombinations {
/**
* All call-paths to the procedure containing the statement.
*/
private LiveRangeVariablesEffectiveCallPaths.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;
/**
* If the statement is an assignment to a call parameter this contains the aliases for that specific call.
*/
private Pass2AliasElimination.Aliases callAliases;
/** Effective alive variables for each call path. */
private Map<LiveRangeVariablesEffectiveCallPaths.CallPath, Collection<VariableRef>> effectiveAliveAtStmt;
AliveCombinationsCallPath(LiveRangeVariablesEffectiveCallPaths.CallPaths callPaths, Collection<VariableRef> referencedInProcedure, Collection<VariableRef> aliveAtStmt, Pass2AliasElimination.Aliases callAliases) {
this.callPaths = callPaths;
this.referencedInProcedure = referencedInProcedure;
this.aliveAtStmt = aliveAtStmt;
this.callAliases = callAliases;
// Initialize the effective alive at statement per call-path
this.effectiveAliveAtStmt = new LinkedHashMap<>();
for(LiveRangeVariablesEffectiveCallPaths.CallPath callPath : callPaths.getCallPaths()) {
// Add alive at call
LinkedHashSet<VariableRef> effectiveAlive = new LinkedHashSet<>();
// Add alive through the call path
effectiveAlive.addAll(callPath.getAlive());
// Clear out any variables referenced in the method
effectiveAlive.removeAll(referencedInProcedure);
// Add alive at statement
effectiveAlive.addAll(aliveAtStmt);
// Store the effective alive vars
effectiveAliveAtStmt.put(callPath, effectiveAlive);
}
}
public LiveRangeVariablesEffectiveCallPaths.CallPaths getCallPaths() {
return callPaths;
}
/**
* 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
*/
Collection<VariableRef> getEffectiveAliveAtStmt(LiveRangeVariablesEffectiveCallPaths.CallPath callPath) {
return effectiveAliveAtStmt.get(callPath);
}
Pass2AliasElimination.Aliases getEffectiveAliasesAtStmt(LiveRangeVariablesEffectiveCallPaths.CallPath callPath) {
if(callAliases == null) {
return callPath.getPathAliases();
} else {
Pass2AliasElimination.Aliases aliases = new Pass2AliasElimination.Aliases();
aliases.addAll(callPath.getPathAliases());
aliases.addAll(callAliases);
return aliases;
}
}
/**
* Get all effective alive combinations for a specific statement.
*
* @return All effective alive combinations
*/
public Collection<LiveRangeVariablesEffective.AliveCombination> getAll() {
final ArrayList<LiveRangeVariablesEffective.AliveCombination> aliveCombinations = new ArrayList<>();
for(LiveRangeVariablesEffectiveCallPaths.CallPath callPath : callPaths.getCallPaths()) {
aliveCombinations.add(new AliveCombinationCallPath(callPath, getEffectiveAliveAtStmt(callPath), getEffectiveAliasesAtStmt(callPath)));
}
return aliveCombinations;
}
}
/** An alive combination at a specific statement */
public static class AliveCombinationCallPath implements LiveRangeVariablesEffective.AliveCombination {
private LiveRangeVariablesEffectiveCallPaths.CallPath callPath;
private Collection<VariableRef> effectiveAliveAtStmt;
private Pass2AliasElimination.Aliases effectiveAliasesAtStmt;
AliveCombinationCallPath(LiveRangeVariablesEffectiveCallPaths.CallPath callPath, Collection<VariableRef> effectiveAliveAtStmt, Pass2AliasElimination.Aliases effectiveAliasesAtStmt) {
this.callPath = callPath;
this.effectiveAliveAtStmt = effectiveAliveAtStmt;
this.effectiveAliasesAtStmt = effectiveAliasesAtStmt;
}
public LiveRangeVariablesEffectiveCallPaths.CallPath getCallPath() {
return callPath;
}
public Collection<VariableRef> getEffectiveAliveAtStmt() {
return effectiveAliveAtStmt;
}
public Pass2AliasElimination.Aliases getEffectiveAliasesAtStmt() {
return effectiveAliasesAtStmt;
}
@Override
public String toString() {
StringBuilder out = new StringBuilder();
out.append(getCallPathString(callPath.getPath()));
out.append(getAliveString(getEffectiveAliveAtStmt()));
return out.toString();
}
private String getCallPathString(List<CallGraph.CallBlock.Call> path) {
StringBuilder out = new StringBuilder();
boolean first = true;
for(CallGraph.CallBlock.Call call : path) {
if(!first) {
out.append("::");
}
first = false;
out.append(call.toString());
}
return out.toString();
}
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();
}
}
}

View File

@ -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 LiveRangeVariablesEffective liveRangeVariablesEffective;
private LiveRangeVariablesEffectiveCallPaths 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) */

View File

@ -5,6 +5,7 @@ import dk.camelot64.kickc.model.values.VariableRef;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
/** Statement base class implementing shared properties and logic */
public abstract class StatementBase implements Statement {
@ -57,12 +58,14 @@ public abstract class StatementBase implements Statement {
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
StatementBase that = (StatementBase) o;
return index != null ? index.equals(that.index) : that.index == null;
return Objects.equals(source, that.source) &&
Objects.equals(index, that.index) &&
Objects.equals(comments, that.comments);
}
@Override
public int hashCode() {
return index != null ? index.hashCode() : 0;
return Objects.hash(source, index, comments);
}
public String idxString() {
@ -83,33 +86,17 @@ public abstract class StatementBase implements Statement {
alive.append(getAliveString(liveRanges.getAlive(index)));
if(program.hasLiveRangeVariablesEffective()) {
LiveRangeVariablesEffective liveRangeVariablesEffective = program.getLiveRangeVariablesEffective();
if(liveRangeVariablesEffective != null) {
LiveRangeVariablesEffective.AliveCombinations aliveCombinations = liveRangeVariablesEffective.getAliveCombinations(this);
alive.append(" ( ");
for(LiveRangeVariablesEffective.CallPath callPath : aliveCombinations.getCallPaths().getCallPaths()) {
alive.append(getCallPathString(callPath.getPath()));
alive.append(getAliveString(aliveCombinations.getEffectiveAliveAtStmt(callPath)));
alive.append(" ");
}
alive.append(")");
LiveRangeVariablesEffective.AliveCombinations aliveCombinations = liveRangeVariablesEffective.getAliveCombinations(this);
alive.append(" ( ");
for(LiveRangeVariablesEffective.AliveCombination aliveCombination : aliveCombinations.getAll()) {
alive.append(aliveCombination.toString());
alive.append(" ");
}
alive.append(")");
}
return alive.toString();
}
private String getCallPathString(List<CallGraph.CallBlock.Call> path) {
StringBuilder out = new StringBuilder();
boolean first = true;
for(CallGraph.CallBlock.Call call : path) {
if(!first) {
out.append("::");
}
first = false;
out.append(call.toString());
}
return out.toString();
}
private String getAliveString(Collection<VariableRef> alive) {
StringBuilder str = new StringBuilder();
str.append(" [ ");
@ -121,4 +108,5 @@ public abstract class StatementBase implements Statement {
return str.toString();
}
}

View File

@ -199,10 +199,10 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
*/
private static boolean isStatementAllocationOverlapping(Program program, Statement statement) {
LiveRangeVariablesEffective.AliveCombinations aliveCombinations = program.getLiveRangeVariablesEffective().getAliveCombinations(statement);
for(LiveRangeVariablesEffective.CallPath callPath : aliveCombinations.getCallPaths().getCallPaths()) {
for(LiveRangeVariablesEffective.AliveCombination combination : aliveCombinations.getAll()) {
LinkedHashMap<Registers.Register, LiveRangeEquivalenceClass> usedRegisters = new LinkedHashMap<>();
Collection<VariableRef> alive = aliveCombinations.getEffectiveAliveAtStmt(callPath);
Pass2AliasElimination.Aliases callPathAliases = aliveCombinations.getEffectiveAliasesAtStmt(callPath);
Collection<VariableRef> alive = combination.getEffectiveAliveAtStmt();
Pass2AliasElimination.Aliases callPathAliases = combination.getEffectiveAliasesAtStmt();
for(VariableRef varRef : alive) {
Variable var = program.getSymbolInfos().getVariable(varRef);
Registers.Register allocation = var.getAllocation();

View File

@ -16,7 +16,7 @@ import java.util.*;
/**
* Find effective alive intervals for all variables in all statements. Add the intervals to the Program.
*/
public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariablesEffective> {
public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariablesEffectiveCallPaths> {
public PassNCalcLiveRangesEffective(Program program) {
super(program);
@ -25,7 +25,7 @@ public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariabl
/**
* Call-paths for all procedures.
*/
private Map<ProcedureRef, LiveRangeVariablesEffective.CallPaths> procedureCallPaths;
private Map<ProcedureRef, LiveRangeVariablesEffectiveCallPaths.CallPaths> procedureCallPaths;
/**
* Normal variable live ranges.
@ -38,12 +38,12 @@ public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariabl
private VariableReferenceInfos referenceInfo;
@Override
public LiveRangeVariablesEffective calculate() {
public LiveRangeVariablesEffectiveCallPaths calculate() {
this.liveRangeVariables = getProgram().getLiveRangeVariables();
this.referenceInfo = getProgram().getVariableReferenceInfos();
this.procedureCallPaths = new LinkedHashMap<>();
populateProcedureCallPaths();
LiveRangeVariablesEffective aliveEffective = new LiveRangeVariablesEffective(getProgram(), procedureCallPaths, liveRangeVariables, referenceInfo);
LiveRangeVariablesEffectiveCallPaths aliveEffective = new LiveRangeVariablesEffectiveCallPaths(getProgram(), procedureCallPaths, liveRangeVariables, referenceInfo);
return aliveEffective;
//getLog().append("Calculated effective variable live ranges");
}
@ -63,9 +63,9 @@ public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariabl
visited.add(procedure.getRef());
ProcedureRef procedureRef = procedure.getRef();
LiveRangeVariablesEffective.CallPaths callPaths = procedureCallPaths.get(procedureRef);
LiveRangeVariablesEffectiveCallPaths.CallPaths callPaths = procedureCallPaths.get(procedureRef);
if(callPaths == null) {
callPaths = new LiveRangeVariablesEffective.CallPaths(procedureRef);
callPaths = new LiveRangeVariablesEffectiveCallPaths.CallPaths(procedureRef);
if(procedure.getInterruptType()!=null || Pass2ConstantIdentification.isAddressOfUsed(procedureRef, getProgram())) {
// Interrupt is called outside procedure scope - create initial call-path.
@ -73,7 +73,7 @@ public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariabl
ArrayList<VariableRef> rootAlive = new ArrayList<>();
// Initialize with global cross-scope aliases (assumed empty)
Pass2AliasElimination.Aliases rootAliases = new Pass2AliasElimination.Aliases();
LiveRangeVariablesEffective.CallPath rootCallPath = new LiveRangeVariablesEffective.CallPath(rootPath, rootAlive, rootAliases, rootAliases);
LiveRangeVariablesEffectiveCallPaths.CallPath rootCallPath = new LiveRangeVariablesEffectiveCallPaths.CallPath(rootPath, rootAlive, rootAliases, rootAliases);
callPaths.add(rootCallPath);
}
@ -93,9 +93,9 @@ public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariabl
// Find variables referenced in caller procedure
Collection<VariableRef> referencedInCaller = referenceInfo.getReferencedVars(callerProcedure.getRef().getLabelRef());
// For each caller path - create a new call-path
LiveRangeVariablesEffective.CallPaths callerPaths = procedureCallPaths.get(callerProcedure.getRef());
LiveRangeVariablesEffectiveCallPaths.CallPaths callerPaths = procedureCallPaths.get(callerProcedure.getRef());
if(callerPaths!=null)
for(LiveRangeVariablesEffective.CallPath callerPath : callerPaths.getCallPaths()) {
for(LiveRangeVariablesEffectiveCallPaths.CallPath callerPath : callerPaths.getCallPaths()) {
ArrayList<CallGraph.CallBlock.Call> path = new ArrayList<>(callerPath.getPath());
path.add(caller);
Collection<VariableRef> alive = new LinkedHashSet<>();
@ -106,7 +106,7 @@ public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariabl
Pass2AliasElimination.Aliases pathAliases = new Pass2AliasElimination.Aliases();
pathAliases.addAll(callerPath.getPathAliases());
pathAliases.addAll(innerAliases);
LiveRangeVariablesEffective.CallPath callPath = new LiveRangeVariablesEffective.CallPath(path, alive, innerAliases, pathAliases);
LiveRangeVariablesEffectiveCallPaths.CallPath callPath = new LiveRangeVariablesEffectiveCallPaths.CallPath(path, alive, innerAliases, pathAliases);
callPaths.add(callPath);
}
} else {
@ -116,7 +116,7 @@ public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariabl
ArrayList<VariableRef> rootAlive = new ArrayList<>();
// Initialize with global cross-scope aliases (assumed empty)
Pass2AliasElimination.Aliases rootAliases = new Pass2AliasElimination.Aliases();
LiveRangeVariablesEffective.CallPath rootCallPath = new LiveRangeVariablesEffective.CallPath(rootPath, rootAlive, rootAliases, rootAliases);
LiveRangeVariablesEffectiveCallPaths.CallPath rootCallPath = new LiveRangeVariablesEffectiveCallPaths.CallPath(rootPath, rootAlive, rootAliases, rootAliases);
callPaths.add(rootCallPath);
}
}