From b72b2f591080de620bde1a49b379111eceef828f Mon Sep 17 00:00:00 2001
From: jespergravgaard <jesper@balmangravgaard.dk>
Date: Sat, 28 Dec 2019 01:59:26 +0100
Subject: [PATCH] Fixing struct size for structs containing arrays.

---
 .../kickc/model/operators/OperatorSizeOf.java |  16 +
 .../Pass0GenerateStatementSequence.java       |   6 +-
 .../kickc/passes/Pass1StructTypeSizeFix.java  |  34 +-
 .../kickc/passes/Pass1UnwindStructValues.java |  29 +-
 .../dk/camelot64/kickc/test/TestPrograms.java |  15 +
 src/test/kc/struct-24.kc                      |  18 +
 src/test/kc/struct-25.kc                      |  12 +
 src/test/kc/struct-26.kc                      |  19 +
 src/test/ref/struct-24.asm                    |  24 ++
 src/test/ref/struct-24.cfg                    |  23 ++
 src/test/ref/struct-24.log                    | 387 ++++++++++++++++++
 src/test/ref/struct-24.sym                    |  12 +
 src/test/ref/struct-25.asm                    |  11 +
 src/test/ref/struct-25.cfg                    |  17 +
 src/test/ref/struct-25.log                    | 232 +++++++++++
 src/test/ref/struct-25.sym                    |  10 +
 src/test/ref/struct-ptr-23.log                |   2 +
 src/test/ref/struct-ptr-31.log                |   2 +
 src/test/ref/struct-ptr-32.log                |   2 +
 src/test/ref/struct-ptr-33.log                |   2 +
 20 files changed, 853 insertions(+), 20 deletions(-)
 create mode 100644 src/test/kc/struct-24.kc
 create mode 100644 src/test/kc/struct-25.kc
 create mode 100644 src/test/kc/struct-26.kc
 create mode 100644 src/test/ref/struct-24.asm
 create mode 100644 src/test/ref/struct-24.cfg
 create mode 100644 src/test/ref/struct-24.log
 create mode 100644 src/test/ref/struct-24.sym
 create mode 100644 src/test/ref/struct-25.asm
 create mode 100644 src/test/ref/struct-25.cfg
 create mode 100644 src/test/ref/struct-25.log
 create mode 100644 src/test/ref/struct-25.sym

diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorSizeOf.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorSizeOf.java
index 7e651c5eb..3a4a58e29 100644
--- a/src/main/java/dk/camelot64/kickc/model/operators/OperatorSizeOf.java
+++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorSizeOf.java
@@ -48,6 +48,22 @@ public class OperatorSizeOf extends OperatorUnary {
       return typeSizeConstant.getConstantRef();
    }
 
+   /**
+    * Fix the size value of the constant variable if needed.
+    * Sizes for structs and other complex types is not known until late in Pass1, so they may need fixing.
+    * @param programScope The program scope (used for finding/adding the constant).
+    * @param type The type to get the variable for
+    */
+   public static void fixSizeOfConstantVar(ProgramScope programScope, SymbolType type) {
+      String typeConstName = getSizeofConstantName(type);
+      Variable typeSizeConstant = programScope.getConstant(typeConstName);
+      if(typeSizeConstant != null) {
+         // Constant found - update it
+         long typeSize = type.getSizeBytes();
+         typeSizeConstant.setInitValue(new ConstantInteger(typeSize&0xff, SymbolType.BYTE));
+      }
+   }
+
    /**
     * Get the name of the constant variable containing the size of a specific type
     *
diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java
index 7b7b1559b..afc04af4a 100644
--- a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java
+++ b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java
@@ -612,7 +612,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
    public Object visitDeclVariableInitKasm(KickCParser.DeclVariableInitKasmContext ctx) {
       String varName = ctx.NAME().getText();
       StatementSource statementSource = new StatementSource(ctx);
-      if(!(this.declVarType instanceof SymbolTypePointer) || declArraySpec==null) {
+      if(!(this.declVarType instanceof SymbolTypePointer) || declArraySpec == null) {
          throw new CompileError("KickAsm initializers only supported for arrays " + declVarType.getTypeName(), statementSource);
       }
       // Add KickAsm statement
@@ -1147,7 +1147,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
          if(rangeFirstValue instanceof ConstantInteger) ((ConstantInteger) rangeFirstValue).setType(varType);
          if(rangeLastValue instanceof ConstantInteger) ((ConstantInteger) rangeLastValue).setType(varType);
       }
-      boolean initialAssignment = (declVarType!=null);
+      boolean initialAssignment = (declVarType != null);
       Statement stmtInit = new StatementAssignment((LValue) lValue.getRef(), rangeFirstValue, initialAssignment, statementSource, Comment.NO_COMMENTS);
       sequence.addStatement(stmtInit);
       // Add label
@@ -1952,7 +1952,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
       sequence.addStatement(new StatementLabel(trueLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
       RValue trueValue = (RValue) this.visit(ctx.expr(1));
       SymbolVariableRef trueVar = getCurrentScope().addVariableIntermediate().getRef();
-      sequence.addStatement(new StatementAssignment((LValue) trueVar,  trueValue, true, new StatementSource(ctx), Comment.NO_COMMENTS));
+      sequence.addStatement(new StatementAssignment((LValue) trueVar, trueValue, true, new StatementSource(ctx), Comment.NO_COMMENTS));
       LabelRef trueExitLabel = sequence.getCurrentBlockLabel();
       sequence.addStatement(new StatementLabel(endJumpLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
       StatementPhiBlock phiBlock = new StatementPhiBlock(Comment.NO_COMMENTS);
diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1StructTypeSizeFix.java b/src/main/java/dk/camelot64/kickc/passes/Pass1StructTypeSizeFix.java
index 519f95322..b64717547 100644
--- a/src/main/java/dk/camelot64/kickc/passes/Pass1StructTypeSizeFix.java
+++ b/src/main/java/dk/camelot64/kickc/passes/Pass1StructTypeSizeFix.java
@@ -1,14 +1,14 @@
 package dk.camelot64.kickc.passes;
 
 import dk.camelot64.kickc.model.Program;
+import dk.camelot64.kickc.model.operators.OperatorSizeOf;
+import dk.camelot64.kickc.model.symbols.Scope;
 import dk.camelot64.kickc.model.symbols.StructDefinition;
 import dk.camelot64.kickc.model.symbols.Variable;
 import dk.camelot64.kickc.model.types.SymbolType;
 import dk.camelot64.kickc.model.types.SymbolTypePointer;
 import dk.camelot64.kickc.model.types.SymbolTypeStruct;
 
-import java.util.concurrent.atomic.AtomicBoolean;
-
 /**
  * Fixes byte-size of all struct types. (which may be a bit off if struct types are referenced before being parsed completely)
  */
