From fa937d4874846e94918b1df83d2b64733121079a Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Fri, 23 Jul 2021 17:26:47 +0200 Subject: [PATCH] Added support for union default initializers (initializing the first element) including any necessary padding to reach the right byte size. #197 --- .../cache/fragment-cache-mos6502x.asm | 31 +++ .../camelot64/kickc/model/Initializers.java | 8 +- .../kickc/passes/Pass4CodeGeneration.java | 12 + .../kickc/test/TestProgramsFast.java | 15 + src/test/kc/union-4.c | 21 ++ src/test/kc/union-5.c | 20 ++ src/test/kc/union-6.c | 16 ++ src/test/ref/union-4.asm | 38 +++ src/test/ref/union-4.cfg | 12 + src/test/ref/union-4.log | 257 ++++++++++++++++++ src/test/ref/union-4.sym | 6 + src/test/ref/union-5.asm | 29 ++ src/test/ref/union-5.cfg | 11 + src/test/ref/union-5.log | 228 ++++++++++++++++ src/test/ref/union-5.sym | 5 + src/test/ref/union-6.asm | 30 ++ src/test/ref/union-6.cfg | 12 + src/test/ref/union-6.log | 222 +++++++++++++++ src/test/ref/union-6.sym | 9 + 19 files changed, 978 insertions(+), 4 deletions(-) create mode 100644 src/test/kc/union-4.c create mode 100644 src/test/kc/union-5.c create mode 100644 src/test/kc/union-6.c create mode 100644 src/test/ref/union-4.asm create mode 100644 src/test/ref/union-4.cfg create mode 100644 src/test/ref/union-4.log create mode 100644 src/test/ref/union-4.sym create mode 100644 src/test/ref/union-5.asm create mode 100644 src/test/ref/union-5.cfg create mode 100644 src/test/ref/union-5.log create mode 100644 src/test/ref/union-5.sym create mode 100644 src/test/ref/union-6.asm create mode 100644 src/test/ref/union-6.cfg create mode 100644 src/test/ref/union-6.log create mode 100644 src/test/ref/union-6.sym diff --git a/src/main/fragment/cache/fragment-cache-mos6502x.asm b/src/main/fragment/cache/fragment-cache-mos6502x.asm index 4afcdbfbc..cc6f75509 100644 --- a/src/main/fragment/cache/fragment-cache-mos6502x.asm +++ b/src/main/fragment/cache/fragment-cache-mos6502x.asm @@ -15234,3 +15234,34 @@ sta {z1}+2 lda {z2}+3 sbc #>{c1}>>$10 sta {z1}+3 +//FRAGMENT vwuz1=vwuc1_plus_vbuz2 +lda {z2} +clc +adc #<{c1} +sta {z1} +lda #>{c1} +adc #0 +sta {z1}+1 +//FRAGMENT vwuz1=vwuc1_plus_vbuaa +clc +adc #<{c1} +sta {z1} +lda #>{c1} +adc #0 +sta {z1}+1 +//FRAGMENT vwuz1=vwuc1_plus_vbuxx +txa +clc +adc #<{c1} +sta {z1} +lda #>{c1} +adc #0 +sta {z1}+1 +//FRAGMENT vwuz1=vwuc1_plus_vbuyy +tya +clc +adc #<{c1} +sta {z1} +lda #>{c1} +adc #0 +sta {z1}+1 diff --git a/src/main/java/dk/camelot64/kickc/model/Initializers.java b/src/main/java/dk/camelot64/kickc/model/Initializers.java index 80549eb4d..6281b9360 100644 --- a/src/main/java/dk/camelot64/kickc/model/Initializers.java +++ b/src/main/java/dk/camelot64/kickc/model/Initializers.java @@ -141,11 +141,11 @@ public class Initializers { // Recursively cast all sub-elements StructDefinition structDefinition = structType.getStructDefinition(program.getScope()); Collection memberDefinitions = structDefinition.getAllVars(false); - int size = memberDefinitions.size(); - if(size != valueList.getList().size()) { + int structInitNeedSize = structDefinition.isUnion()? 1 : memberDefinitions.size() ; + if(structInitNeedSize != valueList.getList().size()) { throw new CompileError( "Struct initializer has wrong size (" + valueList.getList().size() + "), " + - "which does not match the number of members in " + structType.getTypeName() + " (" + size + " members).\n" + + "which does not match the number of members in " + structType.getTypeName() + " (" + structInitNeedSize + " members).\n" + " Struct initializer: " + valueList.toString(program), source); } @@ -157,7 +157,7 @@ public class Initializers { LinkedHashMap constMemberMap = new LinkedHashMap<>(); Iterator memberDefIt = memberDefinitions.iterator(); Iterator valueIt = valueList.getList().iterator(); - for(int i = 0; i < size; i++) { + for(int i = 0; i < structInitNeedSize; i++) { Variable memberDef = memberDefIt.next(); RValue memberValue = valueIt.next(); RValue constantifiedMemberValue = constantify(memberValue, new ValueTypeSpec(memberDef.getType()), program, source); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java index 5504ddf9d..49f6562f3 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java @@ -653,10 +653,22 @@ public class Pass4CodeGeneration { if(value instanceof ConstantStructValue) { // Add each struct member recursively ConstantStructValue structValue = (ConstantStructValue) value; + int size = 0; for(SymbolVariableRef memberRef : structValue.getMembers()) { ConstantValue memberValue = structValue.getValue(memberRef); Variable memberVariable = getScope().getVar(memberRef); addChunkData(dataChunk, memberValue, memberVariable.getType(), memberVariable.getArraySpec(), scopeRef); + size += SymbolTypeStruct.getMemberSizeBytes(memberVariable.getType(), memberVariable.getArraySize(), getScope()); + } + // Add padding if this is a union and the first member does not use all bytes + final int declaredSize = structValue.getStructType().getSizeBytes(); + if(size$12345678 + sta ipv4+1 + lda #<$12345678>>$10 + sta ipv4+2 + lda #>$12345678>>$10 + sta ipv4+3 + // SCREEN[0] = ipv4.b[3] + sta SCREEN + // SCREEN[1] = ipv4.b[2] + lda ipv4+2 + sta SCREEN+1 + // SCREEN[2] = ipv4.b[1] + lda ipv4+1 + sta SCREEN+2 + // SCREEN[3] = ipv4.b[0] + lda ipv4 + sta SCREEN+3 + // } + rts +} +.segment Data + ipv4: .fill SIZEOF_UNION_IPV4, 0 diff --git a/src/test/ref/union-4.cfg b/src/test/ref/union-4.cfg new file mode 100644 index 000000000..e48326cbd --- /dev/null +++ b/src/test/ref/union-4.cfg @@ -0,0 +1,12 @@ + +void main() +main: scope:[main] from + [0] *((dword*)&ipv4) = $12345678 + [1] *SCREEN = *((byte*)&ipv4+3) + [2] *(SCREEN+1) = *((byte*)&ipv4+2) + [3] *(SCREEN+2) = *((byte*)&ipv4+1) + [4] *(SCREEN+3) = *((byte*)&ipv4) + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return diff --git a/src/test/ref/union-4.log b/src/test/ref/union-4.log new file mode 100644 index 000000000..7a7cc7eec --- /dev/null +++ b/src/test/ref/union-4.log @@ -0,0 +1,257 @@ +Fixing struct type size union IPV4 to 4 +Fixing struct type size union IPV4 to 4 +Fixing struct type SIZE_OF union IPV4 to 4 +Fixing struct type SIZE_OF union IPV4 to 4 + +CONTROL FLOW GRAPH SSA + +void main() +main: scope:[main] from __start + *((dword*)&ipv4+OFFSET_UNION_IPV4_D) = $12345678 + SCREEN[0] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[3] + SCREEN[1] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[2] + SCREEN[2] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[1] + SCREEN[3] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[0] + to:main::@return +main::@return: scope:[main] from main + return + to:@return + +void __start() +__start: scope:[__start] from + call main + to:__start::@1 +__start::@1: scope:[__start] from __start + to:__start::@return +__start::@return: scope:[__start] from __start::@1 + return + to:@return + +SYMBOL TABLE SSA +constant byte OFFSET_UNION_IPV4_B = 0 +constant byte OFFSET_UNION_IPV4_D = 0 +constant byte* const SCREEN = (byte*)$400 +void __start() +union IPV4 ipv4 loadstore = {} +void main() + +Adding number conversion cast (unumber) 3 in SCREEN[0] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[3] +Adding number conversion cast (unumber) 0 in SCREEN[0] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[(unumber)3] +Adding number conversion cast (unumber) 2 in SCREEN[1] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[2] +Adding number conversion cast (unumber) 1 in SCREEN[1] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[(unumber)2] +Adding number conversion cast (unumber) 1 in SCREEN[2] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[1] +Adding number conversion cast (unumber) 2 in SCREEN[2] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[(unumber)1] +Adding number conversion cast (unumber) 0 in SCREEN[3] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[0] +Adding number conversion cast (unumber) 3 in SCREEN[3] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[(unumber)0] +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast 3 +Simplifying constant integer cast 0 +Simplifying constant integer cast 2 +Simplifying constant integer cast 1 +Simplifying constant integer cast 1 +Simplifying constant integer cast 2 +Simplifying constant integer cast 0 +Simplifying constant integer cast 3 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 3 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 2 +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 2 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 3 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Simplifying expression containing zero (dword*)&ipv4 in [0] *((dword*)&ipv4+OFFSET_UNION_IPV4_D) = $12345678 +Simplifying expression containing zero (byte*)&ipv4 in [1] SCREEN[0] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[3] +Simplifying expression containing zero SCREEN in [1] SCREEN[0] = ((byte*)&ipv4)[3] +Simplifying expression containing zero (byte*)&ipv4 in [2] SCREEN[1] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[2] +Simplifying expression containing zero (byte*)&ipv4 in [3] SCREEN[2] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[1] +Simplifying expression containing zero (byte*)&ipv4+OFFSET_UNION_IPV4_B in [4] SCREEN[3] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[0] +Simplifying expression containing zero (byte*)&ipv4 in [4] SCREEN[3] = *((byte*)&ipv4+OFFSET_UNION_IPV4_B) +Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused constant OFFSET_UNION_IPV4_D +Eliminating unused constant OFFSET_UNION_IPV4_B +Successful SSA optimization PassNEliminateUnusedVars +Removing unused procedure __start +Removing unused procedure block __start +Removing unused procedure block __start::@1 +Removing unused procedure block __start::@return +Successful SSA optimization PassNEliminateEmptyStart +Consolidated array index constant in *((byte*)&ipv4+3) +Consolidated array index constant in *((byte*)&ipv4+2) +Consolidated array index constant in *(SCREEN+1) +Consolidated array index constant in *((byte*)&ipv4+1) +Consolidated array index constant in *(SCREEN+2) +Consolidated array index constant in *(SCREEN+3) +Successful SSA optimization Pass2ConstantAdditionElimination +Finalized unsigned number type (byte) 4 +Finalized unsigned number type (byte) 4 +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] *((dword*)&ipv4) = $12345678 + [1] *SCREEN = *((byte*)&ipv4+3) + [2] *(SCREEN+1) = *((byte*)&ipv4+2) + [3] *(SCREEN+2) = *((byte*)&ipv4+1) + [4] *(SCREEN+3) = *((byte*)&ipv4) + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return + + +VARIABLE REGISTER WEIGHTS +union IPV4 ipv4 loadstore = {} +void main() + +Initial phi equivalence classes +Added variable ipv4 to live range equivalence class [ ipv4 ] +Complete equivalence classes +[ ipv4 ] +Allocated mem[4] [ ipv4 ] +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [0] *((dword*)&ipv4) = $12345678 [ ipv4 ] ( [ ipv4 ] { } ) always clobbers reg byte a +Statement [1] *SCREEN = *((byte*)&ipv4+3) [ ipv4 ] ( [ ipv4 ] { } ) always clobbers reg byte a +Statement [2] *(SCREEN+1) = *((byte*)&ipv4+2) [ ipv4 ] ( [ ipv4 ] { } ) always clobbers reg byte a +Statement [3] *(SCREEN+2) = *((byte*)&ipv4+1) [ ipv4 ] ( [ ipv4 ] { } ) always clobbers reg byte a +Statement [4] *(SCREEN+3) = *((byte*)&ipv4) [ ] ( [ ] { } ) always clobbers reg byte a +Potential registers mem[4] [ ipv4 ] : mem[4] , + +REGISTER UPLIFT SCOPES +Uplift Scope [IPV4] +Uplift Scope [main] +Uplift Scope [] 0: mem[4] [ ipv4 ] + +Uplifting [IPV4] best 65 combination +Uplifting [main] best 65 combination +Uplifting [] best 65 combination mem[4] [ ipv4 ] + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Minimal union with C-Standard behavior - union with array member + // Upstart + // Commodore 64 PRG executable file +.file [name="union-4.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_UNION_IPV4 = 4 + .label SCREEN = $400 +.segment Code + // main +main: { + // [0] *((dword*)&ipv4) = $12345678 -- _deref_pduc1=vduc2 + lda #<$12345678 + sta ipv4 + lda #>$12345678 + sta ipv4+1 + lda #<$12345678>>$10 + sta ipv4+2 + lda #>$12345678>>$10 + sta ipv4+3 + // [1] *SCREEN = *((byte*)&ipv4+3) -- _deref_pbuc1=_deref_pbuc2 + lda ipv4+3 + sta SCREEN + // [2] *(SCREEN+1) = *((byte*)&ipv4+2) -- _deref_pbuc1=_deref_pbuc2 + lda ipv4+2 + sta SCREEN+1 + // [3] *(SCREEN+2) = *((byte*)&ipv4+1) -- _deref_pbuc1=_deref_pbuc2 + lda ipv4+1 + sta SCREEN+2 + // [4] *(SCREEN+3) = *((byte*)&ipv4) -- _deref_pbuc1=_deref_pbuc2 + lda ipv4 + sta SCREEN+3 + jmp __breturn + // main::@return + __breturn: + // [5] return + rts +} + // File Data +.segment Data + ipv4: .fill SIZEOF_UNION_IPV4, 0 + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction lda ipv4+3 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Removing instruction __breturn: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +constant byte* const SCREEN = (byte*) 1024 +constant byte SIZEOF_UNION_IPV4 = 4 +union IPV4 ipv4 loadstore mem[4] = {} +void main() + +mem[4] [ ipv4 ] + + +FINAL ASSEMBLER +Score: 58 + + // File Comments +// Minimal union with C-Standard behavior - union with array member + // Upstart + // Commodore 64 PRG executable file +.file [name="union-4.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_UNION_IPV4 = 4 + .label SCREEN = $400 +.segment Code + // main +main: { + // ipv4.d = 0x12345678ul + // [0] *((dword*)&ipv4) = $12345678 -- _deref_pduc1=vduc2 + lda #<$12345678 + sta ipv4 + lda #>$12345678 + sta ipv4+1 + lda #<$12345678>>$10 + sta ipv4+2 + lda #>$12345678>>$10 + sta ipv4+3 + // SCREEN[0] = ipv4.b[3] + // [1] *SCREEN = *((byte*)&ipv4+3) -- _deref_pbuc1=_deref_pbuc2 + sta SCREEN + // SCREEN[1] = ipv4.b[2] + // [2] *(SCREEN+1) = *((byte*)&ipv4+2) -- _deref_pbuc1=_deref_pbuc2 + lda ipv4+2 + sta SCREEN+1 + // SCREEN[2] = ipv4.b[1] + // [3] *(SCREEN+2) = *((byte*)&ipv4+1) -- _deref_pbuc1=_deref_pbuc2 + lda ipv4+1 + sta SCREEN+2 + // SCREEN[3] = ipv4.b[0] + // [4] *(SCREEN+3) = *((byte*)&ipv4) -- _deref_pbuc1=_deref_pbuc2 + lda ipv4 + sta SCREEN+3 + // main::@return + // } + // [5] return + rts +} + // File Data +.segment Data + ipv4: .fill SIZEOF_UNION_IPV4, 0 + diff --git a/src/test/ref/union-4.sym b/src/test/ref/union-4.sym new file mode 100644 index 000000000..10cfef106 --- /dev/null +++ b/src/test/ref/union-4.sym @@ -0,0 +1,6 @@ +constant byte* const SCREEN = (byte*) 1024 +constant byte SIZEOF_UNION_IPV4 = 4 +union IPV4 ipv4 loadstore mem[4] = {} +void main() + +mem[4] [ ipv4 ] diff --git a/src/test/ref/union-5.asm b/src/test/ref/union-5.asm new file mode 100644 index 000000000..35f2ff2a0 --- /dev/null +++ b/src/test/ref/union-5.asm @@ -0,0 +1,29 @@ +// Minimal union with C-Standard behavior - union initializer + // Commodore 64 PRG executable file +.file [name="union-5.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) + .label SCREEN = $400 +.segment Code +main: { + // SCREEN[0] = ipv4.b[3] + lda ipv4+3 + sta SCREEN + // SCREEN[1] = ipv4.b[2] + lda ipv4+2 + sta SCREEN+1 + // SCREEN[2] = ipv4.b[1] + lda ipv4+1 + sta SCREEN+2 + // SCREEN[3] = ipv4.b[0] + lda ipv4 + sta SCREEN+3 + // } + rts +} +.segment Data + ipv4: .dword $12345678 diff --git a/src/test/ref/union-5.cfg b/src/test/ref/union-5.cfg new file mode 100644 index 000000000..f4a844848 --- /dev/null +++ b/src/test/ref/union-5.cfg @@ -0,0 +1,11 @@ + +void main() +main: scope:[main] from + [0] *SCREEN = *((byte*)&ipv4+3) + [1] *(SCREEN+1) = *((byte*)&ipv4+2) + [2] *(SCREEN+2) = *((byte*)&ipv4+1) + [3] *(SCREEN+3) = *((byte*)&ipv4) + to:main::@return +main::@return: scope:[main] from main + [4] return + to:@return diff --git a/src/test/ref/union-5.log b/src/test/ref/union-5.log new file mode 100644 index 000000000..55ee93083 --- /dev/null +++ b/src/test/ref/union-5.log @@ -0,0 +1,228 @@ +Fixing struct type size union IPV4 to 4 +Fixing struct type size union IPV4 to 4 +Fixing struct type SIZE_OF union IPV4 to 4 +Fixing struct type SIZE_OF union IPV4 to 4 + +CONTROL FLOW GRAPH SSA + +void main() +main: scope:[main] from __start + SCREEN[0] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[3] + SCREEN[1] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[2] + SCREEN[2] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[1] + SCREEN[3] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[0] + to:main::@return +main::@return: scope:[main] from main + return + to:@return + +void __start() +__start: scope:[__start] from + call main + to:__start::@1 +__start::@1: scope:[__start] from __start + to:__start::@return +__start::@return: scope:[__start] from __start::@1 + return + to:@return + +SYMBOL TABLE SSA +constant byte OFFSET_UNION_IPV4_B = 0 +constant byte* const SCREEN = (byte*)$400 +void __start() +union IPV4 ipv4 loadstore = { d: $12345678 } +void main() + +Adding number conversion cast (unumber) 3 in SCREEN[0] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[3] +Adding number conversion cast (unumber) 0 in SCREEN[0] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[(unumber)3] +Adding number conversion cast (unumber) 2 in SCREEN[1] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[2] +Adding number conversion cast (unumber) 1 in SCREEN[1] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[(unumber)2] +Adding number conversion cast (unumber) 1 in SCREEN[2] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[1] +Adding number conversion cast (unumber) 2 in SCREEN[2] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[(unumber)1] +Adding number conversion cast (unumber) 0 in SCREEN[3] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[0] +Adding number conversion cast (unumber) 3 in SCREEN[3] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[(unumber)0] +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast 3 +Simplifying constant integer cast 0 +Simplifying constant integer cast 2 +Simplifying constant integer cast 1 +Simplifying constant integer cast 1 +Simplifying constant integer cast 2 +Simplifying constant integer cast 0 +Simplifying constant integer cast 3 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 3 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 2 +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 2 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 3 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Simplifying expression containing zero (byte*)&ipv4 in [0] SCREEN[0] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[3] +Simplifying expression containing zero SCREEN in [0] SCREEN[0] = ((byte*)&ipv4)[3] +Simplifying expression containing zero (byte*)&ipv4 in [1] SCREEN[1] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[2] +Simplifying expression containing zero (byte*)&ipv4 in [2] SCREEN[2] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[1] +Simplifying expression containing zero (byte*)&ipv4+OFFSET_UNION_IPV4_B in [3] SCREEN[3] = ((byte*)&ipv4+OFFSET_UNION_IPV4_B)[0] +Simplifying expression containing zero (byte*)&ipv4 in [3] SCREEN[3] = *((byte*)&ipv4+OFFSET_UNION_IPV4_B) +Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused constant OFFSET_UNION_IPV4_B +Successful SSA optimization PassNEliminateUnusedVars +Removing unused procedure __start +Removing unused procedure block __start +Removing unused procedure block __start::@1 +Removing unused procedure block __start::@return +Successful SSA optimization PassNEliminateEmptyStart +Consolidated array index constant in *((byte*)&ipv4+3) +Consolidated array index constant in *((byte*)&ipv4+2) +Consolidated array index constant in *(SCREEN+1) +Consolidated array index constant in *((byte*)&ipv4+1) +Consolidated array index constant in *(SCREEN+2) +Consolidated array index constant in *(SCREEN+3) +Successful SSA optimization Pass2ConstantAdditionElimination +Finalized unsigned number type (byte) 4 +Finalized unsigned number type (byte) 4 +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] *SCREEN = *((byte*)&ipv4+3) + [1] *(SCREEN+1) = *((byte*)&ipv4+2) + [2] *(SCREEN+2) = *((byte*)&ipv4+1) + [3] *(SCREEN+3) = *((byte*)&ipv4) + to:main::@return +main::@return: scope:[main] from main + [4] return + to:@return + + +VARIABLE REGISTER WEIGHTS +union IPV4 ipv4 loadstore = { d: $12345678 } +void main() + +Initial phi equivalence classes +Added variable ipv4 to live range equivalence class [ ipv4 ] +Complete equivalence classes +[ ipv4 ] +Allocated mem[4] [ ipv4 ] +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [0] *SCREEN = *((byte*)&ipv4+3) [ ipv4 ] ( [ ipv4 ] { } ) always clobbers reg byte a +Statement [1] *(SCREEN+1) = *((byte*)&ipv4+2) [ ipv4 ] ( [ ipv4 ] { } ) always clobbers reg byte a +Statement [2] *(SCREEN+2) = *((byte*)&ipv4+1) [ ipv4 ] ( [ ipv4 ] { } ) always clobbers reg byte a +Statement [3] *(SCREEN+3) = *((byte*)&ipv4) [ ] ( [ ] { } ) always clobbers reg byte a +Potential registers mem[4] [ ipv4 ] : mem[4] , + +REGISTER UPLIFT SCOPES +Uplift Scope [IPV4] +Uplift Scope [main] +Uplift Scope [] 0: mem[4] [ ipv4 ] + +Uplifting [IPV4] best 41 combination +Uplifting [main] best 41 combination +Uplifting [] best 41 combination mem[4] [ ipv4 ] + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Minimal union with C-Standard behavior - union initializer + // Upstart + // Commodore 64 PRG executable file +.file [name="union-5.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 + .label SCREEN = $400 +.segment Code + // main +main: { + // [0] *SCREEN = *((byte*)&ipv4+3) -- _deref_pbuc1=_deref_pbuc2 + lda ipv4+3 + sta SCREEN + // [1] *(SCREEN+1) = *((byte*)&ipv4+2) -- _deref_pbuc1=_deref_pbuc2 + lda ipv4+2 + sta SCREEN+1 + // [2] *(SCREEN+2) = *((byte*)&ipv4+1) -- _deref_pbuc1=_deref_pbuc2 + lda ipv4+1 + sta SCREEN+2 + // [3] *(SCREEN+3) = *((byte*)&ipv4) -- _deref_pbuc1=_deref_pbuc2 + lda ipv4 + sta SCREEN+3 + jmp __breturn + // main::@return + __breturn: + // [4] return + rts +} + // File Data +.segment Data + ipv4: .dword $12345678 + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction __breturn: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +constant byte* const SCREEN = (byte*) 1024 +union IPV4 ipv4 loadstore mem[4] = { d: $12345678 } +void main() + +mem[4] [ ipv4 ] + + +FINAL ASSEMBLER +Score: 38 + + // File Comments +// Minimal union with C-Standard behavior - union initializer + // Upstart + // Commodore 64 PRG executable file +.file [name="union-5.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 + .label SCREEN = $400 +.segment Code + // main +main: { + // SCREEN[0] = ipv4.b[3] + // [0] *SCREEN = *((byte*)&ipv4+3) -- _deref_pbuc1=_deref_pbuc2 + lda ipv4+3 + sta SCREEN + // SCREEN[1] = ipv4.b[2] + // [1] *(SCREEN+1) = *((byte*)&ipv4+2) -- _deref_pbuc1=_deref_pbuc2 + lda ipv4+2 + sta SCREEN+1 + // SCREEN[2] = ipv4.b[1] + // [2] *(SCREEN+2) = *((byte*)&ipv4+1) -- _deref_pbuc1=_deref_pbuc2 + lda ipv4+1 + sta SCREEN+2 + // SCREEN[3] = ipv4.b[0] + // [3] *(SCREEN+3) = *((byte*)&ipv4) -- _deref_pbuc1=_deref_pbuc2 + lda ipv4 + sta SCREEN+3 + // main::@return + // } + // [4] return + rts +} + // File Data +.segment Data + ipv4: .dword $12345678 + diff --git a/src/test/ref/union-5.sym b/src/test/ref/union-5.sym new file mode 100644 index 000000000..31ea575d1 --- /dev/null +++ b/src/test/ref/union-5.sym @@ -0,0 +1,5 @@ +constant byte* const SCREEN = (byte*) 1024 +union IPV4 ipv4 loadstore mem[4] = { d: $12345678 } +void main() + +mem[4] [ ipv4 ] diff --git a/src/test/ref/union-6.asm b/src/test/ref/union-6.asm new file mode 100644 index 000000000..ed3ba2f23 --- /dev/null +++ b/src/test/ref/union-6.asm @@ -0,0 +1,30 @@ +// Minimal union with C-Standard behavior - union initializer with first element smaller than second + // Commodore 64 PRG executable file +.file [name="union-6.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) + .label SCREEN = $400 +.segment Code +main: { + // data.w = 0x1234 + lda #<$1234 + sta data + lda #>$1234 + sta data+1 + // BYTE1(data.w) + // SCREEN[0] = BYTE1(data.w) + sta SCREEN + // BYTE0(data.w) + lda data + // SCREEN[1] = BYTE0(data.w) + sta SCREEN+1 + // } + rts +} +.segment Data + data: .byte $c + .fill 1, 0 diff --git a/src/test/ref/union-6.cfg b/src/test/ref/union-6.cfg new file mode 100644 index 000000000..c701abb6a --- /dev/null +++ b/src/test/ref/union-6.cfg @@ -0,0 +1,12 @@ + +void main() +main: scope:[main] from + [0] *((word*)&data) = $1234 + [1] main::$0 = byte1 *((word*)&data) + [2] *SCREEN = main::$0 + [3] main::$1 = byte0 *((word*)&data) + [4] *(SCREEN+1) = main::$1 + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return diff --git a/src/test/ref/union-6.log b/src/test/ref/union-6.log new file mode 100644 index 000000000..6ccd284bf --- /dev/null +++ b/src/test/ref/union-6.log @@ -0,0 +1,222 @@ + +CONTROL FLOW GRAPH SSA + +void main() +main: scope:[main] from __start + *((word*)&data+OFFSET_UNION_DATA_W) = $1234 + main::$0 = byte1 *((word*)&data+OFFSET_UNION_DATA_W) + SCREEN[0] = main::$0 + main::$1 = byte0 *((word*)&data+OFFSET_UNION_DATA_W) + SCREEN[1] = main::$1 + to:main::@return +main::@return: scope:[main] from main + return + to:@return + +void __start() +__start: scope:[__start] from + call main + to:__start::@1 +__start::@1: scope:[__start] from __start + to:__start::@return +__start::@return: scope:[__start] from __start::@1 + return + to:@return + +SYMBOL TABLE SSA +constant byte OFFSET_UNION_DATA_W = 0 +constant byte* const SCREEN = (byte*)$400 +void __start() +union Data data loadstore = { b: $c } +void main() +byte~ main::$0 +byte~ main::$1 + +Adding number conversion cast (unumber) $1234 in *((word*)&data+OFFSET_UNION_DATA_W) = $1234 +Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0 +Adding number conversion cast (unumber) 1 in SCREEN[1] = main::$1 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast *((word*)&data+OFFSET_UNION_DATA_W) = (unumber)$1234 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast $1234 +Simplifying constant integer cast 0 +Simplifying constant integer cast 1 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (word) $1234 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 1 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Simplifying expression containing zero (word*)&data in [0] *((word*)&data+OFFSET_UNION_DATA_W) = $1234 +Simplifying expression containing zero (word*)&data in [1] main::$0 = byte1 *((word*)&data+OFFSET_UNION_DATA_W) +Simplifying expression containing zero SCREEN in [2] SCREEN[0] = main::$0 +Simplifying expression containing zero (word*)&data in [3] main::$1 = byte0 *((word*)&data+OFFSET_UNION_DATA_W) +Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused constant OFFSET_UNION_DATA_W +Successful SSA optimization PassNEliminateUnusedVars +Removing unused procedure __start +Removing unused procedure block __start +Removing unused procedure block __start::@1 +Removing unused procedure block __start::@return +Successful SSA optimization PassNEliminateEmptyStart +Consolidated array index constant in *(SCREEN+1) +Successful SSA optimization Pass2ConstantAdditionElimination +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] *((word*)&data) = $1234 + [1] main::$0 = byte1 *((word*)&data) + [2] *SCREEN = main::$0 + [3] main::$1 = byte0 *((word*)&data) + [4] *(SCREEN+1) = main::$1 + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return + + +VARIABLE REGISTER WEIGHTS +union Data data loadstore = { b: $c } +void main() +byte~ main::$0 4.0 +byte~ main::$1 4.0 + +Initial phi equivalence classes +Added variable main::$0 to live range equivalence class [ main::$0 ] +Added variable main::$1 to live range equivalence class [ main::$1 ] +Added variable data to live range equivalence class [ data ] +Complete equivalence classes +[ main::$0 ] +[ main::$1 ] +[ data ] +Allocated zp[1]:2 [ main::$0 ] +Allocated zp[1]:3 [ main::$1 ] +Allocated mem[2] [ data ] +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [0] *((word*)&data) = $1234 [ data ] ( [ data ] { } ) always clobbers reg byte a +Potential registers zp[1]:2 [ main::$0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:3 [ main::$1 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y , +Potential registers mem[2] [ data ] : mem[2] , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 4: zp[1]:2 [ main::$0 ] 4: zp[1]:3 [ main::$1 ] +Uplift Scope [Data] +Uplift Scope [] 0: mem[2] [ data ] + +Uplifting [main] best 37 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ] +Uplifting [Data] best 37 combination +Uplifting [] best 37 combination mem[2] [ data ] + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Minimal union with C-Standard behavior - union initializer with first element smaller than second + // Upstart + // Commodore 64 PRG executable file +.file [name="union-6.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 + .label SCREEN = $400 +.segment Code + // main +main: { + // [0] *((word*)&data) = $1234 -- _deref_pwuc1=vwuc2 + lda #<$1234 + sta data + lda #>$1234 + sta data+1 + // [1] main::$0 = byte1 *((word*)&data) -- vbuaa=_byte1__deref_pwuc1 + lda data+1 + // [2] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa + sta SCREEN + // [3] main::$1 = byte0 *((word*)&data) -- vbuaa=_byte0__deref_pwuc1 + lda data + // [4] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa + sta SCREEN+1 + jmp __breturn + // main::@return + __breturn: + // [5] return + rts +} + // File Data +.segment Data + data: .byte $c + .fill 1, 0 + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction lda data+1 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Removing instruction __breturn: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +constant byte* const SCREEN = (byte*) 1024 +union Data data loadstore mem[2] = { b: $c } +void main() +byte~ main::$0 reg byte a 4.0 +byte~ main::$1 reg byte a 4.0 + +reg byte a [ main::$0 ] +reg byte a [ main::$1 ] +mem[2] [ data ] + + +FINAL ASSEMBLER +Score: 30 + + // File Comments +// Minimal union with C-Standard behavior - union initializer with first element smaller than second + // Upstart + // Commodore 64 PRG executable file +.file [name="union-6.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 + .label SCREEN = $400 +.segment Code + // main +main: { + // data.w = 0x1234 + // [0] *((word*)&data) = $1234 -- _deref_pwuc1=vwuc2 + lda #<$1234 + sta data + lda #>$1234 + sta data+1 + // BYTE1(data.w) + // [1] main::$0 = byte1 *((word*)&data) -- vbuaa=_byte1__deref_pwuc1 + // SCREEN[0] = BYTE1(data.w) + // [2] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa + sta SCREEN + // BYTE0(data.w) + // [3] main::$1 = byte0 *((word*)&data) -- vbuaa=_byte0__deref_pwuc1 + lda data + // SCREEN[1] = BYTE0(data.w) + // [4] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa + sta SCREEN+1 + // main::@return + // } + // [5] return + rts +} + // File Data +.segment Data + data: .byte $c + .fill 1, 0 + diff --git a/src/test/ref/union-6.sym b/src/test/ref/union-6.sym new file mode 100644 index 000000000..2b9b5a258 --- /dev/null +++ b/src/test/ref/union-6.sym @@ -0,0 +1,9 @@ +constant byte* const SCREEN = (byte*) 1024 +union Data data loadstore mem[2] = { b: $c } +void main() +byte~ main::$0 reg byte a 4.0 +byte~ main::$1 reg byte a 4.0 + +reg byte a [ main::$0 ] +reg byte a [ main::$1 ] +mem[2] [ data ]