1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-12-30 15:31:17 +00:00
This commit is contained in:
jespergravgaard 2019-09-03 08:35:38 +02:00
parent 162b29b2d4
commit 42ecee2f94
11 changed files with 852 additions and 70 deletions

View File

@ -0,0 +1,8 @@
lda #>{c1}
cmp #>{c2}
bne !+
lda #<{c1}
cmp #<{c2}
beq {la1}
!:
bcc {la1}

View File

@ -0,0 +1,4 @@
lda {z2}
sta {z1}
lda {z2}+1
sta {z1}+1

View File

@ -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)

View File

@ -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
*

View File

@ -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 {

View 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;
}

View 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;
}

View 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
}

View 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

View 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

View 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 ]