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:
parent
624c27686c
commit
73854b7ee3
@ -0,0 +1,4 @@
|
||||
lda #<{c1}
|
||||
sta {z1}
|
||||
lda #>{c1}
|
||||
sta {z1}+1
|
@ -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()));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
18
src/test/kc/declared-memory-var-3.kc
Normal file
18
src/test/kc/declared-memory-var-3.kc
Normal 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;
|
||||
|
||||
}
|
21
src/test/kc/declared-memory-var-4.kc
Normal file
21
src/test/kc/declared-memory-var-4.kc
Normal 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];
|
||||
|
||||
}
|
31
src/test/ref/declared-memory-var-3.asm
Normal file
31
src/test/ref/declared-memory-var-3.asm
Normal 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
|
||||
}
|
20
src/test/ref/declared-memory-var-3.cfg
Normal file
20
src/test/ref/declared-memory-var-3.cfg
Normal 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
|
406
src/test/ref/declared-memory-var-3.log
Normal file
406
src/test/ref/declared-memory-var-3.log
Normal 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
|
||||
|
21
src/test/ref/declared-memory-var-3.sym
Normal file
21
src/test/ref/declared-memory-var-3.sym
Normal 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 ]
|
56
src/test/ref/declared-memory-var-4.asm
Normal file
56
src/test/ref/declared-memory-var-4.asm
Normal 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
|
30
src/test/ref/declared-memory-var-4.cfg
Normal file
30
src/test/ref/declared-memory-var-4.cfg
Normal 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
|
673
src/test/ref/declared-memory-var-4.log
Normal file
673
src/test/ref/declared-memory-var-4.log
Normal 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
|
||||
|
37
src/test/ref/declared-memory-var-4.sym
Normal file
37
src/test/ref/declared-memory-var-4.sym
Normal 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 ]
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user