From 114a237e24f98b29d7137ac8e1cd01aa56675fe0 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sun, 16 Jun 2019 15:03:23 +0200 Subject: [PATCH] Added address-of test identifying problems with address-of implementation. Error is #200 --- .../java/dk/camelot64/kickc/Compiler.java | 1 - .../kickc/passes/Pass1UnwindStructValues.java | 23 +- .../passes/Pass2ConstantIdentification.java | 10 + ...ass4RegisterUpliftPotentialInitialize.java | 6 - .../dk/camelot64/kickc/test/TestPrograms.java | 15 +- .../{test-address-of.kc => address-of-0.kc} | 1 + ...st-address-of-param.kc => address-of-1.kc} | 1 + src/test/kc/address-of-2.kc | 42 + .../{test-address-of.asm => address-of-0.asm} | 1 + .../{test-address-of.cfg => address-of-0.cfg} | 0 .../{test-address-of.log => address-of-0.log} | 3 + .../{test-address-of.sym => address-of-0.sym} | 0 ...-address-of-param.asm => address-of-1.asm} | 1 + ...-address-of-param.cfg => address-of-1.cfg} | 0 ...-address-of-param.log => address-of-1.log} | 3 + ...-address-of-param.sym => address-of-1.sym} | 0 src/test/ref/address-of-2.asm | 52 ++ src/test/ref/address-of-2.cfg | 46 ++ src/test/ref/address-of-2.log | 780 ++++++++++++++++++ src/test/ref/address-of-2.sym | 27 + src/test/ref/struct-ptr-12-ref.asm | 18 + src/test/ref/struct-ptr-12-ref.cfg | 19 + src/test/ref/struct-ptr-12-ref.log | 331 ++++++++ src/test/ref/struct-ptr-12-ref.sym | 17 + 24 files changed, 1383 insertions(+), 14 deletions(-) rename src/test/kc/{test-address-of.kc => address-of-0.kc} (73%) rename src/test/kc/{test-address-of-param.kc => address-of-1.kc} (84%) create mode 100644 src/test/kc/address-of-2.kc rename src/test/ref/{test-address-of.asm => address-of-0.asm} (83%) rename src/test/ref/{test-address-of.cfg => address-of-0.cfg} (100%) rename src/test/ref/{test-address-of.log => address-of-0.log} (98%) rename src/test/ref/{test-address-of.sym => address-of-0.sym} (100%) rename src/test/ref/{test-address-of-param.asm => address-of-1.asm} (93%) rename src/test/ref/{test-address-of-param.cfg => address-of-1.cfg} (100%) rename src/test/ref/{test-address-of-param.log => address-of-1.log} (99%) rename src/test/ref/{test-address-of-param.sym => address-of-1.sym} (100%) create mode 100644 src/test/ref/address-of-2.asm create mode 100644 src/test/ref/address-of-2.cfg create mode 100644 src/test/ref/address-of-2.log create mode 100644 src/test/ref/address-of-2.sym create mode 100644 src/test/ref/struct-ptr-12-ref.asm create mode 100644 src/test/ref/struct-ptr-12-ref.cfg create mode 100644 src/test/ref/struct-ptr-12-ref.log create mode 100644 src/test/ref/struct-ptr-12-ref.sym diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index 1aa32c90e..d60ac2785 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -170,7 +170,6 @@ public class Compiler { new Pass1AssertReturn(program).execute(); new Pass1AssertUsedVars(program).execute(); - if(getLog().isVerbosePass1CreateSsa()) { getLog().append("SYMBOLS"); getLog().append(program.getScope().toString(program, null)); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java b/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java index 9c063e0c6..3734aaf37 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java @@ -230,7 +230,6 @@ public class Pass1UnwindStructValues extends Pass1Base { for(Variable variable : getScope().getAllVariables(true)) { if(variable.getType() instanceof SymbolTypeStruct) { if(structUnwinding.getVariableUnwinding(variable.getRef()) == null) { - if(!variable.isDeclaredVolatile() && !Pass2ConstantIdentification.isAddressOfUsed(variable.getRef(), getProgram())) { // A non-volatile struct variable Scope scope = variable.getScope(); if(!(scope instanceof StructDefinition)) { @@ -244,13 +243,14 @@ public class Pass1UnwindStructValues extends Pass1Base { } else { memberVariable = scope.addVariable(variable.getLocalName() + "_" + member.getLocalName(), member.getType()); } + memberVariable.setDeclaredVolatile(variable.isDeclaredVolatile()); + memberVariable.setDeclaredConstant(variable.isDeclaredConstant()); variableUnwinding.setMemberUnwinding(member.getLocalName(), memberVariable.getRef()); getLog().append("Created struct value member variable " + memberVariable.toString(getProgram())); } getLog().append("Converted struct value to member variables " + variable.toString(getProgram())); modified = true; } - } } } } @@ -396,6 +396,25 @@ public class Pass1UnwindStructValues extends Pass1Base { return structVariables.get(ref); } + /** + * Find the struct variable that the passed symbol was unwound from. + * + * @param symbolRef The symbol to look for + * @return The struct variable containing it. null if the passed symbol is not an unwound variable. + */ + public VariableRef getContainingStructVariable(SymbolRef symbolRef) { + for(VariableRef structVarRef : structVariables.keySet()) { + VariableUnwinding variableUnwinding = getVariableUnwinding(structVarRef); + for(String memberName : variableUnwinding.getMemberNames()) { + LValue memberUnwinding = variableUnwinding.getMemberUnwinding(memberName); + if(memberUnwinding instanceof VariableRef && memberUnwinding.equals(symbolRef)) { + return structVarRef; + } + } + } + return null; + } + /** Information about how a single struct variable was unwound. */ static class VariableUnwinding implements StructMemberUnwinding { diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java index 58cbc1719..7d97935fe 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java @@ -295,6 +295,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization { */ public static boolean isAddressOfUsed(SymbolRef symbolRef, Program program) { final boolean[] found = {false}; + // Examine all program values in expressions ProgramValueIterator.execute(program, (programValue, currentStmt, stmtIt, currentBlock) -> { Value value = programValue.get(); if(value instanceof ConstantSymbolPointer) { @@ -308,6 +309,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization { return true; } + // Examine all statements for(ControlFlowBlock block : program.getGraph().getAllBlocks()) { for(Statement statement : block.getStatements()) { if(statement instanceof StatementAssignment) { @@ -318,6 +320,14 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization { } } } + + // If the symbol is part of an unwound struct - look at the struct itself + Pass1UnwindStructValues.StructUnwinding structUnwinding = program.getStructUnwinding(); + VariableRef structVarRef = structUnwinding.getContainingStructVariable(symbolRef); + if(structVarRef!=null) { + return isAddressOfUsed(structVarRef, program); + } + return false; } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftPotentialInitialize.java b/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftPotentialInitialize.java index a99167211..acac2834b 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftPotentialInitialize.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftPotentialInitialize.java @@ -89,10 +89,4 @@ public class Pass4RegisterUpliftPotentialInitialize extends Pass2Base { return false; } - private boolean hasIntersection(Collection vars1, List vars2) { - ArrayList set = new ArrayList<>(vars1); - set.retainAll(vars2); - return set.size() > 0; - } - } diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 38b1640ac..08e7365f5 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -73,12 +73,12 @@ public class TestPrograms { compileAndCompare("struct-ptr-13"); } - /* TODO: Implement address-of (&) for struct values @Test public void testStructPtr12Ref() throws IOException, URISyntaxException { compileAndCompare("struct-ptr-12-ref", log()); } + /* @Test public void testStructPtr12() throws IOException, URISyntaxException { compileAndCompare("struct-ptr-12", log().verboseCreateSsa().verboseParse().verboseStatementSequence()); @@ -1706,13 +1706,18 @@ public class TestPrograms { } @Test - public void testAddressOfParam() throws IOException, URISyntaxException { - compileAndCompare("test-address-of-param"); + public void testAddressOf2() throws IOException, URISyntaxException { + compileAndCompare("address-of-2"); } @Test - public void testAddressOf() throws IOException, URISyntaxException { - compileAndCompare("test-address-of"); + public void testAddressOf1() throws IOException, URISyntaxException { + compileAndCompare("address-of-1"); + } + + @Test + public void testAddressOf0() throws IOException, URISyntaxException { + compileAndCompare("address-of-0"); } @Test diff --git a/src/test/kc/test-address-of.kc b/src/test/kc/address-of-0.kc similarity index 73% rename from src/test/kc/test-address-of.kc rename to src/test/kc/address-of-0.kc index 0042efc2c..584d52282 100644 --- a/src/test/kc/test-address-of.kc +++ b/src/test/kc/address-of-0.kc @@ -1,3 +1,4 @@ +// Test address-of - use the pointer to get the value void main() { byte* SCREEN = $400; diff --git a/src/test/kc/test-address-of-param.kc b/src/test/kc/address-of-1.kc similarity index 84% rename from src/test/kc/test-address-of-param.kc rename to src/test/kc/address-of-1.kc index 7f497b87f..88337cd71 100644 --- a/src/test/kc/test-address-of-param.kc +++ b/src/test/kc/address-of-1.kc @@ -1,3 +1,4 @@ +// Test address-of - pass the pointer as parameter void main() { byte* SCREEN = $400; diff --git a/src/test/kc/address-of-2.kc b/src/test/kc/address-of-2.kc new file mode 100644 index 000000000..0f66172f3 --- /dev/null +++ b/src/test/kc/address-of-2.kc @@ -0,0 +1,42 @@ +// Test address-of by assigning the affected variable in multiple ways + +byte val = 0; + +void main() { + const byte* SCREEN1 = 0x0400; + const byte* SCREEN2 = SCREEN1+40; + byte idx = 0; + SCREEN1[idx] = val; + SCREEN2[idx++] = '.'; + // Here we have not yet used address-of - so val can be versioned freely + val = 1; + SCREEN1[idx] = val; + SCREEN2[idx++] = '.'; + // Use address-of - hereafter all versions of val must be in the same memory + byte* ptr = &val; + // Set value directly + val = 2; + SCREEN1[idx] = val; + SCREEN2[idx++] = *ptr; + // Set value through pointer + *ptr = 3; + SCREEN1[idx] = val; + SCREEN2[idx++] = *ptr; + // Set value directly in a call + setv(4); + SCREEN1[idx] = val; + SCREEN2[idx++] = *ptr; + // Set value through pointer in a call + setp(ptr, 5); + SCREEN1[idx] = val; + SCREEN2[idx++] = *ptr; +} + +void setv(byte v) { + val = v; +} + +void setp(byte* p, byte v) { + *p = v; +} + diff --git a/src/test/ref/test-address-of.asm b/src/test/ref/address-of-0.asm similarity index 83% rename from src/test/ref/test-address-of.asm rename to src/test/ref/address-of-0.asm index f2ab512e7..e54bc604b 100644 --- a/src/test/ref/test-address-of.asm +++ b/src/test/ref/address-of-0.asm @@ -1,3 +1,4 @@ +// Test address-of - use the pointer to get the value .pc = $801 "Basic" :BasicUpstart(main) .pc = $80d "Program" diff --git a/src/test/ref/test-address-of.cfg b/src/test/ref/address-of-0.cfg similarity index 100% rename from src/test/ref/test-address-of.cfg rename to src/test/ref/address-of-0.cfg diff --git a/src/test/ref/test-address-of.log b/src/test/ref/address-of-0.log similarity index 98% rename from src/test/ref/test-address-of.log rename to src/test/ref/address-of-0.log index 841524241..787320b73 100644 --- a/src/test/ref/test-address-of.log +++ b/src/test/ref/address-of-0.log @@ -150,6 +150,7 @@ Allocated zp ZP_BYTE:3 [ main::c#0 ] INITIAL ASM //SEG0 File Comments +// Test address-of - use the pointer to get the value //SEG1 Basic Upstart .pc = $801 "Basic" :BasicUpstart(bbegin) @@ -227,6 +228,7 @@ Uplifting [main] best 443 combination zp ZP_BYTE:2 [ main::b#2 main::b#1 ] ASSEMBLER BEFORE OPTIMIZATION //SEG0 File Comments +// Test address-of - use the pointer to get the value //SEG1 Basic Upstart .pc = $801 "Basic" :BasicUpstart(bbegin) @@ -335,6 +337,7 @@ FINAL ASSEMBLER Score: 341 //SEG0 File Comments +// Test address-of - use the pointer to get the value //SEG1 Basic Upstart .pc = $801 "Basic" :BasicUpstart(main) diff --git a/src/test/ref/test-address-of.sym b/src/test/ref/address-of-0.sym similarity index 100% rename from src/test/ref/test-address-of.sym rename to src/test/ref/address-of-0.sym diff --git a/src/test/ref/test-address-of-param.asm b/src/test/ref/address-of-1.asm similarity index 93% rename from src/test/ref/test-address-of-param.asm rename to src/test/ref/address-of-1.asm index 7cfbdb225..035de222b 100644 --- a/src/test/ref/test-address-of-param.asm +++ b/src/test/ref/address-of-1.asm @@ -1,3 +1,4 @@ +// Test address-of - pass the pointer as parameter .pc = $801 "Basic" :BasicUpstart(main) .pc = $80d "Program" diff --git a/src/test/ref/test-address-of-param.cfg b/src/test/ref/address-of-1.cfg similarity index 100% rename from src/test/ref/test-address-of-param.cfg rename to src/test/ref/address-of-1.cfg diff --git a/src/test/ref/test-address-of-param.log b/src/test/ref/address-of-1.log similarity index 99% rename from src/test/ref/test-address-of-param.log rename to src/test/ref/address-of-1.log index 2ca507dc2..8a8c03968 100644 --- a/src/test/ref/test-address-of-param.log +++ b/src/test/ref/address-of-1.log @@ -263,6 +263,7 @@ Allocated zp ZP_BYTE:7 [ main::b3#0 ] INITIAL ASM //SEG0 File Comments +// Test address-of - pass the pointer as parameter //SEG1 Basic Upstart .pc = $801 "Basic" :BasicUpstart(bbegin) @@ -412,6 +413,7 @@ Allocated (was zp ZP_BYTE:7) zp ZP_BYTE:6 [ main::b3#0 ] ASSEMBLER BEFORE OPTIMIZATION //SEG0 File Comments +// Test address-of - pass the pointer as parameter //SEG1 Basic Upstart .pc = $801 "Basic" :BasicUpstart(bbegin) @@ -591,6 +593,7 @@ FINAL ASSEMBLER Score: 108 //SEG0 File Comments +// Test address-of - pass the pointer as parameter //SEG1 Basic Upstart .pc = $801 "Basic" :BasicUpstart(main) diff --git a/src/test/ref/test-address-of-param.sym b/src/test/ref/address-of-1.sym similarity index 100% rename from src/test/ref/test-address-of-param.sym rename to src/test/ref/address-of-1.sym diff --git a/src/test/ref/address-of-2.asm b/src/test/ref/address-of-2.asm new file mode 100644 index 000000000..b2bad2eac --- /dev/null +++ b/src/test/ref/address-of-2.asm @@ -0,0 +1,52 @@ +// Test address-of by assigning the affected variable in multiple ways +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label val = 2 +main: { + .label SCREEN1 = $400 + .label ptr = val + .label SCREEN2 = SCREEN1+$28 + lda #0 + sta SCREEN1 + lda #'.' + sta SCREEN2 + // Here we have not yet used address-of - so val can be versioned freely + lda #1 + sta val + sta SCREEN1+1 + lda #'.' + sta SCREEN2+1 + lda #2 + sta SCREEN1+2 + lda ptr + sta SCREEN2+2 + // Set value through pointer + lda #3 + sta ptr + lda #2 + sta SCREEN1+3 + lda ptr + sta SCREEN2+3 + jsr setv + lda #setv.v + sta SCREEN1+4 + lda ptr + sta SCREEN2+4 + jsr setp + lda #setv.v + sta SCREEN1+5 + lda ptr + sta SCREEN2+5 + rts +} +setp: { + .const v = 5 + lda #v + sta main.ptr + rts +} +setv: { + .label v = 4 + rts +} diff --git a/src/test/ref/address-of-2.cfg b/src/test/ref/address-of-2.cfg new file mode 100644 index 000000000..ae82daf58 --- /dev/null +++ b/src/test/ref/address-of-2.cfg @@ -0,0 +1,46 @@ +@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] *((const byte*) main::SCREEN1#0) ← (byte) 0 + [5] *((const byte*) main::SCREEN2#0) ← (byte) '.' + [6] (byte) val#1 ← (byte) 1 + [7] *((const byte*) main::SCREEN1#0+(byte) 1) ← (byte) val#1 + [8] *((const byte*) main::SCREEN2#0+(byte) 1) ← (byte) '.' + [9] *((const byte*) main::SCREEN1#0+(byte) 2) ← (byte) 2 + [10] *((const byte*) main::SCREEN2#0+(byte) 2) ← *((const byte*) main::ptr#0) + [11] *((const byte*) main::ptr#0) ← (byte) 3 + [12] *((const byte*) main::SCREEN1#0+(byte) 3) ← (byte) 2 + [13] *((const byte*) main::SCREEN2#0+(byte) 3) ← *((const byte*) main::ptr#0) + [14] call setv + to:main::@1 +main::@1: scope:[main] from main + [15] *((const byte*) main::SCREEN1#0+(byte) 4) ← (const byte) setv::v#0 + [16] *((const byte*) main::SCREEN2#0+(byte) 4) ← *((const byte*) main::ptr#0) + [17] call setp + to:main::@2 +main::@2: scope:[main] from main::@1 + [18] *((const byte*) main::SCREEN1#0+(byte) 5) ← (const byte) setv::v#0 + [19] *((const byte*) main::SCREEN2#0+(byte) 5) ← *((const byte*) main::ptr#0) + to:main::@return +main::@return: scope:[main] from main::@2 + [20] return + to:@return +setp: scope:[setp] from main::@1 + [21] *((const byte*) main::ptr#0) ← (const byte) setp::v#0 + to:setp::@return +setp::@return: scope:[setp] from setp + [22] return + to:@return +setv: scope:[setv] from main + [23] phi() + to:setv::@return +setv::@return: scope:[setv] from setv + [24] return + to:@return diff --git a/src/test/ref/address-of-2.log b/src/test/ref/address-of-2.log new file mode 100644 index 000000000..fd1f7e258 --- /dev/null +++ b/src/test/ref/address-of-2.log @@ -0,0 +1,780 @@ +Adding pointer type conversion cast (byte*) main::SCREEN1 in (byte*) main::SCREEN1 ← (number) $400 +Culled Empty Block (label) @1 +Culled Empty Block (label) @2 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (byte) val#0 ← (number) 0 + to:@3 +main: scope:[main] from @3 + (byte) val#8 ← phi( @3/(byte) val#14 ) + (byte*) main::SCREEN1#0 ← ((byte*)) (number) $400 + (byte*~) main::$0 ← (byte*) main::SCREEN1#0 + (number) $28 + (byte*) main::SCREEN2#0 ← (byte*~) main::$0 + (byte) main::idx#0 ← (number) 0 + *((byte*) main::SCREEN1#0 + (byte) main::idx#0) ← (byte) val#8 + *((byte*) main::SCREEN2#0 + (byte) main::idx#0) ← (byte) '.' + (byte) main::idx#1 ← ++ (byte) main::idx#0 + (byte) val#1 ← (number) 1 + *((byte*) main::SCREEN1#0 + (byte) main::idx#1) ← (byte) val#1 + *((byte*) main::SCREEN2#0 + (byte) main::idx#1) ← (byte) '.' + (byte) main::idx#2 ← ++ (byte) main::idx#1 + (byte*~) main::$1 ← & (byte) val#1 + (byte*) main::ptr#0 ← (byte*~) main::$1 + (byte) val#2 ← (number) 2 + *((byte*) main::SCREEN1#0 + (byte) main::idx#2) ← (byte) val#2 + *((byte*) main::SCREEN2#0 + (byte) main::idx#2) ← *((byte*) main::ptr#0) + (byte) main::idx#3 ← ++ (byte) main::idx#2 + *((byte*) main::ptr#0) ← (number) 3 + *((byte*) main::SCREEN1#0 + (byte) main::idx#3) ← (byte) val#2 + *((byte*) main::SCREEN2#0 + (byte) main::idx#3) ← *((byte*) main::ptr#0) + (byte) main::idx#4 ← ++ (byte) main::idx#3 + (byte) setv::v#0 ← (number) 4 + call setv + to:main::@1 +main::@1: scope:[main] from main + (byte*) main::ptr#1 ← phi( main/(byte*) main::ptr#0 ) + (byte) main::idx#7 ← phi( main/(byte) main::idx#4 ) + (byte) val#9 ← phi( main/(byte) val#6 ) + (byte) val#3 ← (byte) val#9 + *((byte*) main::SCREEN1#0 + (byte) main::idx#7) ← (byte) val#3 + *((byte*) main::SCREEN2#0 + (byte) main::idx#7) ← *((byte*) main::ptr#1) + (byte) main::idx#5 ← ++ (byte) main::idx#7 + (byte*) setp::p#0 ← (byte*) main::ptr#1 + (byte) setp::v#0 ← (number) 5 + call setp + to:main::@2 +main::@2: scope:[main] from main::@1 + (byte*) main::ptr#2 ← phi( main::@1/(byte*) main::ptr#1 ) + (byte) main::idx#8 ← phi( main::@1/(byte) main::idx#5 ) + (byte) val#10 ← phi( main::@1/(byte) val#3 ) + *((byte*) main::SCREEN1#0 + (byte) main::idx#8) ← (byte) val#10 + *((byte*) main::SCREEN2#0 + (byte) main::idx#8) ← *((byte*) main::ptr#2) + (byte) main::idx#6 ← ++ (byte) main::idx#8 + to:main::@return +main::@return: scope:[main] from main::@2 + (byte) val#11 ← phi( main::@2/(byte) val#10 ) + (byte) val#4 ← (byte) val#11 + return + to:@return +setv: scope:[setv] from main + (byte) setv::v#1 ← phi( main/(byte) setv::v#0 ) + (byte) val#5 ← (byte) setv::v#1 + to:setv::@return +setv::@return: scope:[setv] from setv + (byte) val#12 ← phi( setv/(byte) val#5 ) + (byte) val#6 ← (byte) val#12 + return + to:@return +setp: scope:[setp] from main::@1 + (byte*) setp::p#1 ← phi( main::@1/(byte*) setp::p#0 ) + (byte) setp::v#1 ← phi( main::@1/(byte) setp::v#0 ) + *((byte*) setp::p#1) ← (byte) setp::v#1 + to:setp::@return +setp::@return: scope:[setp] from setp + return + to:@return +@3: scope:[] from @begin + (byte) val#14 ← phi( @begin/(byte) val#0 ) + call main + to:@4 +@4: scope:[] from @3 + (byte) val#13 ← phi( @3/(byte) val#4 ) + (byte) val#7 ← (byte) val#13 + to:@end +@end: scope:[] from @4 + +SYMBOL TABLE SSA +(label) @3 +(label) @4 +(label) @begin +(label) @end +(void()) main() +(byte*~) main::$0 +(byte*~) main::$1 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte*) main::SCREEN1 +(byte*) main::SCREEN1#0 +(byte*) main::SCREEN2 +(byte*) main::SCREEN2#0 +(byte) main::idx +(byte) main::idx#0 +(byte) main::idx#1 +(byte) main::idx#2 +(byte) main::idx#3 +(byte) main::idx#4 +(byte) main::idx#5 +(byte) main::idx#6 +(byte) main::idx#7 +(byte) main::idx#8 +(byte*) main::ptr +(byte*) main::ptr#0 +(byte*) main::ptr#1 +(byte*) main::ptr#2 +(void()) setp((byte*) setp::p , (byte) setp::v) +(label) setp::@return +(byte*) setp::p +(byte*) setp::p#0 +(byte*) setp::p#1 +(byte) setp::v +(byte) setp::v#0 +(byte) setp::v#1 +(void()) setv((byte) setv::v) +(label) setv::@return +(byte) setv::v +(byte) setv::v#0 +(byte) setv::v#1 +(byte) val +(byte) val#0 +(byte) val#1 +(byte) val#10 +(byte) val#11 +(byte) val#12 +(byte) val#13 +(byte) val#14 +(byte) val#2 +(byte) val#3 +(byte) val#4 +(byte) val#5 +(byte) val#6 +(byte) val#7 +(byte) val#8 +(byte) val#9 + +Adding number conversion cast (unumber) 0 in (byte) val#0 ← (number) 0 +Adding number conversion cast (unumber) $28 in (byte*~) main::$0 ← (byte*) main::SCREEN1#0 + (number) $28 +Adding number conversion cast (unumber) 0 in (byte) main::idx#0 ← (number) 0 +Adding number conversion cast (unumber) 1 in (byte) val#1 ← (number) 1 +Adding number conversion cast (unumber) 2 in (byte) val#2 ← (number) 2 +Adding number conversion cast (unumber) 3 in *((byte*) main::ptr#0) ← (number) 3 +Adding number conversion cast (unumber) 4 in (byte) setv::v#0 ← (number) 4 +Adding number conversion cast (unumber) 5 in (byte) setp::v#0 ← (number) 5 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte) val#0 ← (unumber)(number) 0 +Inlining cast (byte*) main::SCREEN1#0 ← (byte*)(number) $400 +Inlining cast (byte) main::idx#0 ← (unumber)(number) 0 +Inlining cast (byte) val#1 ← (unumber)(number) 1 +Inlining cast (byte) val#2 ← (unumber)(number) 2 +Inlining cast *((byte*) main::ptr#0) ← (unumber)(number) 3 +Inlining cast (byte) setv::v#0 ← (unumber)(number) 4 +Inlining cast (byte) setp::v#0 ← (unumber)(number) 5 +Successful SSA optimization Pass2InlineCast +Simplifying constant integer cast 0 +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast $28 +Simplifying constant integer cast 0 +Simplifying constant integer cast 1 +Simplifying constant integer cast 2 +Simplifying constant integer cast 3 +Simplifying constant integer cast 4 +Simplifying constant integer cast 5 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) $28 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 2 +Finalized unsigned number type (byte) 3 +Finalized unsigned number type (byte) 4 +Finalized unsigned number type (byte) 5 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias (byte*) main::SCREEN2#0 = (byte*~) main::$0 +Alias (byte*) main::ptr#0 = (byte*~) main::$1 (byte*) main::ptr#1 (byte*) main::ptr#2 +Alias (byte) main::idx#4 = (byte) main::idx#7 +Alias (byte) val#10 = (byte) val#3 (byte) val#9 (byte) val#11 (byte) val#4 +Alias (byte) main::idx#5 = (byte) main::idx#8 +Alias (byte) val#12 = (byte) val#5 (byte) val#6 +Alias (byte) val#0 = (byte) val#14 +Alias (byte) val#13 = (byte) val#7 +Successful SSA optimization Pass2AliasElimination +Identical Phi Values (byte) val#8 (byte) val#0 +Identical Phi Values (byte) val#10 (byte) val#12 +Identical Phi Values (byte) setv::v#1 (byte) setv::v#0 +Identical Phi Values (byte) setp::v#1 (byte) setp::v#0 +Identical Phi Values (byte*) setp::p#1 (byte*) setp::p#0 +Identical Phi Values (byte) val#13 (byte) val#10 +Successful SSA optimization Pass2IdenticalPhiElimination +Constant right-side identified [13] (byte*) main::ptr#0 ← & (byte) val#1 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte) val#0 = 0 +Constant (const byte*) main::SCREEN1#0 = (byte*) 1024 +Constant (const byte) main::idx#0 = 0 +Constant (const byte*) main::ptr#0 = &val#1 +Constant (const byte) val#2 = 2 +Constant (const byte) setv::v#0 = 4 +Constant (const byte) setp::v#0 = 5 +Successful SSA optimization Pass2ConstantIdentification +Constant (const byte*) setp::p#0 = main::ptr#0 +Constant (const byte) val#12 = setv::v#0 +Successful SSA optimization Pass2ConstantIdentification +Simplifying expression containing zero main::SCREEN1#0 in [6] *((const byte*) main::SCREEN1#0 + (const byte) main::idx#0) ← (const byte) val#0 +Simplifying expression containing zero main::SCREEN2#0 in [7] *((byte*) main::SCREEN2#0 + (const byte) main::idx#0) ← (byte) '.' +Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused variable (byte) main::idx#6 and assignment [22] (byte) main::idx#6 ← ++ (byte) main::idx#5 +Successful SSA optimization PassNEliminateUnusedVars +Constant right-side identified [0] (byte*) main::SCREEN2#0 ← (const byte*) main::SCREEN1#0 + (byte) $28 +Constant right-side identified [3] (byte) main::idx#1 ← ++ (const byte) main::idx#0 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte*) main::SCREEN2#0 = main::SCREEN1#0+$28 +Constant (const byte) main::idx#1 = ++main::idx#0 +Successful SSA optimization Pass2ConstantIdentification +Constant right-side identified [5] (byte) main::idx#2 ← ++ (const byte) main::idx#1 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte) main::idx#2 = ++main::idx#1 +Successful SSA optimization Pass2ConstantIdentification +Constant right-side identified [7] (byte) main::idx#3 ← ++ (const byte) main::idx#2 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte) main::idx#3 = ++main::idx#2 +Successful SSA optimization Pass2ConstantIdentification +Constant right-side identified [10] (byte) main::idx#4 ← ++ (const byte) main::idx#3 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte) main::idx#4 = ++main::idx#3 +Successful SSA optimization Pass2ConstantIdentification +Constant right-side identified [13] (byte) main::idx#5 ← ++ (const byte) main::idx#4 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte) main::idx#5 = ++main::idx#4 +Successful SSA optimization Pass2ConstantIdentification +Inlining constant with different constant siblings (const byte) main::idx#0 +Inlining constant with different constant siblings (const byte) main::idx#1 +Inlining constant with different constant siblings (const byte) main::idx#2 +Inlining constant with different constant siblings (const byte) main::idx#3 +Inlining constant with different constant siblings (const byte) main::idx#4 +Inlining constant with different constant siblings (const byte) main::idx#5 +Inlining constant with var siblings (const byte) val#0 +Inlining constant with var siblings (const byte) val#2 +Inlining constant with var siblings (const byte) val#12 +Constant inlined main::idx#0 = (byte) 0 +Constant inlined main::idx#1 = ++(byte) 0 +Constant inlined val#0 = (byte) 0 +Constant inlined main::idx#2 = ++++(byte) 0 +Constant inlined main::idx#3 = ++++++(byte) 0 +Constant inlined main::idx#4 = ++++++++(byte) 0 +Constant inlined main::idx#5 = ++++++++++(byte) 0 +Constant inlined val#12 = (const byte) setv::v#0 +Constant inlined setp::p#0 = (const byte*) main::ptr#0 +Constant inlined val#2 = (byte) 2 +Successful SSA optimization Pass2ConstantInlining +Consolidated array index constant in *(main::SCREEN1#0+++0) +Consolidated array index constant in *(main::SCREEN2#0+++0) +Consolidated array index constant in *(main::SCREEN1#0+++++0) +Consolidated array index constant in *(main::SCREEN2#0+++++0) +Consolidated array index constant in *(main::SCREEN1#0+++++++0) +Consolidated array index constant in *(main::SCREEN2#0+++++++0) +Consolidated array index constant in *(main::SCREEN1#0+++++++++0) +Consolidated array index constant in *(main::SCREEN2#0+++++++++0) +Consolidated array index constant in *(main::SCREEN1#0+++++++++++0) +Consolidated array index constant in *(main::SCREEN2#0+++++++++++0) +Successful SSA optimization Pass2ConstantAdditionElimination +Simplifying constant integer increment ++0 +Simplifying constant integer increment ++0 +Simplifying constant integer increment ++0 +Simplifying constant integer increment ++1 +Simplifying constant integer increment ++1 +Simplifying constant integer increment ++2 +Simplifying constant integer increment ++2 +Simplifying constant integer increment ++3 +Simplifying constant integer increment ++3 +Simplifying constant integer increment ++4 +Successful SSA optimization Pass2ConstantSimplification +Simplifying constant integer increment ++1 +Simplifying constant integer increment ++2 +Simplifying constant integer increment ++3 +Simplifying constant integer increment ++4 +Successful SSA optimization Pass2ConstantSimplification +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @3 +Adding NOP phi() at start of @4 +Adding NOP phi() at start of @end +Adding NOP phi() at start of setv +CALL GRAPH +Calls in [] to main:2 +Calls in [main] to setv:15 setp:18 + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Culled Empty Block (label) @4 +Renumbering block @3 to @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 setv + +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] *((const byte*) main::SCREEN1#0) ← (byte) 0 + [5] *((const byte*) main::SCREEN2#0) ← (byte) '.' + [6] (byte) val#1 ← (byte) 1 + [7] *((const byte*) main::SCREEN1#0+(byte) 1) ← (byte) val#1 + [8] *((const byte*) main::SCREEN2#0+(byte) 1) ← (byte) '.' + [9] *((const byte*) main::SCREEN1#0+(byte) 2) ← (byte) 2 + [10] *((const byte*) main::SCREEN2#0+(byte) 2) ← *((const byte*) main::ptr#0) + [11] *((const byte*) main::ptr#0) ← (byte) 3 + [12] *((const byte*) main::SCREEN1#0+(byte) 3) ← (byte) 2 + [13] *((const byte*) main::SCREEN2#0+(byte) 3) ← *((const byte*) main::ptr#0) + [14] call setv + to:main::@1 +main::@1: scope:[main] from main + [15] *((const byte*) main::SCREEN1#0+(byte) 4) ← (const byte) setv::v#0 + [16] *((const byte*) main::SCREEN2#0+(byte) 4) ← *((const byte*) main::ptr#0) + [17] call setp + to:main::@2 +main::@2: scope:[main] from main::@1 + [18] *((const byte*) main::SCREEN1#0+(byte) 5) ← (const byte) setv::v#0 + [19] *((const byte*) main::SCREEN2#0+(byte) 5) ← *((const byte*) main::ptr#0) + to:main::@return +main::@return: scope:[main] from main::@2 + [20] return + to:@return +setp: scope:[setp] from main::@1 + [21] *((const byte*) main::ptr#0) ← (const byte) setp::v#0 + to:setp::@return +setp::@return: scope:[setp] from setp + [22] return + to:@return +setv: scope:[setv] from main + [23] phi() + to:setv::@return +setv::@return: scope:[setv] from setv + [24] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte*) main::SCREEN1 +(byte*) main::SCREEN2 +(byte) main::idx +(byte*) main::ptr +(void()) setp((byte*) setp::p , (byte) setp::v) +(byte*) setp::p +(byte) setp::v +(void()) setv((byte) setv::v) +(byte) setv::v +(byte) val +(byte) val#1 4.0 + +Initial phi equivalence classes +Added variable val#1 to zero page equivalence class [ val#1 ] +Complete equivalence classes +[ val#1 ] +Allocated zp ZP_BYTE:2 [ val#1 ] + +INITIAL ASM +//SEG0 File Comments +// Test address-of by assigning the affected variable in multiple ways +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label val = 2 +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .label SCREEN1 = $400 + .label ptr = val + .label SCREEN2 = SCREEN1+$28 + //SEG10 [4] *((const byte*) main::SCREEN1#0) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta SCREEN1 + //SEG11 [5] *((const byte*) main::SCREEN2#0) ← (byte) '.' -- _deref_pbuc1=vbuc2 + lda #'.' + sta SCREEN2 + //SEG12 [6] (byte) val#1 ← (byte) 1 -- vbuz1=vbuc1 + // Here we have not yet used address-of - so val can be versioned freely + lda #1 + sta val + //SEG13 [7] *((const byte*) main::SCREEN1#0+(byte) 1) ← (byte) val#1 -- _deref_pbuc1=vbuz1 + lda val + sta SCREEN1+1 + //SEG14 [8] *((const byte*) main::SCREEN2#0+(byte) 1) ← (byte) '.' -- _deref_pbuc1=vbuc2 + lda #'.' + sta SCREEN2+1 + //SEG15 [9] *((const byte*) main::SCREEN1#0+(byte) 2) ← (byte) 2 -- _deref_pbuc1=vbuc2 + lda #2 + sta SCREEN1+2 + //SEG16 [10] *((const byte*) main::SCREEN2#0+(byte) 2) ← *((const byte*) main::ptr#0) -- _deref_pbuc1=_deref_pbuc2 + lda ptr + sta SCREEN2+2 + //SEG17 [11] *((const byte*) main::ptr#0) ← (byte) 3 -- _deref_pbuc1=vbuc2 + // Set value through pointer + lda #3 + sta ptr + //SEG18 [12] *((const byte*) main::SCREEN1#0+(byte) 3) ← (byte) 2 -- _deref_pbuc1=vbuc2 + lda #2 + sta SCREEN1+3 + //SEG19 [13] *((const byte*) main::SCREEN2#0+(byte) 3) ← *((const byte*) main::ptr#0) -- _deref_pbuc1=_deref_pbuc2 + lda ptr + sta SCREEN2+3 + //SEG20 [14] call setv + //SEG21 [23] phi from main to setv [phi:main->setv] + setv_from_main: + jsr setv + jmp b1 + //SEG22 main::@1 + b1: + //SEG23 [15] *((const byte*) main::SCREEN1#0+(byte) 4) ← (const byte) setv::v#0 -- _deref_pbuc1=vbuc2 + lda #setv.v + sta SCREEN1+4 + //SEG24 [16] *((const byte*) main::SCREEN2#0+(byte) 4) ← *((const byte*) main::ptr#0) -- _deref_pbuc1=_deref_pbuc2 + lda ptr + sta SCREEN2+4 + //SEG25 [17] call setp + jsr setp + jmp b2 + //SEG26 main::@2 + b2: + //SEG27 [18] *((const byte*) main::SCREEN1#0+(byte) 5) ← (const byte) setv::v#0 -- _deref_pbuc1=vbuc2 + lda #setv.v + sta SCREEN1+5 + //SEG28 [19] *((const byte*) main::SCREEN2#0+(byte) 5) ← *((const byte*) main::ptr#0) -- _deref_pbuc1=_deref_pbuc2 + lda ptr + sta SCREEN2+5 + jmp breturn + //SEG29 main::@return + breturn: + //SEG30 [20] return + rts +} +//SEG31 setp +setp: { + .const v = 5 + //SEG32 [21] *((const byte*) main::ptr#0) ← (const byte) setp::v#0 -- _deref_pbuc1=vbuc2 + lda #v + sta main.ptr + jmp breturn + //SEG33 setp::@return + breturn: + //SEG34 [22] return + rts +} +//SEG35 setv +setv: { + .label v = 4 + jmp breturn + //SEG36 setv::@return + breturn: + //SEG37 [24] return + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] *((const byte*) main::SCREEN1#0) ← (byte) 0 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [5] *((const byte*) main::SCREEN2#0) ← (byte) '.' [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [6] (byte) val#1 ← (byte) 1 [ val#1 ] ( main:2 [ val#1 ] ) always clobbers reg byte a +Statement [7] *((const byte*) main::SCREEN1#0+(byte) 1) ← (byte) val#1 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [8] *((const byte*) main::SCREEN2#0+(byte) 1) ← (byte) '.' [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [9] *((const byte*) main::SCREEN1#0+(byte) 2) ← (byte) 2 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [10] *((const byte*) main::SCREEN2#0+(byte) 2) ← *((const byte*) main::ptr#0) [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [11] *((const byte*) main::ptr#0) ← (byte) 3 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [12] *((const byte*) main::SCREEN1#0+(byte) 3) ← (byte) 2 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [13] *((const byte*) main::SCREEN2#0+(byte) 3) ← *((const byte*) main::ptr#0) [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [15] *((const byte*) main::SCREEN1#0+(byte) 4) ← (const byte) setv::v#0 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [16] *((const byte*) main::SCREEN2#0+(byte) 4) ← *((const byte*) main::ptr#0) [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [18] *((const byte*) main::SCREEN1#0+(byte) 5) ← (const byte) setv::v#0 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [19] *((const byte*) main::SCREEN2#0+(byte) 5) ← *((const byte*) main::ptr#0) [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [21] *((const byte*) main::ptr#0) ← (const byte) setp::v#0 [ ] ( main:2::setp:17 [ ] ) always clobbers reg byte a +Potential registers zp ZP_BYTE:2 [ val#1 ] : zp ZP_BYTE:2 , + +REGISTER UPLIFT SCOPES +Uplift Scope [] 4: zp ZP_BYTE:2 [ val#1 ] +Uplift Scope [main] +Uplift Scope [setv] +Uplift Scope [setp] + +Uplifting [] best 182 combination zp ZP_BYTE:2 [ val#1 ] +Uplifting [main] best 182 combination +Uplifting [setv] best 182 combination +Uplifting [setp] best 182 combination +Attempting to uplift remaining variables inzp ZP_BYTE:2 [ val#1 ] +Uplifting [] best 182 combination zp ZP_BYTE:2 [ val#1 ] + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Test address-of by assigning the affected variable in multiple ways +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label val = 2 +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .label SCREEN1 = $400 + .label ptr = val + .label SCREEN2 = SCREEN1+$28 + //SEG10 [4] *((const byte*) main::SCREEN1#0) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta SCREEN1 + //SEG11 [5] *((const byte*) main::SCREEN2#0) ← (byte) '.' -- _deref_pbuc1=vbuc2 + lda #'.' + sta SCREEN2 + //SEG12 [6] (byte) val#1 ← (byte) 1 -- vbuz1=vbuc1 + // Here we have not yet used address-of - so val can be versioned freely + lda #1 + sta val + //SEG13 [7] *((const byte*) main::SCREEN1#0+(byte) 1) ← (byte) val#1 -- _deref_pbuc1=vbuz1 + lda val + sta SCREEN1+1 + //SEG14 [8] *((const byte*) main::SCREEN2#0+(byte) 1) ← (byte) '.' -- _deref_pbuc1=vbuc2 + lda #'.' + sta SCREEN2+1 + //SEG15 [9] *((const byte*) main::SCREEN1#0+(byte) 2) ← (byte) 2 -- _deref_pbuc1=vbuc2 + lda #2 + sta SCREEN1+2 + //SEG16 [10] *((const byte*) main::SCREEN2#0+(byte) 2) ← *((const byte*) main::ptr#0) -- _deref_pbuc1=_deref_pbuc2 + lda ptr + sta SCREEN2+2 + //SEG17 [11] *((const byte*) main::ptr#0) ← (byte) 3 -- _deref_pbuc1=vbuc2 + // Set value through pointer + lda #3 + sta ptr + //SEG18 [12] *((const byte*) main::SCREEN1#0+(byte) 3) ← (byte) 2 -- _deref_pbuc1=vbuc2 + lda #2 + sta SCREEN1+3 + //SEG19 [13] *((const byte*) main::SCREEN2#0+(byte) 3) ← *((const byte*) main::ptr#0) -- _deref_pbuc1=_deref_pbuc2 + lda ptr + sta SCREEN2+3 + //SEG20 [14] call setv + //SEG21 [23] phi from main to setv [phi:main->setv] + setv_from_main: + jsr setv + jmp b1 + //SEG22 main::@1 + b1: + //SEG23 [15] *((const byte*) main::SCREEN1#0+(byte) 4) ← (const byte) setv::v#0 -- _deref_pbuc1=vbuc2 + lda #setv.v + sta SCREEN1+4 + //SEG24 [16] *((const byte*) main::SCREEN2#0+(byte) 4) ← *((const byte*) main::ptr#0) -- _deref_pbuc1=_deref_pbuc2 + lda ptr + sta SCREEN2+4 + //SEG25 [17] call setp + jsr setp + jmp b2 + //SEG26 main::@2 + b2: + //SEG27 [18] *((const byte*) main::SCREEN1#0+(byte) 5) ← (const byte) setv::v#0 -- _deref_pbuc1=vbuc2 + lda #setv.v + sta SCREEN1+5 + //SEG28 [19] *((const byte*) main::SCREEN2#0+(byte) 5) ← *((const byte*) main::ptr#0) -- _deref_pbuc1=_deref_pbuc2 + lda ptr + sta SCREEN2+5 + jmp breturn + //SEG29 main::@return + breturn: + //SEG30 [20] return + rts +} +//SEG31 setp +setp: { + .const v = 5 + //SEG32 [21] *((const byte*) main::ptr#0) ← (const byte) setp::v#0 -- _deref_pbuc1=vbuc2 + lda #v + sta main.ptr + jmp breturn + //SEG33 setp::@return + breturn: + //SEG34 [22] return + rts +} +//SEG35 setv +setv: { + .label v = 4 + jmp breturn + //SEG36 setv::@return + breturn: + //SEG37 [24] return + rts +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp b2 +Removing instruction jmp breturn +Removing instruction jmp breturn +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction lda val +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction bend_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction setv_from_main: +Removing instruction b1: +Removing instruction b2: +Removing instruction breturn: +Removing instruction breturn: +Removing instruction breturn: +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()) main() +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte*) main::SCREEN1 +(const byte*) main::SCREEN1#0 SCREEN1 = (byte*) 1024 +(byte*) main::SCREEN2 +(const byte*) main::SCREEN2#0 SCREEN2 = (const byte*) main::SCREEN1#0+(byte) $28 +(byte) main::idx +(byte*) main::ptr +(const byte*) main::ptr#0 ptr = &(byte) val#1 +(void()) setp((byte*) setp::p , (byte) setp::v) +(label) setp::@return +(byte*) setp::p +(byte) setp::v +(const byte) setp::v#0 v = (byte) 5 +(void()) setv((byte) setv::v) +(label) setv::@return +(byte) setv::v +(const byte) setv::v#0 v = (byte) 4 +(byte) val +(byte) val#1 val zp ZP_BYTE:2 4.0 + +zp ZP_BYTE:2 [ val#1 ] + + +FINAL ASSEMBLER +Score: 125 + +//SEG0 File Comments +// Test address-of by assigning the affected variable in multiple ways +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label val = 2 +//SEG3 @begin +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main +main: { + .label SCREEN1 = $400 + .label ptr = val + .label SCREEN2 = SCREEN1+$28 + //SEG10 [4] *((const byte*) main::SCREEN1#0) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta SCREEN1 + //SEG11 [5] *((const byte*) main::SCREEN2#0) ← (byte) '.' -- _deref_pbuc1=vbuc2 + lda #'.' + sta SCREEN2 + //SEG12 [6] (byte) val#1 ← (byte) 1 -- vbuz1=vbuc1 + // Here we have not yet used address-of - so val can be versioned freely + lda #1 + sta val + //SEG13 [7] *((const byte*) main::SCREEN1#0+(byte) 1) ← (byte) val#1 -- _deref_pbuc1=vbuz1 + sta SCREEN1+1 + //SEG14 [8] *((const byte*) main::SCREEN2#0+(byte) 1) ← (byte) '.' -- _deref_pbuc1=vbuc2 + lda #'.' + sta SCREEN2+1 + //SEG15 [9] *((const byte*) main::SCREEN1#0+(byte) 2) ← (byte) 2 -- _deref_pbuc1=vbuc2 + lda #2 + sta SCREEN1+2 + //SEG16 [10] *((const byte*) main::SCREEN2#0+(byte) 2) ← *((const byte*) main::ptr#0) -- _deref_pbuc1=_deref_pbuc2 + lda ptr + sta SCREEN2+2 + //SEG17 [11] *((const byte*) main::ptr#0) ← (byte) 3 -- _deref_pbuc1=vbuc2 + // Set value through pointer + lda #3 + sta ptr + //SEG18 [12] *((const byte*) main::SCREEN1#0+(byte) 3) ← (byte) 2 -- _deref_pbuc1=vbuc2 + lda #2 + sta SCREEN1+3 + //SEG19 [13] *((const byte*) main::SCREEN2#0+(byte) 3) ← *((const byte*) main::ptr#0) -- _deref_pbuc1=_deref_pbuc2 + lda ptr + sta SCREEN2+3 + //SEG20 [14] call setv + //SEG21 [23] phi from main to setv [phi:main->setv] + jsr setv + //SEG22 main::@1 + //SEG23 [15] *((const byte*) main::SCREEN1#0+(byte) 4) ← (const byte) setv::v#0 -- _deref_pbuc1=vbuc2 + lda #setv.v + sta SCREEN1+4 + //SEG24 [16] *((const byte*) main::SCREEN2#0+(byte) 4) ← *((const byte*) main::ptr#0) -- _deref_pbuc1=_deref_pbuc2 + lda ptr + sta SCREEN2+4 + //SEG25 [17] call setp + jsr setp + //SEG26 main::@2 + //SEG27 [18] *((const byte*) main::SCREEN1#0+(byte) 5) ← (const byte) setv::v#0 -- _deref_pbuc1=vbuc2 + lda #setv.v + sta SCREEN1+5 + //SEG28 [19] *((const byte*) main::SCREEN2#0+(byte) 5) ← *((const byte*) main::ptr#0) -- _deref_pbuc1=_deref_pbuc2 + lda ptr + sta SCREEN2+5 + //SEG29 main::@return + //SEG30 [20] return + rts +} +//SEG31 setp +setp: { + .const v = 5 + //SEG32 [21] *((const byte*) main::ptr#0) ← (const byte) setp::v#0 -- _deref_pbuc1=vbuc2 + lda #v + sta main.ptr + //SEG33 setp::@return + //SEG34 [22] return + rts +} +//SEG35 setv +setv: { + .label v = 4 + //SEG36 setv::@return + //SEG37 [24] return + rts +} + diff --git a/src/test/ref/address-of-2.sym b/src/test/ref/address-of-2.sym new file mode 100644 index 000000000..5bb29bff7 --- /dev/null +++ b/src/test/ref/address-of-2.sym @@ -0,0 +1,27 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte*) main::SCREEN1 +(const byte*) main::SCREEN1#0 SCREEN1 = (byte*) 1024 +(byte*) main::SCREEN2 +(const byte*) main::SCREEN2#0 SCREEN2 = (const byte*) main::SCREEN1#0+(byte) $28 +(byte) main::idx +(byte*) main::ptr +(const byte*) main::ptr#0 ptr = &(byte) val#1 +(void()) setp((byte*) setp::p , (byte) setp::v) +(label) setp::@return +(byte*) setp::p +(byte) setp::v +(const byte) setp::v#0 v = (byte) 5 +(void()) setv((byte) setv::v) +(label) setv::@return +(byte) setv::v +(const byte) setv::v#0 v = (byte) 4 +(byte) val +(byte) val#1 val zp ZP_BYTE:2 4.0 + +zp ZP_BYTE:2 [ val#1 ] diff --git a/src/test/ref/struct-ptr-12-ref.asm b/src/test/ref/struct-ptr-12-ref.asm new file mode 100644 index 000000000..a157cfcc8 --- /dev/null +++ b/src/test/ref/struct-ptr-12-ref.asm @@ -0,0 +1,18 @@ +// Reference file for Minimal struct - using address-of +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +main: { + .label q = p + .label SCREEN = $400 + .label p = 2 + lda #<2*$100+3 + sta p + lda #>2*$100+3 + sta p+1 + lda q + sta SCREEN + lda q+1 + sta SCREEN+1 + rts +} diff --git a/src/test/ref/struct-ptr-12-ref.cfg b/src/test/ref/struct-ptr-12-ref.cfg new file mode 100644 index 000000000..7e34ccdf4 --- /dev/null +++ b/src/test/ref/struct-ptr-12-ref.cfg @@ -0,0 +1,19 @@ +@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] (word) main::p#0 ← (byte) 2*(word) $100+(byte) 3 + [5] (byte~) main::$1 ← < *((const word*) main::q#0) + [6] *((const byte*) main::SCREEN#0) ← (byte~) main::$1 + [7] (byte~) main::$2 ← > *((const word*) main::q#0) + [8] *((const byte*) main::SCREEN#0+(byte) 1) ← (byte~) main::$2 + to:main::@return +main::@return: scope:[main] from main + [9] return + to:@return diff --git a/src/test/ref/struct-ptr-12-ref.log b/src/test/ref/struct-ptr-12-ref.log new file mode 100644 index 000000000..0bde36aef --- /dev/null +++ b/src/test/ref/struct-ptr-12-ref.log @@ -0,0 +1,331 @@ +Identified literal word (word) { 2, 3 } in (word) main::p ← { (number) 2, (number) 3 } +Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (word) main::p#0 ← ((word)) { (number) 2, (number) 3 } + (word*~) main::$0 ← & (word) main::p#0 + (word*) main::q#0 ← (word*~) main::$0 + (byte*) main::SCREEN#0 ← ((byte*)) (number) $400 + (byte~) main::$1 ← < *((word*) main::q#0) + *((byte*) main::SCREEN#0 + (number) 0) ← (byte~) main::$1 + (byte~) main::$2 ← > *((word*) main::q#0) + *((byte*) main::SCREEN#0 + (number) 1) ← (byte~) main::$2 + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + call main + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(void()) main() +(word*~) main::$0 +(byte~) main::$1 +(byte~) main::$2 +(label) main::@return +(byte*) main::SCREEN +(byte*) main::SCREEN#0 +(word) main::p +(word) main::p#0 +(word*) main::q +(word*) main::q#0 + +Fixing inline constructor with main::$3 ← (byte)2 w= (byte)3 +Successful SSA optimization Pass2FixInlineConstructorsNew +Adding number conversion cast (unumber) 0 in *((byte*) main::SCREEN#0 + (number) 0) ← (byte~) main::$1 +Adding number conversion cast (unumber) 1 in *((byte*) main::SCREEN#0 + (number) 1) ← (byte~) main::$2 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400 +Successful SSA optimization Pass2InlineCast +Simplifying constant integer cast 2 +Simplifying constant integer cast 3 +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast 0 +Simplifying constant integer cast 1 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 1 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias (word) main::p#0 = (word~) main::$3 +Alias (word*) main::q#0 = (word*~) main::$0 +Successful SSA optimization Pass2AliasElimination +Constant right-side identified [0] (word) main::p#0 ← (byte) 2 w= (byte) 3 +Constant right-side identified [2] (word*) main::q#0 ← & (word) main::p#0 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const word*) main::q#0 = &main::p#0 +Constant (const byte*) main::SCREEN#0 = (byte*) 1024 +Successful SSA optimization Pass2ConstantIdentification +Simplifying expression containing zero main::SCREEN#0 in [6] *((const byte*) main::SCREEN#0 + (byte) 0) ← (byte~) main::$1 +Successful SSA optimization PassNSimplifyExpressionWithZero +Adding number conversion cast (unumber) 2*$100+3 in (word) main::p#0 ← (byte) 2*(number) $100+(byte) 3 +Adding number conversion cast (unumber) 2*$100 in (word) main::p#0 ← ((unumber)) (byte) 2*(number) $100+(byte) 3 +Adding number conversion cast (unumber) $100 in (word) main::p#0 ← ((unumber)) (unumber)(byte) 2*(number) $100+(byte) 3 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (word) main::p#0 ← (unumber)(unumber)(byte) 2*(unumber)(number) $100+(byte) 3 +Successful SSA optimization Pass2InlineCast +Simplifying constant integer cast (unumber)(byte) 2*(unumber)(number) $100+(byte) 3 +Simplifying constant integer cast (byte) 2*(unumber)(number) $100 +Simplifying constant integer cast $100 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (word) $100 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Consolidated array index constant in *(main::SCREEN#0+1) +Successful SSA optimization Pass2ConstantAdditionElimination +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +CALL GRAPH +Calls in [] to main:2 + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Culled Empty Block (label) @2 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end + +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] (word) main::p#0 ← (byte) 2*(word) $100+(byte) 3 + [5] (byte~) main::$1 ← < *((const word*) main::q#0) + [6] *((const byte*) main::SCREEN#0) ← (byte~) main::$1 + [7] (byte~) main::$2 ← > *((const word*) main::q#0) + [8] *((const byte*) main::SCREEN#0+(byte) 1) ← (byte~) main::$2 + to:main::@return +main::@return: scope:[main] from main + [9] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte~) main::$1 4.0 +(byte~) main::$2 4.0 +(byte*) main::SCREEN +(word) main::p +(word) main::p#0 20.0 +(word*) main::q + +Initial phi equivalence classes +Added variable main::p#0 to zero page equivalence class [ main::p#0 ] +Added variable main::$1 to zero page equivalence class [ main::$1 ] +Added variable main::$2 to zero page equivalence class [ main::$2 ] +Complete equivalence classes +[ main::p#0 ] +[ main::$1 ] +[ main::$2 ] +Allocated zp ZP_WORD:2 [ main::p#0 ] +Allocated zp ZP_BYTE:4 [ main::$1 ] +Allocated zp ZP_BYTE:5 [ main::$2 ] + +INITIAL ASM +//SEG0 File Comments +// Reference file for Minimal struct - using address-of +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .label q = p + .label SCREEN = $400 + .label _1 = 4 + .label _2 = 5 + .label p = 2 + //SEG10 [4] (word) main::p#0 ← (byte) 2*(word) $100+(byte) 3 -- vwuz1=vwuc1 + lda #<2*$100+3 + sta p + lda #>2*$100+3 + sta p+1 + //SEG11 [5] (byte~) main::$1 ← < *((const word*) main::q#0) -- vbuz1=_lo__deref_pwuc1 + lda q + sta _1 + //SEG12 [6] *((const byte*) main::SCREEN#0) ← (byte~) main::$1 -- _deref_pbuc1=vbuz1 + lda _1 + sta SCREEN + //SEG13 [7] (byte~) main::$2 ← > *((const word*) main::q#0) -- vbuz1=_hi__deref_pwuc1 + lda q+1 + sta _2 + //SEG14 [8] *((const byte*) main::SCREEN#0+(byte) 1) ← (byte~) main::$2 -- _deref_pbuc1=vbuz1 + lda _2 + sta SCREEN+1 + jmp breturn + //SEG15 main::@return + breturn: + //SEG16 [9] return + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] (word) main::p#0 ← (byte) 2*(word) $100+(byte) 3 [ ] ( main:2 [ ] ) always clobbers reg byte a +Potential registers zp ZP_WORD:2 [ main::p#0 ] : zp ZP_WORD:2 , +Potential registers zp ZP_BYTE:4 [ main::$1 ] : zp ZP_BYTE:4 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:5 [ main::$2 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 20: zp ZP_WORD:2 [ main::p#0 ] 4: zp ZP_BYTE:4 [ main::$1 ] 4: zp ZP_BYTE:5 [ main::$2 ] +Uplift Scope [] + +Uplifting [main] best 47 combination zp ZP_WORD:2 [ main::p#0 ] reg byte a [ main::$1 ] reg byte a [ main::$2 ] +Uplifting [] best 47 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Reference file for Minimal struct - using address-of +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .label q = p + .label SCREEN = $400 + .label p = 2 + //SEG10 [4] (word) main::p#0 ← (byte) 2*(word) $100+(byte) 3 -- vwuz1=vwuc1 + lda #<2*$100+3 + sta p + lda #>2*$100+3 + sta p+1 + //SEG11 [5] (byte~) main::$1 ← < *((const word*) main::q#0) -- vbuaa=_lo__deref_pwuc1 + lda q + //SEG12 [6] *((const byte*) main::SCREEN#0) ← (byte~) main::$1 -- _deref_pbuc1=vbuaa + sta SCREEN + //SEG13 [7] (byte~) main::$2 ← > *((const word*) main::q#0) -- vbuaa=_hi__deref_pwuc1 + lda q+1 + //SEG14 [8] *((const byte*) main::SCREEN#0+(byte) 1) ← (byte~) main::$2 -- _deref_pbuc1=vbuaa + sta SCREEN+1 + jmp breturn + //SEG15 main::@return + breturn: + //SEG16 [9] return + rts +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction bend_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction breturn: +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()) main() +(byte~) main::$1 reg byte a 4.0 +(byte~) main::$2 reg byte a 4.0 +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 +(word) main::p +(word) main::p#0 p zp ZP_WORD:2 20.0 +(word*) main::q +(const word*) main::q#0 q = &(word) main::p#0 + +zp ZP_WORD:2 [ main::p#0 ] +reg byte a [ main::$1 ] +reg byte a [ main::$2 ] + + +FINAL ASSEMBLER +Score: 32 + +//SEG0 File Comments +// Reference file for Minimal struct - using address-of +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main +main: { + .label q = p + .label SCREEN = $400 + .label p = 2 + //SEG10 [4] (word) main::p#0 ← (byte) 2*(word) $100+(byte) 3 -- vwuz1=vwuc1 + lda #<2*$100+3 + sta p + lda #>2*$100+3 + sta p+1 + //SEG11 [5] (byte~) main::$1 ← < *((const word*) main::q#0) -- vbuaa=_lo__deref_pwuc1 + lda q + //SEG12 [6] *((const byte*) main::SCREEN#0) ← (byte~) main::$1 -- _deref_pbuc1=vbuaa + sta SCREEN + //SEG13 [7] (byte~) main::$2 ← > *((const word*) main::q#0) -- vbuaa=_hi__deref_pwuc1 + lda q+1 + //SEG14 [8] *((const byte*) main::SCREEN#0+(byte) 1) ← (byte~) main::$2 -- _deref_pbuc1=vbuaa + sta SCREEN+1 + //SEG15 main::@return + //SEG16 [9] return + rts +} + diff --git a/src/test/ref/struct-ptr-12-ref.sym b/src/test/ref/struct-ptr-12-ref.sym new file mode 100644 index 000000000..00b1677f0 --- /dev/null +++ b/src/test/ref/struct-ptr-12-ref.sym @@ -0,0 +1,17 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(byte~) main::$1 reg byte a 4.0 +(byte~) main::$2 reg byte a 4.0 +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 +(word) main::p +(word) main::p#0 p zp ZP_WORD:2 20.0 +(word*) main::q +(const word*) main::q#0 q = &(word) main::p#0 + +zp ZP_WORD:2 [ main::p#0 ] +reg byte a [ main::$1 ] +reg byte a [ main::$2 ]