1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-26 12:49:21 +00:00

Fixed missing fragment. Closes #435

This commit is contained in:
jespergravgaard 2020-05-11 20:55:29 +02:00
parent b8d0e50fbb
commit 362ec9bb0b
7 changed files with 527 additions and 0 deletions

View File

@ -0,0 +1,7 @@
lda #<{c2}
clc
adc {c1}
sta {c1}
lda #>{c2}
adc {c1}+1
sta {c1}+1

View File

@ -42,6 +42,11 @@ public class TestPrograms {
public TestPrograms() {
}
@Test
public void testStructPointerInts() throws IOException, URISyntaxException {
compileAndCompare("struct-pointer-ints.c");
}
@Test
public void testPolygon() throws IOException, URISyntaxException {
compileAndCompare("complex/polygon/polygon.c");

View File

@ -0,0 +1,19 @@
// Demonstrates missing fragment _deref_pwuc1=_deref_pwuc1_plus_vwuc2
// https://gitlab.com/camelot/kickc/-/issues/435 reported by G.B.
typedef struct myStruct
{
unsigned int a, b;
} myStruct;
void update(myStruct *s, unsigned int size)
{
s->a += size;
}
int main(void)
{
myStruct s;
update(&s, 1000);
return 0;
}

View File

@ -0,0 +1,34 @@
// Demonstrates missing fragment _deref_pwuc1=_deref_pwuc1_plus_vwuc2
// https://gitlab.com/camelot/kickc/-/issues/435 reported by G.B.
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const SIZEOF_STRUCT_MYSTRUCT = 4
main: {
.label s = 2
// s
ldy #SIZEOF_STRUCT_MYSTRUCT
lda #0
!:
dey
sta s,y
bne !-
// update(&s, 1000)
jsr update
// }
rts
}
update: {
.const size = $3e8
.label s = main.s
// s->a += size
lda #<size
clc
adc.z s
sta.z s
lda #>size
adc.z s+1
sta.z s+1
// }
rts
}

View File

@ -0,0 +1,26 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
(signed word()) main()
main: scope:[main] from @1
[4] *(&(struct myStruct) main::s) ← memset(struct myStruct, (const byte) SIZEOF_STRUCT_MYSTRUCT)
[5] call update
to:main::@return
main::@return: scope:[main] from main
[6] return
to:@return
(void()) update((struct myStruct*) update::s , (word) update::size)
update: scope:[update] from main
[7] *((word*)(const struct myStruct*) update::s#0) ← *((word*)(const struct myStruct*) update::s#0) + (const word) update::size#0
to:update::@return
update::@return: scope:[update] from update
[8] return
to:@return

View File

@ -0,0 +1,418 @@
Setting struct to load/store in variable affected by address-of (void~) main::$0 ← call update &(struct myStruct) main::s (number) $3e8
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
(void()) update((struct myStruct*) update::s , (word) update::size)
update: scope:[update] from main
(word) update::size#1 ← phi( main/(word) update::size#0 )
(struct myStruct*) update::s#1 ← phi( main/(struct myStruct*) update::s#0 )
(word*~) update::$2 ← (word*)(struct myStruct*) update::s#1
(word*~) update::$0 ← (word*~) update::$2 + (const byte) OFFSET_STRUCT_MYSTRUCT_A
(word*~) update::$3 ← (word*)(struct myStruct*) update::s#1
(word*~) update::$1 ← (word*~) update::$3 + (const byte) OFFSET_STRUCT_MYSTRUCT_A
*((word*~) update::$1) ← *((word*~) update::$0) + (word) update::size#1
to:update::@return
update::@return: scope:[update] from update
return
to:@return
(signed word()) main()
main: scope:[main] from @1
*(&(struct myStruct) main::s) ← memset(struct myStruct, (const byte) SIZEOF_STRUCT_MYSTRUCT)
(struct myStruct) main::s ← struct-unwound {*(&(struct myStruct) main::s)}
(struct myStruct*) update::s#0 ← &(struct myStruct) main::s
(word) update::size#0 ← (number) $3e8
call update
to:main::@1
main::@1: scope:[main] from main
(signed word) main::return#0 ← (number) 0
to:main::@return
main::@return: scope:[main] from main::@1
(signed word) main::return#3 ← phi( main::@1/(signed word) main::return#0 )
(signed word) main::return#1 ← (signed word) main::return#3
return
to:@return
@1: scope:[] from @begin
call main
(signed word) main::return#2 ← (signed word) main::return#1
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_MYSTRUCT_A = (byte) 0
(const byte) SIZEOF_STRUCT_MYSTRUCT = (byte) 4
(signed word()) main()
(label) main::@1
(label) main::@return
(signed word) main::return
(signed word) main::return#0
(signed word) main::return#1
(signed word) main::return#2
(signed word) main::return#3
(struct myStruct) main::s loadstore
(word) myStruct::a
(word) myStruct::b
(void()) update((struct myStruct*) update::s , (word) update::size)
(word*~) update::$0
(word*~) update::$1
(word*~) update::$2
(word*~) update::$3
(label) update::@return
(struct myStruct*) update::s
(struct myStruct*) update::s#0
(struct myStruct*) update::s#1
(word) update::size
(word) update::size#0
(word) update::size#1
Adding number conversion cast (unumber) $3e8 in (word) update::size#0 ← (number) $3e8
Adding number conversion cast (snumber) 0 in (signed word) main::return#0 ← (number) 0
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (word) update::size#0 ← (unumber)(number) $3e8
Inlining cast (signed word) main::return#0 ← (snumber)(number) 0
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast $3e8
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (word) $3e8
Finalized signed number type (signed byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias main::return#0 = main::return#3 main::return#1
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (struct myStruct*) update::s#1 (struct myStruct*) update::s#0
Identical Phi Values (word) update::size#1 (word) update::size#0
Successful SSA optimization Pass2IdenticalPhiElimination
Removing C-classic struct-unwound assignment [8] (struct myStruct) main::s ← struct-unwound {*(&(struct myStruct) main::s)}
Constant (const struct myStruct*) update::s#0 = &main::s
Constant (const word) update::size#0 = $3e8
Constant (const signed word) main::return#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Constant (const word*) update::$2 = (word*)update::s#0
Constant (const word*) update::$3 = (word*)update::s#0
Constant (const signed word) main::return#2 = main::return#0
Successful SSA optimization Pass2ConstantIdentification
Converting *(pointer+n) to pointer[n] [5] *((word*~) update::$1) ← *((word*~) update::$0) + (const word) update::size#0 -- *(update::$2 + OFFSET_STRUCT_MYSTRUCT_A)
Converting *(pointer+n) to pointer[n] [5] *((word*~) update::$1) ← *((const word*) update::$2 + (const byte) OFFSET_STRUCT_MYSTRUCT_A) + (const word) update::size#0 -- *(update::$3 + OFFSET_STRUCT_MYSTRUCT_A)
Successful SSA optimization Pass2InlineDerefIdx
Simplifying expression containing zero update::$2 in [2] (word*~) update::$0 ← (const word*) update::$2 + (const byte) OFFSET_STRUCT_MYSTRUCT_A
Simplifying expression containing zero update::$3 in [4] (word*~) update::$1 ← (const word*) update::$3 + (const byte) OFFSET_STRUCT_MYSTRUCT_A
Simplifying expression containing zero update::$2 in [5] *((const word*) update::$3 + (const byte) OFFSET_STRUCT_MYSTRUCT_A) ← *((const word*) update::$2 + (const byte) OFFSET_STRUCT_MYSTRUCT_A) + (const word) update::size#0
Simplifying expression containing zero update::$3 in [5] *((const word*) update::$3 + (const byte) OFFSET_STRUCT_MYSTRUCT_A) ← *((const word*) update::$2) + (const word) update::size#0
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable (word*~) update::$0 and assignment [0] (word*~) update::$0 ← (const word*) update::$2
Eliminating unused variable (word*~) update::$1 and assignment [1] (word*~) update::$1 ← (const word*) update::$3
Eliminating unused constant (const signed word) main::return#2
Eliminating unused constant (const byte) OFFSET_STRUCT_MYSTRUCT_A
Successful SSA optimization PassNEliminateUnusedVars
Eliminating unused constant (const signed word) main::return#0
Successful SSA optimization PassNEliminateUnusedVars
Constant inlined update::$2 = (word*)(const struct myStruct*) update::s#0
Constant inlined update::$3 = (word*)(const struct myStruct*) update::s#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 @end
Adding NOP phi() at start of main::@1
CALL GRAPH
Calls in [] to main:2
Calls in [main] to update:6
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
Culled Empty Block (label) @2
Culled Empty Block (label) main::@1
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
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()
(signed word()) main()
main: scope:[main] from @1
[4] *(&(struct myStruct) main::s) ← memset(struct myStruct, (const byte) SIZEOF_STRUCT_MYSTRUCT)
[5] call update
to:main::@return
main::@return: scope:[main] from main
[6] return
to:@return
(void()) update((struct myStruct*) update::s , (word) update::size)
update: scope:[update] from main
[7] *((word*)(const struct myStruct*) update::s#0) ← *((word*)(const struct myStruct*) update::s#0) + (const word) update::size#0
to:update::@return
update::@return: scope:[update] from update
[8] return
to:@return
VARIABLE REGISTER WEIGHTS
(signed word()) main()
(signed word) main::return
(struct myStruct) main::s loadstore
(word) myStruct::a
(word) myStruct::b
(void()) update((struct myStruct*) update::s , (word) update::size)
(struct myStruct*) update::s
(word) update::size
Initial phi equivalence classes
Added variable main::s to live range equivalence class [ main::s ]
Complete equivalence classes
[ main::s ]
Allocated zp[4]:2 [ main::s ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Demonstrates missing fragment _deref_pwuc1=_deref_pwuc1_plus_vwuc2
// https://gitlab.com/camelot/kickc/-/issues/435 reported by G.B.
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_MYSTRUCT = 4
// @begin
__bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
.label s = 2
// [4] *(&(struct myStruct) main::s) ← memset(struct myStruct, (const byte) SIZEOF_STRUCT_MYSTRUCT) -- _deref_pssc1=_memset_vbuc2
ldy #SIZEOF_STRUCT_MYSTRUCT
lda #0
!:
dey
sta s,y
bne !-
// [5] call update
jsr update
jmp __breturn
// main::@return
__breturn:
// [6] return
rts
}
// update
update: {
.const size = $3e8
.label s = main.s
// [7] *((word*)(const struct myStruct*) update::s#0) ← *((word*)(const struct myStruct*) update::s#0) + (const word) update::size#0 -- _deref_pwuc1=_deref_pwuc1_plus_vwuc2
lda #<size
clc
adc.z s
sta.z s
lda #>size
adc.z s+1
sta.z s+1
jmp __breturn
// update::@return
__breturn:
// [8] return
rts
}
// File Data
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] *(&(struct myStruct) main::s) ← memset(struct myStruct, (const byte) SIZEOF_STRUCT_MYSTRUCT) [ ] ( main:2 [ ] { } ) always clobbers reg byte a reg byte y
Statement [7] *((word*)(const struct myStruct*) update::s#0) ← *((word*)(const struct myStruct*) update::s#0) + (const word) update::size#0 [ ] ( main:2::update:5 [ ] { } ) always clobbers reg byte a
Potential registers zp[4]:2 [ main::s ] : zp[4]:2 ,
REGISTER UPLIFT SCOPES
Uplift Scope [myStruct]
Uplift Scope [update]
Uplift Scope [main] 0: zp[4]:2 [ main::s ]
Uplift Scope []
Uplifting [myStruct] best 67 combination
Uplifting [update] best 67 combination
Uplifting [main] best 67 combination zp[4]:2 [ main::s ]
Uplifting [] best 67 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Demonstrates missing fragment _deref_pwuc1=_deref_pwuc1_plus_vwuc2
// https://gitlab.com/camelot/kickc/-/issues/435 reported by G.B.
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_MYSTRUCT = 4
// @begin
__bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
.label s = 2
// [4] *(&(struct myStruct) main::s) ← memset(struct myStruct, (const byte) SIZEOF_STRUCT_MYSTRUCT) -- _deref_pssc1=_memset_vbuc2
ldy #SIZEOF_STRUCT_MYSTRUCT
lda #0
!:
dey
sta s,y
bne !-
// [5] call update
jsr update
jmp __breturn
// main::@return
__breturn:
// [6] return
rts
}
// update
update: {
.const size = $3e8
.label s = main.s
// [7] *((word*)(const struct myStruct*) update::s#0) ← *((word*)(const struct myStruct*) update::s#0) + (const word) update::size#0 -- _deref_pwuc1=_deref_pwuc1_plus_vwuc2
lda #<size
clc
adc.z s
sta.z s
lda #>size
adc.z s+1
sta.z s+1
jmp __breturn
// update::@return
__breturn:
// [8] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __bend
Removing instruction jmp __breturn
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __b1_from___bbegin:
Removing instruction __b1:
Removing instruction __bend_from___b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __bbegin:
Removing instruction __bend:
Removing instruction __breturn:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(const byte) SIZEOF_STRUCT_MYSTRUCT = (byte) 4
(signed word()) main()
(label) main::@return
(signed word) main::return
(struct myStruct) main::s loadstore zp[4]:2
(word) myStruct::a
(word) myStruct::b
(void()) update((struct myStruct*) update::s , (word) update::size)
(label) update::@return
(struct myStruct*) update::s
(const struct myStruct*) update::s#0 s = &(struct myStruct) main::s
(word) update::size
(const word) update::size#0 size = (word) $3e8
zp[4]:2 [ main::s ]
FINAL ASSEMBLER
Score: 49
// File Comments
// Demonstrates missing fragment _deref_pwuc1=_deref_pwuc1_plus_vwuc2
// https://gitlab.com/camelot/kickc/-/issues/435 reported by G.B.
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_MYSTRUCT = 4
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
.label s = 2
// s
// [4] *(&(struct myStruct) main::s) ← memset(struct myStruct, (const byte) SIZEOF_STRUCT_MYSTRUCT) -- _deref_pssc1=_memset_vbuc2
ldy #SIZEOF_STRUCT_MYSTRUCT
lda #0
!:
dey
sta s,y
bne !-
// update(&s, 1000)
// [5] call update
jsr update
// main::@return
// }
// [6] return
rts
}
// update
update: {
.const size = $3e8
.label s = main.s
// s->a += size
// [7] *((word*)(const struct myStruct*) update::s#0) ← *((word*)(const struct myStruct*) update::s#0) + (const word) update::size#0 -- _deref_pwuc1=_deref_pwuc1_plus_vwuc2
lda #<size
clc
adc.z s
sta.z s
lda #>size
adc.z s+1
sta.z s+1
// update::@return
// }
// [8] return
rts
}
// File Data

View File

@ -0,0 +1,18 @@
(label) @1
(label) @begin
(label) @end
(const byte) SIZEOF_STRUCT_MYSTRUCT = (byte) 4
(signed word()) main()
(label) main::@return
(signed word) main::return
(struct myStruct) main::s loadstore zp[4]:2
(word) myStruct::a
(word) myStruct::b
(void()) update((struct myStruct*) update::s , (word) update::size)
(label) update::@return
(struct myStruct*) update::s
(const struct myStruct*) update::s#0 s = &(struct myStruct) main::s
(word) update::size
(const word) update::size#0 size = (word) $3e8
zp[4]:2 [ main::s ]