diff --git a/src/main/fragment/mos6502-common/vwuc1_le_vwuc2_then_la1.asm b/src/main/fragment/mos6502-common/vwuc1_le_vwuc2_then_la1.asm new file mode 100644 index 000000000..7e9a71e44 --- /dev/null +++ b/src/main/fragment/mos6502-common/vwuc1_le_vwuc2_then_la1.asm @@ -0,0 +1,8 @@ +lda #>{c1} +cmp #>{c2} +bne !+ +lda #<{c1} +cmp #<{c2} +beq {la1} +!: +bcc {la1} \ No newline at end of file diff --git a/src/main/fragment/mos6502-common/vwum1=vbuaa_rol_8.asm b/src/main/fragment/mos6502-common/vwum1=vbuaa_rol_8.asm new file mode 100644 index 000000000..826e331cf --- /dev/null +++ b/src/main/fragment/mos6502-common/vwum1=vbuaa_rol_8.asm @@ -0,0 +1,3 @@ +sta {m1}+1 +lda #0 +sta {m1} \ No newline at end of file diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java index 458ef99c5..24694fff5 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java @@ -1,11 +1,11 @@ package dk.camelot64.kickc.fragment; +import dk.camelot64.kickc.model.ConstantNotLiteral; import dk.camelot64.kickc.model.Program; import dk.camelot64.kickc.model.statements.Statement; import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolTypeIntegerFixed; import dk.camelot64.kickc.model.values.*; -import kickass.nonasm.c64.CharToPetsciiConverter; import java.util.*; @@ -94,7 +94,12 @@ public class AsmFragmentInstanceSpec { // Found a constant value that may be multi-typed Value value = bindings.get(name); if(value instanceof ConstantValue) { - ConstantLiteral constantLiteral = ((ConstantValue) value).calculateLiteral(program.getScope()); + ConstantLiteral constantLiteral = null; + try { + constantLiteral = ((ConstantValue) value).calculateLiteral(program.getScope()); + } catch (ConstantNotLiteral e) { + // ignore + } Long constIntValue = null; if(constantLiteral instanceof ConstantInteger) { constIntValue = ((ConstantInteger) constantLiteral).getValue(); diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 1dd756b87..232501ce1 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -44,6 +44,11 @@ public class TestPrograms { public TestPrograms() { } + @Test + public void testConstRefNotLiteralProblem() throws IOException, URISyntaxException { + compileAndCompare("constref-not-literal-problem.c"); + } + @Test public void testStrengthReduction1() throws IOException, URISyntaxException { compileAndCompare("strength-reduction-1.c"); diff --git a/src/test/kc/constref-not-literal-problem.c b/src/test/kc/constref-not-literal-problem.c new file mode 100644 index 000000000..502ad1ace --- /dev/null +++ b/src/test/kc/constref-not-literal-problem.c @@ -0,0 +1,17 @@ +// Demonstrates a problem where constant references are not literal + +char A[] = "qwe"; +char * B = 0x8000; + +void main() { + copy(B, A); +} + +// Copy a byte if the destination is after the source +void copy(void* destination, void* source) { + if((unsigned int)destination>(unsigned int)source) { + char* src = source; + char* dst = destination; + *dst = *src; + } +} diff --git a/src/test/ref/constref-not-literal-problem.asm b/src/test/ref/constref-not-literal-problem.asm new file mode 100644 index 000000000..ea0df27d5 --- /dev/null +++ b/src/test/ref/constref-not-literal-problem.asm @@ -0,0 +1,35 @@ +// Demonstrates a problem where constant references are not literal +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label B = $8000 +main: { + // copy(B, A) + jsr copy + // } + rts +} +// Copy a byte if the destination is after the source +copy: { + .label destination = B + .label source = A + .label src = source + .label dst = destination + // if((unsigned int)destination>(unsigned int)source) + lda #>destination + cmp #>source + bne !+ + lda # copy::$3 + copy::$1 = ! copy::$0 + if(copy::$1) goto copy::@return + to:copy::@1 +copy::@1: scope:[copy] from copy + copy::destination#2 = phi( copy/copy::destination#1 ) + copy::source#2 = phi( copy/copy::source#1 ) + copy::src#0 = ((byte*)) copy::source#2 + copy::dst#0 = ((byte*)) copy::destination#2 + *copy::dst#0 = *copy::src#0 + to:copy::@return +copy::@return: scope:[copy] from copy copy::@1 + return + to:@return + +void __start() +__start: scope:[__start] from + to:__start::__init1 +__start::__init1: scope:[__start] from __start + to:__start::@1 +__start::@1: scope:[__start] from __start::__init1 + call main + to:__start::@2 +__start::@2: scope:[__start] from __start::@1 + to:__start::@return +__start::@return: scope:[__start] from __start::@2 + return + to:@return + +SYMBOL TABLE SSA +const byte* A[] = "qwe" +const byte* B = (byte*)$8000 +void __start() +void copy(void* copy::destination , void* copy::source) +bool~ copy::$0 +bool~ copy::$1 +word~ copy::$2 +word~ copy::$3 +void* copy::destination +void* copy::destination#0 +void* copy::destination#1 +void* copy::destination#2 +byte* copy::dst +byte* copy::dst#0 +void* copy::source +void* copy::source#0 +void* copy::source#1 +void* copy::source#2 +byte* copy::src +byte* copy::src#0 +void main() + +Inlining cast copy::src#0 = (byte*)copy::source#2 +Inlining cast copy::dst#0 = (byte*)copy::destination#2 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (byte*) 32768 +Successful SSA optimization PassNCastSimplification +Inversing boolean not [8] copy::$1 = copy::$2 <= copy::$3 from [7] copy::$0 = copy::$2 > copy::$3 +Successful SSA optimization Pass2UnaryNotSimplification +Alias copy::source#1 = copy::source#2 +Alias copy::destination#1 = copy::destination#2 +Successful SSA optimization Pass2AliasElimination +Identical Phi Values copy::destination#1 copy::destination#0 +Identical Phi Values copy::source#1 copy::source#0 +Successful SSA optimization Pass2IdenticalPhiElimination +Simple Condition copy::$1 [8] if(copy::$2<=copy::$3) goto copy::@return +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant right-side identified [0] copy::destination#0 = (void*)B +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant copy::destination#0 = (void*)B +Constant copy::source#0 = (void*)A +Successful SSA optimization Pass2ConstantIdentification +Constant copy::$2 = (word)copy::destination#0 +Constant copy::$3 = (word)copy::source#0 +Constant copy::src#0 = (byte*)copy::source#0 +Constant copy::dst#0 = (byte*)copy::destination#0 +Successful SSA optimization Pass2ConstantIdentification +Removing unused procedure __start +Removing unused procedure block __start +Removing unused procedure block __start::__init1 +Removing unused procedure block __start::@1 +Removing unused procedure block __start::@2 +Removing unused procedure block __start::@return +Successful SSA optimization PassNEliminateEmptyStart +Constant inlined copy::$2 = (word)copy::destination#0 +Constant inlined copy::$3 = (word)copy::source#0 +Successful SSA optimization Pass2ConstantInlining +Adding NOP phi() at start of main +Adding NOP phi() at start of main::@1 +CALL GRAPH +Calls in [main] to copy:1 + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Culled Empty Block label main::@1 +Adding NOP phi() at start of main + +FINAL CONTROL FLOW GRAPH + +void main() +main: scope:[main] from + [0] phi() + [1] call copy + to:main::@return +main::@return: scope:[main] from main + [2] return + to:@return + +void copy(void* copy::destination , void* copy::source) +copy: scope:[copy] from main + [3] if((word)copy::destination#0<=(word)copy::source#0) goto copy::@return + to:copy::@1 +copy::@1: scope:[copy] from copy + [4] *copy::dst#0 = *copy::src#0 + to:copy::@return +copy::@return: scope:[copy] from copy copy::@1 + [5] return + to:@return + + +VARIABLE REGISTER WEIGHTS +void copy(void* copy::destination , void* copy::source) +void* copy::destination +byte* copy::dst +void* copy::source +byte* copy::src +void main() + +Initial phi equivalence classes +Complete equivalence classes +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [3] if((word)copy::destination#0<=(word)copy::source#0) goto copy::@return [ ] ( copy:1 [ ] { } ) always clobbers reg byte a +Statement [4] *copy::dst#0 = *copy::src#0 [ ] ( copy:1 [ ] { } ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [copy] +Uplift Scope [] + +Uplifting [main] best 50 combination +Uplifting [copy] best 50 combination +Uplifting [] best 50 combination + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Demonstrates a problem where constant references are not literal + // Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + // Global Constants & labels + .label B = $8000 + // main +main: { + // [1] call copy + jsr copy + jmp __breturn + // main::@return + __breturn: + // [2] return + rts +} + // copy +// Copy a byte if the destination is after the source +copy: { + .label destination = B + .label source = A + .label src = source + .label dst = destination + // [3] if((word)copy::destination#0<=(word)copy::source#0) goto copy::@return -- vwuc1_le_vwuc2_then_la1 + lda #>destination + cmp #>source + bne !+ + lda #(unsigned int)source) + // [3] if((word)copy::destination#0<=(word)copy::source#0) goto copy::@return -- vwuc1_le_vwuc2_then_la1 + lda #>destination + cmp #>source + bne !+ + lda #