@@ -20,15 +20,33 @@ public class Pass1StructTypeSizeFix extends Pass2SsaOptimization {
 
    @Override
    public boolean step() {
-      AtomicBoolean modified = new AtomicBoolean(false);
+      boolean modified = false;
+
+      // Update all types in variables
       for(Variable variable : getScope().getAllVars(true)) {
-         modified.set(fixStructSize(variable.getType()));
+         modified |= fixStructSize(variable.getType());
       }
-      return modified.get();
+
+      // Update all SIZEOF_XXX constants
+      for(Scope subScope : getScope().getAllScopes(false)) {
+         if(subScope instanceof StructDefinition) {
+            SymbolTypeStruct typeStruct = new SymbolTypeStruct((StructDefinition) subScope);
+            StructDefinition structDefinition = typeStruct.getStructDefinition(getScope());
+            int sizeBytes = typeStruct.calculateSizeBytes(structDefinition, getScope());
+            if(sizeBytes != typeStruct.getSizeBytes()) {
+               getLog().append("Fixing struct type SIZE_OF " + typeStruct.getTypeName() + " to " + sizeBytes);
+               typeStruct.setSizeBytes(sizeBytes);
+               OperatorSizeOf.fixSizeOfConstantVar(getScope(), typeStruct);
+            }
+         }
+      }
+
+      return modified;
    }
 
    /**
     * Fix struct byte-sizes in the passed type (if any)
+    *
     * @param type The type to fix
     * @return true if anything was modified
     */
@@ -37,11 +55,11 @@ public class Pass1StructTypeSizeFix extends Pass2SsaOptimization {
          SymbolTypeStruct typeStruct = (SymbolTypeStruct) type;
          StructDefinition structDefinition = typeStruct.getStructDefinition(getScope());
          int sizeBytes = typeStruct.calculateSizeBytes(structDefinition, getScope());
-         if(sizeBytes!=typeStruct.getSizeBytes()) {
-            getLog().append("Fixing struct type size "+type.getTypeName() + " to "+sizeBytes);
+         if(sizeBytes != typeStruct.getSizeBytes()) {
+            getLog().append("Fixing struct type size " + type.getTypeName() + " to " + sizeBytes);
             typeStruct.setSizeBytes(sizeBytes);
             return true;
-         }  else {
+         } else {
             return false;
          }
       } else if(type instanceof SymbolTypePointer) {
diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java b/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java
index 4df935651..dc06ad40c 100644
--- a/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java
+++ b/src/main/java/dk/camelot64/kickc/passes/Pass1UnwindStructValues.java
@@ -502,15 +502,26 @@ public class Pass1UnwindStructValues extends Pass1Base {
          ConstantRef memberOffsetConstant = PassNStructPointerRewriting.getMemberOffsetConstant(programScope, structDefinition, memberName);
          Variable member = structDefinition.getMember(memberName);
          Scope scope = programScope.getScope(currentBlock.getScope());
-         Variable memberAddress = scope.addVariableIntermediate();
-         memberAddress.setType(new SymbolTypePointer(member.getType()));
-         ConstantSymbolPointer structPointer = new ConstantSymbolPointer(variable.getRef());
-         CastValue structTypedPointer = new CastValue(new SymbolTypePointer(member.getType()), structPointer);
-         // Add statement $1 = ptr_struct + OFFSET_STRUCT_NAME_MEMBER
-         stmtIt.add(new StatementAssignment((LValue) memberAddress.getRef(), structTypedPointer, Operators.PLUS, memberOffsetConstant, true, currentStmt.getSource(), currentStmt.getComments()));
-         // Unwind to *(ptr_struct+OFFSET_STRUCT_NAME_MEMBER)
-         return new PointerDereferenceSimple(memberAddress.getRef());
-
+         if(member.isArray()) {
+            SymbolTypePointer arrayType = (SymbolTypePointer) member.getType();
+            //memberAddress.setArraySpec(member.getArraySpec());
+            //memberAddress.setType(member.getType());
+            ConstantSymbolPointer structPointer = new ConstantSymbolPointer(variable.getRef());
+            ConstantCastValue structTypedPointer = new ConstantCastValue(new SymbolTypePointer(arrayType.getElementType()), structPointer);
+            // Calculate member address  (element*)&struct + OFFSET_STRUCT_NAME_MEMBER
+            ConstantBinary memberArrayPointer = new ConstantBinary(structTypedPointer, Operators.PLUS, memberOffsetConstant);
+            // Unwind to *(ptr_struct+OFFSET_STRUCT_NAME_MEMBER)
+            return memberArrayPointer;
+         }  else {
+            Variable memberAddress = scope.addVariableIntermediate();
+            memberAddress.setType(new SymbolTypePointer(member.getType()));
+            ConstantSymbolPointer structPointer = new ConstantSymbolPointer(variable.getRef());
+            CastValue structTypedPointer = new CastValue(new SymbolTypePointer(member.getType()), structPointer);
+            // Add statement $1 = ptr_struct + OFFSET_STRUCT_NAME_MEMBER
+            stmtIt.add(new StatementAssignment((LValue) memberAddress.getRef(), structTypedPointer, Operators.PLUS, memberOffsetConstant, true, currentStmt.getSource(), currentStmt.getComments()));
+            // Unwind to *(ptr_struct+OFFSET_STRUCT_NAME_MEMBER)
+            return new PointerDereferenceSimple(memberAddress.getRef());
+         }
       }
 
       @Override
diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java
index 5b188f2ba..f22b28404 100644
--- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java
+++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java
@@ -1127,6 +1127,21 @@ public class TestPrograms {
       assertError("struct-err-0", "Unknown struct type");
    }
 
+   @Test
+   public void testStruct26() throws IOException, URISyntaxException {
+      compileAndCompare("struct-26", log());
+   }
+
+   @Test
+   public void testStruct25() throws IOException, URISyntaxException {
+      compileAndCompare("struct-25");
+   }
+
+   @Test
+   public void testStruct24() throws IOException, URISyntaxException {
+      compileAndCompare("struct-24");
+   }
+
    @Test
    public void testStruct23() throws IOException, URISyntaxException {
       compileAndCompare("struct-23");
diff --git a/src/test/kc/struct-24.kc b/src/test/kc/struct-24.kc
new file mode 100644
index 000000000..7b0ba4c0e
--- /dev/null
+++ b/src/test/kc/struct-24.kc
@@ -0,0 +1,18 @@
+// Minimal struct with C-Standard behavior - member array
+
+struct Point {
+    char x;
+    char[2] initials;
+};
+
+const char* SCREEN = 0x0400;
+
+void main() {
+    __ma struct Point point1;
+    point1.x = 2;
+    point1.initials[0] = 'j';
+    point1.initials[1] = 'g';
+    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/kc/struct-25.kc b/src/test/kc/struct-25.kc
new file mode 100644
index 000000000..daacfd220
--- /dev/null
+++ b/src/test/kc/struct-25.kc
@@ -0,0 +1,12 @@
+// Minimal struct with C-Standard behavior - member array sizeof
+
+struct Point {
+    int x;
+    char[2] initials;
+};
+
+const char* SCREEN = 0x0400;
+
+void main() {
+    SCREEN[0] = sizeof(struct Point);
+}
\ No newline at end of file
diff --git a/src/test/kc/struct-26.kc b/src/test/kc/struct-26.kc
new file mode 100644
index 000000000..cee67f9dd
--- /dev/null
+++ b/src/test/kc/struct-26.kc
@@ -0,0 +1,19 @@
+// Minimal struct with C-Standard behavior - member is array, copy assignment (not supported yet)
+
+struct Point {
+    char x;
+    char[2] initials;
+};
+
+const char* SCREEN = 0x0400;
+
+void main() {
+    __ma struct Point point1;
+    point1.x = 2;
+    point1.initials[0] = 'j';
+    point1.initials[1] = 'g';
+    __ma struct Point point2 = point1;
+    SCREEN[0] = point2.x;
+    SCREEN[1] = point2.initials[0];
+    SCREEN[2] = point2.initials[1];
+}
\ No newline at end of file
diff --git a/src/test/ref/struct-24.asm b/src/test/ref/struct-24.asm
new file mode 100644
index 000000000..1b0d386a4
--- /dev/null
+++ b/src/test/ref/struct-24.asm
@@ -0,0 +1,24 @@
+// Minimal struct with C-Standard behavior - member array
+.pc = $801 "Basic"
+:BasicUpstart(main)
+.pc = $80d "Program"
+  .label SCREEN = $400
+  .const OFFSET_STRUCT_POINT_INITIALS = 1
+main: {
+    .label point1 = 2
+    lda #0
+    sta.z point1
+    lda #2
+    sta.z point1
+    lda #'j'
+    sta point1+OFFSET_STRUCT_POINT_INITIALS
+    lda #'g'
+    sta point1+OFFSET_STRUCT_POINT_INITIALS+1
+    lda.z point1
+    sta SCREEN
+    lda point1+OFFSET_STRUCT_POINT_INITIALS
+    sta SCREEN+1
+    lda point1+OFFSET_STRUCT_POINT_INITIALS+1
+    sta SCREEN+2
+    rts
+}
diff --git a/src/test/ref/struct-24.cfg b/src/test/ref/struct-24.cfg
new file mode 100644
index 000000000..feb62b429
--- /dev/null
+++ b/src/test/ref/struct-24.cfg
@@ -0,0 +1,23 @@
+@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] *((byte*)&(struct Point) main::point1) ← (byte) 0
+  [5] *((byte*)&(struct Point) main::point1) ← (byte) 2
+  [6] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← (byte) 'j'
+  [7] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) ← (byte) 'g'
+  [8] *((const byte*) SCREEN) ← *((byte*)&(struct Point) main::point1)
+  [9] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS)
+  [10] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1)
+  to:main::@return
+main::@return: scope:[main]  from main
+  [11] return 
+  to:@return
diff --git a/src/test/ref/struct-24.log b/src/test/ref/struct-24.log
new file mode 100644
index 000000000..123e27bbd
--- /dev/null
+++ b/src/test/ref/struct-24.log
@@ -0,0 +1,387 @@
+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
+Adding struct value member variable default initializer *((byte*~) main::$0) ← (byte) 0
+Replacing struct member reference (struct Point) main::point1.x with member unwinding reference *((byte*~) main::$1)
+Replacing struct member reference (struct Point) main::point1.initials with member unwinding reference (byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS
+Replacing struct member reference (struct Point) main::point1.initials with member unwinding reference (byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS
+Replacing struct member reference (struct Point) main::point1.x with member unwinding reference *((byte*~) main::$2)
+Replacing struct member reference (struct Point) main::point1.initials with member unwinding reference (byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS
+Replacing struct member reference (struct Point) main::point1.initials with member unwinding reference (byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS
+Adding versioned struct unwinding for (struct Point) main::point1
+
+CONTROL FLOW GRAPH SSA
+@begin: scope:[]  from
+  to:@1
+
+(void()) main()
+main: scope:[main]  from @1
+  (byte*~) main::$0 ← (byte*)&(struct Point) main::point1 + (const byte) OFFSET_STRUCT_POINT_X
+  *((byte*~) main::$0) ← (byte) 0
+  (struct Point) main::point1 ← struct-unwound {*((byte*~) main::$0)}
+  *((byte*~) main::$1) ← (number) 2
+  (byte*~) main::$1 ← (byte*)&(struct Point) main::point1 + (const byte) OFFSET_STRUCT_POINT_X
+  *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0) ← (byte) 'j'
+  *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1) ← (byte) 'g'
+  *((const byte*) SCREEN + (number) 0) ← *((byte*~) main::$2)
+  (byte*~) main::$2 ← (byte*)&(struct Point) main::point1 + (const byte) OFFSET_STRUCT_POINT_X
+  *((const byte*) SCREEN + (number) 1) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0)
+  *((const byte*) SCREEN + (number) 2) ← *((byte*)&(struct Point) main::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()
+(byte*~) main::$0
+(byte*~) main::$1
+(byte*~) main::$2
+(label) main::@return
+(struct Point) main::point1 loadstore
+
+Adding number conversion cast (unumber) 2 in *((byte*~) main::$1) ← (number) 2
+Adding number conversion cast (unumber) 0 in *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0) ← (byte) 'j'
+Adding number conversion cast (unumber) 1 in *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1) ← (byte) 'g'
+Adding number conversion cast (unumber) 0 in *((const byte*) SCREEN + (number) 0) ← *((byte*~) main::$2)
+Adding number conversion cast (unumber) 0 in *((const byte*) SCREEN + (number) 1) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 0)
+Adding number conversion cast (unumber) 1 in *((const byte*) SCREEN + (number) 1) ← *((byte*)&(struct Point) main::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) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (number) 1)
+Adding number conversion cast (unumber) 2 in *((const byte*) SCREEN + (number) 2) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (unumber)(number) 1)
+Successful SSA optimization PassNAddNumberTypeConversions
+Inlining cast *((byte*~) main::$1) ← (unumber)(number) 2
+Successful SSA optimization Pass2InlineCast
+Simplifying constant pointer cast (byte*) 1024
+Simplifying constant integer cast 2
+Simplifying constant integer cast 0
+Simplifying constant integer cast 1
+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) 2
+Finalized unsigned number type (byte) 0
+Finalized unsigned number type (byte) 1
+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
+Removing C-classic struct-unwound assignment [2] (struct Point) main::point1 ← struct-unwound {*((byte*~) main::$0)}
+Constant right-side identified [0] (byte*~) main::$0 ← (byte*)&(struct Point) main::point1 + (const byte) OFFSET_STRUCT_POINT_X
+Constant right-side identified [4] (byte*~) main::$1 ← (byte*)&(struct Point) main::point1 + (const byte) OFFSET_STRUCT_POINT_X
+Constant right-side identified [8] (byte*~) main::$2 ← (byte*)&(struct Point) main::point1 + (const byte) OFFSET_STRUCT_POINT_X
+Successful SSA optimization Pass2ConstantRValueConsolidation
+Constant (const byte*) main::$0 = (byte*)&main::point1+OFFSET_STRUCT_POINT_X
+Constant (const byte*) main::$1 = (byte*)&main::point1+OFFSET_STRUCT_POINT_X
+Constant (const byte*) main::$2 = (byte*)&main::point1+OFFSET_STRUCT_POINT_X
+Successful SSA optimization Pass2ConstantIdentification
+Simplifying expression containing zero (byte*)&main::point1 in 
+Simplifying expression containing zero (byte*)&main::point1 in 
+Simplifying expression containing zero (byte*)&main::point1 in 
+Simplifying expression containing zero (byte*)&main::point1+OFFSET_STRUCT_POINT_INITIALS in [5] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS + (byte) 0) ← (byte) 'j'
+Simplifying expression containing zero SCREEN in [7] *((const byte*) SCREEN + (byte) 0) ← *((const byte*) main::$2)
+Simplifying expression containing zero (byte*)&main::point1+OFFSET_STRUCT_POINT_INITIALS in [9] *((const byte*) SCREEN + (byte) 1) ← *((byte*)&(struct Point) main::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
+Constant inlined main::$1 = (byte*)&(struct Point) main::point1
+Constant inlined main::$2 = (byte*)&(struct Point) main::point1
+Constant inlined main::$0 = (byte*)&(struct Point) main::point1
+Successful SSA optimization Pass2ConstantInlining
+Consolidated array index constant in *((byte*)&main::point1+OFFSET_STRUCT_POINT_INITIALS+1)
+Consolidated array index constant in *(SCREEN+1)
+Consolidated array index constant in *((byte*)&main::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] *((byte*)&(struct Point) main::point1) ← (byte) 0
+  [5] *((byte*)&(struct Point) main::point1) ← (byte) 2
+  [6] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← (byte) 'j'
+  [7] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) ← (byte) 'g'
+  [8] *((const byte*) SCREEN) ← *((byte*)&(struct Point) main::point1)
+  [9] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS)
+  [10] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1)
+  to:main::@return
+main::@return: scope:[main]  from main
+  [11] return 
+  to:@return
+
+
+VARIABLE REGISTER WEIGHTS
+(byte) Point::x
+(void()) main()
+(struct Point) main::point1 loadstore
+
+Initial phi equivalence classes
+Added variable main::point1 to live range equivalence class [ main::point1 ]
+Complete equivalence classes
+[ main::point1 ]
+Allocated zp[3]:2 [ main::point1 ]
+
+INITIAL ASM
+Target platform is c64basic / MOS6502X
+  // File Comments
+// Minimal struct with C-Standard behavior - member array
+  // 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: {
+    .label point1 = 2
+    // [4] *((byte*)&(struct Point) main::point1) ← (byte) 0 -- _deref_pbuc1=vbuc2 
+    lda #0
+    sta.z point1
+    // [5] *((byte*)&(struct Point) main::point1) ← (byte) 2 -- _deref_pbuc1=vbuc2 
+    lda #2
+    sta.z point1
+    // [6] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← (byte) 'j' -- _deref_pbuc1=vbuc2 
+    lda #'j'
+    sta point1+OFFSET_STRUCT_POINT_INITIALS
+    // [7] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) ← (byte) 'g' -- _deref_pbuc1=vbuc2 
+    lda #'g'
+    sta point1+OFFSET_STRUCT_POINT_INITIALS+1
+    // [8] *((const byte*) SCREEN) ← *((byte*)&(struct Point) main::point1) -- _deref_pbuc1=_deref_pbuc2 
+    lda.z point1
+    sta SCREEN
+    // [9] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) -- _deref_pbuc1=_deref_pbuc2 
+    lda point1+OFFSET_STRUCT_POINT_INITIALS
+    sta SCREEN+1
+    // [10] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) main::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:
+    // [11] return 
+    rts
+}
+  // File Data
+
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [4] *((byte*)&(struct Point) main::point1) ← (byte) 0 [ main::point1 ] ( main:2 [ main::point1 ] ) always clobbers reg byte a 
+Statement [5] *((byte*)&(struct Point) main::point1) ← (byte) 2 [ main::point1 ] ( main:2 [ main::point1 ] ) always clobbers reg byte a 
+Statement [6] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← (byte) 'j' [ main::point1 ] ( main:2 [ main::point1 ] ) always clobbers reg byte a 
+Statement [7] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) ← (byte) 'g' [ main::point1 ] ( main:2 [ main::point1 ] ) always clobbers reg byte a 
+Statement [8] *((const byte*) SCREEN) ← *((byte*)&(struct Point) main::point1) [ main::point1 ] ( main:2 [ main::point1 ] ) always clobbers reg byte a 
+Statement [9] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) [ main::point1 ] ( main:2 [ main::point1 ] ) always clobbers reg byte a 
+Statement [10] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) [ ] ( main:2 [ ] ) always clobbers reg byte a 
+Potential registers zp[3]:2 [ main::point1 ] : zp[3]:2 , 
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [Point] 
+Uplift Scope [main] 0: zp[3]:2 [ main::point1 ] 
+Uplift Scope [] 
+
+Uplifting [Point] best 66 combination 
+Uplifting [main] best 66 combination zp[3]:2 [ main::point1 ] 
+Uplifting [] best 66 combination 
+
+ASSEMBLER BEFORE OPTIMIZATION
+  // File Comments
+// Minimal struct with C-Standard behavior - member array
+  // 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: {
+    .label point1 = 2
+    // [4] *((byte*)&(struct Point) main::point1) ← (byte) 0 -- _deref_pbuc1=vbuc2 
+    lda #0
+    sta.z point1
+    // [5] *((byte*)&(struct Point) main::point1) ← (byte) 2 -- _deref_pbuc1=vbuc2 
+    lda #2
+    sta.z point1
+    // [6] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← (byte) 'j' -- _deref_pbuc1=vbuc2 
+    lda #'j'
+    sta point1+OFFSET_STRUCT_POINT_INITIALS
+    // [7] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) ← (byte) 'g' -- _deref_pbuc1=vbuc2 
+    lda #'g'
+    sta point1+OFFSET_STRUCT_POINT_INITIALS+1
+    // [8] *((const byte*) SCREEN) ← *((byte*)&(struct Point) main::point1) -- _deref_pbuc1=_deref_pbuc2 
+    lda.z point1
+    sta SCREEN
+    // [9] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) -- _deref_pbuc1=_deref_pbuc2 
+    lda point1+OFFSET_STRUCT_POINT_INITIALS
+    sta SCREEN+1
+    // [10] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) main::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:
+    // [11] return 
+    rts
+}
+  // File Data
+
+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) main::point1 loadstore zp[3]:2
+
+zp[3]:2 [ main::point1 ]
+
+
+FINAL ASSEMBLER
+Score: 51
+
+  // File Comments
+// Minimal struct with C-Standard behavior - member array
+  // 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: {
+    .label point1 = 2
+    // point1
+    // [4] *((byte*)&(struct Point) main::point1) ← (byte) 0 -- _deref_pbuc1=vbuc2 
+    lda #0
+    sta.z point1
+    // point1.x = 2
+    // [5] *((byte*)&(struct Point) main::point1) ← (byte) 2 -- _deref_pbuc1=vbuc2 
+    lda #2
+    sta.z point1
+    // point1.initials[0] = 'j'
+    // [6] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS) ← (byte) 'j' -- _deref_pbuc1=vbuc2 
+    lda #'j'
+    sta point1+OFFSET_STRUCT_POINT_INITIALS
+    // point1.initials[1] = 'g'
+    // [7] *((byte*)&(struct Point) main::point1+(const byte) OFFSET_STRUCT_POINT_INITIALS+(byte) 1) ← (byte) 'g' -- _deref_pbuc1=vbuc2 
+    lda #'g'
+    sta point1+OFFSET_STRUCT_POINT_INITIALS+1
+    // SCREEN[0] = point1.x
+    // [8] *((const byte*) SCREEN) ← *((byte*)&(struct Point) main::point1) -- _deref_pbuc1=_deref_pbuc2 
+    lda.z point1
+    sta SCREEN
+    // SCREEN[1] = point1.initials[0]
+    // [9] *((const byte*) SCREEN+(byte) 1) ← *((byte*)&(struct Point) main::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]
+    // [10] *((const byte*) SCREEN+(byte) 2) ← *((byte*)&(struct Point) main::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
+    // }
+    // [11] return 
+    rts
+}
+  // File Data
+
diff --git a/src/test/ref/struct-24.sym b/src/test/ref/struct-24.sym
new file mode 100644
index 000000000..4de77febc
--- /dev/null
+++ b/src/test/ref/struct-24.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) main::point1 loadstore zp[3]:2
+
+zp[3]:2 [ main::point1 ]
diff --git a/src/test/ref/struct-25.asm b/src/test/ref/struct-25.asm
new file mode 100644
index 000000000..2ff179a69
--- /dev/null
+++ b/src/test/ref/struct-25.asm
@@ -0,0 +1,11 @@
+// Minimal struct with C-Standard behavior - member array sizeof
+.pc = $801 "Basic"
+:BasicUpstart(main)
+.pc = $80d "Program"
+  .label SCREEN = $400
+  .const SIZEOF_STRUCT_POINT = 4
+main: {
+    lda #SIZEOF_STRUCT_POINT
+    sta SCREEN
+    rts
+}
diff --git a/src/test/ref/struct-25.cfg b/src/test/ref/struct-25.cfg
new file mode 100644
index 000000000..e34e0f15e
--- /dev/null
+++ b/src/test/ref/struct-25.cfg
@@ -0,0 +1,17 @@
+@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) ← (const byte) SIZEOF_STRUCT_POINT
+  to:main::@return
+main::@return: scope:[main]  from main
+  [5] return 
+  to:@return
diff --git a/src/test/ref/struct-25.log b/src/test/ref/struct-25.log
new file mode 100644
index 000000000..67384a572
--- /dev/null
+++ b/src/test/ref/struct-25.log
@@ -0,0 +1,232 @@
+Fixing struct type SIZE_OF struct Point to 4
+
+CONTROL FLOW GRAPH SSA
+@begin: scope:[]  from
+  to:@1
+
+(void()) main()
+main: scope:[main]  from @1
+  *((const byte*) SCREEN + (number) 0) ← (const byte) SIZEOF_STRUCT_POINT
+  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*) Point::initials[(number) 2]  = { fill( 2, 0) }
+(signed word) Point::x
+(const byte*) SCREEN = (byte*)(number) $400
+(const byte) SIZEOF_STRUCT_POINT = (byte) 4
+(void()) main()
+(label) main::@return
+
+Adding number conversion cast (unumber) 0 in *((const byte*) SCREEN + (number) 0) ← (const byte) SIZEOF_STRUCT_POINT
+Successful SSA optimization PassNAddNumberTypeConversions
+Simplifying constant pointer cast (byte*) 1024
+Simplifying constant integer cast 0
+Successful SSA optimization PassNCastSimplification
+Finalized unsigned number type (byte) 0
+Successful SSA optimization PassNFinalizeNumberTypeConversions
+Simplifying expression containing zero SCREEN in [0] *((const byte*) SCREEN + (byte) 0) ← (const byte) SIZEOF_STRUCT_POINT
+Successful SSA optimization PassNSimplifyExpressionWithZero
+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) ← (const byte) SIZEOF_STRUCT_POINT
+  to:main::@return
+main::@return: scope:[main]  from main
+  [5] return 
+  to:@return
+
+
+VARIABLE REGISTER WEIGHTS
+(signed word) Point::x
+(void()) main()
+
+Initial phi equivalence classes
+Complete equivalence classes
+
+INITIAL ASM
+Target platform is c64basic / MOS6502X
+  // File Comments
+// Minimal struct with C-Standard behavior - member array sizeof
+  // Upstart
+.pc = $801 "Basic"
+:BasicUpstart(__bbegin)
+.pc = $80d "Program"
+  // Global Constants & labels
+  .label SCREEN = $400
+  .const SIZEOF_STRUCT_POINT = 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: {
+    // [4] *((const byte*) SCREEN) ← (const byte) SIZEOF_STRUCT_POINT -- _deref_pbuc1=vbuc2 
+    lda #SIZEOF_STRUCT_POINT
+    sta SCREEN
+    jmp __breturn
+    // main::@return
+  __breturn:
+    // [5] return 
+    rts
+}
+  // File Data
+
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [4] *((const byte*) SCREEN) ← (const byte) SIZEOF_STRUCT_POINT [ ] ( main:2 [ ] ) always clobbers reg byte a 
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [Point] 
+Uplift Scope [main] 
+Uplift Scope [] 
+
+Uplifting [Point] best 27 combination 
+Uplifting [main] best 27 combination 
+Uplifting [] best 27 combination 
+
+ASSEMBLER BEFORE OPTIMIZATION
+  // File Comments
+// Minimal struct with C-Standard behavior - member array sizeof
+  // Upstart
+.pc = $801 "Basic"
+:BasicUpstart(__bbegin)
+.pc = $80d "Program"
+  // Global Constants & labels
+  .label SCREEN = $400
+  .const SIZEOF_STRUCT_POINT = 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: {
+    // [4] *((const byte*) SCREEN) ← (const byte) SIZEOF_STRUCT_POINT -- _deref_pbuc1=vbuc2 
+    lda #SIZEOF_STRUCT_POINT
+    sta SCREEN
+    jmp __breturn
+    // main::@return
+  __breturn:
+    // [5] return 
+    rts
+}
+  // File Data
+
+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*) Point::initials[(number) 2]  = { fill( 2, 0) }
+(signed word) Point::x
+(const byte*) SCREEN = (byte*) 1024
+(const byte) SIZEOF_STRUCT_POINT = (byte) 4
+(void()) main()
+(label) main::@return
+
+
+
+FINAL ASSEMBLER
+Score: 12
+
+  // File Comments
+// Minimal struct with C-Standard behavior - member array sizeof
+  // Upstart
+.pc = $801 "Basic"
+:BasicUpstart(main)
+.pc = $80d "Program"
+  // Global Constants & labels
+  .label SCREEN = $400
+  .const SIZEOF_STRUCT_POINT = 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: {
+    // SCREEN[0] = sizeof(struct Point)
+    // [4] *((const byte*) SCREEN) ← (const byte) SIZEOF_STRUCT_POINT -- _deref_pbuc1=vbuc2 
+    lda #SIZEOF_STRUCT_POINT
+    sta SCREEN
+    // main::@return
+    // }
+    // [5] return 
+    rts
+}
+  // File Data
+
diff --git a/src/test/ref/struct-25.sym b/src/test/ref/struct-25.sym
new file mode 100644
index 000000000..3fa6c8161
--- /dev/null
+++ b/src/test/ref/struct-25.sym
@@ -0,0 +1,10 @@
+(label) @1
+(label) @begin
+(label) @end
+(const byte*) Point::initials[(number) 2]  = { fill( 2, 0) }
+(signed word) Point::x
+(const byte*) SCREEN = (byte*) 1024
+(const byte) SIZEOF_STRUCT_POINT = (byte) 4
+(void()) main()
+(label) main::@return
+
diff --git a/src/test/ref/struct-ptr-23.log b/src/test/ref/struct-ptr-23.log
index 394ed2d10..858120c71 100644
--- a/src/test/ref/struct-ptr-23.log
+++ b/src/test/ref/struct-ptr-23.log
@@ -1,6 +1,8 @@
 Fixing struct type size struct Person to 5
 Fixing struct type size struct Person to 5
 Fixing struct type size struct Person to 5
