mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-20 00:29:10 +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());
|
return new SymbolTypePointer(((SymbolTypePointer) type1).getElementType());
|
||||||
} else if(type1 instanceof SymbolTypePointer && type2 instanceof SymbolTypePointer) {
|
} else if(type1 instanceof SymbolTypePointer && type2 instanceof SymbolTypePointer) {
|
||||||
return SymbolType.WORD;
|
return SymbolType.WORD;
|
||||||
|
} else if(SymbolType.STRING.equals(type1) && SymbolType.isInteger(type2)) {
|
||||||
|
return new SymbolTypePointer(SymbolType.BYTE);
|
||||||
}
|
}
|
||||||
// Handle numeric types through proper promotion
|
// Handle numeric types through proper promotion
|
||||||
if(SymbolType.isInteger(type1) && SymbolType.isInteger(type2)) {
|
if(SymbolType.isInteger(type1) && SymbolType.isInteger(type2)) {
|
||||||
|
@ -39,6 +39,8 @@ public class OperatorPlus extends OperatorBinary {
|
|||||||
return new SymbolTypePointer(((SymbolTypePointer) type2).getElementType());
|
return new SymbolTypePointer(((SymbolTypePointer) type2).getElementType());
|
||||||
} else if(type1 instanceof SymbolTypePointer && SymbolType.isInteger(type2)) {
|
} else if(type1 instanceof SymbolTypePointer && SymbolType.isInteger(type2)) {
|
||||||
return new SymbolTypePointer(((SymbolTypePointer) type1).getElementType());
|
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
|
// Handle numeric types through proper promotion
|
||||||
if(SymbolType.isInteger(type1) && SymbolType.isInteger(type2)) {
|
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);
|
VariableReferenceInfos variableReferenceInfos = new VariableReferenceInfos(blockSuccessors, symbolVarReferences, blockVarReferences, statementVarReferences);
|
||||||
if(getLog().isVerboseSSAOptimize()) {
|
//if(getLog().isVerboseSSAOptimize()) {
|
||||||
getLog().append(variableReferenceInfos.getSizeInfo());
|
// getLog().append(variableReferenceInfos.getSizeInfo());
|
||||||
}
|
//}
|
||||||
return variableReferenceInfos;
|
return variableReferenceInfos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,16 @@ public class TestPrograms {
|
|||||||
public 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
|
//@Test
|
||||||
//public void testOs51() throws IOException, URISyntaxException {
|
//public void testOs51() throws IOException, URISyntaxException {
|
||||||
// compileAndCompare("complex/unit5/os5.1", log().verboseSSAOptimize());
|
// compileAndCompare("complex/unit5/os5.1", log().verboseSSAOptimize());
|
||||||
@ -685,7 +695,8 @@ public class TestPrograms {
|
|||||||
compileAndCompare("struct-ptr-29");
|
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
|
//@Test
|
||||||
//public void testStructPtr28() throws IOException, URISyntaxException {
|
//public void testStructPtr28() throws IOException, URISyntaxException {
|
||||||
// compileAndCompare("struct-ptr-28");
|
// compileAndCompare("struct-ptr-28");
|
||||||
@ -708,7 +719,7 @@ public class TestPrograms {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStructPtr23() throws IOException, URISyntaxException {
|
public void testStructPtr23() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("struct-ptr-23", log());
|
compileAndCompare("struct-ptr-23");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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
|
// Example of a struct containing an array
|
||||||
// It works on the surface - but illustrates the problem with structs containing arrays treating them like pointers.
|
// 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 {
|
struct Person {
|
||||||
char id;
|
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