diff --git a/src/main/java/dk/camelot64/kickc/TODO.txt b/src/main/java/dk/camelot64/kickc/TODO.txt index e41271878..7ae5f1c0d 100644 --- a/src/main/java/dk/camelot64/kickc/TODO.txt +++ b/src/main/java/dk/camelot64/kickc/TODO.txt @@ -1,6 +1,10 @@ Known Problems +- In immemarray.kc the if(++j==8) is broken because the optimizer culls the empty block main::@3 (because the value is constant). In the end the phi()-function in main::@2 has two handlers for min::@1 phi( main::@1/(byte) main::j#1 main::@1/(const byte) main::j#2 ) Features +- Add string constants +- Add support for expressions in data initializers. +- Add support for empty / filled byte data arrays. - Move the main code into a main() function, and disallow code outside functions. The main function per default has no parameters and exits with RTS. - Improve locality of block sequence for if(cond) { stmt1; } else { stmt2; } to if(!cond) goto @else stmt1; jmp @end; @else: stmt2; @end: - Optimize if/else by swapping if & else if cond is easier to evaluate than !cond. @@ -10,7 +14,6 @@ Features - Add Fixed Point number types fixed[8.8], fixed[16.8] - maybe even fixed[24.4] - Add imports - Add structs -- Add possibility of declaring in-program data - just like .byte/.fill in KickAss. - Let { stmt } introduce a new anonymous scope. (But not when optimizing) - Add preprocessing / find a way to allow some functions to run at compile time - Implement inline compilation of functions (and a mechanism for choosing which methods / calls to inline) @@ -116,3 +119,4 @@ Done + In loopnest.asm x&y are used in both loops - the outer x&y are clobbered by the inner loop. + In voronoi.asm in render() x is clobbered during call to findcol(). + Optimize getAliveEffective() to improve speed ++ Add possibility of declaring in-program data - just like .byte/.fill in KickAss. diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmData.java b/src/main/java/dk/camelot64/kickc/asm/AsmData.java new file mode 100644 index 000000000..18dd13490 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/asm/AsmData.java @@ -0,0 +1,73 @@ +package dk.camelot64.kickc.asm; + +import java.util.List; + +/** A labelled numeric data directive. */ +public class AsmData implements AsmLine { + + private String label; + private Type type; + private List values; + private int index; + + public static enum Type { + BYTE("byte", 1), + WORD("word", 2), + DWORD("dword", 4); + + public final String asm; + public final int bytes; + + Type(String asm, int bytes) { + this.asm = asm; + this.bytes = bytes; + } + + } + + public AsmData(String label, Type type, List values) { + this.label = label; + this.type = type; + this.values = values; + } + + public int getElementBytes() { + return type.bytes; + } + + @Override + public int getLineBytes() { + return values.size()*getElementBytes(); + } + + @Override + public double getLineCycles() { + return 0; + } + + @Override + public String getAsm() { + StringBuilder asm = new StringBuilder(); + asm.append(label+": "); + asm.append("."+type.asm+" "); + boolean first = true; + for (String value : values) { + if(!first) + asm.append(", "); + first = false; + asm.append(value); + } + return asm.toString(); + } + + @Override + public int getIndex() { + return index; + } + + @Override + public void setIndex(int index) { + this.index = index; + } + +} diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmProgram.java b/src/main/java/dk/camelot64/kickc/asm/AsmProgram.java index cdbfd6b10..ec869b325 100644 --- a/src/main/java/dk/camelot64/kickc/asm/AsmProgram.java +++ b/src/main/java/dk/camelot64/kickc/asm/AsmProgram.java @@ -85,7 +85,15 @@ public class AsmProgram { addLine(new AsmConstant(name, value)); } - + /** + * Add a BYTE/WORD/DWORD data declaration tot the ASM + * @param label The label of the data + * @param type The type of the data + * @param asmElements The value of the elements + */ + public void addData(String label, AsmData.Type type, List asmElements) { + addLine(new AsmData(label, type, asmElements)); + } /** * Get the number of bytes the segment occupies in memory. @@ -175,19 +183,4 @@ public class AsmProgram { } - /** - * Get all segments representing a specific ICL statement - * @param statementIndex The statement index - * @return The ASM segments representing the statement - * */ - public Collection getSegmentsByStatementIndex(int statementIndex) { - List statementSegments = new ArrayList<>(); - for (AsmSegment segment : segments) { - if(segment.getStatementIdx()!=null && segment.getStatementIdx()==statementIndex) { - statementSegments.add(segment); - } - } - return statementSegments; - } - } diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmSegment.java b/src/main/java/dk/camelot64/kickc/asm/AsmSegment.java index a51626240..fdec15678 100644 --- a/src/main/java/dk/camelot64/kickc/asm/AsmSegment.java +++ b/src/main/java/dk/camelot64/kickc/asm/AsmSegment.java @@ -138,7 +138,7 @@ public class AsmSegment { printState.decIndent(); } out.append(printState.getIndent()); - if (line instanceof AsmComment || line instanceof AsmInstruction || line instanceof AsmLabelDecl || line instanceof AsmConstant) { + if (line instanceof AsmComment || line instanceof AsmInstruction || line instanceof AsmLabelDecl || line instanceof AsmConstant || line instanceof AsmData ) { out.append(" "); } out.append(line.getAsm() + "\n"); diff --git a/src/main/java/dk/camelot64/kickc/model/ConstantArray.java b/src/main/java/dk/camelot64/kickc/model/ConstantArray.java new file mode 100644 index 000000000..e869ca538 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/model/ConstantArray.java @@ -0,0 +1,53 @@ +package dk.camelot64.kickc.model; + +import java.util.List; + +/** + * An array of constants. The array is allocated in the code memory (eg. as a set of .byte's ). + */ +public class ConstantArray implements ConstantValue { + + private List list; + + private SymbolType elementType; + + public ConstantArray(List list, SymbolType elementType) { + this.list = list; + this.elementType = elementType; + } + + @Override + public SymbolType getType(ProgramScope scope) { + return new SymbolTypeArray(elementType); + } + + public SymbolType getElementType() { + return elementType; + } + + public List getElements() { + return list; + } + + @Override + public String toString() { + return toString(null); + } + + @Override + public String toString(Program program) { + StringBuilder out = new StringBuilder(); + boolean first = true; + out.append("{ "); + for (ConstantValue constantValue : list) { + if (!first) { + out.append(", "); + } + first = false; + out.append(constantValue.toString(program)); + } + out.append(" }"); + return out.toString(); + } + +} diff --git a/src/main/java/dk/camelot64/kickc/model/ValueArray.java b/src/main/java/dk/camelot64/kickc/model/ValueArray.java new file mode 100644 index 000000000..e9c4caf1e --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/model/ValueArray.java @@ -0,0 +1,34 @@ +package dk.camelot64.kickc.model; + +import java.util.List; + +/** An array of sub-values. Only used for variable initializers. Compilation execution will typically resolve it into a constant array before ASM-generation. */ +public class ValueArray implements RValue { + + private List list; + + public ValueArray(List list) { + this.list = list; + } + + public List getList() { + return list; + } + + @Override + public String toString(Program program) { + StringBuilder out = new StringBuilder(); + boolean first = true; + out.append("{ "); + for (RValue constantValue : list) { + if (!first) { + out.append(", "); + } + first = false; + out.append(constantValue.toString(program)); + } + out.append(" }"); + return out.toString(); + } + +} diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1GenerateStatementSequence.java b/src/main/java/dk/camelot64/kickc/passes/Pass1GenerateStatementSequence.java index 53ab0736a..1823bfe40 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1GenerateStatementSequence.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1GenerateStatementSequence.java @@ -397,7 +397,12 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor { @Override public RValue visitInitList(KickCParser.InitListContext ctx) { - throw new RuntimeException("Not implemented"); + List initValues = new ArrayList<>(); + for (KickCParser.InitializerContext initializer : ctx.initializer()) { + RValue rValue = (RValue) visit(initializer); + initValues.add(rValue); + } + return new ValueArray(initValues); } @Override diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java index 511ba7fff..859a174ac 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java @@ -2,10 +2,14 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.model.*; +import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; -/** Compiler Pass propagating constants in expressions eliminating constant variables */ +/** + * Compiler Pass propagating constants in expressions eliminating constant variables + */ public class Pass2ConstantIdentification extends Pass2SsaOptimization { public Pass2ConstantIdentification(Program program) { @@ -14,6 +18,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization { /** * Propagate constants, replacing variables with constants where possible. + * * @return true optimization was performed. false if no optimization was possible. */ @Override @@ -33,7 +38,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization { constScope.remove(variable); constScope.add(constantVar); constAliases.put(constRef, constantVar.getRef()); - getLog().append("Constant " + constantVar.toString(getProgram()) + " = "+constantVar.getValue()); + getLog().append("Constant " + constantVar.toString(getProgram()) + " = " + constantVar.getValue()); } // Remove assignments to constants in the code removeAssignments(constants.keySet()); @@ -44,6 +49,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization { /** * Find variables that have constant values. + * * @return Map from Variable to the Constant value */ private Map findConstantVariables() { @@ -74,7 +80,36 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization { if (constant != null) { constants.put(variable, constant); } + } else if (assignment.getrValue2() instanceof ValueArray && assignment.getOperator() == null && assignment.getrValue1() == null) { + ValueArray valueArray = (ValueArray) assignment.getrValue2(); + List values = valueArray.getList(); + boolean allConstant = true; + SymbolType elementType = null; + List elements = new ArrayList<>(); + for (RValue value : values) { + if (value instanceof ConstantValue) { + ConstantValue constantValue = (ConstantValue) value; + SymbolType type = constantValue.getType(getSymbols()); + if (elementType == null) { + elementType = type; + } else { + if (!elementType.equals(type)) { + throw new RuntimeException("Array type mismatch " + elementType + "!=" + type + " " + valueArray.toString(getProgram())); + } + } + elements.add(constantValue); + } else { + allConstant = false; + elementType = null; + break; + } + } + if (allConstant && elementType != null) { + ConstantValue constant = new ConstantArray(elements, elementType); + constants.put(variable, constant); + } } + } return null; } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java index c02017dab..8efa23c6b 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java @@ -33,6 +33,7 @@ public class Pass4CodeGeneration { asm.startSegment(null, "Global Constants & labels"); addConstants(asm, currentScope); addZpLabels(asm, currentScope); + addData(asm, currentScope); for (ControlFlowBlock block : getGraph().getAllBlocks()) { if (!block.getScope().equals(currentScope)) { if (!ScopeRef.ROOT.equals(currentScope)) { @@ -44,6 +45,7 @@ public class Pass4CodeGeneration { // Add all ZP labels for the scope addConstants(asm, currentScope); addZpLabels(asm, currentScope); + addData(asm, currentScope); } // Generate entry points (if needed) genBlockEntryPoints(asm, block); @@ -90,14 +92,49 @@ public class Pass4CodeGeneration { Collection scopeConstants = scope.getAllConstants(false); Set added = new LinkedHashSet<>(); for (ConstantVar constantVar : scopeConstants) { - String asmName = constantVar.getAsmName() == null ? constantVar.getLocalName() : constantVar.getAsmName(); - if (asmName != null && !added.contains(asmName)) { - asm.addConstant(asmName.replace("#", "_").replace("$", "_"), AsmFragment.getAsmConstant(program, constantVar.getValue(), 99)); - added.add(asmName); + if(! (constantVar.getValue() instanceof ConstantArray)) { + String asmName = constantVar.getAsmName() == null ? constantVar.getLocalName() : constantVar.getAsmName(); + if (asmName != null && !added.contains(asmName)) { + asm.addConstant(asmName.replace("#", "_").replace("$", "_"), AsmFragment.getAsmConstant(program, constantVar.getValue(), 99)); + added.add(asmName); + } } } } + /** + * Add data directives for constants declarations + * + * @param asm The ASM program + * @param scopeRef The scope + */ + private void addData(AsmProgram asm, ScopeRef scopeRef) { + Scope scope = program.getScope().getScope(scopeRef); + Collection scopeConstants = scope.getAllConstants(false); + Set added = new LinkedHashSet<>(); + for (ConstantVar constantVar : scopeConstants) { + if(constantVar.getValue() instanceof ConstantArray) { + ConstantArray constantArray = (ConstantArray) constantVar.getValue(); + String asmName = constantVar.getAsmName() == null ? constantVar.getLocalName() : constantVar.getAsmName(); + if (asmName != null && !added.contains(asmName)) { + + List asmElements = new ArrayList<>(); + for (ConstantValue element : constantArray.getElements()) { + String asmElement = AsmFragment.getAsmConstant(program, element, 99); + asmElements.add(asmElement); + } + if(SymbolTypeBasic.BYTE.equals(constantArray.getElementType())) { + asm.addData(asmName.replace("#", "_").replace("$", "_"), AsmData.Type.BYTE, asmElements); + added.add(asmName); + } else { + throw new RuntimeException("Unhandled constant array element type "+constantArray.toString(program)); + } + } + } + } + } + + /** * Add label declarations for all scope variables assigned to ZP registers diff --git a/src/main/java/dk/camelot64/kickc/test/ref/inmemarray.asm b/src/main/java/dk/camelot64/kickc/test/ref/inmemarray.asm new file mode 100644 index 000000000..c77f720ce --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/inmemarray.asm @@ -0,0 +1,19 @@ + .const SCREEN = $400 + TXT: .byte 3, 1, $d, 5, $c, $f, $14, $20 + jsr main +main: { + ldx #0 + ldy #0 + b1: + lda TXT,y + sta SCREEN,x + iny + cpy #8 + bne b2 + ldy #0 + b2: + inx + cpx #$65 + bne b1 + rts +} diff --git a/src/main/java/dk/camelot64/kickc/test/ref/inmemarray.cfg b/src/main/java/dk/camelot64/kickc/test/ref/inmemarray.cfg new file mode 100644 index 000000000..9a5d33081 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/inmemarray.cfg @@ -0,0 +1,23 @@ +@begin: scope:[] from + [0] call main param-assignment [ ] + to:@end +@end: scope:[] from @begin +main: scope:[main] from @begin + [1] phi() [ ] + to:main::@1 +main::@1: scope:[main] from main main::@2 + [2] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 ) [ main::j#3 main::i#2 ] + [2] (byte) main::j#3 ← phi( main/(byte) 0 main::@2/(byte) main::j#4 ) [ main::j#3 main::i#2 ] + [3] (byte~) main::$0 ← (const byte[]) TXT#0 *idx (byte) main::j#3 [ main::j#3 main::i#2 main::$0 ] + [4] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::j#3 main::i#2 ] + [5] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] + [6] if((byte) main::j#1!=(byte) 8) goto main::@2 [ main::i#2 main::j#1 ] + to:main::@2 +main::@2: scope:[main] from main::@1 main::@1 + [7] (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@1/(byte) 0 ) [ main::i#2 main::j#4 ] + [8] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::j#4 main::i#1 ] + [9] if((byte) main::i#1!=(byte) 101) goto main::@1 [ main::j#4 main::i#1 ] + to:main::@return +main::@return: scope:[main] from main::@2 + [10] return [ ] + to:@return diff --git a/src/main/java/dk/camelot64/kickc/test/ref/inmemarray.log b/src/main/java/dk/camelot64/kickc/test/ref/inmemarray.log new file mode 100644 index 000000000..ba30f5ff6 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/inmemarray.log @@ -0,0 +1,1203 @@ + +byte* SCREEN = $0400; +byte[] TXT = { 3, 1, 13, 5, 12, 15, 20, 32}; + +main(); + +void main() { + byte j = 0; + for(byte i : 0..100) { + SCREEN[i] = TXT[j]; + if(++j==8) { + j = 0; + } + } +} +Adding pre/post-modifier (byte) main::j ← ++ (byte) main::j +PROGRAM + (byte*) SCREEN ← (word) 1024 + (byte[]) TXT ← { (byte) 3, (byte) 1, (byte) 13, (byte) 5, (byte) 12, (byte) 15, (byte) 20, (byte) 32 } + (void~) $0 ← call main +proc (void()) main() + (byte) main::j ← (byte) 0 + (byte) main::i ← (byte) 0 +main::@1: + (byte~) main::$0 ← (byte[]) TXT *idx (byte) main::j + *((byte*) SCREEN + (byte) main::i) ← (byte~) main::$0 + (byte) main::j ← ++ (byte) main::j + (boolean~) main::$1 ← (byte) main::j == (byte) 8 + (boolean~) main::$2 ← ! (boolean~) main::$1 + if((boolean~) main::$2) goto main::@2 + (byte) main::j ← (byte) 0 +main::@2: + (byte) main::i ← ++ (byte) main::i + (boolean~) main::$3 ← (byte) main::i != (byte) 101 + if((boolean~) main::$3) goto main::@1 +main::@return: + return +endproc // main() + +SYMBOLS +(void~) $0 +(byte*) SCREEN +(byte[]) TXT +(void()) main() +(byte~) main::$0 +(boolean~) main::$1 +(boolean~) main::$2 +(boolean~) main::$3 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte) main::i +(byte) main::j + +INITIAL CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) SCREEN ← (word) 1024 + (byte[]) TXT ← { (byte) 3, (byte) 1, (byte) 13, (byte) 5, (byte) 12, (byte) 15, (byte) 20, (byte) 32 } + (void~) $0 ← call main + to:@1 +main: scope:[main] from + (byte) main::j ← (byte) 0 + (byte) main::i ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte~) main::$0 ← (byte[]) TXT *idx (byte) main::j + *((byte*) SCREEN + (byte) main::i) ← (byte~) main::$0 + (byte) main::j ← ++ (byte) main::j + (boolean~) main::$1 ← (byte) main::j == (byte) 8 + (boolean~) main::$2 ← ! (boolean~) main::$1 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::i ← ++ (byte) main::i + (boolean~) main::$3 ← (byte) main::i != (byte) 101 + if((boolean~) main::$3) goto main::@1 + to:main::@4 +main::@3: scope:[main] from main::@1 + (byte) main::j ← (byte) 0 + to:main::@2 +main::@4: scope:[main] from main::@2 + to:main::@return +main::@return: scope:[main] from main::@4 + return + to:@return +@1: scope:[] from @begin + to:@end +@end: scope:[] from @1 + +Removing empty block main::@4 +Removing empty block @1 +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) SCREEN ← (word) 1024 + (byte[]) TXT ← { (byte) 3, (byte) 1, (byte) 13, (byte) 5, (byte) 12, (byte) 15, (byte) 20, (byte) 32 } + (void~) $0 ← call main + to:@end +main: scope:[main] from + (byte) main::j ← (byte) 0 + (byte) main::i ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte~) main::$0 ← (byte[]) TXT *idx (byte) main::j + *((byte*) SCREEN + (byte) main::i) ← (byte~) main::$0 + (byte) main::j ← ++ (byte) main::j + (boolean~) main::$1 ← (byte) main::j == (byte) 8 + (boolean~) main::$2 ← ! (boolean~) main::$1 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::i ← ++ (byte) main::i + (boolean~) main::$3 ← (byte) main::i != (byte) 101 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte) main::j ← (byte) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@end: scope:[] from @begin + +PROCEDURE MODIFY VARIABLE ANALYSIS + +CONTROL FLOW GRAPH WITH ASSIGNMENT CALL +@begin: scope:[] from + (byte*) SCREEN ← (word) 1024 + (byte[]) TXT ← { (byte) 3, (byte) 1, (byte) 13, (byte) 5, (byte) 12, (byte) 15, (byte) 20, (byte) 32 } + call main param-assignment + to:@2 +@2: scope:[] from @begin + to:@end +main: scope:[main] from @begin + (byte) main::j ← (byte) 0 + (byte) main::i ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte~) main::$0 ← (byte[]) TXT *idx (byte) main::j + *((byte*) SCREEN + (byte) main::i) ← (byte~) main::$0 + (byte) main::j ← ++ (byte) main::j + (boolean~) main::$1 ← (byte) main::j == (byte) 8 + (boolean~) main::$2 ← ! (boolean~) main::$1 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::i ← ++ (byte) main::i + (boolean~) main::$3 ← (byte) main::i != (byte) 101 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte) main::j ← (byte) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@end: scope:[] from @2 + +Completing Phi functions... +Completing Phi functions... +Completing Phi functions... +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (byte*) SCREEN#0 ← (word) 1024 + (byte[]) TXT#0 ← { (byte) 3, (byte) 1, (byte) 13, (byte) 5, (byte) 12, (byte) 15, (byte) 20, (byte) 32 } + call main param-assignment + to:@2 +@2: scope:[] from @begin + to:@end +main: scope:[main] from @begin + (byte*) SCREEN#2 ← phi( @begin/(byte*) SCREEN#0 ) + (byte[]) TXT#2 ← phi( @begin/(byte[]) TXT#0 ) + (byte) main::j#0 ← (byte) 0 + (byte) main::i#0 ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte*) SCREEN#1 ← phi( main/(byte*) SCREEN#2 main::@2/(byte*) SCREEN#3 ) + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte[]) TXT#1 ← phi( main/(byte[]) TXT#2 main::@2/(byte[]) TXT#3 ) + (byte~) main::$0 ← (byte[]) TXT#1 *idx (byte) main::j#3 + *((byte*) SCREEN#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + (boolean~) main::$1 ← (byte) main::j#1 == (byte) 8 + (boolean~) main::$2 ← ! (boolean~) main::$1 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte*) SCREEN#3 ← phi( main::@1/(byte*) SCREEN#1 main::@3/(byte*) SCREEN#4 ) + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte[]) TXT#3 ← phi( main::@1/(byte[]) TXT#1 main::@3/(byte[]) TXT#4 ) + (byte) main::i#3 ← phi( main::@1/(byte) main::i#2 main::@3/(byte) main::i#4 ) + (byte) main::i#1 ← ++ (byte) main::i#3 + (boolean~) main::$3 ← (byte) main::i#1 != (byte) 101 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte*) SCREEN#4 ← phi( main::@1/(byte*) SCREEN#1 ) + (byte[]) TXT#4 ← phi( main::@1/(byte[]) TXT#1 ) + (byte) main::i#4 ← phi( main::@1/(byte) main::i#2 ) + (byte) main::j#2 ← (byte) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@end: scope:[] from @2 + +CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN +@begin: scope:[] from + (byte*) SCREEN#0 ← (word) 1024 + (byte[]) TXT#0 ← { (byte) 3, (byte) 1, (byte) 13, (byte) 5, (byte) 12, (byte) 15, (byte) 20, (byte) 32 } + call main param-assignment + to:@2 +@2: scope:[] from @begin + to:@end +main: scope:[main] from @begin + (byte*) SCREEN#2 ← phi( @begin/(byte*) SCREEN#0 ) + (byte[]) TXT#2 ← phi( @begin/(byte[]) TXT#0 ) + (byte) main::j#0 ← (byte) 0 + (byte) main::i#0 ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte*) SCREEN#1 ← phi( main/(byte*) SCREEN#2 main::@2/(byte*) SCREEN#3 ) + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte[]) TXT#1 ← phi( main/(byte[]) TXT#2 main::@2/(byte[]) TXT#3 ) + (byte~) main::$0 ← (byte[]) TXT#1 *idx (byte) main::j#3 + *((byte*) SCREEN#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + (boolean~) main::$1 ← (byte) main::j#1 == (byte) 8 + (boolean~) main::$2 ← ! (boolean~) main::$1 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte*) SCREEN#3 ← phi( main::@1/(byte*) SCREEN#1 main::@3/(byte*) SCREEN#4 ) + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte[]) TXT#3 ← phi( main::@1/(byte[]) TXT#1 main::@3/(byte[]) TXT#4 ) + (byte) main::i#3 ← phi( main::@1/(byte) main::i#2 main::@3/(byte) main::i#4 ) + (byte) main::i#1 ← ++ (byte) main::i#3 + (boolean~) main::$3 ← (byte) main::i#1 != (byte) 101 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte*) SCREEN#4 ← phi( main::@1/(byte*) SCREEN#1 ) + (byte[]) TXT#4 ← phi( main::@1/(byte[]) TXT#1 ) + (byte) main::i#4 ← phi( main::@1/(byte) main::i#2 ) + (byte) main::j#2 ← (byte) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@end: scope:[] from @2 + +INITIAL SSA SYMBOL TABLE +(label) @2 +(label) @begin +(label) @end +(byte*) SCREEN +(byte*) SCREEN#0 +(byte*) SCREEN#1 +(byte*) SCREEN#2 +(byte*) SCREEN#3 +(byte*) SCREEN#4 +(byte[]) TXT +(byte[]) TXT#0 +(byte[]) TXT#1 +(byte[]) TXT#2 +(byte[]) TXT#3 +(byte[]) TXT#4 +(void()) main() +(byte~) main::$0 +(boolean~) main::$1 +(boolean~) main::$2 +(boolean~) main::$3 +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@return +(byte) main::i +(byte) main::i#0 +(byte) main::i#1 +(byte) main::i#2 +(byte) main::i#3 +(byte) main::i#4 +(byte) main::j +(byte) main::j#0 +(byte) main::j#1 +(byte) main::j#2 +(byte) main::j#3 +(byte) main::j#4 + +Culled Empty Block (label) @2 +Succesful SSA optimization Pass2CullEmptyBlocks +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) SCREEN#0 ← (word) 1024 + (byte[]) TXT#0 ← { (byte) 3, (byte) 1, (byte) 13, (byte) 5, (byte) 12, (byte) 15, (byte) 20, (byte) 32 } + call main param-assignment + to:@end +main: scope:[main] from @begin + (byte*) SCREEN#2 ← phi( @begin/(byte*) SCREEN#0 ) + (byte[]) TXT#2 ← phi( @begin/(byte[]) TXT#0 ) + (byte) main::j#0 ← (byte) 0 + (byte) main::i#0 ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte*) SCREEN#1 ← phi( main/(byte*) SCREEN#2 main::@2/(byte*) SCREEN#3 ) + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte[]) TXT#1 ← phi( main/(byte[]) TXT#2 main::@2/(byte[]) TXT#3 ) + (byte~) main::$0 ← (byte[]) TXT#1 *idx (byte) main::j#3 + *((byte*) SCREEN#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + (boolean~) main::$1 ← (byte) main::j#1 == (byte) 8 + (boolean~) main::$2 ← ! (boolean~) main::$1 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte*) SCREEN#3 ← phi( main::@1/(byte*) SCREEN#1 main::@3/(byte*) SCREEN#4 ) + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte[]) TXT#3 ← phi( main::@1/(byte[]) TXT#1 main::@3/(byte[]) TXT#4 ) + (byte) main::i#3 ← phi( main::@1/(byte) main::i#2 main::@3/(byte) main::i#4 ) + (byte) main::i#1 ← ++ (byte) main::i#3 + (boolean~) main::$3 ← (byte) main::i#1 != (byte) 101 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte*) SCREEN#4 ← phi( main::@1/(byte*) SCREEN#1 ) + (byte[]) TXT#4 ← phi( main::@1/(byte[]) TXT#1 ) + (byte) main::i#4 ← phi( main::@1/(byte) main::i#2 ) + (byte) main::j#2 ← (byte) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@end: scope:[] from @begin + +Inversing boolean not (boolean~) main::$2 ← (byte) main::j#1 != (byte) 8 from (boolean~) main::$1 ← (byte) main::j#1 == (byte) 8 +Succesful SSA optimization Pass2UnaryNotSimplification +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) SCREEN#0 ← (word) 1024 + (byte[]) TXT#0 ← { (byte) 3, (byte) 1, (byte) 13, (byte) 5, (byte) 12, (byte) 15, (byte) 20, (byte) 32 } + call main param-assignment + to:@end +main: scope:[main] from @begin + (byte*) SCREEN#2 ← phi( @begin/(byte*) SCREEN#0 ) + (byte[]) TXT#2 ← phi( @begin/(byte[]) TXT#0 ) + (byte) main::j#0 ← (byte) 0 + (byte) main::i#0 ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte*) SCREEN#1 ← phi( main/(byte*) SCREEN#2 main::@2/(byte*) SCREEN#3 ) + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte[]) TXT#1 ← phi( main/(byte[]) TXT#2 main::@2/(byte[]) TXT#3 ) + (byte~) main::$0 ← (byte[]) TXT#1 *idx (byte) main::j#3 + *((byte*) SCREEN#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + (boolean~) main::$2 ← (byte) main::j#1 != (byte) 8 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte*) SCREEN#3 ← phi( main::@1/(byte*) SCREEN#1 main::@3/(byte*) SCREEN#4 ) + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte[]) TXT#3 ← phi( main::@1/(byte[]) TXT#1 main::@3/(byte[]) TXT#4 ) + (byte) main::i#3 ← phi( main::@1/(byte) main::i#2 main::@3/(byte) main::i#4 ) + (byte) main::i#1 ← ++ (byte) main::i#3 + (boolean~) main::$3 ← (byte) main::i#1 != (byte) 101 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte*) SCREEN#4 ← phi( main::@1/(byte*) SCREEN#1 ) + (byte[]) TXT#4 ← phi( main::@1/(byte[]) TXT#1 ) + (byte) main::i#4 ← phi( main::@1/(byte) main::i#2 ) + (byte) main::j#2 ← (byte) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@end: scope:[] from @begin + +Alias (byte[]) TXT#0 = (byte[]) TXT#2 +Alias (byte*) SCREEN#0 = (byte*) SCREEN#2 +Alias (byte) main::i#2 = (byte) main::i#4 +Alias (byte[]) TXT#1 = (byte[]) TXT#4 +Alias (byte*) SCREEN#1 = (byte*) SCREEN#4 +Succesful SSA optimization Pass2AliasElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) SCREEN#0 ← (word) 1024 + (byte[]) TXT#0 ← { (byte) 3, (byte) 1, (byte) 13, (byte) 5, (byte) 12, (byte) 15, (byte) 20, (byte) 32 } + call main param-assignment + to:@end +main: scope:[main] from @begin + (byte) main::j#0 ← (byte) 0 + (byte) main::i#0 ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte*) SCREEN#1 ← phi( main/(byte*) SCREEN#0 main::@2/(byte*) SCREEN#3 ) + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte[]) TXT#1 ← phi( main/(byte[]) TXT#0 main::@2/(byte[]) TXT#3 ) + (byte~) main::$0 ← (byte[]) TXT#1 *idx (byte) main::j#3 + *((byte*) SCREEN#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + (boolean~) main::$2 ← (byte) main::j#1 != (byte) 8 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte*) SCREEN#3 ← phi( main::@1/(byte*) SCREEN#1 main::@3/(byte*) SCREEN#1 ) + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte[]) TXT#3 ← phi( main::@1/(byte[]) TXT#1 main::@3/(byte[]) TXT#1 ) + (byte) main::i#3 ← phi( main::@1/(byte) main::i#2 main::@3/(byte) main::i#2 ) + (byte) main::i#1 ← ++ (byte) main::i#3 + (boolean~) main::$3 ← (byte) main::i#1 != (byte) 101 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte) main::j#2 ← (byte) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@end: scope:[] from @begin + +Redundant Phi (byte) main::i#3 (byte) main::i#2 +Redundant Phi (byte[]) TXT#3 (byte[]) TXT#1 +Redundant Phi (byte*) SCREEN#3 (byte*) SCREEN#1 +Succesful SSA optimization Pass2RedundantPhiElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) SCREEN#0 ← (word) 1024 + (byte[]) TXT#0 ← { (byte) 3, (byte) 1, (byte) 13, (byte) 5, (byte) 12, (byte) 15, (byte) 20, (byte) 32 } + call main param-assignment + to:@end +main: scope:[main] from @begin + (byte) main::j#0 ← (byte) 0 + (byte) main::i#0 ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte*) SCREEN#1 ← phi( main/(byte*) SCREEN#0 main::@2/(byte*) SCREEN#1 ) + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte[]) TXT#1 ← phi( main/(byte[]) TXT#0 main::@2/(byte[]) TXT#1 ) + (byte~) main::$0 ← (byte[]) TXT#1 *idx (byte) main::j#3 + *((byte*) SCREEN#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + (boolean~) main::$2 ← (byte) main::j#1 != (byte) 8 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte) main::i#1 ← ++ (byte) main::i#2 + (boolean~) main::$3 ← (byte) main::i#1 != (byte) 101 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte) main::j#2 ← (byte) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@end: scope:[] from @begin + +Self Phi Eliminated (byte[]) TXT#1 +Self Phi Eliminated (byte*) SCREEN#1 +Succesful SSA optimization Pass2SelfPhiElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) SCREEN#0 ← (word) 1024 + (byte[]) TXT#0 ← { (byte) 3, (byte) 1, (byte) 13, (byte) 5, (byte) 12, (byte) 15, (byte) 20, (byte) 32 } + call main param-assignment + to:@end +main: scope:[main] from @begin + (byte) main::j#0 ← (byte) 0 + (byte) main::i#0 ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte*) SCREEN#1 ← phi( main/(byte*) SCREEN#0 ) + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte[]) TXT#1 ← phi( main/(byte[]) TXT#0 ) + (byte~) main::$0 ← (byte[]) TXT#1 *idx (byte) main::j#3 + *((byte*) SCREEN#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + (boolean~) main::$2 ← (byte) main::j#1 != (byte) 8 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte) main::i#1 ← ++ (byte) main::i#2 + (boolean~) main::$3 ← (byte) main::i#1 != (byte) 101 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte) main::j#2 ← (byte) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@end: scope:[] from @begin + +Simple Condition (boolean~) main::$2 if((byte) main::j#1!=(byte) 8) goto main::@2 +Simple Condition (boolean~) main::$3 if((byte) main::i#1!=(byte) 101) goto main::@1 +Succesful SSA optimization Pass2ConditionalJumpSimplification +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) SCREEN#0 ← (word) 1024 + (byte[]) TXT#0 ← { (byte) 3, (byte) 1, (byte) 13, (byte) 5, (byte) 12, (byte) 15, (byte) 20, (byte) 32 } + call main param-assignment + to:@end +main: scope:[main] from @begin + (byte) main::j#0 ← (byte) 0 + (byte) main::i#0 ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte*) SCREEN#1 ← phi( main/(byte*) SCREEN#0 ) + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte[]) TXT#1 ← phi( main/(byte[]) TXT#0 ) + (byte~) main::$0 ← (byte[]) TXT#1 *idx (byte) main::j#3 + *((byte*) SCREEN#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + if((byte) main::j#1!=(byte) 8) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte) main::i#1 ← ++ (byte) main::i#2 + if((byte) main::i#1!=(byte) 101) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte) main::j#2 ← (byte) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@end: scope:[] from @begin + +Constant (const byte*) SCREEN#0 = 1024 +Constant (const byte[]) TXT#0 = { 3, 1, 13, 5, 12, 15, 20, 32 } +Constant (const byte) main::j#0 = 0 +Constant (const byte) main::i#0 = 0 +Constant (const byte) main::j#2 = 0 +Succesful SSA optimization Pass2ConstantIdentification +CONTROL FLOW GRAPH +@begin: scope:[] from + call main param-assignment + to:@end +main: scope:[main] from @begin + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::i#2 ← phi( main/(const byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte*) SCREEN#1 ← phi( main/(const byte*) SCREEN#0 ) + (byte) main::j#3 ← phi( main/(const byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte[]) TXT#1 ← phi( main/(const byte[]) TXT#0 ) + (byte~) main::$0 ← (byte[]) TXT#1 *idx (byte) main::j#3 + *((byte*) SCREEN#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + if((byte) main::j#1!=(byte) 8) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(const byte) main::j#2 ) + (byte) main::i#1 ← ++ (byte) main::i#2 + if((byte) main::i#1!=(byte) 101) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@end: scope:[] from @begin + +Constant (const byte[]) TXT#1 = TXT#0 +Constant (const byte*) SCREEN#1 = SCREEN#0 +Succesful SSA optimization Pass2ConstantIdentification +CONTROL FLOW GRAPH +@begin: scope:[] from + call main param-assignment + to:@end +main: scope:[main] from @begin + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::i#2 ← phi( main/(const byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte) main::j#3 ← phi( main/(const byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte~) main::$0 ← (const byte[]) TXT#1 *idx (byte) main::j#3 + *((const byte*) SCREEN#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + if((byte) main::j#1!=(byte) 8) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(const byte) main::j#2 ) + (byte) main::i#1 ← ++ (byte) main::i#2 + if((byte) main::i#1!=(byte) 101) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@end: scope:[] from @begin + +Multiple usages for variable. Not optimizing sub-constant (byte) main::j#3 +Culled Empty Block (label) main::@3 +Succesful SSA optimization Pass2CullEmptyBlocks +CONTROL FLOW GRAPH +@begin: scope:[] from + call main param-assignment + to:@end +main: scope:[main] from @begin + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::i#2 ← phi( main/(const byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte) main::j#3 ← phi( main/(const byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte~) main::$0 ← (const byte[]) TXT#1 *idx (byte) main::j#3 + *((const byte*) SCREEN#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + if((byte) main::j#1!=(byte) 8) goto main::@2 + to:main::@2 +main::@2: scope:[main] from main::@1 main::@1 + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@1/(const byte) main::j#2 ) + (byte) main::i#1 ← ++ (byte) main::i#2 + if((byte) main::i#1!=(byte) 101) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@2 + return + to:@return +@end: scope:[] from @begin + +Multiple usages for variable. Not optimizing sub-constant (byte) main::j#3 +Multiple usages for variable. Not optimizing sub-constant (byte) main::j#3 +Constant inlined SCREEN#1 = (const byte*) SCREEN#0 +Constant inlined main::j#2 = (byte) 0 +Constant inlined main::j#0 = (byte) 0 +Constant inlined main::i#0 = (byte) 0 +Constant inlined TXT#1 = (const byte[]) TXT#0 +Succesful SSA optimization Pass2ConstantInlining +CONTROL FLOW GRAPH +@begin: scope:[] from + call main param-assignment + to:@end +main: scope:[main] from @begin + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 ) + (byte) main::j#3 ← phi( main/(byte) 0 main::@2/(byte) main::j#4 ) + (byte~) main::$0 ← (const byte[]) TXT#0 *idx (byte) main::j#3 + *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + if((byte) main::j#1!=(byte) 8) goto main::@2 + to:main::@2 +main::@2: scope:[main] from main::@1 main::@1 + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@1/(byte) 0 ) + (byte) main::i#1 ← ++ (byte) main::i#2 + if((byte) main::i#1!=(byte) 101) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@2 + return + to:@return +@end: scope:[] from @begin + +FINAL SYMBOL TABLE +(label) @begin +(label) @end +(byte*) SCREEN +(const byte*) SCREEN#0 = (word) 1024 +(byte[]) TXT +(const byte[]) TXT#0 = { (byte) 3, (byte) 1, (byte) 13, (byte) 5, (byte) 12, (byte) 15, (byte) 20, (byte) 32 } +(void()) main() +(byte~) main::$0 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte) main::i +(byte) main::i#1 +(byte) main::i#2 +(byte) main::j +(byte) main::j#1 +(byte) main::j#3 +(byte) main::j#4 + +Block Sequence Planned @begin @end main main::@1 main::@2 main::@return +Added new block during phi lifting main::@5(between main::@2 and main::@1) +Added new block during phi lifting main::@6(between main::@1 and main::@2) +Block Sequence Planned @begin @end main main::@1 main::@6 main::@2 main::@return main::@5 +CONTROL FLOW GRAPH - PHI LIFTED +@begin: scope:[] from + call main param-assignment + to:@end +@end: scope:[] from @begin +main: scope:[main] from @begin + to:main::@1 +main::@1: scope:[main] from main main::@5 + (byte) main::i#2 ← phi( main/(byte) 0 main::@5/(byte~) main::i#5 ) + (byte) main::j#3 ← phi( main/(byte) 0 main::@5/(byte~) main::j#5 ) + (byte~) main::$0 ← (const byte[]) TXT#0 *idx (byte) main::j#3 + *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + if((byte) main::j#1!=(byte) 8) goto main::@6 + to:main::@6 +main::@6: scope:[main] from main::@1 main::@1 + (byte~) main::j#6 ← (byte) main::j#1 + to:main::@2 +main::@2: scope:[main] from main::@6 + (byte) main::j#4 ← phi( main::@6/(byte~) main::j#6 main::@1/(byte) 0 ) + (byte) main::i#1 ← ++ (byte) main::i#2 + if((byte) main::i#1!=(byte) 101) goto main::@5 + to:main::@return +main::@return: scope:[main] from main::@2 + return + to:@return +main::@5: scope:[main] from main::@2 + (byte~) main::j#5 ← (byte) main::j#4 + (byte~) main::i#5 ← (byte) main::i#1 + to:main::@1 + +Adding NOP phi() at start of main +CALL GRAPH +Calls in [] to 0:main + +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +CONTROL FLOW GRAPH - LIVE RANGES FOUND +@begin: scope:[] from + [0] call main param-assignment [ ] + to:@end +@end: scope:[] from @begin +main: scope:[main] from @begin + [1] phi() [ ] + to:main::@1 +main::@1: scope:[main] from main main::@5 + [2] (byte) main::i#2 ← phi( main/(byte) 0 main::@5/(byte~) main::i#5 ) [ main::j#3 main::i#2 ] + [2] (byte) main::j#3 ← phi( main/(byte) 0 main::@5/(byte~) main::j#5 ) [ main::j#3 main::i#2 ] + [3] (byte~) main::$0 ← (const byte[]) TXT#0 *idx (byte) main::j#3 [ main::j#3 main::i#2 main::$0 ] + [4] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::j#3 main::i#2 ] + [5] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] + [6] if((byte) main::j#1!=(byte) 8) goto main::@6 [ main::i#2 main::j#1 ] + to:main::@6 +main::@6: scope:[main] from main::@1 main::@1 + [7] (byte~) main::j#6 ← (byte) main::j#1 [ main::i#2 main::j#6 ] + to:main::@2 +main::@2: scope:[main] from main::@6 + [8] (byte) main::j#4 ← phi( main::@6/(byte~) main::j#6 main::@1/(byte) 0 ) [ main::i#2 main::j#4 ] + [9] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::j#4 main::i#1 ] + [10] if((byte) main::i#1!=(byte) 101) goto main::@5 [ main::j#4 main::i#1 ] + to:main::@return +main::@return: scope:[main] from main::@2 + [11] return [ ] + to:@return +main::@5: scope:[main] from main::@2 + [12] (byte~) main::j#5 ← (byte) main::j#4 [ main::j#5 main::i#1 ] + [13] (byte~) main::i#5 ← (byte) main::i#1 [ main::j#5 main::i#5 ] + to:main::@1 + +Created 3 initial phi equivalence classes +Coalesced [7] main::j#6 ← main::j#1 +Coalesced [12] main::j#5 ← main::j#4 +Coalesced [13] main::i#5 ← main::i#1 +Coalesced down to 2 phi equivalence classes +Culled Empty Block (label) main::@6 +Culled Empty Block (label) main::@5 +Block Sequence Planned @begin @end main main::@1 main::@2 main::@return +Adding NOP phi() at start of main +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +CONTROL FLOW GRAPH - PHI MEM COALESCED +@begin: scope:[] from + [0] call main param-assignment [ ] + to:@end +@end: scope:[] from @begin +main: scope:[main] from @begin + [1] phi() [ ] + to:main::@1 +main::@1: scope:[main] from main main::@2 + [2] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 ) [ main::j#3 main::i#2 ] + [2] (byte) main::j#3 ← phi( main/(byte) 0 main::@2/(byte) main::j#4 ) [ main::j#3 main::i#2 ] + [3] (byte~) main::$0 ← (const byte[]) TXT#0 *idx (byte) main::j#3 [ main::j#3 main::i#2 main::$0 ] + [4] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::j#3 main::i#2 ] + [5] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] + [6] if((byte) main::j#1!=(byte) 8) goto main::@2 [ main::i#2 main::j#1 ] + to:main::@2 +main::@2: scope:[main] from main::@1 main::@1 + [7] (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@1/(byte) 0 ) [ main::i#2 main::j#4 ] + [8] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::j#4 main::i#1 ] + [9] if((byte) main::i#1!=(byte) 101) goto main::@1 [ main::j#4 main::i#1 ] + to:main::@return +main::@return: scope:[main] from main::@2 + [10] return [ ] + to:@return + +DOMINATORS +@begin dominated by @begin +@end dominated by @end @begin +main dominated by @begin main +main::@1 dominated by @begin main::@1 main +main::@2 dominated by @begin main::@2 main::@1 main +main::@return dominated by main::@return @begin main::@2 main::@1 main + +Found back edge: Loop head: main::@1 tails: main::@2 blocks: null +Populated: Loop head: main::@1 tails: main::@2 blocks: main::@2 main::@1 +NATURAL LOOPS +Loop head: main::@1 tails: main::@2 blocks: main::@2 main::@1 + +Found 0 loops in scope [] +Found 1 loops in scope [main] + Loop head: main::@1 tails: main::@2 blocks: main::@2 main::@1 +NATURAL LOOPS WITH DEPTH +Loop head: main::@1 tails: main::@2 blocks: main::@2 main::@1 depth: 1 + + +VARIABLE REGISTER WEIGHTS +(byte*) SCREEN +(byte[]) TXT +(void()) main() +(byte~) main::$0 22.0 +(byte) main::i +(byte) main::i#1 16.5 +(byte) main::i#2 5.5 +(byte) main::j +(byte) main::j#1 16.5 +(byte) main::j#3 11.0 +(byte) main::j#4 7.333333333333333 + +Initial phi equivalence classes +[ main::j#3 main::j#4 main::j#1 ] +[ main::i#2 main::i#1 ] +Added variable main::$0 to zero page equivalence class [ main::$0 ] +Complete equivalence classes +[ main::j#3 main::j#4 main::j#1 ] +[ main::i#2 main::i#1 ] +[ main::$0 ] +Allocated zp ZP_BYTE:2 [ main::j#3 main::j#4 main::j#1 ] +Allocated zp ZP_BYTE:3 [ main::i#2 main::i#1 ] +Allocated zp ZP_BYTE:4 [ main::$0 ] +INITIAL ASM +//SEG0 Global Constants & labels + .const SCREEN = $400 + TXT: .byte 3, 1, $d, 5, $c, $f, $14, $20 +//SEG1 @begin +bbegin: +//SEG2 [0] call main param-assignment [ ] +//SEG3 [1] phi from @begin to main +main_from_bbegin: + jsr main + jmp bend +//SEG4 @end +bend: +//SEG5 main +main: { + .label _0 = 4 + .label j = 2 + .label i = 3 + //SEG6 [2] phi from main to main::@1 + b1_from_main: + //SEG7 [2] phi (byte) main::i#2 = (byte) 0 -- zpby1=coby1 + lda #0 + sta i + //SEG8 [2] phi (byte) main::j#3 = (byte) 0 -- zpby1=coby1 + lda #0 + sta j + jmp b1 + //SEG9 [2] phi from main::@2 to main::@1 + b1_from_b2: + //SEG10 [2] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy + //SEG11 [2] phi (byte) main::j#3 = (byte) main::j#4 -- register_copy + jmp b1 + //SEG12 main::@1 + b1: + //SEG13 [3] (byte~) main::$0 ← (const byte[]) TXT#0 *idx (byte) main::j#3 [ main::j#3 main::i#2 main::$0 ] -- zpby1=cowo1_staridx_zpby2 + ldx j + lda TXT,x + sta _0 + //SEG14 [4] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::j#3 main::i#2 ] -- cowo1_staridx_zpby1=zpby2 + lda _0 + ldx i + sta SCREEN,x + //SEG15 [5] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] -- zpby1=_inc_zpby1 + inc j + //SEG16 [6] if((byte) main::j#1!=(byte) 8) goto main::@2 [ main::i#2 main::j#1 ] -- zpby1_neq_coby1_then_la1 + lda j + cmp #8 + bne b2_from_b1 + //SEG17 [7] phi from main::@1 main::@1 to main::@2 + b2_from_b1: + b2_from_b1: + //SEG18 [7] phi (byte) main::j#4 = (byte) main::j#1 -- register_copy + //SEG19 [7] phi (byte) main::j#4 = (byte) 0 -- zpby1=coby1 + lda #0 + sta j + jmp b2 + //SEG20 main::@2 + b2: + //SEG21 [8] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::j#4 main::i#1 ] -- zpby1=_inc_zpby1 + inc i + //SEG22 [9] if((byte) main::i#1!=(byte) 101) goto main::@1 [ main::j#4 main::i#1 ] -- zpby1_neq_coby1_then_la1 + lda i + cmp #$65 + bne b1_from_b2 + jmp breturn + //SEG23 main::@return + breturn: + //SEG24 [10] return [ ] + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Potential registers zp ZP_BYTE:2 [ main::j#3 main::j#4 main::j#1 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:3 [ main::i#2 main::i#1 ] : zp ZP_BYTE:3 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:4 [ main::$0 ] : zp ZP_BYTE:4 , reg byte a , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 34.83: zp ZP_BYTE:2 [ main::j#3 main::j#4 main::j#1 ] 22: zp ZP_BYTE:3 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:4 [ main::$0 ] +Uplift Scope [] + +Uplifting [main] best 420 combination reg byte y [ main::j#3 main::j#4 main::j#1 ] reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$0 ] +Uplifting [] best 420 combination +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction bne b2_from_b1 +Removing instruction jmp b2 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +ASSEMBLER +//SEG0 Global Constants & labels + .const SCREEN = $400 + TXT: .byte 3, 1, $d, 5, $c, $f, $14, $20 +//SEG1 @begin +bbegin: +//SEG2 [0] call main param-assignment [ ] +//SEG3 [1] phi from @begin to main +main_from_bbegin: + jsr main +//SEG4 @end +bend: +//SEG5 main +main: { + //SEG6 [2] phi from main to main::@1 + b1_from_main: + //SEG7 [2] phi (byte) main::i#2 = (byte) 0 -- xby=coby1 + ldx #0 + //SEG8 [2] phi (byte) main::j#3 = (byte) 0 -- yby=coby1 + ldy #0 + jmp b1 + //SEG9 [2] phi from main::@2 to main::@1 + b1_from_b2: + //SEG10 [2] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy + //SEG11 [2] phi (byte) main::j#3 = (byte) main::j#4 -- register_copy + //SEG12 main::@1 + b1: + //SEG13 [3] (byte~) main::$0 ← (const byte[]) TXT#0 *idx (byte) main::j#3 [ main::j#3 main::i#2 main::$0 ] -- aby=cowo1_staridx_yby + lda TXT,y + //SEG14 [4] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::j#3 main::i#2 ] -- cowo1_staridx_xby=aby + sta SCREEN,x + //SEG15 [5] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] -- yby=_inc_yby + iny + //SEG16 [6] if((byte) main::j#1!=(byte) 8) goto main::@2 [ main::i#2 main::j#1 ] -- yby_neq_coby1_then_la1 + cpy #8 + //SEG17 [7] phi from main::@1 main::@1 to main::@2 + b2_from_b1: + b2_from_b1: + //SEG18 [7] phi (byte) main::j#4 = (byte) main::j#1 -- register_copy + //SEG19 [7] phi (byte) main::j#4 = (byte) 0 -- yby=coby1 + ldy #0 + //SEG20 main::@2 + b2: + //SEG21 [8] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::j#4 main::i#1 ] -- xby=_inc_xby + inx + //SEG22 [9] if((byte) main::i#1!=(byte) 101) goto main::@1 [ main::j#4 main::i#1 ] -- xby_neq_coby1_then_la1 + cpx #$65 + bne b1_from_b2 + //SEG23 main::@return + breturn: + //SEG24 [10] return [ ] + rts +} + +Replacing label b1_from_b2 with b1 +Removing instruction main_from_bbegin: +Removing instruction b1_from_b2: +Removing instruction b2_from_b1: +Removing instruction b2_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +ASSEMBLER +//SEG0 Global Constants & labels + .const SCREEN = $400 + TXT: .byte 3, 1, $d, 5, $c, $f, $14, $20 +//SEG1 @begin +bbegin: +//SEG2 [0] call main param-assignment [ ] +//SEG3 [1] phi from @begin to main + jsr main +//SEG4 @end +bend: +//SEG5 main +main: { + //SEG6 [2] phi from main to main::@1 + b1_from_main: + //SEG7 [2] phi (byte) main::i#2 = (byte) 0 -- xby=coby1 + ldx #0 + //SEG8 [2] phi (byte) main::j#3 = (byte) 0 -- yby=coby1 + ldy #0 + jmp b1 + //SEG9 [2] phi from main::@2 to main::@1 + //SEG10 [2] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy + //SEG11 [2] phi (byte) main::j#3 = (byte) main::j#4 -- register_copy + //SEG12 main::@1 + b1: + //SEG13 [3] (byte~) main::$0 ← (const byte[]) TXT#0 *idx (byte) main::j#3 [ main::j#3 main::i#2 main::$0 ] -- aby=cowo1_staridx_yby + lda TXT,y + //SEG14 [4] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::j#3 main::i#2 ] -- cowo1_staridx_xby=aby + sta SCREEN,x + //SEG15 [5] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] -- yby=_inc_yby + iny + //SEG16 [6] if((byte) main::j#1!=(byte) 8) goto main::@2 [ main::i#2 main::j#1 ] -- yby_neq_coby1_then_la1 + cpy #8 + //SEG17 [7] phi from main::@1 main::@1 to main::@2 + //SEG18 [7] phi (byte) main::j#4 = (byte) main::j#1 -- register_copy + //SEG19 [7] phi (byte) main::j#4 = (byte) 0 -- yby=coby1 + ldy #0 + //SEG20 main::@2 + b2: + //SEG21 [8] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::j#4 main::i#1 ] -- xby=_inc_xby + inx + //SEG22 [9] if((byte) main::i#1!=(byte) 101) goto main::@1 [ main::j#4 main::i#1 ] -- xby_neq_coby1_then_la1 + cpx #$65 + bne b1 + //SEG23 main::@return + breturn: + //SEG24 [10] return [ ] + rts +} + +Removing instruction bbegin: +Removing instruction bend: +Removing instruction b1_from_main: +Removing instruction b2: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +ASSEMBLER +//SEG0 Global Constants & labels + .const SCREEN = $400 + TXT: .byte 3, 1, $d, 5, $c, $f, $14, $20 +//SEG1 @begin +//SEG2 [0] call main param-assignment [ ] +//SEG3 [1] phi from @begin to main + jsr main +//SEG4 @end +//SEG5 main +main: { + //SEG6 [2] phi from main to main::@1 + //SEG7 [2] phi (byte) main::i#2 = (byte) 0 -- xby=coby1 + ldx #0 + //SEG8 [2] phi (byte) main::j#3 = (byte) 0 -- yby=coby1 + ldy #0 + jmp b1 + //SEG9 [2] phi from main::@2 to main::@1 + //SEG10 [2] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy + //SEG11 [2] phi (byte) main::j#3 = (byte) main::j#4 -- register_copy + //SEG12 main::@1 + b1: + //SEG13 [3] (byte~) main::$0 ← (const byte[]) TXT#0 *idx (byte) main::j#3 [ main::j#3 main::i#2 main::$0 ] -- aby=cowo1_staridx_yby + lda TXT,y + //SEG14 [4] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::j#3 main::i#2 ] -- cowo1_staridx_xby=aby + sta SCREEN,x + //SEG15 [5] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] -- yby=_inc_yby + iny + //SEG16 [6] if((byte) main::j#1!=(byte) 8) goto main::@2 [ main::i#2 main::j#1 ] -- yby_neq_coby1_then_la1 + cpy #8 + //SEG17 [7] phi from main::@1 main::@1 to main::@2 + //SEG18 [7] phi (byte) main::j#4 = (byte) main::j#1 -- register_copy + //SEG19 [7] phi (byte) main::j#4 = (byte) 0 -- yby=coby1 + ldy #0 + //SEG20 main::@2 + //SEG21 [8] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::j#4 main::i#1 ] -- xby=_inc_xby + inx + //SEG22 [9] if((byte) main::i#1!=(byte) 101) goto main::@1 [ main::j#4 main::i#1 ] -- xby_neq_coby1_then_la1 + cpx #$65 + bne b1 + //SEG23 main::@return + //SEG24 [10] return [ ] + rts +} + +Removing instruction jmp b1 +Succesful ASM optimization Pass5NextJumpElimination +ASSEMBLER +//SEG0 Global Constants & labels + .const SCREEN = $400 + TXT: .byte 3, 1, $d, 5, $c, $f, $14, $20 +//SEG1 @begin +//SEG2 [0] call main param-assignment [ ] +//SEG3 [1] phi from @begin to main + jsr main +//SEG4 @end +//SEG5 main +main: { + //SEG6 [2] phi from main to main::@1 + //SEG7 [2] phi (byte) main::i#2 = (byte) 0 -- xby=coby1 + ldx #0 + //SEG8 [2] phi (byte) main::j#3 = (byte) 0 -- yby=coby1 + ldy #0 + //SEG9 [2] phi from main::@2 to main::@1 + //SEG10 [2] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy + //SEG11 [2] phi (byte) main::j#3 = (byte) main::j#4 -- register_copy + //SEG12 main::@1 + b1: + //SEG13 [3] (byte~) main::$0 ← (const byte[]) TXT#0 *idx (byte) main::j#3 [ main::j#3 main::i#2 main::$0 ] -- aby=cowo1_staridx_yby + lda TXT,y + //SEG14 [4] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::j#3 main::i#2 ] -- cowo1_staridx_xby=aby + sta SCREEN,x + //SEG15 [5] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] -- yby=_inc_yby + iny + //SEG16 [6] if((byte) main::j#1!=(byte) 8) goto main::@2 [ main::i#2 main::j#1 ] -- yby_neq_coby1_then_la1 + cpy #8 + //SEG17 [7] phi from main::@1 main::@1 to main::@2 + //SEG18 [7] phi (byte) main::j#4 = (byte) main::j#1 -- register_copy + //SEG19 [7] phi (byte) main::j#4 = (byte) 0 -- yby=coby1 + ldy #0 + //SEG20 main::@2 + //SEG21 [8] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::j#4 main::i#1 ] -- xby=_inc_xby + inx + //SEG22 [9] if((byte) main::i#1!=(byte) 101) goto main::@1 [ main::j#4 main::i#1 ] -- xby_neq_coby1_then_la1 + cpx #$65 + bne b1 + //SEG23 main::@return + //SEG24 [10] return [ ] + rts +} + +FINAL SYMBOL TABLE +(label) @begin +(label) @end +(byte*) SCREEN +(const byte*) SCREEN#0 SCREEN = (word) 1024 +(byte[]) TXT +(const byte[]) TXT#0 TXT = { (byte) 3, (byte) 1, (byte) 13, (byte) 5, (byte) 12, (byte) 15, (byte) 20, (byte) 32 } +(void()) main() +(byte~) main::$0 reg byte a 22.0 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte) main::i +(byte) main::i#1 reg byte x 16.5 +(byte) main::i#2 reg byte x 5.5 +(byte) main::j +(byte) main::j#1 reg byte y 16.5 +(byte) main::j#3 reg byte y 11.0 +(byte) main::j#4 reg byte y 7.333333333333333 + +reg byte y [ main::j#3 main::j#4 main::j#1 ] +reg byte x [ main::i#2 main::i#1 ] +reg byte a [ main::$0 ] + +FINAL CODE +//SEG0 Global Constants & labels + .const SCREEN = $400 + TXT: .byte 3, 1, $d, 5, $c, $f, $14, $20 +//SEG1 @begin +//SEG2 [0] call main param-assignment [ ] +//SEG3 [1] phi from @begin to main + jsr main +//SEG4 @end +//SEG5 main +main: { + //SEG6 [2] phi from main to main::@1 + //SEG7 [2] phi (byte) main::i#2 = (byte) 0 -- xby=coby1 + ldx #0 + //SEG8 [2] phi (byte) main::j#3 = (byte) 0 -- yby=coby1 + ldy #0 + //SEG9 [2] phi from main::@2 to main::@1 + //SEG10 [2] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy + //SEG11 [2] phi (byte) main::j#3 = (byte) main::j#4 -- register_copy + //SEG12 main::@1 + b1: + //SEG13 [3] (byte~) main::$0 ← (const byte[]) TXT#0 *idx (byte) main::j#3 [ main::j#3 main::i#2 main::$0 ] -- aby=cowo1_staridx_yby + lda TXT,y + //SEG14 [4] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::j#3 main::i#2 ] -- cowo1_staridx_xby=aby + sta SCREEN,x + //SEG15 [5] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] -- yby=_inc_yby + iny + //SEG16 [6] if((byte) main::j#1!=(byte) 8) goto main::@2 [ main::i#2 main::j#1 ] -- yby_neq_coby1_then_la1 + cpy #8 + //SEG17 [7] phi from main::@1 main::@1 to main::@2 + //SEG18 [7] phi (byte) main::j#4 = (byte) main::j#1 -- register_copy + //SEG19 [7] phi (byte) main::j#4 = (byte) 0 -- yby=coby1 + ldy #0 + //SEG20 main::@2 + //SEG21 [8] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::j#4 main::i#1 ] -- xby=_inc_xby + inx + //SEG22 [9] if((byte) main::i#1!=(byte) 101) goto main::@1 [ main::j#4 main::i#1 ] -- xby_neq_coby1_then_la1 + cpx #$65 + bne b1 + //SEG23 main::@return + //SEG24 [10] return [ ] + rts +} + diff --git a/src/main/java/dk/camelot64/kickc/test/ref/inmemarray.sym b/src/main/java/dk/camelot64/kickc/test/ref/inmemarray.sym new file mode 100644 index 000000000..f02eca4be --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/inmemarray.sym @@ -0,0 +1,22 @@ +(label) @begin +(label) @end +(byte*) SCREEN +(const byte*) SCREEN#0 SCREEN = (word) 1024 +(byte[]) TXT +(const byte[]) TXT#0 TXT = { (byte) 3, (byte) 1, (byte) 13, (byte) 5, (byte) 12, (byte) 15, (byte) 20, (byte) 32 } +(void()) main() +(byte~) main::$0 reg byte a 22.0 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte) main::i +(byte) main::i#1 reg byte x 16.5 +(byte) main::i#2 reg byte x 5.5 +(byte) main::j +(byte) main::j#1 reg byte y 16.5 +(byte) main::j#3 reg byte y 11.0 +(byte) main::j#4 reg byte y 7.333333333333333 + +reg byte y [ main::j#3 main::j#4 main::j#1 ] +reg byte x [ main::i#2 main::i#1 ] +reg byte a [ main::$0 ]