mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-06 13:31:05 +00:00
Fixed problem with adding ints to literal string pointers. Closes #315
This commit is contained in:
parent
bc1bb7d2e5
commit
0ce718371e
@ -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)) {
|
||||
|
@ -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)) {
|
||||
|
@ -88,9 +88,9 @@ public class PassNCalcVariableReferenceInfos extends PassNCalcBase<VariableRefer
|
||||
});
|
||||
}
|
||||
VariableReferenceInfos variableReferenceInfos = new VariableReferenceInfos(blockSuccessors, symbolVarReferences, blockVarReferences, statementVarReferences);
|
||||
if(getLog().isVerboseSSAOptimize()) {
|
||||
getLog().append(variableReferenceInfos.getSizeInfo());
|
||||
}
|
||||
//if(getLog().isVerboseSSAOptimize()) {
|
||||
// getLog().append(variableReferenceInfos.getSizeInfo());
|
||||
//}
|
||||
return variableReferenceInfos;
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,16 @@ public class TestPrograms {
|
||||
public TestPrograms() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringPointerProblem() throws IOException, URISyntaxException {
|
||||
compileAndCompare("string-pointer-problem");
|
||||
}
|
||||
|
||||
//@Test
|
||||
//public void testOs52() throws IOException, URISyntaxException {
|
||||
// compileAndCompare("complex/unit5/os5.2");
|
||||
//}
|
||||
|
||||
//@Test
|
||||
//public void testOs51() throws IOException, URISyntaxException {
|
||||
// compileAndCompare("complex/unit5/os5.1", log().verboseSSAOptimize());
|
||||
@ -685,7 +695,8 @@ public class TestPrograms {
|
||||
compileAndCompare("struct-ptr-29");
|
||||
}
|
||||
|
||||
// TODO: Fix problem with object-allocated structs that contain arrays!
|
||||
// TODO: Fix problem with stack-allocated structs that contain arrays!
|
||||
// https://gitlab.com/camelot/kickc/issues/314
|
||||
//@Test
|
||||
//public void testStructPtr28() throws IOException, URISyntaxException {
|
||||
// compileAndCompare("struct-ptr-28");
|
||||
@ -708,7 +719,7 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testStructPtr23() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-ptr-23", log());
|
||||
compileAndCompare("struct-ptr-23");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
14
src/test/kc/string-pointer-problem.kc
Normal file
14
src/test/kc/string-pointer-problem.kc
Normal file
@ -0,0 +1,14 @@
|
||||
// Test adding integer index to a pointer that is a literal string
|
||||
// https://gitlab.com/camelot/kickc/issues/315
|
||||
|
||||
void main() {
|
||||
set_process_name("keyboard");
|
||||
}
|
||||
|
||||
char* process_name = 0x0400;
|
||||
|
||||
void set_process_name(char* name) {
|
||||
for(signed int j = 0; j < 17; j++){
|
||||
process_name[j]=name[j];
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// Example of a struct containing an array
|
||||
// It works on the surface - but illustrates the problem with structs containing arrays treating them like pointers.
|
||||
// https://gitlab.com/camelot/kickc/issues/312
|
||||
// https://gitlab.com/camelot/kickc/issues/314
|
||||
|
||||
struct Person {
|
||||
char id;
|
||||
|
54
src/test/ref/string-pointer-problem.asm
Normal file
54
src/test/ref/string-pointer-problem.asm
Normal file
@ -0,0 +1,54 @@
|
||||
// Test adding integer index to a pointer that is a literal string
|
||||
// https://gitlab.com/camelot/kickc/issues/315
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.label process_name = $400
|
||||
main: {
|
||||
jsr set_process_name
|
||||
rts
|
||||
name: .text "keyboard"
|
||||
.byte 0
|
||||
}
|
||||
set_process_name: {
|
||||
.label j = 2
|
||||
.label _1 = 4
|
||||
.label _2 = 6
|
||||
lda #<0
|
||||
sta.z j
|
||||
sta.z j+1
|
||||
b1:
|
||||
lda.z j+1
|
||||
bmi b2
|
||||
cmp #>$11
|
||||
bcc b2
|
||||
bne !+
|
||||
lda.z j
|
||||
cmp #<$11
|
||||
bcc b2
|
||||
!:
|
||||
rts
|
||||
b2:
|
||||
lda #<main.name
|
||||
clc
|
||||
adc.z j
|
||||
sta.z _1
|
||||
lda #>main.name
|
||||
adc.z j+1
|
||||
sta.z _1+1
|
||||
lda #<process_name
|
||||
clc
|
||||
adc.z j
|
||||
sta.z _2
|
||||
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
|
||||
}
|
32
src/test/ref/string-pointer-problem.cfg
Normal file
32
src/test/ref/string-pointer-problem.cfg
Normal file
@ -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
|
566
src/test/ref/string-pointer-problem.log
Normal file
566
src/test/ref/string-pointer-problem.log
Normal file
@ -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
|
||||
clc
|
||||
adc.z j
|
||||
sta.z _1
|
||||
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
|
||||
clc
|
||||
adc.z j
|
||||
sta.z _2
|
||||
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
|
||||
clc
|
||||
adc.z j
|
||||
sta.z _1
|
||||
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
|
||||
clc
|
||||
adc.z j
|
||||
sta.z _2
|
||||
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
|
||||
clc
|
||||
adc.z j
|
||||
sta.z _1
|
||||
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
|
||||
clc
|
||||
adc.z j
|
||||
sta.z _2
|
||||
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
|
||||
|
22
src/test/ref/string-pointer-problem.sym
Normal file
22
src/test/ref/string-pointer-problem.sym
Normal file
@ -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 ]
|
Loading…
x
Reference in New Issue
Block a user