diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index fb8c718e8..be097bcd2 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -176,7 +176,7 @@ public class Compiler { getLog().append(program.getScope().toString(program, false)); } - new Pass1AddressOfVolatile(program).execute(); + new Pass1AddressOfHandling(program).execute(); new Pass1FixLValuesLoHi(program).execute(); new Pass1AssertNoLValueIntermediate(program).execute(); new PassNAddTypeConversionAssignment(program, false).execute(); @@ -190,7 +190,7 @@ public class Compiler { new Pass1PointerSizeofFix(program).execute(); // After this point in the code all pointer math is byte-based new PassNSizeOfSimplification(program).execute(); // Needed to eliminate sizeof() referencing pointer value variables - new Pass2AssertTypeMatch(program).check(); + new PassNAssertTypeMatch(program).check(); new Pass1ConstantifyRValue(program).execute(); new Pass1UnwindStructVariables(program).execute(); @@ -262,7 +262,7 @@ public class Compiler { List assertions = new ArrayList<>(); //assertions.add(new Pass2AssertNoLValueObjectEquality(program)); assertions.add(new PassNAssertTypeDeref(program)); - assertions.add(new Pass2AssertTypeMatch(program)); + assertions.add(new PassNAssertTypeMatch(program)); assertions.add(new Pass2AssertSymbols(program)); assertions.add(new Pass2AssertBlocks(program)); assertions.add(new Pass2AssertNoCallParameters(program)); diff --git a/src/main/java/dk/camelot64/kickc/model/StructVariableMemberUnwinding.java b/src/main/java/dk/camelot64/kickc/model/StructVariableMemberUnwinding.java index 4d4e32430..0c733c2f3 100644 --- a/src/main/java/dk/camelot64/kickc/model/StructVariableMemberUnwinding.java +++ b/src/main/java/dk/camelot64/kickc/model/StructVariableMemberUnwinding.java @@ -39,7 +39,6 @@ public class StructVariableMemberUnwinding { return structVariables.get(ref); } - /** Information about how a single struct variable was unwound. */ public static class VariableUnwinding { diff --git a/src/main/java/dk/camelot64/kickc/model/symbols/Variable.java b/src/main/java/dk/camelot64/kickc/model/symbols/Variable.java index 9810f615c..e07af9998 100644 --- a/src/main/java/dk/camelot64/kickc/model/symbols/Variable.java +++ b/src/main/java/dk/camelot64/kickc/model/symbols/Variable.java @@ -304,6 +304,10 @@ public class Variable implements Symbol { return kind; } + public void setKind(Kind kind) { + this.kind = kind; + } + public boolean isKindConstant() { return Kind.CONSTANT.equals(getKind()); } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1AddressOfVolatile.java b/src/main/java/dk/camelot64/kickc/passes/Pass1AddressOfHandling.java similarity index 62% rename from src/main/java/dk/camelot64/kickc/passes/Pass1AddressOfVolatile.java rename to src/main/java/dk/camelot64/kickc/passes/Pass1AddressOfHandling.java index 02b17e67a..9d237d645 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1AddressOfVolatile.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1AddressOfHandling.java @@ -7,14 +7,15 @@ import dk.camelot64.kickc.model.iterator.ProgramValueIterator; import dk.camelot64.kickc.model.operators.Operators; import dk.camelot64.kickc.model.symbols.Symbol; import dk.camelot64.kickc.model.symbols.Variable; +import dk.camelot64.kickc.model.types.SymbolTypeStruct; import dk.camelot64.kickc.model.values.*; /** - * Add inferred volatile to all variables, where address-of is used + * Update variables properly if address-of is used */ -public class Pass1AddressOfVolatile extends Pass2SsaOptimization { +public class Pass1AddressOfHandling extends Pass2SsaOptimization { - public Pass1AddressOfVolatile(Program program) { + public Pass1AddressOfHandling(Program program) { super(program); } @@ -26,8 +27,9 @@ public class Pass1AddressOfVolatile extends Pass2SsaOptimization { if(rValue instanceof SymbolVariableRef) { Symbol toSymbol = getScope().getSymbol((SymbolVariableRef) rValue); if(toSymbol instanceof Variable) { - ((Variable) toSymbol).setInferredVolatile(true); - getLog().append("Setting inferred volatile on symbol affected by address-of " + currentStmt.toString(getProgram(), false)); + final Variable variable = (Variable) toSymbol; + final String stmtStr = currentStmt.toString(getProgram(), false); + updateAddressOfVariable(variable, stmtStr); } } } @@ -38,9 +40,9 @@ public class Pass1AddressOfVolatile extends Pass2SsaOptimization { if(value instanceof SymbolVariableRef) { Symbol toSymbol = getScope().getSymbol((SymbolVariableRef) value); if(toSymbol instanceof Variable) { - ((Variable) toSymbol).setInferredVolatile(true); + final Variable variable = (Variable) toSymbol; final String stmtStr = currentStmt==null?toSymbol.toString(getProgram()):currentStmt.toString(getProgram(), false); - getLog().append("Setting inferred volatile on symbol affected by address-of " + stmtStr); + updateAddressOfVariable(variable, stmtStr); } } } @@ -48,5 +50,15 @@ public class Pass1AddressOfVolatile extends Pass2SsaOptimization { return false; } + private void updateAddressOfVariable(Variable variable, String stmtStr) { + if(variable.getType() instanceof SymbolTypeStruct) { + variable.setKind(Variable.Kind.LOAD_STORE); + getLog().append("Setting struct to load/store in variable affected by address-of " + stmtStr); + } else { + variable.setInferredVolatile(true); + getLog().append("Setting inferred volatile on symbol affected by address-of " + stmtStr); + } + } + } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2AssertTypeMatch.java b/src/main/java/dk/camelot64/kickc/passes/PassNAssertTypeMatch.java similarity index 89% rename from src/main/java/dk/camelot64/kickc/passes/Pass2AssertTypeMatch.java rename to src/main/java/dk/camelot64/kickc/passes/PassNAssertTypeMatch.java index f23dcc729..064cc3af1 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2AssertTypeMatch.java +++ b/src/main/java/dk/camelot64/kickc/passes/PassNAssertTypeMatch.java @@ -5,20 +5,18 @@ import dk.camelot64.kickc.model.ControlFlowBlock; import dk.camelot64.kickc.model.Program; import dk.camelot64.kickc.model.statements.Statement; import dk.camelot64.kickc.model.statements.StatementAssignment; -import dk.camelot64.kickc.model.statements.StatementConditionalJump; import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolTypeConversion; import dk.camelot64.kickc.model.types.SymbolTypeInference; import dk.camelot64.kickc.model.values.AssignmentRValue; import dk.camelot64.kickc.model.values.LValue; -import dk.camelot64.kickc.model.values.RValue; /** * Asserts that types match in all assignments and calculations */ -public class Pass2AssertTypeMatch extends Pass2SsaAssertion { +public class PassNAssertTypeMatch extends Pass2SsaAssertion { - public Pass2AssertTypeMatch(Program program) { + public PassNAssertTypeMatch(Program program) { super(program); } diff --git a/src/main/java/dk/camelot64/kickc/passes/unwinding/ValueSourceStructValueList.java b/src/main/java/dk/camelot64/kickc/passes/unwinding/ValueSourceStructValueList.java index c70ba6ecb..d87e7a1f9 100644 --- a/src/main/java/dk/camelot64/kickc/passes/unwinding/ValueSourceStructValueList.java +++ b/src/main/java/dk/camelot64/kickc/passes/unwinding/ValueSourceStructValueList.java @@ -59,8 +59,7 @@ public class ValueSourceStructValueList extends ValueSourceBase { public ValueSource getMemberUnwinding(String memberName, Program program, ProgramScope programScope, Statement currentStmt, ListIterator stmtIt, ControlFlowBlock currentBlock) { int memberIndex = getMemberNames(programScope).indexOf(memberName); final RValue memberValue = valueList.getList().get(memberIndex); - final ValueSource valueSource = ValueSourceFactory.getValueSource(memberValue, program, programScope, currentStmt, stmtIt, currentBlock); - return valueSource; + return ValueSourceFactory.getValueSource(memberValue, program, programScope, currentStmt, stmtIt, currentBlock); } } diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index bcdfcb22f..a943879b4 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -976,12 +976,10 @@ public class TestPrograms { // compileAndCompare("struct-ptr-29"); //} - // TODO: Fix problem with stack-allocated structs that contain arrays! - // https://gitlab.com/camelot/kickc/issues/314 - //@Test - //public void testStructPtr28() throws IOException, URISyntaxException { - // compileAndCompare("struct-ptr-28"); - //} + @Test + public void testStructPtr28() throws IOException, URISyntaxException { + compileAndCompare("struct-ptr-28"); + } @Test public void testStructPtr26() throws IOException, URISyntaxException { diff --git a/src/test/ref/declared-memory-var-3.log b/src/test/ref/declared-memory-var-3.log index 77197dc36..73e399b50 100644 --- a/src/test/ref/declared-memory-var-3.log +++ b/src/test/ref/declared-memory-var-3.log @@ -1,4 +1,4 @@ -Setting inferred volatile on symbol affected by address-of (struct foo*) main::barp ← &(struct foo) bar +Setting struct to load/store in variable affected by address-of (struct foo*) main::barp ← &(struct foo) bar Replacing struct member reference *((struct foo*) main::barp).thing1 with member unwinding reference *((byte*~) main::$0) Replacing struct member reference *((struct foo*) main::barp).thing2 with member unwinding reference *((byte*~) main::$1) Identified constant variable (struct foo*) main::barp diff --git a/src/test/ref/declared-memory-var-4.log b/src/test/ref/declared-memory-var-4.log index 02617a110..d24914f5b 100644 --- a/src/test/ref/declared-memory-var-4.log +++ b/src/test/ref/declared-memory-var-4.log @@ -2,7 +2,7 @@ Fixing struct type size struct foo to 14 Fixing struct type size struct foo to 14 Fixing struct type SIZE_OF struct foo to 14 Fixing struct type SIZE_OF struct foo to 14 -Setting inferred volatile on symbol affected by address-of (struct foo*) main::barp ← &(struct foo) bar +Setting struct to load/store in variable affected by address-of (struct foo*) main::barp ← &(struct foo) bar Replacing struct member reference *((struct foo*) main::barp).thing1 with member unwinding reference *((byte*~) main::$1) Replacing struct member reference *((struct foo*) main::barp).thing2 with member unwinding reference *((byte*~) main::$2) Replacing struct member reference *((struct foo*) main::barp).thing3 with member unwinding reference (byte*~) main::$3 diff --git a/src/test/ref/parse-negated-struct-ref.log b/src/test/ref/parse-negated-struct-ref.log index a284ca0c1..1ffcb345b 100644 --- a/src/test/ref/parse-negated-struct-ref.log +++ b/src/test/ref/parse-negated-struct-ref.log @@ -1,4 +1,4 @@ -Setting inferred volatile on symbol affected by address-of (struct A*) main::a ← &(struct A) aa +Setting struct to load/store in variable affected by address-of (struct A*) main::a ← &(struct A) aa Replacing struct member reference *((struct A*) main::a).b with member unwinding reference *((byte*~) main::$2) Warning! Adding boolean cast to non-boolean sub-expression *((byte*~) main::$2) Identified constant variable (struct A*) main::a diff --git a/src/test/ref/struct-21.log b/src/test/ref/struct-21.log index d42d5d4eb..d792ea277 100644 --- a/src/test/ref/struct-21.log +++ b/src/test/ref/struct-21.log @@ -1,4 +1,4 @@ -Setting inferred volatile on symbol affected by address-of (struct Point*) main::ptr ← &(struct Point) main::point1 +Setting struct to load/store in variable affected by address-of (struct Point*) main::ptr ← &(struct Point) main::point1 Adding value bulk copy *(&(struct Point) main::point1) ← memcpy(*(&(const struct Point) $0), struct Point, (const byte) SIZEOF_STRUCT_POINT) Replacing struct member reference *((struct Point*) main::ptr).x with member unwinding reference *((byte*~) main::$0) Replacing struct member reference *((struct Point*) main::ptr).y with member unwinding reference *((byte*~) main::$1) diff --git a/src/test/ref/struct-35.log b/src/test/ref/struct-35.log index 5d785abb3..6dda12b43 100644 --- a/src/test/ref/struct-35.log +++ b/src/test/ref/struct-35.log @@ -1,4 +1,4 @@ -Setting inferred volatile on symbol affected by address-of (struct Point*) main::p2 ← &(struct Point) point2 +Setting struct to load/store in variable affected by address-of (struct Point*) main::p2 ← &(struct Point) point2 Adding value bulk copy *((struct Point*) main::p2) ← memcpy(*(&(struct Point) point1), struct Point, (const byte) SIZEOF_STRUCT_POINT) Replacing struct member reference (struct Point) point2.x with member unwinding reference *((byte*)&(struct Point) point2+(const byte) OFFSET_STRUCT_POINT_X) Replacing struct member reference (struct Point) point2.y with member unwinding reference *((byte*)&(struct Point) point2+(const byte) OFFSET_STRUCT_POINT_Y) diff --git a/src/test/ref/struct-ptr-12.log b/src/test/ref/struct-ptr-12.log index ecdd29810..74c8a3b35 100644 --- a/src/test/ref/struct-ptr-12.log +++ b/src/test/ref/struct-ptr-12.log @@ -1,4 +1,4 @@ -Setting inferred volatile on symbol affected by address-of (struct Point*) main::q ← &(struct Point) main::p +Setting struct to load/store in variable affected by address-of (struct Point*) main::q ← &(struct Point) main::p Adding value bulk copy *(&(struct Point) main::p) ← memcpy(*(&(const struct Point) $0), struct Point, (const byte) SIZEOF_STRUCT_POINT) Replacing struct member reference *((struct Point*) main::q).x with member unwinding reference *((byte*~) main::$0) Replacing struct member reference *((struct Point*) main::q).y with member unwinding reference *((byte*~) main::$1) diff --git a/src/test/ref/struct-ptr-14.log b/src/test/ref/struct-ptr-14.log index 9f5cc4ad5..a00dcb42e 100644 --- a/src/test/ref/struct-ptr-14.log +++ b/src/test/ref/struct-ptr-14.log @@ -1,4 +1,4 @@ -Setting inferred volatile on symbol affected by address-of (struct Point*) main::q ← &(struct Point) main::p +Setting struct to load/store in variable affected by address-of (struct Point*) main::q ← &(struct Point) main::p Adding value bulk copy *(&(struct Point) main::p) ← memcpy(*(&(const struct Point) $0), struct Point, (const byte) SIZEOF_STRUCT_POINT) Replacing struct member reference *((struct Point*) main::q).x with member unwinding reference *((byte*~) main::$1) Replacing struct member reference *((struct Point*) main::q).y with member unwinding reference *((byte*~) main::$2) diff --git a/src/test/ref/struct-ptr-19.asm b/src/test/ref/struct-ptr-19.asm index 2dc776e8b..b36cb9c89 100644 --- a/src/test/ref/struct-ptr-19.asm +++ b/src/test/ref/struct-ptr-19.asm @@ -3,18 +3,20 @@ :BasicUpstart(main) .pc = $80d "Program" .label SCREEN = $400 + .const SIZEOF_STRUCT_POINT = 2 .const OFFSET_STRUCT_POINT_Y = 1 .label idx = 2 main: { - .label ptr = point_x - .label point_x = 3 - .label point_y = 4 - lda #1 - sta.z point_x - lda #2 - sta.z point_y - ldy.z point_x - tax + .label ptr = point + .label point = 3 + ldy #SIZEOF_STRUCT_POINT + !: + lda __0-1,y + sta point-1,y + dey + bne !- + ldy.z point + ldx point+OFFSET_STRUCT_POINT_Y lda #0 sta.z idx jsr print @@ -35,3 +37,4 @@ print: { sty.z idx rts } + __0: .byte 1, 2 diff --git a/src/test/ref/struct-ptr-19.cfg b/src/test/ref/struct-ptr-19.cfg index 42e40a32c..8901ed3ef 100644 --- a/src/test/ref/struct-ptr-19.cfg +++ b/src/test/ref/struct-ptr-19.cfg @@ -10,31 +10,30 @@ (void()) main() main: scope:[main] from @1 - [4] (byte) main::point_x#0 ← (byte) 1 - [5] (byte) main::point_y#0 ← (byte) 2 - [6] (byte) print::p_x#0 ← (byte) main::point_x#0 - [7] (byte) print::p_y#0 ← (byte) main::point_y#0 - [8] call print + [4] *(&(struct Point) main::point) ← memcpy(*(&(const struct Point) $0), struct Point, (const byte) SIZEOF_STRUCT_POINT) + [5] (byte) print::p_x#0 ← *((byte*)&(struct Point) main::point) + [6] (byte) print::p_y#0 ← *((byte*)&(struct Point) main::point+(const byte) OFFSET_STRUCT_POINT_Y) + [7] call print to:main::@1 main::@1: scope:[main] from main - [9] (byte) print::p_x#1 ← *((byte*)(const struct Point*) main::ptr) - [10] (byte) print::p_y#1 ← *((byte*)(const struct Point*) main::ptr+(const byte) OFFSET_STRUCT_POINT_Y) - [11] call print + [8] (byte) print::p_x#1 ← *((byte*)(const struct Point*) main::ptr) + [9] (byte) print::p_y#1 ← *((byte*)(const struct Point*) main::ptr+(const byte) OFFSET_STRUCT_POINT_Y) + [10] call print to:main::@return main::@return: scope:[main] from main::@1 - [12] return + [11] return to:@return (void()) print((byte) print::p_x , (byte) print::p_y) print: scope:[print] from main main::@1 - [13] (byte) print::p_y#2 ← phi( main/(byte) print::p_y#0 main::@1/(byte) print::p_y#1 ) - [13] (byte) idx#11 ← phi( main/(byte) 0 main::@1/(byte) idx#12 ) - [13] (byte) print::p_x#2 ← phi( main/(byte) print::p_x#0 main::@1/(byte) print::p_x#1 ) - [14] *((const byte*) SCREEN + (byte) idx#11) ← (byte) print::p_x#2 - [15] (byte) idx#4 ← ++ (byte) idx#11 - [16] *((const byte*) SCREEN + (byte) idx#4) ← (byte) print::p_y#2 - [17] (byte) idx#12 ← ++ (byte) idx#4 + [12] (byte) print::p_y#2 ← phi( main/(byte) print::p_y#0 main::@1/(byte) print::p_y#1 ) + [12] (byte) idx#11 ← phi( main/(byte) 0 main::@1/(byte) idx#12 ) + [12] (byte) print::p_x#2 ← phi( main/(byte) print::p_x#0 main::@1/(byte) print::p_x#1 ) + [13] *((const byte*) SCREEN + (byte) idx#11) ← (byte) print::p_x#2 + [14] (byte) idx#4 ← ++ (byte) idx#11 + [15] *((const byte*) SCREEN + (byte) idx#4) ← (byte) print::p_y#2 + [16] (byte) idx#12 ← ++ (byte) idx#4 to:print::@return print::@return: scope:[print] from print - [18] return + [17] return to:@return diff --git a/src/test/ref/struct-ptr-19.log b/src/test/ref/struct-ptr-19.log index c7dec280d..8958e933a 100644 --- a/src/test/ref/struct-ptr-19.log +++ b/src/test/ref/struct-ptr-19.log @@ -1,15 +1,10 @@ -Setting inferred volatile on symbol affected by address-of (struct Point*) main::ptr ← &(struct Point) main::point -Created struct value member variable (byte) main::point_x -Created struct value member variable (byte) main::point_y -Converted struct value to member variables (struct Point) main::point +Setting struct to load/store in variable affected by address-of (struct Point*) main::ptr ← &(struct Point) main::point Created struct value member variable (byte) print::p_x Created struct value member variable (byte) print::p_y Converted struct value to member variables (struct Point) print::p Converted procedure struct value parameter to member unwinding (void()) print((byte) print::p_x , (byte) print::p_y) -Unwinding value copy (struct Point) main::point ← { x: (byte) 1, y: (byte) 2 } -Adding value simple copy (byte) main::point_x ← (byte) 1 -Adding value simple copy (byte) main::point_y ← (byte) 2 -Converted procedure struct value parameter to member unwinding in call (void~) main::$0 ← call print (byte) main::point_x (byte) main::point_y +Adding value bulk copy *(&(struct Point) main::point) ← memcpy(*(&(const struct Point) $0), struct Point, (const byte) SIZEOF_STRUCT_POINT) +Converted procedure struct value parameter to member unwinding in call (void~) main::$0 ← call print *((byte*)&(struct Point) main::point+(const byte) OFFSET_STRUCT_POINT_X) *((byte*)&(struct Point) main::point+(const byte) OFFSET_STRUCT_POINT_Y) Converted procedure struct value parameter to member unwinding in call (void~) main::$1 ← call print *((byte*~) main::$2) *((byte*~) main::$3) Replacing struct member reference (struct Point) print::p.x with member unwinding reference (byte) print::p_x Replacing struct member reference (struct Point) print::p.y with member unwinding reference (byte) print::p_y @@ -24,11 +19,10 @@ CONTROL FLOW GRAPH SSA (void()) main() main: scope:[main] from @2 (byte) idx#14 ← phi( @2/(byte) idx#15 ) - (byte) main::point_x#0 ← (byte) 1 - (byte) main::point_y#0 ← (byte) 2 - (struct Point) main::point#0 ← struct-unwound {(byte) main::point_x#0, (byte) main::point_y#0} - (byte) print::p_x#0 ← (byte) main::point_x#0 - (byte) print::p_y#0 ← (byte) main::point_y#0 + *(&(struct Point) main::point) ← memcpy(*(&(const struct Point) $0), struct Point, (const byte) SIZEOF_STRUCT_POINT) + (struct Point) main::point ← struct-unwound {*(&(struct Point) main::point)} + (byte) print::p_x#0 ← *((byte*)&(struct Point) main::point+(const byte) OFFSET_STRUCT_POINT_X) + (byte) print::p_y#0 ← *((byte*)&(struct Point) main::point+(const byte) OFFSET_STRUCT_POINT_Y) call print to:main::@1 main::@1: scope:[main] from main @@ -76,6 +70,7 @@ print::@return: scope:[print] from print @end: scope:[] from @3 SYMBOL TABLE SSA +(const struct Point) $0 = { x: (byte) 1, y: (byte) 2 } (label) @2 (label) @3 (label) @begin @@ -85,6 +80,7 @@ SYMBOL TABLE SSA (byte) Point::x (byte) Point::y (const byte*) SCREEN = (byte*)(number) $400 +(const byte) SIZEOF_STRUCT_POINT = (byte) 2 (byte) idx (byte) idx#0 (byte) idx#1 @@ -108,12 +104,7 @@ SYMBOL TABLE SSA (label) main::@1 (label) main::@2 (label) main::@return -(struct Point) main::point -(struct Point) main::point#0 -(byte) main::point_x -(byte) main::point_x#0 -(byte) main::point_y -(byte) main::point_y#0 +(struct Point) main::point loadstore (const struct Point*) main::ptr = &(struct Point) main::point (void()) print((byte) print::p_x , (byte) print::p_y) (label) print::@return @@ -140,18 +131,17 @@ Identical Phi Values (byte) idx#1 (byte) idx#12 Identical Phi Values (byte) idx#10 (byte) idx#12 Identical Phi Values (byte) idx#13 (byte) idx#10 Successful SSA optimization Pass2IdenticalPhiElimination -Rewriting struct address-of to first member &(struct Point) main::point -Successful SSA optimization PassNStructAddressOfRewriting -Constant right-side identified [10] (byte*~) main::$2 ← (byte*)(const struct Point*) main::ptr + (const byte) OFFSET_STRUCT_POINT_X -Constant right-side identified [11] (byte*~) main::$3 ← (byte*)(const struct Point*) main::ptr + (const byte) OFFSET_STRUCT_POINT_Y +Removing C-classic struct-unwound assignment [3] (struct Point) main::point ← struct-unwound {*(&(struct Point) main::point)} +Constant right-side identified [9] (byte*~) main::$2 ← (byte*)(const struct Point*) main::ptr + (const byte) OFFSET_STRUCT_POINT_X +Constant right-side identified [10] (byte*~) main::$3 ← (byte*)(const struct Point*) main::ptr + (const byte) OFFSET_STRUCT_POINT_Y Successful SSA optimization Pass2ConstantRValueConsolidation Constant (const byte) idx#0 = 0 Constant (const byte*) main::$2 = (byte*)main::ptr+OFFSET_STRUCT_POINT_X Constant (const byte*) main::$3 = (byte*)main::ptr+OFFSET_STRUCT_POINT_Y Successful SSA optimization Pass2ConstantIdentification Simplifying expression containing zero (byte*)main::ptr in +Simplifying expression containing zero (byte*)&main::point in [4] (byte) print::p_x#0 ← *((byte*)&(struct Point) main::point+(const byte) OFFSET_STRUCT_POINT_X) Successful SSA optimization PassNSimplifyExpressionWithZero -Eliminating unused variable (struct Point) main::point#0 and assignment [2] (struct Point) main::point#0 ← struct-unwound {(byte) main::point_x#0, (byte) main::point_y#0} Eliminating unused constant (const byte) OFFSET_STRUCT_POINT_X Successful SSA optimization PassNEliminateUnusedVars Inlining constant with var siblings (const byte) idx#0 @@ -166,14 +156,14 @@ Adding NOP phi() at start of @end Adding NOP phi() at start of main::@2 CALL GRAPH Calls in [] to main:2 -Calls in [main] to print:11 print:17 +Calls in [main] to print:10 print:16 Created 3 initial phi equivalence classes -Coalesced [9] print::p_x#3 ← print::p_x#0 -Coalesced [10] print::p_y#3 ← print::p_y#0 -Coalesced [14] print::p_x#4 ← print::p_x#1 -Coalesced [15] idx#16 ← idx#12 -Coalesced [16] print::p_y#4 ← print::p_y#1 +Coalesced [8] print::p_x#3 ← print::p_x#0 +Coalesced [9] print::p_y#3 ← print::p_y#0 +Coalesced [13] print::p_x#4 ← print::p_x#1 +Coalesced [14] idx#16 ← idx#12 +Coalesced [15] print::p_y#4 ← print::p_y#1 Coalesced down to 3 phi equivalence classes Culled Empty Block (label) @3 Culled Empty Block (label) main::@2 @@ -195,33 +185,32 @@ FINAL CONTROL FLOW GRAPH (void()) main() main: scope:[main] from @1 - [4] (byte) main::point_x#0 ← (byte) 1 - [5] (byte) main::point_y#0 ← (byte) 2 - [6] (byte) print::p_x#0 ← (byte) main::point_x#0 - [7] (byte) print::p_y#0 ← (byte) main::point_y#0 - [8] call print + [4] *(&(struct Point) main::point) ← memcpy(*(&(const struct Point) $0), struct Point, (const byte) SIZEOF_STRUCT_POINT) + [5] (byte) print::p_x#0 ← *((byte*)&(struct Point) main::point) + [6] (byte) print::p_y#0 ← *((byte*)&(struct Point) main::point+(const byte) OFFSET_STRUCT_POINT_Y) + [7] call print to:main::@1 main::@1: scope:[main] from main - [9] (byte) print::p_x#1 ← *((byte*)(const struct Point*) main::ptr) - [10] (byte) print::p_y#1 ← *((byte*)(const struct Point*) main::ptr+(const byte) OFFSET_STRUCT_POINT_Y) - [11] call print + [8] (byte) print::p_x#1 ← *((byte*)(const struct Point*) main::ptr) + [9] (byte) print::p_y#1 ← *((byte*)(const struct Point*) main::ptr+(const byte) OFFSET_STRUCT_POINT_Y) + [10] call print to:main::@return main::@return: scope:[main] from main::@1 - [12] return + [11] return to:@return (void()) print((byte) print::p_x , (byte) print::p_y) print: scope:[print] from main main::@1 - [13] (byte) print::p_y#2 ← phi( main/(byte) print::p_y#0 main::@1/(byte) print::p_y#1 ) - [13] (byte) idx#11 ← phi( main/(byte) 0 main::@1/(byte) idx#12 ) - [13] (byte) print::p_x#2 ← phi( main/(byte) print::p_x#0 main::@1/(byte) print::p_x#1 ) - [14] *((const byte*) SCREEN + (byte) idx#11) ← (byte) print::p_x#2 - [15] (byte) idx#4 ← ++ (byte) idx#11 - [16] *((const byte*) SCREEN + (byte) idx#4) ← (byte) print::p_y#2 - [17] (byte) idx#12 ← ++ (byte) idx#4 + [12] (byte) print::p_y#2 ← phi( main/(byte) print::p_y#0 main::@1/(byte) print::p_y#1 ) + [12] (byte) idx#11 ← phi( main/(byte) 0 main::@1/(byte) idx#12 ) + [12] (byte) print::p_x#2 ← phi( main/(byte) print::p_x#0 main::@1/(byte) print::p_x#1 ) + [13] *((const byte*) SCREEN + (byte) idx#11) ← (byte) print::p_x#2 + [14] (byte) idx#4 ← ++ (byte) idx#11 + [15] *((const byte*) SCREEN + (byte) idx#4) ← (byte) print::p_y#2 + [16] (byte) idx#12 ← ++ (byte) idx#4 to:print::@return print::@return: scope:[print] from print - [18] return + [17] return to:@return @@ -233,11 +222,7 @@ VARIABLE REGISTER WEIGHTS (byte) idx#12 0.8 (byte) idx#4 3.0 (void()) main() -(struct Point) main::point -(byte) main::point_x -(byte) main::point_x#0 2.0 -(byte) main::point_y -(byte) main::point_y#0 2.0 +(struct Point) main::point loadstore (void()) print((byte) print::p_x , (byte) print::p_y) (struct Point) print::p (byte) print::p_x @@ -254,19 +239,18 @@ Initial phi equivalence classes [ idx#11 idx#12 ] [ print::p_y#2 print::p_y#0 print::p_y#1 ] Added variable idx#4 to live range equivalence class [ idx#4 ] +Added variable main::point to live range equivalence class [ main::point ] Complete equivalence classes [ print::p_x#2 print::p_x#0 print::p_x#1 ] [ idx#11 idx#12 ] [ print::p_y#2 print::p_y#0 print::p_y#1 ] -[ main::point_x#0 ] -[ main::point_y#0 ] [ idx#4 ] +[ main::point ] Allocated zp[1]:2 [ print::p_x#2 print::p_x#0 print::p_x#1 ] Allocated zp[1]:3 [ idx#11 idx#12 ] Allocated zp[1]:4 [ print::p_y#2 print::p_y#0 print::p_y#1 ] -Allocated zp[1]:5 [ main::point_x#0 ] -Allocated zp[1]:6 [ main::point_y#0 ] -Allocated zp[1]:7 [ idx#4 ] +Allocated zp[1]:5 [ idx#4 ] +Allocated zp[2]:6 [ main::point ] INITIAL ASM Target platform is c64basic / MOS6502X @@ -278,8 +262,9 @@ Target platform is c64basic / MOS6502X .pc = $80d "Program" // Global Constants & labels .label SCREEN = $400 + .const SIZEOF_STRUCT_POINT = 2 .const OFFSET_STRUCT_POINT_Y = 1 - .label idx = 7 + .label idx = 5 .label idx_1 = 3 // @begin __bbegin: @@ -297,50 +282,50 @@ __bend_from___b1: __bend: // main main: { - .label ptr = point_x - .label point_x = 5 - .label point_y = 6 - // [4] (byte) main::point_x#0 ← (byte) 1 -- vbuz1=vbuc1 - lda #1 - sta.z point_x - // [5] (byte) main::point_y#0 ← (byte) 2 -- vbuz1=vbuc1 - lda #2 - sta.z point_y - // [6] (byte) print::p_x#0 ← (byte) main::point_x#0 -- vbuz1=vbuz2 - lda.z point_x + .label ptr = point + .label point = 6 + // [4] *(&(struct Point) main::point) ← memcpy(*(&(const struct Point) $0), struct Point, (const byte) SIZEOF_STRUCT_POINT) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3 + ldy #SIZEOF_STRUCT_POINT + !: + lda __0-1,y + sta point-1,y + dey + bne !- + // [5] (byte) print::p_x#0 ← *((byte*)&(struct Point) main::point) -- vbuz1=_deref_pbuc1 + lda.z point sta.z print.p_x - // [7] (byte) print::p_y#0 ← (byte) main::point_y#0 -- vbuz1=vbuz2 - lda.z point_y + // [6] (byte) print::p_y#0 ← *((byte*)&(struct Point) main::point+(const byte) OFFSET_STRUCT_POINT_Y) -- vbuz1=_deref_pbuc1 + lda point+OFFSET_STRUCT_POINT_Y sta.z print.p_y - // [8] call print - // [13] phi from main to print [phi:main->print] + // [7] call print + // [12] phi from main to print [phi:main->print] print_from_main: - // [13] phi (byte) print::p_y#2 = (byte) print::p_y#0 [phi:main->print#0] -- register_copy - // [13] phi (byte) idx#11 = (byte) 0 [phi:main->print#1] -- vbuz1=vbuc1 + // [12] phi (byte) print::p_y#2 = (byte) print::p_y#0 [phi:main->print#0] -- register_copy + // [12] phi (byte) idx#11 = (byte) 0 [phi:main->print#1] -- vbuz1=vbuc1 lda #0 sta.z idx_1 - // [13] phi (byte) print::p_x#2 = (byte) print::p_x#0 [phi:main->print#2] -- register_copy + // [12] phi (byte) print::p_x#2 = (byte) print::p_x#0 [phi:main->print#2] -- register_copy jsr print jmp __b1 // main::@1 __b1: - // [9] (byte) print::p_x#1 ← *((byte*)(const struct Point*) main::ptr) -- vbuz1=_deref_pbuc1 + // [8] (byte) print::p_x#1 ← *((byte*)(const struct Point*) main::ptr) -- vbuz1=_deref_pbuc1 lda.z ptr sta.z print.p_x - // [10] (byte) print::p_y#1 ← *((byte*)(const struct Point*) main::ptr+(const byte) OFFSET_STRUCT_POINT_Y) -- vbuz1=_deref_pbuc1 + // [9] (byte) print::p_y#1 ← *((byte*)(const struct Point*) main::ptr+(const byte) OFFSET_STRUCT_POINT_Y) -- vbuz1=_deref_pbuc1 lda ptr+OFFSET_STRUCT_POINT_Y sta.z print.p_y - // [11] call print - // [13] phi from main::@1 to print [phi:main::@1->print] + // [10] call print + // [12] phi from main::@1 to print [phi:main::@1->print] print_from___b1: - // [13] phi (byte) print::p_y#2 = (byte) print::p_y#1 [phi:main::@1->print#0] -- register_copy - // [13] phi (byte) idx#11 = (byte) idx#12 [phi:main::@1->print#1] -- register_copy - // [13] phi (byte) print::p_x#2 = (byte) print::p_x#1 [phi:main::@1->print#2] -- register_copy + // [12] phi (byte) print::p_y#2 = (byte) print::p_y#1 [phi:main::@1->print#0] -- register_copy + // [12] phi (byte) idx#11 = (byte) idx#12 [phi:main::@1->print#1] -- register_copy + // [12] phi (byte) print::p_x#2 = (byte) print::p_x#1 [phi:main::@1->print#2] -- register_copy jsr print jmp __breturn // main::@return __breturn: - // [12] return + // [11] return rts } // print @@ -348,59 +333,53 @@ main: { print: { .label p_x = 2 .label p_y = 4 - // [14] *((const byte*) SCREEN + (byte) idx#11) ← (byte) print::p_x#2 -- pbuc1_derefidx_vbuz1=vbuz2 + // [13] *((const byte*) SCREEN + (byte) idx#11) ← (byte) print::p_x#2 -- pbuc1_derefidx_vbuz1=vbuz2 lda.z p_x ldy.z idx_1 sta SCREEN,y - // [15] (byte) idx#4 ← ++ (byte) idx#11 -- vbuz1=_inc_vbuz2 + // [14] (byte) idx#4 ← ++ (byte) idx#11 -- vbuz1=_inc_vbuz2 ldy.z idx_1 iny sty.z idx - // [16] *((const byte*) SCREEN + (byte) idx#4) ← (byte) print::p_y#2 -- pbuc1_derefidx_vbuz1=vbuz2 + // [15] *((const byte*) SCREEN + (byte) idx#4) ← (byte) print::p_y#2 -- pbuc1_derefidx_vbuz1=vbuz2 lda.z p_y ldy.z idx sta SCREEN,y - // [17] (byte) idx#12 ← ++ (byte) idx#4 -- vbuz1=_inc_vbuz2 + // [16] (byte) idx#12 ← ++ (byte) idx#4 -- vbuz1=_inc_vbuz2 ldy.z idx iny sty.z idx_1 jmp __breturn // print::@return __breturn: - // [18] return + // [17] return rts } // File Data + __0: .byte 1, 2 REGISTER UPLIFT POTENTIAL REGISTERS -Statement [4] (byte) main::point_x#0 ← (byte) 1 [ main::point_x#0 ] ( main:2 [ main::point_x#0 ] ) always clobbers reg byte a -Statement [5] (byte) main::point_y#0 ← (byte) 2 [ main::point_x#0 main::point_y#0 ] ( main:2 [ main::point_x#0 main::point_y#0 ] ) always clobbers reg byte a +Statement [4] *(&(struct Point) main::point) ← memcpy(*(&(const struct Point) $0), struct Point, (const byte) SIZEOF_STRUCT_POINT) [ main::point ] ( main:2 [ main::point ] ) always clobbers reg byte a reg byte y Potential registers zp[1]:2 [ print::p_x#2 print::p_x#0 print::p_x#1 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y , Potential registers zp[1]:3 [ idx#11 idx#12 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y , Potential registers zp[1]:4 [ print::p_y#2 print::p_y#0 print::p_y#1 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y , -Potential registers zp[1]:5 [ main::point_x#0 ] : zp[1]:5 , -Potential registers zp[1]:6 [ main::point_y#0 ] : zp[1]:6 , -Potential registers zp[1]:7 [ idx#4 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:5 [ idx#4 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y , +Potential registers zp[2]:6 [ main::point ] : zp[2]:6 , REGISTER UPLIFT SCOPES Uplift Scope [print] 10: zp[1]:2 [ print::p_x#2 print::p_x#0 print::p_x#1 ] 10: zp[1]:4 [ print::p_y#2 print::p_y#0 print::p_y#1 ] -Uplift Scope [] 3.8: zp[1]:3 [ idx#11 idx#12 ] 3: zp[1]:7 [ idx#4 ] -Uplift Scope [main] 2: zp[1]:5 [ main::point_x#0 ] 2: zp[1]:6 [ main::point_y#0 ] +Uplift Scope [] 3.8: zp[1]:3 [ idx#11 idx#12 ] 3: zp[1]:5 [ idx#4 ] Uplift Scope [Point] +Uplift Scope [main] 0: zp[2]:6 [ main::point ] -Uplifting [print] best 109 combination reg byte y [ print::p_x#2 print::p_x#0 print::p_x#1 ] reg byte x [ print::p_y#2 print::p_y#0 print::p_y#1 ] -Uplifting [] best 100 combination zp[1]:3 [ idx#11 idx#12 ] reg byte y [ idx#4 ] -Uplifting [main] best 100 combination zp[1]:5 [ main::point_x#0 ] zp[1]:6 [ main::point_y#0 ] -Uplifting [Point] best 100 combination +Uplifting [print] best 116 combination reg byte y [ print::p_x#2 print::p_x#0 print::p_x#1 ] reg byte x [ print::p_y#2 print::p_y#0 print::p_y#1 ] +Uplifting [] best 107 combination zp[1]:3 [ idx#11 idx#12 ] reg byte y [ idx#4 ] +Uplifting [Point] best 107 combination +Uplifting [main] best 107 combination zp[2]:6 [ main::point ] Attempting to uplift remaining variables inzp[1]:3 [ idx#11 idx#12 ] -Uplifting [] best 100 combination zp[1]:3 [ idx#11 idx#12 ] -Attempting to uplift remaining variables inzp[1]:5 [ main::point_x#0 ] -Uplifting [main] best 100 combination zp[1]:5 [ main::point_x#0 ] -Attempting to uplift remaining variables inzp[1]:6 [ main::point_y#0 ] -Uplifting [main] best 100 combination zp[1]:6 [ main::point_y#0 ] +Uplifting [] best 107 combination zp[1]:3 [ idx#11 idx#12 ] Allocated (was zp[1]:3) zp[1]:2 [ idx#11 idx#12 ] -Allocated (was zp[1]:5) zp[1]:3 [ main::point_x#0 ] -Allocated (was zp[1]:6) zp[1]:4 [ main::point_y#0 ] +Allocated (was zp[2]:6) zp[2]:3 [ main::point ] ASSEMBLER BEFORE OPTIMIZATION // File Comments @@ -411,6 +390,7 @@ ASSEMBLER BEFORE OPTIMIZATION .pc = $80d "Program" // Global Constants & labels .label SCREEN = $400 + .const SIZEOF_STRUCT_POINT = 2 .const OFFSET_STRUCT_POINT_Y = 1 .label idx = 2 // @begin @@ -429,71 +409,72 @@ __bend_from___b1: __bend: // main main: { - .label ptr = point_x - .label point_x = 3 - .label point_y = 4 - // [4] (byte) main::point_x#0 ← (byte) 1 -- vbuz1=vbuc1 - lda #1 - sta.z point_x - // [5] (byte) main::point_y#0 ← (byte) 2 -- vbuz1=vbuc1 - lda #2 - sta.z point_y - // [6] (byte) print::p_x#0 ← (byte) main::point_x#0 -- vbuyy=vbuz1 - ldy.z point_x - // [7] (byte) print::p_y#0 ← (byte) main::point_y#0 -- vbuxx=vbuz1 - ldx.z point_y - // [8] call print - // [13] phi from main to print [phi:main->print] + .label ptr = point + .label point = 3 + // [4] *(&(struct Point) main::point) ← memcpy(*(&(const struct Point) $0), struct Point, (const byte) SIZEOF_STRUCT_POINT) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3 + ldy #SIZEOF_STRUCT_POINT + !: + lda __0-1,y + sta point-1,y + dey + bne !- + // [5] (byte) print::p_x#0 ← *((byte*)&(struct Point) main::point) -- vbuyy=_deref_pbuc1 + ldy.z point + // [6] (byte) print::p_y#0 ← *((byte*)&(struct Point) main::point+(const byte) OFFSET_STRUCT_POINT_Y) -- vbuxx=_deref_pbuc1 + ldx point+OFFSET_STRUCT_POINT_Y + // [7] call print + // [12] phi from main to print [phi:main->print] print_from_main: - // [13] phi (byte) print::p_y#2 = (byte) print::p_y#0 [phi:main->print#0] -- register_copy - // [13] phi (byte) idx#11 = (byte) 0 [phi:main->print#1] -- vbuz1=vbuc1 + // [12] phi (byte) print::p_y#2 = (byte) print::p_y#0 [phi:main->print#0] -- register_copy + // [12] phi (byte) idx#11 = (byte) 0 [phi:main->print#1] -- vbuz1=vbuc1 lda #0 sta.z idx - // [13] phi (byte) print::p_x#2 = (byte) print::p_x#0 [phi:main->print#2] -- register_copy + // [12] phi (byte) print::p_x#2 = (byte) print::p_x#0 [phi:main->print#2] -- register_copy jsr print jmp __b1 // main::@1 __b1: - // [9] (byte) print::p_x#1 ← *((byte*)(const struct Point*) main::ptr) -- vbuyy=_deref_pbuc1 + // [8] (byte) print::p_x#1 ← *((byte*)(const struct Point*) main::ptr) -- vbuyy=_deref_pbuc1 ldy.z ptr - // [10] (byte) print::p_y#1 ← *((byte*)(const struct Point*) main::ptr+(const byte) OFFSET_STRUCT_POINT_Y) -- vbuxx=_deref_pbuc1 + // [9] (byte) print::p_y#1 ← *((byte*)(const struct Point*) main::ptr+(const byte) OFFSET_STRUCT_POINT_Y) -- vbuxx=_deref_pbuc1 ldx ptr+OFFSET_STRUCT_POINT_Y - // [11] call print - // [13] phi from main::@1 to print [phi:main::@1->print] + // [10] call print + // [12] phi from main::@1 to print [phi:main::@1->print] print_from___b1: - // [13] phi (byte) print::p_y#2 = (byte) print::p_y#1 [phi:main::@1->print#0] -- register_copy - // [13] phi (byte) idx#11 = (byte) idx#12 [phi:main::@1->print#1] -- register_copy - // [13] phi (byte) print::p_x#2 = (byte) print::p_x#1 [phi:main::@1->print#2] -- register_copy + // [12] phi (byte) print::p_y#2 = (byte) print::p_y#1 [phi:main::@1->print#0] -- register_copy + // [12] phi (byte) idx#11 = (byte) idx#12 [phi:main::@1->print#1] -- register_copy + // [12] phi (byte) print::p_x#2 = (byte) print::p_x#1 [phi:main::@1->print#2] -- register_copy jsr print jmp __breturn // main::@return __breturn: - // [12] return + // [11] return rts } // print // print(byte register(Y) p_x, byte register(X) p_y) print: { - // [14] *((const byte*) SCREEN + (byte) idx#11) ← (byte) print::p_x#2 -- pbuc1_derefidx_vbuz1=vbuyy + // [13] *((const byte*) SCREEN + (byte) idx#11) ← (byte) print::p_x#2 -- pbuc1_derefidx_vbuz1=vbuyy tya ldy.z idx sta SCREEN,y - // [15] (byte) idx#4 ← ++ (byte) idx#11 -- vbuyy=_inc_vbuz1 + // [14] (byte) idx#4 ← ++ (byte) idx#11 -- vbuyy=_inc_vbuz1 ldy.z idx iny - // [16] *((const byte*) SCREEN + (byte) idx#4) ← (byte) print::p_y#2 -- pbuc1_derefidx_vbuyy=vbuxx + // [15] *((const byte*) SCREEN + (byte) idx#4) ← (byte) print::p_y#2 -- pbuc1_derefidx_vbuyy=vbuxx txa sta SCREEN,y - // [17] (byte) idx#12 ← ++ (byte) idx#4 -- vbuz1=_inc_vbuyy + // [16] (byte) idx#12 ← ++ (byte) idx#4 -- vbuz1=_inc_vbuyy iny sty.z idx jmp __breturn // print::@return __breturn: - // [18] return + // [17] return rts } // File Data + __0: .byte 1, 2 ASSEMBLER OPTIMIZATIONS Removing instruction jmp __b1 @@ -502,7 +483,6 @@ Removing instruction jmp __b1 Removing instruction jmp __breturn Removing instruction jmp __breturn Succesful ASM optimization Pass5NextJumpElimination -Replacing instruction ldx.z point_y with TAX Removing instruction ldy.z idx Succesful ASM optimization Pass5UnnecesaryLoadElimination Replacing label __bbegin with __b1 @@ -524,6 +504,7 @@ Removing instruction __b1: Succesful ASM optimization Pass5UnusedLabelElimination FINAL SYMBOL TABLE +(const struct Point) $0 = { x: (byte) 1, y: (byte) 2 } (label) @1 (label) @begin (label) @end @@ -531,6 +512,7 @@ FINAL SYMBOL TABLE (byte) Point::x (byte) Point::y (const byte*) SCREEN = (byte*) 1024 +(const byte) SIZEOF_STRUCT_POINT = (byte) 2 (byte) idx (byte) idx#11 idx zp[1]:2 3.0 (byte) idx#12 idx zp[1]:2 0.8 @@ -538,12 +520,8 @@ FINAL SYMBOL TABLE (void()) main() (label) main::@1 (label) main::@return -(struct Point) main::point -(byte) main::point_x -(byte) main::point_x#0 point_x zp[1]:3 2.0 -(byte) main::point_y -(byte) main::point_y#0 point_y zp[1]:4 2.0 -(const struct Point*) main::ptr = (struct Point*)&(byte) main::point_x#0 +(struct Point) main::point loadstore zp[2]:3 +(const struct Point*) main::ptr = &(struct Point) main::point (void()) print((byte) print::p_x , (byte) print::p_y) (label) print::@return (struct Point) print::p @@ -559,13 +537,12 @@ FINAL SYMBOL TABLE reg byte y [ print::p_x#2 print::p_x#0 print::p_x#1 ] zp[1]:2 [ idx#11 idx#12 ] reg byte x [ print::p_y#2 print::p_y#0 print::p_y#1 ] -zp[1]:3 [ main::point_x#0 ] -zp[1]:4 [ main::point_y#0 ] reg byte y [ idx#4 ] +zp[2]:3 [ main::point ] FINAL ASSEMBLER -Score: 75 +Score: 83 // File Comments // Demonstrates problem with passing struct pointer deref as parameter to call @@ -575,6 +552,7 @@ Score: 75 .pc = $80d "Program" // Global Constants & labels .label SCREEN = $400 + .const SIZEOF_STRUCT_POINT = 2 .const OFFSET_STRUCT_POINT_Y = 1 .label idx = 2 // @begin @@ -585,69 +563,70 @@ Score: 75 // @end // main main: { - .label ptr = point_x - .label point_x = 3 - .label point_y = 4 + .label ptr = point + .label point = 3 // point = { 1, 2 } - // [4] (byte) main::point_x#0 ← (byte) 1 -- vbuz1=vbuc1 - lda #1 - sta.z point_x - // [5] (byte) main::point_y#0 ← (byte) 2 -- vbuz1=vbuc1 - lda #2 - sta.z point_y + // [4] *(&(struct Point) main::point) ← memcpy(*(&(const struct Point) $0), struct Point, (const byte) SIZEOF_STRUCT_POINT) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3 + ldy #SIZEOF_STRUCT_POINT + !: + lda __0-1,y + sta point-1,y + dey + bne !- // print(point) - // [6] (byte) print::p_x#0 ← (byte) main::point_x#0 -- vbuyy=vbuz1 - ldy.z point_x - // [7] (byte) print::p_y#0 ← (byte) main::point_y#0 -- vbuxx=vbuz1 - tax - // [8] call print - // [13] phi from main to print [phi:main->print] - // [13] phi (byte) print::p_y#2 = (byte) print::p_y#0 [phi:main->print#0] -- register_copy - // [13] phi (byte) idx#11 = (byte) 0 [phi:main->print#1] -- vbuz1=vbuc1 + // [5] (byte) print::p_x#0 ← *((byte*)&(struct Point) main::point) -- vbuyy=_deref_pbuc1 + ldy.z point + // [6] (byte) print::p_y#0 ← *((byte*)&(struct Point) main::point+(const byte) OFFSET_STRUCT_POINT_Y) -- vbuxx=_deref_pbuc1 + ldx point+OFFSET_STRUCT_POINT_Y + // [7] call print + // [12] phi from main to print [phi:main->print] + // [12] phi (byte) print::p_y#2 = (byte) print::p_y#0 [phi:main->print#0] -- register_copy + // [12] phi (byte) idx#11 = (byte) 0 [phi:main->print#1] -- vbuz1=vbuc1 lda #0 sta.z idx - // [13] phi (byte) print::p_x#2 = (byte) print::p_x#0 [phi:main->print#2] -- register_copy + // [12] phi (byte) print::p_x#2 = (byte) print::p_x#0 [phi:main->print#2] -- register_copy jsr print // main::@1 // print(*ptr) - // [9] (byte) print::p_x#1 ← *((byte*)(const struct Point*) main::ptr) -- vbuyy=_deref_pbuc1 + // [8] (byte) print::p_x#1 ← *((byte*)(const struct Point*) main::ptr) -- vbuyy=_deref_pbuc1 ldy.z ptr - // [10] (byte) print::p_y#1 ← *((byte*)(const struct Point*) main::ptr+(const byte) OFFSET_STRUCT_POINT_Y) -- vbuxx=_deref_pbuc1 + // [9] (byte) print::p_y#1 ← *((byte*)(const struct Point*) main::ptr+(const byte) OFFSET_STRUCT_POINT_Y) -- vbuxx=_deref_pbuc1 ldx ptr+OFFSET_STRUCT_POINT_Y - // [11] call print - // [13] phi from main::@1 to print [phi:main::@1->print] - // [13] phi (byte) print::p_y#2 = (byte) print::p_y#1 [phi:main::@1->print#0] -- register_copy - // [13] phi (byte) idx#11 = (byte) idx#12 [phi:main::@1->print#1] -- register_copy - // [13] phi (byte) print::p_x#2 = (byte) print::p_x#1 [phi:main::@1->print#2] -- register_copy + // [10] call print + // [12] phi from main::@1 to print [phi:main::@1->print] + // [12] phi (byte) print::p_y#2 = (byte) print::p_y#1 [phi:main::@1->print#0] -- register_copy + // [12] phi (byte) idx#11 = (byte) idx#12 [phi:main::@1->print#1] -- register_copy + // [12] phi (byte) print::p_x#2 = (byte) print::p_x#1 [phi:main::@1->print#2] -- register_copy jsr print // main::@return // } - // [12] return + // [11] return rts } // print // print(byte register(Y) p_x, byte register(X) p_y) print: { // SCREEN[idx++] = p.x - // [14] *((const byte*) SCREEN + (byte) idx#11) ← (byte) print::p_x#2 -- pbuc1_derefidx_vbuz1=vbuyy + // [13] *((const byte*) SCREEN + (byte) idx#11) ← (byte) print::p_x#2 -- pbuc1_derefidx_vbuz1=vbuyy tya ldy.z idx sta SCREEN,y // SCREEN[idx++] = p.x; - // [15] (byte) idx#4 ← ++ (byte) idx#11 -- vbuyy=_inc_vbuz1 + // [14] (byte) idx#4 ← ++ (byte) idx#11 -- vbuyy=_inc_vbuz1 iny // SCREEN[idx++] = p.y - // [16] *((const byte*) SCREEN + (byte) idx#4) ← (byte) print::p_y#2 -- pbuc1_derefidx_vbuyy=vbuxx + // [15] *((const byte*) SCREEN + (byte) idx#4) ← (byte) print::p_y#2 -- pbuc1_derefidx_vbuyy=vbuxx txa sta SCREEN,y // SCREEN[idx++] = p.y; - // [17] (byte) idx#12 ← ++ (byte) idx#4 -- vbuz1=_inc_vbuyy + // [16] (byte) idx#12 ← ++ (byte) idx#4 -- vbuz1=_inc_vbuyy iny sty.z idx // print::@return // } - // [18] return + // [17] return rts } // File Data + __0: .byte 1, 2 diff --git a/src/test/ref/struct-ptr-19.sym b/src/test/ref/struct-ptr-19.sym index 82bd9fecf..ebe6b8af3 100644 --- a/src/test/ref/struct-ptr-19.sym +++ b/src/test/ref/struct-ptr-19.sym @@ -1,3 +1,4 @@ +(const struct Point) $0 = { x: (byte) 1, y: (byte) 2 } (label) @1 (label) @begin (label) @end @@ -5,6 +6,7 @@ (byte) Point::x (byte) Point::y (const byte*) SCREEN = (byte*) 1024 +(const byte) SIZEOF_STRUCT_POINT = (byte) 2 (byte) idx (byte) idx#11 idx zp[1]:2 3.0 (byte) idx#12 idx zp[1]:2 0.8 @@ -12,12 +14,8 @@ (void()) main() (label) main::@1 (label) main::@return -(struct Point) main::point -(byte) main::point_x -(byte) main::point_x#0 point_x zp[1]:3 2.0 -(byte) main::point_y -(byte) main::point_y#0 point_y zp[1]:4 2.0 -(const struct Point*) main::ptr = (struct Point*)&(byte) main::point_x#0 +(struct Point) main::point loadstore zp[2]:3 +(const struct Point*) main::ptr = &(struct Point) main::point (void()) print((byte) print::p_x , (byte) print::p_y) (label) print::@return (struct Point) print::p @@ -33,6 +31,5 @@ reg byte y [ print::p_x#2 print::p_x#0 print::p_x#1 ] zp[1]:2 [ idx#11 idx#12 ] reg byte x [ print::p_y#2 print::p_y#0 print::p_y#1 ] -zp[1]:3 [ main::point_x#0 ] -zp[1]:4 [ main::point_y#0 ] reg byte y [ idx#4 ] +zp[2]:3 [ main::point ] diff --git a/src/test/ref/struct-ptr-28.asm b/src/test/ref/struct-ptr-28.asm index 6fa082f4b..7944c57f7 100644 --- a/src/test/ref/struct-ptr-28.asm +++ b/src/test/ref/struct-ptr-28.asm @@ -1,48 +1,44 @@ // Example of a struct containing an array // It works on the surface - but illustrates the problem with structs containing arrays treating them like pointers. -// https://gitlab.com/camelot/kickc/issues/312 +// https://gitlab.com/camelot/kickc/issues/314 .pc = $801 "Basic" :BasicUpstart(main) .pc = $80d "Program" - .const OFFSET_STRUCT_PERSON_NAME = 1 .label SCREEN = $400 + .const SIZEOF_STRUCT_PERSON = $11 + .const OFFSET_STRUCT_PERSON_NAME = 1 main: { - .label jesper_id = 5 - .label jesper_name = 6 - .label henriette_id = 8 - .label henriette_name = 9 - lda #4 - sta.z jesper_id - lda #<_4 - sta.z jesper_name - lda #>_4 - sta.z jesper_name+1 + .label jesper = 8 + .label henriette = $19 + ldy #SIZEOF_STRUCT_PERSON + !: + lda __0-1,y + sta jesper-1,y + dey + bne !- ldx #0 - lda #jesper_id + lda #>jesper sta.z print_person.person+1 jsr print_person - lda #7 - sta.z henriette_id - lda #<_5 - sta.z henriette_name - lda #>_5 - sta.z henriette_name+1 - lda #henriette_id + lda #>henriette sta.z print_person.person+1 jsr print_person rts - _4: .text "jesper" - .byte 0 - _5: .text "henriette" - .byte 0 } -// print_person(struct Person* zeropage(2) person) +// print_person(struct Person* zp(2) person) print_person: { - .label i = 4 + .label __1 = 4 + .label __2 = 6 .label person = 2 ldy #0 lda (person),y @@ -53,36 +49,43 @@ print_person: { lda #' ' sta SCREEN,x inx + ldy #0 + __b1: + lda #OFFSET_STRUCT_PERSON_NAME + clc + adc.z person + sta.z __1 lda #0 - sta.z i - b1: - ldy #OFFSET_STRUCT_PERSON_NAME - lda (person),y - sta.z $fe - iny - lda (person),y - sta.z $ff - ldy.z i - lda ($fe),y + adc.z person+1 + sta.z __1+1 + lda (__1),y cmp #0 - bne b2 + bne __b2 lda #' ' sta SCREEN,x inx rts - b2: - ldy #OFFSET_STRUCT_PERSON_NAME - lda (person),y - sta.z $fe - iny - lda (person),y - sta.z $ff - ldy.z i - lda ($fe),y + __b2: + lda #OFFSET_STRUCT_PERSON_NAME + clc + adc.z person + sta.z __2 + lda #0 + adc.z person+1 + sta.z __2+1 + lda (__2),y sta SCREEN,x inx - inc.z i - jmp b1 + iny + jmp __b1 } DIGIT: .text "0123456789" .byte 0 + __0: .byte 4 + .text "jesper" + .byte 0 + .fill 9, 0 + __1: .byte 7 + .text "henriette" + .byte 0 + .fill 6, 0 diff --git a/src/test/ref/struct-ptr-28.cfg b/src/test/ref/struct-ptr-28.cfg index ef1f8b0c7..eeb74df3a 100644 --- a/src/test/ref/struct-ptr-28.cfg +++ b/src/test/ref/struct-ptr-28.cfg @@ -7,41 +7,45 @@ to:@end @end: scope:[] from @1 [3] phi() + +(void()) main() main: scope:[main] from @1 - [4] (byte) main::jesper_id#0 ← (byte) 4 - [5] (byte[$10]) main::jesper_name#0 ← (const string) main::$4 - [6] call print_person + [4] *(&(struct Person) main::jesper) ← memcpy(*(&(const struct Person) $0), struct Person, (const byte) SIZEOF_STRUCT_PERSON) + [5] call print_person to:main::@1 main::@1: scope:[main] from main - [7] (byte) main::henriette_id#0 ← (byte) 7 - [8] (byte[$10]) main::henriette_name#0 ← (const string) main::$5 - [9] call print_person + [6] *(&(struct Person) main::henriette) ← memcpy(*(&(const struct Person) $1), struct Person, (const byte) SIZEOF_STRUCT_PERSON) + [7] call print_person to:main::@return main::@return: scope:[main] from main::@1 - [10] return + [8] return to:@return + +(void()) print_person((struct Person*) print_person::person) print_person: scope:[print_person] from main main::@1 - [11] (byte) idx#13 ← phi( main/(byte) 0 main::@1/(byte) idx#16 ) - [11] (struct Person*) print_person::person#2 ← phi( main/(struct Person*)&(byte) main::jesper_id#0 main::@1/(struct Person*)&(byte) main::henriette_id#0 ) - [12] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) - [13] (byte) idx#4 ← ++ (byte) idx#13 - [14] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' - [15] (byte) idx#5 ← ++ (byte) idx#4 + [9] (byte) idx#13 ← phi( main/(byte) 0 main::@1/(byte) idx#16 ) + [9] (struct Person*) print_person::person#2 ← phi( main/&(struct Person) main::jesper main::@1/&(struct Person) main::henriette ) + [10] *((const byte*) SCREEN + (byte) idx#13) ← *((const byte*) DIGIT + *((byte*)(struct Person*) print_person::person#2)) + [11] (byte) idx#4 ← ++ (byte) idx#13 + [12] *((const byte*) SCREEN + (byte) idx#4) ← (byte) ' ' + [13] (byte) idx#5 ← ++ (byte) idx#4 to:print_person::@1 print_person::@1: scope:[print_person] from print_person print_person::@2 - [16] (byte) idx#14 ← phi( print_person/(byte) idx#5 print_person::@2/(byte) idx#6 ) - [16] (byte) print_person::i#2 ← phi( print_person/(byte) 0 print_person::@2/(byte) print_person::i#1 ) - [17] if((byte) 0!=*(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2)) goto print_person::@2 + [14] (byte) idx#14 ← phi( print_person/(byte) idx#5 print_person::@2/(byte) idx#6 ) + [14] (byte) print_person::i#2 ← phi( print_person/(byte) 0 print_person::@2/(byte) print_person::i#1 ) + [15] (byte*~) print_person::$1 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME + [16] if((byte) 0!=*((byte*~) print_person::$1 + (byte) print_person::i#2)) goto print_person::@2 to:print_person::@3 print_person::@3: scope:[print_person] from print_person::@1 - [18] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' - [19] (byte) idx#16 ← ++ (byte) idx#14 + [17] *((const byte*) SCREEN + (byte) idx#14) ← (byte) ' ' + [18] (byte) idx#16 ← ++ (byte) idx#14 to:print_person::@return print_person::@return: scope:[print_person] from print_person::@3 - [20] return + [19] return to:@return print_person::@2: scope:[print_person] from print_person::@1 - [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) + [20] (byte*~) print_person::$2 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME + [21] *((const byte*) SCREEN + (byte) idx#14) ← *((byte*~) print_person::$2 + (byte) print_person::i#2) [22] (byte) idx#6 ← ++ (byte) idx#14 [23] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 to:print_person::@1 diff --git a/src/test/ref/struct-ptr-28.log b/src/test/ref/struct-ptr-28.log index 326435b94..ce5e1af75 100644 --- a/src/test/ref/struct-ptr-28.log +++ b/src/test/ref/struct-ptr-28.log @@ -1,45 +1,38 @@ -Setting inferred volatile on symbol affected by address-of (struct Person*~) main::$0 ← & (struct Person) main::jesper -Setting inferred volatile on symbol affected by address-of (struct Person*~) main::$2 ← & (struct Person) main::henriette -Created struct value member variable (byte) main::jesper_id -Created struct value member variable (byte[$10]) main::jesper_name -Converted struct value to member variables (struct Person) main::jesper -Created struct value member variable (byte) main::henriette_id -Created struct value member variable (byte[$10]) main::henriette_name -Converted struct value to member variables (struct Person) main::henriette -Adding struct value list initializer (byte) main::jesper_id ← (number) 4 -Adding struct value list initializer (byte[$10]) main::jesper_name ← (string) "jesper" -Adding struct value list initializer (byte) main::henriette_id ← (number) 7 -Adding struct value list initializer (byte[$10]) main::henriette_name ← (string) "henriette" -Rewriting struct pointer member access *((struct Person*) print_person::person).id -Rewriting struct pointer member access *((struct Person*) print_person::person).name -Rewriting struct pointer member access *((struct Person*) print_person::person).name -Warning! Adding boolean cast to non-boolean condition *(*((byte[$10]*) print_person::$1) + (byte) print_person::i) +Fixing struct type size struct Person to 17 +Fixing struct type size struct Person to 17 +Fixing struct type size struct Person to 17 +Fixing struct type SIZE_OF struct Person to 17 +Fixing struct type SIZE_OF struct Person to 17 +Setting struct to load/store in variable affected by address-of (void~) main::$0 ← call print_person &(struct Person) main::jesper +Setting struct to load/store in variable affected by address-of (void~) main::$1 ← call print_person &(struct Person) main::henriette +Adding value bulk copy *(&(struct Person) main::jesper) ← memcpy(*(&(const struct Person) $0), struct Person, (const byte) SIZEOF_STRUCT_PERSON) +Adding value bulk copy *(&(struct Person) main::henriette) ← memcpy(*(&(const struct Person) $1), struct Person, (const byte) SIZEOF_STRUCT_PERSON) +Replacing struct member reference *((struct Person*) print_person::person).id with member unwinding reference *((byte*~) print_person::$0) +Replacing struct member reference *((struct Person*) print_person::person).name with member unwinding reference (byte*~) print_person::$1 +Replacing struct member reference *((struct Person*) print_person::person).name with member unwinding reference (byte*~) print_person::$2 +Warning! Adding boolean cast to non-boolean condition *((byte*~) print_person::$1 + (byte) print_person::i) Culled Empty Block (label) print_person::@4 Culled Empty Block (label) print_person::@5 Culled Empty Block (label) print_person::@6 -Adding versioned struct unwinding for (struct Person) main::jesper#0 -Adding versioned struct unwinding for (struct Person) main::henriette#0 CONTROL FLOW GRAPH SSA @begin: scope:[] from to:@1 + +(void()) main() main: scope:[main] from @2 (byte) idx#18 ← phi( @2/(byte) idx#20 ) - (byte) main::jesper_id#0 ← (number) 4 - (byte[$10]) main::jesper_name#0 ← (const string) main::$4 - (struct Person) main::jesper#0 ← struct-unwound {(byte) main::jesper_id#0, (byte[$10]) main::jesper_name#0} - (struct Person*~) main::$0 ← & (struct Person) main::jesper#0 - (struct Person*) print_person::person#0 ← (struct Person*~) main::$0 + *(&(struct Person) main::jesper) ← memcpy(*(&(const struct Person) $0), struct Person, (const byte) SIZEOF_STRUCT_PERSON) + (struct Person) main::jesper ← struct-unwound {*(&(struct Person) main::jesper)} + (struct Person*) print_person::person#0 ← &(struct Person) main::jesper call print_person to:main::@1 main::@1: scope:[main] from main (byte) idx#10 ← phi( main/(byte) idx#8 ) (byte) idx#0 ← (byte) idx#10 - (byte) main::henriette_id#0 ← (number) 7 - (byte[$10]) main::henriette_name#0 ← (const string) main::$5 - (struct Person) main::henriette#0 ← struct-unwound {(byte) main::henriette_id#0, (byte[$10]) main::henriette_name#0} - (struct Person*~) main::$2 ← & (struct Person) main::henriette#0 - (struct Person*) print_person::person#1 ← (struct Person*~) main::$2 + *(&(struct Person) main::henriette) ← memcpy(*(&(const struct Person) $1), struct Person, (const byte) SIZEOF_STRUCT_PERSON) + (struct Person) main::henriette ← struct-unwound {*(&(struct Person) main::henriette)} + (struct Person*) print_person::person#1 ← &(struct Person) main::henriette call print_person to:main::@2 main::@2: scope:[main] from main::@1 @@ -52,40 +45,40 @@ main::@return: scope:[main] from main::@2 return to:@return @1: scope:[] from @begin - (byte*) SCREEN#0 ← ((byte*)) (number) $400 - (byte) idx#3 ← (number) 0 - (byte[]) DIGIT#0 ← (const string) $0 + (byte) idx#3 ← (byte) 0 to:@2 + +(void()) print_person((struct Person*) print_person::person) print_person: scope:[print_person] from main main::@1 (byte) idx#13 ← phi( main/(byte) idx#18 main::@1/(byte) idx#0 ) (struct Person*) print_person::person#2 ← phi( main/(struct Person*) print_person::person#0 main::@1/(struct Person*) print_person::person#1 ) - (byte*) print_person::$0 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID - *((byte*) SCREEN#0 + (byte) idx#13) ← *((byte[]) DIGIT#0 + *((byte*) print_person::$0)) + (byte*~) print_person::$0 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID + *((const byte*) SCREEN + (byte) idx#13) ← *((const byte*) DIGIT + *((byte*~) print_person::$0)) (byte) idx#4 ← ++ (byte) idx#13 - *((byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' + *((const byte*) SCREEN + (byte) idx#4) ← (byte) ' ' (byte) idx#5 ← ++ (byte) idx#4 - (byte) print_person::i#0 ← (number) 0 + (byte) print_person::i#0 ← (byte) 0 to:print_person::@1 print_person::@1: scope:[print_person] from print_person print_person::@2 (byte) idx#19 ← phi( print_person/(byte) idx#5 print_person::@2/(byte) idx#6 ) (byte) print_person::i#2 ← phi( print_person/(byte) print_person::i#0 print_person::@2/(byte) print_person::i#1 ) (struct Person*) print_person::person#3 ← phi( print_person/(struct Person*) print_person::person#2 print_person::@2/(struct Person*) print_person::person#4 ) - (byte[$10]*) print_person::$1 ← (byte[$10]*)(struct Person*) print_person::person#3 + (const byte) OFFSET_STRUCT_PERSON_NAME - (bool~) print_person::$3 ← (number) 0 != *(*((byte[$10]*) print_person::$1) + (byte) print_person::i#2) + (byte*~) print_person::$1 ← (byte*)(struct Person*) print_person::person#3 + (const byte) OFFSET_STRUCT_PERSON_NAME + (bool~) print_person::$3 ← (number) 0 != *((byte*~) print_person::$1 + (byte) print_person::i#2) if((bool~) print_person::$3) goto print_person::@2 to:print_person::@3 print_person::@2: scope:[print_person] from print_person::@1 (byte) idx#14 ← phi( print_person::@1/(byte) idx#19 ) (byte) print_person::i#3 ← phi( print_person::@1/(byte) print_person::i#2 ) (struct Person*) print_person::person#4 ← phi( print_person::@1/(struct Person*) print_person::person#3 ) - (byte[$10]*) print_person::$2 ← (byte[$10]*)(struct Person*) print_person::person#4 + (const byte) OFFSET_STRUCT_PERSON_NAME - *((byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*) print_person::$2) + (byte) print_person::i#3) + (byte*~) print_person::$2 ← (byte*)(struct Person*) print_person::person#4 + (const byte) OFFSET_STRUCT_PERSON_NAME + *((const byte*) SCREEN + (byte) idx#14) ← *((byte*~) print_person::$2 + (byte) print_person::i#3) (byte) idx#6 ← ++ (byte) idx#14 (byte) print_person::i#1 ← ++ (byte) print_person::i#3 to:print_person::@1 print_person::@3: scope:[print_person] from print_person::@1 (byte) idx#15 ← phi( print_person::@1/(byte) idx#19 ) - *((byte*) SCREEN#0 + (byte) idx#15) ← (byte) ' ' + *((const byte*) SCREEN + (byte) idx#15) ← (byte) ' ' (byte) idx#7 ← ++ (byte) idx#15 to:print_person::@return print_person::@return: scope:[print_person] from print_person::@3 @@ -104,20 +97,20 @@ print_person::@return: scope:[print_person] from print_person::@3 @end: scope:[] from @3 SYMBOL TABLE SSA -(const string) $0 = (string) "0123456789" +(const struct Person) $0 = { id: (byte) 4, name: (string) "jesper" } +(const struct Person) $1 = { id: (byte) 7, name: (string) "henriette" } (label) @1 (label) @2 (label) @3 (label) @begin (label) @end -(byte[]) DIGIT -(byte[]) DIGIT#0 +(const byte*) DIGIT[] = (string) "0123456789" (const byte) OFFSET_STRUCT_PERSON_ID = (byte) 0 (const byte) OFFSET_STRUCT_PERSON_NAME = (byte) 1 (byte) Person::id -(byte[$10]) Person::name -(byte*) SCREEN -(byte*) SCREEN#0 +(const byte*) Person::name[(number) $10] = { fill( $10, 0) } +(const byte*) SCREEN = (byte*)(number) $400 +(const byte) SIZEOF_STRUCT_PERSON = (byte) $11 (byte) idx (byte) idx#0 (byte) idx#1 @@ -141,29 +134,15 @@ SYMBOL TABLE SSA (byte) idx#8 (byte) idx#9 (void()) main() -(struct Person*~) main::$0 -(struct Person*~) main::$2 -(const string) main::$4 = (string) "jesper" -(const string) main::$5 = (string) "henriette" (label) main::@1 (label) main::@2 (label) main::@return -(struct Person) main::henriette -(struct Person) main::henriette#0 -(byte) main::henriette_id -(byte) main::henriette_id#0 -(byte[$10]) main::henriette_name -(byte[$10]) main::henriette_name#0 -(struct Person) main::jesper -(struct Person) main::jesper#0 -(byte) main::jesper_id -(byte) main::jesper_id#0 -(byte[$10]) main::jesper_name -(byte[$10]) main::jesper_name#0 +(struct Person) main::henriette loadstore +(struct Person) main::jesper loadstore (void()) print_person((struct Person*) print_person::person) -(byte*) print_person::$0 -(byte[$10]*) print_person::$1 -(byte[$10]*) print_person::$2 +(byte*~) print_person::$0 +(byte*~) print_person::$1 +(byte*~) print_person::$2 (bool~) print_person::$3 (label) print_person::@1 (label) print_person::@2 @@ -181,34 +160,14 @@ SYMBOL TABLE SSA (struct Person*) print_person::person#3 (struct Person*) print_person::person#4 -Adding number conversion cast (unumber) 4 in (byte) main::jesper_id#0 ← (number) 4 -Adding number conversion cast (unumber) 7 in (byte) main::henriette_id#0 ← (number) 7 -Adding number conversion cast (unumber) 0 in (byte) idx#3 ← (number) 0 -Adding number conversion cast (unumber) 0 in (byte) print_person::i#0 ← (number) 0 -Adding number conversion cast (unumber) 0 in (bool~) print_person::$3 ← (number) 0 != *(*((byte[$10]*) print_person::$1) + (byte) print_person::i#2) +Adding number conversion cast (unumber) 0 in (bool~) print_person::$3 ← (number) 0 != *((byte*~) print_person::$1 + (byte) print_person::i#2) Successful SSA optimization PassNAddNumberTypeConversions -Inlining cast (byte) main::jesper_id#0 ← (unumber)(number) 4 -Inlining cast (byte) main::henriette_id#0 ← (unumber)(number) 7 -Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400 -Inlining cast (byte) idx#3 ← (unumber)(number) 0 -Inlining cast (byte) print_person::i#0 ← (unumber)(number) 0 -Successful SSA optimization Pass2InlineCast -Simplifying constant integer cast 4 -Simplifying constant integer cast 7 Simplifying constant pointer cast (byte*) 1024 Simplifying constant integer cast 0 -Simplifying constant integer cast 0 -Simplifying constant integer cast 0 Successful SSA optimization PassNCastSimplification -Finalized unsigned number type (byte) 4 -Finalized unsigned number type (byte) 7 -Finalized unsigned number type (byte) 0 -Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 0 Successful SSA optimization PassNFinalizeNumberTypeConversions -Alias (struct Person*) print_person::person#0 = (struct Person*~) main::$0 Alias (byte) idx#0 = (byte) idx#10 -Alias (struct Person*) print_person::person#1 = (struct Person*~) main::$2 Alias (byte) idx#1 = (byte) idx#11 (byte) idx#12 (byte) idx#2 Alias (struct Person*) print_person::person#3 = (struct Person*) print_person::person#4 Alias (byte) print_person::i#2 = (byte) print_person::i#3 @@ -223,33 +182,21 @@ Identical Phi Values (byte) idx#1 (byte) idx#16 Identical Phi Values (struct Person*) print_person::person#3 (struct Person*) print_person::person#2 Identical Phi Values (byte) idx#17 (byte) idx#1 Successful SSA optimization Pass2IdenticalPhiElimination -Simple Condition (bool~) print_person::$3 [33] if((byte) 0!=*(*((byte[$10]*) print_person::$1) + (byte) print_person::i#2)) goto print_person::@2 +Simple Condition (bool~) print_person::$3 [27] if((byte) 0!=*((byte*~) print_person::$1 + (byte) print_person::i#2)) goto print_person::@2 Successful SSA optimization Pass2ConditionalJumpSimplification -Rewriting struct address-of to first member [4] (struct Person*) print_person::person#0 ← (struct Person*)&(byte) main::jesper_id#0 -Rewriting struct address-of to first member [12] (struct Person*) print_person::person#1 ← (struct Person*)&(byte) main::henriette_id#0 -Successful SSA optimization PassNStructAddressOfRewriting -Constant right-side identified [4] (struct Person*) print_person::person#0 ← (struct Person*)&(byte) main::jesper_id#0 -Constant right-side identified [12] (struct Person*) print_person::person#1 ← (struct Person*)&(byte) main::henriette_id#0 -Successful SSA optimization Pass2ConstantRValueConsolidation -Constant (const struct Person*) print_person::person#0 = (struct Person*)&main::jesper_id#0 -Constant (const struct Person*) print_person::person#1 = (struct Person*)&main::henriette_id#0 -Constant (const byte*) SCREEN#0 = (byte*) 1024 +Removing C-classic struct-unwound assignment [2] (struct Person) main::jesper ← struct-unwound {*(&(struct Person) main::jesper)} +Removing C-classic struct-unwound assignment [8] (struct Person) main::henriette ← struct-unwound {*(&(struct Person) main::henriette)} +Constant (const struct Person*) print_person::person#0 = &main::jesper +Constant (const struct Person*) print_person::person#1 = &main::henriette Constant (const byte) idx#20 = 0 -Constant (const byte[]) DIGIT#0 = $0 Constant (const byte) print_person::i#0 = 0 Successful SSA optimization Pass2ConstantIdentification -Converting *(pointer+n) to pointer[n] [25] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*) print_person::$0)) -- *((byte*)print_person::person#2 + OFFSET_STRUCT_PERSON_ID) -Converting *(pointer+n) to pointer[n] [33] if((byte) 0!=*(*((byte[$10]*) print_person::$1) + (byte) print_person::i#2)) goto print_person::@2 -- *((byte[$10]*)print_person::person#2 + OFFSET_STRUCT_PERSON_NAME) -Converting *(pointer+n) to pointer[n] [36] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*) print_person::$2) + (byte) print_person::i#2) -- *((byte[$10]*)print_person::person#2 + OFFSET_STRUCT_PERSON_NAME) +Converting *(pointer+n) to pointer[n] [19] *((const byte*) SCREEN + (byte) idx#13) ← *((const byte*) DIGIT + *((byte*~) print_person::$0)) -- *((byte*)print_person::person#2 + OFFSET_STRUCT_PERSON_ID) Successful SSA optimization Pass2InlineDerefIdx -Simplifying expression containing zero (byte*)print_person::person#2 in [24] (byte*) print_person::$0 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID -Simplifying expression containing zero (byte*)print_person::person#2 in [25] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID)) +Simplifying expression containing zero (byte*)print_person::person#2 in [18] (byte*~) print_person::$0 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID +Simplifying expression containing zero (byte*)print_person::person#2 in [19] *((const byte*) SCREEN + (byte) idx#13) ← *((const byte*) DIGIT + *((byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID)) Successful SSA optimization PassNSimplifyExpressionWithZero -Eliminating unused variable (struct Person) main::jesper#0 and assignment [2] (struct Person) main::jesper#0 ← struct-unwound {(byte) main::jesper_id#0, (byte[$10]) main::jesper_name#0} -Eliminating unused variable (struct Person) main::henriette#0 and assignment [6] (struct Person) main::henriette#0 ← struct-unwound {(byte) main::henriette_id#0, (byte[$10]) main::henriette_name#0} -Eliminating unused variable (byte*) print_person::$0 and assignment [10] (byte*) print_person::$0 ← (byte*)(struct Person*) print_person::person#2 -Eliminating unused variable (byte[$10]*) print_person::$1 and assignment [16] (byte[$10]*) print_person::$1 ← (byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME -Eliminating unused variable (byte[$10]*) print_person::$2 and assignment [18] (byte[$10]*) print_person::$2 ← (byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME +Eliminating unused variable (byte*~) print_person::$0 and assignment [6] (byte*~) print_person::$0 ← (byte*)(struct Person*) print_person::person#2 Eliminating unused constant (const byte) OFFSET_STRUCT_PERSON_ID Successful SSA optimization PassNEliminateUnusedVars Inlining constant with var siblings (const struct Person*) print_person::person#0 @@ -257,10 +204,9 @@ Inlining constant with var siblings (const struct Person*) print_person::person# Inlining constant with var siblings (const byte) print_person::i#0 Inlining constant with var siblings (const byte) idx#20 Constant inlined idx#20 = (byte) 0 -Constant inlined $0 = (const byte[]) DIGIT#0 -Constant inlined print_person::person#0 = (struct Person*)&(byte) main::jesper_id#0 +Constant inlined print_person::person#0 = &(struct Person) main::jesper Constant inlined print_person::i#0 = (byte) 0 -Constant inlined print_person::person#1 = (struct Person*)&(byte) main::henriette_id#0 +Constant inlined print_person::person#1 = &(struct Person) main::henriette Successful SSA optimization Pass2ConstantInlining Adding NOP phi() at start of @begin Adding NOP phi() at start of @1 @@ -270,11 +216,11 @@ Adding NOP phi() at start of @end Adding NOP phi() at start of main::@2 CALL GRAPH Calls in [] to main:3 -Calls in [main] to print_person:8 print_person:12 +Calls in [main] to print_person:7 print_person:10 Created 4 initial phi equivalence classes -Coalesced [11] idx#21 ← idx#16 -Coalesced [20] idx#22 ← idx#5 +Coalesced [9] idx#21 ← idx#16 +Coalesced [18] idx#22 ← idx#5 Coalesced [29] print_person::i#4 ← print_person::i#1 Coalesced [30] idx#23 ← idx#6 Coalesced down to 4 phi equivalence classes @@ -296,73 +242,68 @@ FINAL CONTROL FLOW GRAPH to:@end @end: scope:[] from @1 [3] phi() + +(void()) main() main: scope:[main] from @1 - [4] (byte) main::jesper_id#0 ← (byte) 4 - [5] (byte[$10]) main::jesper_name#0 ← (const string) main::$4 - [6] call print_person + [4] *(&(struct Person) main::jesper) ← memcpy(*(&(const struct Person) $0), struct Person, (const byte) SIZEOF_STRUCT_PERSON) + [5] call print_person to:main::@1 main::@1: scope:[main] from main - [7] (byte) main::henriette_id#0 ← (byte) 7 - [8] (byte[$10]) main::henriette_name#0 ← (const string) main::$5 - [9] call print_person + [6] *(&(struct Person) main::henriette) ← memcpy(*(&(const struct Person) $1), struct Person, (const byte) SIZEOF_STRUCT_PERSON) + [7] call print_person to:main::@return main::@return: scope:[main] from main::@1 - [10] return + [8] return to:@return + +(void()) print_person((struct Person*) print_person::person) print_person: scope:[print_person] from main main::@1 - [11] (byte) idx#13 ← phi( main/(byte) 0 main::@1/(byte) idx#16 ) - [11] (struct Person*) print_person::person#2 ← phi( main/(struct Person*)&(byte) main::jesper_id#0 main::@1/(struct Person*)&(byte) main::henriette_id#0 ) - [12] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) - [13] (byte) idx#4 ← ++ (byte) idx#13 - [14] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' - [15] (byte) idx#5 ← ++ (byte) idx#4 + [9] (byte) idx#13 ← phi( main/(byte) 0 main::@1/(byte) idx#16 ) + [9] (struct Person*) print_person::person#2 ← phi( main/&(struct Person) main::jesper main::@1/&(struct Person) main::henriette ) + [10] *((const byte*) SCREEN + (byte) idx#13) ← *((const byte*) DIGIT + *((byte*)(struct Person*) print_person::person#2)) + [11] (byte) idx#4 ← ++ (byte) idx#13 + [12] *((const byte*) SCREEN + (byte) idx#4) ← (byte) ' ' + [13] (byte) idx#5 ← ++ (byte) idx#4 to:print_person::@1 print_person::@1: scope:[print_person] from print_person print_person::@2 - [16] (byte) idx#14 ← phi( print_person/(byte) idx#5 print_person::@2/(byte) idx#6 ) - [16] (byte) print_person::i#2 ← phi( print_person/(byte) 0 print_person::@2/(byte) print_person::i#1 ) - [17] if((byte) 0!=*(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2)) goto print_person::@2 + [14] (byte) idx#14 ← phi( print_person/(byte) idx#5 print_person::@2/(byte) idx#6 ) + [14] (byte) print_person::i#2 ← phi( print_person/(byte) 0 print_person::@2/(byte) print_person::i#1 ) + [15] (byte*~) print_person::$1 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME + [16] if((byte) 0!=*((byte*~) print_person::$1 + (byte) print_person::i#2)) goto print_person::@2 to:print_person::@3 print_person::@3: scope:[print_person] from print_person::@1 - [18] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' - [19] (byte) idx#16 ← ++ (byte) idx#14 + [17] *((const byte*) SCREEN + (byte) idx#14) ← (byte) ' ' + [18] (byte) idx#16 ← ++ (byte) idx#14 to:print_person::@return print_person::@return: scope:[print_person] from print_person::@3 - [20] return + [19] return to:@return print_person::@2: scope:[print_person] from print_person::@1 - [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) + [20] (byte*~) print_person::$2 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME + [21] *((const byte*) SCREEN + (byte) idx#14) ← *((byte*~) print_person::$2 + (byte) print_person::i#2) [22] (byte) idx#6 ← ++ (byte) idx#14 [23] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 to:print_person::@1 VARIABLE REGISTER WEIGHTS -(byte[]) DIGIT (byte) Person::id -(byte[$10]) Person::name -(byte*) SCREEN (byte) idx (byte) idx#13 3.0 -(byte) idx#14 9.75 -(byte) idx#16 0.8 +(byte) idx#14 6.5 +(byte) idx#16 1.0 (byte) idx#4 3.0 (byte) idx#5 4.0 (byte) idx#6 11.0 (void()) main() -(struct Person) main::henriette -(byte) main::henriette_id -(byte) main::henriette_id#0 20.0 -(byte[$10]) main::henriette_name -(byte[$10]) main::henriette_name#0 20.0 -(struct Person) main::jesper -(byte) main::jesper_id -(byte) main::jesper_id#0 20.0 -(byte[$10]) main::jesper_name -(byte[$10]) main::jesper_name#0 20.0 +(struct Person) main::henriette loadstore +(struct Person) main::jesper loadstore (void()) print_person((struct Person*) print_person::person) +(byte*~) print_person::$1 22.0 +(byte*~) print_person::$2 22.0 (byte) print_person::i (byte) print_person::i#1 22.0 -(byte) print_person::i#2 11.0 +(byte) print_person::i#2 7.333333333333333 (struct Person*) print_person::person (struct Person*) print_person::person#2 @@ -371,519 +312,516 @@ Initial phi equivalence classes [ idx#13 idx#16 ] [ print_person::i#2 print_person::i#1 ] [ idx#14 idx#5 idx#6 ] -Added variable idx#4 to zero page equivalence class [ idx#4 ] +Added variable idx#4 to live range equivalence class [ idx#4 ] +Added variable print_person::$1 to live range equivalence class [ print_person::$1 ] +Added variable print_person::$2 to live range equivalence class [ print_person::$2 ] +Added variable main::jesper to live range equivalence class [ main::jesper ] +Added variable main::henriette to live range equivalence class [ main::henriette ] Complete equivalence classes [ print_person::person#2 ] [ idx#13 idx#16 ] [ print_person::i#2 print_person::i#1 ] [ idx#14 idx#5 idx#6 ] -[ main::jesper_id#0 ] -[ main::jesper_name#0 ] -[ main::henriette_id#0 ] -[ main::henriette_name#0 ] [ idx#4 ] -Allocated zp ZP_WORD:2 [ print_person::person#2 ] -Allocated zp ZP_BYTE:4 [ idx#13 idx#16 ] -Allocated zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] -Allocated zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ] -Allocated zp ZP_BYTE:7 [ main::jesper_id#0 ] -Allocated zp ZP_WORD:8 [ main::jesper_name#0 ] -Allocated zp ZP_BYTE:10 [ main::henriette_id#0 ] -Allocated zp ZP_WORD:11 [ main::henriette_name#0 ] -Allocated zp ZP_BYTE:13 [ idx#4 ] +[ print_person::$1 ] +[ print_person::$2 ] +[ main::jesper ] +[ main::henriette ] +Allocated zp[2]:2 [ print_person::person#2 ] +Allocated zp[1]:4 [ idx#13 idx#16 ] +Allocated zp[1]:5 [ print_person::i#2 print_person::i#1 ] +Allocated zp[1]:6 [ idx#14 idx#5 idx#6 ] +Allocated zp[1]:7 [ idx#4 ] +Allocated zp[2]:8 [ print_person::$1 ] +Allocated zp[2]:10 [ print_person::$2 ] +Allocated zp[17]:12 [ main::jesper ] +Allocated zp[17]:29 [ main::henriette ] INITIAL ASM Target platform is c64basic / MOS6502X // File Comments // Example of a struct containing an array // It works on the surface - but illustrates the problem with structs containing arrays treating them like pointers. -// https://gitlab.com/camelot/kickc/issues/312 +// https://gitlab.com/camelot/kickc/issues/314 // Upstart .pc = $801 "Basic" -:BasicUpstart(bbegin) +:BasicUpstart(__bbegin) .pc = $80d "Program" // Global Constants & labels - .const OFFSET_STRUCT_PERSON_NAME = 1 .label SCREEN = $400 - .label idx = $d - .label idx_5 = 6 - .label idx_6 = 6 - .label idx_13 = 4 - .label idx_14 = 6 - .label idx_16 = 4 + .const SIZEOF_STRUCT_PERSON = $11 + .const OFFSET_STRUCT_PERSON_NAME = 1 + .label idx = 7 + .label idx_1 = 6 + .label idx_2 = 4 // @begin -bbegin: +__bbegin: // [1] phi from @begin to @1 [phi:@begin->@1] -b1_from_bbegin: - jmp b1 +__b1_from___bbegin: + jmp __b1 // @1 -b1: +__b1: // [2] call main jsr main // [3] phi from @1 to @end [phi:@1->@end] -bend_from_b1: - jmp bend +__bend_from___b1: + jmp __bend // @end -bend: +__bend: // main main: { - .label jesper_id = 7 - .label jesper_name = 8 - .label henriette_id = $a - .label henriette_name = $b - // [4] (byte) main::jesper_id#0 ← (byte) 4 -- vbuz1=vbuc1 - lda #4 - sta.z jesper_id - // [5] (byte[$10]) main::jesper_name#0 ← (const string) main::$4 -- pbuz1=pbuc1 - lda #<_4 - sta.z jesper_name - lda #>_4 - sta.z jesper_name+1 - // [6] call print_person - // [11] phi from main to print_person [phi:main->print_person] + .label jesper = $c + .label henriette = $1d + // [4] *(&(struct Person) main::jesper) ← memcpy(*(&(const struct Person) $0), struct Person, (const byte) SIZEOF_STRUCT_PERSON) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3 + ldy #SIZEOF_STRUCT_PERSON + !: + lda __0-1,y + sta jesper-1,y + dey + bne !- + // [5] call print_person + // [9] phi from main to print_person [phi:main->print_person] print_person_from_main: - // [11] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#0] -- vbuz1=vbuc1 + // [9] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#0] -- vbuz1=vbuc1 lda #0 - sta.z idx_13 - // [11] phi (struct Person*) print_person::person#2 = (struct Person*)&(byte) main::jesper_id#0 [phi:main->print_person#1] -- pssz1=pssc1 - lda #print_person#1] -- pssz1=pssc1 + lda #jesper_id + lda #>jesper sta.z print_person.person+1 jsr print_person - jmp b1 + jmp __b1 // main::@1 - b1: - // [7] (byte) main::henriette_id#0 ← (byte) 7 -- vbuz1=vbuc1 - lda #7 - sta.z henriette_id - // [8] (byte[$10]) main::henriette_name#0 ← (const string) main::$5 -- pbuz1=pbuc1 - lda #<_5 - sta.z henriette_name - lda #>_5 - sta.z henriette_name+1 - // [9] call print_person - // [11] phi from main::@1 to print_person [phi:main::@1->print_person] - print_person_from_b1: - // [11] phi (byte) idx#13 = (byte) idx#16 [phi:main::@1->print_person#0] -- register_copy - // [11] phi (struct Person*) print_person::person#2 = (struct Person*)&(byte) main::henriette_id#0 [phi:main::@1->print_person#1] -- pssz1=pssc1 - lda #print_person] + print_person_from___b1: + // [9] phi (byte) idx#13 = (byte) idx#16 [phi:main::@1->print_person#0] -- register_copy + // [9] phi (struct Person*) print_person::person#2 = &(struct Person) main::henriette [phi:main::@1->print_person#1] -- pssz1=pssc1 + lda #henriette_id + lda #>henriette sta.z print_person.person+1 jsr print_person - jmp breturn + jmp __breturn // main::@return - breturn: - // [10] return + __breturn: + // [8] return rts - _4: .text "jesper" - .byte 0 - _5: .text "henriette" - .byte 0 } // print_person -// print_person(struct Person* zeropage(2) person) +// print_person(struct Person* zp(2) person) print_person: { + .label __1 = 8 + .label __2 = $a .label i = 5 .label person = 2 - // [12] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_(_deref_pbuz2) - ldx.z idx_13 + // [10] *((const byte*) SCREEN + (byte) idx#13) ← *((const byte*) DIGIT + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_(_deref_pbuz2) + ldx.z idx_2 ldy #0 lda (person),y tay lda DIGIT,y sta SCREEN,x - // [13] (byte) idx#4 ← ++ (byte) idx#13 -- vbuz1=_inc_vbuz2 - ldy.z idx_13 + // [11] (byte) idx#4 ← ++ (byte) idx#13 -- vbuz1=_inc_vbuz2 + ldy.z idx_2 iny sty.z idx - // [14] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuz1=vbuc2 + // [12] *((const byte*) SCREEN + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuz1=vbuc2 lda #' ' ldy.z idx sta SCREEN,y - // [15] (byte) idx#5 ← ++ (byte) idx#4 -- vbuz1=_inc_vbuz2 + // [13] (byte) idx#5 ← ++ (byte) idx#4 -- vbuz1=_inc_vbuz2 ldy.z idx iny - sty.z idx_5 - // [16] phi from print_person to print_person::@1 [phi:print_person->print_person::@1] - b1_from_print_person: - // [16] phi (byte) idx#14 = (byte) idx#5 [phi:print_person->print_person::@1#0] -- register_copy - // [16] phi (byte) print_person::i#2 = (byte) 0 [phi:print_person->print_person::@1#1] -- vbuz1=vbuc1 + sty.z idx_1 + // [14] phi from print_person to print_person::@1 [phi:print_person->print_person::@1] + __b1_from_print_person: + // [14] phi (byte) idx#14 = (byte) idx#5 [phi:print_person->print_person::@1#0] -- register_copy + // [14] phi (byte) print_person::i#2 = (byte) 0 [phi:print_person->print_person::@1#1] -- vbuz1=vbuc1 lda #0 sta.z i - jmp b1 + jmp __b1 // print_person::@1 - b1: - // [17] if((byte) 0!=*(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2)) goto print_person::@2 -- vbuc1_neq_(pptz1_derefidx_vbuc2)_derefidx_vbuz2_then_la1 - ldy #OFFSET_STRUCT_PERSON_NAME - lda (person),y - sta.z $fe - iny - lda (person),y - sta.z $ff + __b1: + // [15] (byte*~) print_person::$1 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME -- pbuz1=pbuz2_plus_vbuc1 + lda #OFFSET_STRUCT_PERSON_NAME + clc + adc.z person + sta.z __1 + lda #0 + adc.z person+1 + sta.z __1+1 + // [16] if((byte) 0!=*((byte*~) print_person::$1 + (byte) print_person::i#2)) goto print_person::@2 -- vbuc1_neq_pbuz1_derefidx_vbuz2_then_la1 ldy.z i - lda ($fe),y + lda (__1),y cmp #0 - bne b2 - jmp b3 + bne __b2 + jmp __b3 // print_person::@3 - b3: - // [18] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' -- pbuc1_derefidx_vbuz1=vbuc2 + __b3: + // [17] *((const byte*) SCREEN + (byte) idx#14) ← (byte) ' ' -- pbuc1_derefidx_vbuz1=vbuc2 lda #' ' - ldy.z idx_14 + ldy.z idx_1 sta SCREEN,y - // [19] (byte) idx#16 ← ++ (byte) idx#14 -- vbuz1=_inc_vbuz2 - ldy.z idx_14 + // [18] (byte) idx#16 ← ++ (byte) idx#14 -- vbuz1=_inc_vbuz2 + ldy.z idx_1 iny - sty.z idx_16 - jmp breturn + sty.z idx_2 + jmp __breturn // print_person::@return - breturn: - // [20] return + __breturn: + // [19] return rts // print_person::@2 - b2: - // [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) -- pbuc1_derefidx_vbuz1=(pptz2_derefidx_vbuc2)_derefidx_vbuz3 - ldx.z idx_14 - ldy #OFFSET_STRUCT_PERSON_NAME - lda (person),y - sta.z $fe - iny - lda (person),y - sta.z $ff + __b2: + // [20] (byte*~) print_person::$2 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME -- pbuz1=pbuz2_plus_vbuc1 + lda #OFFSET_STRUCT_PERSON_NAME + clc + adc.z person + sta.z __2 + lda #0 + adc.z person+1 + sta.z __2+1 + // [21] *((const byte*) SCREEN + (byte) idx#14) ← *((byte*~) print_person::$2 + (byte) print_person::i#2) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuz3 + ldx.z idx_1 ldy.z i - lda ($fe),y + lda (__2),y sta SCREEN,x // [22] (byte) idx#6 ← ++ (byte) idx#14 -- vbuz1=_inc_vbuz1 - inc.z idx_6 + inc.z idx_1 // [23] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 -- vbuz1=_inc_vbuz1 inc.z i - // [16] phi from print_person::@2 to print_person::@1 [phi:print_person::@2->print_person::@1] - b1_from_b2: - // [16] phi (byte) idx#14 = (byte) idx#6 [phi:print_person::@2->print_person::@1#0] -- register_copy - // [16] phi (byte) print_person::i#2 = (byte) print_person::i#1 [phi:print_person::@2->print_person::@1#1] -- register_copy - jmp b1 + // [14] phi from print_person::@2 to print_person::@1 [phi:print_person::@2->print_person::@1] + __b1_from___b2: + // [14] phi (byte) idx#14 = (byte) idx#6 [phi:print_person::@2->print_person::@1#0] -- register_copy + // [14] phi (byte) print_person::i#2 = (byte) print_person::i#1 [phi:print_person::@2->print_person::@1#1] -- register_copy + jmp __b1 } // File Data DIGIT: .text "0123456789" .byte 0 + __0: .byte 4 + .text "jesper" + .byte 0 + .fill 9, 0 + __1: .byte 7 + .text "henriette" + .byte 0 + .fill 6, 0 REGISTER UPLIFT POTENTIAL REGISTERS -Statement [4] (byte) main::jesper_id#0 ← (byte) 4 [ ] ( main:2 [ ] ) always clobbers reg byte a -Statement [5] (byte[$10]) main::jesper_name#0 ← (const string) main::$4 [ ] ( main:2 [ ] ) always clobbers reg byte a -Statement [7] (byte) main::henriette_id#0 ← (byte) 7 [ idx#16 ] ( main:2 [ idx#16 ] ) always clobbers reg byte a -Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ idx#13 idx#16 ] -Statement [8] (byte[$10]) main::henriette_name#0 ← (const string) main::$5 [ idx#16 ] ( main:2 [ idx#16 ] ) always clobbers reg byte a -Statement [12] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) [ print_person::person#2 idx#13 ] ( main:2::print_person:6 [ print_person::person#2 idx#13 ] main:2::print_person:9 [ print_person::person#2 idx#13 ] ) always clobbers reg byte a reg byte y -Removing always clobbered register reg byte y as potential for zp ZP_BYTE:4 [ idx#13 idx#16 ] -Statement [14] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' [ print_person::person#2 idx#4 ] ( main:2::print_person:6 [ print_person::person#2 idx#4 ] main:2::print_person:9 [ print_person::person#2 idx#4 ] ) always clobbers reg byte a -Removing always clobbered register reg byte a as potential for zp ZP_BYTE:13 [ idx#4 ] -Statement [17] if((byte) 0!=*(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2)) goto print_person::@2 [ print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:6 [ print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:9 [ print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a reg byte y -Removing always clobbered register reg byte a as potential for zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] -Removing always clobbered register reg byte y as potential for zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] -Removing always clobbered register reg byte a as potential for zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ] -Removing always clobbered register reg byte y as potential for zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ] -Statement [18] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' [ idx#14 ] ( main:2::print_person:6 [ idx#14 ] main:2::print_person:9 [ idx#14 ] ) always clobbers reg byte a -Statement [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) [ print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:6 [ print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:9 [ print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a reg byte y -Statement [4] (byte) main::jesper_id#0 ← (byte) 4 [ ] ( main:2 [ ] ) always clobbers reg byte a -Statement [5] (byte[$10]) main::jesper_name#0 ← (const string) main::$4 [ ] ( main:2 [ ] ) always clobbers reg byte a -Statement [7] (byte) main::henriette_id#0 ← (byte) 7 [ idx#16 ] ( main:2 [ idx#16 ] ) always clobbers reg byte a -Statement [8] (byte[$10]) main::henriette_name#0 ← (const string) main::$5 [ idx#16 ] ( main:2 [ idx#16 ] ) always clobbers reg byte a -Statement [12] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) [ print_person::person#2 idx#13 ] ( main:2::print_person:6 [ print_person::person#2 idx#13 ] main:2::print_person:9 [ print_person::person#2 idx#13 ] ) always clobbers reg byte a reg byte y -Statement [14] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' [ print_person::person#2 idx#4 ] ( main:2::print_person:6 [ print_person::person#2 idx#4 ] main:2::print_person:9 [ print_person::person#2 idx#4 ] ) always clobbers reg byte a -Statement [17] if((byte) 0!=*(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2)) goto print_person::@2 [ print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:6 [ print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:9 [ print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a reg byte y -Statement [18] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' [ idx#14 ] ( main:2::print_person:6 [ idx#14 ] main:2::print_person:9 [ idx#14 ] ) always clobbers reg byte a -Statement [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) [ print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:6 [ print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:9 [ print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a reg byte y -Potential registers zp ZP_WORD:2 [ print_person::person#2 ] : zp ZP_WORD:2 , -Potential registers zp ZP_BYTE:4 [ idx#13 idx#16 ] : zp ZP_BYTE:4 , reg byte x , -Potential registers zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] : zp ZP_BYTE:5 , reg byte x , -Potential registers zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ] : zp ZP_BYTE:6 , reg byte x , -Potential registers zp ZP_BYTE:7 [ main::jesper_id#0 ] : zp ZP_BYTE:7 , -Potential registers zp ZP_WORD:8 [ main::jesper_name#0 ] : zp ZP_WORD:8 , -Potential registers zp ZP_BYTE:10 [ main::henriette_id#0 ] : zp ZP_BYTE:10 , -Potential registers zp ZP_WORD:11 [ main::henriette_name#0 ] : zp ZP_WORD:11 , -Potential registers zp ZP_BYTE:13 [ idx#4 ] : zp ZP_BYTE:13 , reg byte x , reg byte y , +Statement [4] *(&(struct Person) main::jesper) ← memcpy(*(&(const struct Person) $0), struct Person, (const byte) SIZEOF_STRUCT_PERSON) [ main::henriette ] ( main:2 [ main::henriette ] ) always clobbers reg byte a reg byte y +Statement [6] *(&(struct Person) main::henriette) ← memcpy(*(&(const struct Person) $1), struct Person, (const byte) SIZEOF_STRUCT_PERSON) [ main::henriette idx#16 ] ( main:2 [ main::henriette idx#16 ] ) always clobbers reg byte a reg byte y +Removing always clobbered register reg byte a as potential for zp[1]:4 [ idx#13 idx#16 ] +Removing always clobbered register reg byte y as potential for zp[1]:4 [ idx#13 idx#16 ] +Statement [10] *((const byte*) SCREEN + (byte) idx#13) ← *((const byte*) DIGIT + *((byte*)(struct Person*) print_person::person#2)) [ main::henriette print_person::person#2 idx#13 ] ( main:2::print_person:5 [ main::henriette print_person::person#2 idx#13 ] main:2::print_person:7 [ main::henriette print_person::person#2 idx#13 ] ) always clobbers reg byte a reg byte y +Statement [12] *((const byte*) SCREEN + (byte) idx#4) ← (byte) ' ' [ main::henriette print_person::person#2 idx#4 ] ( main:2::print_person:5 [ main::henriette print_person::person#2 idx#4 ] main:2::print_person:7 [ main::henriette print_person::person#2 idx#4 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp[1]:7 [ idx#4 ] +Statement [15] (byte*~) print_person::$1 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME [ main::henriette print_person::person#2 print_person::i#2 idx#14 print_person::$1 ] ( main:2::print_person:5 [ main::henriette print_person::person#2 print_person::i#2 idx#14 print_person::$1 ] main:2::print_person:7 [ main::henriette print_person::person#2 print_person::i#2 idx#14 print_person::$1 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp[1]:5 [ print_person::i#2 print_person::i#1 ] +Removing always clobbered register reg byte a as potential for zp[1]:6 [ idx#14 idx#5 idx#6 ] +Statement [16] if((byte) 0!=*((byte*~) print_person::$1 + (byte) print_person::i#2)) goto print_person::@2 [ main::henriette print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:5 [ main::henriette print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:7 [ main::henriette print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a +Statement [17] *((const byte*) SCREEN + (byte) idx#14) ← (byte) ' ' [ main::henriette idx#14 ] ( main:2::print_person:5 [ main::henriette idx#14 ] main:2::print_person:7 [ main::henriette idx#14 ] ) always clobbers reg byte a +Statement [20] (byte*~) print_person::$2 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME [ main::henriette print_person::person#2 print_person::i#2 idx#14 print_person::$2 ] ( main:2::print_person:5 [ main::henriette print_person::person#2 print_person::i#2 idx#14 print_person::$2 ] main:2::print_person:7 [ main::henriette print_person::person#2 print_person::i#2 idx#14 print_person::$2 ] ) always clobbers reg byte a +Statement [21] *((const byte*) SCREEN + (byte) idx#14) ← *((byte*~) print_person::$2 + (byte) print_person::i#2) [ main::henriette print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:5 [ main::henriette print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:7 [ main::henriette print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a +Statement [4] *(&(struct Person) main::jesper) ← memcpy(*(&(const struct Person) $0), struct Person, (const byte) SIZEOF_STRUCT_PERSON) [ main::henriette ] ( main:2 [ main::henriette ] ) always clobbers reg byte a reg byte y +Statement [6] *(&(struct Person) main::henriette) ← memcpy(*(&(const struct Person) $1), struct Person, (const byte) SIZEOF_STRUCT_PERSON) [ main::henriette idx#16 ] ( main:2 [ main::henriette idx#16 ] ) always clobbers reg byte a reg byte y +Statement [10] *((const byte*) SCREEN + (byte) idx#13) ← *((const byte*) DIGIT + *((byte*)(struct Person*) print_person::person#2)) [ main::henriette print_person::person#2 idx#13 ] ( main:2::print_person:5 [ main::henriette print_person::person#2 idx#13 ] main:2::print_person:7 [ main::henriette print_person::person#2 idx#13 ] ) always clobbers reg byte a reg byte y +Statement [12] *((const byte*) SCREEN + (byte) idx#4) ← (byte) ' ' [ main::henriette print_person::person#2 idx#4 ] ( main:2::print_person:5 [ main::henriette print_person::person#2 idx#4 ] main:2::print_person:7 [ main::henriette print_person::person#2 idx#4 ] ) always clobbers reg byte a +Statement [15] (byte*~) print_person::$1 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME [ main::henriette print_person::person#2 print_person::i#2 idx#14 print_person::$1 ] ( main:2::print_person:5 [ main::henriette print_person::person#2 print_person::i#2 idx#14 print_person::$1 ] main:2::print_person:7 [ main::henriette print_person::person#2 print_person::i#2 idx#14 print_person::$1 ] ) always clobbers reg byte a +Statement [16] if((byte) 0!=*((byte*~) print_person::$1 + (byte) print_person::i#2)) goto print_person::@2 [ main::henriette print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:5 [ main::henriette print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:7 [ main::henriette print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a +Statement [17] *((const byte*) SCREEN + (byte) idx#14) ← (byte) ' ' [ main::henriette idx#14 ] ( main:2::print_person:5 [ main::henriette idx#14 ] main:2::print_person:7 [ main::henriette idx#14 ] ) always clobbers reg byte a +Statement [20] (byte*~) print_person::$2 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME [ main::henriette print_person::person#2 print_person::i#2 idx#14 print_person::$2 ] ( main:2::print_person:5 [ main::henriette print_person::person#2 print_person::i#2 idx#14 print_person::$2 ] main:2::print_person:7 [ main::henriette print_person::person#2 print_person::i#2 idx#14 print_person::$2 ] ) always clobbers reg byte a +Statement [21] *((const byte*) SCREEN + (byte) idx#14) ← *((byte*~) print_person::$2 + (byte) print_person::i#2) [ main::henriette print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:5 [ main::henriette print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:7 [ main::henriette print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a +Potential registers zp[2]:2 [ print_person::person#2 ] : zp[2]:2 , +Potential registers zp[1]:4 [ idx#13 idx#16 ] : zp[1]:4 , reg byte x , +Potential registers zp[1]:5 [ print_person::i#2 print_person::i#1 ] : zp[1]:5 , reg byte x , reg byte y , +Potential registers zp[1]:6 [ idx#14 idx#5 idx#6 ] : zp[1]:6 , reg byte x , reg byte y , +Potential registers zp[1]:7 [ idx#4 ] : zp[1]:7 , reg byte x , reg byte y , +Potential registers zp[2]:8 [ print_person::$1 ] : zp[2]:8 , +Potential registers zp[2]:10 [ print_person::$2 ] : zp[2]:10 , +Potential registers zp[17]:12 [ main::jesper ] : zp[17]:12 , +Potential registers zp[17]:29 [ main::henriette ] : zp[17]:29 , REGISTER UPLIFT SCOPES -Uplift Scope [main] 20: zp ZP_BYTE:7 [ main::jesper_id#0 ] 20: zp ZP_WORD:8 [ main::jesper_name#0 ] 20: zp ZP_BYTE:10 [ main::henriette_id#0 ] 20: zp ZP_WORD:11 [ main::henriette_name#0 ] -Uplift Scope [print_person] 33: zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] 0: zp ZP_WORD:2 [ print_person::person#2 ] -Uplift Scope [] 24.75: zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ] 3.8: zp ZP_BYTE:4 [ idx#13 idx#16 ] 3: zp ZP_BYTE:13 [ idx#4 ] +Uplift Scope [print_person] 29.33: zp[1]:5 [ print_person::i#2 print_person::i#1 ] 22: zp[2]:8 [ print_person::$1 ] 22: zp[2]:10 [ print_person::$2 ] 0: zp[2]:2 [ print_person::person#2 ] +Uplift Scope [] 21.5: zp[1]:6 [ idx#14 idx#5 idx#6 ] 4: zp[1]:4 [ idx#13 idx#16 ] 3: zp[1]:7 [ idx#4 ] Uplift Scope [Person] +Uplift Scope [main] 0: zp[17]:12 [ main::jesper ] 0: zp[17]:29 [ main::henriette ] -Uplifting [main] best 1121 combination zp ZP_BYTE:7 [ main::jesper_id#0 ] zp ZP_WORD:8 [ main::jesper_name#0 ] zp ZP_BYTE:10 [ main::henriette_id#0 ] zp ZP_WORD:11 [ main::henriette_name#0 ] -Uplifting [print_person] best 1121 combination zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] zp ZP_WORD:2 [ print_person::person#2 ] -Uplifting [] best 1031 combination reg byte x [ idx#14 idx#5 idx#6 ] reg byte x [ idx#13 idx#16 ] reg byte x [ idx#4 ] -Uplifting [Person] best 1031 combination -Attempting to uplift remaining variables inzp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] -Uplifting [print_person] best 1031 combination zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] -Attempting to uplift remaining variables inzp ZP_BYTE:7 [ main::jesper_id#0 ] -Uplifting [main] best 1031 combination zp ZP_BYTE:7 [ main::jesper_id#0 ] -Attempting to uplift remaining variables inzp ZP_BYTE:10 [ main::henriette_id#0 ] -Uplifting [main] best 1031 combination zp ZP_BYTE:10 [ main::henriette_id#0 ] -Allocated (was zp ZP_BYTE:5) zp ZP_BYTE:4 [ print_person::i#2 print_person::i#1 ] -Allocated (was zp ZP_BYTE:7) zp ZP_BYTE:5 [ main::jesper_id#0 ] -Allocated (was zp ZP_WORD:8) zp ZP_WORD:6 [ main::jesper_name#0 ] -Allocated (was zp ZP_BYTE:10) zp ZP_BYTE:8 [ main::henriette_id#0 ] -Allocated (was zp ZP_WORD:11) zp ZP_WORD:9 [ main::henriette_name#0 ] +Uplifting [print_person] best 943 combination reg byte y [ print_person::i#2 print_person::i#1 ] zp[2]:8 [ print_person::$1 ] zp[2]:10 [ print_person::$2 ] zp[2]:2 [ print_person::person#2 ] +Uplifting [] best 853 combination reg byte x [ idx#14 idx#5 idx#6 ] reg byte x [ idx#13 idx#16 ] reg byte x [ idx#4 ] +Uplifting [Person] best 853 combination +Uplifting [main] best 853 combination zp[17]:12 [ main::jesper ] zp[17]:29 [ main::henriette ] +Allocated (was zp[2]:8) zp[2]:4 [ print_person::$1 ] +Allocated (was zp[2]:10) zp[2]:6 [ print_person::$2 ] +Allocated (was zp[17]:12) zp[17]:8 [ main::jesper ] +Allocated (was zp[17]:29) zp[17]:25 [ main::henriette ] ASSEMBLER BEFORE OPTIMIZATION // File Comments // Example of a struct containing an array // It works on the surface - but illustrates the problem with structs containing arrays treating them like pointers. -// https://gitlab.com/camelot/kickc/issues/312 +// https://gitlab.com/camelot/kickc/issues/314 // Upstart .pc = $801 "Basic" -:BasicUpstart(bbegin) +:BasicUpstart(__bbegin) .pc = $80d "Program" // Global Constants & labels - .const OFFSET_STRUCT_PERSON_NAME = 1 .label SCREEN = $400 + .const SIZEOF_STRUCT_PERSON = $11 + .const OFFSET_STRUCT_PERSON_NAME = 1 // @begin -bbegin: +__bbegin: // [1] phi from @begin to @1 [phi:@begin->@1] -b1_from_bbegin: - jmp b1 +__b1_from___bbegin: + jmp __b1 // @1 -b1: +__b1: // [2] call main jsr main // [3] phi from @1 to @end [phi:@1->@end] -bend_from_b1: - jmp bend +__bend_from___b1: + jmp __bend // @end -bend: +__bend: // main main: { - .label jesper_id = 5 - .label jesper_name = 6 - .label henriette_id = 8 - .label henriette_name = 9 - // [4] (byte) main::jesper_id#0 ← (byte) 4 -- vbuz1=vbuc1 - lda #4 - sta.z jesper_id - // [5] (byte[$10]) main::jesper_name#0 ← (const string) main::$4 -- pbuz1=pbuc1 - lda #<_4 - sta.z jesper_name - lda #>_4 - sta.z jesper_name+1 - // [6] call print_person - // [11] phi from main to print_person [phi:main->print_person] + .label jesper = 8 + .label henriette = $19 + // [4] *(&(struct Person) main::jesper) ← memcpy(*(&(const struct Person) $0), struct Person, (const byte) SIZEOF_STRUCT_PERSON) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3 + ldy #SIZEOF_STRUCT_PERSON + !: + lda __0-1,y + sta jesper-1,y + dey + bne !- + // [5] call print_person + // [9] phi from main to print_person [phi:main->print_person] print_person_from_main: - // [11] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#0] -- vbuxx=vbuc1 + // [9] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#0] -- vbuxx=vbuc1 ldx #0 - // [11] phi (struct Person*) print_person::person#2 = (struct Person*)&(byte) main::jesper_id#0 [phi:main->print_person#1] -- pssz1=pssc1 - lda #print_person#1] -- pssz1=pssc1 + lda #jesper_id + lda #>jesper sta.z print_person.person+1 jsr print_person - jmp b1 + jmp __b1 // main::@1 - b1: - // [7] (byte) main::henriette_id#0 ← (byte) 7 -- vbuz1=vbuc1 - lda #7 - sta.z henriette_id - // [8] (byte[$10]) main::henriette_name#0 ← (const string) main::$5 -- pbuz1=pbuc1 - lda #<_5 - sta.z henriette_name - lda #>_5 - sta.z henriette_name+1 - // [9] call print_person - // [11] phi from main::@1 to print_person [phi:main::@1->print_person] - print_person_from_b1: - // [11] phi (byte) idx#13 = (byte) idx#16 [phi:main::@1->print_person#0] -- register_copy - // [11] phi (struct Person*) print_person::person#2 = (struct Person*)&(byte) main::henriette_id#0 [phi:main::@1->print_person#1] -- pssz1=pssc1 - lda #print_person] + print_person_from___b1: + // [9] phi (byte) idx#13 = (byte) idx#16 [phi:main::@1->print_person#0] -- register_copy + // [9] phi (struct Person*) print_person::person#2 = &(struct Person) main::henriette [phi:main::@1->print_person#1] -- pssz1=pssc1 + lda #henriette_id + lda #>henriette sta.z print_person.person+1 jsr print_person - jmp breturn + jmp __breturn // main::@return - breturn: - // [10] return + __breturn: + // [8] return rts - _4: .text "jesper" - .byte 0 - _5: .text "henriette" - .byte 0 } // print_person -// print_person(struct Person* zeropage(2) person) +// print_person(struct Person* zp(2) person) print_person: { - .label i = 4 + .label __1 = 4 + .label __2 = 6 .label person = 2 - // [12] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_(_deref_pbuz1) + // [10] *((const byte*) SCREEN + (byte) idx#13) ← *((const byte*) DIGIT + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_(_deref_pbuz1) ldy #0 lda (person),y tay lda DIGIT,y sta SCREEN,x - // [13] (byte) idx#4 ← ++ (byte) idx#13 -- vbuxx=_inc_vbuxx + // [11] (byte) idx#4 ← ++ (byte) idx#13 -- vbuxx=_inc_vbuxx inx - // [14] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2 + // [12] *((const byte*) SCREEN + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2 lda #' ' sta SCREEN,x - // [15] (byte) idx#5 ← ++ (byte) idx#4 -- vbuxx=_inc_vbuxx + // [13] (byte) idx#5 ← ++ (byte) idx#4 -- vbuxx=_inc_vbuxx inx - // [16] phi from print_person to print_person::@1 [phi:print_person->print_person::@1] - b1_from_print_person: - // [16] phi (byte) idx#14 = (byte) idx#5 [phi:print_person->print_person::@1#0] -- register_copy - // [16] phi (byte) print_person::i#2 = (byte) 0 [phi:print_person->print_person::@1#1] -- vbuz1=vbuc1 - lda #0 - sta.z i - jmp b1 + // [14] phi from print_person to print_person::@1 [phi:print_person->print_person::@1] + __b1_from_print_person: + // [14] phi (byte) idx#14 = (byte) idx#5 [phi:print_person->print_person::@1#0] -- register_copy + // [14] phi (byte) print_person::i#2 = (byte) 0 [phi:print_person->print_person::@1#1] -- vbuyy=vbuc1 + ldy #0 + jmp __b1 // print_person::@1 - b1: - // [17] if((byte) 0!=*(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2)) goto print_person::@2 -- vbuc1_neq_(pptz1_derefidx_vbuc2)_derefidx_vbuz2_then_la1 - ldy #OFFSET_STRUCT_PERSON_NAME - lda (person),y - sta.z $fe - iny - lda (person),y - sta.z $ff - ldy.z i - lda ($fe),y + __b1: + // [15] (byte*~) print_person::$1 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME -- pbuz1=pbuz2_plus_vbuc1 + lda #OFFSET_STRUCT_PERSON_NAME + clc + adc.z person + sta.z __1 + lda #0 + adc.z person+1 + sta.z __1+1 + // [16] if((byte) 0!=*((byte*~) print_person::$1 + (byte) print_person::i#2)) goto print_person::@2 -- vbuc1_neq_pbuz1_derefidx_vbuyy_then_la1 + lda (__1),y cmp #0 - bne b2 - jmp b3 + bne __b2 + jmp __b3 // print_person::@3 - b3: - // [18] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2 + __b3: + // [17] *((const byte*) SCREEN + (byte) idx#14) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2 lda #' ' sta SCREEN,x - // [19] (byte) idx#16 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx + // [18] (byte) idx#16 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx inx - jmp breturn + jmp __breturn // print_person::@return - breturn: - // [20] return + __breturn: + // [19] return rts // print_person::@2 - b2: - // [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) -- pbuc1_derefidx_vbuxx=(pptz1_derefidx_vbuc2)_derefidx_vbuz2 - ldy #OFFSET_STRUCT_PERSON_NAME - lda (person),y - sta.z $fe - iny - lda (person),y - sta.z $ff - ldy.z i - lda ($fe),y + __b2: + // [20] (byte*~) print_person::$2 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME -- pbuz1=pbuz2_plus_vbuc1 + lda #OFFSET_STRUCT_PERSON_NAME + clc + adc.z person + sta.z __2 + lda #0 + adc.z person+1 + sta.z __2+1 + // [21] *((const byte*) SCREEN + (byte) idx#14) ← *((byte*~) print_person::$2 + (byte) print_person::i#2) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuyy + lda (__2),y sta SCREEN,x // [22] (byte) idx#6 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx inx - // [23] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 -- vbuz1=_inc_vbuz1 - inc.z i - // [16] phi from print_person::@2 to print_person::@1 [phi:print_person::@2->print_person::@1] - b1_from_b2: - // [16] phi (byte) idx#14 = (byte) idx#6 [phi:print_person::@2->print_person::@1#0] -- register_copy - // [16] phi (byte) print_person::i#2 = (byte) print_person::i#1 [phi:print_person::@2->print_person::@1#1] -- register_copy - jmp b1 + // [23] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 -- vbuyy=_inc_vbuyy + iny + // [14] phi from print_person::@2 to print_person::@1 [phi:print_person::@2->print_person::@1] + __b1_from___b2: + // [14] phi (byte) idx#14 = (byte) idx#6 [phi:print_person::@2->print_person::@1#0] -- register_copy + // [14] phi (byte) print_person::i#2 = (byte) print_person::i#1 [phi:print_person::@2->print_person::@1#1] -- register_copy + jmp __b1 } // File Data DIGIT: .text "0123456789" .byte 0 + __0: .byte 4 + .text "jesper" + .byte 0 + .fill 9, 0 + __1: .byte 7 + .text "henriette" + .byte 0 + .fill 6, 0 ASSEMBLER OPTIMIZATIONS -Removing instruction jmp b1 -Removing instruction jmp bend -Removing instruction jmp b1 -Removing instruction jmp breturn -Removing instruction jmp b1 -Removing instruction jmp b3 -Removing instruction jmp breturn +Removing instruction jmp __b1 +Removing instruction jmp __bend +Removing instruction jmp __b1 +Removing instruction jmp __breturn +Removing instruction jmp __b1 +Removing instruction jmp __b3 +Removing instruction jmp __breturn Succesful ASM optimization Pass5NextJumpElimination -Removing instruction b1_from_bbegin: -Removing instruction b1: -Removing instruction bend_from_b1: +Replacing label __bbegin with __b1 +Removing instruction __bbegin: +Removing instruction __b1_from___bbegin: +Removing instruction __bend_from___b1: Succesful ASM optimization Pass5RedundantLabelElimination -Removing instruction bend: +Removing instruction __bend: Removing instruction print_person_from_main: -Removing instruction b1: -Removing instruction print_person_from_b1: -Removing instruction breturn: -Removing instruction b1_from_print_person: -Removing instruction b3: -Removing instruction breturn: -Removing instruction b1_from_b2: +Removing instruction __b1: +Removing instruction print_person_from___b1: +Removing instruction __breturn: +Removing instruction __b1_from_print_person: +Removing instruction __b3: +Removing instruction __breturn: +Removing instruction __b1_from___b2: Succesful ASM optimization Pass5UnusedLabelElimination Updating BasicUpstart to call main directly Removing instruction jsr main Succesful ASM optimization Pass5SkipBegin -Removing instruction bbegin: +Removing instruction __b1: Succesful ASM optimization Pass5UnusedLabelElimination FINAL SYMBOL TABLE +(const struct Person) $0 = { id: (byte) 4, name: (string) "jesper" } +(const struct Person) $1 = { id: (byte) 7, name: (string) "henriette" } (label) @1 (label) @begin (label) @end -(byte[]) DIGIT -(const byte[]) DIGIT#0 DIGIT = (string) "0123456789" -(const byte) OFFSET_STRUCT_PERSON_NAME OFFSET_STRUCT_PERSON_NAME = (byte) 1 +(const byte*) DIGIT[] = (string) "0123456789" +(const byte) OFFSET_STRUCT_PERSON_NAME = (byte) 1 (byte) Person::id -(byte[$10]) Person::name -(byte*) SCREEN -(const byte*) SCREEN#0 SCREEN = (byte*) 1024 +(const byte*) Person::name[(number) $10] = { fill( $10, 0) } +(const byte*) SCREEN = (byte*) 1024 +(const byte) SIZEOF_STRUCT_PERSON = (byte) $11 (byte) idx (byte) idx#13 reg byte x 3.0 -(byte) idx#14 reg byte x 9.75 -(byte) idx#16 reg byte x 0.8 +(byte) idx#14 reg byte x 6.5 +(byte) idx#16 reg byte x 1.0 (byte) idx#4 reg byte x 3.0 (byte) idx#5 reg byte x 4.0 (byte) idx#6 reg byte x 11.0 (void()) main() -(const string) main::$4 $4 = (string) "jesper" -(const string) main::$5 $5 = (string) "henriette" (label) main::@1 (label) main::@return -(struct Person) main::henriette -(byte) main::henriette_id -(byte) main::henriette_id#0 henriette_id zp ZP_BYTE:8 20.0 -(byte[$10]) main::henriette_name -(byte[$10]) main::henriette_name#0 henriette_name zp ZP_WORD:9 20.0 -(struct Person) main::jesper -(byte) main::jesper_id -(byte) main::jesper_id#0 jesper_id zp ZP_BYTE:5 20.0 -(byte[$10]) main::jesper_name -(byte[$10]) main::jesper_name#0 jesper_name zp ZP_WORD:6 20.0 +(struct Person) main::henriette loadstore zp[17]:25 +(struct Person) main::jesper loadstore zp[17]:8 (void()) print_person((struct Person*) print_person::person) +(byte*~) print_person::$1 zp[2]:4 22.0 +(byte*~) print_person::$2 zp[2]:6 22.0 (label) print_person::@1 (label) print_person::@2 (label) print_person::@3 (label) print_person::@return (byte) print_person::i -(byte) print_person::i#1 i zp ZP_BYTE:4 22.0 -(byte) print_person::i#2 i zp ZP_BYTE:4 11.0 +(byte) print_person::i#1 reg byte y 22.0 +(byte) print_person::i#2 reg byte y 7.333333333333333 (struct Person*) print_person::person -(struct Person*) print_person::person#2 person zp ZP_WORD:2 +(struct Person*) print_person::person#2 person zp[2]:2 -zp ZP_WORD:2 [ print_person::person#2 ] +zp[2]:2 [ print_person::person#2 ] reg byte x [ idx#13 idx#16 ] -zp ZP_BYTE:4 [ print_person::i#2 print_person::i#1 ] +reg byte y [ print_person::i#2 print_person::i#1 ] reg byte x [ idx#14 idx#5 idx#6 ] -zp ZP_BYTE:5 [ main::jesper_id#0 ] -zp ZP_WORD:6 [ main::jesper_name#0 ] -zp ZP_BYTE:8 [ main::henriette_id#0 ] -zp ZP_WORD:9 [ main::henriette_name#0 ] reg byte x [ idx#4 ] +zp[2]:4 [ print_person::$1 ] +zp[2]:6 [ print_person::$2 ] +zp[17]:8 [ main::jesper ] +zp[17]:25 [ main::henriette ] FINAL ASSEMBLER -Score: 950 +Score: 772 // File Comments // Example of a struct containing an array // It works on the surface - but illustrates the problem with structs containing arrays treating them like pointers. -// https://gitlab.com/camelot/kickc/issues/312 +// https://gitlab.com/camelot/kickc/issues/314 // Upstart .pc = $801 "Basic" :BasicUpstart(main) .pc = $80d "Program" // Global Constants & labels - .const OFFSET_STRUCT_PERSON_NAME = 1 .label SCREEN = $400 + .const SIZEOF_STRUCT_PERSON = $11 + .const OFFSET_STRUCT_PERSON_NAME = 1 // @begin // [1] phi from @begin to @1 [phi:@begin->@1] // @1 @@ -892,137 +830,139 @@ Score: 950 // @end // main main: { - .label jesper_id = 5 - .label jesper_name = 6 - .label henriette_id = 8 - .label henriette_name = 9 + .label jesper = 8 + .label henriette = $19 // jesper = { 4, "jesper" } - // [4] (byte) main::jesper_id#0 ← (byte) 4 -- vbuz1=vbuc1 - lda #4 - sta.z jesper_id - // [5] (byte[$10]) main::jesper_name#0 ← (const string) main::$4 -- pbuz1=pbuc1 - lda #<_4 - sta.z jesper_name - lda #>_4 - sta.z jesper_name+1 + // [4] *(&(struct Person) main::jesper) ← memcpy(*(&(const struct Person) $0), struct Person, (const byte) SIZEOF_STRUCT_PERSON) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3 + ldy #SIZEOF_STRUCT_PERSON + !: + lda __0-1,y + sta jesper-1,y + dey + bne !- // print_person(&jesper) - // [6] call print_person - // [11] phi from main to print_person [phi:main->print_person] - // [11] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#0] -- vbuxx=vbuc1 + // [5] call print_person + // [9] phi from main to print_person [phi:main->print_person] + // [9] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#0] -- vbuxx=vbuc1 ldx #0 - // [11] phi (struct Person*) print_person::person#2 = (struct Person*)&(byte) main::jesper_id#0 [phi:main->print_person#1] -- pssz1=pssc1 - lda #print_person#1] -- pssz1=pssc1 + lda #jesper_id + lda #>jesper sta.z print_person.person+1 jsr print_person // main::@1 // henriette = { 7, "henriette" } - // [7] (byte) main::henriette_id#0 ← (byte) 7 -- vbuz1=vbuc1 - lda #7 - sta.z henriette_id - // [8] (byte[$10]) main::henriette_name#0 ← (const string) main::$5 -- pbuz1=pbuc1 - lda #<_5 - sta.z henriette_name - lda #>_5 - sta.z henriette_name+1 + // [6] *(&(struct Person) main::henriette) ← memcpy(*(&(const struct Person) $1), struct Person, (const byte) SIZEOF_STRUCT_PERSON) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3 + ldy #SIZEOF_STRUCT_PERSON + !: + lda __1-1,y + sta henriette-1,y + dey + bne !- // print_person(&henriette) - // [9] call print_person - // [11] phi from main::@1 to print_person [phi:main::@1->print_person] - // [11] phi (byte) idx#13 = (byte) idx#16 [phi:main::@1->print_person#0] -- register_copy - // [11] phi (struct Person*) print_person::person#2 = (struct Person*)&(byte) main::henriette_id#0 [phi:main::@1->print_person#1] -- pssz1=pssc1 - lda #print_person] + // [9] phi (byte) idx#13 = (byte) idx#16 [phi:main::@1->print_person#0] -- register_copy + // [9] phi (struct Person*) print_person::person#2 = &(struct Person) main::henriette [phi:main::@1->print_person#1] -- pssz1=pssc1 + lda #henriette_id + lda #>henriette sta.z print_person.person+1 jsr print_person // main::@return // } - // [10] return + // [8] return rts - _4: .text "jesper" - .byte 0 - _5: .text "henriette" - .byte 0 } // print_person -// print_person(struct Person* zeropage(2) person) +// print_person(struct Person* zp(2) person) print_person: { - .label i = 4 + .label __1 = 4 + .label __2 = 6 .label person = 2 // SCREEN[idx++] = DIGIT[person->id] - // [12] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_(_deref_pbuz1) + // [10] *((const byte*) SCREEN + (byte) idx#13) ← *((const byte*) DIGIT + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_(_deref_pbuz1) ldy #0 lda (person),y tay lda DIGIT,y sta SCREEN,x // SCREEN[idx++] = DIGIT[person->id]; - // [13] (byte) idx#4 ← ++ (byte) idx#13 -- vbuxx=_inc_vbuxx + // [11] (byte) idx#4 ← ++ (byte) idx#13 -- vbuxx=_inc_vbuxx inx // SCREEN[idx++] = ' ' - // [14] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2 + // [12] *((const byte*) SCREEN + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2 lda #' ' sta SCREEN,x // SCREEN[idx++] = ' '; - // [15] (byte) idx#5 ← ++ (byte) idx#4 -- vbuxx=_inc_vbuxx + // [13] (byte) idx#5 ← ++ (byte) idx#4 -- vbuxx=_inc_vbuxx inx - // [16] phi from print_person to print_person::@1 [phi:print_person->print_person::@1] - // [16] phi (byte) idx#14 = (byte) idx#5 [phi:print_person->print_person::@1#0] -- register_copy - // [16] phi (byte) print_person::i#2 = (byte) 0 [phi:print_person->print_person::@1#1] -- vbuz1=vbuc1 - lda #0 - sta.z i + // [14] phi from print_person to print_person::@1 [phi:print_person->print_person::@1] + // [14] phi (byte) idx#14 = (byte) idx#5 [phi:print_person->print_person::@1#0] -- register_copy + // [14] phi (byte) print_person::i#2 = (byte) 0 [phi:print_person->print_person::@1#1] -- vbuyy=vbuc1 + ldy #0 // print_person::@1 - b1: + __b1: // for(byte i=0; person->name[i]; i++) - // [17] if((byte) 0!=*(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2)) goto print_person::@2 -- vbuc1_neq_(pptz1_derefidx_vbuc2)_derefidx_vbuz2_then_la1 - ldy #OFFSET_STRUCT_PERSON_NAME - lda (person),y - sta.z $fe - iny - lda (person),y - sta.z $ff - ldy.z i - lda ($fe),y + // [15] (byte*~) print_person::$1 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME -- pbuz1=pbuz2_plus_vbuc1 + lda #OFFSET_STRUCT_PERSON_NAME + clc + adc.z person + sta.z __1 + lda #0 + adc.z person+1 + sta.z __1+1 + // [16] if((byte) 0!=*((byte*~) print_person::$1 + (byte) print_person::i#2)) goto print_person::@2 -- vbuc1_neq_pbuz1_derefidx_vbuyy_then_la1 + lda (__1),y cmp #0 - bne b2 + bne __b2 // print_person::@3 // SCREEN[idx++] = ' ' - // [18] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2 + // [17] *((const byte*) SCREEN + (byte) idx#14) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2 lda #' ' sta SCREEN,x // SCREEN[idx++] = ' '; - // [19] (byte) idx#16 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx + // [18] (byte) idx#16 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx inx // print_person::@return // } - // [20] return + // [19] return rts // print_person::@2 - b2: + __b2: // SCREEN[idx++] = person->name[i] - // [21] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte[$10]*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) -- pbuc1_derefidx_vbuxx=(pptz1_derefidx_vbuc2)_derefidx_vbuz2 - ldy #OFFSET_STRUCT_PERSON_NAME - lda (person),y - sta.z $fe - iny - lda (person),y - sta.z $ff - ldy.z i - lda ($fe),y + // [20] (byte*~) print_person::$2 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME -- pbuz1=pbuz2_plus_vbuc1 + lda #OFFSET_STRUCT_PERSON_NAME + clc + adc.z person + sta.z __2 + lda #0 + adc.z person+1 + sta.z __2+1 + // [21] *((const byte*) SCREEN + (byte) idx#14) ← *((byte*~) print_person::$2 + (byte) print_person::i#2) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuyy + lda (__2),y sta SCREEN,x // SCREEN[idx++] = person->name[i]; // [22] (byte) idx#6 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx inx // for(byte i=0; person->name[i]; i++) - // [23] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 -- vbuz1=_inc_vbuz1 - inc.z i - // [16] phi from print_person::@2 to print_person::@1 [phi:print_person::@2->print_person::@1] - // [16] phi (byte) idx#14 = (byte) idx#6 [phi:print_person::@2->print_person::@1#0] -- register_copy - // [16] phi (byte) print_person::i#2 = (byte) print_person::i#1 [phi:print_person::@2->print_person::@1#1] -- register_copy - jmp b1 + // [23] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 -- vbuyy=_inc_vbuyy + iny + // [14] phi from print_person::@2 to print_person::@1 [phi:print_person::@2->print_person::@1] + // [14] phi (byte) idx#14 = (byte) idx#6 [phi:print_person::@2->print_person::@1#0] -- register_copy + // [14] phi (byte) print_person::i#2 = (byte) print_person::i#1 [phi:print_person::@2->print_person::@1#1] -- register_copy + jmp __b1 } // File Data DIGIT: .text "0123456789" .byte 0 + __0: .byte 4 + .text "jesper" + .byte 0 + .fill 9, 0 + __1: .byte 7 + .text "henriette" + .byte 0 + .fill 6, 0 diff --git a/src/test/ref/struct-ptr-28.sym b/src/test/ref/struct-ptr-28.sym index ebf9b75ff..bd1cee595 100644 --- a/src/test/ref/struct-ptr-28.sym +++ b/src/test/ref/struct-ptr-28.sym @@ -1,52 +1,45 @@ +(const struct Person) $0 = { id: (byte) 4, name: (string) "jesper" } +(const struct Person) $1 = { id: (byte) 7, name: (string) "henriette" } (label) @1 (label) @begin (label) @end -(byte[]) DIGIT -(const byte[]) DIGIT#0 DIGIT = (string) "0123456789" -(const byte) OFFSET_STRUCT_PERSON_NAME OFFSET_STRUCT_PERSON_NAME = (byte) 1 +(const byte*) DIGIT[] = (string) "0123456789" +(const byte) OFFSET_STRUCT_PERSON_NAME = (byte) 1 (byte) Person::id -(byte[$10]) Person::name -(byte*) SCREEN -(const byte*) SCREEN#0 SCREEN = (byte*) 1024 +(const byte*) Person::name[(number) $10] = { fill( $10, 0) } +(const byte*) SCREEN = (byte*) 1024 +(const byte) SIZEOF_STRUCT_PERSON = (byte) $11 (byte) idx (byte) idx#13 reg byte x 3.0 -(byte) idx#14 reg byte x 9.75 -(byte) idx#16 reg byte x 0.8 +(byte) idx#14 reg byte x 6.5 +(byte) idx#16 reg byte x 1.0 (byte) idx#4 reg byte x 3.0 (byte) idx#5 reg byte x 4.0 (byte) idx#6 reg byte x 11.0 (void()) main() -(const string) main::$4 $4 = (string) "jesper" -(const string) main::$5 $5 = (string) "henriette" (label) main::@1 (label) main::@return -(struct Person) main::henriette -(byte) main::henriette_id -(byte) main::henriette_id#0 henriette_id zp ZP_BYTE:8 20.0 -(byte[$10]) main::henriette_name -(byte[$10]) main::henriette_name#0 henriette_name zp ZP_WORD:9 20.0 -(struct Person) main::jesper -(byte) main::jesper_id -(byte) main::jesper_id#0 jesper_id zp ZP_BYTE:5 20.0 -(byte[$10]) main::jesper_name -(byte[$10]) main::jesper_name#0 jesper_name zp ZP_WORD:6 20.0 +(struct Person) main::henriette loadstore zp[17]:25 +(struct Person) main::jesper loadstore zp[17]:8 (void()) print_person((struct Person*) print_person::person) +(byte*~) print_person::$1 zp[2]:4 22.0 +(byte*~) print_person::$2 zp[2]:6 22.0 (label) print_person::@1 (label) print_person::@2 (label) print_person::@3 (label) print_person::@return (byte) print_person::i -(byte) print_person::i#1 i zp ZP_BYTE:4 22.0 -(byte) print_person::i#2 i zp ZP_BYTE:4 11.0 +(byte) print_person::i#1 reg byte y 22.0 +(byte) print_person::i#2 reg byte y 7.333333333333333 (struct Person*) print_person::person -(struct Person*) print_person::person#2 person zp ZP_WORD:2 +(struct Person*) print_person::person#2 person zp[2]:2 -zp ZP_WORD:2 [ print_person::person#2 ] +zp[2]:2 [ print_person::person#2 ] reg byte x [ idx#13 idx#16 ] -zp ZP_BYTE:4 [ print_person::i#2 print_person::i#1 ] +reg byte y [ print_person::i#2 print_person::i#1 ] reg byte x [ idx#14 idx#5 idx#6 ] -zp ZP_BYTE:5 [ main::jesper_id#0 ] -zp ZP_WORD:6 [ main::jesper_name#0 ] -zp ZP_BYTE:8 [ main::henriette_id#0 ] -zp ZP_WORD:9 [ main::henriette_name#0 ] reg byte x [ idx#4 ] +zp[2]:4 [ print_person::$1 ] +zp[2]:6 [ print_person::$2 ] +zp[17]:8 [ main::jesper ] +zp[17]:25 [ main::henriette ]