1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-29 03:56:15 +00:00

Fixed problem with adding ints to literal string pointers. Closes #315

This commit is contained in:
jespergravgaard 2019-09-14 11:21:29 +02:00
parent bc1bb7d2e5
commit 0ce718371e
10 changed files with 709 additions and 6 deletions

View File

@ -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)) {

View File

@ -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)) {

View File

@ -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;
} }

View File

@ -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

View 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];
}
}

View File

@ -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;

View 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
}

View 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

View 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

View 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 ]