1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-01-11 20:30:08 +00:00

#pragma struct_model(classic) fixes problem with variable instances of structs with array members. Closes

This commit is contained in:
jespergravgaard 2021-08-02 23:00:15 +02:00
parent 6c4d0488b9
commit 4f2ae64cac
10 changed files with 455 additions and 60 deletions

@ -2322,6 +2322,10 @@ public class TestProgramsFast extends TestPrograms {
compileAndCompare("union-0.c");
}
@Test
public void testStruct46() throws IOException {
compileAndCompare("struct-46.c");
}
@Test
public void testStruct45() throws IOException {

@ -1,7 +1,7 @@
// https://gitlab.com/camelot/kickc/-/issues/590
#pragma var_model(mem)
#pragma struct_model(classic)
#pragma var_model(struct_mem)
struct deviceslot {
unsigned char hostSlot;

26
src/test/kc/struct-46.c Normal file

@ -0,0 +1,26 @@
// https://gitlab.com/camelot/kickc/-/issues/587
// Creating variable instances of structs with array members fails to compile
#pragma struct_model(classic)
#pragma var_model(struct_mem)
typedef struct netconfig {
char ssid[32];
char password[64];
} NetConfig;
typedef struct other {
char a;
char b;
} Other;
char const * OUT = (char*)0x8000;
void main() {
Other x;
NetConfig a = {"123", "abc"};
*(OUT + 0) = a.ssid[0];
NetConfig b;
}

@ -14,6 +14,7 @@
.segment Code
main: {
.label slotsA = ssA
.label i = 2
// deviceslot_t s1 = {'A', 'R', "f1"}
ldy #SIZEOF_STRUCT_DEVICESLOT
!:
@ -50,17 +51,17 @@ main: {
dey
bne !-
lda #0
sta i
sta.z i
__b1:
// deviceslot_t ds = slotsA->slot[i]
lda i
lda.z i
asl
asl
asl
asl
asl
clc
adc i
adc.z i
asl
tax
ldy #0
@ -73,12 +74,12 @@ main: {
bne !-
// *(OUT + i) = ds.mode
lda ds+OFFSET_STRUCT_DEVICESLOT_MODE
ldy i
ldy.z i
sta OUT,y
// for(char i: 0..1)
inc i
inc.z i
lda #2
cmp i
cmp.z i
bne __b1
// }
rts
@ -87,7 +88,6 @@ main: {
s2: .fill SIZEOF_STRUCT_DEVICESLOT, 0
ssA: .fill SIZEOF_STRUCT_DEVICESLOTSA, 0
ds: .fill SIZEOF_STRUCT_DEVICESLOT, 0
i: .byte 0
}
__0: .byte 'A', 'R'
.text "f1"

@ -1,4 +1,3 @@
Updating intermediate variable memory area to MAIN_MEMORY main::$1
Fixing struct type size struct deviceslot to 66
Fixing struct type size struct deviceslotsA to 132
Fixing struct type size struct deviceslot to 66
@ -231,10 +230,10 @@ Complete equivalence classes
[ main::s2 ]
[ main::ssA ]
[ main::ds ]
Allocated mem[1] [ main::i#2 main::i#1 ]
Allocated mem[1] [ main::$11 ]
Allocated mem[1] [ main::$12 ]
Allocated mem[1] [ main::$4 ]
Allocated zp[1]:2 [ main::i#2 main::i#1 ]
Allocated zp[1]:3 [ main::$11 ]
Allocated zp[1]:4 [ main::$12 ]
Allocated zp[1]:5 [ main::$4 ]
Allocated mem[66] [ main::s1 ]
Allocated mem[66] [ main::s2 ]
Allocated mem[132] [ main::ssA ]
@ -246,12 +245,12 @@ Statement [2] *(&main::ssA) = memset(struct deviceslotsA, SIZEOF_STRUCT_DEVICESL
Statement [3] *((struct deviceslot*)main::slotsA) = memcpy(*(&main::s1), struct deviceslot, SIZEOF_STRUCT_DEVICESLOT) [ main::s2 main::ds ] ( [ main::s2 main::ds ] { } ) always clobbers reg byte a reg byte y
Statement [4] *((struct deviceslot*)main::slotsA+1*SIZEOF_STRUCT_DEVICESLOT) = memcpy(*(&main::s2), struct deviceslot, SIZEOF_STRUCT_DEVICESLOT) [ main::ds ] ( [ main::ds ] { } ) always clobbers reg byte a reg byte y
Statement [6] main::$11 = main::i#2 << 5 [ main::i#2 main::$11 main::ds ] ( [ main::i#2 main::$11 main::ds ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for mem[1] [ main::i#2 main::i#1 ]
Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ]
Statement [7] main::$12 = main::$11 + main::i#2 [ main::i#2 main::$12 main::ds ] ( [ main::i#2 main::$12 main::ds ] { } ) always clobbers reg byte a
Statement [8] main::$4 = main::$12 << 1 [ main::i#2 main::$4 main::ds ] ( [ main::i#2 main::$4 main::ds ] { } ) always clobbers reg byte a
Statement [9] *(&main::ds) = memcpy(((struct deviceslot*)main::slotsA)[main::$4], struct deviceslot, SIZEOF_STRUCT_DEVICESLOT) [ main::i#2 main::ds ] ( [ main::i#2 main::ds ] { } ) always clobbers reg byte a reg byte x reg byte y
Removing always clobbered register reg byte x as potential for mem[1] [ main::i#2 main::i#1 ]
Removing always clobbered register reg byte y as potential for mem[1] [ main::i#2 main::i#1 ]
Removing always clobbered register reg byte x as potential for zp[1]:2 [ main::i#2 main::i#1 ]
Removing always clobbered register reg byte y as potential for zp[1]:2 [ main::i#2 main::i#1 ]
Statement [10] OUT[main::i#2] = *((byte*)&main::ds+OFFSET_STRUCT_DEVICESLOT_MODE) [ main::i#2 main::ds ] ( [ main::i#2 main::ds ] { } ) always clobbers reg byte a reg byte y
Statement [12] if(main::i#1!=2) goto main::@1 [ main::i#1 main::ds ] ( [ main::i#1 main::ds ] { } ) always clobbers reg byte a
Statement [0] *(&main::s1) = memcpy(*(&$0), struct deviceslot, SIZEOF_STRUCT_DEVICESLOT) [ main::s2 main::ssA main::s1 main::ds ] ( [ main::s2 main::ssA main::s1 main::ds ] { } ) always clobbers reg byte a reg byte y
@ -265,27 +264,27 @@ Statement [8] main::$4 = main::$12 << 1 [ main::i#2 main::$4 main::ds ] ( [ mai
Statement [9] *(&main::ds) = memcpy(((struct deviceslot*)main::slotsA)[main::$4], struct deviceslot, SIZEOF_STRUCT_DEVICESLOT) [ main::i#2 main::ds ] ( [ main::i#2 main::ds ] { } ) always clobbers reg byte a reg byte x reg byte y
Statement [10] OUT[main::i#2] = *((byte*)&main::ds+OFFSET_STRUCT_DEVICESLOT_MODE) [ main::i#2 main::ds ] ( [ main::i#2 main::ds ] { } ) always clobbers reg byte a reg byte y
Statement [12] if(main::i#1!=2) goto main::@1 [ main::i#1 main::ds ] ( [ main::i#1 main::ds ] { } ) always clobbers reg byte a
Potential registers mem[1] [ main::i#2 main::i#1 ] : mem[1] ,
Potential registers mem[1] [ main::$11 ] : mem[1] , reg byte a , reg byte x , reg byte y ,
Potential registers mem[1] [ main::$12 ] : mem[1] , reg byte a , reg byte x , reg byte y ,
Potential registers mem[1] [ main::$4 ] : mem[1] , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 ,
Potential registers zp[1]:3 [ main::$11 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:4 [ main::$12 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:5 [ main::$4 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
Potential registers mem[66] [ main::s1 ] : mem[66] ,
Potential registers mem[66] [ main::s2 ] : mem[66] ,
Potential registers mem[132] [ main::ssA ] : mem[132] ,
Potential registers mem[66] [ main::ds ] : mem[66] ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 25.67: mem[1] [ main::i#2 main::i#1 ] 22: mem[1] [ main::$11 ] 22: mem[1] [ main::$12 ] 11: mem[1] [ main::$4 ] 0: mem[66] [ main::s1 ] 0: mem[66] [ main::s2 ] 0: mem[132] [ main::ssA ] 0: mem[66] [ main::ds ]
Uplift Scope [main] 25.67: zp[1]:2 [ main::i#2 main::i#1 ] 22: zp[1]:3 [ main::$11 ] 22: zp[1]:4 [ main::$12 ] 11: zp[1]:5 [ main::$4 ] 0: mem[66] [ main::s1 ] 0: mem[66] [ main::s2 ] 0: mem[132] [ main::ssA ] 0: mem[66] [ main::ds ]
Uplift Scope [deviceslot]
Uplift Scope [deviceslotsA]
Uplift Scope []
Uplifting [main] best 948 combination mem[1] [ main::i#2 main::i#1 ] reg byte a [ main::$11 ] reg byte a [ main::$12 ] reg byte a [ main::$4 ] mem[66] [ main::s1 ] mem[66] [ main::s2 ] mem[132] [ main::ssA ] mem[66] [ main::ds ]
Uplifting [deviceslot] best 948 combination
Uplifting [deviceslotsA] best 948 combination
Uplifting [] best 948 combination
Attempting to uplift remaining variables inmem[1] [ main::i#2 main::i#1 ]
Uplifting [main] best 948 combination mem[1] [ main::i#2 main::i#1 ]
Uplifting [main] best 888 combination zp[1]:2 [ main::i#2 main::i#1 ] reg byte a [ main::$11 ] reg byte a [ main::$12 ] reg byte a [ main::$4 ] mem[66] [ main::s1 ] mem[66] [ main::s2 ] mem[132] [ main::ssA ] mem[66] [ main::ds ]
Uplifting [deviceslot] best 888 combination
Uplifting [deviceslotsA] best 888 combination
Uplifting [] best 888 combination
Attempting to uplift remaining variables inzp[1]:2 [ main::i#2 main::i#1 ]
Uplifting [main] best 888 combination zp[1]:2 [ main::i#2 main::i#1 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
@ -308,6 +307,7 @@ ASSEMBLER BEFORE OPTIMIZATION
// main
main: {
.label slotsA = ssA
.label i = 2
// [0] *(&main::s1) = memcpy(*(&$0), struct deviceslot, SIZEOF_STRUCT_DEVICESLOT) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_DEVICESLOT
!:
@ -345,9 +345,9 @@ main: {
bne !-
// [5] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [5] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbum1=vbuc1
// [5] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta i
sta.z i
jmp __b1
// [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
__b1_from___b1:
@ -355,16 +355,16 @@ main: {
jmp __b1
// main::@1
__b1:
// [6] main::$11 = main::i#2 << 5 -- vbuaa=vbum1_rol_5
lda i
// [6] main::$11 = main::i#2 << 5 -- vbuaa=vbuz1_rol_5
lda.z i
asl
asl
asl
asl
asl
// [7] main::$12 = main::$11 + main::i#2 -- vbuaa=vbuaa_plus_vbum1
// [7] main::$12 = main::$11 + main::i#2 -- vbuaa=vbuaa_plus_vbuz1
clc
adc i
adc.z i
// [8] main::$4 = main::$12 << 1 -- vbuaa=vbuaa_rol_1
asl
// [9] *(&main::ds) = memcpy(((struct deviceslot*)main::slotsA)[main::$4], struct deviceslot, SIZEOF_STRUCT_DEVICESLOT) -- _deref_pssc1=pssc2_derefidx_vbuaa_memcpy_vbuc3
@ -377,15 +377,15 @@ main: {
iny
cpy #SIZEOF_STRUCT_DEVICESLOT
bne !-
// [10] OUT[main::i#2] = *((byte*)&main::ds+OFFSET_STRUCT_DEVICESLOT_MODE) -- pbuc1_derefidx_vbum1=_deref_pbuc2
// [10] OUT[main::i#2] = *((byte*)&main::ds+OFFSET_STRUCT_DEVICESLOT_MODE) -- pbuc1_derefidx_vbuz1=_deref_pbuc2
lda ds+OFFSET_STRUCT_DEVICESLOT_MODE
ldy i
ldy.z i
sta OUT,y
// [11] main::i#1 = ++ main::i#2 -- vbum1=_inc_vbum1
inc i
// [12] if(main::i#1!=2) goto main::@1 -- vbum1_neq_vbuc1_then_la1
// [11] main::i#1 = ++ main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [12] if(main::i#1!=2) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #2
cmp i
cmp.z i
bne __b1_from___b1
jmp __breturn
// main::@return
@ -397,7 +397,6 @@ main: {
s2: .fill SIZEOF_STRUCT_DEVICESLOT, 0
ssA: .fill SIZEOF_STRUCT_DEVICESLOTSA, 0
ds: .fill SIZEOF_STRUCT_DEVICESLOT, 0
i: .byte 0
}
// File Data
__0: .byte 'A', 'R'
@ -435,14 +434,14 @@ byte~ main::$12 reg byte a 22.0
byte~ main::$4 reg byte a 11.0
struct deviceslot main::ds loadstore mem[66]
byte main::i
byte main::i#1 i mem[1] 16.5
byte main::i#2 i mem[1] 9.166666666666666
byte main::i#1 i zp[1]:2 16.5
byte main::i#2 i zp[1]:2 9.166666666666666
struct deviceslot main::s1 loadstore mem[66]
struct deviceslot main::s2 loadstore mem[66]
constant struct deviceslotsA* main::slotsA = &main::ssA
volatile struct deviceslotsA main::ssA loadstore mem[132]
mem[1] [ main::i#2 main::i#1 ]
zp[1]:2 [ main::i#2 main::i#1 ]
reg byte a [ main::$11 ]
reg byte a [ main::$12 ]
reg byte a [ main::$4 ]
@ -453,7 +452,7 @@ mem[66] [ main::ds ]
FINAL ASSEMBLER
Score: 858
Score: 798
// File Comments
// https://gitlab.com/camelot/kickc/-/issues/590
@ -475,6 +474,7 @@ Score: 858
// main
main: {
.label slotsA = ssA
.label i = 2
// deviceslot_t s1 = {'A', 'R', "f1"}
// [0] *(&main::s1) = memcpy(*(&$0), struct deviceslot, SIZEOF_STRUCT_DEVICESLOT) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_DEVICESLOT
@ -516,24 +516,24 @@ main: {
dey
bne !-
// [5] phi from main to main::@1 [phi:main->main::@1]
// [5] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbum1=vbuc1
// [5] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta i
sta.z i
// [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [5] phi main::i#2 = main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// main::@1
__b1:
// deviceslot_t ds = slotsA->slot[i]
// [6] main::$11 = main::i#2 << 5 -- vbuaa=vbum1_rol_5
lda i
// [6] main::$11 = main::i#2 << 5 -- vbuaa=vbuz1_rol_5
lda.z i
asl
asl
asl
asl
asl
// [7] main::$12 = main::$11 + main::i#2 -- vbuaa=vbuaa_plus_vbum1
// [7] main::$12 = main::$11 + main::i#2 -- vbuaa=vbuaa_plus_vbuz1
clc
adc i
adc.z i
// [8] main::$4 = main::$12 << 1 -- vbuaa=vbuaa_rol_1
asl
// [9] *(&main::ds) = memcpy(((struct deviceslot*)main::slotsA)[main::$4], struct deviceslot, SIZEOF_STRUCT_DEVICESLOT) -- _deref_pssc1=pssc2_derefidx_vbuaa_memcpy_vbuc3
@ -547,16 +547,16 @@ main: {
cpy #SIZEOF_STRUCT_DEVICESLOT
bne !-
// *(OUT + i) = ds.mode
// [10] OUT[main::i#2] = *((byte*)&main::ds+OFFSET_STRUCT_DEVICESLOT_MODE) -- pbuc1_derefidx_vbum1=_deref_pbuc2
// [10] OUT[main::i#2] = *((byte*)&main::ds+OFFSET_STRUCT_DEVICESLOT_MODE) -- pbuc1_derefidx_vbuz1=_deref_pbuc2
lda ds+OFFSET_STRUCT_DEVICESLOT_MODE
ldy i
ldy.z i
sta OUT,y
// for(char i: 0..1)
// [11] main::i#1 = ++ main::i#2 -- vbum1=_inc_vbum1
inc i
// [12] if(main::i#1!=2) goto main::@1 -- vbum1_neq_vbuc1_then_la1
// [11] main::i#1 = ++ main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [12] if(main::i#1!=2) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #2
cmp i
cmp.z i
bne __b1
// main::@return
// }
@ -567,7 +567,6 @@ main: {
s2: .fill SIZEOF_STRUCT_DEVICESLOT, 0
ssA: .fill SIZEOF_STRUCT_DEVICESLOTSA, 0
ds: .fill SIZEOF_STRUCT_DEVICESLOT, 0
i: .byte 0
}
// File Data
__0: .byte 'A', 'R'

@ -10,14 +10,14 @@ byte~ main::$12 reg byte a 22.0
byte~ main::$4 reg byte a 11.0
struct deviceslot main::ds loadstore mem[66]
byte main::i
byte main::i#1 i mem[1] 16.5
byte main::i#2 i mem[1] 9.166666666666666
byte main::i#1 i zp[1]:2 16.5
byte main::i#2 i zp[1]:2 9.166666666666666
struct deviceslot main::s1 loadstore mem[66]
struct deviceslot main::s2 loadstore mem[66]
constant struct deviceslotsA* main::slotsA = &main::ssA
volatile struct deviceslotsA main::ssA loadstore mem[132]
mem[1] [ main::i#2 main::i#1 ]
zp[1]:2 [ main::i#2 main::i#1 ]
reg byte a [ main::$11 ]
reg byte a [ main::$12 ]
reg byte a [ main::$4 ]

@ -0,0 +1,52 @@
// https://gitlab.com/camelot/kickc/-/issues/587
// Creating variable instances of structs with array members fails to compile
// Commodore 64 PRG executable file
.file [name="struct-46.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.const SIZEOF_STRUCT_OTHER = 2
.const SIZEOF_STRUCT_NETCONFIG = $60
.label OUT = $8000
.segment Code
main: {
// Other x
ldy #SIZEOF_STRUCT_OTHER
lda #0
!:
dey
sta x,y
bne !-
// NetConfig a = {"123", "abc"}
ldy #SIZEOF_STRUCT_NETCONFIG
!:
lda __0-1,y
sta a-1,y
dey
bne !-
// *(OUT + 0) = a.ssid[0]
lda a
sta OUT
// NetConfig b
ldy #SIZEOF_STRUCT_NETCONFIG
lda #0
!:
dey
sta b,y
bne !-
// }
rts
.segment Data
x: .fill SIZEOF_STRUCT_OTHER, 0
a: .fill SIZEOF_STRUCT_NETCONFIG, 0
b: .fill SIZEOF_STRUCT_NETCONFIG, 0
}
__0: .text "123"
.byte 0
.fill $1c, 0
.text "abc"
.byte 0
.fill $3c, 0

@ -0,0 +1,11 @@
void main()
main: scope:[main] from
[0] *(&main::x) = memset(struct other, SIZEOF_STRUCT_OTHER)
[1] *(&main::a) = memcpy(*(&$0), struct netconfig, SIZEOF_STRUCT_NETCONFIG)
[2] *OUT = *((byte*)&main::a)
[3] *(&main::b) = memset(struct netconfig, SIZEOF_STRUCT_NETCONFIG)
to:main::@return
main::@return: scope:[main] from main
[4] return
to:@return

291
src/test/ref/struct-46.log Normal file

@ -0,0 +1,291 @@
Fixing struct type size struct netconfig to 96
Fixing struct type size struct netconfig to 96
Fixing struct type size struct netconfig to 96
Fixing struct type SIZE_OF struct netconfig to 96
Fixing struct type SIZE_OF struct netconfig to 96
Inlined call call __init
Removing C-classic struct-unwound assignment main::x = struct-unwound {*(&main::x)}
Removing C-classic struct-unwound assignment main::a = struct-unwound {*(&main::a)}
Removing C-classic struct-unwound assignment main::b = struct-unwound {*(&main::b)}
CONTROL FLOW GRAPH SSA
void main()
main: scope:[main] from __start::@1
*(&main::x) = memset(struct other, SIZEOF_STRUCT_OTHER)
*(&main::a) = memcpy(*(&$0), struct netconfig, SIZEOF_STRUCT_NETCONFIG)
main::$0 = OUT + 0
*main::$0 = ((byte*)&main::a+OFFSET_STRUCT_NETCONFIG_SSID)[0]
*(&main::b) = memset(struct netconfig, SIZEOF_STRUCT_NETCONFIG)
to:main::@return
main::@return: scope:[main] from main
return
to:@return
void __start()
__start: scope:[__start] from
to:__start::__init1
__start::__init1: scope:[__start] from __start
to:__start::@1
__start::@1: scope:[__start] from __start::__init1
call main
to:__start::@2
__start::@2: scope:[__start] from __start::@1
to:__start::@return
__start::@return: scope:[__start] from __start::@2
return
to:@return
SYMBOL TABLE SSA
constant struct netconfig $0 = { ssid: "123", password: "abc" }
constant byte OFFSET_STRUCT_NETCONFIG_SSID = 0
constant const byte* OUT = (byte*)$8000
constant byte SIZEOF_STRUCT_NETCONFIG = $60
constant byte SIZEOF_STRUCT_OTHER = 2
void __start()
void main()
const byte*~ main::$0
struct netconfig main::a loadstore
struct netconfig main::b loadstore
struct other main::x loadstore
Adding number conversion cast (unumber) 0 in main::$0 = OUT + 0
Adding number conversion cast (unumber) 0 in *main::$0 = ((byte*)&main::a+OFFSET_STRUCT_NETCONFIG_SSID)[0]
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (byte*) 32768
Simplifying constant integer cast 0
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Constant right-side identified [2] main::$0 = OUT + 0
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant main::$0 = OUT+0
Successful SSA optimization Pass2ConstantIdentification
Simplifying expression containing zero OUT in
Simplifying expression containing zero (byte*)&main::a+OFFSET_STRUCT_NETCONFIG_SSID in [3] *main::$0 = ((byte*)&main::a+OFFSET_STRUCT_NETCONFIG_SSID)[0]
Simplifying expression containing zero (byte*)&main::a in [3] *main::$0 = *((byte*)&main::a+OFFSET_STRUCT_NETCONFIG_SSID)
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused constant OFFSET_STRUCT_NETCONFIG_SSID
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::__init1
Removing unused procedure block __start::@1
Removing unused procedure block __start::@2
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Constant inlined main::$0 = OUT
Successful SSA optimization Pass2ConstantInlining
Finalized unsigned number type (byte) $20
Finalized unsigned number type (byte) $20
Finalized unsigned number type (byte) $40
Finalized unsigned number type (byte) $40
Successful SSA optimization PassNFinalizeNumberTypeConversions
CALL GRAPH
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] *(&main::x) = memset(struct other, SIZEOF_STRUCT_OTHER)
[1] *(&main::a) = memcpy(*(&$0), struct netconfig, SIZEOF_STRUCT_NETCONFIG)
[2] *OUT = *((byte*)&main::a)
[3] *(&main::b) = memset(struct netconfig, SIZEOF_STRUCT_NETCONFIG)
to:main::@return
main::@return: scope:[main] from main
[4] return
to:@return
VARIABLE REGISTER WEIGHTS
void main()
struct netconfig main::a loadstore
struct netconfig main::b loadstore
struct other main::x loadstore
Initial phi equivalence classes
Added variable main::x to live range equivalence class [ main::x ]
Added variable main::a to live range equivalence class [ main::a ]
Added variable main::b to live range equivalence class [ main::b ]
Complete equivalence classes
[ main::x ]
[ main::a ]
[ main::b ]
Allocated mem[2] [ main::x ]
Allocated mem[96] [ main::a ]
Allocated mem[96] [ main::b ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *(&main::x) = memset(struct other, SIZEOF_STRUCT_OTHER) [ main::a main::b ] ( [ main::a main::b ] { } ) always clobbers reg byte a reg byte y
Statement [1] *(&main::a) = memcpy(*(&$0), struct netconfig, SIZEOF_STRUCT_NETCONFIG) [ main::a main::b ] ( [ main::a main::b ] { } ) always clobbers reg byte a reg byte y
Statement [2] *OUT = *((byte*)&main::a) [ main::b ] ( [ main::b ] { } ) always clobbers reg byte a
Statement [3] *(&main::b) = memset(struct netconfig, SIZEOF_STRUCT_NETCONFIG) [ ] ( [ ] { } ) always clobbers reg byte a reg byte y
Potential registers mem[2] [ main::x ] : mem[2] ,
Potential registers mem[96] [ main::a ] : mem[96] ,
Potential registers mem[96] [ main::b ] : mem[96] ,
REGISTER UPLIFT SCOPES
Uplift Scope [netconfig]
Uplift Scope [other]
Uplift Scope [main] 0: mem[2] [ main::x ] 0: mem[96] [ main::a ] 0: mem[96] [ main::b ]
Uplift Scope []
Uplifting [netconfig] best 59 combination
Uplifting [other] best 59 combination
Uplifting [main] best 59 combination mem[2] [ main::x ] mem[96] [ main::a ] mem[96] [ main::b ]
Uplifting [] best 59 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// https://gitlab.com/camelot/kickc/-/issues/587
// Creating variable instances of structs with array members fails to compile
// Upstart
// Commodore 64 PRG executable file
.file [name="struct-46.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.const SIZEOF_STRUCT_OTHER = 2
.const SIZEOF_STRUCT_NETCONFIG = $60
.label OUT = $8000
.segment Code
// main
main: {
// [0] *(&main::x) = memset(struct other, SIZEOF_STRUCT_OTHER) -- _deref_pssc1=_memset_vbuc2
ldy #SIZEOF_STRUCT_OTHER
lda #0
!:
dey
sta x,y
bne !-
// [1] *(&main::a) = memcpy(*(&$0), struct netconfig, SIZEOF_STRUCT_NETCONFIG) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_NETCONFIG
!:
lda __0-1,y
sta a-1,y
dey
bne !-
// [2] *OUT = *((byte*)&main::a) -- _deref_pbuc1=_deref_pbuc2
lda a
sta OUT
// [3] *(&main::b) = memset(struct netconfig, SIZEOF_STRUCT_NETCONFIG) -- _deref_pssc1=_memset_vbuc2
ldy #SIZEOF_STRUCT_NETCONFIG
lda #0
!:
dey
sta b,y
bne !-
jmp __breturn
// main::@return
__breturn:
// [4] return
rts
.segment Data
x: .fill SIZEOF_STRUCT_OTHER, 0
a: .fill SIZEOF_STRUCT_NETCONFIG, 0
b: .fill SIZEOF_STRUCT_NETCONFIG, 0
}
// File Data
__0: .text "123"
.byte 0
.fill $1c, 0
.text "abc"
.byte 0
.fill $3c, 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
constant struct netconfig $0 = { ssid: "123", password: "abc" }
constant const byte* OUT = (byte*) 32768
constant byte SIZEOF_STRUCT_NETCONFIG = $60
constant byte SIZEOF_STRUCT_OTHER = 2
void main()
struct netconfig main::a loadstore mem[96]
struct netconfig main::b loadstore mem[96]
struct other main::x loadstore mem[2]
mem[2] [ main::x ]
mem[96] [ main::a ]
mem[96] [ main::b ]
FINAL ASSEMBLER
Score: 56
// File Comments
// https://gitlab.com/camelot/kickc/-/issues/587
// Creating variable instances of structs with array members fails to compile
// Upstart
// Commodore 64 PRG executable file
.file [name="struct-46.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.const SIZEOF_STRUCT_OTHER = 2
.const SIZEOF_STRUCT_NETCONFIG = $60
.label OUT = $8000
.segment Code
// main
main: {
// Other x
// [0] *(&main::x) = memset(struct other, SIZEOF_STRUCT_OTHER) -- _deref_pssc1=_memset_vbuc2
ldy #SIZEOF_STRUCT_OTHER
lda #0
!:
dey
sta x,y
bne !-
// NetConfig a = {"123", "abc"}
// [1] *(&main::a) = memcpy(*(&$0), struct netconfig, SIZEOF_STRUCT_NETCONFIG) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
ldy #SIZEOF_STRUCT_NETCONFIG
!:
lda __0-1,y
sta a-1,y
dey
bne !-
// *(OUT + 0) = a.ssid[0]
// [2] *OUT = *((byte*)&main::a) -- _deref_pbuc1=_deref_pbuc2
lda a
sta OUT
// NetConfig b
// [3] *(&main::b) = memset(struct netconfig, SIZEOF_STRUCT_NETCONFIG) -- _deref_pssc1=_memset_vbuc2
ldy #SIZEOF_STRUCT_NETCONFIG
lda #0
!:
dey
sta b,y
bne !-
// main::@return
// }
// [4] return
rts
.segment Data
x: .fill SIZEOF_STRUCT_OTHER, 0
a: .fill SIZEOF_STRUCT_NETCONFIG, 0
b: .fill SIZEOF_STRUCT_NETCONFIG, 0
}
// File Data
__0: .text "123"
.byte 0
.fill $1c, 0
.text "abc"
.byte 0
.fill $3c, 0

@ -0,0 +1,12 @@
constant struct netconfig $0 = { ssid: "123", password: "abc" }
constant const byte* OUT = (byte*) 32768
constant byte SIZEOF_STRUCT_NETCONFIG = $60
constant byte SIZEOF_STRUCT_OTHER = 2
void main()
struct netconfig main::a loadstore mem[96]
struct netconfig main::b loadstore mem[96]
struct other main::x loadstore mem[2]
mem[2] [ main::x ]
mem[96] [ main::a ]
mem[96] [ main::b ]