From 0c33353bf80d754a03844f48fcc685484b42a38f Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Thu, 25 Jul 2019 23:06:09 +0200 Subject: [PATCH] Fixed problems with sizeof()-handling struct members. Closes #230 --- .../kickc/passes/Pass1PointerSizeofFix.java | 59 ++- ...-pointer-inside-struct-sizeof-rewriting.kc | 10 +- ...pointer-inside-struct-sizeof-rewriting.asm | 34 +- ...pointer-inside-struct-sizeof-rewriting.cfg | 22 +- ...pointer-inside-struct-sizeof-rewriting.log | 443 ++++-------------- ...pointer-inside-struct-sizeof-rewriting.sym | 17 +- 6 files changed, 159 insertions(+), 426 deletions(-) diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1PointerSizeofFix.java b/src/main/java/dk/camelot64/kickc/passes/Pass1PointerSizeofFix.java index d3de1afd8..375a5538b 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1PointerSizeofFix.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1PointerSizeofFix.java @@ -9,12 +9,14 @@ import dk.camelot64.kickc.model.operators.OperatorSizeOf; import dk.camelot64.kickc.model.operators.Operators; import dk.camelot64.kickc.model.statements.Statement; import dk.camelot64.kickc.model.statements.StatementAssignment; +import dk.camelot64.kickc.model.symbols.StructDefinition; import dk.camelot64.kickc.model.symbols.Symbol; import dk.camelot64.kickc.model.symbols.Variable; import dk.camelot64.kickc.model.symbols.VariableIntermediate; import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolTypeInference; import dk.camelot64.kickc.model.types.SymbolTypePointer; +import dk.camelot64.kickc.model.types.SymbolTypeStruct; import dk.camelot64.kickc.model.values.*; import java.util.LinkedHashMap; @@ -38,25 +40,22 @@ public class Pass1PointerSizeofFix extends Pass1Base { Statement statement = stmtIt.next(); if(statement instanceof StatementAssignment) { StatementAssignment assignment = (StatementAssignment) statement; - if((assignment.getrValue1() == null) && (assignment.getOperator() != null) && (assignment.getrValue2() instanceof VariableRef)) { + if((assignment.getrValue1() == null) && (assignment.getOperator() != null) && (assignment.getrValue2() != null)) { fixPointerUnary(assignment); - } else if((assignment.getrValue1() instanceof VariableRef) && (assignment.getOperator() != null) && (assignment.getrValue2() != null)) { + } else if((assignment.getrValue1() != null) && (assignment.getOperator() != null) && (assignment.getrValue2() != null)) { fixPointerBinary(block, stmtIt, assignment); } } } } - // For each statement maps RValues used as index to the new *2 variable created + // For each statement maps RValues used as index to the new *sizeof() variable created Map> handled = new LinkedHashMap<>(); - ProgramValueIterator.execute(getProgram(), (programValue, currentStmt, stmtIt, currentBlock) -> { if(programValue.get() instanceof PointerDereferenceIndexed) { PointerDereferenceIndexed deref = (PointerDereferenceIndexed) programValue.get(); - if(deref.getPointer() instanceof VariableRef) { - VariableRef varRef = (VariableRef) deref.getPointer(); - Variable variable = getScope().getVariable(varRef); - SymbolTypePointer pointerType = (SymbolTypePointer) variable.getType(); + SymbolTypePointer pointerType = getPointerType(deref.getPointer()); + if(pointerType != null) { if(pointerType.getElementType().getSizeBytes() > 1) { // Array-indexing into a non-byte pointer - multiply by sizeof() getLog().append("Fixing pointer array-indexing " + deref.toString(getProgram())); @@ -78,7 +77,6 @@ public class Pass1PointerSizeofFix extends Pass1Base { } } }); - return false; } @@ -89,10 +87,8 @@ public class Pass1PointerSizeofFix extends Pass1Base { */ public void fixPointerBinary(ControlFlowBlock block, ListIterator stmtIt, StatementAssignment assignment) { - VariableRef varRef = (VariableRef) assignment.getrValue1(); - Variable variable = getScope().getVariable(varRef); - if(variable.getType() instanceof SymbolTypePointer) { - SymbolTypePointer pointerType = (SymbolTypePointer) variable.getType(); + SymbolTypePointer pointerType = getPointerType(assignment.getrValue1()); + if(pointerType != null) { if(SymbolType.VOID.equals(pointerType.getElementType())) { if(Operators.PLUS.equals(assignment.getOperator()) || Operators.MINUS.equals(assignment.getOperator())) { throw new CompileError("Void pointer math not allowed. ", assignment); @@ -139,11 +135,9 @@ public class Pass1PointerSizeofFix extends Pass1Base { * @param assignment The assignment statement */ public void fixPointerUnary(StatementAssignment assignment) { - // Found assignment of unary operator - VariableRef varRef = (VariableRef) assignment.getrValue2(); - Variable variable = getScope().getVariable(varRef); - if(variable.getType() instanceof SymbolTypePointer) { - SymbolTypePointer pointerType = (SymbolTypePointer) variable.getType(); + // Found assignment with unary operator + SymbolTypePointer pointerType = getPointerType(assignment.getrValue2()); + if(pointerType != null) { if(SymbolType.VOID.equals(pointerType.getElementType())) { if(Operators.INCREMENT.equals(assignment.getOperator()) || Operators.DECREMENT.equals(assignment.getOperator())) { throw new CompileError("Void pointer math not allowed. ", assignment); @@ -168,5 +162,34 @@ public class Pass1PointerSizeofFix extends Pass1Base { } } + /** + * Examine the passed value to determine if it is a pointer. + * If it is a pointer return the type of the pointer + * @param pointer The potential pointer to examine + * @return The type of the pointer - if the value was a pointer. null if the value is not a pointer. + */ + private SymbolTypePointer getPointerType(RValue pointer) { + if(pointer instanceof VariableRef) { + VariableRef varRef = (VariableRef) pointer; + Variable variable = getScope().getVariable(varRef); + SymbolType type = variable.getType(); + if(type instanceof SymbolTypePointer) { + return (SymbolTypePointer) type; + } + } else if(pointer instanceof StructMemberRef) { + StructMemberRef structMemberRef = (StructMemberRef) pointer; + RValue struct = structMemberRef.getStruct(); + SymbolType structType = SymbolTypeInference.inferType(getScope(), struct); + if(structType instanceof SymbolTypeStruct) { + StructDefinition structDefinition = ((SymbolTypeStruct) structType).getStructDefinition(getScope()); + Variable memberVariable = structDefinition.getMember(structMemberRef.getMemberName()); + SymbolType memberType = memberVariable.getType(); + if(memberType instanceof SymbolTypePointer) { + return (SymbolTypePointer) memberType; + } + } + } + return null; + } } diff --git a/src/test/kc/problem-pointer-inside-struct-sizeof-rewriting.kc b/src/test/kc/problem-pointer-inside-struct-sizeof-rewriting.kc index 2466c6f6d..7730529b9 100644 --- a/src/test/kc/problem-pointer-inside-struct-sizeof-rewriting.kc +++ b/src/test/kc/problem-pointer-inside-struct-sizeof-rewriting.kc @@ -8,11 +8,7 @@ struct RadixInfo { void main() { const unsigned int* SCREEN = 0x400; - for( byte radix: 0..1) { - struct RadixInfo info = { RADIX_DECIMAL_VALUES }; - for( char digit: 0..4 ) { - unsigned int digit_value = info.values[digit]; - SCREEN[digit] = digit_value; - } - } + struct RadixInfo info = { RADIX_DECIMAL_VALUES }; + SCREEN[0] = info.values[1]; + SCREEN[1] = RADIX_DECIMAL_VALUES[1]; } \ No newline at end of file diff --git a/src/test/ref/problem-pointer-inside-struct-sizeof-rewriting.asm b/src/test/ref/problem-pointer-inside-struct-sizeof-rewriting.asm index 400eb5faf..651da41bf 100644 --- a/src/test/ref/problem-pointer-inside-struct-sizeof-rewriting.asm +++ b/src/test/ref/problem-pointer-inside-struct-sizeof-rewriting.asm @@ -2,33 +2,17 @@ .pc = $801 "Basic" :BasicUpstart(main) .pc = $80d "Program" + .const SIZEOF_WORD = 2 main: { .label SCREEN = $400 - .label digit_value = 3 - .label radix = 2 - lda #0 - sta radix - b1: - ldx #0 - b2: - lda RADIX_DECIMAL_VALUES,x - sta digit_value - lda RADIX_DECIMAL_VALUES+1,x - sta digit_value+1 - txa - asl - tay - lda digit_value - sta SCREEN,y - lda digit_value+1 - sta SCREEN+1,y - inx - cpx #5 - bne b2 - inc radix - lda #2 - cmp radix - bne b1 + lda RADIX_DECIMAL_VALUES+1*SIZEOF_WORD + sta SCREEN + lda RADIX_DECIMAL_VALUES+1*SIZEOF_WORD+1 + sta SCREEN+1 + lda RADIX_DECIMAL_VALUES+1*SIZEOF_WORD + sta SCREEN+1*SIZEOF_WORD + lda RADIX_DECIMAL_VALUES+1*SIZEOF_WORD+1 + sta SCREEN+1*SIZEOF_WORD+1 rts } RADIX_DECIMAL_VALUES: .word $2710, $3e8, $64, $a diff --git a/src/test/ref/problem-pointer-inside-struct-sizeof-rewriting.cfg b/src/test/ref/problem-pointer-inside-struct-sizeof-rewriting.cfg index 938440737..24ddf1201 100644 --- a/src/test/ref/problem-pointer-inside-struct-sizeof-rewriting.cfg +++ b/src/test/ref/problem-pointer-inside-struct-sizeof-rewriting.cfg @@ -8,23 +8,9 @@ @end: scope:[] from @1 [3] phi() main: scope:[main] from @1 - [4] phi() - to:main::@1 -main::@1: scope:[main] from main main::@3 - [5] (byte) main::radix#4 ← phi( main/(byte) 0 main::@3/(byte) main::radix#1 ) - to:main::@2 -main::@2: scope:[main] from main::@1 main::@2 - [6] (byte) main::digit#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::digit#1 ) - [7] (word) main::digit_value#0 ← *((const word[]) RADIX_DECIMAL_VALUES#0 + (byte) main::digit#2) - [8] (byte~) main::$2 ← (byte) main::digit#2 << (byte) 1 - [9] *((const word*) main::SCREEN#0 + (byte~) main::$2) ← (word) main::digit_value#0 - [10] (byte) main::digit#1 ← ++ (byte) main::digit#2 - [11] if((byte) main::digit#1!=(byte) 5) goto main::@2 - to:main::@3 -main::@3: scope:[main] from main::@2 - [12] (byte) main::radix#1 ← ++ (byte) main::radix#4 - [13] if((byte) main::radix#1!=(byte) 2) goto main::@1 + [4] *((const word*) main::SCREEN#0) ← *((const word[]) RADIX_DECIMAL_VALUES#0+(byte) 1*(const byte) SIZEOF_WORD) + [5] *((const word*) main::SCREEN#0+(byte) 1*(const byte) SIZEOF_WORD) ← *((const word[]) RADIX_DECIMAL_VALUES#0+(byte) 1*(const byte) SIZEOF_WORD) to:main::@return -main::@return: scope:[main] from main::@3 - [14] return +main::@return: scope:[main] from main + [6] return to:@return diff --git a/src/test/ref/problem-pointer-inside-struct-sizeof-rewriting.log b/src/test/ref/problem-pointer-inside-struct-sizeof-rewriting.log index a32df8114..e4ad1e609 100644 --- a/src/test/ref/problem-pointer-inside-struct-sizeof-rewriting.log +++ b/src/test/ref/problem-pointer-inside-struct-sizeof-rewriting.log @@ -1,9 +1,11 @@ -Fixing pointer array-indexing *((word*) main::SCREEN + (byte) main::digit) +Fixing pointer array-indexing *((struct RadixInfo) main::info.values + (number) 1) +Fixing pointer array-indexing *((word*) main::SCREEN + (number) 0) +Fixing pointer array-indexing *((word[]) RADIX_DECIMAL_VALUES + (number) 1) +Fixing pointer array-indexing *((word*) main::SCREEN + (number) 1) Created struct value member variable (word*) main::info_values Converted struct value to member variables (struct RadixInfo) main::info Adding struct value list initializer (word*) main::info_values ← (word[]) RADIX_DECIMAL_VALUES Replacing struct member reference (struct RadixInfo) main::info.values with member variable reference (word*) main::info_values -Culled Empty Block (label) main::@4 CONTROL FLOW GRAPH SSA @begin: scope:[] from @@ -11,31 +13,14 @@ CONTROL FLOW GRAPH SSA to:@1 main: scope:[main] from @1 (word*) main::SCREEN#0 ← ((word*)) (number) $400 - (byte) main::radix#0 ← (byte) 0 - to:main::@1 -main::@1: scope:[main] from main main::@3 - (byte) main::radix#4 ← phi( main/(byte) main::radix#0 main::@3/(byte) main::radix#1 ) (word*) main::info_values#0 ← (word[]) RADIX_DECIMAL_VALUES#0 - (byte) main::digit#0 ← (byte) 0 - to:main::@2 -main::@2: scope:[main] from main::@1 main::@2 - (byte) main::radix#3 ← phi( main::@1/(byte) main::radix#4 main::@2/(byte) main::radix#3 ) - (byte) main::digit#2 ← phi( main::@1/(byte) main::digit#0 main::@2/(byte) main::digit#1 ) - (word*) main::info_values#1 ← phi( main::@1/(word*) main::info_values#0 main::@2/(word*) main::info_values#1 ) - (word) main::digit_value#0 ← *((word*) main::info_values#1 + (byte) main::digit#2) - (byte~) main::$2 ← (byte) main::digit#2 * (const byte) SIZEOF_WORD - *((word*) main::SCREEN#0 + (byte~) main::$2) ← (word) main::digit_value#0 - (byte) main::digit#1 ← (byte) main::digit#2 + rangenext(0,4) - (bool~) main::$0 ← (byte) main::digit#1 != rangelast(0,4) - if((bool~) main::$0) goto main::@2 - to:main::@3 -main::@3: scope:[main] from main::@2 - (byte) main::radix#2 ← phi( main::@2/(byte) main::radix#3 ) - (byte) main::radix#1 ← (byte) main::radix#2 + rangenext(0,1) - (bool~) main::$1 ← (byte) main::radix#1 != rangelast(0,1) - if((bool~) main::$1) goto main::@1 + (number~) main::$0 ← (number) 1 * (const byte) SIZEOF_WORD + (number~) main::$1 ← (number) 0 * (const byte) SIZEOF_WORD + *((word*) main::SCREEN#0 + (number~) main::$1) ← *((word*) main::info_values#0 + (number~) main::$0) + (number~) main::$2 ← (number) 1 * (const byte) SIZEOF_WORD + *((word*) main::SCREEN#0 + (number~) main::$2) ← *((word[]) RADIX_DECIMAL_VALUES#0 + (number~) main::$2) to:main::@return -main::@return: scope:[main] from main::@3 +main::@return: scope:[main] from main return to:@return @1: scope:[] from @begin @@ -55,31 +40,22 @@ SYMBOL TABLE SSA (word*) RadixInfo::values (const byte) SIZEOF_WORD = (byte) 2 (void()) main() -(bool~) main::$0 -(bool~) main::$1 -(byte~) main::$2 -(label) main::@1 -(label) main::@2 -(label) main::@3 +(number~) main::$0 +(number~) main::$1 +(number~) main::$2 (label) main::@return (word*) main::SCREEN (word*) main::SCREEN#0 -(byte) main::digit -(byte) main::digit#0 -(byte) main::digit#1 -(byte) main::digit#2 -(word) main::digit_value -(word) main::digit_value#0 (word*) main::info_values (word*) main::info_values#0 -(word*) main::info_values#1 -(byte) main::radix -(byte) main::radix#0 -(byte) main::radix#1 -(byte) main::radix#2 -(byte) main::radix#3 -(byte) main::radix#4 +Adding number conversion cast (unumber) 1 in (number~) main::$0 ← (number) 1 * (const byte) SIZEOF_WORD +Adding number conversion cast (unumber) main::$0 in (number~) main::$0 ← (unumber)(number) 1 * (const byte) SIZEOF_WORD +Adding number conversion cast (unumber) 0 in (number~) main::$1 ← (number) 0 * (const byte) SIZEOF_WORD +Adding number conversion cast (unumber) main::$1 in (number~) main::$1 ← (unumber)(number) 0 * (const byte) SIZEOF_WORD +Adding number conversion cast (unumber) 1 in (number~) main::$2 ← (number) 1 * (const byte) SIZEOF_WORD +Adding number conversion cast (unumber) main::$2 in (number~) main::$2 ← (unumber)(number) 1 * (const byte) SIZEOF_WORD +Successful SSA optimization PassNAddNumberTypeConversions Adding number conversion cast (word) to elements in (word[]) RADIX_DECIMAL_VALUES#0 ← { (word)(number) $2710, (word)(number) $3e8, (word)(number) $64, (word)(number) $a } Successful SSA optimization PassNAddArrayNumberTypeConversions Inlining cast (word*) main::SCREEN#0 ← (word*)(number) $400 @@ -89,68 +65,57 @@ Simplifying constant integer cast $3e8 Simplifying constant integer cast $64 Simplifying constant integer cast $a Simplifying constant pointer cast (word*) 1024 +Simplifying constant integer cast 1 +Simplifying constant integer cast 0 +Simplifying constant integer cast 1 Successful SSA optimization PassNCastSimplification -Alias (byte) main::radix#2 = (byte) main::radix#3 -Successful SSA optimization Pass2AliasElimination -Identical Phi Values (word*) main::info_values#1 (word*) main::info_values#0 -Identical Phi Values (byte) main::radix#2 (byte) main::radix#4 -Successful SSA optimization Pass2IdenticalPhiElimination -Simple Condition (bool~) main::$0 [12] if((byte) main::digit#1!=rangelast(0,4)) goto main::@2 -Simple Condition (bool~) main::$1 [16] if((byte) main::radix#1!=rangelast(0,1)) goto main::@1 -Successful SSA optimization Pass2ConditionalJumpSimplification +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 1 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Inferred type updated to byte in (unumber~) main::$0 ← (byte) 1 * (const byte) SIZEOF_WORD +Inferred type updated to byte in (unumber~) main::$1 ← (byte) 0 * (const byte) SIZEOF_WORD +Inferred type updated to byte in (unumber~) main::$2 ← (byte) 1 * (const byte) SIZEOF_WORD Constant right-side identified [0] (word[]) RADIX_DECIMAL_VALUES#0 ← { (word) $2710, (word) $3e8, (word) $64, (word) $a } +Constant right-side identified [3] (byte~) main::$0 ← (byte) 1 * (const byte) SIZEOF_WORD +Constant right-side identified [4] (byte~) main::$1 ← (byte) 0 * (const byte) SIZEOF_WORD +Constant right-side identified [6] (byte~) main::$2 ← (byte) 1 * (const byte) SIZEOF_WORD Successful SSA optimization Pass2ConstantRValueConsolidation Constant (const word[]) RADIX_DECIMAL_VALUES#0 = { $2710, $3e8, $64, $a } Constant (const word*) main::SCREEN#0 = (word*) 1024 -Constant (const byte) main::radix#0 = 0 -Constant (const byte) main::digit#0 = 0 +Constant (const byte) main::$0 = 1*SIZEOF_WORD +Constant (const byte) main::$1 = 0*SIZEOF_WORD +Constant (const byte) main::$2 = 1*SIZEOF_WORD Successful SSA optimization Pass2ConstantIdentification Constant (const word*) main::info_values#0 = RADIX_DECIMAL_VALUES#0 Successful SSA optimization Pass2ConstantIdentification -Resolved ranged next value [10] main::digit#1 ← ++ main::digit#2 to ++ -Resolved ranged comparison value [12] if(main::digit#1!=rangelast(0,4)) goto main::@2 to (number) 5 -Resolved ranged next value [14] main::radix#1 ← ++ main::radix#4 to ++ -Resolved ranged comparison value [16] if(main::radix#1!=rangelast(0,1)) goto main::@1 to (number) 2 -Adding number conversion cast (unumber) 5 in if((byte) main::digit#1!=(number) 5) goto main::@2 -Adding number conversion cast (unumber) 2 in if((byte) main::radix#1!=(number) 2) goto main::@1 -Successful SSA optimization PassNAddNumberTypeConversions -Simplifying constant integer cast 5 -Simplifying constant integer cast 2 -Successful SSA optimization PassNCastSimplification -Finalized unsigned number type (byte) 5 -Finalized unsigned number type (byte) 2 -Successful SSA optimization PassNFinalizeNumberTypeConversions -Rewriting multiplication to use shift [3] (byte~) main::$2 ← (byte) main::digit#2 * (const byte) SIZEOF_WORD -Successful SSA optimization Pass2MultiplyToShiftRewriting -Inlining constant with var siblings (const byte) main::radix#0 -Inlining constant with var siblings (const byte) main::digit#0 -Constant inlined main::info_values#0 = (const word[]) RADIX_DECIMAL_VALUES#0 -Constant inlined main::radix#0 = (byte) 0 -Constant inlined main::digit#0 = (byte) 0 -Successful SSA optimization Pass2ConstantInlining -Eliminating unused constant (const byte) SIZEOF_WORD +Simplifying constant evaluating to zero (byte) 0*(const byte) SIZEOF_WORD in +Successful SSA optimization PassNSimplifyConstantZero +Simplifying expression containing zero main::SCREEN#0 in [5] *((const word*) main::SCREEN#0 + (const byte) main::$1) ← *((const word*) main::info_values#0 + (const byte) main::$0) +Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused constant (const byte) main::$1 Successful SSA optimization PassNEliminateUnusedVars -Added new block during phi lifting main::@5(between main::@3 and main::@1) -Added new block during phi lifting main::@6(between main::@2 and main::@2) +Constant inlined main::info_values#0 = (const word[]) RADIX_DECIMAL_VALUES#0 +Constant inlined main::$2 = (byte) 1*(const byte) SIZEOF_WORD +Constant inlined main::$0 = (byte) 1*(const byte) SIZEOF_WORD +Successful SSA optimization Pass2ConstantInlining +Consolidated array index constant in *(RADIX_DECIMAL_VALUES#0+1*SIZEOF_WORD) +Consolidated array index constant in *(RADIX_DECIMAL_VALUES#0+1*SIZEOF_WORD) +Consolidated array index constant in *(main::SCREEN#0+1*SIZEOF_WORD) +Successful SSA optimization Pass2ConstantAdditionElimination Adding NOP phi() at start of @begin Adding NOP phi() at start of @1 Adding NOP phi() at start of @2 Adding NOP phi() at start of @end -Adding NOP phi() at start of main CALL GRAPH Calls in [] to main:2 -Created 2 initial phi equivalence classes -Coalesced [16] main::radix#5 ← main::radix#1 -Coalesced [17] main::digit#3 ← main::digit#1 -Coalesced down to 2 phi equivalence classes +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes Culled Empty Block (label) @2 -Culled Empty Block (label) main::@5 -Culled Empty Block (label) main::@6 Adding NOP phi() at start of @begin Adding NOP phi() at start of @1 Adding NOP phi() at start of @end -Adding NOP phi() at start of main FINAL CONTROL FLOW GRAPH @begin: scope:[] from @@ -163,25 +128,11 @@ FINAL CONTROL FLOW GRAPH @end: scope:[] from @1 [3] phi() main: scope:[main] from @1 - [4] phi() - to:main::@1 -main::@1: scope:[main] from main main::@3 - [5] (byte) main::radix#4 ← phi( main/(byte) 0 main::@3/(byte) main::radix#1 ) - to:main::@2 -main::@2: scope:[main] from main::@1 main::@2 - [6] (byte) main::digit#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::digit#1 ) - [7] (word) main::digit_value#0 ← *((const word[]) RADIX_DECIMAL_VALUES#0 + (byte) main::digit#2) - [8] (byte~) main::$2 ← (byte) main::digit#2 << (byte) 1 - [9] *((const word*) main::SCREEN#0 + (byte~) main::$2) ← (word) main::digit_value#0 - [10] (byte) main::digit#1 ← ++ (byte) main::digit#2 - [11] if((byte) main::digit#1!=(byte) 5) goto main::@2 - to:main::@3 -main::@3: scope:[main] from main::@2 - [12] (byte) main::radix#1 ← ++ (byte) main::radix#4 - [13] if((byte) main::radix#1!=(byte) 2) goto main::@1 + [4] *((const word*) main::SCREEN#0) ← *((const word[]) RADIX_DECIMAL_VALUES#0+(byte) 1*(const byte) SIZEOF_WORD) + [5] *((const word*) main::SCREEN#0+(byte) 1*(const byte) SIZEOF_WORD) ← *((const word[]) RADIX_DECIMAL_VALUES#0+(byte) 1*(const byte) SIZEOF_WORD) to:main::@return -main::@return: scope:[main] from main::@3 - [14] return +main::@return: scope:[main] from main + [6] return to:@return @@ -189,32 +140,11 @@ VARIABLE REGISTER WEIGHTS (word[]) RADIX_DECIMAL_VALUES (word*) RadixInfo::values (void()) main() -(byte~) main::$2 202.0 (word*) main::SCREEN -(byte) main::digit -(byte) main::digit#1 151.5 -(byte) main::digit#2 101.0 -(word) main::digit_value -(word) main::digit_value#0 101.0 (word*) main::info_values -(byte) main::radix -(byte) main::radix#1 16.5 -(byte) main::radix#4 3.142857142857143 Initial phi equivalence classes -[ main::radix#4 main::radix#1 ] -[ main::digit#2 main::digit#1 ] -Added variable main::digit_value#0 to zero page equivalence class [ main::digit_value#0 ] -Added variable main::$2 to zero page equivalence class [ main::$2 ] Complete equivalence classes -[ main::radix#4 main::radix#1 ] -[ main::digit#2 main::digit#1 ] -[ main::digit_value#0 ] -[ main::$2 ] -Allocated zp ZP_BYTE:2 [ main::radix#4 main::radix#1 ] -Allocated zp ZP_BYTE:3 [ main::digit#2 main::digit#1 ] -Allocated zp ZP_WORD:4 [ main::digit_value#0 ] -Allocated zp ZP_BYTE:6 [ main::$2 ] INITIAL ASM Target platform is c64basic @@ -225,6 +155,7 @@ Target platform is c64basic :BasicUpstart(bbegin) .pc = $80d "Program" // Global Constants & labels + .const SIZEOF_WORD = 2 // @begin bbegin: // [1] phi from @begin to @1 [phi:@begin->@1] @@ -233,8 +164,6 @@ b1_from_bbegin: // @1 b1: // [2] call main - // [4] phi from @1 to main [phi:@1->main] -main_from_b1: jsr main // [3] phi from @1 to @end [phi:@1->@end] bend_from_b1: @@ -244,99 +173,37 @@ bend: // main main: { .label SCREEN = $400 - .label _2 = 6 - .label digit_value = 4 - .label digit = 3 - .label radix = 2 - // [5] phi from main to main::@1 [phi:main->main::@1] - b1_from_main: - // [5] phi (byte) main::radix#4 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 - lda #0 - sta radix - jmp b1 - // [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1] - b1_from_b3: - // [5] phi (byte) main::radix#4 = (byte) main::radix#1 [phi:main::@3->main::@1#0] -- register_copy - jmp b1 - // main::@1 - b1: - // [6] phi from main::@1 to main::@2 [phi:main::@1->main::@2] - b2_from_b1: - // [6] phi (byte) main::digit#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1 - lda #0 - sta digit - jmp b2 - // [6] phi from main::@2 to main::@2 [phi:main::@2->main::@2] - b2_from_b2: - // [6] phi (byte) main::digit#2 = (byte) main::digit#1 [phi:main::@2->main::@2#0] -- register_copy - jmp b2 - // main::@2 - b2: - // [7] (word) main::digit_value#0 ← *((const word[]) RADIX_DECIMAL_VALUES#0 + (byte) main::digit#2) -- vwuz1=pwuc1_derefidx_vbuz2 - ldy digit - lda RADIX_DECIMAL_VALUES,y - sta digit_value - lda RADIX_DECIMAL_VALUES+1,y - sta digit_value+1 - // [8] (byte~) main::$2 ← (byte) main::digit#2 << (byte) 1 -- vbuz1=vbuz2_rol_1 - lda digit - asl - sta _2 - // [9] *((const word*) main::SCREEN#0 + (byte~) main::$2) ← (word) main::digit_value#0 -- pwuc1_derefidx_vbuz1=vwuz2 - ldy _2 - lda digit_value - sta SCREEN,y - lda digit_value+1 - sta SCREEN+1,y - // [10] (byte) main::digit#1 ← ++ (byte) main::digit#2 -- vbuz1=_inc_vbuz1 - inc digit - // [11] if((byte) main::digit#1!=(byte) 5) goto main::@2 -- vbuz1_neq_vbuc1_then_la1 - lda #5 - cmp digit - bne b2_from_b2 - jmp b3 - // main::@3 - b3: - // [12] (byte) main::radix#1 ← ++ (byte) main::radix#4 -- vbuz1=_inc_vbuz1 - inc radix - // [13] if((byte) main::radix#1!=(byte) 2) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 - lda #2 - cmp radix - bne b1_from_b3 + // [4] *((const word*) main::SCREEN#0) ← *((const word[]) RADIX_DECIMAL_VALUES#0+(byte) 1*(const byte) SIZEOF_WORD) -- _deref_pwuc1=_deref_pwuc2 + lda RADIX_DECIMAL_VALUES+1*SIZEOF_WORD + sta SCREEN + lda RADIX_DECIMAL_VALUES+1*SIZEOF_WORD+1 + sta SCREEN+1 + // [5] *((const word*) main::SCREEN#0+(byte) 1*(const byte) SIZEOF_WORD) ← *((const word[]) RADIX_DECIMAL_VALUES#0+(byte) 1*(const byte) SIZEOF_WORD) -- _deref_pwuc1=_deref_pwuc2 + lda RADIX_DECIMAL_VALUES+1*SIZEOF_WORD + sta SCREEN+1*SIZEOF_WORD + lda RADIX_DECIMAL_VALUES+1*SIZEOF_WORD+1 + sta SCREEN+1*SIZEOF_WORD+1 jmp breturn // main::@return breturn: - // [14] return + // [6] return rts } // File Data RADIX_DECIMAL_VALUES: .word $2710, $3e8, $64, $a REGISTER UPLIFT POTENTIAL REGISTERS -Statement [7] (word) main::digit_value#0 ← *((const word[]) RADIX_DECIMAL_VALUES#0 + (byte) main::digit#2) [ main::radix#4 main::digit#2 main::digit_value#0 ] ( main:2 [ main::radix#4 main::digit#2 main::digit_value#0 ] ) always clobbers reg byte a -Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::radix#4 main::radix#1 ] -Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::digit#2 main::digit#1 ] -Statement [8] (byte~) main::$2 ← (byte) main::digit#2 << (byte) 1 [ main::radix#4 main::digit#2 main::digit_value#0 main::$2 ] ( main:2 [ main::radix#4 main::digit#2 main::digit_value#0 main::$2 ] ) always clobbers reg byte a -Statement [9] *((const word*) main::SCREEN#0 + (byte~) main::$2) ← (word) main::digit_value#0 [ main::radix#4 main::digit#2 ] ( main:2 [ main::radix#4 main::digit#2 ] ) always clobbers reg byte a -Statement [7] (word) main::digit_value#0 ← *((const word[]) RADIX_DECIMAL_VALUES#0 + (byte) main::digit#2) [ main::radix#4 main::digit#2 main::digit_value#0 ] ( main:2 [ main::radix#4 main::digit#2 main::digit_value#0 ] ) always clobbers reg byte a -Statement [8] (byte~) main::$2 ← (byte) main::digit#2 << (byte) 1 [ main::radix#4 main::digit#2 main::digit_value#0 main::$2 ] ( main:2 [ main::radix#4 main::digit#2 main::digit_value#0 main::$2 ] ) always clobbers reg byte a -Statement [9] *((const word*) main::SCREEN#0 + (byte~) main::$2) ← (word) main::digit_value#0 [ main::radix#4 main::digit#2 ] ( main:2 [ main::radix#4 main::digit#2 ] ) always clobbers reg byte a -Potential registers zp ZP_BYTE:2 [ main::radix#4 main::radix#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y , -Potential registers zp ZP_BYTE:3 [ main::digit#2 main::digit#1 ] : zp ZP_BYTE:3 , reg byte x , reg byte y , -Potential registers zp ZP_WORD:4 [ main::digit_value#0 ] : zp ZP_WORD:4 , -Potential registers zp ZP_BYTE:6 [ main::$2 ] : zp ZP_BYTE:6 , reg byte a , reg byte x , reg byte y , +Statement [4] *((const word*) main::SCREEN#0) ← *((const word[]) RADIX_DECIMAL_VALUES#0+(byte) 1*(const byte) SIZEOF_WORD) [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [5] *((const word*) main::SCREEN#0+(byte) 1*(const byte) SIZEOF_WORD) ← *((const word[]) RADIX_DECIMAL_VALUES#0+(byte) 1*(const byte) SIZEOF_WORD) [ ] ( main:2 [ ] ) always clobbers reg byte a REGISTER UPLIFT SCOPES -Uplift Scope [main] 252.5: zp ZP_BYTE:3 [ main::digit#2 main::digit#1 ] 202: zp ZP_BYTE:6 [ main::$2 ] 101: zp ZP_WORD:4 [ main::digit_value#0 ] 19.64: zp ZP_BYTE:2 [ main::radix#4 main::radix#1 ] Uplift Scope [RadixInfo] +Uplift Scope [main] Uplift Scope [] -Uplifting [main] best 5733 combination reg byte x [ main::digit#2 main::digit#1 ] reg byte a [ main::$2 ] zp ZP_WORD:4 [ main::digit_value#0 ] zp ZP_BYTE:2 [ main::radix#4 main::radix#1 ] -Uplifting [RadixInfo] best 5733 combination -Uplifting [] best 5733 combination -Attempting to uplift remaining variables inzp ZP_BYTE:2 [ main::radix#4 main::radix#1 ] -Uplifting [main] best 5733 combination zp ZP_BYTE:2 [ main::radix#4 main::radix#1 ] -Allocated (was zp ZP_WORD:4) zp ZP_WORD:3 [ main::digit_value#0 ] +Uplifting [RadixInfo] best 53 combination +Uplifting [main] best 53 combination +Uplifting [] best 53 combination ASSEMBLER BEFORE OPTIMIZATION // File Comments @@ -346,6 +213,7 @@ ASSEMBLER BEFORE OPTIMIZATION :BasicUpstart(bbegin) .pc = $80d "Program" // Global Constants & labels + .const SIZEOF_WORD = 2 // @begin bbegin: // [1] phi from @begin to @1 [phi:@begin->@1] @@ -354,8 +222,6 @@ b1_from_bbegin: // @1 b1: // [2] call main - // [4] phi from @1 to main [phi:@1->main] -main_from_b1: jsr main // [3] phi from @1 to @end [phi:@1->@end] bend_from_b1: @@ -365,63 +231,20 @@ bend: // main main: { .label SCREEN = $400 - .label digit_value = 3 - .label radix = 2 - // [5] phi from main to main::@1 [phi:main->main::@1] - b1_from_main: - // [5] phi (byte) main::radix#4 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 - lda #0 - sta radix - jmp b1 - // [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1] - b1_from_b3: - // [5] phi (byte) main::radix#4 = (byte) main::radix#1 [phi:main::@3->main::@1#0] -- register_copy - jmp b1 - // main::@1 - b1: - // [6] phi from main::@1 to main::@2 [phi:main::@1->main::@2] - b2_from_b1: - // [6] phi (byte) main::digit#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuxx=vbuc1 - ldx #0 - jmp b2 - // [6] phi from main::@2 to main::@2 [phi:main::@2->main::@2] - b2_from_b2: - // [6] phi (byte) main::digit#2 = (byte) main::digit#1 [phi:main::@2->main::@2#0] -- register_copy - jmp b2 - // main::@2 - b2: - // [7] (word) main::digit_value#0 ← *((const word[]) RADIX_DECIMAL_VALUES#0 + (byte) main::digit#2) -- vwuz1=pwuc1_derefidx_vbuxx - lda RADIX_DECIMAL_VALUES,x - sta digit_value - lda RADIX_DECIMAL_VALUES+1,x - sta digit_value+1 - // [8] (byte~) main::$2 ← (byte) main::digit#2 << (byte) 1 -- vbuaa=vbuxx_rol_1 - txa - asl - // [9] *((const word*) main::SCREEN#0 + (byte~) main::$2) ← (word) main::digit_value#0 -- pwuc1_derefidx_vbuaa=vwuz1 - tay - lda digit_value - sta SCREEN,y - lda digit_value+1 - sta SCREEN+1,y - // [10] (byte) main::digit#1 ← ++ (byte) main::digit#2 -- vbuxx=_inc_vbuxx - inx - // [11] if((byte) main::digit#1!=(byte) 5) goto main::@2 -- vbuxx_neq_vbuc1_then_la1 - cpx #5 - bne b2_from_b2 - jmp b3 - // main::@3 - b3: - // [12] (byte) main::radix#1 ← ++ (byte) main::radix#4 -- vbuz1=_inc_vbuz1 - inc radix - // [13] if((byte) main::radix#1!=(byte) 2) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 - lda #2 - cmp radix - bne b1_from_b3 + // [4] *((const word*) main::SCREEN#0) ← *((const word[]) RADIX_DECIMAL_VALUES#0+(byte) 1*(const byte) SIZEOF_WORD) -- _deref_pwuc1=_deref_pwuc2 + lda RADIX_DECIMAL_VALUES+1*SIZEOF_WORD + sta SCREEN + lda RADIX_DECIMAL_VALUES+1*SIZEOF_WORD+1 + sta SCREEN+1 + // [5] *((const word*) main::SCREEN#0+(byte) 1*(const byte) SIZEOF_WORD) ← *((const word[]) RADIX_DECIMAL_VALUES#0+(byte) 1*(const byte) SIZEOF_WORD) -- _deref_pwuc1=_deref_pwuc2 + lda RADIX_DECIMAL_VALUES+1*SIZEOF_WORD + sta SCREEN+1*SIZEOF_WORD + lda RADIX_DECIMAL_VALUES+1*SIZEOF_WORD+1 + sta SCREEN+1*SIZEOF_WORD+1 jmp breturn // main::@return breturn: - // [14] return + // [6] return rts } // File Data @@ -430,32 +253,18 @@ main: { ASSEMBLER OPTIMIZATIONS Removing instruction jmp b1 Removing instruction jmp bend -Removing instruction jmp b1 -Removing instruction jmp b2 -Removing instruction jmp b3 Removing instruction jmp breturn Succesful ASM optimization Pass5NextJumpElimination -Replacing label b2_from_b2 with b2 -Replacing label b1_from_b3 with b1 Removing instruction b1_from_bbegin: Removing instruction b1: -Removing instruction main_from_b1: Removing instruction bend_from_b1: -Removing instruction b1_from_b3: -Removing instruction b2_from_b1: -Removing instruction b2_from_b2: Succesful ASM optimization Pass5RedundantLabelElimination Removing instruction bend: -Removing instruction b1_from_main: -Removing instruction b3: Removing instruction breturn: Succesful ASM optimization Pass5UnusedLabelElimination Updating BasicUpstart to call main directly Removing instruction jsr main Succesful ASM optimization Pass5SkipBegin -Removing instruction jmp b1 -Removing instruction jmp b2 -Succesful ASM optimization Pass5NextJumpElimination Removing instruction bbegin: Succesful ASM optimization Pass5UnusedLabelElimination @@ -466,32 +275,17 @@ FINAL SYMBOL TABLE (word[]) RADIX_DECIMAL_VALUES (const word[]) RADIX_DECIMAL_VALUES#0 RADIX_DECIMAL_VALUES = { (word) $2710, (word) $3e8, (word) $64, (word) $a } (word*) RadixInfo::values +(const byte) SIZEOF_WORD SIZEOF_WORD = (byte) 2 (void()) main() -(byte~) main::$2 reg byte a 202.0 -(label) main::@1 -(label) main::@2 -(label) main::@3 (label) main::@return (word*) main::SCREEN (const word*) main::SCREEN#0 SCREEN = (word*) 1024 -(byte) main::digit -(byte) main::digit#1 reg byte x 151.5 -(byte) main::digit#2 reg byte x 101.0 -(word) main::digit_value -(word) main::digit_value#0 digit_value zp ZP_WORD:3 101.0 (word*) main::info_values -(byte) main::radix -(byte) main::radix#1 radix zp ZP_BYTE:2 16.5 -(byte) main::radix#4 radix zp ZP_BYTE:2 3.142857142857143 -zp ZP_BYTE:2 [ main::radix#4 main::radix#1 ] -reg byte x [ main::digit#2 main::digit#1 ] -zp ZP_WORD:3 [ main::digit_value#0 ] -reg byte a [ main::$2 ] FINAL ASSEMBLER -Score: 4731 +Score: 38 // File Comments // Illustrates a problem with pointer sizeof()-rewriting for pointers inside structs @@ -500,66 +294,31 @@ Score: 4731 :BasicUpstart(main) .pc = $80d "Program" // Global Constants & labels + .const SIZEOF_WORD = 2 // @begin // [1] phi from @begin to @1 [phi:@begin->@1] // @1 // [2] call main - // [4] phi from @1 to main [phi:@1->main] // [3] phi from @1 to @end [phi:@1->@end] // @end // main main: { .label SCREEN = $400 - .label digit_value = 3 - .label radix = 2 - // [5] phi from main to main::@1 [phi:main->main::@1] - // [5] phi (byte) main::radix#4 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 - lda #0 - sta radix - // [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1] - // [5] phi (byte) main::radix#4 = (byte) main::radix#1 [phi:main::@3->main::@1#0] -- register_copy - // main::@1 - b1: - // [6] phi from main::@1 to main::@2 [phi:main::@1->main::@2] - // [6] phi (byte) main::digit#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuxx=vbuc1 - ldx #0 - // [6] phi from main::@2 to main::@2 [phi:main::@2->main::@2] - // [6] phi (byte) main::digit#2 = (byte) main::digit#1 [phi:main::@2->main::@2#0] -- register_copy - // main::@2 - b2: - // digit_value = info.values[digit] - // [7] (word) main::digit_value#0 ← *((const word[]) RADIX_DECIMAL_VALUES#0 + (byte) main::digit#2) -- vwuz1=pwuc1_derefidx_vbuxx - lda RADIX_DECIMAL_VALUES,x - sta digit_value - lda RADIX_DECIMAL_VALUES+1,x - sta digit_value+1 - // SCREEN[digit] = digit_value - // [8] (byte~) main::$2 ← (byte) main::digit#2 << (byte) 1 -- vbuaa=vbuxx_rol_1 - txa - asl - // [9] *((const word*) main::SCREEN#0 + (byte~) main::$2) ← (word) main::digit_value#0 -- pwuc1_derefidx_vbuaa=vwuz1 - tay - lda digit_value - sta SCREEN,y - lda digit_value+1 - sta SCREEN+1,y - // for( char digit: 0..4 ) - // [10] (byte) main::digit#1 ← ++ (byte) main::digit#2 -- vbuxx=_inc_vbuxx - inx - // [11] if((byte) main::digit#1!=(byte) 5) goto main::@2 -- vbuxx_neq_vbuc1_then_la1 - cpx #5 - bne b2 - // main::@3 - // for( byte radix: 0..1) - // [12] (byte) main::radix#1 ← ++ (byte) main::radix#4 -- vbuz1=_inc_vbuz1 - inc radix - // [13] if((byte) main::radix#1!=(byte) 2) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 - lda #2 - cmp radix - bne b1 + // SCREEN[0] = info.values[1] + // [4] *((const word*) main::SCREEN#0) ← *((const word[]) RADIX_DECIMAL_VALUES#0+(byte) 1*(const byte) SIZEOF_WORD) -- _deref_pwuc1=_deref_pwuc2 + lda RADIX_DECIMAL_VALUES+1*SIZEOF_WORD + sta SCREEN + lda RADIX_DECIMAL_VALUES+1*SIZEOF_WORD+1 + sta SCREEN+1 + // SCREEN[1] = RADIX_DECIMAL_VALUES[1] + // [5] *((const word*) main::SCREEN#0+(byte) 1*(const byte) SIZEOF_WORD) ← *((const word[]) RADIX_DECIMAL_VALUES#0+(byte) 1*(const byte) SIZEOF_WORD) -- _deref_pwuc1=_deref_pwuc2 + lda RADIX_DECIMAL_VALUES+1*SIZEOF_WORD + sta SCREEN+1*SIZEOF_WORD + lda RADIX_DECIMAL_VALUES+1*SIZEOF_WORD+1 + sta SCREEN+1*SIZEOF_WORD+1 // main::@return // } - // [14] return + // [6] return rts } // File Data diff --git a/src/test/ref/problem-pointer-inside-struct-sizeof-rewriting.sym b/src/test/ref/problem-pointer-inside-struct-sizeof-rewriting.sym index 00bd9e75a..1300f7e5b 100644 --- a/src/test/ref/problem-pointer-inside-struct-sizeof-rewriting.sym +++ b/src/test/ref/problem-pointer-inside-struct-sizeof-rewriting.sym @@ -4,25 +4,10 @@ (word[]) RADIX_DECIMAL_VALUES (const word[]) RADIX_DECIMAL_VALUES#0 RADIX_DECIMAL_VALUES = { (word) $2710, (word) $3e8, (word) $64, (word) $a } (word*) RadixInfo::values +(const byte) SIZEOF_WORD SIZEOF_WORD = (byte) 2 (void()) main() -(byte~) main::$2 reg byte a 202.0 -(label) main::@1 -(label) main::@2 -(label) main::@3 (label) main::@return (word*) main::SCREEN (const word*) main::SCREEN#0 SCREEN = (word*) 1024 -(byte) main::digit -(byte) main::digit#1 reg byte x 151.5 -(byte) main::digit#2 reg byte x 101.0 -(word) main::digit_value -(word) main::digit_value#0 digit_value zp ZP_WORD:3 101.0 (word*) main::info_values -(byte) main::radix -(byte) main::radix#1 radix zp ZP_BYTE:2 16.5 -(byte) main::radix#4 radix zp ZP_BYTE:2 3.142857142857143 -zp ZP_BYTE:2 [ main::radix#4 main::radix#1 ] -reg byte x [ main::digit#2 main::digit#1 ] -zp ZP_WORD:3 [ main::digit_value#0 ] -reg byte a [ main::$2 ]