From c8178378b277cd1a8d6da793148bc06824372d21 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Mon, 10 Jun 2019 21:24:33 +0200 Subject: [PATCH] Implemented struct array access rewriting code. Removed "old" struct asm instance code. --- .../pssc1_derefidx_vbuxx_mbr_0=vbuaa.asm | 2 - .../pssc1_derefidx_vbuxx_mbr_1=vbuaa.asm | 2 - .../pssc1_derefidx_vbuyy_mbr_0=vbuaa.asm | 2 - .../pssc1_derefidx_vbuyy_mbr_1=vbuaa.asm | 2 - .../fragment/vbuaa=_deref_pssc1_mbr_0.asm | 1 - .../fragment/vbuaa=_deref_pssc1_mbr_1.asm | 1 - .../vbuaa=pssc1_derefidx_vbuxx_mbr_0.asm | 1 - .../vbuaa=pssc1_derefidx_vbuxx_mbr_1.asm | 1 - .../vbuaa=pssc1_derefidx_vbuyy_mbr_0.asm | 1 - .../vbuaa=pssc1_derefidx_vbuyy_mbr_1.asm | 1 - src/main/fragment/vssz1=vssf2.asm | 3 - .../java/dk/camelot64/kickc/Compiler.java | 4 +- .../kickc/fragment/AsmFragmentInstance.java | 10 - .../AsmFragmentInstanceSpecFactory.java | 21 - .../passes/PassNStructPointerRewriting.java | 24 + .../dk/camelot64/kickc/test/TestPrograms.java | 12 +- src/test/kc/struct-ptr-7.kc | 21 + src/test/kc/struct-ptr-8.kc | 23 + src/test/ref/struct-ptr-0.asm | 5 +- src/test/ref/struct-ptr-0.cfg | 8 +- src/test/ref/struct-ptr-0.log | 146 ++-- src/test/ref/struct-ptr-0.sym | 5 +- src/test/ref/struct-ptr-7.asm | 27 + src/test/ref/struct-ptr-7.cfg | 22 + src/test/ref/struct-ptr-7.log | 524 ++++++++++++ src/test/ref/struct-ptr-7.sym | 14 + src/test/ref/struct-ptr-8.asm | 50 ++ src/test/ref/struct-ptr-8.cfg | 38 + src/test/ref/struct-ptr-8.log | 787 ++++++++++++++++++ src/test/ref/struct-ptr-8.sym | 39 + 30 files changed, 1683 insertions(+), 114 deletions(-) delete mode 100644 src/main/fragment/pssc1_derefidx_vbuxx_mbr_0=vbuaa.asm delete mode 100644 src/main/fragment/pssc1_derefidx_vbuxx_mbr_1=vbuaa.asm delete mode 100644 src/main/fragment/pssc1_derefidx_vbuyy_mbr_0=vbuaa.asm delete mode 100644 src/main/fragment/pssc1_derefidx_vbuyy_mbr_1=vbuaa.asm delete mode 100644 src/main/fragment/vbuaa=_deref_pssc1_mbr_0.asm delete mode 100644 src/main/fragment/vbuaa=_deref_pssc1_mbr_1.asm delete mode 100644 src/main/fragment/vbuaa=pssc1_derefidx_vbuxx_mbr_0.asm delete mode 100644 src/main/fragment/vbuaa=pssc1_derefidx_vbuxx_mbr_1.asm delete mode 100644 src/main/fragment/vbuaa=pssc1_derefidx_vbuyy_mbr_0.asm delete mode 100644 src/main/fragment/vbuaa=pssc1_derefidx_vbuyy_mbr_1.asm delete mode 100644 src/main/fragment/vssz1=vssf2.asm create mode 100644 src/test/kc/struct-ptr-7.kc create mode 100644 src/test/kc/struct-ptr-8.kc create mode 100644 src/test/ref/struct-ptr-7.asm create mode 100644 src/test/ref/struct-ptr-7.cfg create mode 100644 src/test/ref/struct-ptr-7.log create mode 100644 src/test/ref/struct-ptr-7.sym create mode 100644 src/test/ref/struct-ptr-8.asm create mode 100644 src/test/ref/struct-ptr-8.cfg create mode 100644 src/test/ref/struct-ptr-8.log create mode 100644 src/test/ref/struct-ptr-8.sym diff --git a/src/main/fragment/pssc1_derefidx_vbuxx_mbr_0=vbuaa.asm b/src/main/fragment/pssc1_derefidx_vbuxx_mbr_0=vbuaa.asm deleted file mode 100644 index 916e765e0..000000000 --- a/src/main/fragment/pssc1_derefidx_vbuxx_mbr_0=vbuaa.asm +++ /dev/null @@ -1,2 +0,0 @@ -sta {c1},x - diff --git a/src/main/fragment/pssc1_derefidx_vbuxx_mbr_1=vbuaa.asm b/src/main/fragment/pssc1_derefidx_vbuxx_mbr_1=vbuaa.asm deleted file mode 100644 index 778da5aff..000000000 --- a/src/main/fragment/pssc1_derefidx_vbuxx_mbr_1=vbuaa.asm +++ /dev/null @@ -1,2 +0,0 @@ -sta {c1}+1,x - diff --git a/src/main/fragment/pssc1_derefidx_vbuyy_mbr_0=vbuaa.asm b/src/main/fragment/pssc1_derefidx_vbuyy_mbr_0=vbuaa.asm deleted file mode 100644 index 64fd3eaf2..000000000 --- a/src/main/fragment/pssc1_derefidx_vbuyy_mbr_0=vbuaa.asm +++ /dev/null @@ -1,2 +0,0 @@ -sta {c1},y - diff --git a/src/main/fragment/pssc1_derefidx_vbuyy_mbr_1=vbuaa.asm b/src/main/fragment/pssc1_derefidx_vbuyy_mbr_1=vbuaa.asm deleted file mode 100644 index 91a797b27..000000000 --- a/src/main/fragment/pssc1_derefidx_vbuyy_mbr_1=vbuaa.asm +++ /dev/null @@ -1,2 +0,0 @@ -sta {c1}+1,y - diff --git a/src/main/fragment/vbuaa=_deref_pssc1_mbr_0.asm b/src/main/fragment/vbuaa=_deref_pssc1_mbr_0.asm deleted file mode 100644 index bee08251a..000000000 --- a/src/main/fragment/vbuaa=_deref_pssc1_mbr_0.asm +++ /dev/null @@ -1 +0,0 @@ -lda {c1} \ No newline at end of file diff --git a/src/main/fragment/vbuaa=_deref_pssc1_mbr_1.asm b/src/main/fragment/vbuaa=_deref_pssc1_mbr_1.asm deleted file mode 100644 index a836deba0..000000000 --- a/src/main/fragment/vbuaa=_deref_pssc1_mbr_1.asm +++ /dev/null @@ -1 +0,0 @@ -lda {c1}+1 \ No newline at end of file diff --git a/src/main/fragment/vbuaa=pssc1_derefidx_vbuxx_mbr_0.asm b/src/main/fragment/vbuaa=pssc1_derefidx_vbuxx_mbr_0.asm deleted file mode 100644 index 7454fa763..000000000 --- a/src/main/fragment/vbuaa=pssc1_derefidx_vbuxx_mbr_0.asm +++ /dev/null @@ -1 +0,0 @@ -lda {c1},x \ No newline at end of file diff --git a/src/main/fragment/vbuaa=pssc1_derefidx_vbuxx_mbr_1.asm b/src/main/fragment/vbuaa=pssc1_derefidx_vbuxx_mbr_1.asm deleted file mode 100644 index 66ef35236..000000000 --- a/src/main/fragment/vbuaa=pssc1_derefidx_vbuxx_mbr_1.asm +++ /dev/null @@ -1 +0,0 @@ -lda {c1}+1,x \ No newline at end of file diff --git a/src/main/fragment/vbuaa=pssc1_derefidx_vbuyy_mbr_0.asm b/src/main/fragment/vbuaa=pssc1_derefidx_vbuyy_mbr_0.asm deleted file mode 100644 index b2b867b05..000000000 --- a/src/main/fragment/vbuaa=pssc1_derefidx_vbuyy_mbr_0.asm +++ /dev/null @@ -1 +0,0 @@ -lda {c1},y \ No newline at end of file diff --git a/src/main/fragment/vbuaa=pssc1_derefidx_vbuyy_mbr_1.asm b/src/main/fragment/vbuaa=pssc1_derefidx_vbuyy_mbr_1.asm deleted file mode 100644 index 5c24499d4..000000000 --- a/src/main/fragment/vbuaa=pssc1_derefidx_vbuyy_mbr_1.asm +++ /dev/null @@ -1 +0,0 @@ -lda {c1}+1,y \ No newline at end of file diff --git a/src/main/fragment/vssz1=vssf2.asm b/src/main/fragment/vssz1=vssf2.asm deleted file mode 100644 index 5a5c14b91..000000000 --- a/src/main/fragment/vssz1=vssf2.asm +++ /dev/null @@ -1,3 +0,0 @@ -lda #0 -sta {z1} -sta {z1}+1 \ No newline at end of file diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index 77a4f0cec..6fd32791a 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -254,7 +254,6 @@ public class Compiler { private List getPass2Optimizations() { List optimizations = new ArrayList<>(); optimizations.add(new Pass2FixInlineConstructorsNew(program)); - optimizations.add(new PassNAddNumberTypeConversions(program)); optimizations.add(new PassNAddArrayNumberTypeConversions(program)); optimizations.add(new Pass2InlineCast(program)); @@ -262,7 +261,6 @@ public class Compiler { optimizations.add(new PassNFinalizeNumberTypeConversions(program)); optimizations.add(new PassNTypeInference(program)); optimizations.add(new PassNAddTypeConversionAssignment(program)); - optimizations.add(new PassNTypeIdSimplification(program)); optimizations.add(new PassNSizeOfSimplification(program)); optimizations.add(new PassNStatementIndices(program)); @@ -275,7 +273,7 @@ public class Compiler { optimizations.add(new Pass2ConditionalJumpSimplification(program)); optimizations.add(new Pass2ConditionalAndOrRewriting(program)); optimizations.add(new PassNAddBooleanCasts(program)); - + optimizations.add(new PassNStructPointerRewriting(program)); optimizations.add(new Pass2ConditionalJumpSequenceImprovement(program)); optimizations.add(new Pass2ConstantRValueConsolidation(program)); optimizations.add(new Pass2ConstantIdentification(program)); diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstance.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstance.java index 99a7fc713..02dbd837b 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstance.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstance.java @@ -95,16 +95,6 @@ public class AsmFragmentInstance { } else if(boundValue instanceof Label) { String param = ((Label) boundValue).getLocalName().replace('@', 'b').replace(':', '_').replace("$", "_"); return new AsmParameter(param, false); - } else if(boundValue instanceof StructMemberRef) { - StructMemberRef structMemberRef = (StructMemberRef) boundValue; - StructDefinition structDefinition = program.getScope().getStructDefinition(structMemberRef); - Variable structMember = structDefinition.getMember(structMemberRef.getMemberName()); - long memberByteOffset = structDefinition.getMemberByteOffset(structMember); - VariableRef struct = (VariableRef) structMemberRef.getStruct(); - Variable structVar = program.getScope().getVariable( struct); - Registers.RegisterZpStruct structRegister = (Registers.RegisterZpStruct) structVar.getAllocation(); - // TODO Use STRUCT_OFFSET constants instead of hardcoded constants - return new AsmParameter(AsmFormat.getAsmParamName(structVar, codeScopeRef)+"+"+memberByteOffset,true); } else { throw new RuntimeException("Bound Value Type not implemented " + boundValue); } diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecFactory.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecFactory.java index e3ba7c90c..8b66849a0 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecFactory.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecFactory.java @@ -303,27 +303,6 @@ public class AsmFragmentInstanceSpecFactory { String name = "la" + nextLabelIdx++; bind(name, value); return name; - } else if(value instanceof StructZero) { - return "vssf" + ((StructZero) value).getTypeStruct().getSizeBytes(); - } else if(value instanceof StructMemberRef) { - StructMemberRef structMemberRef = (StructMemberRef) value; - StructDefinition structDefinition = program.getScope().getStructDefinition(structMemberRef); - Variable structMember = structDefinition.getMember(structMemberRef.getMemberName()); - long memberByteOffset = structDefinition.getMemberByteOffset(structMember); - - RValue struct = structMemberRef.getStruct(); - if(struct instanceof VariableRef) { - Variable structVar = program.getScope().getVariable((VariableRef) struct); - if(structVar.getAllocation() instanceof Registers.RegisterZpStruct) { - Registers.RegisterZpStruct structRegister = (Registers.RegisterZpStruct) structVar.getAllocation(); - Registers.RegisterZpStructMember memberRegister = structRegister.getMemberRegister(memberByteOffset); - String name = getTypePrefix(structMember.getType()) + getRegisterName(memberRegister); - bind(name, structMemberRef); - return name; - } - } else { - return bind(struct) + "_mbr_" + memberByteOffset; - } } throw new RuntimeException("Binding of value type not supported " + value); } diff --git a/src/main/java/dk/camelot64/kickc/passes/PassNStructPointerRewriting.java b/src/main/java/dk/camelot64/kickc/passes/PassNStructPointerRewriting.java index 14b9af119..fc8f629ee 100644 --- a/src/main/java/dk/camelot64/kickc/passes/PassNStructPointerRewriting.java +++ b/src/main/java/dk/camelot64/kickc/passes/PassNStructPointerRewriting.java @@ -54,6 +54,30 @@ public class PassNStructPointerRewriting extends Pass2SsaOptimization { // Replace (*ptr_struct).x with *($1) programValue.set(new PointerDereferenceSimple(memberAddress.getRef())); modified.set(true); + } else if(struct instanceof PointerDereferenceIndexed) { + RValue structPointer = ((PointerDereferenceIndexed) struct).getPointer(); + // We have a match for ptr_struct[idx].x + SymbolType structType = SymbolTypeInference.inferType(getScope(), struct); + if(!(structType instanceof SymbolTypeStruct)) { + throw new CompileError("Accessing member of a non-struct ", currentStmt.getSource()); + } + StructDefinition structDefinition = ((SymbolTypeStruct) structType).getStructDefinition(getScope()); + ConstantRef memberOffsetConstant = getMemberOffsetConstant(getScope(), structDefinition, structMemberRef.getMemberName()); + SymbolType memberType = SymbolTypeInference.inferType(getScope(), structMemberRef); + getLog().append("Rewriting struct pointer member access " + programValue.get().toString(getProgram())); + // Cast struct pointer to the type of the member + CastValue structTypedPointer = new CastValue(new SymbolTypePointer(memberType), structPointer); + // Create temporary variable to hold pointer to member ($1) + Scope scope = getScope().getScope(currentBlock.getScope()); + VariableIntermediate memberAddress = scope.addVariableIntermediate(); + memberAddress.setType(new SymbolTypePointer(memberType)); + // Add statement $1 = ptr_struct + OFFSET_STRUCT_NAME_MEMBER + stmtIt.previous(); + stmtIt.add(new StatementAssignment(memberAddress.getRef(), structTypedPointer, Operators.PLUS, memberOffsetConstant, currentStmt.getSource(), currentStmt.getComments())); + stmtIt.next(); + // Replace ptr_struct[idx].x with ($1)[idx] + programValue.set(new PointerDereferenceIndexed(memberAddress.getRef(), ((PointerDereferenceIndexed) struct).getIndex())); + modified.set(true); } } }); diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index c1abbed52..75c3c3adc 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -35,6 +35,16 @@ public class TestPrograms { public TestPrograms() { } + @Test + public void testStructPtr8() throws IOException, URISyntaxException { + compileAndCompare("struct-ptr-8"); + } + + @Test + public void testStructPtr7() throws IOException, URISyntaxException { + compileAndCompare("struct-ptr-7"); + } + @Test public void testStructPtr6() throws IOException, URISyntaxException { compileAndCompare("struct-ptr-6"); @@ -67,7 +77,7 @@ public class TestPrograms { @Test public void testStructPtr0() throws IOException, URISyntaxException { - compileAndCompare("struct-ptr-0", log()); + compileAndCompare("struct-ptr-0"); } @Test diff --git a/src/test/kc/struct-ptr-7.kc b/src/test/kc/struct-ptr-7.kc new file mode 100644 index 000000000..679b7802c --- /dev/null +++ b/src/test/kc/struct-ptr-7.kc @@ -0,0 +1,21 @@ +// Minimal struct - direct (constant) array access + +struct Point { + byte x; + byte y; +}; + +struct Point[2] points; + +void main() { + points[0].x = 2; + points[0].y = 3; + points[1].x = 5; + points[1].y = 6; + + const byte* SCREEN = 0x0400; + SCREEN[0] = points[0].x; + SCREEN[1] = points[0].y; + SCREEN[3] = points[1].x; + SCREEN[4] = points[1].y; +} \ No newline at end of file diff --git a/src/test/kc/struct-ptr-8.kc b/src/test/kc/struct-ptr-8.kc new file mode 100644 index 000000000..6ef239fb7 --- /dev/null +++ b/src/test/kc/struct-ptr-8.kc @@ -0,0 +1,23 @@ +// Minimal struct - variable array access + +struct Point { + byte x; + byte y; +}; + +struct Point[2] points; + +void main() { + for( byte i: 0..1) { + points[i].x = 2+i; + points[i].y = 3+i; + } + + const byte* SCREEN = 0x0400; + byte idx = 0; + for( byte i: 0..1) { + SCREEN[idx++] = points[i].x; + SCREEN[idx++] = points[i].y; + SCREEN[idx++] = ' '; + } +} \ No newline at end of file diff --git a/src/test/ref/struct-ptr-0.asm b/src/test/ref/struct-ptr-0.asm index 998d77eb6..85f0500c1 100644 --- a/src/test/ref/struct-ptr-0.asm +++ b/src/test/ref/struct-ptr-0.asm @@ -2,6 +2,7 @@ .pc = $801 "Basic" :BasicUpstart(main) .pc = $80d "Program" + .const OFFSET_STRUCT_POINT_Y = 1 main: { .label SCREEN = $400 .label _5 = 2 @@ -18,7 +19,7 @@ main: { iny tya ldy _5 - sta points+1,y + sta points+OFFSET_STRUCT_POINT_Y,y inx cpx #5 bne b1 @@ -29,7 +30,7 @@ main: { tax lda points,x sta SCREEN,y - lda points+1,x + lda points+OFFSET_STRUCT_POINT_Y,x sta SCREEN+$28,y iny cpy #5 diff --git a/src/test/ref/struct-ptr-0.cfg b/src/test/ref/struct-ptr-0.cfg index 77cf1ccaf..65047b6d9 100644 --- a/src/test/ref/struct-ptr-0.cfg +++ b/src/test/ref/struct-ptr-0.cfg @@ -13,17 +13,17 @@ main: scope:[main] from @1 main::@1: scope:[main] from main main::@1 [5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 ) [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 - [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 + [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$5) ← (byte) main::i#2 [8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 - [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 + [9] *((byte*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$5) ← (byte~) main::$0 [10] (byte) main::i#1 ← ++ (byte) main::i#2 [11] if((byte) main::i#1!=(byte) 5) goto main::@1 to:main::@2 main::@2: scope:[main] from main::@1 main::@2 [12] (byte) main::i1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::i1#1 ) [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 - [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x - [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y + [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$7) + [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$7) [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 [17] if((byte) main::i1#1!=(byte) 5) goto main::@2 to:main::@return diff --git a/src/test/ref/struct-ptr-0.log b/src/test/ref/struct-ptr-0.log index 5d7f09b74..df09fa81e 100644 --- a/src/test/ref/struct-ptr-0.log +++ b/src/test/ref/struct-ptr-0.log @@ -2,6 +2,10 @@ Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i) Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i) Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i1) Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i1) +Rewriting struct pointer member access *((struct Point[4]) points + (byte~) main::$4).x +Rewriting struct pointer member access *((struct Point[4]) points + (byte~) main::$5).y +Rewriting struct pointer member access *((struct Point[4]) points + (byte~) main::$6).x +Rewriting struct pointer member access *((struct Point[4]) points + (byte~) main::$7).y Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400 Culled Empty Block (label) main::@4 @@ -15,10 +19,12 @@ main: scope:[main] from @1 main::@1: scope:[main] from main main::@1 (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 ) (byte~) main::$4 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT - *((struct Point[4]) points#0 + (byte~) main::$4).x ← (byte) main::i#2 + (byte*) main::$8 ← (byte*)(struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_X + *((byte*) main::$8 + (byte~) main::$4) ← (byte) main::i#2 (number~) main::$0 ← (byte) main::i#2 + (number) 1 (byte~) main::$5 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT - *((struct Point[4]) points#0 + (byte~) main::$5).y ← (number~) main::$0 + (byte*) main::$9 ← (byte*)(struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y + *((byte*) main::$9 + (byte~) main::$5) ← (number~) main::$0 (byte) main::i#1 ← (byte) main::i#2 + rangenext(0,4) (bool~) main::$1 ← (byte) main::i#1 != rangelast(0,4) if((bool~) main::$1) goto main::@1 @@ -30,10 +36,12 @@ main::@2: scope:[main] from main::@1 main::@3: scope:[main] from main::@2 main::@3 (byte) main::i1#2 ← phi( main::@2/(byte) main::i1#0 main::@3/(byte) main::i1#1 ) (byte~) main::$6 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT - *((byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((struct Point[4]) points#0 + (byte~) main::$6).x + (byte*) main::$10 ← (byte*)(struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_X + *((byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*) main::$10 + (byte~) main::$6) (byte*~) main::$2 ← (byte*) main::SCREEN#0 + (number) $28 (byte~) main::$7 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT - *((byte*~) main::$2 + (byte) main::i1#2) ← *((struct Point[4]) points#0 + (byte~) main::$7).y + (byte*) main::$11 ← (byte*)(struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y + *((byte*~) main::$2 + (byte) main::i1#2) ← *((byte*) main::$11 + (byte~) main::$7) (byte) main::i1#1 ← (byte) main::i1#2 + rangenext(0,4) (bool~) main::$3 ← (byte) main::i1#1 != rangelast(0,4) if((bool~) main::$3) goto main::@3 @@ -53,18 +61,24 @@ SYMBOL TABLE SSA (label) @2 (label) @begin (label) @end +(const byte) OFFSET_STRUCT_POINT_X = (byte) 0 +(const byte) OFFSET_STRUCT_POINT_Y = (byte) 1 (byte) Point::x (byte) Point::y (const byte) SIZEOF_STRUCT_POINT = (byte) 2 (void()) main() (number~) main::$0 (bool~) main::$1 +(byte*) main::$10 +(byte*) main::$11 (byte*~) main::$2 (bool~) main::$3 (byte~) main::$4 (byte~) main::$5 (byte~) main::$6 (byte~) main::$7 +(byte*) main::$8 +(byte*) main::$9 (label) main::@1 (label) main::@2 (label) main::@3 @@ -96,11 +110,11 @@ Finalized unsigned number type (byte) 1 Finalized unsigned number type (byte) $28 Successful SSA optimization PassNFinalizeNumberTypeConversions Inferred type updated to byte in (unumber~) main::$0 ← (byte) main::i#2 + (byte) 1 -Identified duplicate assignment right side [6] (byte~) main::$5 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT -Identified duplicate assignment right side [17] (byte~) main::$7 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT +Identified duplicate assignment right side [7] (byte~) main::$5 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT +Identified duplicate assignment right side [20] (byte~) main::$7 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT Successful SSA optimization Pass2DuplicateRValueIdentification -Simple Condition (bool~) main::$1 [10] if((byte) main::i#1!=rangelast(0,4)) goto main::@1 -Simple Condition (bool~) main::$3 [21] if((byte) main::i1#1!=rangelast(0,4)) goto main::@3 +Simple Condition (bool~) main::$1 [12] if((byte) main::i#1!=rangelast(0,4)) goto main::@1 +Simple Condition (bool~) main::$3 [25] if((byte) main::i1#1!=rangelast(0,4)) goto main::@3 Successful SSA optimization Pass2ConditionalJumpSimplification Constant right-side identified [0] (struct Point[4]) points#0 ← { fill( 4, 0) } Successful SSA optimization Pass2ConstantRValueConsolidation @@ -109,10 +123,20 @@ Constant (const byte) main::i#0 = 0 Constant (const byte*) main::SCREEN#0 = (byte*) 1024 Constant (const byte) main::i1#0 = 0 Successful SSA optimization Pass2ConstantIdentification -Resolved ranged next value [8] main::i#1 ← ++ main::i#2 to ++ -Resolved ranged comparison value [10] if(main::i#1!=rangelast(0,4)) goto main::@1 to (number) 5 -Resolved ranged next value [19] main::i1#1 ← ++ main::i1#2 to ++ -Resolved ranged comparison value [21] if(main::i1#1!=rangelast(0,4)) goto main::@3 to (number) 5 +Constant value identified (byte*)points#0 in [4] (byte*) main::$8 ← (byte*)(const struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_X +Constant value identified (byte*)points#0 in [8] (byte*) main::$9 ← (byte*)(const struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y +Constant value identified (byte*)points#0 in [17] (byte*) main::$10 ← (byte*)(const struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_X +Constant value identified (byte*)points#0 in [21] (byte*) main::$11 ← (byte*)(const struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y +Successful SSA optimization Pass2ConstantValues +Resolved ranged next value [10] main::i#1 ← ++ main::i#2 to ++ +Resolved ranged comparison value [12] if(main::i#1!=rangelast(0,4)) goto main::@1 to (number) 5 +Resolved ranged next value [23] main::i1#1 ← ++ main::i1#2 to ++ +Resolved ranged comparison value [25] if(main::i1#1!=rangelast(0,4)) goto main::@3 to (number) 5 +Simplifying expression containing zero (byte*)points#0 in [4] (byte*) main::$8 ← (byte*)(const struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_X +Simplifying expression containing zero (byte*)points#0 in [17] (byte*) main::$10 ← (byte*)(const struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_X +Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused constant (const byte) OFFSET_STRUCT_POINT_X +Successful SSA optimization PassNEliminateUnusedVars Adding number conversion cast (unumber) 5 in if((byte) main::i#1!=(number) 5) goto main::@1 Adding number conversion cast (unumber) 5 in if((byte) main::i1#1!=(number) 5) goto main::@3 Successful SSA optimization PassNAddNumberTypeConversions @@ -125,18 +149,28 @@ Successful SSA optimization PassNFinalizeNumberTypeConversions Alias (byte~) main::$5 = (byte~) main::$4 Alias (byte~) main::$7 = (byte~) main::$6 Successful SSA optimization Pass2AliasElimination -Constant right-side identified [11] (byte*~) main::$2 ← (const byte*) main::SCREEN#0 + (byte) $28 +Constant right-side identified [6] (byte*) main::$9 ← (byte*)(const struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y +Constant right-side identified [14] (byte*~) main::$2 ← (const byte*) main::SCREEN#0 + (byte) $28 +Constant right-side identified [16] (byte*) main::$11 ← (byte*)(const struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte*) main::$8 = (byte*)points#0 +Constant (const byte*) main::$9 = (byte*)points#0+OFFSET_STRUCT_POINT_Y +Constant (const byte*) main::$10 = (byte*)points#0 Constant (const byte*) main::$2 = main::SCREEN#0+$28 +Constant (const byte*) main::$11 = (byte*)points#0+OFFSET_STRUCT_POINT_Y Successful SSA optimization Pass2ConstantIdentification Rewriting multiplication to use shift [1] (byte~) main::$5 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT Rewriting multiplication to use shift [8] (byte~) main::$7 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT Successful SSA optimization Pass2MultiplyToShiftRewriting Inlining constant with var siblings (const byte) main::i#0 Inlining constant with var siblings (const byte) main::i1#0 +Constant inlined main::$2 = (const byte*) main::SCREEN#0+(byte) $28 Constant inlined main::i#0 = (byte) 0 Constant inlined main::i1#0 = (byte) 0 -Constant inlined main::$2 = (const byte*) main::SCREEN#0+(byte) $28 +Constant inlined main::$9 = (byte*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y +Constant inlined main::$10 = (byte*)(const struct Point[4]) points#0 +Constant inlined main::$8 = (byte*)(const struct Point[4]) points#0 +Constant inlined main::$11 = (byte*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y Successful SSA optimization Pass2ConstantInlining Eliminating unused constant (const byte) SIZEOF_STRUCT_POINT Successful SSA optimization PassNEliminateUnusedVars @@ -181,17 +215,17 @@ main: scope:[main] from @1 main::@1: scope:[main] from main main::@1 [5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 ) [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 - [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 + [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$5) ← (byte) main::i#2 [8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 - [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 + [9] *((byte*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$5) ← (byte~) main::$0 [10] (byte) main::i#1 ← ++ (byte) main::i#2 [11] if((byte) main::i#1!=(byte) 5) goto main::@1 to:main::@2 main::@2: scope:[main] from main::@1 main::@2 [12] (byte) main::i1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::i1#1 ) [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 - [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x - [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y + [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$7) + [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$7) [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 [17] if((byte) main::i1#1!=(byte) 5) goto main::@2 to:main::@return @@ -205,8 +239,8 @@ VARIABLE REGISTER WEIGHTS (byte) Point::y (void()) main() (byte~) main::$0 22.0 -(byte~) main::$5 3.6666666666666665 -(byte~) main::$7 5.5 +(byte~) main::$5 11.0 +(byte~) main::$7 16.5 (byte*) main::SCREEN (byte) main::i (byte) main::i#1 16.5 @@ -242,6 +276,7 @@ INITIAL ASM :BasicUpstart(bbegin) .pc = $80d "Program" //SEG2 Global Constants & labels + .const OFFSET_STRUCT_POINT_Y = 1 //SEG3 @begin bbegin: //SEG4 [1] phi from @begin to @1 [phi:@begin->@1] @@ -282,7 +317,7 @@ main: { lda i asl sta _5 - //SEG17 [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 -- pssc1_derefidx_vbuz1_mbr_0=vbuz2 + //SEG17 [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$5) ← (byte) main::i#2 -- pbuc1_derefidx_vbuz1=vbuz2 lda i ldy _5 sta points,y @@ -290,10 +325,10 @@ main: { ldy i iny sty _0 - //SEG19 [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 -- pssc1_derefidx_vbuz1_mbr_1=vbuz2 + //SEG19 [9] *((byte*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$5) ← (byte~) main::$0 -- pbuc1_derefidx_vbuz1=vbuz2 lda _0 ldy _5 - sta points+1,y + sta points+OFFSET_STRUCT_POINT_Y,y //SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 inc i //SEG21 [11] if((byte) main::i#1!=(byte) 5) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 @@ -316,16 +351,16 @@ main: { lda i1 asl sta _7 - //SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x -- pbuc1_derefidx_vbuz1=pssc2_derefidx_vbuz2_mbr_0 - ldx _7 - lda points,x - ldx i1 - sta SCREEN,x - //SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y -- pbuc1_derefidx_vbuz1=pssc2_derefidx_vbuz2_mbr_1 - ldx _7 - lda points+1,x - ldx i1 - sta SCREEN+$28,x + //SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$7) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz2 + ldy _7 + lda points,y + ldy i1 + sta SCREEN,y + //SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$7) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz2 + ldy _7 + lda points+OFFSET_STRUCT_POINT_Y,y + ldy i1 + sta SCREEN+$28,y //SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuz1=_inc_vbuz1 inc i1 //SEG31 [17] if((byte) main::i1#1!=(byte) 5) goto main::@2 -- vbuz1_neq_vbuc1_then_la1 @@ -343,18 +378,18 @@ main: { REGISTER UPLIFT POTENTIAL REGISTERS Statement [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ] -Statement [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a +Statement [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$5) ← (byte) main::i#2 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::$5 ] Statement [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] -Statement [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a +Statement [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$7) [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp ZP_BYTE:6 [ main::$7 ] -Statement [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y [ main::i1#2 ] ( main:2 [ main::i1#2 ] ) always clobbers reg byte a +Statement [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$7) [ main::i1#2 ] ( main:2 [ main::i1#2 ] ) always clobbers reg byte a Statement [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a -Statement [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a +Statement [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$5) ← (byte) main::i#2 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a Statement [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a -Statement [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a -Statement [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y [ main::i1#2 ] ( main:2 [ main::i1#2 ] ) always clobbers reg byte a +Statement [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$7) [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a +Statement [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$7) [ main::i1#2 ] ( main:2 [ main::i1#2 ] ) always clobbers reg byte a Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y , Potential registers zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] : zp ZP_BYTE:3 , reg byte x , reg byte y , Potential registers zp ZP_BYTE:4 [ main::$5 ] : zp ZP_BYTE:4 , reg byte x , reg byte y , @@ -362,7 +397,7 @@ Potential registers zp ZP_BYTE:5 [ main::$0 ] : zp ZP_BYTE:5 , reg byte a , reg Potential registers zp ZP_BYTE:6 [ main::$7 ] : zp ZP_BYTE:6 , reg byte x , reg byte y , REGISTER UPLIFT SCOPES -Uplift Scope [main] 30.25: zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] 27.5: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:5 [ main::$0 ] 5.5: zp ZP_BYTE:6 [ main::$7 ] 3.67: zp ZP_BYTE:4 [ main::$5 ] +Uplift Scope [main] 30.25: zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] 27.5: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:5 [ main::$0 ] 16.5: zp ZP_BYTE:6 [ main::$7 ] 11: zp ZP_BYTE:4 [ main::$5 ] Uplift Scope [Point] Uplift Scope [] @@ -382,6 +417,7 @@ ASSEMBLER BEFORE OPTIMIZATION :BasicUpstart(bbegin) .pc = $80d "Program" //SEG2 Global Constants & labels + .const OFFSET_STRUCT_POINT_Y = 1 //SEG3 @begin bbegin: //SEG4 [1] phi from @begin to @1 [phi:@begin->@1] @@ -417,7 +453,7 @@ main: { txa asl sta _5 - //SEG17 [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 -- pssc1_derefidx_vbuz1_mbr_0=vbuxx + //SEG17 [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$5) ← (byte) main::i#2 -- pbuc1_derefidx_vbuz1=vbuxx ldy _5 txa sta points,y @@ -425,10 +461,10 @@ main: { txa tay iny - //SEG19 [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 -- pssc1_derefidx_vbuz1_mbr_1=vbuyy + //SEG19 [9] *((byte*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$5) ← (byte~) main::$0 -- pbuc1_derefidx_vbuz1=vbuyy tya ldy _5 - sta points+1,y + sta points+OFFSET_STRUCT_POINT_Y,y //SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx inx //SEG21 [11] if((byte) main::i#1!=(byte) 5) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 @@ -449,11 +485,11 @@ main: { tya asl tax - //SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x -- pbuc1_derefidx_vbuyy=pssc2_derefidx_vbuxx_mbr_0 + //SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$7) -- pbuc1_derefidx_vbuyy=pbuc2_derefidx_vbuxx lda points,x sta SCREEN,y - //SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y -- pbuc1_derefidx_vbuyy=pssc2_derefidx_vbuxx_mbr_1 - lda points+1,x + //SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$7) -- pbuc1_derefidx_vbuyy=pbuc2_derefidx_vbuxx + lda points+OFFSET_STRUCT_POINT_Y,x sta SCREEN+$28,y //SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuyy=_inc_vbuyy iny @@ -503,12 +539,13 @@ FINAL SYMBOL TABLE (label) @1 (label) @begin (label) @end +(const byte) OFFSET_STRUCT_POINT_Y OFFSET_STRUCT_POINT_Y = (byte) 1 (byte) Point::x (byte) Point::y (void()) main() (byte~) main::$0 reg byte y 22.0 -(byte~) main::$5 $5 zp ZP_BYTE:2 3.6666666666666665 -(byte~) main::$7 reg byte x 5.5 +(byte~) main::$5 $5 zp ZP_BYTE:2 11.0 +(byte~) main::$7 reg byte x 16.5 (label) main::@1 (label) main::@2 (label) main::@return @@ -540,6 +577,7 @@ Score: 746 :BasicUpstart(main) .pc = $80d "Program" //SEG2 Global Constants & labels + .const OFFSET_STRUCT_POINT_Y = 1 //SEG3 @begin //SEG4 [1] phi from @begin to @1 [phi:@begin->@1] //SEG5 @1 @@ -562,7 +600,7 @@ main: { txa asl sta _5 - //SEG17 [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 -- pssc1_derefidx_vbuz1_mbr_0=vbuxx + //SEG17 [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$5) ← (byte) main::i#2 -- pbuc1_derefidx_vbuz1=vbuxx tay txa sta points,y @@ -570,10 +608,10 @@ main: { txa tay iny - //SEG19 [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 -- pssc1_derefidx_vbuz1_mbr_1=vbuyy + //SEG19 [9] *((byte*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$5) ← (byte~) main::$0 -- pbuc1_derefidx_vbuz1=vbuyy tya ldy _5 - sta points+1,y + sta points+OFFSET_STRUCT_POINT_Y,y //SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx inx //SEG21 [11] if((byte) main::i#1!=(byte) 5) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 @@ -590,11 +628,11 @@ main: { tya asl tax - //SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x -- pbuc1_derefidx_vbuyy=pssc2_derefidx_vbuxx_mbr_0 + //SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$7) -- pbuc1_derefidx_vbuyy=pbuc2_derefidx_vbuxx lda points,x sta SCREEN,y - //SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y -- pbuc1_derefidx_vbuyy=pssc2_derefidx_vbuxx_mbr_1 - lda points+1,x + //SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$7) -- pbuc1_derefidx_vbuyy=pbuc2_derefidx_vbuxx + lda points+OFFSET_STRUCT_POINT_Y,x sta SCREEN+$28,y //SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuyy=_inc_vbuyy iny diff --git a/src/test/ref/struct-ptr-0.sym b/src/test/ref/struct-ptr-0.sym index b96d36f23..07a0af07c 100644 --- a/src/test/ref/struct-ptr-0.sym +++ b/src/test/ref/struct-ptr-0.sym @@ -1,12 +1,13 @@ (label) @1 (label) @begin (label) @end +(const byte) OFFSET_STRUCT_POINT_Y OFFSET_STRUCT_POINT_Y = (byte) 1 (byte) Point::x (byte) Point::y (void()) main() (byte~) main::$0 reg byte y 22.0 -(byte~) main::$5 $5 zp ZP_BYTE:2 3.6666666666666665 -(byte~) main::$7 reg byte x 5.5 +(byte~) main::$5 $5 zp ZP_BYTE:2 11.0 +(byte~) main::$7 reg byte x 16.5 (label) main::@1 (label) main::@2 (label) main::@return diff --git a/src/test/ref/struct-ptr-7.asm b/src/test/ref/struct-ptr-7.asm new file mode 100644 index 000000000..ded40c789 --- /dev/null +++ b/src/test/ref/struct-ptr-7.asm @@ -0,0 +1,27 @@ +// Minimal struct - direct (constant) array access +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .const SIZEOF_STRUCT_POINT = 2 + .const OFFSET_STRUCT_POINT_Y = 1 +main: { + .label SCREEN = $400 + lda #2 + sta points + lda #3 + sta points+OFFSET_STRUCT_POINT_Y + lda #5 + sta points+1*SIZEOF_STRUCT_POINT + lda #6 + sta points+OFFSET_STRUCT_POINT_Y+1*SIZEOF_STRUCT_POINT + lda points + sta SCREEN + lda points+OFFSET_STRUCT_POINT_Y + sta SCREEN+1 + lda points+1*SIZEOF_STRUCT_POINT + sta SCREEN+3 + lda points+OFFSET_STRUCT_POINT_Y+1*SIZEOF_STRUCT_POINT + sta SCREEN+4 + rts +} + points: .fill 2*2, 0 diff --git a/src/test/ref/struct-ptr-7.cfg b/src/test/ref/struct-ptr-7.cfg new file mode 100644 index 000000000..2f62cb793 --- /dev/null +++ b/src/test/ref/struct-ptr-7.cfg @@ -0,0 +1,22 @@ +@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] *((byte*)(const struct Point[2]) points#0) ← (byte) 2 + [5] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) ← (byte) 3 + [6] *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 5 + [7] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 6 + [8] *((const byte*) main::SCREEN#0) ← *((byte*)(const struct Point[2]) points#0) + [9] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) + [10] *((const byte*) main::SCREEN#0+(byte) 3) ← *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) + [11] *((const byte*) main::SCREEN#0+(byte) 4) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) + to:main::@return +main::@return: scope:[main] from main + [12] return + to:@return diff --git a/src/test/ref/struct-ptr-7.log b/src/test/ref/struct-ptr-7.log new file mode 100644 index 000000000..9db434d51 --- /dev/null +++ b/src/test/ref/struct-ptr-7.log @@ -0,0 +1,524 @@ +Fixing pointer array-indexing *((struct Point[2]) points + (number) 0) +Fixing pointer array-indexing *((struct Point[2]) points + (number) 0) +Fixing pointer array-indexing *((struct Point[2]) points + (number) 1) +Fixing pointer array-indexing *((struct Point[2]) points + (number) 1) +Fixing pointer array-indexing *((struct Point[2]) points + (number) 0) +Fixing pointer array-indexing *((struct Point[2]) points + (number) 0) +Fixing pointer array-indexing *((struct Point[2]) points + (number) 1) +Fixing pointer array-indexing *((struct Point[2]) points + (number) 1) +Rewriting struct pointer member access *((struct Point[2]) points + (number~) main::$0).x +Rewriting struct pointer member access *((struct Point[2]) points + (number~) main::$1).y +Rewriting struct pointer member access *((struct Point[2]) points + (number~) main::$2).x +Rewriting struct pointer member access *((struct Point[2]) points + (number~) main::$3).y +Rewriting struct pointer member access *((struct Point[2]) points + (number~) main::$4).x +Rewriting struct pointer member access *((struct Point[2]) points + (number~) main::$5).y +Rewriting struct pointer member access *((struct Point[2]) points + (number~) main::$6).x +Rewriting struct pointer member access *((struct Point[2]) points + (number~) main::$7).y +Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (struct Point[2]) points#0 ← { fill( 2, 0) } + to:@1 +main: scope:[main] from @1 + (number~) main::$0 ← (number) 0 * (const byte) SIZEOF_STRUCT_POINT + (byte*) main::$8 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X + *((byte*) main::$8 + (number~) main::$0) ← (number) 2 + (number~) main::$1 ← (number) 0 * (const byte) SIZEOF_STRUCT_POINT + (byte*) main::$9 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y + *((byte*) main::$9 + (number~) main::$1) ← (number) 3 + (number~) main::$2 ← (number) 1 * (const byte) SIZEOF_STRUCT_POINT + (byte*) main::$10 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X + *((byte*) main::$10 + (number~) main::$2) ← (number) 5 + (number~) main::$3 ← (number) 1 * (const byte) SIZEOF_STRUCT_POINT + (byte*) main::$11 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y + *((byte*) main::$11 + (number~) main::$3) ← (number) 6 + (byte*) main::SCREEN#0 ← ((byte*)) (number) $400 + (number~) main::$4 ← (number) 0 * (const byte) SIZEOF_STRUCT_POINT + (byte*) main::$12 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X + *((byte*) main::SCREEN#0 + (number) 0) ← *((byte*) main::$12 + (number~) main::$4) + (number~) main::$5 ← (number) 0 * (const byte) SIZEOF_STRUCT_POINT + (byte*) main::$13 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y + *((byte*) main::SCREEN#0 + (number) 1) ← *((byte*) main::$13 + (number~) main::$5) + (number~) main::$6 ← (number) 1 * (const byte) SIZEOF_STRUCT_POINT + (byte*) main::$14 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X + *((byte*) main::SCREEN#0 + (number) 3) ← *((byte*) main::$14 + (number~) main::$6) + (number~) main::$7 ← (number) 1 * (const byte) SIZEOF_STRUCT_POINT + (byte*) main::$15 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y + *((byte*) main::SCREEN#0 + (number) 4) ← *((byte*) main::$15 + (number~) main::$7) + 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 +(const byte) OFFSET_STRUCT_POINT_X = (byte) 0 +(const byte) OFFSET_STRUCT_POINT_Y = (byte) 1 +(byte) Point::x +(byte) Point::y +(const byte) SIZEOF_STRUCT_POINT = (byte) 2 +(void()) main() +(number~) main::$0 +(number~) main::$1 +(byte*) main::$10 +(byte*) main::$11 +(byte*) main::$12 +(byte*) main::$13 +(byte*) main::$14 +(byte*) main::$15 +(number~) main::$2 +(number~) main::$3 +(number~) main::$4 +(number~) main::$5 +(number~) main::$6 +(number~) main::$7 +(byte*) main::$8 +(byte*) main::$9 +(label) main::@return +(byte*) main::SCREEN +(byte*) main::SCREEN#0 +(struct Point[2]) points +(struct Point[2]) points#0 + +Adding number conversion cast (unumber) 0 in (number~) main::$0 ← (number) 0 * (const byte) SIZEOF_STRUCT_POINT +Adding number conversion cast (unumber) main::$0 in (number~) main::$0 ← (unumber)(number) 0 * (const byte) SIZEOF_STRUCT_POINT +Adding number conversion cast (unumber) 2 in *((byte*) main::$8 + (unumber~) main::$0) ← (number) 2 +Adding number conversion cast (unumber) 0 in (number~) main::$1 ← (number) 0 * (const byte) SIZEOF_STRUCT_POINT +Adding number conversion cast (unumber) main::$1 in (number~) main::$1 ← (unumber)(number) 0 * (const byte) SIZEOF_STRUCT_POINT +Adding number conversion cast (unumber) 3 in *((byte*) main::$9 + (unumber~) main::$1) ← (number) 3 +Adding number conversion cast (unumber) 1 in (number~) main::$2 ← (number) 1 * (const byte) SIZEOF_STRUCT_POINT +Adding number conversion cast (unumber) main::$2 in (number~) main::$2 ← (unumber)(number) 1 * (const byte) SIZEOF_STRUCT_POINT +Adding number conversion cast (unumber) 5 in *((byte*) main::$10 + (unumber~) main::$2) ← (number) 5 +Adding number conversion cast (unumber) 1 in (number~) main::$3 ← (number) 1 * (const byte) SIZEOF_STRUCT_POINT +Adding number conversion cast (unumber) main::$3 in (number~) main::$3 ← (unumber)(number) 1 * (const byte) SIZEOF_STRUCT_POINT +Adding number conversion cast (unumber) 6 in *((byte*) main::$11 + (unumber~) main::$3) ← (number) 6 +Adding number conversion cast (unumber) 0 in (number~) main::$4 ← (number) 0 * (const byte) SIZEOF_STRUCT_POINT +Adding number conversion cast (unumber) main::$4 in (number~) main::$4 ← (unumber)(number) 0 * (const byte) SIZEOF_STRUCT_POINT +Adding number conversion cast (unumber) 0 in *((byte*) main::SCREEN#0 + (number) 0) ← *((byte*) main::$12 + (unumber~) main::$4) +Adding number conversion cast (unumber) 0 in (number~) main::$5 ← (number) 0 * (const byte) SIZEOF_STRUCT_POINT +Adding number conversion cast (unumber) main::$5 in (number~) main::$5 ← (unumber)(number) 0 * (const byte) SIZEOF_STRUCT_POINT +Adding number conversion cast (unumber) 1 in *((byte*) main::SCREEN#0 + (number) 1) ← *((byte*) main::$13 + (unumber~) main::$5) +Adding number conversion cast (unumber) 1 in (number~) main::$6 ← (number) 1 * (const byte) SIZEOF_STRUCT_POINT +Adding number conversion cast (unumber) main::$6 in (number~) main::$6 ← (unumber)(number) 1 * (const byte) SIZEOF_STRUCT_POINT +Adding number conversion cast (unumber) 3 in *((byte*) main::SCREEN#0 + (number) 3) ← *((byte*) main::$14 + (unumber~) main::$6) +Adding number conversion cast (unumber) 1 in (number~) main::$7 ← (number) 1 * (const byte) SIZEOF_STRUCT_POINT +Adding number conversion cast (unumber) main::$7 in (number~) main::$7 ← (unumber)(number) 1 * (const byte) SIZEOF_STRUCT_POINT +Adding number conversion cast (unumber) 4 in *((byte*) main::SCREEN#0 + (number) 4) ← *((byte*) main::$15 + (unumber~) main::$7) +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast *((byte*) main::$8 + (unumber~) main::$0) ← (unumber)(number) 2 +Inlining cast *((byte*) main::$9 + (unumber~) main::$1) ← (unumber)(number) 3 +Inlining cast *((byte*) main::$10 + (unumber~) main::$2) ← (unumber)(number) 5 +Inlining cast *((byte*) main::$11 + (unumber~) main::$3) ← (unumber)(number) 6 +Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400 +Successful SSA optimization Pass2InlineCast +Simplifying constant integer cast 0 +Simplifying constant integer cast 2 +Simplifying constant integer cast 0 +Simplifying constant integer cast 3 +Simplifying constant integer cast 1 +Simplifying constant integer cast 5 +Simplifying constant integer cast 1 +Simplifying constant integer cast 6 +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 1 +Simplifying constant integer cast 1 +Simplifying constant integer cast 3 +Simplifying constant integer cast 1 +Simplifying constant integer cast 4 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 2 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 3 +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 5 +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 6 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 3 +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 4 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Inferred type updated to byte in (unumber~) main::$0 ← (byte) 0 * (const byte) SIZEOF_STRUCT_POINT +Inferred type updated to byte in (unumber~) main::$1 ← (byte) 0 * (const byte) SIZEOF_STRUCT_POINT +Inferred type updated to byte in (unumber~) main::$2 ← (byte) 1 * (const byte) SIZEOF_STRUCT_POINT +Inferred type updated to byte in (unumber~) main::$3 ← (byte) 1 * (const byte) SIZEOF_STRUCT_POINT +Inferred type updated to byte in (unumber~) main::$4 ← (byte) 0 * (const byte) SIZEOF_STRUCT_POINT +Inferred type updated to byte in (unumber~) main::$5 ← (byte) 0 * (const byte) SIZEOF_STRUCT_POINT +Inferred type updated to byte in (unumber~) main::$6 ← (byte) 1 * (const byte) SIZEOF_STRUCT_POINT +Inferred type updated to byte in (unumber~) main::$7 ← (byte) 1 * (const byte) SIZEOF_STRUCT_POINT +Constant right-side identified [0] (struct Point[2]) points#0 ← { fill( 2, 0) } +Constant right-side identified [1] (byte~) main::$0 ← (byte) 0 * (const byte) SIZEOF_STRUCT_POINT +Constant right-side identified [4] (byte~) main::$1 ← (byte) 0 * (const byte) SIZEOF_STRUCT_POINT +Constant right-side identified [7] (byte~) main::$2 ← (byte) 1 * (const byte) SIZEOF_STRUCT_POINT +Constant right-side identified [10] (byte~) main::$3 ← (byte) 1 * (const byte) SIZEOF_STRUCT_POINT +Constant right-side identified [14] (byte~) main::$4 ← (byte) 0 * (const byte) SIZEOF_STRUCT_POINT +Constant right-side identified [17] (byte~) main::$5 ← (byte) 0 * (const byte) SIZEOF_STRUCT_POINT +Constant right-side identified [20] (byte~) main::$6 ← (byte) 1 * (const byte) SIZEOF_STRUCT_POINT +Constant right-side identified [23] (byte~) main::$7 ← (byte) 1 * (const byte) SIZEOF_STRUCT_POINT +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const struct Point[2]) points#0 = { fill( 2, 0) } +Constant (const byte) main::$0 = 0*SIZEOF_STRUCT_POINT +Constant (const byte) main::$1 = 0*SIZEOF_STRUCT_POINT +Constant (const byte) main::$2 = 1*SIZEOF_STRUCT_POINT +Constant (const byte) main::$3 = 1*SIZEOF_STRUCT_POINT +Constant (const byte*) main::SCREEN#0 = (byte*) 1024 +Constant (const byte) main::$4 = 0*SIZEOF_STRUCT_POINT +Constant (const byte) main::$5 = 0*SIZEOF_STRUCT_POINT +Constant (const byte) main::$6 = 1*SIZEOF_STRUCT_POINT +Constant (const byte) main::$7 = 1*SIZEOF_STRUCT_POINT +Successful SSA optimization Pass2ConstantIdentification +Constant value identified (byte*)points#0 in [2] (byte*) main::$8 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X +Constant value identified (byte*)points#0 in [5] (byte*) main::$9 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y +Constant value identified (byte*)points#0 in [8] (byte*) main::$10 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X +Constant value identified (byte*)points#0 in [11] (byte*) main::$11 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y +Constant value identified (byte*)points#0 in [15] (byte*) main::$12 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X +Constant value identified (byte*)points#0 in [18] (byte*) main::$13 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y +Constant value identified (byte*)points#0 in [21] (byte*) main::$14 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X +Constant value identified (byte*)points#0 in [24] (byte*) main::$15 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y +Successful SSA optimization Pass2ConstantValues +Simplifying constant evaluating to zero (byte) 0*(const byte) SIZEOF_STRUCT_POINT in +Simplifying constant evaluating to zero (byte) 0*(const byte) SIZEOF_STRUCT_POINT in +Simplifying constant evaluating to zero (byte) 0*(const byte) SIZEOF_STRUCT_POINT in +Simplifying constant evaluating to zero (byte) 0*(const byte) SIZEOF_STRUCT_POINT in +Successful SSA optimization PassNSimplifyConstantZero +Simplifying expression containing zero (byte*)points#0 in [2] (byte*) main::$8 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X +Simplifying expression containing zero main::$8 in [3] *((byte*) main::$8 + (const byte) main::$0) ← (byte) 2 +Simplifying expression containing zero main::$9 in [6] *((byte*) main::$9 + (const byte) main::$1) ← (byte) 3 +Simplifying expression containing zero (byte*)points#0 in [8] (byte*) main::$10 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X +Simplifying expression containing zero (byte*)points#0 in [15] (byte*) main::$12 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X +Simplifying expression containing zero main::$12 in [16] *((const byte*) main::SCREEN#0 + (byte) 0) ← *((byte*) main::$12 + (const byte) main::$4) +Simplifying expression containing zero main::SCREEN#0 in [16] *((const byte*) main::SCREEN#0 + (byte) 0) ← *((byte*) main::$12) +Simplifying expression containing zero main::$13 in [19] *((const byte*) main::SCREEN#0 + (byte) 1) ← *((byte*) main::$13 + (const byte) main::$5) +Simplifying expression containing zero (byte*)points#0 in [21] (byte*) main::$14 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X +Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused constant (const byte) main::$0 +Eliminating unused constant (const byte) main::$1 +Eliminating unused constant (const byte) main::$4 +Eliminating unused constant (const byte) main::$5 +Eliminating unused constant (const byte) OFFSET_STRUCT_POINT_X +Successful SSA optimization PassNEliminateUnusedVars +Constant right-side identified [2] (byte*) main::$9 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y +Constant right-side identified [6] (byte*) main::$11 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y +Constant right-side identified [10] (byte*) main::$13 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y +Constant right-side identified [14] (byte*) main::$15 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte*) main::$8 = (byte*)points#0 +Constant (const byte*) main::$9 = (byte*)points#0+OFFSET_STRUCT_POINT_Y +Constant (const byte*) main::$10 = (byte*)points#0 +Constant (const byte*) main::$11 = (byte*)points#0+OFFSET_STRUCT_POINT_Y +Constant (const byte*) main::$12 = (byte*)points#0 +Constant (const byte*) main::$13 = (byte*)points#0+OFFSET_STRUCT_POINT_Y +Constant (const byte*) main::$14 = (byte*)points#0 +Constant (const byte*) main::$15 = (byte*)points#0+OFFSET_STRUCT_POINT_Y +Successful SSA optimization Pass2ConstantIdentification +Constant inlined main::$12 = (byte*)(const struct Point[2]) points#0 +Constant inlined main::$13 = (byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y +Constant inlined main::$14 = (byte*)(const struct Point[2]) points#0 +Constant inlined main::$15 = (byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y +Constant inlined main::$10 = (byte*)(const struct Point[2]) points#0 +Constant inlined main::$11 = (byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y +Constant inlined main::$2 = (byte) 1*(const byte) SIZEOF_STRUCT_POINT +Constant inlined main::$6 = (byte) 1*(const byte) SIZEOF_STRUCT_POINT +Constant inlined main::$3 = (byte) 1*(const byte) SIZEOF_STRUCT_POINT +Constant inlined main::$9 = (byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y +Constant inlined main::$7 = (byte) 1*(const byte) SIZEOF_STRUCT_POINT +Constant inlined main::$8 = (byte*)(const struct Point[2]) points#0 +Successful SSA optimization Pass2ConstantInlining +Consolidated array index constant in *((byte*)points#0+1*SIZEOF_STRUCT_POINT) +Consolidated array index constant in *((byte*)points#0+OFFSET_STRUCT_POINT_Y+1*SIZEOF_STRUCT_POINT) +Consolidated array index constant in *(main::SCREEN#0+1) +Consolidated array index constant in *((byte*)points#0+1*SIZEOF_STRUCT_POINT) +Consolidated array index constant in *(main::SCREEN#0+3) +Consolidated array index constant in *((byte*)points#0+OFFSET_STRUCT_POINT_Y+1*SIZEOF_STRUCT_POINT) +Consolidated array index constant in *(main::SCREEN#0+4) +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] *((byte*)(const struct Point[2]) points#0) ← (byte) 2 + [5] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) ← (byte) 3 + [6] *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 5 + [7] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 6 + [8] *((const byte*) main::SCREEN#0) ← *((byte*)(const struct Point[2]) points#0) + [9] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) + [10] *((const byte*) main::SCREEN#0+(byte) 3) ← *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) + [11] *((const byte*) main::SCREEN#0+(byte) 4) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) + to:main::@return +main::@return: scope:[main] from main + [12] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(byte) Point::x +(byte) Point::y +(void()) main() +(byte*) main::SCREEN +(struct Point[2]) points + +Initial phi equivalence classes +Complete equivalence classes + +INITIAL ASM +//SEG0 File Comments +// Minimal struct - direct (constant) array access +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const SIZEOF_STRUCT_POINT = 2 + .const OFFSET_STRUCT_POINT_Y = 1 +//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 SCREEN = $400 + //SEG10 [4] *((byte*)(const struct Point[2]) points#0) ← (byte) 2 -- _deref_pbuc1=vbuc2 + lda #2 + sta points + //SEG11 [5] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) ← (byte) 3 -- _deref_pbuc1=vbuc2 + lda #3 + sta points+OFFSET_STRUCT_POINT_Y + //SEG12 [6] *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 5 -- _deref_pbuc1=vbuc2 + lda #5 + sta points+1*SIZEOF_STRUCT_POINT + //SEG13 [7] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 6 -- _deref_pbuc1=vbuc2 + lda #6 + sta points+OFFSET_STRUCT_POINT_Y+1*SIZEOF_STRUCT_POINT + //SEG14 [8] *((const byte*) main::SCREEN#0) ← *((byte*)(const struct Point[2]) points#0) -- _deref_pbuc1=_deref_pbuc2 + lda points + sta SCREEN + //SEG15 [9] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) -- _deref_pbuc1=_deref_pbuc2 + lda points+OFFSET_STRUCT_POINT_Y + sta SCREEN+1 + //SEG16 [10] *((const byte*) main::SCREEN#0+(byte) 3) ← *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) -- _deref_pbuc1=_deref_pbuc2 + lda points+1*SIZEOF_STRUCT_POINT + sta SCREEN+3 + //SEG17 [11] *((const byte*) main::SCREEN#0+(byte) 4) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) -- _deref_pbuc1=_deref_pbuc2 + lda points+OFFSET_STRUCT_POINT_Y+1*SIZEOF_STRUCT_POINT + sta SCREEN+4 + jmp breturn + //SEG18 main::@return + breturn: + //SEG19 [12] return + rts +} + points: .fill 2*2, 0 + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] *((byte*)(const struct Point[2]) points#0) ← (byte) 2 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [5] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) ← (byte) 3 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [6] *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 5 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [7] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 6 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [8] *((const byte*) main::SCREEN#0) ← *((byte*)(const struct Point[2]) points#0) [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [9] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [10] *((const byte*) main::SCREEN#0+(byte) 3) ← *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [11] *((const byte*) main::SCREEN#0+(byte) 4) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) [ ] ( main:2 [ ] ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [Point] +Uplift Scope [main] +Uplift Scope [] + +Uplifting [Point] best 77 combination +Uplifting [main] best 77 combination +Uplifting [] best 77 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Minimal struct - direct (constant) array access +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const SIZEOF_STRUCT_POINT = 2 + .const OFFSET_STRUCT_POINT_Y = 1 +//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 SCREEN = $400 + //SEG10 [4] *((byte*)(const struct Point[2]) points#0) ← (byte) 2 -- _deref_pbuc1=vbuc2 + lda #2 + sta points + //SEG11 [5] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) ← (byte) 3 -- _deref_pbuc1=vbuc2 + lda #3 + sta points+OFFSET_STRUCT_POINT_Y + //SEG12 [6] *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 5 -- _deref_pbuc1=vbuc2 + lda #5 + sta points+1*SIZEOF_STRUCT_POINT + //SEG13 [7] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 6 -- _deref_pbuc1=vbuc2 + lda #6 + sta points+OFFSET_STRUCT_POINT_Y+1*SIZEOF_STRUCT_POINT + //SEG14 [8] *((const byte*) main::SCREEN#0) ← *((byte*)(const struct Point[2]) points#0) -- _deref_pbuc1=_deref_pbuc2 + lda points + sta SCREEN + //SEG15 [9] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) -- _deref_pbuc1=_deref_pbuc2 + lda points+OFFSET_STRUCT_POINT_Y + sta SCREEN+1 + //SEG16 [10] *((const byte*) main::SCREEN#0+(byte) 3) ← *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) -- _deref_pbuc1=_deref_pbuc2 + lda points+1*SIZEOF_STRUCT_POINT + sta SCREEN+3 + //SEG17 [11] *((const byte*) main::SCREEN#0+(byte) 4) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) -- _deref_pbuc1=_deref_pbuc2 + lda points+OFFSET_STRUCT_POINT_Y+1*SIZEOF_STRUCT_POINT + sta SCREEN+4 + jmp breturn + //SEG18 main::@return + breturn: + //SEG19 [12] return + rts +} + points: .fill 2*2, 0 + +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 +(const byte) OFFSET_STRUCT_POINT_Y OFFSET_STRUCT_POINT_Y = (byte) 1 +(byte) Point::x +(byte) Point::y +(const byte) SIZEOF_STRUCT_POINT SIZEOF_STRUCT_POINT = (byte) 2 +(void()) main() +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 +(struct Point[2]) points +(const struct Point[2]) points#0 points = { fill( 2, 0) } + + + +FINAL ASSEMBLER +Score: 62 + +//SEG0 File Comments +// Minimal struct - direct (constant) array access +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const SIZEOF_STRUCT_POINT = 2 + .const OFFSET_STRUCT_POINT_Y = 1 +//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 SCREEN = $400 + //SEG10 [4] *((byte*)(const struct Point[2]) points#0) ← (byte) 2 -- _deref_pbuc1=vbuc2 + lda #2 + sta points + //SEG11 [5] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) ← (byte) 3 -- _deref_pbuc1=vbuc2 + lda #3 + sta points+OFFSET_STRUCT_POINT_Y + //SEG12 [6] *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 5 -- _deref_pbuc1=vbuc2 + lda #5 + sta points+1*SIZEOF_STRUCT_POINT + //SEG13 [7] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 6 -- _deref_pbuc1=vbuc2 + lda #6 + sta points+OFFSET_STRUCT_POINT_Y+1*SIZEOF_STRUCT_POINT + //SEG14 [8] *((const byte*) main::SCREEN#0) ← *((byte*)(const struct Point[2]) points#0) -- _deref_pbuc1=_deref_pbuc2 + lda points + sta SCREEN + //SEG15 [9] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) -- _deref_pbuc1=_deref_pbuc2 + lda points+OFFSET_STRUCT_POINT_Y + sta SCREEN+1 + //SEG16 [10] *((const byte*) main::SCREEN#0+(byte) 3) ← *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) -- _deref_pbuc1=_deref_pbuc2 + lda points+1*SIZEOF_STRUCT_POINT + sta SCREEN+3 + //SEG17 [11] *((const byte*) main::SCREEN#0+(byte) 4) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) -- _deref_pbuc1=_deref_pbuc2 + lda points+OFFSET_STRUCT_POINT_Y+1*SIZEOF_STRUCT_POINT + sta SCREEN+4 + //SEG18 main::@return + //SEG19 [12] return + rts +} + points: .fill 2*2, 0 + diff --git a/src/test/ref/struct-ptr-7.sym b/src/test/ref/struct-ptr-7.sym new file mode 100644 index 000000000..e251b3602 --- /dev/null +++ b/src/test/ref/struct-ptr-7.sym @@ -0,0 +1,14 @@ +(label) @1 +(label) @begin +(label) @end +(const byte) OFFSET_STRUCT_POINT_Y OFFSET_STRUCT_POINT_Y = (byte) 1 +(byte) Point::x +(byte) Point::y +(const byte) SIZEOF_STRUCT_POINT SIZEOF_STRUCT_POINT = (byte) 2 +(void()) main() +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 +(struct Point[2]) points +(const struct Point[2]) points#0 points = { fill( 2, 0) } + diff --git a/src/test/ref/struct-ptr-8.asm b/src/test/ref/struct-ptr-8.asm new file mode 100644 index 000000000..2cec58b4a --- /dev/null +++ b/src/test/ref/struct-ptr-8.asm @@ -0,0 +1,50 @@ +// Minimal struct - variable array access +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .const OFFSET_STRUCT_POINT_Y = 1 +main: { + .label SCREEN = $400 + .label i = 2 + .label i1 = 3 + lda #0 + sta i + b1: + lax i + axs #-[2] + lda i + asl + tay + txa + sta points,y + lda #3 + clc + adc i + sta points+OFFSET_STRUCT_POINT_Y,y + inc i + lda #2 + cmp i + bne b1 + ldx #0 + txa + sta i1 + b2: + lda i1 + asl + tay + lda points,y + sta SCREEN,x + inx + lda points+OFFSET_STRUCT_POINT_Y,y + sta SCREEN,x + inx + lda #' ' + sta SCREEN,x + inx + inc i1 + lda #2 + cmp i1 + bne b2 + rts +} + points: .fill 2*2, 0 diff --git a/src/test/ref/struct-ptr-8.cfg b/src/test/ref/struct-ptr-8.cfg new file mode 100644 index 000000000..29f5811d3 --- /dev/null +++ b/src/test/ref/struct-ptr-8.cfg @@ -0,0 +1,38 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@1 + [5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 ) + [6] (byte~) main::$0 ← (byte) 2 + (byte) main::i#2 + [7] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 + [8] *((byte*)(const struct Point[2]) points#0 + (byte~) main::$5) ← (byte~) main::$0 + [9] (byte~) main::$1 ← (byte) 3 + (byte) main::i#2 + [10] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$5) ← (byte~) main::$1 + [11] (byte) main::i#1 ← ++ (byte) main::i#2 + [12] if((byte) main::i#1!=(byte) 2) goto main::@1 + to:main::@2 +main::@2: scope:[main] from main::@1 main::@2 + [13] (byte) main::idx#4 ← phi( main::@1/(byte) 0 main::@2/(byte) main::idx#3 ) + [13] (byte) main::i1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::i1#1 ) + [14] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 + [15] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*)(const struct Point[2]) points#0 + (byte~) main::$7) + [16] (byte) main::idx#1 ← ++ (byte) main::idx#4 + [17] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$7) + [18] (byte) main::idx#2 ← ++ (byte) main::idx#1 + [19] *((const byte*) main::SCREEN#0 + (byte) main::idx#2) ← (byte) ' ' + [20] (byte) main::idx#3 ← ++ (byte) main::idx#2 + [21] (byte) main::i1#1 ← ++ (byte) main::i1#2 + [22] if((byte) main::i1#1!=(byte) 2) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@2 + [23] return + to:@return diff --git a/src/test/ref/struct-ptr-8.log b/src/test/ref/struct-ptr-8.log new file mode 100644 index 000000000..876ebfdfc --- /dev/null +++ b/src/test/ref/struct-ptr-8.log @@ -0,0 +1,787 @@ +Fixing pointer array-indexing *((struct Point[2]) points + (byte) main::i) +Fixing pointer array-indexing *((struct Point[2]) points + (byte) main::i) +Fixing pointer array-indexing *((struct Point[2]) points + (byte) main::i1) +Fixing pointer array-indexing *((struct Point[2]) points + (byte) main::i1) +Rewriting struct pointer member access *((struct Point[2]) points + (byte~) main::$4).x +Rewriting struct pointer member access *((struct Point[2]) points + (byte~) main::$5).y +Rewriting struct pointer member access *((struct Point[2]) points + (byte~) main::$6).x +Rewriting struct pointer member access *((struct Point[2]) points + (byte~) main::$7).y +Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400 +Culled Empty Block (label) main::@4 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (struct Point[2]) points#0 ← { fill( 2, 0) } + to:@1 +main: scope:[main] from @1 + (byte) main::i#0 ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@1 + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 ) + (number~) main::$0 ← (number) 2 + (byte) main::i#2 + (byte~) main::$4 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT + (byte*) main::$8 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X + *((byte*) main::$8 + (byte~) main::$4) ← (number~) main::$0 + (number~) main::$1 ← (number) 3 + (byte) main::i#2 + (byte~) main::$5 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT + (byte*) main::$9 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y + *((byte*) main::$9 + (byte~) main::$5) ← (number~) main::$1 + (byte) main::i#1 ← (byte) main::i#2 + rangenext(0,1) + (bool~) main::$2 ← (byte) main::i#1 != rangelast(0,1) + if((bool~) main::$2) goto main::@1 + to:main::@2 +main::@2: scope:[main] from main::@1 + (byte*) main::SCREEN#0 ← ((byte*)) (number) $400 + (byte) main::idx#0 ← (number) 0 + (byte) main::i1#0 ← (byte) 0 + to:main::@3 +main::@3: scope:[main] from main::@2 main::@3 + (byte) main::idx#4 ← phi( main::@2/(byte) main::idx#0 main::@3/(byte) main::idx#3 ) + (byte) main::i1#2 ← phi( main::@2/(byte) main::i1#0 main::@3/(byte) main::i1#1 ) + (byte~) main::$6 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT + (byte*) main::$10 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X + *((byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*) main::$10 + (byte~) main::$6) + (byte) main::idx#1 ← ++ (byte) main::idx#4 + (byte~) main::$7 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT + (byte*) main::$11 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y + *((byte*) main::SCREEN#0 + (byte) main::idx#1) ← *((byte*) main::$11 + (byte~) main::$7) + (byte) main::idx#2 ← ++ (byte) main::idx#1 + *((byte*) main::SCREEN#0 + (byte) main::idx#2) ← (byte) ' ' + (byte) main::idx#3 ← ++ (byte) main::idx#2 + (byte) main::i1#1 ← (byte) main::i1#2 + rangenext(0,1) + (bool~) main::$3 ← (byte) main::i1#1 != rangelast(0,1) + if((bool~) main::$3) goto main::@3 + to:main::@return +main::@return: scope:[main] from main::@3 + 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 +(const byte) OFFSET_STRUCT_POINT_X = (byte) 0 +(const byte) OFFSET_STRUCT_POINT_Y = (byte) 1 +(byte) Point::x +(byte) Point::y +(const byte) SIZEOF_STRUCT_POINT = (byte) 2 +(void()) main() +(number~) main::$0 +(number~) main::$1 +(byte*) main::$10 +(byte*) main::$11 +(bool~) main::$2 +(bool~) main::$3 +(byte~) main::$4 +(byte~) main::$5 +(byte~) main::$6 +(byte~) main::$7 +(byte*) main::$8 +(byte*) main::$9 +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@return +(byte*) main::SCREEN +(byte*) main::SCREEN#0 +(byte) main::i +(byte) main::i#0 +(byte) main::i#1 +(byte) main::i#2 +(byte) main::i1 +(byte) main::i1#0 +(byte) main::i1#1 +(byte) main::i1#2 +(byte) main::idx +(byte) main::idx#0 +(byte) main::idx#1 +(byte) main::idx#2 +(byte) main::idx#3 +(byte) main::idx#4 +(struct Point[2]) points +(struct Point[2]) points#0 + +Adding number conversion cast (unumber) 2 in (number~) main::$0 ← (number) 2 + (byte) main::i#2 +Adding number conversion cast (unumber) main::$0 in (number~) main::$0 ← (unumber)(number) 2 + (byte) main::i#2 +Adding number conversion cast (unumber) 3 in (number~) main::$1 ← (number) 3 + (byte) main::i#2 +Adding number conversion cast (unumber) main::$1 in (number~) main::$1 ← (unumber)(number) 3 + (byte) main::i#2 +Adding number conversion cast (unumber) 0 in (byte) main::idx#0 ← (number) 0 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400 +Inlining cast (byte) main::idx#0 ← (unumber)(number) 0 +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 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 2 +Finalized unsigned number type (byte) 3 +Finalized unsigned number type (byte) 0 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Inferred type updated to byte in (unumber~) main::$0 ← (byte) 2 + (byte) main::i#2 +Inferred type updated to byte in (unumber~) main::$1 ← (byte) 3 + (byte) main::i#2 +Identified duplicate assignment right side [8] (byte~) main::$5 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT +Identified duplicate assignment right side [22] (byte~) main::$7 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT +Successful SSA optimization Pass2DuplicateRValueIdentification +Simple Condition (bool~) main::$2 [13] if((byte) main::i#1!=rangelast(0,1)) goto main::@1 +Simple Condition (bool~) main::$3 [30] if((byte) main::i1#1!=rangelast(0,1)) goto main::@3 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant right-side identified [0] (struct Point[2]) points#0 ← { fill( 2, 0) } +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const struct Point[2]) points#0 = { fill( 2, 0) } +Constant (const byte) main::i#0 = 0 +Constant (const byte*) main::SCREEN#0 = (byte*) 1024 +Constant (const byte) main::idx#0 = 0 +Constant (const byte) main::i1#0 = 0 +Successful SSA optimization Pass2ConstantIdentification +Constant value identified (byte*)points#0 in [5] (byte*) main::$8 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X +Constant value identified (byte*)points#0 in [9] (byte*) main::$9 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y +Constant value identified (byte*)points#0 in [19] (byte*) main::$10 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X +Constant value identified (byte*)points#0 in [23] (byte*) main::$11 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y +Successful SSA optimization Pass2ConstantValues +Resolved ranged next value [11] main::i#1 ← ++ main::i#2 to ++ +Resolved ranged comparison value [13] if(main::i#1!=rangelast(0,1)) goto main::@1 to (number) 2 +Resolved ranged next value [28] main::i1#1 ← ++ main::i1#2 to ++ +Resolved ranged comparison value [30] if(main::i1#1!=rangelast(0,1)) goto main::@3 to (number) 2 +Simplifying expression containing zero (byte*)points#0 in [5] (byte*) main::$8 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X +Simplifying expression containing zero (byte*)points#0 in [19] (byte*) main::$10 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X +Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused constant (const byte) OFFSET_STRUCT_POINT_X +Successful SSA optimization PassNEliminateUnusedVars +Adding number conversion cast (unumber) 2 in if((byte) main::i#1!=(number) 2) goto main::@1 +Adding number conversion cast (unumber) 2 in if((byte) main::i1#1!=(number) 2) goto main::@3 +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant integer cast 2 +Simplifying constant integer cast 2 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 2 +Finalized unsigned number type (byte) 2 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias (byte~) main::$5 = (byte~) main::$4 +Alias (byte~) main::$7 = (byte~) main::$6 +Successful SSA optimization Pass2AliasElimination +Constant right-side identified [7] (byte*) main::$9 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y +Constant right-side identified [17] (byte*) main::$11 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte*) main::$8 = (byte*)points#0 +Constant (const byte*) main::$9 = (byte*)points#0+OFFSET_STRUCT_POINT_Y +Constant (const byte*) main::$10 = (byte*)points#0 +Constant (const byte*) main::$11 = (byte*)points#0+OFFSET_STRUCT_POINT_Y +Successful SSA optimization Pass2ConstantIdentification +Rewriting multiplication to use shift [2] (byte~) main::$5 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT +Rewriting multiplication to use shift [9] (byte~) main::$7 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT +Successful SSA optimization Pass2MultiplyToShiftRewriting +Inlining constant with var siblings (const byte) main::i#0 +Inlining constant with var siblings (const byte) main::idx#0 +Inlining constant with var siblings (const byte) main::i1#0 +Constant inlined main::idx#0 = (byte) 0 +Constant inlined main::i#0 = (byte) 0 +Constant inlined main::i1#0 = (byte) 0 +Constant inlined main::$9 = (byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y +Constant inlined main::$10 = (byte*)(const struct Point[2]) points#0 +Constant inlined main::$8 = (byte*)(const struct Point[2]) points#0 +Constant inlined main::$11 = (byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y +Successful SSA optimization Pass2ConstantInlining +Eliminating unused constant (const byte) SIZEOF_STRUCT_POINT +Successful SSA optimization PassNEliminateUnusedVars +Added new block during phi lifting main::@5(between main::@1 and main::@1) +Added new block during phi lifting main::@6(between main::@3 and main::@3) +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 +Adding NOP phi() at start of main +Adding NOP phi() at start of main::@2 +CALL GRAPH +Calls in [] to main:2 + +Created 3 initial phi equivalence classes +Coalesced [26] main::i1#3 ← main::i1#1 +Coalesced [27] main::idx#5 ← main::idx#3 +Coalesced [28] main::i#3 ← main::i#1 +Coalesced down to 3 phi equivalence classes +Culled Empty Block (label) @2 +Culled Empty Block (label) main::@2 +Culled Empty Block (label) main::@6 +Culled Empty Block (label) main::@5 +Renumbering block main::@3 to main::@2 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@1 + [5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 ) + [6] (byte~) main::$0 ← (byte) 2 + (byte) main::i#2 + [7] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 + [8] *((byte*)(const struct Point[2]) points#0 + (byte~) main::$5) ← (byte~) main::$0 + [9] (byte~) main::$1 ← (byte) 3 + (byte) main::i#2 + [10] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$5) ← (byte~) main::$1 + [11] (byte) main::i#1 ← ++ (byte) main::i#2 + [12] if((byte) main::i#1!=(byte) 2) goto main::@1 + to:main::@2 +main::@2: scope:[main] from main::@1 main::@2 + [13] (byte) main::idx#4 ← phi( main::@1/(byte) 0 main::@2/(byte) main::idx#3 ) + [13] (byte) main::i1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::i1#1 ) + [14] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 + [15] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*)(const struct Point[2]) points#0 + (byte~) main::$7) + [16] (byte) main::idx#1 ← ++ (byte) main::idx#4 + [17] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$7) + [18] (byte) main::idx#2 ← ++ (byte) main::idx#1 + [19] *((const byte*) main::SCREEN#0 + (byte) main::idx#2) ← (byte) ' ' + [20] (byte) main::idx#3 ← ++ (byte) main::idx#2 + [21] (byte) main::i1#1 ← ++ (byte) main::i1#2 + [22] if((byte) main::i1#1!=(byte) 2) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@2 + [23] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(byte) Point::x +(byte) Point::y +(void()) main() +(byte~) main::$0 11.0 +(byte~) main::$1 22.0 +(byte~) main::$5 11.0 +(byte~) main::$7 11.0 +(byte*) main::SCREEN +(byte) main::i +(byte) main::i#1 16.5 +(byte) main::i#2 9.166666666666666 +(byte) main::i1 +(byte) main::i1#1 16.5 +(byte) main::i1#2 4.125 +(byte) main::idx +(byte) main::idx#1 16.5 +(byte) main::idx#2 16.5 +(byte) main::idx#3 7.333333333333333 +(byte) main::idx#4 11.0 +(struct Point[2]) points + +Initial phi equivalence classes +[ main::i#2 main::i#1 ] +[ main::i1#2 main::i1#1 ] +[ main::idx#4 main::idx#3 ] +Added variable main::$0 to zero page equivalence class [ main::$0 ] +Added variable main::$5 to zero page equivalence class [ main::$5 ] +Added variable main::$1 to zero page equivalence class [ main::$1 ] +Added variable main::$7 to zero page equivalence class [ main::$7 ] +Added variable main::idx#1 to zero page equivalence class [ main::idx#1 ] +Added variable main::idx#2 to zero page equivalence class [ main::idx#2 ] +Complete equivalence classes +[ main::i#2 main::i#1 ] +[ main::i1#2 main::i1#1 ] +[ main::idx#4 main::idx#3 ] +[ main::$0 ] +[ main::$5 ] +[ main::$1 ] +[ main::$7 ] +[ main::idx#1 ] +[ main::idx#2 ] +Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ] +Allocated zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] +Allocated zp ZP_BYTE:4 [ main::idx#4 main::idx#3 ] +Allocated zp ZP_BYTE:5 [ main::$0 ] +Allocated zp ZP_BYTE:6 [ main::$5 ] +Allocated zp ZP_BYTE:7 [ main::$1 ] +Allocated zp ZP_BYTE:8 [ main::$7 ] +Allocated zp ZP_BYTE:9 [ main::idx#1 ] +Allocated zp ZP_BYTE:10 [ main::idx#2 ] + +INITIAL ASM +//SEG0 File Comments +// Minimal struct - variable array access +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const OFFSET_STRUCT_POINT_Y = 1 +//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 +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + .label SCREEN = $400 + .label _0 = 5 + .label _1 = 7 + .label _5 = 6 + .label _7 = 8 + .label i = 2 + .label idx = 9 + .label idx_2 = $a + .label idx_3 = 4 + .label i1 = 3 + .label idx_4 = 4 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 + lda #0 + sta i + jmp b1 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + jmp b1 + //SEG15 main::@1 + b1: + //SEG16 [6] (byte~) main::$0 ← (byte) 2 + (byte) main::i#2 -- vbuz1=vbuc1_plus_vbuz2 + lax i + axs #-[2] + stx _0 + //SEG17 [7] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuz2_rol_1 + lda i + asl + sta _5 + //SEG18 [8] *((byte*)(const struct Point[2]) points#0 + (byte~) main::$5) ← (byte~) main::$0 -- pbuc1_derefidx_vbuz1=vbuz2 + lda _0 + ldy _5 + sta points,y + //SEG19 [9] (byte~) main::$1 ← (byte) 3 + (byte) main::i#2 -- vbuz1=vbuc1_plus_vbuz2 + lax i + axs #-[3] + stx _1 + //SEG20 [10] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$5) ← (byte~) main::$1 -- pbuc1_derefidx_vbuz1=vbuz2 + lda _1 + ldy _5 + sta points+OFFSET_STRUCT_POINT_Y,y + //SEG21 [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 + inc i + //SEG22 [12] if((byte) main::i#1!=(byte) 2) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 + lda #2 + cmp i + bne b1_from_b1 + //SEG23 [13] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + b2_from_b1: + //SEG24 [13] phi (byte) main::idx#4 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1 + lda #0 + sta idx_4 + //SEG25 [13] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#1] -- vbuz1=vbuc1 + lda #0 + sta i1 + jmp b2 + //SEG26 [13] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + b2_from_b2: + //SEG27 [13] phi (byte) main::idx#4 = (byte) main::idx#3 [phi:main::@2->main::@2#0] -- register_copy + //SEG28 [13] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#1] -- register_copy + jmp b2 + //SEG29 main::@2 + b2: + //SEG30 [14] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 -- vbuz1=vbuz2_rol_1 + lda i1 + asl + sta _7 + //SEG31 [15] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*)(const struct Point[2]) points#0 + (byte~) main::$7) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz2 + ldy _7 + lda points,y + ldy idx_4 + sta SCREEN,y + //SEG32 [16] (byte) main::idx#1 ← ++ (byte) main::idx#4 -- vbuz1=_inc_vbuz2 + ldy idx_4 + iny + sty idx + //SEG33 [17] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$7) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz2 + ldy _7 + lda points+OFFSET_STRUCT_POINT_Y,y + ldy idx + sta SCREEN,y + //SEG34 [18] (byte) main::idx#2 ← ++ (byte) main::idx#1 -- vbuz1=_inc_vbuz2 + ldy idx + iny + sty idx_2 + //SEG35 [19] *((const byte*) main::SCREEN#0 + (byte) main::idx#2) ← (byte) ' ' -- pbuc1_derefidx_vbuz1=vbuc2 + lda #' ' + ldy idx_2 + sta SCREEN,y + //SEG36 [20] (byte) main::idx#3 ← ++ (byte) main::idx#2 -- vbuz1=_inc_vbuz2 + ldy idx_2 + iny + sty idx_3 + //SEG37 [21] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuz1=_inc_vbuz1 + inc i1 + //SEG38 [22] if((byte) main::i1#1!=(byte) 2) goto main::@2 -- vbuz1_neq_vbuc1_then_la1 + lda #2 + cmp i1 + bne b2_from_b2 + jmp breturn + //SEG39 main::@return + breturn: + //SEG40 [23] return + rts +} + points: .fill 2*2, 0 + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [7] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$0 main::$5 ] ( main:2 [ main::i#2 main::$0 main::$5 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ] +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:5 [ main::$0 ] +Statement [8] *((byte*)(const struct Point[2]) points#0 + (byte~) main::$5) ← (byte~) main::$0 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:6 [ main::$5 ] +Statement [9] (byte~) main::$1 ← (byte) 3 + (byte) main::i#2 [ main::i#2 main::$5 main::$1 ] ( main:2 [ main::i#2 main::$5 main::$1 ] ) always clobbers reg byte a +Statement [14] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::idx#4 main::$7 ] ( main:2 [ main::i1#2 main::idx#4 main::$7 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::idx#4 main::idx#3 ] +Statement [15] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*)(const struct Point[2]) points#0 + (byte~) main::$7) [ main::i1#2 main::idx#4 main::$7 ] ( main:2 [ main::i1#2 main::idx#4 main::$7 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:8 [ main::$7 ] +Statement [17] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$7) [ main::i1#2 main::idx#1 ] ( main:2 [ main::i1#2 main::idx#1 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:9 [ main::idx#1 ] +Statement [19] *((const byte*) main::SCREEN#0 + (byte) main::idx#2) ← (byte) ' ' [ main::i1#2 main::idx#2 ] ( main:2 [ main::i1#2 main::idx#2 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:10 [ main::idx#2 ] +Statement [6] (byte~) main::$0 ← (byte) 2 + (byte) main::i#2 [ main::i#2 main::$0 ] ( main:2 [ main::i#2 main::$0 ] ) always clobbers reg byte a +Statement [7] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$0 main::$5 ] ( main:2 [ main::i#2 main::$0 main::$5 ] ) always clobbers reg byte a +Statement [8] *((byte*)(const struct Point[2]) points#0 + (byte~) main::$5) ← (byte~) main::$0 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a +Statement [9] (byte~) main::$1 ← (byte) 3 + (byte) main::i#2 [ main::i#2 main::$5 main::$1 ] ( main:2 [ main::i#2 main::$5 main::$1 ] ) always clobbers reg byte a +Statement [14] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::idx#4 main::$7 ] ( main:2 [ main::i1#2 main::idx#4 main::$7 ] ) always clobbers reg byte a +Statement [15] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*)(const struct Point[2]) points#0 + (byte~) main::$7) [ main::i1#2 main::idx#4 main::$7 ] ( main:2 [ main::i1#2 main::idx#4 main::$7 ] ) always clobbers reg byte a +Statement [17] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$7) [ main::i1#2 main::idx#1 ] ( main:2 [ main::i1#2 main::idx#1 ] ) always clobbers reg byte a +Statement [19] *((const byte*) main::SCREEN#0 + (byte) main::idx#2) ← (byte) ' ' [ main::i1#2 main::idx#2 ] ( main:2 [ main::i1#2 main::idx#2 ] ) always clobbers reg byte a +Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] : zp ZP_BYTE:3 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:4 [ main::idx#4 main::idx#3 ] : zp ZP_BYTE:4 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:5 [ main::$0 ] : zp ZP_BYTE:5 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:6 [ main::$5 ] : zp ZP_BYTE:6 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:7 [ main::$1 ] : zp ZP_BYTE:7 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:8 [ main::$7 ] : zp ZP_BYTE:8 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:9 [ main::idx#1 ] : zp ZP_BYTE:9 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:10 [ main::idx#2 ] : zp ZP_BYTE:10 , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 25.67: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:7 [ main::$1 ] 20.62: zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] 18.33: zp ZP_BYTE:4 [ main::idx#4 main::idx#3 ] 16.5: zp ZP_BYTE:9 [ main::idx#1 ] 16.5: zp ZP_BYTE:10 [ main::idx#2 ] 11: zp ZP_BYTE:5 [ main::$0 ] 11: zp ZP_BYTE:6 [ main::$5 ] 11: zp ZP_BYTE:8 [ main::$7 ] +Uplift Scope [Point] +Uplift Scope [] + +Uplifting [main] best 1598 combination zp ZP_BYTE:2 [ main::i#2 main::i#1 ] reg byte a [ main::$1 ] zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] reg byte x [ main::idx#4 main::idx#3 ] zp ZP_BYTE:9 [ main::idx#1 ] zp ZP_BYTE:10 [ main::idx#2 ] zp ZP_BYTE:5 [ main::$0 ] zp ZP_BYTE:6 [ main::$5 ] zp ZP_BYTE:8 [ main::$7 ] +Limited combination testing to 100 combinations of 26244 possible. +Uplifting [Point] best 1598 combination +Uplifting [] best 1598 combination +Attempting to uplift remaining variables inzp ZP_BYTE:2 [ main::i#2 main::i#1 ] +Uplifting [main] best 1598 combination zp ZP_BYTE:2 [ main::i#2 main::i#1 ] +Attempting to uplift remaining variables inzp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] +Uplifting [main] best 1598 combination zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] +Attempting to uplift remaining variables inzp ZP_BYTE:9 [ main::idx#1 ] +Uplifting [main] best 1508 combination reg byte x [ main::idx#1 ] +Attempting to uplift remaining variables inzp ZP_BYTE:10 [ main::idx#2 ] +Uplifting [main] best 1418 combination reg byte x [ main::idx#2 ] +Attempting to uplift remaining variables inzp ZP_BYTE:5 [ main::$0 ] +Uplifting [main] best 1378 combination reg byte x [ main::$0 ] +Attempting to uplift remaining variables inzp ZP_BYTE:6 [ main::$5 ] +Uplifting [main] best 1308 combination reg byte y [ main::$5 ] +Attempting to uplift remaining variables inzp ZP_BYTE:8 [ main::$7 ] +Uplifting [main] best 1238 combination reg byte y [ main::$7 ] + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Minimal struct - variable array access +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const OFFSET_STRUCT_POINT_Y = 1 +//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 +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + .label SCREEN = $400 + .label i = 2 + .label i1 = 3 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 + lda #0 + sta i + jmp b1 + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + jmp b1 + //SEG15 main::@1 + b1: + //SEG16 [6] (byte~) main::$0 ← (byte) 2 + (byte) main::i#2 -- vbuxx=vbuc1_plus_vbuz1 + lax i + axs #-[2] + //SEG17 [7] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 -- vbuyy=vbuz1_rol_1 + lda i + asl + tay + //SEG18 [8] *((byte*)(const struct Point[2]) points#0 + (byte~) main::$5) ← (byte~) main::$0 -- pbuc1_derefidx_vbuyy=vbuxx + txa + sta points,y + //SEG19 [9] (byte~) main::$1 ← (byte) 3 + (byte) main::i#2 -- vbuaa=vbuc1_plus_vbuz1 + lda #3 + clc + adc i + //SEG20 [10] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$5) ← (byte~) main::$1 -- pbuc1_derefidx_vbuyy=vbuaa + sta points+OFFSET_STRUCT_POINT_Y,y + //SEG21 [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 + inc i + //SEG22 [12] if((byte) main::i#1!=(byte) 2) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 + lda #2 + cmp i + bne b1_from_b1 + //SEG23 [13] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + b2_from_b1: + //SEG24 [13] phi (byte) main::idx#4 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuxx=vbuc1 + ldx #0 + //SEG25 [13] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#1] -- vbuz1=vbuc1 + lda #0 + sta i1 + jmp b2 + //SEG26 [13] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + b2_from_b2: + //SEG27 [13] phi (byte) main::idx#4 = (byte) main::idx#3 [phi:main::@2->main::@2#0] -- register_copy + //SEG28 [13] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#1] -- register_copy + jmp b2 + //SEG29 main::@2 + b2: + //SEG30 [14] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 -- vbuyy=vbuz1_rol_1 + lda i1 + asl + tay + //SEG31 [15] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*)(const struct Point[2]) points#0 + (byte~) main::$7) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuyy + lda points,y + sta SCREEN,x + //SEG32 [16] (byte) main::idx#1 ← ++ (byte) main::idx#4 -- vbuxx=_inc_vbuxx + inx + //SEG33 [17] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$7) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuyy + lda points+OFFSET_STRUCT_POINT_Y,y + sta SCREEN,x + //SEG34 [18] (byte) main::idx#2 ← ++ (byte) main::idx#1 -- vbuxx=_inc_vbuxx + inx + //SEG35 [19] *((const byte*) main::SCREEN#0 + (byte) main::idx#2) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2 + lda #' ' + sta SCREEN,x + //SEG36 [20] (byte) main::idx#3 ← ++ (byte) main::idx#2 -- vbuxx=_inc_vbuxx + inx + //SEG37 [21] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuz1=_inc_vbuz1 + inc i1 + //SEG38 [22] if((byte) main::i1#1!=(byte) 2) goto main::@2 -- vbuz1_neq_vbuc1_then_la1 + lda #2 + cmp i1 + bne b2_from_b2 + jmp breturn + //SEG39 main::@return + breturn: + //SEG40 [23] return + rts +} + points: .fill 2*2, 0 + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp b2 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Replacing instruction lda #0 with TXA +Replacing label b1_from_b1 with b1 +Replacing label b2_from_b2 with b2 +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction main_from_b1: +Removing instruction bend_from_b1: +Removing instruction b1_from_b1: +Removing instruction b2_from_b2: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction b1_from_main: +Removing instruction b2_from_b1: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction jmp b1 +Removing instruction jmp b2 +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(const byte) OFFSET_STRUCT_POINT_Y OFFSET_STRUCT_POINT_Y = (byte) 1 +(byte) Point::x +(byte) Point::y +(void()) main() +(byte~) main::$0 reg byte x 11.0 +(byte~) main::$1 reg byte a 22.0 +(byte~) main::$5 reg byte y 11.0 +(byte~) main::$7 reg byte y 11.0 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 +(byte) main::i +(byte) main::i#1 i zp ZP_BYTE:2 16.5 +(byte) main::i#2 i zp ZP_BYTE:2 9.166666666666666 +(byte) main::i1 +(byte) main::i1#1 i1 zp ZP_BYTE:3 16.5 +(byte) main::i1#2 i1 zp ZP_BYTE:3 4.125 +(byte) main::idx +(byte) main::idx#1 reg byte x 16.5 +(byte) main::idx#2 reg byte x 16.5 +(byte) main::idx#3 reg byte x 7.333333333333333 +(byte) main::idx#4 reg byte x 11.0 +(struct Point[2]) points +(const struct Point[2]) points#0 points = { fill( 2, 0) } + +zp ZP_BYTE:2 [ main::i#2 main::i#1 ] +zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] +reg byte x [ main::idx#4 main::idx#3 ] +reg byte x [ main::$0 ] +reg byte y [ main::$5 ] +reg byte a [ main::$1 ] +reg byte y [ main::$7 ] +reg byte x [ main::idx#1 ] +reg byte x [ main::idx#2 ] + + +FINAL ASSEMBLER +Score: 1076 + +//SEG0 File Comments +// Minimal struct - variable array access +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .const OFFSET_STRUCT_POINT_Y = 1 +//SEG3 @begin +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +//SEG9 @end +//SEG10 main +main: { + .label SCREEN = $400 + .label i = 2 + .label i1 = 3 + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + //SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 + lda #0 + sta i + //SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + //SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG15 main::@1 + b1: + //SEG16 [6] (byte~) main::$0 ← (byte) 2 + (byte) main::i#2 -- vbuxx=vbuc1_plus_vbuz1 + lax i + axs #-[2] + //SEG17 [7] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 -- vbuyy=vbuz1_rol_1 + lda i + asl + tay + //SEG18 [8] *((byte*)(const struct Point[2]) points#0 + (byte~) main::$5) ← (byte~) main::$0 -- pbuc1_derefidx_vbuyy=vbuxx + txa + sta points,y + //SEG19 [9] (byte~) main::$1 ← (byte) 3 + (byte) main::i#2 -- vbuaa=vbuc1_plus_vbuz1 + lda #3 + clc + adc i + //SEG20 [10] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$5) ← (byte~) main::$1 -- pbuc1_derefidx_vbuyy=vbuaa + sta points+OFFSET_STRUCT_POINT_Y,y + //SEG21 [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 + inc i + //SEG22 [12] if((byte) main::i#1!=(byte) 2) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 + lda #2 + cmp i + bne b1 + //SEG23 [13] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + //SEG24 [13] phi (byte) main::idx#4 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuxx=vbuc1 + ldx #0 + //SEG25 [13] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#1] -- vbuz1=vbuc1 + txa + sta i1 + //SEG26 [13] phi from main::@2 to main::@2 [phi:main::@2->main::@2] + //SEG27 [13] phi (byte) main::idx#4 = (byte) main::idx#3 [phi:main::@2->main::@2#0] -- register_copy + //SEG28 [13] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#1] -- register_copy + //SEG29 main::@2 + b2: + //SEG30 [14] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 -- vbuyy=vbuz1_rol_1 + lda i1 + asl + tay + //SEG31 [15] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*)(const struct Point[2]) points#0 + (byte~) main::$7) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuyy + lda points,y + sta SCREEN,x + //SEG32 [16] (byte) main::idx#1 ← ++ (byte) main::idx#4 -- vbuxx=_inc_vbuxx + inx + //SEG33 [17] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$7) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuyy + lda points+OFFSET_STRUCT_POINT_Y,y + sta SCREEN,x + //SEG34 [18] (byte) main::idx#2 ← ++ (byte) main::idx#1 -- vbuxx=_inc_vbuxx + inx + //SEG35 [19] *((const byte*) main::SCREEN#0 + (byte) main::idx#2) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2 + lda #' ' + sta SCREEN,x + //SEG36 [20] (byte) main::idx#3 ← ++ (byte) main::idx#2 -- vbuxx=_inc_vbuxx + inx + //SEG37 [21] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuz1=_inc_vbuz1 + inc i1 + //SEG38 [22] if((byte) main::i1#1!=(byte) 2) goto main::@2 -- vbuz1_neq_vbuc1_then_la1 + lda #2 + cmp i1 + bne b2 + //SEG39 main::@return + //SEG40 [23] return + rts +} + points: .fill 2*2, 0 + diff --git a/src/test/ref/struct-ptr-8.sym b/src/test/ref/struct-ptr-8.sym new file mode 100644 index 000000000..dcae32299 --- /dev/null +++ b/src/test/ref/struct-ptr-8.sym @@ -0,0 +1,39 @@ +(label) @1 +(label) @begin +(label) @end +(const byte) OFFSET_STRUCT_POINT_Y OFFSET_STRUCT_POINT_Y = (byte) 1 +(byte) Point::x +(byte) Point::y +(void()) main() +(byte~) main::$0 reg byte x 11.0 +(byte~) main::$1 reg byte a 22.0 +(byte~) main::$5 reg byte y 11.0 +(byte~) main::$7 reg byte y 11.0 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 +(byte) main::i +(byte) main::i#1 i zp ZP_BYTE:2 16.5 +(byte) main::i#2 i zp ZP_BYTE:2 9.166666666666666 +(byte) main::i1 +(byte) main::i1#1 i1 zp ZP_BYTE:3 16.5 +(byte) main::i1#2 i1 zp ZP_BYTE:3 4.125 +(byte) main::idx +(byte) main::idx#1 reg byte x 16.5 +(byte) main::idx#2 reg byte x 16.5 +(byte) main::idx#3 reg byte x 7.333333333333333 +(byte) main::idx#4 reg byte x 11.0 +(struct Point[2]) points +(const struct Point[2]) points#0 points = { fill( 2, 0) } + +zp ZP_BYTE:2 [ main::i#2 main::i#1 ] +zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] +reg byte x [ main::idx#4 main::idx#3 ] +reg byte x [ main::$0 ] +reg byte y [ main::$5 ] +reg byte a [ main::$1 ] +reg byte y [ main::$7 ] +reg byte x [ main::idx#1 ] +reg byte x [ main::idx#2 ]