mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-10 10:31:27 +00:00
Refactored effectively alive vars into an interface for experimenting with less memory-intensive implementation.
This commit is contained in:
parent
afe8294cd1
commit
7726c1d43f
@ -0,0 +1,8 @@
|
|||||||
|
lda {c1}
|
||||||
|
asl
|
||||||
|
sta {m1}
|
||||||
|
lda {c1}+1
|
||||||
|
rol
|
||||||
|
sta {m1}+1
|
||||||
|
asl {m1}
|
||||||
|
rol {m1}+1
|
@ -1,381 +1,36 @@
|
|||||||
package dk.camelot64.kickc.model;
|
package dk.camelot64.kickc.model;
|
||||||
|
|
||||||
import dk.camelot64.kickc.model.statements.Statement;
|
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.model.values.VariableRef;
|
||||||
import dk.camelot64.kickc.passes.Pass2AliasElimination;
|
import dk.camelot64.kickc.passes.Pass2AliasElimination;
|
||||||
import dk.camelot64.kickc.passes.calcs.PassNCalcLiveRangesEffective;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
/**
|
public interface LiveRangeVariablesEffective {
|
||||||
* Effective variable live ranges for all statements.
|
|
||||||
* (Including variables alive in calling methods).
|
|
||||||
* Created by {@link PassNCalcLiveRangesEffective}
|
|
||||||
*/
|
|
||||||
public class LiveRangeVariablesEffective {
|
|
||||||
|
|
||||||
/**
|
Collection<VariableRef> getAliveEffective(Statement statement);
|
||||||
* The program.
|
|
||||||
*/
|
|
||||||
private Program program;
|
|
||||||
|
|
||||||
/**
|
AliveCombinations getAliveCombinations(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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 {
|
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;
|
Collection<AliveCombination> getAll();
|
||||||
/**
|
|
||||||
* 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<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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -89,7 +89,7 @@ public class Program {
|
|||||||
/** The live ranges of all variables. PASS 3-4 (CACHED ON-DEMAND) */
|
/** The live ranges of all variables. PASS 3-4 (CACHED ON-DEMAND) */
|
||||||
private LiveRangeVariables liveRangeVariables;
|
private LiveRangeVariables liveRangeVariables;
|
||||||
/** The effective live ranges of all variables. PASS 3-4 (CACHED ON-DEMAND) */
|
/** 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) */
|
/** Separation of live range equivalence classes into scopes - used for register uplift. PASS 4 (CACHED ON-DEMAND) */
|
||||||
private RegisterUpliftProgram registerUpliftProgram;
|
private RegisterUpliftProgram registerUpliftProgram;
|
||||||
/** Cached information about which block is each statement a part of. PASS 2U-5 (CACHED ON-DEMAND) */
|
/** Cached information about which block is each statement a part of. PASS 2U-5 (CACHED ON-DEMAND) */
|
||||||
|
@ -5,6 +5,7 @@ import dk.camelot64.kickc.model.values.VariableRef;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/** Statement base class implementing shared properties and logic */
|
/** Statement base class implementing shared properties and logic */
|
||||||
public abstract class StatementBase implements Statement {
|
public abstract class StatementBase implements Statement {
|
||||||
@ -57,12 +58,14 @@ public abstract class StatementBase implements Statement {
|
|||||||
if(this == o) return true;
|
if(this == o) return true;
|
||||||
if(o == null || getClass() != o.getClass()) return false;
|
if(o == null || getClass() != o.getClass()) return false;
|
||||||
StatementBase that = (StatementBase) o;
|
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
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return index != null ? index.hashCode() : 0;
|
return Objects.hash(source, index, comments);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String idxString() {
|
public String idxString() {
|
||||||
@ -83,33 +86,17 @@ public abstract class StatementBase implements Statement {
|
|||||||
alive.append(getAliveString(liveRanges.getAlive(index)));
|
alive.append(getAliveString(liveRanges.getAlive(index)));
|
||||||
if(program.hasLiveRangeVariablesEffective()) {
|
if(program.hasLiveRangeVariablesEffective()) {
|
||||||
LiveRangeVariablesEffective liveRangeVariablesEffective = program.getLiveRangeVariablesEffective();
|
LiveRangeVariablesEffective liveRangeVariablesEffective = program.getLiveRangeVariablesEffective();
|
||||||
if(liveRangeVariablesEffective != null) {
|
LiveRangeVariablesEffective.AliveCombinations aliveCombinations = liveRangeVariablesEffective.getAliveCombinations(this);
|
||||||
LiveRangeVariablesEffective.AliveCombinations aliveCombinations = liveRangeVariablesEffective.getAliveCombinations(this);
|
alive.append(" ( ");
|
||||||
alive.append(" ( ");
|
for(LiveRangeVariablesEffective.AliveCombination aliveCombination : aliveCombinations.getAll()) {
|
||||||
for(LiveRangeVariablesEffective.CallPath callPath : aliveCombinations.getCallPaths().getCallPaths()) {
|
alive.append(aliveCombination.toString());
|
||||||
alive.append(getCallPathString(callPath.getPath()));
|
alive.append(" ");
|
||||||
alive.append(getAliveString(aliveCombinations.getEffectiveAliveAtStmt(callPath)));
|
|
||||||
alive.append(" ");
|
|
||||||
}
|
|
||||||
alive.append(")");
|
|
||||||
}
|
}
|
||||||
|
alive.append(")");
|
||||||
}
|
}
|
||||||
return alive.toString();
|
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) {
|
private String getAliveString(Collection<VariableRef> alive) {
|
||||||
StringBuilder str = new StringBuilder();
|
StringBuilder str = new StringBuilder();
|
||||||
str.append(" [ ");
|
str.append(" [ ");
|
||||||
@ -121,4 +108,5 @@ public abstract class StatementBase implements Statement {
|
|||||||
return str.toString();
|
return str.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -199,10 +199,10 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
|||||||
*/
|
*/
|
||||||
private static boolean isStatementAllocationOverlapping(Program program, Statement statement) {
|
private static boolean isStatementAllocationOverlapping(Program program, Statement statement) {
|
||||||
LiveRangeVariablesEffective.AliveCombinations aliveCombinations = program.getLiveRangeVariablesEffective().getAliveCombinations(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<>();
|
LinkedHashMap<Registers.Register, LiveRangeEquivalenceClass> usedRegisters = new LinkedHashMap<>();
|
||||||
Collection<VariableRef> alive = aliveCombinations.getEffectiveAliveAtStmt(callPath);
|
Collection<VariableRef> alive = combination.getEffectiveAliveAtStmt();
|
||||||
Pass2AliasElimination.Aliases callPathAliases = aliveCombinations.getEffectiveAliasesAtStmt(callPath);
|
Pass2AliasElimination.Aliases callPathAliases = combination.getEffectiveAliasesAtStmt();
|
||||||
for(VariableRef varRef : alive) {
|
for(VariableRef varRef : alive) {
|
||||||
Variable var = program.getSymbolInfos().getVariable(varRef);
|
Variable var = program.getSymbolInfos().getVariable(varRef);
|
||||||
Registers.Register allocation = var.getAllocation();
|
Registers.Register allocation = var.getAllocation();
|
||||||
|
@ -16,7 +16,7 @@ import java.util.*;
|
|||||||
/**
|
/**
|
||||||
* Find effective alive intervals for all variables in all statements. Add the intervals to the Program.
|
* 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) {
|
public PassNCalcLiveRangesEffective(Program program) {
|
||||||
super(program);
|
super(program);
|
||||||
@ -25,7 +25,7 @@ public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariabl
|
|||||||
/**
|
/**
|
||||||
* Call-paths for all procedures.
|
* Call-paths for all procedures.
|
||||||
*/
|
*/
|
||||||
private Map<ProcedureRef, LiveRangeVariablesEffective.CallPaths> procedureCallPaths;
|
private Map<ProcedureRef, LiveRangeVariablesEffectiveCallPaths.CallPaths> procedureCallPaths;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normal variable live ranges.
|
* Normal variable live ranges.
|
||||||
@ -38,12 +38,12 @@ public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariabl
|
|||||||
private VariableReferenceInfos referenceInfo;
|
private VariableReferenceInfos referenceInfo;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LiveRangeVariablesEffective calculate() {
|
public LiveRangeVariablesEffectiveCallPaths calculate() {
|
||||||
this.liveRangeVariables = getProgram().getLiveRangeVariables();
|
this.liveRangeVariables = getProgram().getLiveRangeVariables();
|
||||||
this.referenceInfo = getProgram().getVariableReferenceInfos();
|
this.referenceInfo = getProgram().getVariableReferenceInfos();
|
||||||
this.procedureCallPaths = new LinkedHashMap<>();
|
this.procedureCallPaths = new LinkedHashMap<>();
|
||||||
populateProcedureCallPaths();
|
populateProcedureCallPaths();
|
||||||
LiveRangeVariablesEffective aliveEffective = new LiveRangeVariablesEffective(getProgram(), procedureCallPaths, liveRangeVariables, referenceInfo);
|
LiveRangeVariablesEffectiveCallPaths aliveEffective = new LiveRangeVariablesEffectiveCallPaths(getProgram(), procedureCallPaths, liveRangeVariables, referenceInfo);
|
||||||
return aliveEffective;
|
return aliveEffective;
|
||||||
//getLog().append("Calculated effective variable live ranges");
|
//getLog().append("Calculated effective variable live ranges");
|
||||||
}
|
}
|
||||||
@ -63,9 +63,9 @@ public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariabl
|
|||||||
visited.add(procedure.getRef());
|
visited.add(procedure.getRef());
|
||||||
|
|
||||||
ProcedureRef procedureRef = procedure.getRef();
|
ProcedureRef procedureRef = procedure.getRef();
|
||||||
LiveRangeVariablesEffective.CallPaths callPaths = procedureCallPaths.get(procedureRef);
|
LiveRangeVariablesEffectiveCallPaths.CallPaths callPaths = procedureCallPaths.get(procedureRef);
|
||||||
if(callPaths == null) {
|
if(callPaths == null) {
|
||||||
callPaths = new LiveRangeVariablesEffective.CallPaths(procedureRef);
|
callPaths = new LiveRangeVariablesEffectiveCallPaths.CallPaths(procedureRef);
|
||||||
|
|
||||||
if(procedure.getInterruptType()!=null || Pass2ConstantIdentification.isAddressOfUsed(procedureRef, getProgram())) {
|
if(procedure.getInterruptType()!=null || Pass2ConstantIdentification.isAddressOfUsed(procedureRef, getProgram())) {
|
||||||
// Interrupt is called outside procedure scope - create initial call-path.
|
// 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<>();
|
ArrayList<VariableRef> rootAlive = new ArrayList<>();
|
||||||
// Initialize with global cross-scope aliases (assumed empty)
|
// Initialize with global cross-scope aliases (assumed empty)
|
||||||
Pass2AliasElimination.Aliases rootAliases = new Pass2AliasElimination.Aliases();
|
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);
|
callPaths.add(rootCallPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,9 +93,9 @@ public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariabl
|
|||||||
// Find variables referenced in caller procedure
|
// Find variables referenced in caller procedure
|
||||||
Collection<VariableRef> referencedInCaller = referenceInfo.getReferencedVars(callerProcedure.getRef().getLabelRef());
|
Collection<VariableRef> referencedInCaller = referenceInfo.getReferencedVars(callerProcedure.getRef().getLabelRef());
|
||||||
// For each caller path - create a new call-path
|
// 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)
|
if(callerPaths!=null)
|
||||||
for(LiveRangeVariablesEffective.CallPath callerPath : callerPaths.getCallPaths()) {
|
for(LiveRangeVariablesEffectiveCallPaths.CallPath callerPath : callerPaths.getCallPaths()) {
|
||||||
ArrayList<CallGraph.CallBlock.Call> path = new ArrayList<>(callerPath.getPath());
|
ArrayList<CallGraph.CallBlock.Call> path = new ArrayList<>(callerPath.getPath());
|
||||||
path.add(caller);
|
path.add(caller);
|
||||||
Collection<VariableRef> alive = new LinkedHashSet<>();
|
Collection<VariableRef> alive = new LinkedHashSet<>();
|
||||||
@ -106,7 +106,7 @@ public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariabl
|
|||||||
Pass2AliasElimination.Aliases pathAliases = new Pass2AliasElimination.Aliases();
|
Pass2AliasElimination.Aliases pathAliases = new Pass2AliasElimination.Aliases();
|
||||||
pathAliases.addAll(callerPath.getPathAliases());
|
pathAliases.addAll(callerPath.getPathAliases());
|
||||||
pathAliases.addAll(innerAliases);
|
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);
|
callPaths.add(callPath);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -116,7 +116,7 @@ public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariabl
|
|||||||
ArrayList<VariableRef> rootAlive = new ArrayList<>();
|
ArrayList<VariableRef> rootAlive = new ArrayList<>();
|
||||||
// Initialize with global cross-scope aliases (assumed empty)
|
// Initialize with global cross-scope aliases (assumed empty)
|
||||||
Pass2AliasElimination.Aliases rootAliases = new Pass2AliasElimination.Aliases();
|
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);
|
callPaths.add(rootCallPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user