From 80f57ed5f14d832616c2fb37ca21a0b6b6cc9938 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Fri, 27 Apr 2018 14:49:35 +0200 Subject: [PATCH] Added boolean pointer test and a test that modifying a constant results in an error. --- .../java/dk/camelot64/kickc/CompileLog.java | 4 +- .../camelot64/kickc/fragment/AsmFormat.java | 18 +- .../fragment/AsmFragmentInstanceSpec.java | 2 + .../kickc/fragment/asm/vboaa=vboc1.asm | 1 + .../model/operators/OperatorCastBool.java | 31 ++ .../model/operators/OperatorCastPtrBool.java | 30 ++ .../kickc/model/operators/Operators.java | 6 + .../passes/Pass2ConstantIdentification.java | 1 + .../dk/camelot64/kickc/test/TestPrograms.java | 9 + .../camelot64/kickc/test/kc/bool-pointer.kc | 13 + .../kickc/test/kc/const-pointer-modify.kc | 8 + .../camelot64/kickc/test/ref/bool-pointer.asm | 20 + .../camelot64/kickc/test/ref/bool-pointer.cfg | 21 + .../camelot64/kickc/test/ref/bool-pointer.log | 409 ++++++++++++++++++ .../camelot64/kickc/test/ref/bool-pointer.sym | 8 + 15 files changed, 578 insertions(+), 3 deletions(-) create mode 100644 src/main/java/dk/camelot64/kickc/fragment/asm/vboaa=vboc1.asm create mode 100644 src/main/java/dk/camelot64/kickc/model/operators/OperatorCastBool.java create mode 100644 src/main/java/dk/camelot64/kickc/model/operators/OperatorCastPtrBool.java create mode 100644 src/test/java/dk/camelot64/kickc/test/kc/bool-pointer.kc create mode 100644 src/test/java/dk/camelot64/kickc/test/kc/const-pointer-modify.kc create mode 100644 src/test/java/dk/camelot64/kickc/test/ref/bool-pointer.asm create mode 100644 src/test/java/dk/camelot64/kickc/test/ref/bool-pointer.cfg create mode 100644 src/test/java/dk/camelot64/kickc/test/ref/bool-pointer.log create mode 100644 src/test/java/dk/camelot64/kickc/test/ref/bool-pointer.sym diff --git a/src/main/java/dk/camelot64/kickc/CompileLog.java b/src/main/java/dk/camelot64/kickc/CompileLog.java index 579113205..f67656397 100644 --- a/src/main/java/dk/camelot64/kickc/CompileLog.java +++ b/src/main/java/dk/camelot64/kickc/CompileLog.java @@ -20,7 +20,7 @@ public class CompileLog { /** * Should fragment synthesis be verbose. */ - private boolean verboseFragmentLog = false; + private boolean verboseFragmentLog = true; /** * Should ASM optimization be verbose. @@ -35,7 +35,7 @@ public class CompileLog { /** * Should the log be output to System.out while being built */ - private boolean sysOut = false; + private boolean sysOut = true; public CompileLog() { this.log = new StringBuilder(); diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFormat.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFormat.java index 93d919fcf..f91320481 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFormat.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFormat.java @@ -28,6 +28,8 @@ public class AsmFormat { return getAsmParamName(constantVar.getScope().getRef(), asmName, codeScope); } else if(value instanceof ConstantInteger) { return getAsmNumber(((ConstantInteger) value).getValue()); + } else if(value instanceof ConstantBool) { + return getAsmBool(((ConstantBool) value).getBool()); } else if(value instanceof ConstantChar) { return "'" + ((ConstantChar) value).getValue() + "'"; } else if(value instanceof ConstantString) { @@ -76,7 +78,7 @@ public class AsmFormat { } else { return getAsmConstant(program, new ConstantBinary(new ConstantInteger((long)0xff), Operators.BOOL_AND, operand), outerPrecedence, codeScope); } - } else if(Operators.CAST_WORD.equals(operator) || Operators.CAST_SWORD.equals(operator) || Operators.CAST_PTRBY.equals(operator)) { + } else if(Operators.CAST_WORD.equals(operator) || Operators.CAST_SWORD.equals(operator) || Operators.CAST_PTRBY.equals(operator)|| Operators.CAST_PTRBO.equals(operator)) { SymbolType operandType = SymbolTypeInference.inferType(program.getScope(), operand); if(SymbolType.isWord(operandType) || SymbolType.isSWord(operandType) || SymbolType.isByte(operandType) || SymbolType.isSByte(operandType) || operandType instanceof SymbolTypePointer) { // No cast needed @@ -124,6 +126,7 @@ public class AsmFormat { } } + public static String getAsmNumber(Number number) { if(number instanceof Long || number instanceof Integer) { if(number.longValue() >= 0L && number.longValue() <= 9L) { @@ -135,6 +138,19 @@ public class AsmFormat { throw new RuntimeException("Unsupported number type " + number); } + /** + * Get the ASM code for a boolean value + * @param bool the boolean vallue + * @return "0" / "1" + */ + private static String getAsmBool(Boolean bool) { + if(bool) { + return "1"; + } else { + return "0"; + } + } + /** * Get the ASM parameter for a specific bound constant/ variable * diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java index a7541d9a6..343a96170 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java @@ -315,6 +315,8 @@ public class AsmFragmentInstanceSpec { return "pwu"; } else if(SymbolType.isSWord(elementType)) { return "pws"; + } else if(SymbolType.BOOLEAN.equals(elementType)) { + return "pbo"; } else { throw new RuntimeException("Not implemented " + type); } diff --git a/src/main/java/dk/camelot64/kickc/fragment/asm/vboaa=vboc1.asm b/src/main/java/dk/camelot64/kickc/fragment/asm/vboaa=vboc1.asm new file mode 100644 index 000000000..d2e0b6326 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/fragment/asm/vboaa=vboc1.asm @@ -0,0 +1 @@ +lda #{c1} \ No newline at end of file diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastBool.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastBool.java new file mode 100644 index 000000000..15c92f1e2 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastBool.java @@ -0,0 +1,31 @@ +package dk.camelot64.kickc.model.operators; + +import dk.camelot64.kickc.model.CompileError; +import dk.camelot64.kickc.model.types.SymbolType; +import dk.camelot64.kickc.model.types.SymbolTypeSimple; +import dk.camelot64.kickc.model.values.ConstantInteger; +import dk.camelot64.kickc.model.values.ConstantLiteral; +import dk.camelot64.kickc.model.values.ConstantPointer; + +/** Unary Cast to boolean operator ( (byte) x ) */ +public class OperatorCastBool extends OperatorUnary { + + public OperatorCastBool(int precedence) { + super("((boolean))", "_bool_", precedence); + } + + @Override + public ConstantLiteral calculateLiteral(ConstantLiteral value) { + if(value instanceof ConstantInteger) { + return new ConstantInteger(0x1 & ((ConstantInteger) value).getValue()); + } else if(value instanceof ConstantPointer) { + return new ConstantInteger(0x1 & ((ConstantPointer) value).getLocation()); + } + throw new CompileError("Calculation not implemented " + getOperator() + " " + value ); + } + + @Override + public SymbolType inferType(SymbolTypeSimple operandType) { + return SymbolType.BOOLEAN; + } +} diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastPtrBool.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastPtrBool.java new file mode 100644 index 000000000..225cd62d2 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastPtrBool.java @@ -0,0 +1,30 @@ +package dk.camelot64.kickc.model.operators; + +import dk.camelot64.kickc.model.CompileError; +import dk.camelot64.kickc.model.types.SymbolType; +import dk.camelot64.kickc.model.types.SymbolTypePointer; +import dk.camelot64.kickc.model.types.SymbolTypeSimple; +import dk.camelot64.kickc.model.values.ConstantInteger; +import dk.camelot64.kickc.model.values.ConstantLiteral; +import dk.camelot64.kickc.model.values.ConstantPointer; + +/** Unary Cast to boolean pointer operator ( (boolean*) x ) */ +public class OperatorCastPtrBool extends OperatorUnary { + + public OperatorCastPtrBool(int precedence) { + super("((boolean*))", "_ptrbo_", precedence); + } + + @Override + public ConstantLiteral calculateLiteral(ConstantLiteral value) { + if(value instanceof ConstantInteger) { + return new ConstantPointer(((ConstantInteger) value).getInteger(), SymbolType.BOOLEAN); + } + throw new CompileError("Calculation not implemented " + getOperator() + " " + value ); + } + + @Override + public SymbolType inferType(SymbolTypeSimple operandType) { + return new SymbolTypePointer(SymbolType.BOOLEAN); + } +} diff --git a/src/main/java/dk/camelot64/kickc/model/operators/Operators.java b/src/main/java/dk/camelot64/kickc/model/operators/Operators.java index c4aacf033..ff88c7e89 100644 --- a/src/main/java/dk/camelot64/kickc/model/operators/Operators.java +++ b/src/main/java/dk/camelot64/kickc/model/operators/Operators.java @@ -26,6 +26,8 @@ public class Operators { public static final OperatorUnary CAST_DWORD = new OperatorCastDWord(2); public static final OperatorUnary CAST_SDWORD = new OperatorCastSDWord(2); public static final OperatorUnary CAST_PTRBY = new OperatorCastPtrByte(2); + public static final OperatorUnary CAST_PTRBO = new OperatorCastPtrBool(2); + public static final OperatorUnary CAST_BOOL= new OperatorCastBool(2); public static final OperatorBinary MULTIPLY = new OperatorMultiply(3); public static final OperatorBinary DIVIDE = new OperatorDivide(3); public static final OperatorBinary PLUS = new OperatorPlus(4); @@ -133,8 +135,12 @@ public class Operators { return CAST_DWORD; } else if(SymbolType.SDWORD.equals(castType)) { return CAST_SDWORD; + } else if(SymbolType.BOOLEAN.equals(castType)) { + return CAST_BOOL; } else if(castType instanceof SymbolTypePointer && SymbolType.BYTE.equals(((SymbolTypePointer) castType).getElementType())) { return CAST_PTRBY; + } else if(castType instanceof SymbolTypePointer && SymbolType.BOOLEAN.equals(((SymbolTypePointer) castType).getElementType())) { + return CAST_PTRBO; } else { throw new RuntimeException("Unknown cast type " + castType); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java index 869e2217a..6032ffa5c 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java @@ -235,6 +235,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization { case "((dword))": case "((signed dword))": case "((byte*))": + case "((boolean*))": case "!": return new ConstantUnary(operator, c); case "*": { // pointer dereference - not constant diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 811651398..d8c653d93 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -119,6 +119,11 @@ public class TestPrograms { compileAndCompare("bool-function"); } + @Test + public void testBoolPointer() throws IOException, URISyntaxException { + compileAndCompare("bool-pointer"); + } + @Test public void testC64DtvBlitterMin() throws IOException, URISyntaxException { compileAndCompare("c64dtv-blittermin"); @@ -754,6 +759,10 @@ public class TestPrograms { assertError("recursion-error-complex", "Recursion"); } + @Test + public void testConstPointerModifyError() throws IOException, URISyntaxException { + assertError("const-pointer-modify", "Constants can not be modified"); + } private void assertError(String kcFile, String expectError) throws IOException, URISyntaxException { try { diff --git a/src/test/java/dk/camelot64/kickc/test/kc/bool-pointer.kc b/src/test/java/dk/camelot64/kickc/test/kc/bool-pointer.kc new file mode 100644 index 000000000..ed0aef2f2 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/kc/bool-pointer.kc @@ -0,0 +1,13 @@ +// Tests a pointer to a boolean + +void main() { + boolean* bscreen = $400; + bscreen[0] = true; + bscreen[1] = false; + bscreen = bscreen+2; + *bscreen = true; + if(*bscreen) { + *(++bscreen)= true; + } + +} \ No newline at end of file diff --git a/src/test/java/dk/camelot64/kickc/test/kc/const-pointer-modify.kc b/src/test/java/dk/camelot64/kickc/test/kc/const-pointer-modify.kc new file mode 100644 index 000000000..c658ee100 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/kc/const-pointer-modify.kc @@ -0,0 +1,8 @@ +// Test that modifying constant pointers fail + +void main() { + const byte* screen = $400; + screen[0] = 'c'; + screen++; + screen[0] = 'm'; +} \ No newline at end of file diff --git a/src/test/java/dk/camelot64/kickc/test/ref/bool-pointer.asm b/src/test/java/dk/camelot64/kickc/test/ref/bool-pointer.asm new file mode 100644 index 000000000..f96378a59 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/bool-pointer.asm @@ -0,0 +1,20 @@ +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + jsr main +main: { + lda #1 + sta $400+0 + lda #0 + sta $400+1 + lda #1 + sta $400+2 + cmp #0 + bne b2 + breturn: + rts + b2: + lda #1 + sta $400+2+1 + jmp breturn +} diff --git a/src/test/java/dk/camelot64/kickc/test/ref/bool-pointer.cfg b/src/test/java/dk/camelot64/kickc/test/ref/bool-pointer.cfg new file mode 100644 index 000000000..59edf3e01 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/bool-pointer.cfg @@ -0,0 +1,21 @@ +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@1 +@1: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @1 + [3] phi() [ ] ( ) +main: scope:[main] from @1 + [4] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 0) ← true [ ] ( main:2 [ ] ) + [5] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 1) ← false [ ] ( main:2 [ ] ) + [6] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2) ← true [ ] ( main:2 [ ] ) + [7] if(*(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2)) goto main::@2 [ ] ( main:2 [ ] ) + to:main::@return +main::@return: scope:[main] from main main::@2 + [8] return [ ] ( main:2 [ ] ) + to:@return +main::@2: scope:[main] from main + [9] *(++((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2) ← true [ ] ( main:2 [ ] ) + to:main::@return diff --git a/src/test/java/dk/camelot64/kickc/test/ref/bool-pointer.log b/src/test/java/dk/camelot64/kickc/test/ref/bool-pointer.log new file mode 100644 index 000000000..185a0586d --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/bool-pointer.log @@ -0,0 +1,409 @@ +PARSING src/test/java/dk/camelot64/kickc/test/kc/bool-pointer.kc +// Tests a pointer to a boolean + +void main() { + boolean* bscreen = $400; + bscreen[0] = true; + bscreen[1] = false; + bscreen = bscreen+2; + *bscreen = true; + if(*bscreen) { + *(++bscreen)= true; + } + +} +Adding pre/post-modifier (boolean*) main::bscreen ← ++ (boolean*) main::bscreen +SYMBOLS +(label) @1 +(label) @begin +(label) @end +(void()) main() +(boolean*~) main::$0 +(boolean~) main::$1 +(label) main::@1 +(label) main::@2 +(label) main::@return +(boolean*) main::bscreen + +Promoting word/signed word/dword/signed dword to boolean* in main::bscreen ← ((boolean*)) 1024 +INITIAL CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from + (boolean*) main::bscreen ← ((boolean*)) (word/signed word/dword/signed dword) 1024 + *((boolean*) main::bscreen + (byte/signed byte/word/signed word/dword/signed dword) 0) ← true + *((boolean*) main::bscreen + (byte/signed byte/word/signed word/dword/signed dword) 1) ← false + (boolean*~) main::$0 ← (boolean*) main::bscreen + (byte/signed byte/word/signed word/dword/signed dword) 2 + (boolean*) main::bscreen ← (boolean*~) main::$0 + *((boolean*) main::bscreen) ← true + (boolean~) main::$1 ← ! *((boolean*) main::bscreen) + if((boolean~) main::$1) goto main::@1 + to:main::@2 +main::@1: scope:[main] from main main::@2 + to:main::@return +main::@2: scope:[main] from main + (boolean*) main::bscreen ← ++ (boolean*) main::bscreen + *((boolean*) main::bscreen) ← true + to:main::@1 +main::@return: scope:[main] from main::@1 + return + to:@return +@1: scope:[] from @begin + call main + to:@end +@end: scope:[] from @1 + +PROCEDURE MODIFY VARIABLE ANALYSIS + +Completing Phi functions... + +CONTROL FLOW GRAPH SSA WITH ASSIGNMENT CALL & RETURN +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (boolean*) main::bscreen#0 ← ((boolean*)) (word/signed word/dword/signed dword) 1024 + *((boolean*) main::bscreen#0 + (byte/signed byte/word/signed word/dword/signed dword) 0) ← true + *((boolean*) main::bscreen#0 + (byte/signed byte/word/signed word/dword/signed dword) 1) ← false + (boolean*~) main::$0 ← (boolean*) main::bscreen#0 + (byte/signed byte/word/signed word/dword/signed dword) 2 + (boolean*) main::bscreen#1 ← (boolean*~) main::$0 + *((boolean*) main::bscreen#1) ← true + (boolean~) main::$1 ← ! *((boolean*) main::bscreen#1) + if((boolean~) main::$1) goto main::@1 + to:main::@2 +main::@1: scope:[main] from main + to:main::@return +main::@2: scope:[main] from main + (boolean*) main::bscreen#3 ← phi( main/(boolean*) main::bscreen#1 ) + (boolean*) main::bscreen#2 ← ++ (boolean*) main::bscreen#3 + *((boolean*) main::bscreen#2) ← true + to:main::@return +main::@return: scope:[main] from main::@1 main::@2 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + 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() +(boolean*~) main::$0 +(boolean~) main::$1 +(label) main::@1 +(label) main::@2 +(label) main::@return +(boolean*) main::bscreen +(boolean*) main::bscreen#0 +(boolean*) main::bscreen#1 +(boolean*) main::bscreen#2 +(boolean*) main::bscreen#3 + +OPTIMIZING CONTROL FLOW GRAPH +Culled Empty Block (label) main::@1 +Culled Empty Block (label) @2 +Succesful SSA optimization Pass2CullEmptyBlocks +Alias (boolean*) main::bscreen#1 = (boolean*~) main::$0 (boolean*) main::bscreen#3 +Succesful SSA optimization Pass2AliasElimination +Rewriting ! if()-condition to reversed if() (boolean~) main::$1 ← ! *((boolean*) main::bscreen#1) +Succesful SSA optimization Pass2ConditionalAndOrRewriting +Constant (const boolean*) main::bscreen#0 = ((boolean*))1024 +Succesful SSA optimization Pass2ConstantIdentification +Constant (const boolean*) main::bscreen#1 = main::bscreen#0+2 +Succesful SSA optimization Pass2ConstantIdentification +Constant (const boolean*) main::bscreen#2 = ++main::bscreen#1 +Succesful SSA optimization Pass2ConstantIdentification +Consolidated array index constant in *(main::bscreen#0+0) +Consolidated array index constant in *(main::bscreen#0+1) +Succesful SSA optimization Pass2ConstantAdditionElimination +OPTIMIZING CONTROL FLOW GRAPH +Inlining constant with different constant siblings (const boolean*) main::bscreen#0 +Inlining constant with different constant siblings (const boolean*) main::bscreen#0 +Inlining constant with different constant siblings (const boolean*) main::bscreen#1 +Inlining constant with different constant siblings (const boolean*) main::bscreen#1 +Inlining constant with different constant siblings (const boolean*) main::bscreen#2 +Inlining constant with different constant siblings (const boolean*) main::bscreen#2 +Constant inlined main::bscreen#2 = ++((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2 +Constant inlined main::bscreen#0 = ((boolean*))(word/signed word/dword/signed dword) 1024 +Constant inlined main::bscreen#1 = ((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2 +Succesful SSA optimization Pass2ConstantInlining +Block Sequence Planned @begin @1 @end main main::@return main::@2 +Block Sequence Planned @begin @1 @end main main::@return main::@2 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +CALL GRAPH +Calls in [] to main:2 + +Propagating live ranges... +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Block Sequence Planned @begin @1 @end main main::@return main::@2 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Propagating live ranges... + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@1 +@1: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @1 + [3] phi() [ ] ( ) +main: scope:[main] from @1 + [4] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 0) ← true [ ] ( main:2 [ ] ) + [5] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 1) ← false [ ] ( main:2 [ ] ) + [6] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2) ← true [ ] ( main:2 [ ] ) + [7] if(*(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2)) goto main::@2 [ ] ( main:2 [ ] ) + to:main::@return +main::@return: scope:[main] from main main::@2 + [8] return [ ] ( main:2 [ ] ) + to:@return +main::@2: scope:[main] from main + [9] *(++((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2) ← true [ ] ( main:2 [ ] ) + to:main::@return + +DOMINATORS +@begin dominated by @begin +@1 dominated by @1 @begin +@end dominated by @1 @begin @end +main dominated by @1 @begin main +main::@return dominated by main::@return @1 @begin main +main::@2 dominated by @1 @begin main::@2 main + +NATURAL LOOPS + +NATURAL LOOPS WITH DEPTH +Found 0 loops in scope [] +Found 0 loops in scope [main] + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(boolean*) main::bscreen + +Initial phi equivalence classes +Complete equivalence classes +New fragment synthesis _deref_pboc1=vboc2 +New fragment synthesis _deref_pboc1=vboc2 - sub-option vboaa=vboc1 +New fragment synthesis vboaa=vboc1 +New fragment synthesis vboaa=vboc1 - Successfully loaded vboaa=vboc1.asm +Fragment synthesis vboaa=vboc1 - New best, scheduling parent _deref_pboc1=vboc2 +Fragment synthesis _deref_pboc1=vboc2 - Successfully synthesized from vboaa=vboc1 +Found best fragment _deref_pboc1=vboc2 < vboaa=vboc1 score: 6.5 +New fragment synthesis _deref_pboc1_then_la1 +New fragment synthesis _deref_pboc1_then_la1 - sub-option vboaa_then_la1 +New fragment synthesis _deref_pboc1_then_la1 - sub-option vboxx_then_la1 +New fragment synthesis _deref_pboc1_then_la1 - sub-option vboyy_then_la1 +New fragment synthesis vboaa_then_la1 +New fragment synthesis vboaa_then_la1 - Successfully loaded vboaa_then_la1.asm +New fragment synthesis vboaa_then_la1 - sub-option vboxx_then_la1 +New fragment synthesis vboaa_then_la1 - sub-option vboyy_then_la1 +New fragment synthesis vboxx_then_la1 +New fragment synthesis vboxx_then_la1 - Successfully loaded vboxx_then_la1.asm +New fragment synthesis vboxx_then_la1 - sub-option vboaa_then_la1 +New fragment synthesis vboyy_then_la1 +New fragment synthesis vboyy_then_la1 - Successfully loaded vboyy_then_la1.asm +New fragment synthesis vboyy_then_la1 - sub-option vboaa_then_la1 +Fragment synthesis vboyy_then_la1 - New best, scheduling parent vboaa_then_la1 +Fragment synthesis vboyy_then_la1 - New best, scheduling parent _deref_pboc1_then_la1 +Fragment synthesis vboxx_then_la1 - New best, scheduling parent vboaa_then_la1 +Fragment synthesis vboxx_then_la1 - New best, scheduling parent _deref_pboc1_then_la1 +Fragment synthesis vboaa_then_la1 - Successfully synthesized from vboxx_then_la1 +Fragment synthesis vboaa_then_la1 - Successfully synthesized from vboyy_then_la1 +Fragment synthesis vboaa_then_la1 - New best, scheduling parent vboxx_then_la1 +Fragment synthesis vboaa_then_la1 - New best, scheduling parent vboyy_then_la1 +Fragment synthesis vboaa_then_la1 - New best, scheduling parent _deref_pboc1_then_la1 +Fragment synthesis vboyy_then_la1 - Successfully synthesized from vboaa_then_la1 +Fragment synthesis vboxx_then_la1 - Successfully synthesized from vboaa_then_la1 +Fragment synthesis _deref_pboc1_then_la1 - Successfully synthesized from vboaa_then_la1 +Fragment synthesis _deref_pboc1_then_la1 - Successfully synthesized from vboxx_then_la1 +Fragment synthesis _deref_pboc1_then_la1 - Successfully synthesized from vboyy_then_la1 +Found best fragment _deref_pboc1_then_la1 < vboaa_then_la1 score: 9.0 + +INITIAL ASM +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG4 @1 +b1: +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG7 @end +bend: +//SEG8 main +main: { + //SEG9 [4] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 0) ← true [ ] ( main:2 [ ] ) -- _deref_pboc1=vboc2 + lda #1 + sta $400+0 + //SEG10 [5] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 1) ← false [ ] ( main:2 [ ] ) -- _deref_pboc1=vboc2 + lda #0 + sta $400+1 + //SEG11 [6] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2) ← true [ ] ( main:2 [ ] ) -- _deref_pboc1=vboc2 + lda #1 + sta $400+2 + //SEG12 [7] if(*(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2)) goto main::@2 [ ] ( main:2 [ ] ) -- _deref_pboc1_then_la1 + lda $400+2 + cmp #0 + bne b2 + jmp breturn + //SEG13 main::@return + breturn: + //SEG14 [8] return [ ] ( main:2 [ ] ) + rts + //SEG15 main::@2 + b2: + //SEG16 [9] *(++((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2) ← true [ ] ( main:2 [ ] ) -- _deref_pboc1=vboc2 + lda #1 + sta $400+2+1 + jmp breturn +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 0) ← true [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [5] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 1) ← false [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [6] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2) ← true [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [7] if(*(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2)) goto main::@2 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [9] *(++((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2) ← true [ ] ( main:2 [ ] ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [] + +Uplifting [main] best 56 combination +Uplifting [] best 56 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG4 @1 +b1: +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG7 @end +bend: +//SEG8 main +main: { + //SEG9 [4] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 0) ← true [ ] ( main:2 [ ] ) -- _deref_pboc1=vboc2 + lda #1 + sta $400+0 + //SEG10 [5] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 1) ← false [ ] ( main:2 [ ] ) -- _deref_pboc1=vboc2 + lda #0 + sta $400+1 + //SEG11 [6] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2) ← true [ ] ( main:2 [ ] ) -- _deref_pboc1=vboc2 + lda #1 + sta $400+2 + //SEG12 [7] if(*(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2)) goto main::@2 [ ] ( main:2 [ ] ) -- _deref_pboc1_then_la1 + lda $400+2 + cmp #0 + bne b2 + jmp breturn + //SEG13 main::@return + breturn: + //SEG14 [8] return [ ] ( main:2 [ ] ) + rts + //SEG15 main::@2 + b2: + //SEG16 [9] *(++((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2) ← true [ ] ( main:2 [ ] ) -- _deref_pboc1=vboc2 + lda #1 + sta $400+2+1 + jmp breturn +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction lda $400+2 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Removing instruction bbegin: +Removing instruction b1_from_bbegin: +Removing instruction bend_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction b1: +Removing instruction bend: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@2 +(label) main::@return +(boolean*) main::bscreen + + + +FINAL ASSEMBLER +Score: 43 + +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 @1 +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +//SEG7 @end +//SEG8 main +main: { + //SEG9 [4] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 0) ← true [ ] ( main:2 [ ] ) -- _deref_pboc1=vboc2 + lda #1 + sta $400+0 + //SEG10 [5] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 1) ← false [ ] ( main:2 [ ] ) -- _deref_pboc1=vboc2 + lda #0 + sta $400+1 + //SEG11 [6] *(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2) ← true [ ] ( main:2 [ ] ) -- _deref_pboc1=vboc2 + lda #1 + sta $400+2 + //SEG12 [7] if(*(((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2)) goto main::@2 [ ] ( main:2 [ ] ) -- _deref_pboc1_then_la1 + cmp #0 + bne b2 + //SEG13 main::@return + breturn: + //SEG14 [8] return [ ] ( main:2 [ ] ) + rts + //SEG15 main::@2 + b2: + //SEG16 [9] *(++((boolean*))(word/signed word/dword/signed dword) 1024+(byte/signed byte/word/signed word/dword/signed dword) 2) ← true [ ] ( main:2 [ ] ) -- _deref_pboc1=vboc2 + lda #1 + sta $400+2+1 + jmp breturn +} + diff --git a/src/test/java/dk/camelot64/kickc/test/ref/bool-pointer.sym b/src/test/java/dk/camelot64/kickc/test/ref/bool-pointer.sym new file mode 100644 index 000000000..c0b00da76 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/bool-pointer.sym @@ -0,0 +1,8 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@2 +(label) main::@return +(boolean*) main::bscreen +