1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-12-28 01:29:44 +00:00

Added support for union default initializers (initializing the first element) including any necessary padding to reach the right byte size. #197

This commit is contained in:
jespergravgaard 2021-07-23 17:26:47 +02:00
parent 16234fefa0
commit fa937d4874
19 changed files with 978 additions and 4 deletions

View File

@ -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

View File

@ -141,11 +141,11 @@ public class Initializers {
// Recursively cast all sub-elements
StructDefinition structDefinition = structType.getStructDefinition(program.getScope());
Collection<Variable> 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<SymbolVariableRef, ConstantValue> constMemberMap = new LinkedHashMap<>();
Iterator<Variable> memberDefIt = memberDefinitions.iterator();
Iterator<RValue> 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);

View File

@ -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<declaredSize) {
long paddingSize = declaredSize - size;
// TODO: Use SIZEOF constant
ConstantValue paddingSizeVal = new ConstantInteger(paddingSize);
String paddingBytesAsm = AsmFormat.getAsmConstant(program, paddingSizeVal, 99, scopeRef);
ConstantValue zeroValue = new ConstantInteger(0l, SymbolType.BYTE);
dataChunk.addDataZeroFilled(AsmDataNumeric.Type.BYTE, paddingBytesAsm, (int)paddingSize, getEncoding(zeroValue));
}
} else if(value instanceof StructZero) {
final SymbolTypeStruct typeStruct = ((StructZero) value).getTypeStruct();

View File

@ -2223,6 +2223,21 @@ public class TestProgramsFast extends TestPrograms {
compileAndCompare("struct-directives.c");
}
@Test
public void testUnion6() throws IOException {
compileAndCompare("union-6.c");
}
@Test
public void testUnion5() throws IOException {
compileAndCompare("union-5.c");
}
@Test
public void testUnion4() throws IOException {
compileAndCompare("union-4.c");
}
@Test
public void testUnion3() throws IOException {
compileAndCompare("union-3.c");

21
src/test/kc/union-4.c Normal file
View File

@ -0,0 +1,21 @@
// Minimal union with C-Standard behavior - union with array member
typedef unsigned long uint32_t;
typedef unsigned char byte_t;
typedef union IPV4 {
uint32_t d;
byte_t b[4];
} IPV4;
IPV4 ipv4;
char* const SCREEN = (char*)0x0400;
void main() {
ipv4.d = 0x12345678ul;
SCREEN[0] = ipv4.b[3];
SCREEN[1] = ipv4.b[2];
SCREEN[2] = ipv4.b[1];
SCREEN[3] = ipv4.b[0];
}

20
src/test/kc/union-5.c Normal file
View File

@ -0,0 +1,20 @@
// Minimal union with C-Standard behavior - union initializer
typedef unsigned long uint32_t;
typedef unsigned char byte_t;
typedef union IPV4 {
uint32_t d;
byte_t b[4];
} IPV4;
IPV4 ipv4 = { 0x12345678ul };
char* const SCREEN = (char*)0x0400;
void main() {
SCREEN[0] = ipv4.b[3];
SCREEN[1] = ipv4.b[2];
SCREEN[2] = ipv4.b[1];
SCREEN[3] = ipv4.b[0];
}

16
src/test/kc/union-6.c Normal file
View File

@ -0,0 +1,16 @@
// Minimal union with C-Standard behavior - union initializer with first element smaller than second
typedef union Data {
unsigned char b;
unsigned int w;
} Data;
Data data = { 12 };
char* const SCREEN = (char*)0x0400;
void main() {
data.w = 0x1234;
SCREEN[0] = BYTE1(data.w);
SCREEN[1] = BYTE0(data.w);
}

38
src/test/ref/union-4.asm Normal file
View File

@ -0,0 +1,38 @@
// Minimal union with C-Standard behavior - union with array member
// 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)
.const SIZEOF_UNION_IPV4 = 4
.label SCREEN = $400
.segment Code
main: {
// ipv4.d = 0x12345678ul
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]
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

12
src/test/ref/union-4.cfg Normal file
View File

@ -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

257
src/test/ref/union-4.log Normal file
View File

@ -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

6
src/test/ref/union-4.sym Normal file
View File

@ -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 ]

29
src/test/ref/union-5.asm Normal file
View File

@ -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

11
src/test/ref/union-5.cfg Normal file
View File

@ -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

228
src/test/ref/union-5.log Normal file
View File

@ -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

5
src/test/ref/union-5.sym Normal file
View File

@ -0,0 +1,5 @@
constant byte* const SCREEN = (byte*) 1024
union IPV4 ipv4 loadstore mem[4] = { d: $12345678 }
void main()
mem[4] [ ipv4 ]

30
src/test/ref/union-6.asm Normal file
View File

@ -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

12
src/test/ref/union-6.cfg Normal file
View File

@ -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

222
src/test/ref/union-6.log Normal file
View File

@ -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

9
src/test/ref/union-6.sym Normal file
View File

@ -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 ]