From 98ee476b5b24117e526c64685100851e4299e794 Mon Sep 17 00:00:00 2001
From: jespergravgaard <jesper@balmangravgaard.dk>
Date: Sun, 2 Feb 2020 09:47:51 +0100
Subject: [PATCH] Added another struct test.

---
 .../dk/camelot64/kickc/test/TestPrograms.java |   5 +
 src/test/kc/struct-32.kc                      |   2 +-
 src/test/kc/struct-36.kc                      |  16 +
 src/test/ref/struct-32.asm                    |   2 +-
 src/test/ref/struct-32.log                    |   6 +-
 src/test/ref/struct-36.asm                    |  18 ++
 src/test/ref/struct-36.cfg                    |  19 ++
 src/test/ref/struct-36.log                    | 301 ++++++++++++++++++
 src/test/ref/struct-36.sym                    |  12 +
 9 files changed, 376 insertions(+), 5 deletions(-)
 create mode 100644 src/test/kc/struct-36.kc
 create mode 100644 src/test/ref/struct-36.asm
 create mode 100644 src/test/ref/struct-36.cfg
 create mode 100644 src/test/ref/struct-36.log
 create mode 100644 src/test/ref/struct-36.sym

diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java
index 32637d08b..fa20d95a3 100644
--- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java
+++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java
@@ -1153,6 +1153,11 @@ public class TestPrograms {
       assertError("struct-err-0", "Unknown struct type");
    }
 