+Fixing struct type SIZE_OF struct Person to 5
+Fixing struct type SIZE_OF struct Person to 5
 Fixing pointer increment (struct Person*) main::person ← ++ (struct Person*) main::person
 Rewriting struct pointer member access *((struct Person*) print_person::person).id
 Rewriting struct pointer member access *((struct Person*) print_person::person).initials
diff --git a/src/test/ref/struct-ptr-31.log b/src/test/ref/struct-ptr-31.log
index 7113a3b12..8c3e500e8 100644
--- a/src/test/ref/struct-ptr-31.log
+++ b/src/test/ref/struct-ptr-31.log
@@ -1,5 +1,7 @@
 Fixing struct type size struct Person to 17
 Fixing struct type size struct Person to 17
+Fixing struct type SIZE_OF struct Person to 17
+Fixing struct type SIZE_OF struct Person to 17
 Fixing constant pointer addition (const struct Person*) persons+(number) 1
 Rewriting struct pointer member access *((struct Person*) print_person::person).id
 Rewriting struct pointer member access *((struct Person*) print_person::person).name
diff --git a/src/test/ref/struct-ptr-32.log b/src/test/ref/struct-ptr-32.log
index 1c7d215e4..aa2d43489 100644
--- a/src/test/ref/struct-ptr-32.log
+++ b/src/test/ref/struct-ptr-32.log
@@ -1,5 +1,7 @@
 Fixing struct type size struct Person to 16
 Fixing struct type size struct Person to 16
+Fixing struct type SIZE_OF struct Person to 16
+Fixing struct type SIZE_OF struct Person to 16
 Fixing pointer increment (struct Person*) main::person ← ++ (struct Person*) main::person
 Fixing pointer array-indexing *((const struct Person*) persons + (number) 0)
 Fixing pointer array-indexing *((const struct Person*) persons + (number) 1)
diff --git a/src/test/ref/struct-ptr-33.log b/src/test/ref/struct-ptr-33.log
index b69b442d5..ca6d45b3a 100644
--- a/src/test/ref/struct-ptr-33.log
+++ b/src/test/ref/struct-ptr-33.log
@@ -1,5 +1,7 @@
 Fixing struct type size struct Person to 16
 Fixing struct type size struct Person to 16
+Fixing struct type SIZE_OF struct Person to 16
+Fixing struct type SIZE_OF struct Person to 16
 Fixing pointer increment (struct Person*) main::person ← ++ (struct Person*) main::person
 Rewriting struct pointer member access *((struct Person*) main::person).name
 Rewriting struct pointer member access *((struct Person*) main::person).name