mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-28 16:31:36 +00:00
parent
162b29b2d4
commit
42ecee2f94
8
src/main/fragment/pbuc1_le_pbuc2_then_la1.asm
Normal file
8
src/main/fragment/pbuc1_le_pbuc2_then_la1.asm
Normal file
@ -0,0 +1,8 @@
|
||||
lda #>{c1}
|
||||
cmp #>{c2}
|
||||
bne !+
|
||||
lda #<{c1}
|
||||
cmp #<{c2}
|
||||
beq {la1}
|
||||
!:
|
||||
bcc {la1}
|
4
src/main/fragment/pssz1=pssz2.asm
Normal file
4
src/main/fragment/pssz1=pssz2.asm
Normal file
@ -0,0 +1,4 @@
|
||||
lda {z2}
|
||||
sta {z1}
|
||||
lda {z2}+1
|
||||
sta {z1}+1
|
@ -1,12 +1,11 @@
|
||||
package dk.camelot64.kickc.model;
|
||||
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
import dk.camelot64.kickc.passes.calcs.PassNCalcVariableReferenceInfos;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Cached information about which variables/constants are defined/referenced/used in which statements / blocks / symbols .
|
||||
@ -24,11 +23,14 @@ public class VariableReferenceInfos {
|
||||
/** Variables used in each block. */
|
||||
private Map<LabelRef, Collection<VariableRef>> blockUsedVars;
|
||||
|
||||
/** Variables referenced in each statement. */
|
||||
private Map<Integer, Collection<VariableRef>> stmtReferencedVars;
|
||||
/** For each block this is the closure of all successor blocks. */
|
||||
private Map<LabelRef, Collection<LabelRef>> blockSuccessorClosure;
|
||||
|
||||
/** Variables defined in each statement. */
|
||||
private Map<Integer, Collection<VariableRef>> stmtDefinedVars;
|
||||
/** References to variables/constants by block label. */
|
||||
private Map<LabelRef, Collection<VariableReferenceInfos.ReferenceToSymbolVar>> blockVarReferences;
|
||||
|
||||
/** References to variables/constants by statement index. */
|
||||
private Map<Integer, Collection<VariableReferenceInfos.ReferenceToSymbolVar>> statementVarReferences;
|
||||
|
||||
/** All references to symbol variables (constants/variables). References can be either statements or symbols in the symbol table */
|
||||
private Map<SymbolVariableRef, Collection<ReferenceToSymbolVar>> symbolVarReferences;
|
||||
@ -127,22 +129,30 @@ public class VariableReferenceInfos {
|
||||
public VariableReferenceInfos(
|
||||
Map<LabelRef, Collection<VariableRef>> blockReferencedVars,
|
||||
Map<LabelRef, Collection<VariableRef>> blockUsedVars,
|
||||
Map<Integer, Collection<VariableRef>> stmtReferencedVars,
|
||||
Map<Integer, Collection<VariableRef>> stmtDefinedVars,
|
||||
Map<SymbolVariableRef, Collection<ReferenceToSymbolVar>> symbolVarReferences
|
||||
|
||||
Map<LabelRef, Collection<LabelRef>> blockSuccessorClosure,
|
||||
Map<SymbolVariableRef, Collection<ReferenceToSymbolVar>> symbolVarReferences,
|
||||
Map<LabelRef, Collection<VariableReferenceInfos.ReferenceToSymbolVar>> blockVarReferences,
|
||||
Map<Integer, Collection<VariableReferenceInfos.ReferenceToSymbolVar>> statementVarReferences
|
||||
) {
|
||||
this.blockReferencedVars = blockReferencedVars;
|
||||
this.blockUsedVars = blockUsedVars;
|
||||
this.stmtDefinedVars = stmtDefinedVars;
|
||||
this.stmtReferencedVars = stmtReferencedVars;
|
||||
this.blockSuccessorClosure = blockSuccessorClosure;
|
||||
this.symbolVarReferences = symbolVarReferences;
|
||||
|
||||
this.blockVarReferences = blockVarReferences;
|
||||
this.statementVarReferences = statementVarReferences;
|
||||
}
|
||||
|
||||
public String getSizeInfo() {
|
||||
StringBuilder sizeInfo = new StringBuilder();
|
||||
if(blockReferencedVars!=null) {
|
||||
if(blockSuccessorClosure != null) {
|
||||
sizeInfo.append("blockSuccessorClosure " + blockSuccessorClosure.size() + " labels ");
|
||||
int sub = 0;
|
||||
for(Collection<LabelRef> labelRefs : blockSuccessorClosure.values()) {
|
||||
sub += labelRefs.size();
|
||||
}
|
||||
sizeInfo.append(" " + sub + " labels" + "\n");
|
||||
}
|
||||
if(blockReferencedVars != null) {
|
||||
sizeInfo.append("blockReferencedVars " + blockReferencedVars.size() + " labels ");
|
||||
int sub = 0;
|
||||
for(Collection<VariableRef> variableRefs : blockReferencedVars.values()) {
|
||||
@ -150,7 +160,7 @@ public class VariableReferenceInfos {
|
||||
}
|
||||
sizeInfo.append(" " + sub + " varrefs" + "\n");
|
||||
}
|
||||
if(blockUsedVars!=null) {
|
||||
if(blockUsedVars != null) {
|
||||
sizeInfo.append("blockUsedVars " + blockUsedVars.size() + " labels ");
|
||||
int sub = 0;
|
||||
for(Collection<VariableRef> variableRefs : blockUsedVars.values()) {
|
||||
@ -158,22 +168,6 @@ public class VariableReferenceInfos {
|
||||
}
|
||||
sizeInfo.append(" " + sub + " varrefs" + "\n");
|
||||
}
|
||||
{
|
||||
sizeInfo.append("stmtDefinedVars " + stmtDefinedVars.size() + " ints ");
|
||||
int sub = 0;
|
||||
for(Collection<VariableRef> variableRefs : stmtDefinedVars.values()) {
|
||||
sub += variableRefs.size();
|
||||
}
|
||||
sizeInfo.append(" " + sub + " varrefs" + "\n");
|
||||
}
|
||||
{
|
||||
sizeInfo.append("stmtReferencedVars " + stmtReferencedVars.size() + " ints ");
|
||||
int sub = 0;
|
||||
for(Collection<VariableRef> variableRefs : stmtReferencedVars.values()) {
|
||||
sub += variableRefs.size();
|
||||
}
|
||||
sizeInfo.append(" " + sub + " varrefs" + "\n");
|
||||
}
|
||||
{
|
||||
sizeInfo.append("symbolVarReferences " + symbolVarReferences.size() + " SymbolVariableRefs ");
|
||||
int sub = 0;
|
||||
@ -182,6 +176,22 @@ public class VariableReferenceInfos {
|
||||
}
|
||||
sizeInfo.append(" " + sub + " ReferenceToSymbolVars" + "\n");
|
||||
}
|
||||
{
|
||||
sizeInfo.append("statementVarReferences " + statementVarReferences.size() + " statements ");
|
||||
int sub = 0;
|
||||
for(Collection<ReferenceToSymbolVar> value : statementVarReferences.values()) {
|
||||
sub += value.size();
|
||||
}
|
||||
sizeInfo.append(" " + sub + " ReferenceToSymbolVars" + "\n");
|
||||
}
|
||||
{
|
||||
sizeInfo.append("blockVarReferences " + blockVarReferences.size() + " blocks ");
|
||||
int sub = 0;
|
||||
for(Collection<ReferenceToSymbolVar> value : blockVarReferences.values()) {
|
||||
sub += value.size();
|
||||
}
|
||||
sizeInfo.append(" " + sub + " ReferenceToSymbolVars" + "\n");
|
||||
}
|
||||
return sizeInfo.toString();
|
||||
}
|
||||
|
||||
@ -222,30 +232,52 @@ public class VariableReferenceInfos {
|
||||
* @return Variables defined by the statement
|
||||
*/
|
||||
public Collection<VariableRef> getDefinedVars(Statement stmt) {
|
||||
return stmtDefinedVars.get(stmt.getIndex());
|
||||
Collection<ReferenceToSymbolVar> referenceToSymbolVars = statementVarReferences.get(stmt.getIndex());
|
||||
List<VariableRef> variableRefs = referenceToSymbolVars
|
||||
.stream()
|
||||
.filter(referenceToSymbolVar -> referenceToSymbolVar.getReferenced() instanceof VariableRef)
|
||||
.filter(referenceToSymbolVar -> ReferenceToSymbolVar.ReferenceType.DEFINE.equals(referenceToSymbolVar.getReferenceType()))
|
||||
.map(ReferenceToSymbolVar::getReferenced)
|
||||
.map(symbolVariableRef -> (VariableRef) symbolVariableRef)
|
||||
.collect(Collectors.toList());
|
||||
return variableRefs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the variables referenced (used or defined) in a statement
|
||||
*
|
||||
* @param statement The statement to examine
|
||||
* @param stmt The statement to examine
|
||||
* @return The referenced variables
|
||||
*/
|
||||
public Collection<VariableRef> getReferencedVars(Statement statement) {
|
||||
return stmtReferencedVars.get(statement.getIndex());
|
||||
public Collection<VariableRef> getReferencedVars(Statement stmt) {
|
||||
// Test if new structure is compatible
|
||||
Collection<ReferenceToSymbolVar> referenceToSymbolVars = statementVarReferences.get(stmt.getIndex());
|
||||
List<VariableRef> variableRefs =
|
||||
referenceToSymbolVars
|
||||
.stream()
|
||||
.filter(referenceToSymbolVar -> referenceToSymbolVar.getReferenced() instanceof VariableRef)
|
||||
.map(ReferenceToSymbolVar::getReferenced)
|
||||
.map(symbolVariableRef -> (VariableRef)symbolVariableRef)
|
||||
.collect(Collectors.toList());
|
||||
return variableRefs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the variables used, but not defined, in a statement
|
||||
*
|
||||
* @param statement The statement to examine
|
||||
* @param stmt The statement to examine
|
||||
* @return The used variables (not including defined variables)
|
||||
*/
|
||||
public Collection<VariableRef> getUsedVars(Statement statement) {
|
||||
LinkedHashSet<VariableRef> used = new LinkedHashSet<>();
|
||||
used.addAll(getReferencedVars(statement));
|
||||
used.removeAll(getDefinedVars(statement));
|
||||
return used;
|
||||
public Collection<VariableRef> getUsedVars(Statement stmt) {
|
||||
Collection<ReferenceToSymbolVar> referenceToSymbolVars = statementVarReferences.get(stmt.getIndex());
|
||||
List<VariableRef> variableRefs = referenceToSymbolVars
|
||||
.stream()
|
||||
.filter(referenceToSymbolVar -> referenceToSymbolVar.getReferenced() instanceof VariableRef)
|
||||
.filter(referenceToSymbolVar -> ReferenceToSymbolVar.ReferenceType.USE.equals(referenceToSymbolVar.getReferenceType()))
|
||||
.map(ReferenceToSymbolVar::getReferenced)
|
||||
.map(symbolVariableRef -> (VariableRef) symbolVariableRef)
|
||||
.collect(Collectors.toList());
|
||||
return variableRefs;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -255,10 +287,9 @@ public class VariableReferenceInfos {
|
||||
*/
|
||||
public boolean isUnused(SymbolVariableRef variableRef) {
|
||||
Collection<ReferenceToSymbolVar> refs = symbolVarReferences.get(variableRef);
|
||||
if(refs==null) return true;
|
||||
if(refs == null) return true;
|
||||
return !refs.stream()
|
||||
.anyMatch(referenceToSymbolVar -> ReferenceToSymbolVar.ReferenceType.USE.equals(referenceToSymbolVar.getReferenceType())
|
||||
);
|
||||
.anyMatch(referenceToSymbolVar -> ReferenceToSymbolVar.ReferenceType.USE.equals(referenceToSymbolVar.getReferenceType()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -270,7 +301,7 @@ public class VariableReferenceInfos {
|
||||
public Collection<Integer> getConstRefStatements(ConstantRef constRef) {
|
||||
Collection<ReferenceToSymbolVar> refs = symbolVarReferences.get(constRef);
|
||||
LinkedHashSet<Integer> stmts = new LinkedHashSet<>();
|
||||
if(refs!=null) {
|
||||
if(refs != null) {
|
||||
refs.stream()
|
||||
.filter(referenceToSymbolVar -> referenceToSymbolVar instanceof ReferenceInStatement)
|
||||
.forEach(referenceToSymbolVar -> stmts.add(((ReferenceInStatement) referenceToSymbolVar).getStatementIdx()));
|
||||
@ -287,7 +318,7 @@ public class VariableReferenceInfos {
|
||||
public Collection<Integer> getVarRefStatements(VariableRef varRef) {
|
||||
Collection<ReferenceToSymbolVar> refs = symbolVarReferences.get(varRef);
|
||||
LinkedHashSet<Integer> stmts = new LinkedHashSet<>();
|
||||
if(refs!=null) {
|
||||
if(refs != null) {
|
||||
refs.stream()
|
||||
.filter(referenceToSymbolVar -> referenceToSymbolVar instanceof ReferenceInStatement)
|
||||
.forEach(referenceToSymbolVar -> stmts.add(((ReferenceInStatement) referenceToSymbolVar).getStatementIdx()));
|
||||
@ -304,7 +335,7 @@ public class VariableReferenceInfos {
|
||||
public Collection<Integer> getVarUseStatements(VariableRef varRef) {
|
||||
Collection<ReferenceToSymbolVar> refs = symbolVarReferences.get(varRef);
|
||||
LinkedHashSet<Integer> stmts = new LinkedHashSet<>();
|
||||
if(refs!=null) {
|
||||
if(refs != null) {
|
||||
refs.stream()
|
||||
.filter(referenceToSymbolVar -> referenceToSymbolVar instanceof ReferenceInStatement)
|
||||
.filter(referenceToSymbolVar -> ReferenceToSymbolVar.ReferenceType.USE == referenceToSymbolVar.getReferenceType())
|
||||
@ -323,7 +354,7 @@ public class VariableReferenceInfos {
|
||||
public Collection<SymbolVariableRef> getSymbolRefConsts(ConstantRef constRef) {
|
||||
Collection<ReferenceToSymbolVar> refs = symbolVarReferences.get(constRef);
|
||||
LinkedHashSet<SymbolVariableRef> constRefs = new LinkedHashSet<>();
|
||||
if(refs!=null) {
|
||||
if(refs != null) {
|
||||
refs.stream()
|
||||
.filter(referenceToSymbolVar -> ReferenceToSymbolVar.ReferenceType.USE.equals(referenceToSymbolVar.getReferenceType()))
|
||||
.filter(referenceToSymbolVar -> referenceToSymbolVar instanceof ReferenceInSymbol)
|
||||
|
@ -5,7 +5,9 @@ import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.VariableReferenceInfos;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValue;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementLValue;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
import dk.camelot64.kickc.model.symbols.SymbolVariable;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
|
||||
@ -27,14 +29,19 @@ public class PassNCalcVariableReferenceInfos extends PassNCalcBase<VariableRefer
|
||||
public VariableReferenceInfos calculate() {
|
||||
LinkedHashMap<LabelRef, Collection<VariableRef>> blockReferencedVars = new LinkedHashMap<>();
|
||||
LinkedHashMap<LabelRef, Collection<VariableRef>> blockUsedVars = new LinkedHashMap<>();
|
||||
LinkedHashMap<Integer, Collection<VariableRef>> stmtReferenced = new LinkedHashMap<>();
|
||||
LinkedHashMap<Integer, Collection<VariableRef>> stmtDefined = new LinkedHashMap<>();
|
||||
LinkedHashMap<LabelRef, Collection<LabelRef>> blockSuccessors = new LinkedHashMap<>();
|
||||
|
||||
Map<SymbolVariableRef, Collection<VariableReferenceInfos.ReferenceToSymbolVar>> symbolVarReferences = new LinkedHashMap<>();
|
||||
Map<LabelRef, Collection<VariableReferenceInfos.ReferenceToSymbolVar>> blockVarReferences = new LinkedHashMap<>();
|
||||
Map<Integer, Collection<VariableReferenceInfos.ReferenceToSymbolVar>> statementVarReferences = new LinkedHashMap<>();
|
||||
|
||||
blockDirectVarRefsMap = new LinkedHashMap<>();
|
||||
blockDirectUsedVarsMap = new LinkedHashMap<>();
|
||||
for(ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) {
|
||||
LinkedHashSet<VariableRef> blockDirectVarRefs = new LinkedHashSet<>();
|
||||
LinkedHashSet<VariableRef> blockDirectUsedVars = new LinkedHashSet<>();
|
||||
blockVarReferences.putIfAbsent(block.getLabel(), new ArrayList<>());
|
||||
Collection<VariableReferenceInfos.ReferenceToSymbolVar> blockSymbols = blockVarReferences.get(block.getLabel());
|
||||
for(Statement statement : block.getStatements()) {
|
||||
LinkedHashSet<SymbolVariableRef> stmtSymbolVarRefs = new LinkedHashSet<>();
|
||||
LinkedHashSet<VariableRef> stmtVarRefs = new LinkedHashSet<>();
|
||||
@ -51,29 +58,29 @@ public class PassNCalcVariableReferenceInfos extends PassNCalcBase<VariableRefer
|
||||
stmtUsedVars.removeAll(stmtDefinedVars);
|
||||
blockDirectVarRefs.addAll(stmtVarRefs);
|
||||
blockDirectUsedVars.addAll(stmtUsedVars);
|
||||
|
||||
// Add variable definitions to the statement
|
||||
stmtDefined.put(statement.getIndex(), stmtDefinedVars);
|
||||
statementVarReferences.putIfAbsent(statement.getIndex(), new ArrayList<>());
|
||||
Collection<VariableReferenceInfos.ReferenceToSymbolVar> stmtSymbols = statementVarReferences.get(statement.getIndex());
|
||||
// Identify statement defining variables
|
||||
for(VariableRef variableRef : stmtDefinedVars) {
|
||||
symbolVarReferences.putIfAbsent(variableRef, new ArrayList<>());
|
||||
Collection<VariableReferenceInfos.ReferenceToSymbolVar> references = symbolVarReferences.get(variableRef);
|
||||
references.add(new VariableReferenceInfos.ReferenceInStatement(statement.getIndex(), VariableReferenceInfos.ReferenceToSymbolVar.ReferenceType.DEFINE, variableRef));
|
||||
Collection<VariableReferenceInfos.ReferenceToSymbolVar> varReferences = symbolVarReferences.get(variableRef);
|
||||
VariableReferenceInfos.ReferenceInStatement referenceInStmt = new VariableReferenceInfos.ReferenceInStatement(statement.getIndex(), VariableReferenceInfos.ReferenceToSymbolVar.ReferenceType.DEFINE, variableRef);
|
||||
varReferences.add(referenceInStmt);
|
||||
stmtSymbols.add(referenceInStmt);
|
||||
if(!blockSymbols.contains(referenceInStmt)) blockSymbols.add(referenceInStmt);
|
||||
}
|
||||
// Gather statements referencing variables/constants
|
||||
for(SymbolVariableRef referencedVarRef : stmtSymbolVarRefs) {
|
||||
if(!stmtDefinedVars.contains(referencedVarRef)) {
|
||||
symbolVarReferences.putIfAbsent(referencedVarRef, new ArrayList<>());
|
||||
Collection<VariableReferenceInfos.ReferenceToSymbolVar> references = symbolVarReferences.get(referencedVarRef);
|
||||
references.add(
|
||||
new VariableReferenceInfos.ReferenceInStatement(
|
||||
statement.getIndex(),
|
||||
VariableReferenceInfos.ReferenceToSymbolVar.ReferenceType.USE,
|
||||
referencedVarRef));
|
||||
VariableReferenceInfos.ReferenceInStatement referenceInStmt = new VariableReferenceInfos.ReferenceInStatement(statement.getIndex(), VariableReferenceInfos.ReferenceToSymbolVar.ReferenceType.USE, referencedVarRef);
|
||||
references.add(referenceInStmt);
|
||||
stmtSymbols.add(referenceInStmt);
|
||||
if(!blockSymbols.contains(referenceInStmt)) blockSymbols.add(referenceInStmt);
|
||||
}
|
||||
}
|
||||
// Add variable reference to the statement
|
||||
stmtReferenced.put(statement.getIndex(), stmtVarRefs);
|
||||
}
|
||||
LabelRef blockLabel = block.getLabel();
|
||||
blockDirectVarRefsMap.put(blockLabel, blockDirectVarRefs);
|
||||
@ -83,9 +90,12 @@ public class PassNCalcVariableReferenceInfos extends PassNCalcBase<VariableRefer
|
||||
LabelRef blockLabel = block.getLabel();
|
||||
LinkedHashSet<VariableRef> blockRecursiveVarRefs = new LinkedHashSet<>();
|
||||
LinkedHashSet<VariableRef> blockRecursiveUsedVars = new LinkedHashSet<>();
|
||||
addReferencedVars(block.getLabel(), block, blockRecursiveVarRefs, blockRecursiveUsedVars, new ArrayList<>());
|
||||
findReferencedVars(block.getLabel(), block, blockRecursiveVarRefs, blockRecursiveUsedVars, new ArrayList<>());
|
||||
blockReferencedVars.put(blockLabel, blockRecursiveVarRefs);
|
||||
blockUsedVars.put(blockLabel, blockRecursiveUsedVars);
|
||||
LinkedHashSet<LabelRef> successorClosure = new LinkedHashSet<>();
|
||||
findSuccessorClosure(block.getLabel(), successorClosure, new ArrayList<>());
|
||||
blockSuccessors.put(blockLabel, successorClosure);
|
||||
}
|
||||
// Gather symbols in the symbol table referencing other variables/constants
|
||||
Collection<SymbolVariable> allSymbolVariables = getProgram().getScope().getAllSymbolVariables(true);
|
||||
@ -101,7 +111,7 @@ public class PassNCalcVariableReferenceInfos extends PassNCalcBase<VariableRefer
|
||||
}
|
||||
});
|
||||
}
|
||||
VariableReferenceInfos variableReferenceInfos = new VariableReferenceInfos(blockReferencedVars, blockUsedVars, stmtReferenced, stmtDefined, symbolVarReferences);
|
||||
VariableReferenceInfos variableReferenceInfos = new VariableReferenceInfos(blockReferencedVars, blockUsedVars, blockSuccessors, symbolVarReferences, blockVarReferences, statementVarReferences);
|
||||
if(getLog().isVerboseSSAOptimize()) {
|
||||
getLog().append(variableReferenceInfos.getSizeInfo());
|
||||
}
|
||||
@ -165,7 +175,7 @@ public class PassNCalcVariableReferenceInfos extends PassNCalcBase<VariableRefer
|
||||
* @param usedVars the set of referenced variables
|
||||
* @param visited The blocks already visited during the search. Used to stop infinite recursion
|
||||
*/
|
||||
private void addReferencedVars(LabelRef labelRef, ControlFlowBlock block, LinkedHashSet<VariableRef> referencedVars, LinkedHashSet<VariableRef> usedVars, Collection<LabelRef> visited) {
|
||||
private void findReferencedVars(LabelRef labelRef, ControlFlowBlock block, LinkedHashSet<VariableRef> referencedVars, LinkedHashSet<VariableRef> usedVars, Collection<LabelRef> visited) {
|
||||
if(labelRef == null || visited.contains(labelRef))
|
||||
return;
|
||||
visited.add(labelRef);
|
||||
@ -176,11 +186,32 @@ public class PassNCalcVariableReferenceInfos extends PassNCalcBase<VariableRefer
|
||||
}
|
||||
referencedVars.addAll(blockDirectVarRefsMap.get(labelRef));
|
||||
usedVars.addAll(blockDirectUsedVarsMap.get(labelRef));
|
||||
addReferencedVars(block.getDefaultSuccessor(), null, referencedVars, usedVars, visited);
|
||||
addReferencedVars(block.getConditionalSuccessor(), null, referencedVars, usedVars, visited);
|
||||
addReferencedVars(block.getCallSuccessor(), null, referencedVars, usedVars, visited);
|
||||
findReferencedVars(block.getDefaultSuccessor(), null, referencedVars, usedVars, visited);
|
||||
findReferencedVars(block.getConditionalSuccessor(), null, referencedVars, usedVars, visited);
|
||||
findReferencedVars(block.getCallSuccessor(), null, referencedVars, usedVars, visited);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively get all blocks in the closure of successors & calls for a specific block
|
||||
*
|
||||
* @param labelRef The block to examine
|
||||
* @param successorClosure the set of all blocks that are successors (including called methods).
|
||||
* @param visited The blocks already visited during the search. Used to stop infinite recursion.
|
||||
*/
|
||||
private void findSuccessorClosure(LabelRef labelRef, LinkedHashSet<LabelRef> successorClosure, Collection<LabelRef> visited) {
|
||||
if(labelRef == null || visited.contains(labelRef))
|
||||
return;
|
||||
visited.add(labelRef);
|
||||
ControlFlowBlock block = getProgram().getGraph().getBlock(labelRef);
|
||||
if(block == null)
|
||||
return;
|
||||
successorClosure.add(labelRef);
|
||||
findSuccessorClosure(block.getDefaultSuccessor(), successorClosure, visited);
|
||||
findSuccessorClosure(block.getConditionalSuccessor(), successorClosure, visited);
|
||||
findSuccessorClosure(block.getCallSuccessor(), successorClosure, visited);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the variables defined by a statement
|
||||
*
|
||||
|
@ -638,6 +638,16 @@ public class TestPrograms {
|
||||
}
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testStructPtr25() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-ptr-25");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStructPtr24() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-ptr-24");
|
||||
}
|
||||
|
||||
/* TODO: Fix array of struct containing array https://gitlab.com/camelot/kickc/issues/274
|
||||
@Test
|
||||
public void testStructPtr23() throws IOException, URISyntaxException {
|
||||
|
23
src/test/kc/struct-ptr-24.kc
Normal file
23
src/test/kc/struct-ptr-24.kc
Normal file
@ -0,0 +1,23 @@
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
struct fileentry {
|
||||
BYTE bFlag;
|
||||
BYTE bError;
|
||||
};
|
||||
|
||||
typedef struct fileentry ENTRY;
|
||||
|
||||
ENTRY *filesEnd;
|
||||
ENTRY *dir;
|
||||
|
||||
void main(){
|
||||
ENTRY *file;
|
||||
while(file != filesEnd){
|
||||
PrintName(file);
|
||||
++file;
|
||||
}
|
||||
}
|
||||
|
||||
void PrintName(ENTRY *file) {
|
||||
if (file == dir) *(BYTE *)0xC7 = 1;
|
||||
}
|
10
src/test/kc/struct-ptr-25.kc
Normal file
10
src/test/kc/struct-ptr-25.kc
Normal file
@ -0,0 +1,10 @@
|
||||
char *fileCur;
|
||||
char *fileTop;
|
||||
char *filesEnd;
|
||||
char *file;
|
||||
|
||||
void main(void) {
|
||||
if (fileTop == filesEnd) --fileTop;
|
||||
if (file <= fileCur) --fileCur;
|
||||
if (fileCur < fileTop) fileCur = fileTop;
|
||||
}
|
44
src/test/ref/struct-ptr-24.asm
Normal file
44
src/test/ref/struct-ptr-24.asm
Normal file
@ -0,0 +1,44 @@
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.const SIZEOF_STRUCT_FILEENTRY = 2
|
||||
.label filesEnd = 0
|
||||
.label dir = 0
|
||||
main: {
|
||||
.label file = 2
|
||||
lda #<0
|
||||
sta.z file
|
||||
sta.z file+1
|
||||
b1:
|
||||
lda.z file+1
|
||||
cmp #>filesEnd
|
||||
bne b2
|
||||
lda.z file
|
||||
cmp #<filesEnd
|
||||
bne b2
|
||||
rts
|
||||
b2:
|
||||
jsr PrintName
|
||||
lda #SIZEOF_STRUCT_FILEENTRY
|
||||
clc
|
||||
adc.z file
|
||||
sta.z file
|
||||
bcc !+
|
||||
inc.z file+1
|
||||
!:
|
||||
jmp b1
|
||||
}
|
||||
// PrintName(struct fileentry* zeropage(2) file)
|
||||
PrintName: {
|
||||
.label file = 2
|
||||
lda.z file+1
|
||||
cmp #>dir
|
||||
bne breturn
|
||||
lda.z file
|
||||
cmp #<dir
|
||||
bne breturn
|
||||
lda #1
|
||||
sta $c7
|
||||
breturn:
|
||||
rts
|
||||
}
|
35
src/test/ref/struct-ptr-24.cfg
Normal file
35
src/test/ref/struct-ptr-24.cfg
Normal file
@ -0,0 +1,35 @@
|
||||
@begin: scope:[] from
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
[2] call main
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
[3] phi()
|
||||
main: scope:[main] from @1
|
||||
[4] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@3
|
||||
[5] (struct fileentry*) main::file#2 ← phi( main/(struct fileentry*) 0 main::@3/(struct fileentry*) main::file#1 )
|
||||
[6] if((struct fileentry*) main::file#2!=(const struct fileentry*) filesEnd#0) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[7] return
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[8] (struct fileentry*) PrintName::file#0 ← (struct fileentry*) main::file#2
|
||||
[9] call PrintName
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@2
|
||||
[10] (struct fileentry*) main::file#1 ← (struct fileentry*) main::file#2 + (const byte) SIZEOF_STRUCT_FILEENTRY
|
||||
to:main::@1
|
||||
PrintName: scope:[PrintName] from main::@2
|
||||
[11] if((struct fileentry*) PrintName::file#0!=(const struct fileentry*) dir#0) goto PrintName::@return
|
||||
to:PrintName::@1
|
||||
PrintName::@1: scope:[PrintName] from PrintName
|
||||
[12] *((byte*) 199) ← (byte) 1
|
||||
to:PrintName::@return
|
||||
PrintName::@return: scope:[PrintName] from PrintName PrintName::@1
|
||||
[13] return
|
||||
to:@return
|
561
src/test/ref/struct-ptr-24.log
Normal file
561
src/test/ref/struct-ptr-24.log
Normal file
@ -0,0 +1,561 @@
|
||||
Fixing pointer increment (struct fileentry*) main::file ← ++ (struct fileentry*) main::file
|
||||
Identified constant variable (struct fileentry*) filesEnd
|
||||
Identified constant variable (struct fileentry*) dir
|
||||
Culled Empty Block (label) main::@4
|
||||
Culled Empty Block (label) main::@3
|
||||
Culled Empty Block (label) main::@5
|
||||
Culled Empty Block (label) main::@6
|
||||
Culled Empty Block (label) @1
|
||||
Culled Empty Block (label) PrintName::@1
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
(struct fileentry*) filesEnd#0 ← (struct fileentry*) 0
|
||||
(struct fileentry*) dir#0 ← (struct fileentry*) 0
|
||||
to:@2
|
||||
main: scope:[main] from @2
|
||||
(struct fileentry*) main::file#0 ← (struct fileentry*) 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@7
|
||||
(struct fileentry*) main::file#2 ← phi( main/(struct fileentry*) main::file#0 main::@7/(struct fileentry*) main::file#1 )
|
||||
(bool~) main::$0 ← (struct fileentry*) main::file#2 != (struct fileentry*) filesEnd#0
|
||||
if((bool~) main::$0) goto main::@2
|
||||
to:main::@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
(struct fileentry*) main::file#3 ← phi( main::@1/(struct fileentry*) main::file#2 )
|
||||
(struct fileentry*) PrintName::file#0 ← (struct fileentry*) main::file#3
|
||||
call PrintName
|
||||
to:main::@7
|
||||
main::@7: scope:[main] from main::@2
|
||||
(struct fileentry*) main::file#4 ← phi( main::@2/(struct fileentry*) main::file#3 )
|
||||
(struct fileentry*) main::file#1 ← (struct fileentry*) main::file#4 + (const byte) SIZEOF_STRUCT_FILEENTRY
|
||||
to:main::@1
|
||||
main::@return: scope:[main] from main::@1
|
||||
return
|
||||
to:@return
|
||||
PrintName: scope:[PrintName] from main::@2
|
||||
(struct fileentry*) PrintName::file#1 ← phi( main::@2/(struct fileentry*) PrintName::file#0 )
|
||||
(bool~) PrintName::$0 ← (struct fileentry*) PrintName::file#1 == (struct fileentry*) dir#0
|
||||
(bool~) PrintName::$1 ← ! (bool~) PrintName::$0
|
||||
if((bool~) PrintName::$1) goto PrintName::@return
|
||||
to:PrintName::@2
|
||||
PrintName::@2: scope:[PrintName] from PrintName
|
||||
(byte*~) PrintName::$2 ← ((byte*)) (number) $c7
|
||||
*((byte*~) PrintName::$2) ← (number) 1
|
||||
to:PrintName::@return
|
||||
PrintName::@return: scope:[PrintName] from PrintName PrintName::@2
|
||||
return
|
||||
to:@return
|
||||
@2: scope:[] from @begin
|
||||
call main
|
||||
to:@3
|
||||
@3: scope:[] from @2
|
||||
to:@end
|
||||
@end: scope:[] from @3
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
(label) @2
|
||||
(label) @3
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) PrintName((struct fileentry*) PrintName::file)
|
||||
(bool~) PrintName::$0
|
||||
(bool~) PrintName::$1
|
||||
(byte*~) PrintName::$2
|
||||
(label) PrintName::@2
|
||||
(label) PrintName::@return
|
||||
(struct fileentry*) PrintName::file
|
||||
(struct fileentry*) PrintName::file#0
|
||||
(struct fileentry*) PrintName::file#1
|
||||
(const byte) SIZEOF_STRUCT_FILEENTRY = (byte) 2
|
||||
(struct fileentry*) dir
|
||||
(struct fileentry*) dir#0
|
||||
(byte) fileentry::bError
|
||||
(byte) fileentry::bFlag
|
||||
(struct fileentry*) filesEnd
|
||||
(struct fileentry*) filesEnd#0
|
||||
(void()) main()
|
||||
(bool~) main::$0
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@7
|
||||
(label) main::@return
|
||||
(struct fileentry*) main::file
|
||||
(struct fileentry*) main::file#0
|
||||
(struct fileentry*) main::file#1
|
||||
(struct fileentry*) main::file#2
|
||||
(struct fileentry*) main::file#3
|
||||
(struct fileentry*) main::file#4
|
||||
|
||||
Adding number conversion cast (unumber) 1 in *((byte*~) PrintName::$2) ← (number) 1
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Inlining cast (byte*~) PrintName::$2 ← (byte*)(number) $c7
|
||||
Inlining cast *((byte*~) PrintName::$2) ← (unumber)(number) 1
|
||||
Successful SSA optimization Pass2InlineCast
|
||||
Simplifying constant pointer cast (byte*) 199
|
||||
Simplifying constant integer cast 1
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (byte) 1
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Inversing boolean not [14] (bool~) PrintName::$1 ← (struct fileentry*) PrintName::file#1 != (struct fileentry*) dir#0 from [13] (bool~) PrintName::$0 ← (struct fileentry*) PrintName::file#1 == (struct fileentry*) dir#0
|
||||
Successful SSA optimization Pass2UnaryNotSimplification
|
||||
Alias (struct fileentry*) main::file#2 = (struct fileentry*) main::file#3 (struct fileentry*) main::file#4
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Identical Phi Values (struct fileentry*) PrintName::file#1 (struct fileentry*) PrintName::file#0
|
||||
Successful SSA optimization Pass2IdenticalPhiElimination
|
||||
Simple Condition (bool~) main::$0 [5] if((struct fileentry*) main::file#2!=(struct fileentry*) filesEnd#0) goto main::@2
|
||||
Simple Condition (bool~) PrintName::$1 [15] if((struct fileentry*) PrintName::file#0!=(struct fileentry*) dir#0) goto PrintName::@return
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant (const struct fileentry*) filesEnd#0 = (struct fileentry*) 0
|
||||
Constant (const struct fileentry*) dir#0 = (struct fileentry*) 0
|
||||
Constant (const struct fileentry*) main::file#0 = (struct fileentry*) 0
|
||||
Constant (const byte*) PrintName::$2 = (byte*) 199
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Inlining constant with var siblings (const struct fileentry*) main::file#0
|
||||
Constant inlined PrintName::$2 = (byte*) 199
|
||||
Constant inlined main::file#0 = (struct fileentry*) 0
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @2
|
||||
Adding NOP phi() at start of @3
|
||||
Adding NOP phi() at start of @end
|
||||
Adding NOP phi() at start of main
|
||||
CALL GRAPH
|
||||
Calls in [] to main:2
|
||||
Calls in [main] to PrintName:10
|
||||
|
||||
Created 1 initial phi equivalence classes
|
||||
Coalesced [12] main::file#5 ← main::file#1
|
||||
Coalesced down to 1 phi equivalence classes
|
||||
Culled Empty Block (label) @3
|
||||
Renumbering block @2 to @1
|
||||
Renumbering block main::@7 to main::@3
|
||||
Renumbering block PrintName::@2 to PrintName::@1
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @1
|
||||
Adding NOP phi() at start of @end
|
||||
Adding NOP phi() at start of main
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
[2] call main
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
[3] phi()
|
||||
main: scope:[main] from @1
|
||||
[4] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@3
|
||||
[5] (struct fileentry*) main::file#2 ← phi( main/(struct fileentry*) 0 main::@3/(struct fileentry*) main::file#1 )
|
||||
[6] if((struct fileentry*) main::file#2!=(const struct fileentry*) filesEnd#0) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[7] return
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[8] (struct fileentry*) PrintName::file#0 ← (struct fileentry*) main::file#2
|
||||
[9] call PrintName
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@2
|
||||
[10] (struct fileentry*) main::file#1 ← (struct fileentry*) main::file#2 + (const byte) SIZEOF_STRUCT_FILEENTRY
|
||||
to:main::@1
|
||||
PrintName: scope:[PrintName] from main::@2
|
||||
[11] if((struct fileentry*) PrintName::file#0!=(const struct fileentry*) dir#0) goto PrintName::@return
|
||||
to:PrintName::@1
|
||||
PrintName::@1: scope:[PrintName] from PrintName
|
||||
[12] *((byte*) 199) ← (byte) 1
|
||||
to:PrintName::@return
|
||||
PrintName::@return: scope:[PrintName] from PrintName PrintName::@1
|
||||
[13] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(void()) PrintName((struct fileentry*) PrintName::file)
|
||||
(struct fileentry*) PrintName::file
|
||||
(struct fileentry*) PrintName::file#0 13.0
|
||||
(struct fileentry*) dir
|
||||
(byte) fileentry::bError
|
||||
(byte) fileentry::bFlag
|
||||
(struct fileentry*) filesEnd
|
||||
(void()) main()
|
||||
(struct fileentry*) main::file
|
||||
(struct fileentry*) main::file#1 22.0
|
||||
(struct fileentry*) main::file#2 11.0
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ main::file#2 main::file#1 ]
|
||||
Added variable PrintName::file#0 to zero page equivalence class [ PrintName::file#0 ]
|
||||
Complete equivalence classes
|
||||
[ main::file#2 main::file#1 ]
|
||||
[ PrintName::file#0 ]
|
||||
Allocated zp ZP_WORD:2 [ main::file#2 main::file#1 ]
|
||||
Allocated zp ZP_WORD:4 [ PrintName::file#0 ]
|
||||
|
||||
INITIAL ASM
|
||||
Target platform is c64basic
|
||||
// File Comments
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.const SIZEOF_STRUCT_FILEENTRY = 2
|
||||
.label filesEnd = 0
|
||||
.label dir = 0
|
||||
// @begin
|
||||
bbegin:
|
||||
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
b1_from_bbegin:
|
||||
jmp b1
|
||||
// @1
|
||||
b1:
|
||||
// [2] call main
|
||||
// [4] phi from @1 to main [phi:@1->main]
|
||||
main_from_b1:
|
||||
jsr main
|
||||
// [3] phi from @1 to @end [phi:@1->@end]
|
||||
bend_from_b1:
|
||||
jmp bend
|
||||
// @end
|
||||
bend:
|
||||
// main
|
||||
main: {
|
||||
.label file = 2
|
||||
// [5] phi from main to main::@1 [phi:main->main::@1]
|
||||
b1_from_main:
|
||||
// [5] phi (struct fileentry*) main::file#2 = (struct fileentry*) 0 [phi:main->main::@1#0] -- pssz1=pssc1
|
||||
lda #<0
|
||||
sta.z file
|
||||
lda #>0
|
||||
sta.z file+1
|
||||
jmp b1
|
||||
// main::@1
|
||||
b1:
|
||||
// [6] if((struct fileentry*) main::file#2!=(const struct fileentry*) filesEnd#0) goto main::@2 -- pssz1_neq_pssc1_then_la1
|
||||
lda.z file+1
|
||||
cmp #>filesEnd
|
||||
bne b2
|
||||
lda.z file
|
||||
cmp #<filesEnd
|
||||
bne b2
|
||||
jmp breturn
|
||||
// main::@return
|
||||
breturn:
|
||||
// [7] return
|
||||
rts
|
||||
// main::@2
|
||||
b2:
|
||||
// [8] (struct fileentry*) PrintName::file#0 ← (struct fileentry*) main::file#2 -- pssz1=pssz2
|
||||
lda.z file
|
||||
sta.z PrintName.file
|
||||
lda.z file+1
|
||||
sta.z PrintName.file+1
|
||||
// [9] call PrintName
|
||||
jsr PrintName
|
||||
jmp b3
|
||||
// main::@3
|
||||
b3:
|
||||
// [10] (struct fileentry*) main::file#1 ← (struct fileentry*) main::file#2 + (const byte) SIZEOF_STRUCT_FILEENTRY -- pssz1=pssz1_plus_vbuc1
|
||||
lda #SIZEOF_STRUCT_FILEENTRY
|
||||
clc
|
||||
adc.z file
|
||||
sta.z file
|
||||
bcc !+
|
||||
inc.z file+1
|
||||
!:
|
||||
// [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
|
||||
b1_from_b3:
|
||||
// [5] phi (struct fileentry*) main::file#2 = (struct fileentry*) main::file#1 [phi:main::@3->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
}
|
||||
// PrintName
|
||||
// PrintName(struct fileentry* zeropage(4) file)
|
||||
PrintName: {
|
||||
.label file = 4
|
||||
// [11] if((struct fileentry*) PrintName::file#0!=(const struct fileentry*) dir#0) goto PrintName::@return -- pssz1_neq_pssc1_then_la1
|
||||
lda.z file+1
|
||||
cmp #>dir
|
||||
bne breturn
|
||||
lda.z file
|
||||
cmp #<dir
|
||||
bne breturn
|
||||
jmp b1
|
||||
// PrintName::@1
|
||||
b1:
|
||||
// [12] *((byte*) 199) ← (byte) 1 -- _deref_pbuc1=vbuc2
|
||||
lda #1
|
||||
sta $c7
|
||||
jmp breturn
|
||||
// PrintName::@return
|
||||
breturn:
|
||||
// [13] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [6] if((struct fileentry*) main::file#2!=(const struct fileentry*) filesEnd#0) goto main::@2 [ main::file#2 ] ( main:2 [ main::file#2 ] ) always clobbers reg byte a
|
||||
Statement [8] (struct fileentry*) PrintName::file#0 ← (struct fileentry*) main::file#2 [ main::file#2 PrintName::file#0 ] ( main:2 [ main::file#2 PrintName::file#0 ] ) always clobbers reg byte a
|
||||
Statement [10] (struct fileentry*) main::file#1 ← (struct fileentry*) main::file#2 + (const byte) SIZEOF_STRUCT_FILEENTRY [ main::file#1 ] ( main:2 [ main::file#1 ] ) always clobbers reg byte a
|
||||
Statement [11] if((struct fileentry*) PrintName::file#0!=(const struct fileentry*) dir#0) goto PrintName::@return [ ] ( main:2::PrintName:9 [ main::file#2 ] ) always clobbers reg byte a
|
||||
Statement [12] *((byte*) 199) ← (byte) 1 [ ] ( main:2::PrintName:9 [ main::file#2 ] ) always clobbers reg byte a
|
||||
Potential registers zp ZP_WORD:2 [ main::file#2 main::file#1 ] : zp ZP_WORD:2 ,
|
||||
Potential registers zp ZP_WORD:4 [ PrintName::file#0 ] : zp ZP_WORD:4 ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main] 33: zp ZP_WORD:2 [ main::file#2 main::file#1 ]
|
||||
Uplift Scope [PrintName] 13: zp ZP_WORD:4 [ PrintName::file#0 ]
|
||||
Uplift Scope [fileentry]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 776 combination zp ZP_WORD:2 [ main::file#2 main::file#1 ]
|
||||
Uplifting [PrintName] best 776 combination zp ZP_WORD:4 [ PrintName::file#0 ]
|
||||
Uplifting [fileentry] best 776 combination
|
||||
Uplifting [] best 776 combination
|
||||
Coalescing zero page register [ zp ZP_WORD:2 [ main::file#2 main::file#1 ] ] with [ zp ZP_WORD:4 [ PrintName::file#0 ] ] - score: 1
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.const SIZEOF_STRUCT_FILEENTRY = 2
|
||||
.label filesEnd = 0
|
||||
.label dir = 0
|
||||
// @begin
|
||||
bbegin:
|
||||
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
b1_from_bbegin:
|
||||
jmp b1
|
||||
// @1
|
||||
b1:
|
||||
// [2] call main
|
||||
// [4] phi from @1 to main [phi:@1->main]
|
||||
main_from_b1:
|
||||
jsr main
|
||||
// [3] phi from @1 to @end [phi:@1->@end]
|
||||
bend_from_b1:
|
||||
jmp bend
|
||||
// @end
|
||||
bend:
|
||||
// main
|
||||
main: {
|
||||
.label file = 2
|
||||
// [5] phi from main to main::@1 [phi:main->main::@1]
|
||||
b1_from_main:
|
||||
// [5] phi (struct fileentry*) main::file#2 = (struct fileentry*) 0 [phi:main->main::@1#0] -- pssz1=pssc1
|
||||
lda #<0
|
||||
sta.z file
|
||||
lda #>0
|
||||
sta.z file+1
|
||||
jmp b1
|
||||
// main::@1
|
||||
b1:
|
||||
// [6] if((struct fileentry*) main::file#2!=(const struct fileentry*) filesEnd#0) goto main::@2 -- pssz1_neq_pssc1_then_la1
|
||||
lda.z file+1
|
||||
cmp #>filesEnd
|
||||
bne b2
|
||||
lda.z file
|
||||
cmp #<filesEnd
|
||||
bne b2
|
||||
jmp breturn
|
||||
// main::@return
|
||||
breturn:
|
||||
// [7] return
|
||||
rts
|
||||
// main::@2
|
||||
b2:
|
||||
// [8] (struct fileentry*) PrintName::file#0 ← (struct fileentry*) main::file#2
|
||||
// [9] call PrintName
|
||||
jsr PrintName
|
||||
jmp b3
|
||||
// main::@3
|
||||
b3:
|
||||
// [10] (struct fileentry*) main::file#1 ← (struct fileentry*) main::file#2 + (const byte) SIZEOF_STRUCT_FILEENTRY -- pssz1=pssz1_plus_vbuc1
|
||||
lda #SIZEOF_STRUCT_FILEENTRY
|
||||
clc
|
||||
adc.z file
|
||||
sta.z file
|
||||
bcc !+
|
||||
inc.z file+1
|
||||
!:
|
||||
// [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
|
||||
b1_from_b3:
|
||||
// [5] phi (struct fileentry*) main::file#2 = (struct fileentry*) main::file#1 [phi:main::@3->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
}
|
||||
// PrintName
|
||||
// PrintName(struct fileentry* zeropage(2) file)
|
||||
PrintName: {
|
||||
.label file = 2
|
||||
// [11] if((struct fileentry*) PrintName::file#0!=(const struct fileentry*) dir#0) goto PrintName::@return -- pssz1_neq_pssc1_then_la1
|
||||
lda.z file+1
|
||||
cmp #>dir
|
||||
bne breturn
|
||||
lda.z file
|
||||
cmp #<dir
|
||||
bne breturn
|
||||
jmp b1
|
||||
// PrintName::@1
|
||||
b1:
|
||||
// [12] *((byte*) 199) ← (byte) 1 -- _deref_pbuc1=vbuc2
|
||||
lda #1
|
||||
sta $c7
|
||||
jmp breturn
|
||||
// PrintName::@return
|
||||
breturn:
|
||||
// [13] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp bend
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp breturn
|
||||
Removing instruction jmp b3
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction lda #>0
|
||||
Succesful ASM optimization Pass5UnnecesaryLoadElimination
|
||||
Removing instruction b1_from_bbegin:
|
||||
Removing instruction b1:
|
||||
Removing instruction main_from_b1:
|
||||
Removing instruction bend_from_b1:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction bend:
|
||||
Removing instruction b1_from_main:
|
||||
Removing instruction breturn:
|
||||
Removing instruction b3:
|
||||
Removing instruction b1_from_b3:
|
||||
Removing instruction b1:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
Updating BasicUpstart to call main directly
|
||||
Removing instruction jsr main
|
||||
Succesful ASM optimization Pass5SkipBegin
|
||||
Removing instruction bbegin:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) PrintName((struct fileentry*) PrintName::file)
|
||||
(label) PrintName::@1
|
||||
(label) PrintName::@return
|
||||
(struct fileentry*) PrintName::file
|
||||
(struct fileentry*) PrintName::file#0 file zp ZP_WORD:2 13.0
|
||||
(const byte) SIZEOF_STRUCT_FILEENTRY SIZEOF_STRUCT_FILEENTRY = (byte) 2
|
||||
(struct fileentry*) dir
|
||||
(const struct fileentry*) dir#0 dir = (struct fileentry*) 0
|
||||
(byte) fileentry::bError
|
||||
(byte) fileentry::bFlag
|
||||
(struct fileentry*) filesEnd
|
||||
(const struct fileentry*) filesEnd#0 filesEnd = (struct fileentry*) 0
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@return
|
||||
(struct fileentry*) main::file
|
||||
(struct fileentry*) main::file#1 file zp ZP_WORD:2 22.0
|
||||
(struct fileentry*) main::file#2 file zp ZP_WORD:2 11.0
|
||||
|
||||
zp ZP_WORD:2 [ main::file#2 main::file#1 PrintName::file#0 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 528
|
||||
|
||||
// File Comments
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.const SIZEOF_STRUCT_FILEENTRY = 2
|
||||
.label filesEnd = 0
|
||||
.label dir = 0
|
||||
// @begin
|
||||
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
// @1
|
||||
// [2] call main
|
||||
// [4] phi from @1 to main [phi:@1->main]
|
||||
// [3] phi from @1 to @end [phi:@1->@end]
|
||||
// @end
|
||||
// main
|
||||
main: {
|
||||
.label file = 2
|
||||
// [5] phi from main to main::@1 [phi:main->main::@1]
|
||||
// [5] phi (struct fileentry*) main::file#2 = (struct fileentry*) 0 [phi:main->main::@1#0] -- pssz1=pssc1
|
||||
lda #<0
|
||||
sta.z file
|
||||
sta.z file+1
|
||||
// main::@1
|
||||
b1:
|
||||
// while(file != filesEnd)
|
||||
// [6] if((struct fileentry*) main::file#2!=(const struct fileentry*) filesEnd#0) goto main::@2 -- pssz1_neq_pssc1_then_la1
|
||||
lda.z file+1
|
||||
cmp #>filesEnd
|
||||
bne b2
|
||||
lda.z file
|
||||
cmp #<filesEnd
|
||||
bne b2
|
||||
// main::@return
|
||||
// }
|
||||
// [7] return
|
||||
rts
|
||||
// main::@2
|
||||
b2:
|
||||
// PrintName(file)
|
||||
// [8] (struct fileentry*) PrintName::file#0 ← (struct fileentry*) main::file#2
|
||||
// [9] call PrintName
|
||||
jsr PrintName
|
||||
// main::@3
|
||||
// ++file;
|
||||
// [10] (struct fileentry*) main::file#1 ← (struct fileentry*) main::file#2 + (const byte) SIZEOF_STRUCT_FILEENTRY -- pssz1=pssz1_plus_vbuc1
|
||||
lda #SIZEOF_STRUCT_FILEENTRY
|
||||
clc
|
||||
adc.z file
|
||||
sta.z file
|
||||
bcc !+
|
||||
inc.z file+1
|
||||
!:
|
||||
// [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
|
||||
// [5] phi (struct fileentry*) main::file#2 = (struct fileentry*) main::file#1 [phi:main::@3->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
}
|
||||
// PrintName
|
||||
// PrintName(struct fileentry* zeropage(2) file)
|
||||
PrintName: {
|
||||
.label file = 2
|
||||
// if (file == dir)
|
||||
// [11] if((struct fileentry*) PrintName::file#0!=(const struct fileentry*) dir#0) goto PrintName::@return -- pssz1_neq_pssc1_then_la1
|
||||
lda.z file+1
|
||||
cmp #>dir
|
||||
bne breturn
|
||||
lda.z file
|
||||
cmp #<dir
|
||||
bne breturn
|
||||
// PrintName::@1
|
||||
// *(BYTE *)0xC7 = 1
|
||||
// [12] *((byte*) 199) ← (byte) 1 -- _deref_pbuc1=vbuc2
|
||||
lda #1
|
||||
sta $c7
|
||||
// PrintName::@return
|
||||
breturn:
|
||||
// }
|
||||
// [13] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
25
src/test/ref/struct-ptr-24.sym
Normal file
25
src/test/ref/struct-ptr-24.sym
Normal file
@ -0,0 +1,25 @@
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) PrintName((struct fileentry*) PrintName::file)
|
||||
(label) PrintName::@1
|
||||
(label) PrintName::@return
|
||||
(struct fileentry*) PrintName::file
|
||||
(struct fileentry*) PrintName::file#0 file zp ZP_WORD:2 13.0
|
||||
(const byte) SIZEOF_STRUCT_FILEENTRY SIZEOF_STRUCT_FILEENTRY = (byte) 2
|
||||
(struct fileentry*) dir
|
||||
(const struct fileentry*) dir#0 dir = (struct fileentry*) 0
|
||||
(byte) fileentry::bError
|
||||
(byte) fileentry::bFlag
|
||||
(struct fileentry*) filesEnd
|
||||
(const struct fileentry*) filesEnd#0 filesEnd = (struct fileentry*) 0
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@return
|
||||
(struct fileentry*) main::file
|
||||
(struct fileentry*) main::file#1 file zp ZP_WORD:2 22.0
|
||||
(struct fileentry*) main::file#2 file zp ZP_WORD:2 11.0
|
||||
|
||||
zp ZP_WORD:2 [ main::file#2 main::file#1 PrintName::file#0 ]
|
Loading…
Reference in New Issue
Block a user