From d3e21133fa5930c25f67c8eaf7eb15c97cf4b0dd Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Wed, 19 Jun 2019 23:16:59 +0200 Subject: [PATCH] Added initial void pointer support. Working on #186 --- .../model/types/SymbolTypeConversion.java | 9 +- .../PassNAddTypeConversionAssignment.java | 25 +- .../dk/camelot64/kickc/test/TestPrograms.java | 5 + src/test/kc/pointer-void-0.kc | 10 + src/test/ref/pointer-void-0.asm | 18 ++ src/test/ref/pointer-void-0.cfg | 16 + src/test/ref/pointer-void-0.log | 294 ++++++++++++++++++ src/test/ref/pointer-void-0.sym | 17 + 8 files changed, 378 insertions(+), 16 deletions(-) create mode 100644 src/test/kc/pointer-void-0.kc create mode 100644 src/test/ref/pointer-void-0.asm create mode 100644 src/test/ref/pointer-void-0.cfg create mode 100644 src/test/ref/pointer-void-0.log create mode 100644 src/test/ref/pointer-void-0.sym diff --git a/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeConversion.java b/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeConversion.java index 9e07c94da..77945d06c 100644 --- a/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeConversion.java +++ b/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeConversion.java @@ -131,7 +131,7 @@ public class SymbolTypeConversion { } - public static SymbolType getSmallestSignedFixedIntegerType(ConstantValue constantValue, ProgramScope symbols) { + public static SymbolType getSmallestSignedFixedIntegerType(ConstantValue constantValue, ProgramScope symbols) { ConstantLiteral constantLiteral; try { constantLiteral = constantValue.calculateLiteral(symbols); @@ -152,7 +152,7 @@ public class SymbolTypeConversion { return null; } - public static SymbolType getSmallestUnsignedFixedIntegerType(ConstantValue constantValue, ProgramScope symbols) { + public static SymbolType getSmallestUnsignedFixedIntegerType(ConstantValue constantValue, ProgramScope symbols) { ConstantLiteral constantLiteral; try { constantLiteral = constantValue.calculateLiteral(symbols); @@ -230,9 +230,8 @@ public class SymbolTypeConversion { return true; } if(lValueType instanceof SymbolTypePointer && rValueType instanceof SymbolTypePointer && assignmentTypeMatch(((SymbolTypePointer) lValueType).getElementType(), ((SymbolTypePointer) rValueType).getElementType())) { - // Pointer types assigned from each other - // TODO: Maybe handle sizes - return true; + // Pointer types assigned from each other + return true; } return false; } diff --git a/src/main/java/dk/camelot64/kickc/passes/PassNAddTypeConversionAssignment.java b/src/main/java/dk/camelot64/kickc/passes/PassNAddTypeConversionAssignment.java index d34690762..b695ce3e8 100644 --- a/src/main/java/dk/camelot64/kickc/passes/PassNAddTypeConversionAssignment.java +++ b/src/main/java/dk/camelot64/kickc/passes/PassNAddTypeConversionAssignment.java @@ -37,25 +37,28 @@ public class PassNAddTypeConversionAssignment extends Pass2SsaOptimization { getLog().append("Adding pointer type conversion cast (" + leftType + ") " + binary.getLeft().toString() + " in " + currentStmt.toString(getProgram(), false)); binary.addRightCast(leftType, stmtIt, currentBlock.getScope(), getScope()); modified.set(true); - } - - // Detect word literal constructor - if(SymbolType.WORD.equals(leftType) && isLiteralWordCandidate(rightType)) { + } else if((leftType instanceof SymbolTypePointer) && rightType instanceof SymbolTypePointer && SymbolType.VOID.equals(((SymbolTypePointer) leftType).getElementType())) { + getLog().append("Adding void pointer type conversion cast (" + leftType + ") " + binary.getRight().toString() + " in " + currentStmt.toString(getProgram(), false)); + binary.addRightCast(leftType, stmtIt, currentBlock.getScope(), getScope()); + modified.set(true); + } else if((leftType instanceof SymbolTypePointer) && rightType instanceof SymbolTypePointer && SymbolType.VOID.equals(((SymbolTypePointer) rightType).getElementType())) { + getLog().append("Adding pointer type conversion cast to void pointer (" + leftType + ") " + binary.getRight().toString() + " in " + currentStmt.toString(getProgram(), false)); + binary.addRightCast(leftType, stmtIt, currentBlock.getScope(), getScope()); + modified.set(true); + } else if(SymbolType.WORD.equals(leftType) && isLiteralWordCandidate(rightType)) { + // Detect word literal constructor SymbolType conversionType = SymbolType.WORD; getLog().append("Identified literal word (" + conversionType + ") " + binary.getRight().toString() + " in " + (currentStmt == null ? "" : currentStmt.toString(getProgram(), false))); binary.addRightCast(conversionType, stmtIt, currentBlock == null ? null : currentBlock.getScope(), getScope()); modified.set(true); - } - // Detect word literal constructor - if(leftType instanceof SymbolTypePointer && isLiteralWordCandidate(rightType)) { + } else if(leftType instanceof SymbolTypePointer && isLiteralWordCandidate(rightType)) { + // Detect word literal constructor SymbolType conversionType = SymbolType.WORD; getLog().append("Identified literal word (" + conversionType + ") " + binary.getRight().toString() + " in " + (currentStmt == null ? "" : currentStmt.toString(getProgram(), false))); binary.addRightCast(conversionType, stmtIt, currentBlock == null ? null : currentBlock.getScope(), getScope()); modified.set(true); - } - - // Detect dword literal constructor - if(SymbolType.DWORD.equals(leftType) && isLiteralWordCandidate(rightType)) { + } else if(SymbolType.DWORD.equals(leftType) && isLiteralWordCandidate(rightType)) { + // Detect dword literal constructor SymbolType conversionType = SymbolType.DWORD; getLog().append("Identified literal word (" + conversionType + ") " + binary.getRight().toString() + " in " + (currentStmt == null ? "" : currentStmt.toString(getProgram(), false))); binary.addRightCast(conversionType, stmtIt, currentBlock == null ? null : currentBlock.getScope(), getScope()); diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 9a17b7e6b..d8dc2fad6 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -35,6 +35,11 @@ public class TestPrograms { public TestPrograms() { } + @Test + public void testPointerVoid() throws IOException, URISyntaxException { + compileAndCompare("pointer-void-0"); + } + @Test public void testEnumErr2() throws IOException, URISyntaxException { assertError("enum-err-2", "Enum value not constant"); diff --git a/src/test/kc/pointer-void-0.kc b/src/test/kc/pointer-void-0.kc new file mode 100644 index 000000000..89b7c4e1d --- /dev/null +++ b/src/test/kc/pointer-void-0.kc @@ -0,0 +1,10 @@ +// Test simple void pointer (conversion without casting) + +void main() { + const byte* SCREEN = 0x0400; + word w = 1234; + word* wp = &w; + void* vp = wp; + byte* bp = vp; + *SCREEN = *bp; +} \ No newline at end of file diff --git a/src/test/ref/pointer-void-0.asm b/src/test/ref/pointer-void-0.asm new file mode 100644 index 000000000..fea4e07c1 --- /dev/null +++ b/src/test/ref/pointer-void-0.asm @@ -0,0 +1,18 @@ +// Test simple void pointer (conversion without casting) +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +main: { + .label SCREEN = $400 + .label wp = w + .label vp = wp + .label bp = vp + .label w = 2 + lda #<$4d2 + sta w + lda #>$4d2 + sta w+1 + lda bp + sta SCREEN + rts +} diff --git a/src/test/ref/pointer-void-0.cfg b/src/test/ref/pointer-void-0.cfg new file mode 100644 index 000000000..6b08a67e2 --- /dev/null +++ b/src/test/ref/pointer-void-0.cfg @@ -0,0 +1,16 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] (word) main::w#0 ← (word) $4d2 + [5] *((const byte*) main::SCREEN#0) ← *((const byte*) main::bp#0) + to:main::@return +main::@return: scope:[main] from main + [6] return + to:@return diff --git a/src/test/ref/pointer-void-0.log b/src/test/ref/pointer-void-0.log new file mode 100644 index 000000000..d1a8fbb76 --- /dev/null +++ b/src/test/ref/pointer-void-0.log @@ -0,0 +1,294 @@ +Setting inferred volatile on symbol affected by address-of (word*~) main::$0 ← & (word) main::w +Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400 +Adding void pointer type conversion cast (void*) main::wp in (void*) main::vp ← (word*) main::wp +Adding pointer type conversion cast to void pointer (byte*) main::vp in (byte*) main::bp ← (void*) main::vp + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte*) main::SCREEN#0 ← ((byte*)) (number) $400 + (word) main::w#0 ← (number) $4d2 + (word*~) main::$0 ← & (word) main::w#0 + (word*) main::wp#0 ← (word*~) main::$0 + (void*) main::vp#0 ← ((void*)) (word*) main::wp#0 + (byte*) main::bp#0 ← ((byte*)) (void*) main::vp#0 + *((byte*) main::SCREEN#0) ← *((byte*) main::bp#0) + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + call main + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(void()) main() +(word*~) main::$0 +(label) main::@return +(byte*) main::SCREEN +(byte*) main::SCREEN#0 +(byte*) main::bp +(byte*) main::bp#0 +(void*) main::vp +(void*) main::vp#0 +(word) main::w +(word) main::w#0 +(word*) main::wp +(word*) main::wp#0 + +Adding number conversion cast (unumber) $4d2 in (word) main::w#0 ← (number) $4d2 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400 +Inlining cast (word) main::w#0 ← (unumber)(number) $4d2 +Inlining cast (void*) main::vp#0 ← (void*)(word*) main::wp#0 +Inlining cast (byte*) main::bp#0 ← (byte*)(void*) main::vp#0 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast $4d2 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (word) $4d2 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias (word*) main::wp#0 = (word*~) main::$0 +Successful SSA optimization Pass2AliasElimination +Constant right-side identified [2] (word*) main::wp#0 ← & (word) main::w#0 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte*) main::SCREEN#0 = (byte*) 1024 +Constant (const word*) main::wp#0 = &main::w#0 +Successful SSA optimization Pass2ConstantIdentification +Constant value identified (void*)main::wp#0 in [4] (void*) main::vp#0 ← (void*)(const word*) main::wp#0 +Successful SSA optimization Pass2ConstantValues +Constant (const void*) main::vp#0 = (void*)main::wp#0 +Successful SSA optimization Pass2ConstantIdentification +Constant value identified (byte*)main::vp#0 in [2] (byte*) main::bp#0 ← (byte*)(const void*) main::vp#0 +Successful SSA optimization Pass2ConstantValues +Constant (const byte*) main::bp#0 = (byte*)main::vp#0 +Successful SSA optimization Pass2ConstantIdentification +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +CALL GRAPH +Calls in [] to main:2 + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Culled Empty Block (label) @2 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] (word) main::w#0 ← (word) $4d2 + [5] *((const byte*) main::SCREEN#0) ← *((const byte*) main::bp#0) + to:main::@return +main::@return: scope:[main] from main + [6] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte*) main::SCREEN +(byte*) main::bp +(void*) main::vp +(word) main::w +(word) main::w#0 20.0 +(word*) main::wp + +Initial phi equivalence classes +Complete equivalence classes +[ main::w#0 ] +Allocated zp ZP_WORD:2 [ main::w#0 ] + +INITIAL ASM +//SEG0 File Comments +// Test simple void pointer (conversion without casting) +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .label SCREEN = $400 + .label wp = w + .label vp = wp + .label bp = vp + .label w = 2 + //SEG10 [4] (word) main::w#0 ← (word) $4d2 -- vwuz1=vwuc1 + lda #<$4d2 + sta w + lda #>$4d2 + sta w+1 + //SEG11 [5] *((const byte*) main::SCREEN#0) ← *((const byte*) main::bp#0) -- _deref_pbuc1=_deref_pbuc2 + lda bp + sta SCREEN + jmp breturn + //SEG12 main::@return + breturn: + //SEG13 [6] return + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] (word) main::w#0 ← (word) $4d2 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [5] *((const byte*) main::SCREEN#0) ← *((const byte*) main::bp#0) [ ] ( main:2 [ ] ) always clobbers reg byte a +Potential registers zp ZP_WORD:2 [ main::w#0 ] : zp ZP_WORD:2 , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 20: zp ZP_WORD:2 [ main::w#0 ] +Uplift Scope [] + +Uplifting [main] best 39 combination zp ZP_WORD:2 [ main::w#0 ] +Uplifting [] best 39 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Test simple void pointer (conversion without casting) +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .label SCREEN = $400 + .label wp = w + .label vp = wp + .label bp = vp + .label w = 2 + //SEG10 [4] (word) main::w#0 ← (word) $4d2 -- vwuz1=vwuc1 + lda #<$4d2 + sta w + lda #>$4d2 + sta w+1 + //SEG11 [5] *((const byte*) main::SCREEN#0) ← *((const byte*) main::bp#0) -- _deref_pbuc1=_deref_pbuc2 + lda bp + sta SCREEN + jmp breturn + //SEG12 main::@return + breturn: + //SEG13 [6] return + rts +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction bend_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 +(byte*) main::bp +(const byte*) main::bp#0 bp = (byte*)(const void*) main::vp#0 +(void*) main::vp +(const void*) main::vp#0 vp = (void*)(const word*) main::wp#0 +(word) main::w +(word) main::w#0 w zp ZP_WORD:2 20.0 +(word*) main::wp +(const word*) main::wp#0 wp = &(word) main::w#0 + +zp ZP_WORD:2 [ main::w#0 ] + + +FINAL ASSEMBLER +Score: 24 + +//SEG0 File Comments +// Test simple void pointer (conversion without casting) +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels +//SEG3 @begin +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main +main: { + .label SCREEN = $400 + .label wp = w + .label vp = wp + .label bp = vp + .label w = 2 + //SEG10 [4] (word) main::w#0 ← (word) $4d2 -- vwuz1=vwuc1 + lda #<$4d2 + sta w + lda #>$4d2 + sta w+1 + //SEG11 [5] *((const byte*) main::SCREEN#0) ← *((const byte*) main::bp#0) -- _deref_pbuc1=_deref_pbuc2 + lda bp + sta SCREEN + //SEG12 main::@return + //SEG13 [6] return + rts +} + diff --git a/src/test/ref/pointer-void-0.sym b/src/test/ref/pointer-void-0.sym new file mode 100644 index 000000000..9aed5f3ff --- /dev/null +++ b/src/test/ref/pointer-void-0.sym @@ -0,0 +1,17 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(byte*) main::SCREEN +(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024 +(byte*) main::bp +(const byte*) main::bp#0 bp = (byte*)(const void*) main::vp#0 +(void*) main::vp +(const void*) main::vp#0 vp = (void*)(const word*) main::wp#0 +(word) main::w +(word) main::w#0 w zp ZP_WORD:2 20.0 +(word*) main::wp +(const word*) main::wp#0 wp = &(word) main::w#0 + +zp ZP_WORD:2 [ main::w#0 ]