+   @Test
+   public void testStruct36() throws IOException, URISyntaxException {
+      compileAndCompare("struct-36");
+   }
+
    @Test
    public void testStruct35() throws IOException, URISyntaxException {
       compileAndCompare("struct-35");
diff --git a/src/test/kc/struct-32.kc b/src/test/kc/struct-32.kc
index 839a9c00c..df0883eec 100644
--- a/src/test/kc/struct-32.kc
+++ b/src/test/kc/struct-32.kc
@@ -1,4 +1,4 @@
-// Minimal struct with C-Standard behavior - member is array, copy assignment
+// Minimal struct with C-Standard behavior - copy assignment
 
 struct Point {
     char x;
diff --git a/src/test/kc/struct-36.kc b/src/test/kc/struct-36.kc
new file mode 100644
index 000000000..f9687871d
--- /dev/null
+++ b/src/test/kc/struct-36.kc
@@ -0,0 +1,16 @@
+// Minimal struct with C-Standard behavior - global main-mem struct should be initialized in data, not code
+
+struct Point {
+    char x;
+    char[2] initials;
+};
+
+__mem __ma struct Point point1 = { 2, "jg" };
+
+const char* SCREEN = 0x0400;
+
+void main() {
+    SCREEN[0] = point1.x;
+    SCREEN[1] = point1.initials[0];
+    SCREEN[2] = point1.initials[1];
+}
\ No newline at end of file
diff --git a/src/test/ref/struct-32.asm b/src/test/ref/struct-32.asm
index 637c52e8e..82c352534 100644
--- a/src/test/ref/struct-32.asm
+++ b/src/test/ref/struct-32.asm
@@ -1,4 +1,4 @@
-// Minimal struct with C-Standard behavior - member is array, copy assignment
+// Minimal struct with C-Standard behavior - copy assignment
 .pc = $801 "Basic"
 :BasicUpstart(main)
 .pc = $80d "Program"
diff --git a/src/test/ref/struct-32.log b/src/test/ref/struct-32.log
index 1273d4a8e..bdb4a8b16 100644
--- a/src/test/ref/struct-32.log
+++ b/src/test/ref/struct-32.log
@@ -129,7 +129,7 @@ Allocated zp[2]:4 [ main::point2 ]
 INITIAL ASM
 Target platform is c64basic / MOS6502X
   // File Comments
-// Minimal struct with C-Standard behavior - member is array, copy assignment
+// Minimal struct with C-Standard behavior - copy assignment
   // Upstart
 .pc = $801 "Basic"
 :BasicUpstart(__bbegin)
@@ -211,7 +211,7 @@ Uplifting [] best 76 combination
 
 ASSEMBLER BEFORE OPTIMIZATION
   // File Comments
-// Minimal struct with C-Standard behavior - member is array, copy assignment
+// Minimal struct with C-Standard behavior - copy assignment
   // Upstart
 .pc = $801 "Basic"
 :BasicUpstart(__bbegin)
@@ -313,7 +313,7 @@ FINAL ASSEMBLER
 Score: 61
 
   // File Comments
-// Minimal struct with C-Standard behavior - member is array, copy assignment
+// Minimal struct with C-Standard behavior - copy assignment
   // Upstart
 .pc = $801 "Basic"
 :BasicUpstart(main)
diff --git a/src/test/ref/struct-36.asm b/src/test/ref/struct-36.asm
new file mode 100644
index 000000000..36e27b5d6
--- /dev/null
+++ b/src/test/ref/struct-36.asm
@@ -0,0 +1,18 @@
+// Minimal struct with C-Standard behavior - global main-mem struct should be initialized in data, not code
+.pc = $801 "Basic"
+:BasicUpstart(main)
+.pc = $80d "Program"
+  .label SCREEN = $400
+  .const OFFSET_STRUCT_POINT_INITIALS = 1
+main: {
+    lda point1
+    sta SCREEN
+    lda point1+OFFSET_STRUCT_POINT_INITIALS
+    sta SCREEN+1
+    lda point1+OFFSET_STRUCT_POINT_INITIALS+1
+    sta SCREEN+2
+    rts
+}
+  point1: .byte 2
+  .text "jg"
+  .byte 0
diff --git a/src/test/ref/struct-36.cfg b/src/test/ref/struct-36.cfg
new file mode 100644
index 000000000..d808df9be
--- /dev/null
+++ b/src/test/ref/struct-36.cfg
@@ -0,0 +1,19 @@
+@begin: scope:[]  from
+  [0] phi()
+  to:@1
+@1: scope:[]  from @begin
+  [1] phi()
+  [2] call main 
+  to:@end
+@end: scope:[]  from @1
+  [3] phi()
+
+(void()) main()
+main: scope:[main]  from @1
+  [4] *((const byte*) SCREEN) ← *((byte*)&(struct Point) point1)
+  [5] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS)
+  [6] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1)
+  to:main::@return
+main::@return: scope:[main]  from main
+  [7] return 
+  to:@return
diff --git a/src/test/ref/struct-36.log b/src/test/ref/struct-36.log
new file mode 100644
index 000000000..1f98c2c13
--- /dev/null
+++ b/src/test/ref/struct-36.log
@@ -0,0 +1,301 @@
+Fixing struct type size struct Point to 3
+Fixing struct type SIZE_OF struct Point to 3
+Fixing struct type SIZE_OF struct Point to 3
+Replacing struct member reference (struct Point) point1.x with member unwinding reference *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X)
+Replacing struct member reference (struct Point) point1.initials with member unwinding reference (byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS
+Replacing struct member reference (struct Point) point1.initials with member unwinding reference (byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS
+
+CONTROL FLOW GRAPH SSA
+@begin: scope:[]  from
+  to:@1
+
+(void()) main()
+main: scope:[main]  from @1
+  *((const byte*) SCREEN + (number) 0) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X)
+  *((const byte*) SCREEN + (number) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0)
+  *((const byte*) SCREEN + (number) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1)
+  to:main::@return
+main::@return: scope:[main]  from main
+  return 
+  to:@return
+@1: scope:[]  from @begin
+  call main 
+  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_POINT_INITIALS = (byte) 1
+(const byte) OFFSET_STRUCT_POINT_X = (byte) 0
+(const byte*) Point::initials[(number) 2]  = { fill( 2, 0) }
+(byte) Point::x
+(const byte*) SCREEN = (byte*)(number) $400
+(void()) main()
+(label) main::@return
+(struct Point) point1 loadstore = { x: (byte) 2, initials: (string) "jg" }
+
+Adding number conversion cast (unumber) 0 in *((const byte*) SCREEN + (number) 0) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X)
+Adding number conversion cast (unumber) 0 in *((const byte*) SCREEN + (number) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0)
+Adding number conversion cast (unumber) 1 in *((const byte*) SCREEN + (number) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (unumber)(number) 0)
+Adding number conversion cast (unumber) 1 in *((const byte*) SCREEN + (number) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1)
+Adding number conversion cast (unumber) 2 in *((const byte*) SCREEN + (number) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (unumber)(number) 1)
+Successful SSA optimization PassNAddNumberTypeConversions
+Simplifying constant pointer cast (byte*) 1024
+Simplifying constant integer cast 0
+Simplifying constant integer cast 0
+Simplifying constant integer cast 1
+Simplifying constant integer cast 1
+Simplifying constant integer cast 2
+Successful SSA optimization PassNCastSimplification
+Finalized unsigned number type (byte) 0
+Finalized unsigned number type (byte) 0
+Finalized unsigned number type (byte) 1
+Finalized unsigned number type (byte) 1
+Finalized unsigned number type (byte) 2
+Successful SSA optimization PassNFinalizeNumberTypeConversions
+Simplifying expression containing zero (byte*)&point1 in [0] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_X)
+Simplifying expression containing zero SCREEN in [0] *((const byte*) SCREEN + (byte) 0) ← *((byte*)&(struct Point) point1)
+Simplifying expression containing zero (byte*)&point1+OFFSET_STRUCT_POINT_INITIALS in [1] *((const byte*) SCREEN + (byte) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (byte) 0)
+Successful SSA optimization PassNSimplifyExpressionWithZero
+Eliminating unused constant (const byte) OFFSET_STRUCT_POINT_X
+Successful SSA optimization PassNEliminateUnusedVars
+Consolidated array index constant in *(SCREEN+1)
+Consolidated array index constant in *((byte*)&point1+OFFSET_STRUCT_POINT_INITIALS+1)
+Consolidated array index constant in *(SCREEN+2)
+Successful SSA optimization Pass2ConstantAdditionElimination
+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
+CALL GRAPH
+Calls in [] to main:2 
+
+Created 0 initial phi equivalence classes
+Coalesced down to 0 phi equivalence classes
+Culled Empty Block (label) @2
+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()
+
+(void()) main()
+main: scope:[main]  from @1
+  [4] *((const byte*) SCREEN) ← *((byte*)&(struct Point) point1)
+  [5] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS)
+  [6] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1)
+  to:main::@return
+main::@return: scope:[main]  from main
+  [7] return 
+  to:@return
+
+
+VARIABLE REGISTER WEIGHTS
+(byte) Point::x
+(void()) main()
+(struct Point) point1 loadstore = { x: (byte) 2, initials: (string) "jg" }
+
+Initial phi equivalence classes
+Added variable point1 to live range equivalence class [ point1 ]
+Complete equivalence classes
+[ point1 ]
+Allocated mem[3] [ point1 ]
+
+INITIAL ASM
+Target platform is c64basic / MOS6502X
+  // File Comments
+// Minimal struct with C-Standard behavior - global main-mem struct should be initialized in data, not code
+  // Upstart
+.pc = $801 "Basic"
+:BasicUpstart(__bbegin)
+.pc = $80d "Program"
+  // Global Constants & labels
+  .label SCREEN = $400
+  .const OFFSET_STRUCT_POINT_INITIALS = 1
+  // @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: {
+    // [4] *((const byte*) SCREEN) ← *((byte*)&(struct Point) point1) -- _deref_pbuc1=_deref_pbuc2 
+    lda point1
+    sta SCREEN
+    // [5] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) -- _deref_pbuc1=_deref_pbuc2 
+    lda point1+OFFSET_STRUCT_POINT_INITIALS
+    sta SCREEN+1
+    // [6] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) -- _deref_pbuc1=_deref_pbuc2 
+    lda point1+OFFSET_STRUCT_POINT_INITIALS+1
+    sta SCREEN+2
+    jmp __breturn
+    // main::@return
+  __breturn:
+    // [7] return 
+    rts
+}
+  // File Data
+  point1: .byte 2
+  .text "jg"
+  .byte 0
+
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [4] *((const byte*) SCREEN) ← *((byte*)&(struct Point) point1) [ point1 ] ( main:2 [ point1 ] ) always clobbers reg byte a 
+Statement [5] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) [ point1 ] ( main:2 [ point1 ] ) always clobbers reg byte a 
+Statement [6] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) [ ] ( main:2 [ ] ) always clobbers reg byte a 
+Potential registers mem[3] [ point1 ] : mem[3] , 
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [Point] 
+Uplift Scope [main] 
+Uplift Scope [] 0: mem[3] [ point1 ] 
+
+Uplifting [Point] best 45 combination 
+Uplifting [main] best 45 combination 
+Uplifting [] best 45 combination mem[3] [ point1 ] 
+
+ASSEMBLER BEFORE OPTIMIZATION
+  // File Comments
+// Minimal struct with C-Standard behavior - global main-mem struct should be initialized in data, not code
+  // Upstart
+.pc = $801 "Basic"
+:BasicUpstart(__bbegin)
+.pc = $80d "Program"
+  // Global Constants & labels
+  .label SCREEN = $400
+  .const OFFSET_STRUCT_POINT_INITIALS = 1
+  // @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: {
+    // [4] *((const byte*) SCREEN) ← *((byte*)&(struct Point) point1) -- _deref_pbuc1=_deref_pbuc2 
+    lda point1
+    sta SCREEN
+    // [5] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) -- _deref_pbuc1=_deref_pbuc2 
+    lda point1+OFFSET_STRUCT_POINT_INITIALS
+    sta SCREEN+1
+    // [6] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) -- _deref_pbuc1=_deref_pbuc2 
+    lda point1+OFFSET_STRUCT_POINT_INITIALS+1
+    sta SCREEN+2
+    jmp __breturn
+    // main::@return
+  __breturn:
+    // [7] return 
+    rts
+}
+  // File Data
+  point1: .byte 2
+  .text "jg"
+  .byte 0
+
+ASSEMBLER OPTIMIZATIONS
+Removing instruction jmp __b1
+Removing instruction jmp __bend
+Removing instruction jmp __breturn
+Succesful ASM optimization Pass5NextJumpElimination
+Replacing label __bbegin with __b1
+Removing instruction __bbegin:
+Removing instruction __b1_from___bbegin:
+Removing instruction __bend_from___b1:
+Succesful ASM optimization Pass5RedundantLabelElimination
+Removing instruction __bend:
+Removing instruction __breturn:
+Succesful ASM optimization Pass5UnusedLabelElimination
+Updating BasicUpstart to call main directly
+Removing instruction jsr main
+Succesful ASM optimization Pass5SkipBegin
+Removing instruction __b1:
+Succesful ASM optimization Pass5UnusedLabelElimination
+
+FINAL SYMBOL TABLE
+(label) @1
+(label) @begin
+(label) @end
+(const byte) OFFSET_STRUCT_POINT_INITIALS = (byte) 1
+(const byte*) Point::initials[(number) 2]  = { fill( 2, 0) }
+(byte) Point::x
+(const byte*) SCREEN = (byte*) 1024
+(void()) main()
+(label) main::@return
+(struct Point) point1 loadstore mem[3] = { x: (byte) 2, initials: (string) "jg" }
+
+mem[3] [ point1 ]
+
+
+FINAL ASSEMBLER
+Score: 30
+
+  // File Comments
+// Minimal struct with C-Standard behavior - global main-mem struct should be initialized in data, not code
+  // Upstart
+.pc = $801 "Basic"
+:BasicUpstart(main)
+.pc = $80d "Program"
+  // Global Constants & labels
+  .label SCREEN = $400
+  .const OFFSET_STRUCT_POINT_INITIALS = 1
+  // @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: {
+    // SCREEN[0] = point1.x
+    // [4] *((const byte*) SCREEN) ← *((byte*)&(struct Point) point1) -- _deref_pbuc1=_deref_pbuc2 
+    lda point1
+    sta SCREEN
+    // SCREEN[1] = point1.initials[0]
+    // [5] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) -- _deref_pbuc1=_deref_pbuc2 
+    lda point1+OFFSET_STRUCT_POINT_INITIALS
+    sta SCREEN+1
+    // SCREEN[2] = point1.initials[1]
+    // [6] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) -- _deref_pbuc1=_deref_pbuc2 
+    lda point1+OFFSET_STRUCT_POINT_INITIALS+1
+    sta SCREEN+2
+    // main::@return
+    // }
+    // [7] return 
+    rts
+}
+  // File Data
+  point1: .byte 2
+  .text "jg"
+  .byte 0
+
diff --git a/src/test/ref/struct-36.sym b/src/test/ref/struct-36.sym
new file mode 100644
index 000000000..4b57a0bbc
--- /dev/null
+++ b/src/test/ref/struct-36.sym
@@ -0,0 +1,12 @@
+(label) @1
+(label) @begin
+(label) @end
+(const byte) OFFSET_STRUCT_POINT_INITIALS = (byte) 1
+(const byte*) Point::initials[(number) 2]  = { fill( 2, 0) }
+(byte) Point::x
+(const byte*) SCREEN = (byte*) 1024
+(void()) main()
+(label) main::@return
+(struct Point) point1 loadstore mem[3] = { x: (byte) 2, initials: (string) "jg" }
+
+mem[3] [ point1 ]