1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-01-20 20:31:56 +00:00

Added two memory variable tests with struct values. (illustrating that they do not work yet.) #328

This commit is contained in:
jespergravgaard 2019-09-30 00:18:41 +02:00
parent 624c27686c
commit 73854b7ee3
18 changed files with 1336 additions and 10 deletions

View File

@ -0,0 +1,4 @@
lda #<{c1}
sta {z1}
lda #>{c1}
sta {z1}+1

View File

@ -1,7 +1,9 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.iterator.ProgramValue;
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.symbols.ConstantVar;
import dk.camelot64.kickc.model.symbols.Scope;
import dk.camelot64.kickc.model.symbols.Variable;
@ -37,6 +39,11 @@ public class Pass1PointifyMemoryVariables extends Pass1Base {
ProgramValueIterator.execute(getGraph(), (programValue, currentStmt, stmtIt, currentBlock) -> {
Value value = programValue.get();
if(memoryVarPointers.containsKey(value)) {
if(programValue instanceof ProgramValue.ProgramValueLValue && currentStmt instanceof StatementAssignment) {
if(((StatementAssignment) currentStmt).getrValue2() instanceof StructUnwoundPlaceholder)
// Skip unwound structs!
return;
}
programValue.set(new PointerDereferenceSimple(memoryVarPointers.get(value)));
getLog().append("Updating memory variable reference " + programValue.get().toString(getProgram()));
}

View File

@ -33,7 +33,7 @@ public class PassNStructAddressOfRewriting extends Pass2SsaOptimization {
SymbolRef toSymbolRef = constantSymbolPointer.getToSymbol();
Symbol toSymbol = getScope().getSymbol(toSymbolRef);
if(toSymbol.getType() instanceof SymbolTypeStruct) {
RValue rewrite = rewriteStructAddressOf((VariableRef) toSymbol);
RValue rewrite = rewriteStructAddressOf((VariableRef) toSymbol.getRef());
if(rewrite!=null) {
programValue.set(rewrite);
}
@ -77,7 +77,7 @@ public class PassNStructAddressOfRewriting extends Pass2SsaOptimization {
// Found placeholder assignment!
StructUnwoundPlaceholder placeholder = (StructUnwoundPlaceholder) assignment.getrValue2();
SymbolRef firstMember = (SymbolRef) placeholder.getUnwoundMembers().get(0);
return new CastValue(new SymbolTypePointer(placeholder.getTypeStruct()), new ConstantSymbolPointer(firstMember));
return new ConstantCastValue(new SymbolTypePointer(placeholder.getTypeStruct()), new ConstantSymbolPointer(firstMember));
}
}
return null;

View File

@ -35,6 +35,16 @@ public class TestPrograms {
public TestPrograms() {
}
@Test
public void testDeclaredMemoryVar4() throws IOException, URISyntaxException {
compileAndCompare("declared-memory-var-4");
}
@Test
public void testDeclaredMemoryVar3() throws IOException, URISyntaxException {
compileAndCompare("declared-memory-var-3");
}
@Test
public void testDeclaredMemoryVar2() throws IOException, URISyntaxException {
compileAndCompare("declared-memory-var-2");

View File

@ -0,0 +1,18 @@
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
// Test a memory variable struct value
struct foo {
char thing1;
char thing2;
};
memory struct foo bar = { 'a', 'b' };
void main(void) {
struct foo* barp = &bar;
const char* SCREEN = 0x0400;
char i=0;
SCREEN[i++] = barp->thing1;
SCREEN[i++] = barp->thing2;
}

View File

@ -0,0 +1,21 @@
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
// Test a memory variable struct value - containing a fixed size array
struct foo {
char thing1;
char thing2;
char[12] thing3;
};
memory struct foo bar = { 'a', 'b', "qwe" };
void main(void) {
struct foo* barp = &bar;
const char* SCREEN = 0x0400;
char i=0;
SCREEN[i++] = barp->thing1;
SCREEN[i++] = barp->thing2;
for( char j: 0..11)
SCREEN[i++] = barp->thing3[j];
}

View File

@ -0,0 +1,31 @@
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
// Test a memory variable struct value
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
.const OFFSET_STRUCT_FOO_THING2 = 1
.label bar_ptr = bar_thing1
.label bar_thing1 = 2
.label bar_thing2 = 3
__bbegin:
lda #'a'
sta.z bar_thing1
lda #'b'
sta.z bar_thing2
jsr main
rts
main: {
.label SCREEN = $400
.label barp = 4
lda #<bar_ptr
sta.z barp
lda #>bar_ptr
sta.z barp+1
ldy #0
lda (barp),y
sta SCREEN
ldy #OFFSET_STRUCT_FOO_THING2
lda (barp),y
sta SCREEN+1
rts
}

View File

@ -0,0 +1,20 @@
@begin: scope:[] from
[0] (byte) bar_thing1#0 ← (byte) 'a'
[1] (byte) bar_thing2#0 ← (byte) 'b'
to:@1
@1: scope:[] from @begin
[2] phi()
[3] call main
to:@end
@end: scope:[] from @1
[4] phi()
(void()) main()
main: scope:[main] from @1
[5] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr)
[6] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0)
[7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2)
to:main::@return
main::@return: scope:[main] from main
[8] return
to:@return

View File

@ -0,0 +1,406 @@
Setting inferred volatile on symbol affected by address-of (struct foo*~) main::$0 ← & (struct foo) bar
Created struct value member variable (byte) bar_thing1
Created struct value member variable (byte) bar_thing2
Converted struct value to member variables (struct foo) bar
Adding struct value list initializer (byte) bar_thing1 ← (byte) 'a'
Adding struct value list initializer (byte) bar_thing2 ← (byte) 'b'
Rewriting struct pointer member access *((struct foo*) main::barp).thing1
Rewriting struct pointer member access *((struct foo*) main::barp).thing2
Adding memory variable constant pointer (const struct foo*) bar_ptr
Updating memory variable reference *((const struct foo*) bar_ptr)
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte) bar_thing1#0 ← (byte) 'a'
(byte) bar_thing2#0 ← (byte) 'b'
(struct foo) bar ← struct-unwound {(byte) bar_thing1#0, (byte) bar_thing2#0}
to:@1
(void()) main()
main: scope:[main] from @1
(struct foo*~) main::$0 ← & *((const struct foo*) bar_ptr)
(struct foo*) main::barp#0 ← (struct foo*~) main::$0
(byte*) main::SCREEN ← ((byte*)) (number) $400
(byte) main::i#0 ← (number) 0
(byte*) main::$1 ← (byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING1
*((byte*) main::SCREEN + (byte) main::i#0) ← *((byte*) main::$1)
(byte) main::i#1 ← ++ (byte) main::i#0
(byte*) main::$2 ← (byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2
*((byte*) main::SCREEN + (byte) main::i#1) ← *((byte*) main::$2)
(byte) main::i#2 ← ++ (byte) main::i#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_FOO_THING1 = (byte) 0
(const byte) OFFSET_STRUCT_FOO_THING2 = (byte) 1
(struct foo) bar memory
(const struct foo*) bar_ptr = &(struct foo) bar
(byte) bar_thing1
(byte) bar_thing1#0
(byte) bar_thing2
(byte) bar_thing2#0
(byte) foo::thing1
(byte) foo::thing2
(void()) main()
(struct foo*~) main::$0
(byte*) main::$1
(byte*) main::$2
(label) main::@return
(byte*) main::SCREEN
(struct foo*) main::barp
(struct foo*) main::barp#0
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
Adding number conversion cast (unumber) 0 in (byte) main::i#0 ← (number) 0
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (byte*) main::SCREEN ← (byte*)(number) $400
Inlining cast (byte) main::i#0 ← (unumber)(number) 0
Successful SSA optimization Pass2InlineCast
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
Alias (struct foo*) main::barp#0 = (struct foo*~) main::$0
Successful SSA optimization Pass2AliasElimination
Rewriting struct address-of to first member &(struct foo) bar
Successful SSA optimization PassNStructAddressOfRewriting
Constant (const byte*) main::SCREEN = (byte*) 1024
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Converting *(pointer+n) to pointer[n] [8] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*) main::$1) -- *((byte*)main::barp#0 + OFFSET_STRUCT_FOO_THING1)
Converting *(pointer+n) to pointer[n] [11] *((const byte*) main::SCREEN + (byte) main::i#1) ← *((byte*) main::$2) -- *((byte*)main::barp#0 + OFFSET_STRUCT_FOO_THING2)
Successful SSA optimization Pass2InlineDerefIdx
Simplifying expression containing zero (byte*)main::barp#0 in [7] (byte*) main::$1 ← (byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING1
Simplifying expression containing zero (byte*)main::barp#0 in [8] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING1)
Simplifying expression containing zero main::SCREEN in [8] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*)(struct foo*) main::barp#0)
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable (struct foo) bar and assignment [2] (struct foo) bar ← struct-unwound {(byte) bar_thing1#0, (byte) bar_thing2#0}
Eliminating unused variable (byte*) main::$1 and assignment [4] (byte*) main::$1 ← (byte*)(struct foo*) main::barp#0
Eliminating unused variable (byte*) main::$2 and assignment [7] (byte*) main::$2 ← (byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2
Eliminating unused variable (byte) main::i#2 and assignment [9] (byte) main::i#2 ← ++ (byte) main::i#1
Eliminating unused constant (const byte) OFFSET_STRUCT_FOO_THING1
Successful SSA optimization PassNEliminateUnusedVars
Constant right-side identified [4] (byte) main::i#1 ← ++ (const byte) main::i#0
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte) main::i#1 = ++main::i#0
Successful SSA optimization Pass2ConstantIdentification
Inlining constant with different constant siblings (const byte) main::i#0
Inlining constant with different constant siblings (const byte) main::i#1
Constant inlined main::i#0 = (byte) 0
Constant inlined main::i#1 = ++(byte) 0
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *(main::SCREEN+++0)
Successful SSA optimization Pass2ConstantAdditionElimination
Simplifying constant integer increment ++0
Successful SSA optimization Pass2ConstantSimplification
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:3
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
Culled Empty Block (label) @2
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] (byte) bar_thing1#0 ← (byte) 'a'
[1] (byte) bar_thing2#0 ← (byte) 'b'
to:@1
@1: scope:[] from @begin
[2] phi()
[3] call main
to:@end
@end: scope:[] from @1
[4] phi()
(void()) main()
main: scope:[main] from @1
[5] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr)
[6] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0)
[7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2)
to:main::@return
main::@return: scope:[main] from main
[8] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte) bar_thing1
(byte) bar_thing1#0 20.0
(byte) bar_thing2
(byte) bar_thing2#0 20.0
(byte) foo::thing1
(byte) foo::thing2
(void()) main()
(struct foo*) main::barp
(struct foo*) main::barp#0 1.0
(byte) main::i
Initial phi equivalence classes
Added variable main::barp#0 to zero page equivalence class [ main::barp#0 ]
Complete equivalence classes
[ bar_thing1#0 ]
[ bar_thing2#0 ]
[ main::barp#0 ]
Allocated zp ZP_BYTE:2 [ bar_thing1#0 ]
Allocated zp ZP_BYTE:3 [ bar_thing2#0 ]
Allocated zp ZP_WORD:4 [ main::barp#0 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
// Test a memory variable struct value
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_FOO_THING2 = 1
.label bar_ptr = bar_thing1
.label bar_thing1 = 2
.label bar_thing2 = 3
// @begin
__bbegin:
// [0] (byte) bar_thing1#0 ← (byte) 'a' -- vbuz1=vbuc1
lda #'a'
sta.z bar_thing1
// [1] (byte) bar_thing2#0 ← (byte) 'b' -- vbuz1=vbuc1
lda #'b'
sta.z bar_thing2
// [2] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [3] call main
jsr main
// [4] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
.label SCREEN = $400
.label barp = 4
// [5] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) -- pssz1=_addr__deref_pssc1
lda #<bar_ptr
sta.z barp
lda #>bar_ptr
sta.z barp+1
// [6] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuz1
ldy #0
lda (barp),y
sta SCREEN
// [7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_FOO_THING2
lda (barp),y
sta SCREEN+1
jmp __breturn
// main::@return
__breturn:
// [8] return
rts
}
// File Data
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] (byte) bar_thing1#0 ← (byte) 'a' [ ] ( [ ] ) always clobbers reg byte a
Statement [1] (byte) bar_thing2#0 ← (byte) 'b' [ ] ( [ ] ) always clobbers reg byte a
Statement [5] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) [ main::barp#0 ] ( main:3 [ main::barp#0 ] ) always clobbers reg byte a
Statement [6] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) [ main::barp#0 ] ( main:3 [ main::barp#0 ] ) always clobbers reg byte a reg byte y
Statement [7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) [ ] ( main:3 [ ] ) always clobbers reg byte a reg byte y
Potential registers zp ZP_BYTE:2 [ bar_thing1#0 ] : zp ZP_BYTE:2 ,
Potential registers zp ZP_BYTE:3 [ bar_thing2#0 ] : zp ZP_BYTE:3 ,
Potential registers zp ZP_WORD:4 [ main::barp#0 ] : zp ZP_WORD:4 ,
REGISTER UPLIFT SCOPES
Uplift Scope [] 20: zp ZP_BYTE:2 [ bar_thing1#0 ] 20: zp ZP_BYTE:3 [ bar_thing2#0 ]
Uplift Scope [main] 1: zp ZP_WORD:4 [ main::barp#0 ]
Uplift Scope [foo]
Uplifting [] best 63 combination zp ZP_BYTE:2 [ bar_thing1#0 ] zp ZP_BYTE:3 [ bar_thing2#0 ]
Uplifting [main] best 63 combination zp ZP_WORD:4 [ main::barp#0 ]
Uplifting [foo] best 63 combination
Attempting to uplift remaining variables inzp ZP_BYTE:2 [ bar_thing1#0 ]
Uplifting [] best 63 combination zp ZP_BYTE:2 [ bar_thing1#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:3 [ bar_thing2#0 ]
Uplifting [] best 63 combination zp ZP_BYTE:3 [ bar_thing2#0 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
// Test a memory variable struct value
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_FOO_THING2 = 1
.label bar_ptr = bar_thing1
.label bar_thing1 = 2
.label bar_thing2 = 3
// @begin
__bbegin:
// [0] (byte) bar_thing1#0 ← (byte) 'a' -- vbuz1=vbuc1
lda #'a'
sta.z bar_thing1
// [1] (byte) bar_thing2#0 ← (byte) 'b' -- vbuz1=vbuc1
lda #'b'
sta.z bar_thing2
// [2] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [3] call main
jsr main
// [4] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
.label SCREEN = $400
.label barp = 4
// [5] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) -- pssz1=_addr__deref_pssc1
lda #<bar_ptr
sta.z barp
lda #>bar_ptr
sta.z barp+1
// [6] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuz1
ldy #0
lda (barp),y
sta SCREEN
// [7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_FOO_THING2
lda (barp),y
sta SCREEN+1
jmp __breturn
// main::@return
__breturn:
// [8] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __bend
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __b1_from___bbegin:
Removing instruction __bend_from___b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __b1:
Removing instruction __bend:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_FOO_THING2 OFFSET_STRUCT_FOO_THING2 = (byte) 1
(const struct foo*) bar_ptr bar_ptr = (struct foo*)&(byte) bar_thing1#0
(byte) bar_thing1
(byte) bar_thing1#0 bar_thing1 zp ZP_BYTE:2 20.0
(byte) bar_thing2
(byte) bar_thing2#0 bar_thing2 zp ZP_BYTE:3 20.0
(byte) foo::thing1
(byte) foo::thing2
(void()) main()
(label) main::@return
(const byte*) main::SCREEN SCREEN = (byte*) 1024
(struct foo*) main::barp
(struct foo*) main::barp#0 barp zp ZP_WORD:4 1.0
(byte) main::i
zp ZP_BYTE:2 [ bar_thing1#0 ]
zp ZP_BYTE:3 [ bar_thing2#0 ]
zp ZP_WORD:4 [ main::barp#0 ]
FINAL ASSEMBLER
Score: 60
// File Comments
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
// Test a memory variable struct value
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_FOO_THING2 = 1
.label bar_ptr = bar_thing1
.label bar_thing1 = 2
.label bar_thing2 = 3
// @begin
__bbegin:
// bar = { 'a', 'b' }
// [0] (byte) bar_thing1#0 ← (byte) 'a' -- vbuz1=vbuc1
lda #'a'
sta.z bar_thing1
// [1] (byte) bar_thing2#0 ← (byte) 'b' -- vbuz1=vbuc1
lda #'b'
sta.z bar_thing2
// [2] phi from @begin to @1 [phi:@begin->@1]
// @1
// [3] call main
jsr main
rts
// [4] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
.label SCREEN = $400
.label barp = 4
// barp = &bar
// [5] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) -- pssz1=_addr__deref_pssc1
lda #<bar_ptr
sta.z barp
lda #>bar_ptr
sta.z barp+1
// SCREEN[i++] = barp->thing1
// [6] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuz1
ldy #0
lda (barp),y
sta SCREEN
// SCREEN[i++] = barp->thing2
// [7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_FOO_THING2
lda (barp),y
sta SCREEN+1
// main::@return
// }
// [8] return
rts
}
// File Data

View File

@ -0,0 +1,21 @@
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_FOO_THING2 OFFSET_STRUCT_FOO_THING2 = (byte) 1
(const struct foo*) bar_ptr bar_ptr = (struct foo*)&(byte) bar_thing1#0
(byte) bar_thing1
(byte) bar_thing1#0 bar_thing1 zp ZP_BYTE:2 20.0
(byte) bar_thing2
(byte) bar_thing2#0 bar_thing2 zp ZP_BYTE:3 20.0
(byte) foo::thing1
(byte) foo::thing2
(void()) main()
(label) main::@return
(const byte*) main::SCREEN SCREEN = (byte*) 1024
(struct foo*) main::barp
(struct foo*) main::barp#0 barp zp ZP_WORD:4 1.0
(byte) main::i
zp ZP_BYTE:2 [ bar_thing1#0 ]
zp ZP_BYTE:3 [ bar_thing2#0 ]
zp ZP_WORD:4 [ main::barp#0 ]

View File

@ -0,0 +1,56 @@
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
// Test a memory variable struct value - containing a fixed size array
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
.const OFFSET_STRUCT_FOO_THING2 = 1
.const OFFSET_STRUCT_FOO_THING3 = 2
.label bar_ptr = bar_thing1
.label bar_thing1 = 2
.label bar_thing2 = 3
.label bar_thing3 = 4
__bbegin:
lda #'a'
sta.z bar_thing1
lda #'b'
sta.z bar_thing2
lda #<__0
sta.z bar_thing3
lda #>__0
sta.z bar_thing3+1
jsr main
rts
main: {
.label SCREEN = $400
.label __4 = 8
.label barp = 6
lda #<bar_ptr
sta.z barp
lda #>bar_ptr
sta.z barp+1
ldy #0
lda (barp),y
sta SCREEN
ldy #OFFSET_STRUCT_FOO_THING2
lda (barp),y
sta SCREEN+1
ldx #2
ldy #0
__b1:
lda #OFFSET_STRUCT_FOO_THING3
clc
adc.z barp
sta.z __4
lda #0
adc.z barp+1
sta.z __4+1
lda (__4),y
sta SCREEN,x
inx
iny
cpy #$c
bne __b1
rts
}
__0: .text "qwe"
.byte 0

View File

@ -0,0 +1,30 @@
@begin: scope:[] from
[0] (byte) bar_thing1#0 ← (byte) 'a'
[1] (byte) bar_thing2#0 ← (byte) 'b'
[2] (byte[$c]) bar_thing3#0 ← (const string) $0
to:@1
@1: scope:[] from @begin
[3] phi()
[4] call main
to:@end
@end: scope:[] from @1
[5] phi()
(void()) main()
main: scope:[main] from @1
[6] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr)
[7] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0)
[8] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2)
to:main::@1
main::@1: scope:[main] from main main::@1
[9] (byte) main::i#4 ← phi( main/(byte) 2 main::@1/(byte) main::i#3 )
[9] (byte) main::j#2 ← phi( main/(byte) 0 main::@1/(byte) main::j#1 )
[10] (byte[$c]) main::$4 ← (byte[$c])(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING3
[11] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c]) main::$4 + (byte) main::j#2)
[12] (byte) main::i#3 ← ++ (byte) main::i#4
[13] (byte) main::j#1 ← ++ (byte) main::j#2
[14] if((byte) main::j#1!=(byte) $c) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[15] return
to:@return

View File

@ -0,0 +1,673 @@
Fixing struct type size struct foo to 14
Fixing struct type size struct foo to 14
Setting inferred volatile on symbol affected by address-of (struct foo*~) main::$0 ← & (struct foo) bar
Created struct value member variable (byte) bar_thing1
Created struct value member variable (byte) bar_thing2
Created struct value member variable (byte[$c]) bar_thing3
Converted struct value to member variables (struct foo) bar
Adding struct value list initializer (byte) bar_thing1 ← (byte) 'a'
Adding struct value list initializer (byte) bar_thing2 ← (byte) 'b'
Adding struct value list initializer (byte[$c]) bar_thing3 ← (string) "qwe"
Rewriting struct pointer member access *((struct foo*) main::barp).thing1
Rewriting struct pointer member access *((struct foo*) main::barp).thing2
Rewriting struct pointer member access *((struct foo*) main::barp).thing3
Culled Empty Block (label) main::@2
Adding memory variable constant pointer (const struct foo*) bar_ptr
Updating memory variable reference *((const struct foo*) bar_ptr)
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte) bar_thing1#0 ← (byte) 'a'
(byte) bar_thing2#0 ← (byte) 'b'
(byte[$c]) bar_thing3#0 ← (const string) $0
(struct foo) bar ← struct-unwound {(byte) bar_thing1#0, (byte) bar_thing2#0, (byte[$c]) bar_thing3#0}
to:@1
(void()) main()
main: scope:[main] from @1
(struct foo*~) main::$0 ← & *((const struct foo*) bar_ptr)
(struct foo*) main::barp#0 ← (struct foo*~) main::$0
(byte*) main::SCREEN ← ((byte*)) (number) $400
(byte) main::i#0 ← (number) 0
(byte*) main::$2 ← (byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING1
*((byte*) main::SCREEN + (byte) main::i#0) ← *((byte*) main::$2)
(byte) main::i#1 ← ++ (byte) main::i#0
(byte*) main::$3 ← (byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2
*((byte*) main::SCREEN + (byte) main::i#1) ← *((byte*) main::$3)
(byte) main::i#2 ← ++ (byte) main::i#1
(byte) main::j#0 ← (byte) 0
to:main::@1
main::@1: scope:[main] from main main::@1
(byte) main::i#4 ← phi( main/(byte) main::i#2 main::@1/(byte) main::i#3 )
(byte) main::j#2 ← phi( main/(byte) main::j#0 main::@1/(byte) main::j#1 )
(struct foo*) main::barp#1 ← phi( main/(struct foo*) main::barp#0 main::@1/(struct foo*) main::barp#1 )
(byte[$c]) main::$4 ← (byte[$c])(struct foo*) main::barp#1 + (const byte) OFFSET_STRUCT_FOO_THING3
*((byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c]) main::$4 + (byte) main::j#2)
(byte) main::i#3 ← ++ (byte) main::i#4
(byte) main::j#1 ← (byte) main::j#2 + rangenext(0,$b)
(bool~) main::$1 ← (byte) main::j#1 != rangelast(0,$b)
if((bool~) main::$1) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
@1: scope:[] from @begin
call main
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(const string) $0 = (string) "qwe"
(label) @1
(label) @2
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_FOO_THING1 = (byte) 0
(const byte) OFFSET_STRUCT_FOO_THING2 = (byte) 1
(const byte) OFFSET_STRUCT_FOO_THING3 = (byte) 2
(struct foo) bar memory
(const struct foo*) bar_ptr = &(struct foo) bar
(byte) bar_thing1
(byte) bar_thing1#0
(byte) bar_thing2
(byte) bar_thing2#0
(byte[$c]) bar_thing3
(byte[$c]) bar_thing3#0
(byte) foo::thing1
(byte) foo::thing2
(byte[$c]) foo::thing3
(void()) main()
(struct foo*~) main::$0
(bool~) main::$1
(byte*) main::$2
(byte*) main::$3
(byte[$c]) main::$4
(label) main::@1
(label) main::@return
(byte*) main::SCREEN
(struct foo*) main::barp
(struct foo*) main::barp#0
(struct foo*) main::barp#1
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte) main::i#3
(byte) main::i#4
(byte) main::j
(byte) main::j#0
(byte) main::j#1
(byte) main::j#2
Adding number conversion cast (unumber) 0 in (byte) main::i#0 ← (number) 0
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (byte*) main::SCREEN ← (byte*)(number) $400
Inlining cast (byte) main::i#0 ← (unumber)(number) 0
Successful SSA optimization Pass2InlineCast
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
Alias (struct foo*) main::barp#0 = (struct foo*~) main::$0
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (struct foo*) main::barp#1 (struct foo*) main::barp#0
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition (bool~) main::$1 [21] if((byte) main::j#1!=rangelast(0,$b)) goto main::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Rewriting struct address-of to first member &(struct foo) bar
Successful SSA optimization PassNStructAddressOfRewriting
Constant (const byte*) main::SCREEN = (byte*) 1024
Constant (const byte) main::i#0 = 0
Constant (const byte) main::j#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Resolved ranged next value [19] main::j#1 ← ++ main::j#2 to ++
Resolved ranged comparison value [21] if(main::j#1!=rangelast(0,$b)) goto main::@1 to (number) $c
Converting *(pointer+n) to pointer[n] [9] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*) main::$2) -- *((byte*)main::barp#0 + OFFSET_STRUCT_FOO_THING1)
Converting *(pointer+n) to pointer[n] [12] *((const byte*) main::SCREEN + (byte) main::i#1) ← *((byte*) main::$3) -- *((byte*)main::barp#0 + OFFSET_STRUCT_FOO_THING2)
Successful SSA optimization Pass2InlineDerefIdx
Simplifying expression containing zero (byte*)main::barp#0 in [8] (byte*) main::$2 ← (byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING1
Simplifying expression containing zero (byte*)main::barp#0 in [9] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING1)
Simplifying expression containing zero main::SCREEN in [9] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*)(struct foo*) main::barp#0)
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable (struct foo) bar and assignment [3] (struct foo) bar ← struct-unwound {(byte) bar_thing1#0, (byte) bar_thing2#0, (byte[$c]) bar_thing3#0}
Eliminating unused variable (byte*) main::$2 and assignment [5] (byte*) main::$2 ← (byte*)(struct foo*) main::barp#0
Eliminating unused variable (byte*) main::$3 and assignment [8] (byte*) main::$3 ← (byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2
Eliminating unused constant (const byte) OFFSET_STRUCT_FOO_THING1
Successful SSA optimization PassNEliminateUnusedVars
Adding number conversion cast (unumber) $c in if((byte) main::j#1!=(number) $c) goto main::@1
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast $c
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) $c
Successful SSA optimization PassNFinalizeNumberTypeConversions
Constant right-side identified [5] (byte) main::i#1 ← ++ (const byte) main::i#0
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte) main::i#1 = ++main::i#0
Successful SSA optimization Pass2ConstantIdentification
Constant right-side identified [6] (byte) main::i#2 ← ++ (const byte) main::i#1
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte) main::i#2 = ++main::i#1
Successful SSA optimization Pass2ConstantIdentification
Inlining constant with var siblings (const byte) main::i#0
Inlining constant with var siblings (const byte) main::j#0
Inlining constant with var siblings (const byte) main::i#1
Inlining constant with var siblings (const byte) main::i#2
Constant inlined main::i#0 = (byte) 0
Constant inlined main::i#2 = ++++(byte) 0
Constant inlined main::j#0 = (byte) 0
Constant inlined main::i#1 = ++(byte) 0
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *(main::SCREEN+++0)
Successful SSA optimization Pass2ConstantAdditionElimination
Simplifying constant integer increment ++0
Simplifying constant integer increment ++0
Successful SSA optimization Pass2ConstantSimplification
Simplifying constant integer increment ++1
Successful SSA optimization Pass2ConstantSimplification
Added new block during phi lifting main::@3(between main::@1 and main::@1)
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:4
Created 2 initial phi equivalence classes
Coalesced [17] main::j#3 ← main::j#1
Coalesced [18] main::i#5 ← main::i#3
Coalesced down to 2 phi equivalence classes
Culled Empty Block (label) @2
Culled Empty Block (label) main::@3
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] (byte) bar_thing1#0 ← (byte) 'a'
[1] (byte) bar_thing2#0 ← (byte) 'b'
[2] (byte[$c]) bar_thing3#0 ← (const string) $0
to:@1
@1: scope:[] from @begin
[3] phi()
[4] call main
to:@end
@end: scope:[] from @1
[5] phi()
(void()) main()
main: scope:[main] from @1
[6] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr)
[7] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0)
[8] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2)
to:main::@1
main::@1: scope:[main] from main main::@1
[9] (byte) main::i#4 ← phi( main/(byte) 2 main::@1/(byte) main::i#3 )
[9] (byte) main::j#2 ← phi( main/(byte) 0 main::@1/(byte) main::j#1 )
[10] (byte[$c]) main::$4 ← (byte[$c])(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING3
[11] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c]) main::$4 + (byte) main::j#2)
[12] (byte) main::i#3 ← ++ (byte) main::i#4
[13] (byte) main::j#1 ← ++ (byte) main::j#2
[14] if((byte) main::j#1!=(byte) $c) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[15] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte) bar_thing1
(byte) bar_thing1#0 20.0
(byte) bar_thing2
(byte) bar_thing2#0 20.0
(byte[$c]) bar_thing3
(byte[$c]) bar_thing3#0 20.0
(byte) foo::thing1
(byte) foo::thing2
(byte[$c]) foo::thing3
(void()) main()
(byte[$c]) main::$4 22.0
(struct foo*) main::barp
(struct foo*) main::barp#0 0.2222222222222222
(byte) main::i
(byte) main::i#3 7.333333333333333
(byte) main::i#4 11.0
(byte) main::j
(byte) main::j#1 16.5
(byte) main::j#2 8.25
Initial phi equivalence classes
[ main::j#2 main::j#1 ]
[ main::i#4 main::i#3 ]
Added variable main::barp#0 to zero page equivalence class [ main::barp#0 ]
Added variable main::$4 to zero page equivalence class [ main::$4 ]
Complete equivalence classes
[ main::j#2 main::j#1 ]
[ main::i#4 main::i#3 ]
[ bar_thing1#0 ]
[ bar_thing2#0 ]
[ bar_thing3#0 ]
[ main::barp#0 ]
[ main::$4 ]
Allocated zp ZP_BYTE:2 [ main::j#2 main::j#1 ]
Allocated zp ZP_BYTE:3 [ main::i#4 main::i#3 ]
Allocated zp ZP_BYTE:4 [ bar_thing1#0 ]
Allocated zp ZP_BYTE:5 [ bar_thing2#0 ]
Allocated zp ZP_WORD:6 [ bar_thing3#0 ]
Allocated zp ZP_WORD:8 [ main::barp#0 ]
Allocated zp ZP_WORD:10 [ main::$4 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
// Test a memory variable struct value - containing a fixed size array
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_FOO_THING2 = 1
.const OFFSET_STRUCT_FOO_THING3 = 2
.label bar_ptr = bar_thing1
.label bar_thing1 = 4
.label bar_thing2 = 5
.label bar_thing3 = 6
// @begin
__bbegin:
// [0] (byte) bar_thing1#0 ← (byte) 'a' -- vbuz1=vbuc1
lda #'a'
sta.z bar_thing1
// [1] (byte) bar_thing2#0 ← (byte) 'b' -- vbuz1=vbuc1
lda #'b'
sta.z bar_thing2
// [2] (byte[$c]) bar_thing3#0 ← (const string) $0 -- pbuz1=pbuc1
lda #<__0
sta.z bar_thing3
lda #>__0
sta.z bar_thing3+1
// [3] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [4] call main
jsr main
// [5] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
.label SCREEN = $400
.label __4 = $a
.label barp = 8
.label i = 3
.label j = 2
// [6] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) -- pssz1=_addr__deref_pssc1
lda #<bar_ptr
sta.z barp
lda #>bar_ptr
sta.z barp+1
// [7] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuz1
ldy #0
lda (barp),y
sta SCREEN
// [8] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_FOO_THING2
lda (barp),y
sta SCREEN+1
// [9] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [9] phi (byte) main::i#4 = (byte) 2 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #2
sta.z i
// [9] phi (byte) main::j#2 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1
lda #0
sta.z j
jmp __b1
// [9] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
__b1_from___b1:
// [9] phi (byte) main::i#4 = (byte) main::i#3 [phi:main::@1->main::@1#0] -- register_copy
// [9] phi (byte) main::j#2 = (byte) main::j#1 [phi:main::@1->main::@1#1] -- register_copy
jmp __b1
// main::@1
__b1:
// [10] (byte[$c]) main::$4 ← (byte[$c])(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING3 -- pbuz1=pbuz2_plus_vbuc1
lda #OFFSET_STRUCT_FOO_THING3
clc
adc.z barp
sta.z __4
lda #0
adc.z barp+1
sta.z __4+1
// [11] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c]) main::$4 + (byte) main::j#2) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuz3
ldx.z i
ldy.z j
lda (__4),y
sta SCREEN,x
// [12] (byte) main::i#3 ← ++ (byte) main::i#4 -- vbuz1=_inc_vbuz1
inc.z i
// [13] (byte) main::j#1 ← ++ (byte) main::j#2 -- vbuz1=_inc_vbuz1
inc.z j
// [14] if((byte) main::j#1!=(byte) $c) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #$c
cmp.z j
bne __b1_from___b1
jmp __breturn
// main::@return
__breturn:
// [15] return
rts
}
// File Data
__0: .text "qwe"
.byte 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] (byte) bar_thing1#0 ← (byte) 'a' [ ] ( [ ] ) always clobbers reg byte a
Statement [1] (byte) bar_thing2#0 ← (byte) 'b' [ ] ( [ ] ) always clobbers reg byte a
Statement [2] (byte[$c]) bar_thing3#0 ← (const string) $0 [ ] ( [ ] ) always clobbers reg byte a
Statement [6] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) [ main::barp#0 ] ( main:4 [ main::barp#0 ] ) always clobbers reg byte a
Statement [7] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) [ main::barp#0 ] ( main:4 [ main::barp#0 ] ) always clobbers reg byte a reg byte y
Statement [8] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) [ main::barp#0 ] ( main:4 [ main::barp#0 ] ) always clobbers reg byte a reg byte y
Statement [10] (byte[$c]) main::$4 ← (byte[$c])(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING3 [ main::barp#0 main::j#2 main::i#4 main::$4 ] ( main:4 [ main::barp#0 main::j#2 main::i#4 main::$4 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::j#2 main::j#1 ]
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::i#4 main::i#3 ]
Statement [11] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c]) main::$4 + (byte) main::j#2) [ main::barp#0 main::j#2 main::i#4 ] ( main:4 [ main::barp#0 main::j#2 main::i#4 ] ) always clobbers reg byte a
Statement [0] (byte) bar_thing1#0 ← (byte) 'a' [ ] ( [ ] ) always clobbers reg byte a
Statement [1] (byte) bar_thing2#0 ← (byte) 'b' [ ] ( [ ] ) always clobbers reg byte a
Statement [2] (byte[$c]) bar_thing3#0 ← (const string) $0 [ ] ( [ ] ) always clobbers reg byte a
Statement [6] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) [ main::barp#0 ] ( main:4 [ main::barp#0 ] ) always clobbers reg byte a
Statement [7] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) [ main::barp#0 ] ( main:4 [ main::barp#0 ] ) always clobbers reg byte a reg byte y
Statement [8] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) [ main::barp#0 ] ( main:4 [ main::barp#0 ] ) always clobbers reg byte a reg byte y
Statement [10] (byte[$c]) main::$4 ← (byte[$c])(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING3 [ main::barp#0 main::j#2 main::i#4 main::$4 ] ( main:4 [ main::barp#0 main::j#2 main::i#4 main::$4 ] ) always clobbers reg byte a
Statement [11] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c]) main::$4 + (byte) main::j#2) [ main::barp#0 main::j#2 main::i#4 ] ( main:4 [ main::barp#0 main::j#2 main::i#4 ] ) always clobbers reg byte a
Potential registers zp ZP_BYTE:2 [ main::j#2 main::j#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:3 [ main::i#4 main::i#3 ] : zp ZP_BYTE:3 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:4 [ bar_thing1#0 ] : zp ZP_BYTE:4 ,
Potential registers zp ZP_BYTE:5 [ bar_thing2#0 ] : zp ZP_BYTE:5 ,
Potential registers zp ZP_WORD:6 [ bar_thing3#0 ] : zp ZP_WORD:6 ,
Potential registers zp ZP_WORD:8 [ main::barp#0 ] : zp ZP_WORD:8 ,
Potential registers zp ZP_WORD:10 [ main::$4 ] : zp ZP_WORD:10 ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 24.75: zp ZP_BYTE:2 [ main::j#2 main::j#1 ] 22: zp ZP_WORD:10 [ main::$4 ] 18.33: zp ZP_BYTE:3 [ main::i#4 main::i#3 ] 0.22: zp ZP_WORD:8 [ main::barp#0 ]
Uplift Scope [] 20: zp ZP_BYTE:4 [ bar_thing1#0 ] 20: zp ZP_BYTE:5 [ bar_thing2#0 ] 20: zp ZP_WORD:6 [ bar_thing3#0 ]
Uplift Scope [foo]
Uplifting [main] best 570 combination reg byte y [ main::j#2 main::j#1 ] zp ZP_WORD:10 [ main::$4 ] reg byte x [ main::i#4 main::i#3 ] zp ZP_WORD:8 [ main::barp#0 ]
Uplifting [] best 570 combination zp ZP_BYTE:4 [ bar_thing1#0 ] zp ZP_BYTE:5 [ bar_thing2#0 ] zp ZP_WORD:6 [ bar_thing3#0 ]
Uplifting [foo] best 570 combination
Attempting to uplift remaining variables inzp ZP_BYTE:4 [ bar_thing1#0 ]
Uplifting [] best 570 combination zp ZP_BYTE:4 [ bar_thing1#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:5 [ bar_thing2#0 ]
Uplifting [] best 570 combination zp ZP_BYTE:5 [ bar_thing2#0 ]
Allocated (was zp ZP_BYTE:4) zp ZP_BYTE:2 [ bar_thing1#0 ]
Allocated (was zp ZP_BYTE:5) zp ZP_BYTE:3 [ bar_thing2#0 ]
Allocated (was zp ZP_WORD:6) zp ZP_WORD:4 [ bar_thing3#0 ]
Allocated (was zp ZP_WORD:8) zp ZP_WORD:6 [ main::barp#0 ]
Allocated (was zp ZP_WORD:10) zp ZP_WORD:8 [ main::$4 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
// Test a memory variable struct value - containing a fixed size array
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_FOO_THING2 = 1
.const OFFSET_STRUCT_FOO_THING3 = 2
.label bar_ptr = bar_thing1
.label bar_thing1 = 2
.label bar_thing2 = 3
.label bar_thing3 = 4
// @begin
__bbegin:
// [0] (byte) bar_thing1#0 ← (byte) 'a' -- vbuz1=vbuc1
lda #'a'
sta.z bar_thing1
// [1] (byte) bar_thing2#0 ← (byte) 'b' -- vbuz1=vbuc1
lda #'b'
sta.z bar_thing2
// [2] (byte[$c]) bar_thing3#0 ← (const string) $0 -- pbuz1=pbuc1
lda #<__0
sta.z bar_thing3
lda #>__0
sta.z bar_thing3+1
// [3] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [4] call main
jsr main
// [5] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
.label SCREEN = $400
.label __4 = 8
.label barp = 6
// [6] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) -- pssz1=_addr__deref_pssc1
lda #<bar_ptr
sta.z barp
lda #>bar_ptr
sta.z barp+1
// [7] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuz1
ldy #0
lda (barp),y
sta SCREEN
// [8] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_FOO_THING2
lda (barp),y
sta SCREEN+1
// [9] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [9] phi (byte) main::i#4 = (byte) 2 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #2
// [9] phi (byte) main::j#2 = (byte) 0 [phi:main->main::@1#1] -- vbuyy=vbuc1
ldy #0
jmp __b1
// [9] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
__b1_from___b1:
// [9] phi (byte) main::i#4 = (byte) main::i#3 [phi:main::@1->main::@1#0] -- register_copy
// [9] phi (byte) main::j#2 = (byte) main::j#1 [phi:main::@1->main::@1#1] -- register_copy
jmp __b1
// main::@1
__b1:
// [10] (byte[$c]) main::$4 ← (byte[$c])(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING3 -- pbuz1=pbuz2_plus_vbuc1
lda #OFFSET_STRUCT_FOO_THING3
clc
adc.z barp
sta.z __4
lda #0
adc.z barp+1
sta.z __4+1
// [11] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c]) main::$4 + (byte) main::j#2) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuyy
lda (__4),y
sta SCREEN,x
// [12] (byte) main::i#3 ← ++ (byte) main::i#4 -- vbuxx=_inc_vbuxx
inx
// [13] (byte) main::j#1 ← ++ (byte) main::j#2 -- vbuyy=_inc_vbuyy
iny
// [14] if((byte) main::j#1!=(byte) $c) goto main::@1 -- vbuyy_neq_vbuc1_then_la1
cpy #$c
bne __b1_from___b1
jmp __breturn
// main::@return
__breturn:
// [15] return
rts
}
// File Data
__0: .text "qwe"
.byte 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __bend
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing label __b1_from___b1 with __b1
Removing instruction __b1_from___bbegin:
Removing instruction __bend_from___b1:
Removing instruction __b1_from___b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __b1:
Removing instruction __bend:
Removing instruction __b1_from_main:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
Removing instruction jmp __b1
Succesful ASM optimization Pass5NextJumpElimination
FINAL SYMBOL TABLE
(const string) $0 $0 = (string) "qwe"
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_FOO_THING2 OFFSET_STRUCT_FOO_THING2 = (byte) 1
(const byte) OFFSET_STRUCT_FOO_THING3 OFFSET_STRUCT_FOO_THING3 = (byte) 2
(const struct foo*) bar_ptr bar_ptr = (struct foo*)&(byte) bar_thing1#0
(byte) bar_thing1
(byte) bar_thing1#0 bar_thing1 zp ZP_BYTE:2 20.0
(byte) bar_thing2
(byte) bar_thing2#0 bar_thing2 zp ZP_BYTE:3 20.0
(byte[$c]) bar_thing3
(byte[$c]) bar_thing3#0 bar_thing3 zp ZP_WORD:4 20.0
(byte) foo::thing1
(byte) foo::thing2
(byte[$c]) foo::thing3
(void()) main()
(byte[$c]) main::$4 $4 zp ZP_WORD:8 22.0
(label) main::@1
(label) main::@return
(const byte*) main::SCREEN SCREEN = (byte*) 1024
(struct foo*) main::barp
(struct foo*) main::barp#0 barp zp ZP_WORD:6 0.2222222222222222
(byte) main::i
(byte) main::i#3 reg byte x 7.333333333333333
(byte) main::i#4 reg byte x 11.0
(byte) main::j
(byte) main::j#1 reg byte y 16.5
(byte) main::j#2 reg byte y 8.25
reg byte y [ main::j#2 main::j#1 ]
reg byte x [ main::i#4 main::i#3 ]
zp ZP_BYTE:2 [ bar_thing1#0 ]
zp ZP_BYTE:3 [ bar_thing2#0 ]
zp ZP_WORD:4 [ bar_thing3#0 ]
zp ZP_WORD:6 [ main::barp#0 ]
zp ZP_WORD:8 [ main::$4 ]
FINAL ASSEMBLER
Score: 480
// File Comments
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
// Test a memory variable struct value - containing a fixed size array
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_FOO_THING2 = 1
.const OFFSET_STRUCT_FOO_THING3 = 2
.label bar_ptr = bar_thing1
.label bar_thing1 = 2
.label bar_thing2 = 3
.label bar_thing3 = 4
// @begin
__bbegin:
// bar = { 'a', 'b', "qwe" }
// [0] (byte) bar_thing1#0 ← (byte) 'a' -- vbuz1=vbuc1
lda #'a'
sta.z bar_thing1
// [1] (byte) bar_thing2#0 ← (byte) 'b' -- vbuz1=vbuc1
lda #'b'
sta.z bar_thing2
// [2] (byte[$c]) bar_thing3#0 ← (const string) $0 -- pbuz1=pbuc1
lda #<__0
sta.z bar_thing3
lda #>__0
sta.z bar_thing3+1
// [3] phi from @begin to @1 [phi:@begin->@1]
// @1
// [4] call main
jsr main
rts
// [5] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
.label SCREEN = $400
.label __4 = 8
.label barp = 6
// barp = &bar
// [6] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) -- pssz1=_addr__deref_pssc1
lda #<bar_ptr
sta.z barp
lda #>bar_ptr
sta.z barp+1
// SCREEN[i++] = barp->thing1
// [7] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuz1
ldy #0
lda (barp),y
sta SCREEN
// SCREEN[i++] = barp->thing2
// [8] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_FOO_THING2
lda (barp),y
sta SCREEN+1
// [9] phi from main to main::@1 [phi:main->main::@1]
// [9] phi (byte) main::i#4 = (byte) 2 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #2
// [9] phi (byte) main::j#2 = (byte) 0 [phi:main->main::@1#1] -- vbuyy=vbuc1
ldy #0
// [9] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [9] phi (byte) main::i#4 = (byte) main::i#3 [phi:main::@1->main::@1#0] -- register_copy
// [9] phi (byte) main::j#2 = (byte) main::j#1 [phi:main::@1->main::@1#1] -- register_copy
// main::@1
__b1:
// SCREEN[i++] = barp->thing3[j]
// [10] (byte[$c]) main::$4 ← (byte[$c])(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING3 -- pbuz1=pbuz2_plus_vbuc1
lda #OFFSET_STRUCT_FOO_THING3
clc
adc.z barp
sta.z __4
lda #0
adc.z barp+1
sta.z __4+1
// [11] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c]) main::$4 + (byte) main::j#2) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuyy
lda (__4),y
sta SCREEN,x
// SCREEN[i++] = barp->thing3[j];
// [12] (byte) main::i#3 ← ++ (byte) main::i#4 -- vbuxx=_inc_vbuxx
inx
// for( char j: 0..11)
// [13] (byte) main::j#1 ← ++ (byte) main::j#2 -- vbuyy=_inc_vbuyy
iny
// [14] if((byte) main::j#1!=(byte) $c) goto main::@1 -- vbuyy_neq_vbuc1_then_la1
cpy #$c
bne __b1
// main::@return
// }
// [15] return
rts
}
// File Data
__0: .text "qwe"
.byte 0

View File

@ -0,0 +1,37 @@
(const string) $0 $0 = (string) "qwe"
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_FOO_THING2 OFFSET_STRUCT_FOO_THING2 = (byte) 1
(const byte) OFFSET_STRUCT_FOO_THING3 OFFSET_STRUCT_FOO_THING3 = (byte) 2
(const struct foo*) bar_ptr bar_ptr = (struct foo*)&(byte) bar_thing1#0
(byte) bar_thing1
(byte) bar_thing1#0 bar_thing1 zp ZP_BYTE:2 20.0
(byte) bar_thing2
(byte) bar_thing2#0 bar_thing2 zp ZP_BYTE:3 20.0
(byte[$c]) bar_thing3
(byte[$c]) bar_thing3#0 bar_thing3 zp ZP_WORD:4 20.0
(byte) foo::thing1
(byte) foo::thing2
(byte[$c]) foo::thing3
(void()) main()
(byte[$c]) main::$4 $4 zp ZP_WORD:8 22.0
(label) main::@1
(label) main::@return
(const byte*) main::SCREEN SCREEN = (byte*) 1024
(struct foo*) main::barp
(struct foo*) main::barp#0 barp zp ZP_WORD:6 0.2222222222222222
(byte) main::i
(byte) main::i#3 reg byte x 7.333333333333333
(byte) main::i#4 reg byte x 11.0
(byte) main::j
(byte) main::j#1 reg byte y 16.5
(byte) main::j#2 reg byte y 8.25
reg byte y [ main::j#2 main::j#1 ]
reg byte x [ main::i#4 main::i#3 ]
zp ZP_BYTE:2 [ bar_thing1#0 ]
zp ZP_BYTE:3 [ bar_thing2#0 ]
zp ZP_WORD:4 [ bar_thing3#0 ]
zp ZP_WORD:6 [ main::barp#0 ]
zp ZP_WORD:8 [ main::$4 ]

View File

@ -92,8 +92,6 @@ Simple Condition (bool~) main::$2 [10] if((byte) 0!=*((byte*) main::$3)) goto ma
Successful SSA optimization Pass2ConditionalJumpSimplification
Rewriting struct address-of to first member [4] (struct A*) main::a#0 ← (struct A*)&(byte) aa_b#0
Successful SSA optimization PassNStructAddressOfRewriting
Constant right-side identified [4] (struct A*) main::a#0 ← (struct A*)&(byte) aa_b#0
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte*) main::SCREEN = (byte*) 1024
Constant (const struct A*) main::a#0 = (struct A*)&aa_b#0
Successful SSA optimization Pass2ConstantIdentification

View File

@ -83,8 +83,6 @@ Alias (struct Point*) main::q#0 = (struct Point*~) main::$0
Successful SSA optimization Pass2AliasElimination
Rewriting struct address-of to first member [3] (struct Point*) main::q#0 ← (struct Point*)&(byte) main::p_x#0
Successful SSA optimization PassNStructAddressOfRewriting
Constant right-side identified [3] (struct Point*) main::q#0 ← (struct Point*)&(byte) main::p_x#0
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const struct Point*) main::q#0 = (struct Point*)&main::p_x#0
Constant (const byte*) main::SCREEN = (byte*) 1024
Successful SSA optimization Pass2ConstantIdentification

View File

@ -122,8 +122,6 @@ Identical Phi Values (struct Point*) set::ptr#1 (struct Point*) set::ptr#0
Successful SSA optimization Pass2IdenticalPhiElimination
Rewriting struct address-of to first member [3] (struct Point*) main::q#0 ← (struct Point*)&(byte) main::p_x#0
Successful SSA optimization PassNStructAddressOfRewriting
Constant right-side identified [3] (struct Point*) main::q#0 ← (struct Point*)&(byte) main::p_x#0
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const struct Point*) main::q#0 = (struct Point*)&main::p_x#0
Constant (const byte*) main::SCREEN = (byte*) 1024
Successful SSA optimization Pass2ConstantIdentification

View File

@ -167,8 +167,6 @@ Identical Phi Values (byte) idx#13 (byte) idx#10
Successful SSA optimization Pass2IdenticalPhiElimination
Rewriting struct address-of to first member [6] (struct Point*) main::ptr#0 ← (struct Point*)&(byte) main::point_x#0
Successful SSA optimization PassNStructAddressOfRewriting
Constant right-side identified [6] (struct Point*) main::ptr#0 ← (struct Point*)&(byte) main::point_x#0
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte*) SCREEN = (byte*) 1024
Constant (const byte) idx#0 = 0
Constant (const struct Point*) main::ptr#0 = (struct Point*)&main::point_x#0