1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-08 17:54:40 +00:00

Implemented switchable effective live ranges. Started on "simple" which works for most programs - but fail for tetris, clearscreen and more.

This commit is contained in:
jespergravgaard 2020-03-08 21:07:09 +01:00
parent 7726c1d43f
commit c0b0f063cc
13 changed files with 282 additions and 70 deletions

View File

@ -89,6 +89,10 @@ public class Compiler {
this.enableLoopHeadConstant = false;
}
public void setEnableLiveRangeCallPath(boolean enableLiveRangeCallPath) {
this.program.setEnableLiveRangeCallPath(enableLiveRangeCallPath);
}
void setTargetPlatform(TargetPlatform targetPlatform) {
program.setTargetPlatform(targetPlatform);
}

View File

@ -79,6 +79,9 @@ public class KickC implements Callable<Void> {
@CommandLine.Option(names = {"-Ocache"}, description = "Optimization Option. Enables a fragment cache file.")
private boolean optimizeFragmentCache = false;
//@CommandLine.Option(names = {"-Oliverangecallpath"}, description = "Optimization Option. Enables live ranges per call path optimization, which limits memory usage and code, but takes a lot of compile time.")
private boolean optimizeLiveRangeCallPath = true;
@CommandLine.Option(names = {"-v"}, description = "Verbose output describing the compilation process")
private boolean verbose = false;
@ -163,10 +166,10 @@ public class KickC implements Callable<Void> {
Compiler compiler = new Compiler();
if(target!=null) {
if(target != null) {
TargetPlatform targetPlatform = TargetPlatform.getTargetPlatform(target);
if(targetPlatform==null) {
System.err.println("Unknown target platform "+target);
if(targetPlatform == null) {
System.err.println("Unknown target platform " + target);
StringBuffer supported = new StringBuffer();
supported.append("The supported target platforms are: ");
for(TargetPlatform value : TargetPlatform.values()) {
@ -178,10 +181,10 @@ public class KickC implements Callable<Void> {
compiler.setTargetPlatform(targetPlatform);
}
if(cpu!=null) {
if(cpu != null) {
TargetCpu targetCpu = TargetCpu.getTargetCpu(cpu);
if(targetCpu==null) {
System.err.println("Unknown target CPU "+cpu);
if(targetCpu == null) {
System.err.println("Unknown target CPU " + cpu);
StringBuffer supported = new StringBuffer();
supported.append("The supported target CPUs are: ");
for(TargetCpu value : TargetCpu.values()) {
@ -252,7 +255,7 @@ public class KickC implements Callable<Void> {
if(optimizeNoUplift) {
compiler.setDisableUplift(true);
}
if(optimizeUpliftCombinations != null) {
compiler.setUpliftCombinations(optimizeUpliftCombinations);
}
@ -267,15 +270,17 @@ public class KickC implements Callable<Void> {
compiler.disableLoopHeadConstant();
}
compiler.setEnableLiveRangeCallPath(optimizeLiveRangeCallPath);
if(warnFragmentMissing) {
compiler.setWarnFragmentMissing(true);
}
if(linkScript!=null) {
if(linkScript != null) {
compiler.setLinkScriptFileName(linkScript);
}
if(varModel!=null) {
if(varModel != null) {
List<String> settings = Arrays.asList(varModel.split(","));
settings = settings.stream().map(String::trim).collect(Collectors.toList());
try {
@ -287,10 +292,10 @@ public class KickC implements Callable<Void> {
}
}
if(calling!=null) {
if(calling != null) {
Procedure.CallingConvention callingConvention = Procedure.CallingConvention.getCallingConvension(calling);
if(callingConvention ==null) {
System.err.println("Unknown calling convention "+calling);
if(callingConvention == null) {
System.err.println("Unknown calling convention " + calling);
StringBuffer supported = new StringBuffer();
supported.append("The supported calling conventions are: ");
for(Procedure.CallingConvention value : Procedure.CallingConvention.values()) {
@ -392,8 +397,6 @@ public class KickC implements Callable<Void> {
}
return null;
}

View File

@ -131,14 +131,14 @@ public class CallGraph {
/**
* Get all calls of a specific procedure
*
* @param label The label of the procedure
* @param procedureRef The label of the procedure
* @return All calls
*/
public Collection<CallBlock.Call> getCallers(ScopeRef label) {
public Collection<CallBlock.Call> getCallers(ProcedureRef procedureRef) {
Collection<CallBlock.Call> callers = new ArrayList<>();
for(CallBlock callBlock : callBlocks) {
for(CallBlock.Call call : callBlock.getCalls()) {
if(call.getProcedure().equals(label)) {
if(call.getProcedure().equals(procedureRef)) {
callers.add(call);
}
}
@ -147,11 +147,36 @@ public class CallGraph {
}
/**
* Get all procedures containing calls of a specific procedure
* Get all calls of a specific procedure
*
* @param label The label of the procedure
* @return All calls
*/
public Collection<CallBlock.Call> getRecursiveCallers(ProcedureRef procedureRef) {
final LinkedList<CallBlock.Call> callers = new LinkedList<>();
Deque<ProcedureRef> todo = new LinkedList<>();
todo.add(procedureRef);
Collection<ProcedureRef> visited = new LinkedList<>();
while(!todo.isEmpty()) {
final ProcedureRef procRef = todo.pop();
if(visited.contains(procRef))
continue;
visited.add(procRef);
final Collection<CallBlock.Call> procCallers = getCallers(procRef);
callers.addAll(procCallers);
for(CallBlock.Call caller : procCallers) {
todo.add(caller.getProcedure());
}
}
return callers;
}
/**
* Get all procedures containing calls of a specific procedure
*
* @param label The label of the procedure
* @return All calls
*/
public Collection<ScopeRef> getCallerProcs(ScopeRef label) {
Collection<ScopeRef> callers = new ArrayList<>();
for(CallBlock callBlock : callBlocks) {
@ -170,9 +195,9 @@ public class CallGraph {
* @param scopeRef The scope (procedure/root) to examine
* @return All scopes calling the passed scope (potentially through other callers)
*/
public Collection<ScopeRef> getRecursiveCallers(ScopeRef scopeRef) {
public Collection<ScopeRef> getRecursiveCallerProcs(ScopeRef scopeRef) {
ArrayList<ScopeRef> closure = new ArrayList<>();
addRecursiveCallers(scopeRef, closure);
addRecursiveCallerProcs(scopeRef, closure);
return closure;
}
@ -182,7 +207,7 @@ public class CallGraph {
* @param scopeRef The scope (procedure/root) to examine
* @param found The scopes already found
* */
private void addRecursiveCallers(ScopeRef scopeRef, Collection<ScopeRef> found) {
private void addRecursiveCallerProcs(ScopeRef scopeRef, Collection<ScopeRef> found) {
if(found.contains(scopeRef)) {
// Recursion detected - stop here
return;
@ -190,7 +215,7 @@ public class CallGraph {
found.add(scopeRef);
Collection<ScopeRef> callerProcs = getCallerProcs(scopeRef);
for(ScopeRef callerProc : callerProcs) {
addRecursiveCallers(callerProc, found);
addRecursiveCallerProcs(callerProc, found);
}
}

View File

@ -12,6 +12,8 @@ public interface LiveRangeVariablesEffective {
AliveCombinations getAliveCombinations(Statement statement);
String getSizeInfo();
/**
* Combinations of variables effectively alive at a specific statement.
*/

View File

@ -8,7 +8,7 @@ import dk.camelot64.kickc.model.values.ProcedureRef;
import dk.camelot64.kickc.model.values.ScopeRef;
import dk.camelot64.kickc.model.values.VariableRef;
import dk.camelot64.kickc.passes.Pass2AliasElimination;
import dk.camelot64.kickc.passes.calcs.PassNCalcLiveRangesEffective;
import dk.camelot64.kickc.passes.calcs.PassNCalcLiveRangesEffectiveCallPaths;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
@ -16,7 +16,7 @@ import java.util.concurrent.atomic.AtomicInteger;
/**
* Effective variable live ranges for all statements.
* (Including variables alive in calling methods).
* Created by {@link PassNCalcLiveRangesEffective}
* Created by {@link PassNCalcLiveRangesEffectiveCallPaths}
*/
public class LiveRangeVariablesEffectiveCallPaths implements LiveRangeVariablesEffective {
@ -94,7 +94,7 @@ public class LiveRangeVariablesEffectiveCallPaths implements LiveRangeVariablesE
* @return All combinations of variables alive at the statement
*/
@Override
public AliveCombinationsCallPath getAliveCombinations(Statement statement) {
public AliveCombinations getAliveCombinations(Statement statement) {
AliveCombinationsCallPath stmtCombinations = this.statementAliveCombinations.get(statement.getIndex());
if(stmtCombinations == null) {
Collection<VariableRef> aliveAtStmt = statementLiveVariables.get(statement.getIndex());
@ -150,7 +150,7 @@ public class LiveRangeVariablesEffectiveCallPaths implements LiveRangeVariablesE
}
String getSizeInfo() {
public String getSizeInfo() {
StringBuilder sizeInfo = new StringBuilder();
if(this.procedureCallPaths != null) {
AtomicInteger numCallPaths = new AtomicInteger();

View File

@ -0,0 +1,105 @@
package dk.camelot64.kickc.model;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.values.VariableRef;
import dk.camelot64.kickc.passes.Pass2AliasElimination;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
/**
* Simple and fast implementation of effective alive variables that combines all call-path combinations into a single set and callpath aliases are not handled
*/
public class LiveRangeVariablesEffectiveSimple implements LiveRangeVariablesEffective {
/** All variables potentially effective alive by statement index. */
private Map<Integer, Collection<VariableRef>> statementAliveEffective;
public LiveRangeVariablesEffectiveSimple(Map<Integer, Collection<VariableRef>> statementAliveEffective) {
this.statementAliveEffective = statementAliveEffective;
}
/**
* Get all variables potentially alive at a statement.
* If the statement is inside a method this also includes all variables alive at the exit of any call.
* </p>
*
* @param statement The statement to examine
* @return All variables potentially alive at the statement
*/
@Override
public Collection<VariableRef> getAliveEffective(Statement statement) {
return statementAliveEffective.get(statement.getIndex());
}
@Override
public AliveCombinations getAliveCombinations(Statement statement) {
return new AliveCombinationsSimple(getAliveEffective(statement));
}
public class AliveCombinationsSimple implements AliveCombinations {
private Collection<VariableRef> alive;
public AliveCombinationsSimple(Collection<VariableRef> alive) {
this.alive = alive;
}
@Override
public Collection<AliveCombination> getAll() {
final ArrayList<AliveCombination> aliveCombinations = new ArrayList<>();
aliveCombinations.add(new AliveCombinationSimple(alive));
return aliveCombinations;
}
}
public class AliveCombinationSimple implements AliveCombination {
private Collection<VariableRef> alive;
public AliveCombinationSimple(Collection<VariableRef> alive) {
this.alive = alive;
}
@Override
public Collection<VariableRef> getEffectiveAliveAtStmt() {
return alive;
}
@Override
public Pass2AliasElimination.Aliases getEffectiveAliasesAtStmt() {
return null;
}
@Override
public String toString() {
return getAliveString(alive);
}
private String getAliveString(Collection<VariableRef> alive) {
StringBuilder str = new StringBuilder();
str.append(" [ ");
for(VariableRef variableRef : alive) {
str.append(variableRef.getFullName());
str.append(" ");
}
str.append("]");
return str.toString();
}
}
@Override
public String getSizeInfo() {
StringBuilder sizeInfo = new StringBuilder();
if(this.statementAliveEffective != null) {
sizeInfo.append("SIZE statementAliveEffective ").append(statementAliveEffective.size()).append(" statements ");
int sub = 0;
for(Collection<VariableRef> variableRefs : statementAliveEffective.values()) {
sub += variableRefs.size();
}
sizeInfo.append(" ").append(sub).append(" varrefs").append("\n");
}
return sizeInfo.toString();
}
}

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 LiveRangeVariablesEffectiveCallPaths liveRangeVariablesEffective;
private LiveRangeVariablesEffective liveRangeVariablesEffective;
/** Separation of live range equivalence classes into scopes - used for register uplift. PASS 4 (CACHED ON-DEMAND) */
private RegisterUpliftProgram registerUpliftProgram;
/** Cached information about which block is each statement a part of. PASS 2U-5 (CACHED ON-DEMAND) */
@ -98,6 +98,8 @@ public class Program {
private NaturalLoopSet loopSet;
/** The register weight of all variables describing how much the variable would theoretically gain from being in a register. PASS 3-5 (CACHED ON-DEMAND) */
private VariableRegisterWeights variableRegisterWeights;
/** Enable live ranges per call path optimization, which limits memory usage and code, but takes a lot of compile time. */
private boolean enableLiveRangeCallPath = true;
public Program() {
this.scope = new ProgramScope();
@ -165,6 +167,10 @@ public class Program {
this.asm = null;
}
public void setEnableLiveRangeCallPath(boolean enableLiveRangeCallPath) {
this.enableLiveRangeCallPath = enableLiveRangeCallPath;
}
public boolean isWarnFragmentMissing() {
return warnFragmentMissing;
}
@ -200,6 +206,7 @@ public class Program {
public void initAsmFragmentSynthesizer(AsmFragmentTemplateSynthesizer synthesizer) {
this.asmFragmentSynthesizer = synthesizer;
}
public TargetCpu getTargetCpu() {
return targetCpu;
}
@ -290,6 +297,7 @@ public class Program {
/**
* Get the call-graph for the program. Calculates the call-graph if it has not already been calculated.
*
* @return The call-graph
*/
public CallGraph getCallGraph() {
@ -306,7 +314,7 @@ public class Program {
}
public VariableReferenceInfos getVariableReferenceInfos() {
if(variableReferenceInfos==null)
if(variableReferenceInfos == null)
this.variableReferenceInfos = new PassNCalcVariableReferenceInfos(this).calculate();
return variableReferenceInfos;
}
@ -316,7 +324,7 @@ public class Program {
}
public DominatorsGraph getDominators() {
if(dominators==null)
if(dominators == null)
this.dominators = new PassNCalcDominators(this).calculate();
return dominators;
}
@ -326,7 +334,7 @@ public class Program {
}
public Map<LabelRef, PhiTransitions> getPhiTransitions() {
if(phiTransitions==null)
if(phiTransitions == null)
this.phiTransitions = new PassNCalcPhiTransitions(this).calculate();
return phiTransitions;
}
@ -336,7 +344,7 @@ public class Program {
}
public LiveRangeVariables getLiveRangeVariables() {
if(liveRangeVariables==null)
if(liveRangeVariables == null)
this.liveRangeVariables = new PassNCalcLiveRangeVariables(this).calculate();
return liveRangeVariables;
}
@ -354,7 +362,7 @@ public class Program {
}
public StatementInfos getStatementInfos() {
if(statementInfos==null)
if(statementInfos == null)
this.statementInfos = new PassNCalcStatementInfos(this).calculate();
return statementInfos;
}
@ -375,18 +383,22 @@ public class Program {
}
public SymbolInfos getSymbolInfos() {
if(symbolInfos==null)
if(symbolInfos == null)
this.symbolInfos = new PassNCalcSymbolInfos(this).calculate();
return symbolInfos;
}
public boolean hasLiveRangeVariablesEffective() {
return liveRangeVariablesEffective!=null;
return liveRangeVariablesEffective != null;
}
public LiveRangeVariablesEffective getLiveRangeVariablesEffective() {
if(liveRangeVariablesEffective==null) {
this.liveRangeVariablesEffective = new PassNCalcLiveRangesEffective(this).calculate();
if(liveRangeVariablesEffective == null) {
if(enableLiveRangeCallPath) {
this.liveRangeVariablesEffective = new PassNCalcLiveRangesEffectiveCallPaths(this).calculate();
} else {
this.liveRangeVariablesEffective = new PassNCalcLiveRangesEffectiveSimple(this).calculate();
}
}
return liveRangeVariablesEffective;
}
@ -396,13 +408,13 @@ public class Program {
}
public RegisterUpliftProgram getRegisterUpliftProgram() {
if(registerUpliftProgram==null)
if(registerUpliftProgram == null)
this.registerUpliftProgram = new PassNCalcRegisterUpliftProgram(this).calculate();
return registerUpliftProgram;
}
public NaturalLoopSet getLoopSet() {
if(loopSet==null)
if(loopSet == null)
this.loopSet = new PassNCalcLoopSet(this).calculate();
return loopSet;
}
@ -412,7 +424,7 @@ public class Program {
}
public VariableRegisterWeights getVariableRegisterWeights() {
if(variableRegisterWeights==null)
if(variableRegisterWeights == null)
this.variableRegisterWeights = new PassNCalcVariableRegisterWeight(this).calculate();
return variableRegisterWeights;
}
@ -499,19 +511,20 @@ public class Program {
/**
* Get information about the size of the program
*
* @return Size information
*/
public String getSizeInfo() {
StringBuilder sizeInfo = new StringBuilder();
sizeInfo.append(getScope().getSizeInfo());
sizeInfo.append(getGraph().getSizeInfo());
if(variableReferenceInfos!=null)
if(variableReferenceInfos != null)
sizeInfo.append(variableReferenceInfos.getSizeInfo());
if(getLiveRangeEquivalenceClassSet()!=null)
if(getLiveRangeEquivalenceClassSet() != null)
sizeInfo.append(getLiveRangeEquivalenceClassSet().getSizeInfo());
if(liveRangeVariablesEffective!=null)
if(liveRangeVariablesEffective != null)
sizeInfo.append(liveRangeVariablesEffective.getSizeInfo());
if(getAsm()!=null)
if(getAsm() != null)
sizeInfo.append(getAsm().getSizeInfo());
return sizeInfo.toString();
}

View File

@ -117,7 +117,7 @@ public abstract class Pass4MemoryCoalesce extends Pass2Base {
threads.add(mainThreadHead);
}
} else {
Collection<ScopeRef> recursiveCallers = callGraph.getRecursiveCallers(scopeRef);
Collection<ScopeRef> recursiveCallers = callGraph.getRecursiveCallerProcs(scopeRef);
for(ScopeRef threadHead : threadHeads) {
if(recursiveCallers.contains(threadHead)) {
if(!threads.contains(threadHead)) {

View File

@ -1,6 +1,7 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.values.ProcedureRef;
import dk.camelot64.kickc.model.values.ScopeRef;
import dk.camelot64.kickc.model.values.VariableRef;
@ -55,9 +56,9 @@ public class Pass4MemoryCoalesceCallGraph extends Pass2Base {
if(Registers.RegisterType.MAIN_MEM.equals(thisEC.getRegister().getType()))
continue;
// Find all calling scopes - since we want to avoid coalescing with variables in these
Set<ScopeRef> allCallingScopes = new LinkedHashSet<>();
Set<ProcedureRef> allCallingScopes = new LinkedHashSet<>();
for(ScopeRef ecScope : getEquivalenceClassScopes(thisEC)) {
allCallingScopes.addAll(getAllCallingScopes(ecScope, callGraph));
allCallingScopes.addAll(getAllCallingScopes(new ProcedureRef(ecScope.getFullName()), callGraph));
}
// Go through the already handled equivalence classes - and try to coalesce with any that does not have variables from the calling scopes
boolean coalesced = false;
@ -66,7 +67,7 @@ public class Pass4MemoryCoalesceCallGraph extends Pass2Base {
if(Registers.RegisterType.MAIN_MEM.equals(otherEC.getRegister().getType()))
continue;
// Skip if there is a scope overlap
if(isScopeOverlap(otherEC, allCallingScopes))
if(isProcedureOverlap(otherEC, allCallingScopes))
continue;
// No scope overlap - attempt to coalesce
Pass4MemoryCoalesce.LiveRangeEquivalenceClassCoalesceCandidate candidate = new Pass4MemoryCoalesce.LiveRangeEquivalenceClassCoalesceCandidate(thisEC, otherEC, null);
@ -86,33 +87,33 @@ public class Pass4MemoryCoalesceCallGraph extends Pass2Base {
}
/**
* Determine if any variable in a live range equivalence class has a scope from the passed set of scopes.
* Determine if any variable in a live range equivalence class has a scope from the passed set of procedures.
* @param equivalenceClass The live range equivalence class
* @param scopeRefSet The set of scopes
* @param procedureRefs The set of procedures
* @return true if there is a scope overlap
*/
private boolean isScopeOverlap(LiveRangeEquivalenceClass equivalenceClass, Collection<ScopeRef> scopeRefSet) {
private boolean isProcedureOverlap(LiveRangeEquivalenceClass equivalenceClass, Collection<ProcedureRef> procedureRefs) {
boolean scopeOverlap = false;
for(VariableRef otherVarRef : equivalenceClass.getVariables()) {
ScopeRef otherScopeRef = new ScopeRef(otherVarRef.getScopeNames());
if(scopeRefSet.contains(otherScopeRef))
ProcedureRef otherProcedureRef = new ProcedureRef(otherVarRef.getScopeNames());
if(procedureRefs.contains(otherProcedureRef))
scopeOverlap = true;
}
return scopeOverlap;
}
/**
* Get all scopes call into a specific scope. Recursively includes callers of callers. Also includes the scope itself.
* @param scopeRef The scope to examine
* Get all procedures calling into a specific procedure. Recursively includes callers of callers. Also includes the procedure itself.
* @param procedureRef The scope to examine
* @param callGraph The call graph
* @return All scopes that call into this one (potentially )
* @return All procedures that call into this one (potentially )
*/
private Set<ScopeRef> getAllCallingScopes(ScopeRef scopeRef, CallGraph callGraph) {
LinkedHashSet<ScopeRef> allCallers = new LinkedHashSet<>();
private Set<ProcedureRef> getAllCallingScopes(ProcedureRef procedureRef, CallGraph callGraph) {
LinkedHashSet<ProcedureRef> allCallers = new LinkedHashSet<>();
// Add the scope itself
allCallers.add(scopeRef);
allCallers.add(procedureRef);
// Recursively add the scopes of all callers
for(CallGraph.CallBlock.Call caller : callGraph.getCallers(scopeRef)) {
for(CallGraph.CallBlock.Call caller : callGraph.getCallers(procedureRef)) {
if(!allCallers.contains(caller.getProcedure()))
allCallers.addAll(getAllCallingScopes(caller.getProcedure(), callGraph));
}

View File

@ -201,20 +201,22 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
LiveRangeVariablesEffective.AliveCombinations aliveCombinations = program.getLiveRangeVariablesEffective().getAliveCombinations(statement);
for(LiveRangeVariablesEffective.AliveCombination combination : aliveCombinations.getAll()) {
LinkedHashMap<Registers.Register, LiveRangeEquivalenceClass> usedRegisters = new LinkedHashMap<>();
Collection<VariableRef> alive = combination.getEffectiveAliveAtStmt();
Pass2AliasElimination.Aliases callPathAliases = combination.getEffectiveAliasesAtStmt();
for(VariableRef varRef : alive) {
Collection<VariableRef> aliveAtStmt = combination.getEffectiveAliveAtStmt();
Pass2AliasElimination.Aliases aliasesAtStmt = combination.getEffectiveAliasesAtStmt();
for(VariableRef varRef : aliveAtStmt) {
Variable var = program.getSymbolInfos().getVariable(varRef);
Registers.Register allocation = var.getAllocation();
LiveRangeEquivalenceClass allocationClass = usedRegisters.get(allocation);
if(allocationClass != null && !allocationClass.contains(varRef)) {
// Examine if the var is an alias of a var in the allocation class
boolean overlap = true;
Pass2AliasElimination.AliasSet aliasSet = callPathAliases.findAliasSet(varRef);
if(aliasSet != null) {
for(VariableRef aliasVar : aliasSet.getVars()) {
if(allocationClass.contains(aliasVar)) {
overlap = false;
if(aliasesAtStmt!=null) {
Pass2AliasElimination.AliasSet aliasSet = aliasesAtStmt.findAliasSet(varRef);
if(aliasSet != null) {
for(VariableRef aliasVar : aliasSet.getVars()) {
if(allocationClass.contains(aliasVar)) {
overlap = false;
}
}
}
}

View File

@ -273,7 +273,7 @@ public class PassNCalcLiveRangeVariables extends PassNCalcBase<LiveRangeVariable
ControlFlowBlock block = getProgram().getStatementInfos().getBlock(statement);
if(block.isProcedureEntry(getProgram())) {
// Current is first statement of a call - add the statement preceding the call.
Collection<CallGraph.CallBlock.Call> callers = getProgram().getCallGraph().getCallers(block.getScope());
Collection<CallGraph.CallBlock.Call> callers = getProgram().getCallGraph().getCallers((ProcedureRef) block.getScope());
for(CallGraph.CallBlock.Call call : callers) {
Statement callStmt = getProgram().getStatementInfos().getStatement(call.getCallStatementIdx());
Collection<Statement> precedingCallStmt = getPrecedingStatement(callStmt);

View File

@ -16,9 +16,9 @@ import java.util.*;
/**
* Find effective alive intervals for all variables in all statements. Add the intervals to the Program.
*/
public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariablesEffectiveCallPaths> {
public class PassNCalcLiveRangesEffectiveCallPaths extends PassNCalcBase<LiveRangeVariablesEffectiveCallPaths> {
public PassNCalcLiveRangesEffective(Program program) {
public PassNCalcLiveRangesEffectiveCallPaths(Program program) {
super(program);
}

View File

@ -0,0 +1,57 @@
package dk.camelot64.kickc.passes.calcs;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.values.ProcedureRef;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.*;
/**
* Find effective alive intervals for all variables in all statements. Add the intervals to the Program.
*/
public class PassNCalcLiveRangesEffectiveSimple extends PassNCalcBase<LiveRangeVariablesEffectiveSimple> {
public PassNCalcLiveRangesEffectiveSimple(Program program) {
super(program);
}
@Override
public LiveRangeVariablesEffectiveSimple calculate() {
final LiveRangeVariables liveRangeVariables = getProgram().getLiveRangeVariables();
final CallGraph callGraph = getProgram().getCallGraph();
final LiveRangeVariables.LiveRangeVariablesByStatement liveRangeVariablesByStatement = liveRangeVariables.getLiveRangeVariablesByStatement();
// Find all alive vars from the recursive callers of each procedure
Map<ProcedureRef, Collection<VariableRef>> callersAlive = new LinkedHashMap<>();
Collection<Procedure> procedures = getProgram().getScope().getAllProcedures(true);
for(Procedure procedure : procedures) {
Collection<VariableRef> procCallersAlive = new LinkedHashSet<>();
final Collection<CallGraph.CallBlock.Call> callers = callGraph.getRecursiveCallers(procedure.getRef());
for(CallGraph.CallBlock.Call caller : callers) {
final Integer callStatementIdx = caller.getCallStatementIdx();
final List<VariableRef> callStatementAlive = liveRangeVariables.getAlive(callStatementIdx);
procCallersAlive.addAll(callStatementAlive);
}
callersAlive.put(procedure.getRef(), procCallersAlive);
}
// Find all alive variables for all statements by adding the alive from all recursive callers
final LinkedHashMap<Integer, Collection<VariableRef>> statementAliveEffective = new LinkedHashMap<>();
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
final Procedure procedure = block.getProcedure(getProgram());
for(Statement statement : block.getStatements()) {
final Collection<VariableRef> aliveStmt = new LinkedHashSet<>();
aliveStmt.addAll(liveRangeVariablesByStatement.getAlive(statement.getIndex()));
if(procedure!=null) {
aliveStmt.addAll(callersAlive.get(procedure.getRef()));
}
statementAliveEffective.put(statement.getIndex(), aliveStmt);
}
}
return new LiveRangeVariablesEffectiveSimple(statementAliveEffective);
}
}