From 0ce718371eea589690148c13a8e4dfe88a5ae9dd Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sat, 14 Sep 2019 11:21:29 +0200 Subject: [PATCH] Fixed problem with adding ints to literal string pointers. Closes #315 --- .../kickc/model/operators/OperatorMinus.java | 2 + .../kickc/model/operators/OperatorPlus.java | 2 + .../PassNCalcVariableReferenceInfos.java | 6 +- .../dk/camelot64/kickc/test/TestPrograms.java | 15 +- src/test/kc/string-pointer-problem.kc | 14 + src/test/kc/struct-ptr-28.kc | 2 +- src/test/ref/string-pointer-problem.asm | 54 ++ src/test/ref/string-pointer-problem.cfg | 32 + src/test/ref/string-pointer-problem.log | 566 ++++++++++++++++++ src/test/ref/string-pointer-problem.sym | 22 + 10 files changed, 709 insertions(+), 6 deletions(-) create mode 100644 src/test/kc/string-pointer-problem.kc create mode 100644 src/test/ref/string-pointer-problem.asm create mode 100644 src/test/ref/string-pointer-problem.cfg create mode 100644 src/test/ref/string-pointer-problem.log create mode 100644 src/test/ref/string-pointer-problem.sym diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorMinus.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorMinus.java index 6d2d5f1e9..b8c6bc56f 100644 --- a/src/main/java/dk/camelot64/kickc/model/operators/OperatorMinus.java +++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorMinus.java @@ -40,6 +40,8 @@ public class OperatorMinus extends OperatorBinary { return new SymbolTypePointer(((SymbolTypePointer) type1).getElementType()); } else if(type1 instanceof SymbolTypePointer && type2 instanceof SymbolTypePointer) { return SymbolType.WORD; + } else if(SymbolType.STRING.equals(type1) && SymbolType.isInteger(type2)) { + return new SymbolTypePointer(SymbolType.BYTE); } // Handle numeric types through proper promotion if(SymbolType.isInteger(type1) && SymbolType.isInteger(type2)) { diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorPlus.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorPlus.java index d771f874b..371362971 100644 --- a/src/main/java/dk/camelot64/kickc/model/operators/OperatorPlus.java +++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorPlus.java @@ -39,6 +39,8 @@ public class OperatorPlus extends OperatorBinary { return new SymbolTypePointer(((SymbolTypePointer) type2).getElementType()); } else if(type1 instanceof SymbolTypePointer && SymbolType.isInteger(type2)) { return new SymbolTypePointer(((SymbolTypePointer) type1).getElementType()); + } else if(SymbolType.STRING.equals(type1) && SymbolType.isInteger(type2)) { + return new SymbolTypePointer(SymbolType.BYTE); } // Handle numeric types through proper promotion if(SymbolType.isInteger(type1) && SymbolType.isInteger(type2)) { diff --git a/src/main/java/dk/camelot64/kickc/passes/calcs/PassNCalcVariableReferenceInfos.java b/src/main/java/dk/camelot64/kickc/passes/calcs/PassNCalcVariableReferenceInfos.java index c904a8834..eac666bb4 100644 --- a/src/main/java/dk/camelot64/kickc/passes/calcs/PassNCalcVariableReferenceInfos.java +++ b/src/main/java/dk/camelot64/kickc/passes/calcs/PassNCalcVariableReferenceInfos.java @@ -88,9 +88,9 @@ public class PassNCalcVariableReferenceInfos extends PassNCalcBase$11 + bcc b2 + bne !+ + lda.z j + cmp #<$11 + bcc b2 + !: + rts + b2: + lda #main.name + adc.z j+1 + sta.z _1+1 + lda #process_name + adc.z j+1 + sta.z _2+1 + ldy #0 + lda (_1),y + sta (_2),y + inc.z j + bne !+ + inc.z j+1 + !: + jmp b1 +} diff --git a/src/test/ref/string-pointer-problem.cfg b/src/test/ref/string-pointer-problem.cfg new file mode 100644 index 000000000..565e5fafe --- /dev/null +++ b/src/test/ref/string-pointer-problem.cfg @@ -0,0 +1,32 @@ +@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] phi() + [5] call set_process_name + to:main::@return +main::@return: scope:[main] from main + [6] return + to:@return +set_process_name: scope:[set_process_name] from main + [7] phi() + to:set_process_name::@1 +set_process_name::@1: scope:[set_process_name] from set_process_name set_process_name::@2 + [8] (signed word) set_process_name::j#2 ← phi( set_process_name/(signed byte) 0 set_process_name::@2/(signed word) set_process_name::j#1 ) + [9] if((signed word) set_process_name::j#2<(signed byte) $11) goto set_process_name::@2 + to:set_process_name::@return +set_process_name::@return: scope:[set_process_name] from set_process_name::@1 + [10] return + to:@return +set_process_name::@2: scope:[set_process_name] from set_process_name::@1 + [11] (byte*~) set_process_name::$1 ← (const string) main::name + (signed word) set_process_name::j#2 + [12] (byte*~) set_process_name::$2 ← (const byte*) process_name#0 + (signed word) set_process_name::j#2 + [13] *((byte*~) set_process_name::$2) ← *((byte*~) set_process_name::$1) + [14] (signed word) set_process_name::j#1 ← ++ (signed word) set_process_name::j#2 + to:set_process_name::@1 diff --git a/src/test/ref/string-pointer-problem.log b/src/test/ref/string-pointer-problem.log new file mode 100644 index 000000000..eb77213d3 --- /dev/null +++ b/src/test/ref/string-pointer-problem.log @@ -0,0 +1,566 @@ +Identified constant variable (byte*) process_name +Culled Empty Block (label) set_process_name::@4 +Culled Empty Block (label) set_process_name::@3 +Culled Empty Block (label) set_process_name::@5 +Culled Empty Block (label) set_process_name::@6 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @2 + (byte*) set_process_name::name#0 ← (const string) main::name + call set_process_name + to:main::@1 +main::@1: scope:[main] from main + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +@1: scope:[] from @begin + (byte*) process_name#0 ← ((byte*)) (number) $400 + to:@2 +set_process_name: scope:[set_process_name] from main + (byte*) set_process_name::name#3 ← phi( main/(byte*) set_process_name::name#0 ) + (signed word) set_process_name::j#0 ← (number) 0 + to:set_process_name::@1 +set_process_name::@1: scope:[set_process_name] from set_process_name set_process_name::@2 + (byte*) set_process_name::name#2 ← phi( set_process_name/(byte*) set_process_name::name#3 set_process_name::@2/(byte*) set_process_name::name#1 ) + (signed word) set_process_name::j#2 ← phi( set_process_name/(signed word) set_process_name::j#0 set_process_name::@2/(signed word) set_process_name::j#1 ) + (bool~) set_process_name::$0 ← (signed word) set_process_name::j#2 < (number) $11 + if((bool~) set_process_name::$0) goto set_process_name::@2 + to:set_process_name::@return +set_process_name::@2: scope:[set_process_name] from set_process_name::@1 + (signed word) set_process_name::j#3 ← phi( set_process_name::@1/(signed word) set_process_name::j#2 ) + (byte*) set_process_name::name#1 ← phi( set_process_name::@1/(byte*) set_process_name::name#2 ) + *((byte*) process_name#0 + (signed word) set_process_name::j#3) ← *((byte*) set_process_name::name#1 + (signed word) set_process_name::j#3) + (signed word) set_process_name::j#1 ← ++ (signed word) set_process_name::j#3 + to:set_process_name::@1 +set_process_name::@return: scope:[set_process_name] from set_process_name::@1 + return + to:@return +@2: scope:[] from @1 + call main + to:@3 +@3: scope:[] from @2 + to:@end +@end: scope:[] from @3 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @3 +(label) @begin +(label) @end +(void()) main() +(label) main::@1 +(label) main::@return +(const string) main::name = (string) "keyboard" +(byte*) process_name +(byte*) process_name#0 +(void()) set_process_name((byte*) set_process_name::name) +(bool~) set_process_name::$0 +(label) set_process_name::@1 +(label) set_process_name::@2 +(label) set_process_name::@return +(signed word) set_process_name::j +(signed word) set_process_name::j#0 +(signed word) set_process_name::j#1 +(signed word) set_process_name::j#2 +(signed word) set_process_name::j#3 +(byte*) set_process_name::name +(byte*) set_process_name::name#0 +(byte*) set_process_name::name#1 +(byte*) set_process_name::name#2 +(byte*) set_process_name::name#3 + +Adding number conversion cast (snumber) 0 in (signed word) set_process_name::j#0 ← (number) 0 +Adding number conversion cast (snumber) $11 in (bool~) set_process_name::$0 ← (signed word) set_process_name::j#2 < (number) $11 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte*) process_name#0 ← (byte*)(number) $400 +Inlining cast (signed word) set_process_name::j#0 ← (snumber)(number) 0 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast 0 +Simplifying constant integer cast $11 +Successful SSA optimization PassNCastSimplification +Finalized signed number type (signed byte) 0 +Finalized signed number type (signed byte) $11 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias (byte*) set_process_name::name#1 = (byte*) set_process_name::name#2 +Alias (signed word) set_process_name::j#2 = (signed word) set_process_name::j#3 +Successful SSA optimization Pass2AliasElimination +Identical Phi Values (byte*) set_process_name::name#3 (byte*) set_process_name::name#0 +Identical Phi Values (byte*) set_process_name::name#1 (byte*) set_process_name::name#3 +Successful SSA optimization Pass2IdenticalPhiElimination +Simple Condition (bool~) set_process_name::$0 [8] if((signed word) set_process_name::j#2<(signed byte) $11) goto set_process_name::@2 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant (const byte*) set_process_name::name#0 = main::name +Constant (const byte*) process_name#0 = (byte*) 1024 +Constant (const signed word) set_process_name::j#0 = 0 +Successful SSA optimization Pass2ConstantIdentification +De-inlining pointer[w] to *(pointer+w) [10] *((const byte*) process_name#0 + (signed word) set_process_name::j#2) ← *((const byte*) set_process_name::name#0 + (signed word) set_process_name::j#2) +De-inlining pointer[w] to *(pointer+w) [10] *((const byte*) process_name#0 + (signed word) set_process_name::j#2) ← *((byte*~) set_process_name::$1) +Successful SSA optimization Pass2DeInlineWordDerefIdx +Inlining constant with var siblings (const signed word) set_process_name::j#0 +Constant inlined set_process_name::name#0 = (const string) main::name +Constant inlined set_process_name::j#0 = (signed byte) 0 +Successful SSA optimization Pass2ConstantInlining +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 @3 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +Adding NOP phi() at start of main::@1 +Adding NOP phi() at start of set_process_name +CALL GRAPH +Calls in [] to main:3 +Calls in [main] to set_process_name:7 + +Created 1 initial phi equivalence classes +Coalesced [18] set_process_name::j#4 ← set_process_name::j#1 +Coalesced down to 1 phi equivalence classes +Culled Empty Block (label) @1 +Culled Empty Block (label) @3 +Culled Empty Block (label) main::@1 +Renumbering block @2 to @1 +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 +Adding NOP phi() at start of set_process_name + +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] phi() + [5] call set_process_name + to:main::@return +main::@return: scope:[main] from main + [6] return + to:@return +set_process_name: scope:[set_process_name] from main + [7] phi() + to:set_process_name::@1 +set_process_name::@1: scope:[set_process_name] from set_process_name set_process_name::@2 + [8] (signed word) set_process_name::j#2 ← phi( set_process_name/(signed byte) 0 set_process_name::@2/(signed word) set_process_name::j#1 ) + [9] if((signed word) set_process_name::j#2<(signed byte) $11) goto set_process_name::@2 + to:set_process_name::@return +set_process_name::@return: scope:[set_process_name] from set_process_name::@1 + [10] return + to:@return +set_process_name::@2: scope:[set_process_name] from set_process_name::@1 + [11] (byte*~) set_process_name::$1 ← (const string) main::name + (signed word) set_process_name::j#2 + [12] (byte*~) set_process_name::$2 ← (const byte*) process_name#0 + (signed word) set_process_name::j#2 + [13] *((byte*~) set_process_name::$2) ← *((byte*~) set_process_name::$1) + [14] (signed word) set_process_name::j#1 ← ++ (signed word) set_process_name::j#2 + to:set_process_name::@1 + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte*) process_name +(void()) set_process_name((byte*) set_process_name::name) +(byte*~) set_process_name::$1 11.0 +(byte*~) set_process_name::$2 22.0 +(signed word) set_process_name::j +(signed word) set_process_name::j#1 22.0 +(signed word) set_process_name::j#2 11.0 +(byte*) set_process_name::name + +Initial phi equivalence classes +[ set_process_name::j#2 set_process_name::j#1 ] +Added variable set_process_name::$1 to zero page equivalence class [ set_process_name::$1 ] +Added variable set_process_name::$2 to zero page equivalence class [ set_process_name::$2 ] +Complete equivalence classes +[ set_process_name::j#2 set_process_name::j#1 ] +[ set_process_name::$1 ] +[ set_process_name::$2 ] +Allocated zp ZP_WORD:2 [ set_process_name::j#2 set_process_name::j#1 ] +Allocated zp ZP_WORD:4 [ set_process_name::$1 ] +Allocated zp ZP_WORD:6 [ set_process_name::$2 ] + +INITIAL ASM +Target platform is c64basic / MOS6502X + // File Comments +// Test adding integer index to a pointer that is a literal string +// https://gitlab.com/camelot/kickc/issues/315 + // Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label process_name = $400 + // @begin +bbegin: + // [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 + // @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: + jmp bend + // @end +bend: + // main +main: { + // [5] call set_process_name + // [7] phi from main to set_process_name [phi:main->set_process_name] + set_process_name_from_main: + jsr set_process_name + jmp breturn + // main::@return + breturn: + // [6] return + rts + name: .text "keyboard" + .byte 0 +} + // set_process_name +set_process_name: { + .label j = 2 + .label _1 = 4 + .label _2 = 6 + // [8] phi from set_process_name to set_process_name::@1 [phi:set_process_name->set_process_name::@1] + b1_from_set_process_name: + // [8] phi (signed word) set_process_name::j#2 = (signed byte) 0 [phi:set_process_name->set_process_name::@1#0] -- vwsz1=vbsc1 + lda #<0 + sta.z j + lda #>0 + sta.z j+1 + jmp b1 + // set_process_name::@1 + b1: + // [9] if((signed word) set_process_name::j#2<(signed byte) $11) goto set_process_name::@2 -- vwsz1_lt_vwuc1_then_la1 + lda.z j+1 + bmi b2 + cmp #>$11 + bcc b2 + bne !+ + lda.z j + cmp #<$11 + bcc b2 + !: + jmp breturn + // set_process_name::@return + breturn: + // [10] return + rts + // set_process_name::@2 + b2: + // [11] (byte*~) set_process_name::$1 ← (const string) main::name + (signed word) set_process_name::j#2 -- pbuz1=pbuc1_plus_vwsz2 + lda #main.name + adc.z j+1 + sta.z _1+1 + // [12] (byte*~) set_process_name::$2 ← (const byte*) process_name#0 + (signed word) set_process_name::j#2 -- pbuz1=pbuc1_plus_vwsz2 + lda #process_name + adc.z j+1 + sta.z _2+1 + // [13] *((byte*~) set_process_name::$2) ← *((byte*~) set_process_name::$1) -- _deref_pbuz1=_deref_pbuz2 + ldy #0 + lda (_1),y + ldy #0 + sta (_2),y + // [14] (signed word) set_process_name::j#1 ← ++ (signed word) set_process_name::j#2 -- vwsz1=_inc_vwsz1 + inc.z j + bne !+ + inc.z j+1 + !: + // [8] phi from set_process_name::@2 to set_process_name::@1 [phi:set_process_name::@2->set_process_name::@1] + b1_from_b2: + // [8] phi (signed word) set_process_name::j#2 = (signed word) set_process_name::j#1 [phi:set_process_name::@2->set_process_name::@1#0] -- register_copy + jmp b1 +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [9] if((signed word) set_process_name::j#2<(signed byte) $11) goto set_process_name::@2 [ set_process_name::j#2 ] ( main:2::set_process_name:5 [ set_process_name::j#2 ] ) always clobbers reg byte a +Statement [11] (byte*~) set_process_name::$1 ← (const string) main::name + (signed word) set_process_name::j#2 [ set_process_name::j#2 set_process_name::$1 ] ( main:2::set_process_name:5 [ set_process_name::j#2 set_process_name::$1 ] ) always clobbers reg byte a +Statement [12] (byte*~) set_process_name::$2 ← (const byte*) process_name#0 + (signed word) set_process_name::j#2 [ set_process_name::j#2 set_process_name::$1 set_process_name::$2 ] ( main:2::set_process_name:5 [ set_process_name::j#2 set_process_name::$1 set_process_name::$2 ] ) always clobbers reg byte a +Statement [13] *((byte*~) set_process_name::$2) ← *((byte*~) set_process_name::$1) [ set_process_name::j#2 ] ( main:2::set_process_name:5 [ set_process_name::j#2 ] ) always clobbers reg byte a reg byte y +Potential registers zp ZP_WORD:2 [ set_process_name::j#2 set_process_name::j#1 ] : zp ZP_WORD:2 , +Potential registers zp ZP_WORD:4 [ set_process_name::$1 ] : zp ZP_WORD:4 , +Potential registers zp ZP_WORD:6 [ set_process_name::$2 ] : zp ZP_WORD:6 , + +REGISTER UPLIFT SCOPES +Uplift Scope [set_process_name] 33: zp ZP_WORD:2 [ set_process_name::j#2 set_process_name::j#1 ] 22: zp ZP_WORD:6 [ set_process_name::$2 ] 11: zp ZP_WORD:4 [ set_process_name::$1 ] +Uplift Scope [main] +Uplift Scope [] + +Uplifting [set_process_name] best 1063 combination zp ZP_WORD:2 [ set_process_name::j#2 set_process_name::j#1 ] zp ZP_WORD:6 [ set_process_name::$2 ] zp ZP_WORD:4 [ set_process_name::$1 ] +Uplifting [main] best 1063 combination +Uplifting [] best 1063 combination + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Test adding integer index to a pointer that is a literal string +// https://gitlab.com/camelot/kickc/issues/315 + // Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label process_name = $400 + // @begin +bbegin: + // [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 + // @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: + jmp bend + // @end +bend: + // main +main: { + // [5] call set_process_name + // [7] phi from main to set_process_name [phi:main->set_process_name] + set_process_name_from_main: + jsr set_process_name + jmp breturn + // main::@return + breturn: + // [6] return + rts + name: .text "keyboard" + .byte 0 +} + // set_process_name +set_process_name: { + .label j = 2 + .label _1 = 4 + .label _2 = 6 + // [8] phi from set_process_name to set_process_name::@1 [phi:set_process_name->set_process_name::@1] + b1_from_set_process_name: + // [8] phi (signed word) set_process_name::j#2 = (signed byte) 0 [phi:set_process_name->set_process_name::@1#0] -- vwsz1=vbsc1 + lda #<0 + sta.z j + lda #>0 + sta.z j+1 + jmp b1 + // set_process_name::@1 + b1: + // [9] if((signed word) set_process_name::j#2<(signed byte) $11) goto set_process_name::@2 -- vwsz1_lt_vwuc1_then_la1 + lda.z j+1 + bmi b2 + cmp #>$11 + bcc b2 + bne !+ + lda.z j + cmp #<$11 + bcc b2 + !: + jmp breturn + // set_process_name::@return + breturn: + // [10] return + rts + // set_process_name::@2 + b2: + // [11] (byte*~) set_process_name::$1 ← (const string) main::name + (signed word) set_process_name::j#2 -- pbuz1=pbuc1_plus_vwsz2 + lda #main.name + adc.z j+1 + sta.z _1+1 + // [12] (byte*~) set_process_name::$2 ← (const byte*) process_name#0 + (signed word) set_process_name::j#2 -- pbuz1=pbuc1_plus_vwsz2 + lda #process_name + adc.z j+1 + sta.z _2+1 + // [13] *((byte*~) set_process_name::$2) ← *((byte*~) set_process_name::$1) -- _deref_pbuz1=_deref_pbuz2 + ldy #0 + lda (_1),y + ldy #0 + sta (_2),y + // [14] (signed word) set_process_name::j#1 ← ++ (signed word) set_process_name::j#2 -- vwsz1=_inc_vwsz1 + inc.z j + bne !+ + inc.z j+1 + !: + // [8] phi from set_process_name::@2 to set_process_name::@1 [phi:set_process_name::@2->set_process_name::@1] + b1_from_b2: + // [8] phi (signed word) set_process_name::j#2 = (signed word) set_process_name::j#1 [phi:set_process_name::@2->set_process_name::@1#0] -- register_copy + jmp b1 +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp breturn +Removing instruction jmp b1 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction lda #>0 +Removing instruction ldy #0 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction main_from_b1: +Removing instruction bend_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction set_process_name_from_main: +Removing instruction breturn: +Removing instruction b1_from_set_process_name: +Removing instruction breturn: +Removing instruction b1_from_b2: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(const string) main::name name = (string) "keyboard" +(byte*) process_name +(const byte*) process_name#0 process_name = (byte*) 1024 +(void()) set_process_name((byte*) set_process_name::name) +(byte*~) set_process_name::$1 $1 zp ZP_WORD:4 11.0 +(byte*~) set_process_name::$2 $2 zp ZP_WORD:6 22.0 +(label) set_process_name::@1 +(label) set_process_name::@2 +(label) set_process_name::@return +(signed word) set_process_name::j +(signed word) set_process_name::j#1 j zp ZP_WORD:2 22.0 +(signed word) set_process_name::j#2 j zp ZP_WORD:2 11.0 +(byte*) set_process_name::name + +zp ZP_WORD:2 [ set_process_name::j#2 set_process_name::j#1 ] +zp ZP_WORD:4 [ set_process_name::$1 ] +zp ZP_WORD:6 [ set_process_name::$2 ] + + +FINAL ASSEMBLER +Score: 948 + + // File Comments +// Test adding integer index to a pointer that is a literal string +// https://gitlab.com/camelot/kickc/issues/315 + // Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + // Global Constants & labels + .label process_name = $400 + // @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: { + // set_process_name("keyboard") + // [5] call set_process_name + // [7] phi from main to set_process_name [phi:main->set_process_name] + jsr set_process_name + // main::@return + // } + // [6] return + rts + name: .text "keyboard" + .byte 0 +} + // set_process_name +set_process_name: { + .label j = 2 + .label _1 = 4 + .label _2 = 6 + // [8] phi from set_process_name to set_process_name::@1 [phi:set_process_name->set_process_name::@1] + // [8] phi (signed word) set_process_name::j#2 = (signed byte) 0 [phi:set_process_name->set_process_name::@1#0] -- vwsz1=vbsc1 + lda #<0 + sta.z j + sta.z j+1 + // set_process_name::@1 + b1: + // for(signed int j = 0; j < 17; j++) + // [9] if((signed word) set_process_name::j#2<(signed byte) $11) goto set_process_name::@2 -- vwsz1_lt_vwuc1_then_la1 + lda.z j+1 + bmi b2 + cmp #>$11 + bcc b2 + bne !+ + lda.z j + cmp #<$11 + bcc b2 + !: + // set_process_name::@return + // } + // [10] return + rts + // set_process_name::@2 + b2: + // process_name[j]=name[j] + // [11] (byte*~) set_process_name::$1 ← (const string) main::name + (signed word) set_process_name::j#2 -- pbuz1=pbuc1_plus_vwsz2 + lda #main.name + adc.z j+1 + sta.z _1+1 + // [12] (byte*~) set_process_name::$2 ← (const byte*) process_name#0 + (signed word) set_process_name::j#2 -- pbuz1=pbuc1_plus_vwsz2 + lda #process_name + adc.z j+1 + sta.z _2+1 + // [13] *((byte*~) set_process_name::$2) ← *((byte*~) set_process_name::$1) -- _deref_pbuz1=_deref_pbuz2 + ldy #0 + lda (_1),y + sta (_2),y + // for(signed int j = 0; j < 17; j++) + // [14] (signed word) set_process_name::j#1 ← ++ (signed word) set_process_name::j#2 -- vwsz1=_inc_vwsz1 + inc.z j + bne !+ + inc.z j+1 + !: + // [8] phi from set_process_name::@2 to set_process_name::@1 [phi:set_process_name::@2->set_process_name::@1] + // [8] phi (signed word) set_process_name::j#2 = (signed word) set_process_name::j#1 [phi:set_process_name::@2->set_process_name::@1#0] -- register_copy + jmp b1 +} + // File Data + diff --git a/src/test/ref/string-pointer-problem.sym b/src/test/ref/string-pointer-problem.sym new file mode 100644 index 000000000..cdc202331 --- /dev/null +++ b/src/test/ref/string-pointer-problem.sym @@ -0,0 +1,22 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(const string) main::name name = (string) "keyboard" +(byte*) process_name +(const byte*) process_name#0 process_name = (byte*) 1024 +(void()) set_process_name((byte*) set_process_name::name) +(byte*~) set_process_name::$1 $1 zp ZP_WORD:4 11.0 +(byte*~) set_process_name::$2 $2 zp ZP_WORD:6 22.0 +(label) set_process_name::@1 +(label) set_process_name::@2 +(label) set_process_name::@return +(signed word) set_process_name::j +(signed word) set_process_name::j#1 j zp ZP_WORD:2 22.0 +(signed word) set_process_name::j#2 j zp ZP_WORD:2 11.0 +(byte*) set_process_name::name + +zp ZP_WORD:2 [ set_process_name::j#2 set_process_name::j#1 ] +zp ZP_WORD:4 [ set_process_name::$1 ] +zp ZP_WORD:6 [ set_process_name::$2 ]