1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-27 19:50:10 +00:00

Implemented memory variable data output. Initialization can still be optimized. #328

This commit is contained in:
Jesper Gravgaard 2019-09-26 14:35:02 +02:00
parent 5ddb1e9507
commit 5652a11131
10 changed files with 223 additions and 167 deletions

View File

@ -114,6 +114,7 @@ public class Compiler {
fileName = fileName.substring(0, fileName.length() - 3); fileName = fileName.substring(0, fileName.length() - 3);
} }
program.setFileName(fileName); program.setFileName(fileName);
initAsmFragmentSynthesizer(); initAsmFragmentSynthesizer();
try { try {
Path currentPath = new File(".").toPath(); Path currentPath = new File(".").toPath();

View File

@ -55,12 +55,12 @@ public abstract class SymbolVariable implements Symbol {
/** Strategy being used for storing and accessing the variable. The value depends on the directives memory/register/volatile/const - and on the compilers optimization decisions. /** Strategy being used for storing and accessing the variable. The value depends on the directives memory/register/volatile/const - and on the compilers optimization decisions.
* <ul> * <ul>
* <li>REGISTER-variables are turned into versions and PHI-nodes are used for them throughout the entire program. They cannot be "volatile" and the "address-of" operator cannot be used on them.</li> * <li>PHI_REGISTER-variables are turned into versions and PHI-nodes are used for them throughout the entire program. They cannot be "volatile" and the "address-of" operator cannot be used on them.</li>
* <li>MEMORY-variables are stored in memory and accessed through load/store operators. They cannot be declared as "register".</li> * <li>MEMORY-variables are stored in memory and accessed through load/store operators. They cannot be declared as "register".</li>
* <li>CONSTANT-variables are constant. * <li>CONSTANT-variables are constant.
* </ul> * </ul>
**/ **/
public enum StorageStrategy { REGISTER, MEMORY, CONSTANT } public enum StorageStrategy {PHI_REGISTER, MEMORY, CONSTANT }
/** The storage strategy for the variable. */ /** The storage strategy for the variable. */
private StorageStrategy storageStrategy; private StorageStrategy storageStrategy;
@ -82,7 +82,7 @@ public abstract class SymbolVariable implements Symbol {
this.inferredType = false; this.inferredType = false;
this.comments = new ArrayList<>(); this.comments = new ArrayList<>();
this.dataSegment = dataSegment; this.dataSegment = dataSegment;
this.storageStrategy = StorageStrategy.REGISTER; this.storageStrategy = StorageStrategy.PHI_REGISTER;
setFullName(); setFullName();
} }

View File

@ -262,7 +262,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
List<Directive> directives = declVarDirectives; List<Directive> directives = declVarDirectives;
VariableUnversioned param = new VariableUnversioned(ctx.NAME().getText(), getCurrentScope(), type, currentDataSegment); VariableUnversioned param = new VariableUnversioned(ctx.NAME().getText(), getCurrentScope(), type, currentDataSegment);
// Set initial storage strategy // Set initial storage strategy
param.setStorageStrategy(SymbolVariable.StorageStrategy.REGISTER); param.setStorageStrategy(SymbolVariable.StorageStrategy.PHI_REGISTER);
// Add directives // Add directives
addDirectives(param, type, directives, new StatementSource(ctx)); addDirectives(param, type, directives, new StatementSource(ctx));
exitDeclTypes(); exitDeclTypes();
@ -620,7 +620,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
throw new CompileError(e.getMessage(), new StatementSource(ctx)); throw new CompileError(e.getMessage(), new StatementSource(ctx));
} }
// Set initial storage strategy // Set initial storage strategy
lValue.setStorageStrategy(SymbolVariable.StorageStrategy.REGISTER); lValue.setStorageStrategy(SymbolVariable.StorageStrategy.PHI_REGISTER);
// Add directives // Add directives
addDirectives(lValue, type, directives, new StatementSource(ctx)); addDirectives(lValue, type, directives, new StatementSource(ctx));
// Array / String variables are implicitly constant // Array / String variables are implicitly constant
@ -704,7 +704,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
} else if(directive instanceof DirectiveRegister) { } else if(directive instanceof DirectiveRegister) {
DirectiveRegister directiveRegister = (DirectiveRegister) directive; DirectiveRegister directiveRegister = (DirectiveRegister) directive;
lValue.setDeclaredAsRegister(true); lValue.setDeclaredAsRegister(true);
lValue.setStorageStrategy(SymbolVariable.StorageStrategy.REGISTER); lValue.setStorageStrategy(SymbolVariable.StorageStrategy.PHI_REGISTER);
if(directiveRegister.name != null) { if(directiveRegister.name != null) {
// Ignore register directive without parameter (all variables are placed on ZP and attempted register uplift anyways) // Ignore register directive without parameter (all variables are placed on ZP and attempted register uplift anyways)
Registers.Register register = Registers.getRegister(directiveRegister.name); Registers.Register register = Registers.getRegister(directiveRegister.name);
@ -1207,7 +1207,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
throw new CompileError(e.getMessage(), statementSource); throw new CompileError(e.getMessage(), statementSource);
} }
// Set initial storage strategy // Set initial storage strategy
lValue.setStorageStrategy(SymbolVariable.StorageStrategy.REGISTER); lValue.setStorageStrategy(SymbolVariable.StorageStrategy.PHI_REGISTER);
// Add directives // Add directives
addDirectives(lValue, varType, varDirectives, statementSource); addDirectives(lValue, varType, varDirectives, statementSource);
} else { } else {

View File

@ -433,6 +433,7 @@ public class Pass4CodeGeneration {
Scope scope = program.getScope().getScope(scopeRef); Scope scope = program.getScope().getScope(scopeRef);
Collection<ConstantVar> scopeConstants = scope.getAllConstants(false); Collection<ConstantVar> scopeConstants = scope.getAllConstants(false);
Set<String> added = new LinkedHashSet<>(); Set<String> added = new LinkedHashSet<>();
// Add all constants arrays incl. strings with data
for(ConstantVar constantVar : scopeConstants) { for(ConstantVar constantVar : scopeConstants) {
if(hasData(constantVar)) { if(hasData(constantVar)) {
// Skip if already added // Skip if already added
@ -461,6 +462,31 @@ public class Pass4CodeGeneration {
added.add(asmName); added.add(asmName);
} }
} }
// Add all memory variables
Collection<Variable> scopeVariables = scope.getAllVariables(false);
for(Variable variable : scopeVariables) {
if(variable.getStorageStrategy().equals(SymbolVariable.StorageStrategy.MEMORY)) {
// Skip if already added
String asmName = variable.getAsmName() == null ? variable.getLocalName() : variable.getAsmName();
if(added.contains(asmName)) {
continue;
}
// Set segment
setCurrentSegment(variable.getDataSegment(), asm);
// Add any comments
generateComments(asm, variable.getComments());
// Add any alignment
Integer declaredAlignment = variable.getDeclaredAlignment();
if(declaredAlignment != null) {
String alignment = AsmFormat.getAsmNumber(declaredAlignment);
asm.addDataAlignment(alignment);
}
AsmDataChunk asmDataChunk = new AsmDataChunk();
addChunkData(asmDataChunk, ZeroConstantValues.zeroValue(variable.getType(), getScope()), variable.getType(), scopeRef);
asmDataChunk.addToAsm(AsmFormat.asmFix(asmName), asm);
added.add(asmName);
}
}
} }
/** /**

View File

@ -35,12 +35,10 @@ public class TestPrograms {
public TestPrograms() { public TestPrograms() {
} }
/*
@Test @Test
public void testDelcaredMemoryVar0() throws IOException, URISyntaxException { public void testDeclaredMemoryVar0() throws IOException, URISyntaxException {
compileAndCompare("declared-memory-var-0", log().verboseParse().verboseCreateSsa()); compileAndCompare("declared-memory-var-0", log());
} }
*/
/* /*
@Test @Test

View File

@ -1,6 +1,6 @@
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store) // Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
memory char idx=0; memory char idx;
const char* SCREEN = 0x0400; const char* SCREEN = 0x0400;

View File

@ -1,18 +1,27 @@
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store) // Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
.pc = $801 "Basic" .pc = $801 "Basic"
:BasicUpstart(main) :BasicUpstart(bbegin)
.pc = $80d "Program" .pc = $80d "Program"
.label idx_ptr = idx
.label SCREEN = $400 .label SCREEN = $400
bbegin:
lda #0
sta idx_ptr
jsr main
rts
main: { main: {
ldx #0 ldx #0
txa
b1: b1:
lda idx_ptr
sta SCREEN,x sta SCREEN,x
stx.z $ff txa
clc clc
adc.z $ff adc idx_ptr
sta idx_ptr
inx inx
cpx #6 cpx #6
bne b1 bne b1
sta idx_ptr
rts rts
} }
idx: .byte 0

View File

@ -1,25 +1,28 @@
@begin: scope:[] from @begin: scope:[] from
[0] phi() [0] *((const byte*) idx_ptr) ← (byte) 0
to:@1 to:@1
@1: scope:[] from @begin @1: scope:[] from @begin
[1] phi() [1] phi()
[2] call main [2] call main
to:@2
@2: scope:[] from @1
[3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr)
to:@end to:@end
@end: scope:[] from @1 @end: scope:[] from @2
[3] phi() [4] phi()
(void()) main() (void()) main()
main: scope:[main] from @1 main: scope:[main] from @1
[4] phi() [5] phi()
to:main::@1 to:main::@1
main::@1: scope:[main] from main main::@1 main::@1: scope:[main] from main main::@1
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 ) [6] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[5] (byte) idx#5 ← phi( main/(byte) 0 main::@1/(byte) idx#2 ) [7] *((const byte*) SCREEN#0 + (byte) main::i#2) ← *((const byte*) idx_ptr)
[6] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte) idx#5 [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2
[7] (byte) idx#2 ← (byte) idx#5 + (byte) main::i#2 [9] (byte) main::i#1 ← ++ (byte) main::i#2
[8] (byte) main::i#1 ← ++ (byte) main::i#2 [10] if((byte) main::i#1!=(byte) 6) goto main::@1
[9] if((byte) main::i#1!=(byte) 6) goto main::@1
to:main::@return to:main::@return
main::@return: scope:[main] from main::@1 main::@return: scope:[main] from main::@1
[10] return [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr)
[12] return
to:@return to:@return

View File

@ -1,37 +1,41 @@
Culled Empty Block (label) main::@2 Culled Empty Block (label) main::@2
Adding memory variable constant pointer (const byte*) idx_ptr
Updating memory variable reference *((const byte*) idx_ptr)
Updating memory variable reference *((const byte*) idx_ptr)
Updating memory variable reference *((const byte*) idx_ptr)
Updating memory variable reference *((const byte*) idx_ptr)
Updating memory variable reference *((const byte*) idx_ptr)
Updating memory variable reference *((const byte*) idx_ptr)
Updating memory variable reference *((const byte*) idx_ptr)
Updating memory variable reference *((const byte*) idx_ptr)
CONTROL FLOW GRAPH SSA CONTROL FLOW GRAPH SSA
@begin: scope:[] from @begin: scope:[] from
(byte) idx#0 ← (byte) 0 *((const byte*) idx_ptr) ← (number) 0
(byte*) SCREEN#0 ← ((byte*)) (number) $400 (byte*) SCREEN#0 ← ((byte*)) (number) $400
to:@1 to:@1
(void()) main() (void()) main()
main: scope:[main] from @1 main: scope:[main] from @1
(byte) idx#1 ← (number) 0
(byte) main::i#0 ← (byte) 0 (byte) main::i#0 ← (byte) 0
to:main::@1 to:main::@1
main::@1: scope:[main] from main main::@1 main::@1: scope:[main] from main main::@1
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 ) (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 )
(byte) idx#5 ← phi( main/(byte) idx#1 main::@1/(byte) idx#2 ) *((byte*) SCREEN#0 + (byte) main::i#2) ← *((const byte*) idx_ptr)
*((byte*) SCREEN#0 + (byte) main::i#2) ← (byte) idx#5 *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2
(byte) idx#2 ← (byte) idx#5 + (byte) main::i#2
(byte) main::i#1 ← (byte) main::i#2 + rangenext(0,5) (byte) main::i#1 ← (byte) main::i#2 + rangenext(0,5)
(bool~) main::$0 ← (byte) main::i#1 != rangelast(0,5) (bool~) main::$0 ← (byte) main::i#1 != rangelast(0,5)
if((bool~) main::$0) goto main::@1 if((bool~) main::$0) goto main::@1
to:main::@return to:main::@return
main::@return: scope:[main] from main::@1 main::@return: scope:[main] from main::@1
(byte) idx#6 ← phi( main::@1/(byte) idx#2 ) *((const byte*) idx_ptr) ← *((const byte*) idx_ptr)
(byte) idx#3 ← (byte) idx#6
return return
to:@return to:@return
@1: scope:[] from @begin @1: scope:[] from @begin
(byte) idx#8 ← phi( @begin/(byte) idx#0 )
call main call main
to:@2 to:@2
@2: scope:[] from @1 @2: scope:[] from @1
(byte) idx#7 ← phi( @1/(byte) idx#3 ) *((const byte*) idx_ptr) ← *((const byte*) idx_ptr)
(byte) idx#4 ← (byte) idx#7
to:@end to:@end
@end: scope:[] from @2 @end: scope:[] from @2
@ -43,15 +47,7 @@ SYMBOL TABLE SSA
(byte*) SCREEN (byte*) SCREEN
(byte*) SCREEN#0 (byte*) SCREEN#0
(byte) idx memory (byte) idx memory
(byte) idx#0 memory (const byte*) idx_ptr = &(byte) idx
(byte) idx#1 memory
(byte) idx#2 memory
(byte) idx#3 memory
(byte) idx#4 memory
(byte) idx#5 memory
(byte) idx#6 memory
(byte) idx#7 memory
(byte) idx#8 memory
(void()) main() (void()) main()
(bool~) main::$0 (bool~) main::$0
(label) main::@1 (label) main::@1
@ -61,33 +57,23 @@ SYMBOL TABLE SSA
(byte) main::i#1 (byte) main::i#1
(byte) main::i#2 (byte) main::i#2
Adding number conversion cast (unumber) 0 in (byte) idx#1 ← (number) 0 Adding number conversion cast (unumber) 0 in *((const byte*) idx_ptr) ← (number) 0
Successful SSA optimization PassNAddNumberTypeConversions Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast *((const byte*) idx_ptr) ← (unumber)(number) 0
Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400 Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400
Inlining cast (byte) idx#1 ← (unumber)(number) 0
Successful SSA optimization Pass2InlineCast Successful SSA optimization Pass2InlineCast
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0 Simplifying constant integer cast 0
Simplifying constant pointer cast (byte*) 1024
Successful SSA optimization PassNCastSimplification Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias (byte) idx#2 = (byte) idx#6 (byte) idx#3 Simple Condition (bool~) main::$0 [8] if((byte) main::i#1!=rangelast(0,5)) goto main::@1
Alias (byte) idx#0 = (byte) idx#8
Alias (byte) idx#4 = (byte) idx#7
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (byte) idx#4 (byte) idx#2
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition (bool~) main::$0 [9] if((byte) main::i#1!=rangelast(0,5)) goto main::@1
Successful SSA optimization Pass2ConditionalJumpSimplification Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte) idx#0 = 0
Constant (const byte*) SCREEN#0 = (byte*) 1024 Constant (const byte*) SCREEN#0 = (byte*) 1024
Constant (const byte) idx#1 = 0
Constant (const byte) main::i#0 = 0 Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification Successful SSA optimization Pass2ConstantIdentification
Resolved ranged next value [7] main::i#1 ← ++ main::i#2 to ++ Resolved ranged next value [6] main::i#1 ← ++ main::i#2 to ++
Resolved ranged comparison value [9] if(main::i#1!=rangelast(0,5)) goto main::@1 to (number) 6 Resolved ranged comparison value [8] if(main::i#1!=rangelast(0,5)) goto main::@1 to (number) 6
Eliminating unused constant (const byte) idx#0
Successful SSA optimization PassNEliminateUnusedVars
Adding number conversion cast (unumber) 6 in if((byte) main::i#1!=(number) 6) goto main::@1 Adding number conversion cast (unumber) 6 in if((byte) main::i#1!=(number) 6) goto main::@1
Successful SSA optimization PassNAddNumberTypeConversions Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast 6 Simplifying constant integer cast 6
@ -95,76 +81,67 @@ Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 6 Finalized unsigned number type (byte) 6
Successful SSA optimization PassNFinalizeNumberTypeConversions Successful SSA optimization PassNFinalizeNumberTypeConversions
Inlining constant with var siblings (const byte) main::i#0 Inlining constant with var siblings (const byte) main::i#0
Inlining constant with var siblings (const byte) idx#1
Constant inlined main::i#0 = (byte) 0 Constant inlined main::i#0 = (byte) 0
Constant inlined idx#1 = (byte) 0
Successful SSA optimization Pass2ConstantInlining Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting main::@3(between main::@1 and main::@1) Added new block during phi lifting main::@3(between main::@1 and main::@1)
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1 Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end Adding NOP phi() at start of @end
Adding NOP phi() at start of main Adding NOP phi() at start of main
CALL GRAPH CALL GRAPH
Calls in [] to main:2 Calls in [] to main:2
Created 2 initial phi equivalence classes Created 1 initial phi equivalence classes
Coalesced [12] idx#9 ← idx#2
Coalesced [13] main::i#3 ← main::i#1 Coalesced [13] main::i#3 ← main::i#1
Coalesced down to 2 phi equivalence classes Coalesced down to 1 phi equivalence classes
Culled Empty Block (label) @2
Culled Empty Block (label) main::@3 Culled Empty Block (label) main::@3
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1 Adding NOP phi() at start of @1
Adding NOP phi() at start of @end Adding NOP phi() at start of @end
Adding NOP phi() at start of main Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH FINAL CONTROL FLOW GRAPH
@begin: scope:[] from @begin: scope:[] from
[0] phi() [0] *((const byte*) idx_ptr) ← (byte) 0
to:@1 to:@1
@1: scope:[] from @begin @1: scope:[] from @begin
[1] phi() [1] phi()
[2] call main [2] call main
to:@2
@2: scope:[] from @1
[3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr)
to:@end to:@end
@end: scope:[] from @1 @end: scope:[] from @2
[3] phi() [4] phi()
(void()) main() (void()) main()
main: scope:[main] from @1 main: scope:[main] from @1
[4] phi() [5] phi()
to:main::@1 to:main::@1
main::@1: scope:[main] from main main::@1 main::@1: scope:[main] from main main::@1
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 ) [6] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[5] (byte) idx#5 ← phi( main/(byte) 0 main::@1/(byte) idx#2 ) [7] *((const byte*) SCREEN#0 + (byte) main::i#2) ← *((const byte*) idx_ptr)
[6] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte) idx#5 [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2
[7] (byte) idx#2 ← (byte) idx#5 + (byte) main::i#2 [9] (byte) main::i#1 ← ++ (byte) main::i#2
[8] (byte) main::i#1 ← ++ (byte) main::i#2 [10] if((byte) main::i#1!=(byte) 6) goto main::@1
[9] if((byte) main::i#1!=(byte) 6) goto main::@1
to:main::@return to:main::@return
main::@return: scope:[main] from main::@1 main::@return: scope:[main] from main::@1
[10] return [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr)
[12] return
to:@return to:@return
VARIABLE REGISTER WEIGHTS VARIABLE REGISTER WEIGHTS
(byte*) SCREEN (byte*) SCREEN
(byte) idx memory (byte) idx memory
(byte) idx#2 memory 7.333333333333333
(byte) idx#5 memory 16.5
(void()) main() (void()) main()
(byte) main::i (byte) main::i
(byte) main::i#1 16.5 (byte) main::i#1 16.5
(byte) main::i#2 14.666666666666666 (byte) main::i#2 14.666666666666666
Initial phi equivalence classes Initial phi equivalence classes
[ idx#5 idx#2 ]
[ main::i#2 main::i#1 ] [ main::i#2 main::i#1 ]
Complete equivalence classes Complete equivalence classes
[ idx#5 idx#2 ]
[ main::i#2 main::i#1 ] [ main::i#2 main::i#1 ]
Allocated zp ZP_BYTE:2 [ idx#5 idx#2 ] Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Allocated zp ZP_BYTE:3 [ main::i#2 main::i#1 ]
INITIAL ASM INITIAL ASM
Target platform is c64basic / MOS6502X Target platform is c64basic / MOS6502X
@ -175,79 +152,95 @@ Target platform is c64basic / MOS6502X
:BasicUpstart(bbegin) :BasicUpstart(bbegin)
.pc = $80d "Program" .pc = $80d "Program"
// Global Constants & labels // Global Constants & labels
.label idx_ptr = idx
.label SCREEN = $400 .label SCREEN = $400
.label idx = 2
// @begin // @begin
bbegin: bbegin:
// [0] *((const byte*) idx_ptr) ← (byte) 0 -- _deref_pbuc1=vbuc2
lda #0
sta idx_ptr
// [1] phi from @begin to @1 [phi:@begin->@1] // [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin: b1_from_bbegin:
jmp b1 jmp b1
// @1 // @1
b1: b1:
// [2] call main // [2] call main
// [4] phi from @1 to main [phi:@1->main] // [5] phi from @1 to main [phi:@1->main]
main_from_b1: main_from_b1:
jsr main jsr main
// [3] phi from @1 to @end [phi:@1->@end] jmp b2
bend_from_b1: // @2
b2:
// [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1
lda idx_ptr
sta idx_ptr
// [4] phi from @2 to @end [phi:@2->@end]
bend_from_b2:
jmp bend jmp bend
// @end // @end
bend: bend:
// main // main
main: { main: {
.label i = 3 .label i = 2
// [5] phi from main to main::@1 [phi:main->main::@1] // [6] phi from main to main::@1 [phi:main->main::@1]
b1_from_main: b1_from_main:
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 // [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0 lda #0
sta.z i sta.z i
// [5] phi (byte) idx#5 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1
lda #0
sta.z idx
jmp b1 jmp b1
// [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] // [6] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
b1_from_b1: b1_from_b1:
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy // [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// [5] phi (byte) idx#5 = (byte) idx#2 [phi:main::@1->main::@1#1] -- register_copy
jmp b1 jmp b1
// main::@1 // main::@1
b1: b1:
// [6] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte) idx#5 -- pbuc1_derefidx_vbuz1=vbuz2 // [7] *((const byte*) SCREEN#0 + (byte) main::i#2) ← *((const byte*) idx_ptr) -- pbuc1_derefidx_vbuz1=_deref_pbuc2
lda.z idx
ldy.z i ldy.z i
lda idx_ptr
sta SCREEN,y sta SCREEN,y
// [7] (byte) idx#2 ← (byte) idx#5 + (byte) main::i#2 -- vbuz1=vbuz1_plus_vbuz2 // [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 -- _deref_pbuc1=_deref_pbuc1_plus_vbuz1
lda.z idx lda idx_ptr
clc clc
adc.z i adc.z i
sta.z idx sta idx_ptr
// [8] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 // [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc.z i inc.z i
// [9] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 // [10] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #6 lda #6
cmp.z i cmp.z i
bne b1_from_b1 bne b1_from_b1
jmp breturn jmp breturn
// main::@return // main::@return
breturn: breturn:
// [10] return // [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1
lda idx_ptr
sta idx_ptr
// [12] return
rts rts
} }
// File Data // File Data
idx: .byte 0
REGISTER UPLIFT POTENTIAL REGISTERS REGISTER UPLIFT POTENTIAL REGISTERS
Statement [7] (byte) idx#2 ← (byte) idx#5 + (byte) main::i#2 [ main::i#2 idx#2 ] ( main:2 [ main::i#2 idx#2 ] ) always clobbers reg byte a Statement [0] *((const byte*) idx_ptr) ← (byte) 0 [ ] ( [ ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::i#2 main::i#1 ] Statement [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) [ ] ( [ ] ) always clobbers reg byte a
Statement [7] (byte) idx#2 ← (byte) idx#5 + (byte) main::i#2 [ main::i#2 idx#2 ] ( main:2 [ main::i#2 idx#2 ] ) always clobbers reg byte a Statement [7] *((const byte*) SCREEN#0 + (byte) main::i#2) ← *((const byte*) idx_ptr) [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Potential registers zp ZP_BYTE:2 [ idx#5 idx#2 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y , Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Potential registers zp ZP_BYTE:3 [ main::i#2 main::i#1 ] : zp ZP_BYTE:3 , reg byte x , reg byte y , Statement [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Statement [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [0] *((const byte*) idx_ptr) ← (byte) 0 [ ] ( [ ] ) always clobbers reg byte a
Statement [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) [ ] ( [ ] ) always clobbers reg byte a
Statement [7] *((const byte*) SCREEN#0 + (byte) main::i#2) ← *((const byte*) idx_ptr) [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Statement [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Statement [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) [ ] ( main:2 [ ] ) always clobbers reg byte a
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES REGISTER UPLIFT SCOPES
Uplift Scope [main] 31.17: zp ZP_BYTE:3 [ main::i#2 main::i#1 ] Uplift Scope [main] 31.17: zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Uplift Scope [] 23.83: zp ZP_BYTE:2 [ idx#5 idx#2 ] Uplift Scope []
Uplifting [main] best 423 combination reg byte x [ main::i#2 main::i#1 ] Uplifting [main] best 428 combination reg byte x [ main::i#2 main::i#1 ]
Uplifting [] best 343 combination reg byte a [ idx#5 idx#2 ] Uplifting [] best 428 combination
ASSEMBLER BEFORE OPTIMIZATION ASSEMBLER BEFORE OPTIMIZATION
// File Comments // File Comments
@ -257,93 +250,109 @@ ASSEMBLER BEFORE OPTIMIZATION
:BasicUpstart(bbegin) :BasicUpstart(bbegin)
.pc = $80d "Program" .pc = $80d "Program"
// Global Constants & labels // Global Constants & labels
.label idx_ptr = idx
.label SCREEN = $400 .label SCREEN = $400
// @begin // @begin
bbegin: bbegin:
// [0] *((const byte*) idx_ptr) ← (byte) 0 -- _deref_pbuc1=vbuc2
lda #0
sta idx_ptr
// [1] phi from @begin to @1 [phi:@begin->@1] // [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin: b1_from_bbegin:
jmp b1 jmp b1
// @1 // @1
b1: b1:
// [2] call main // [2] call main
// [4] phi from @1 to main [phi:@1->main] // [5] phi from @1 to main [phi:@1->main]
main_from_b1: main_from_b1:
jsr main jsr main
// [3] phi from @1 to @end [phi:@1->@end] jmp b2
bend_from_b1: // @2
b2:
// [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1
lda idx_ptr
sta idx_ptr
// [4] phi from @2 to @end [phi:@2->@end]
bend_from_b2:
jmp bend jmp bend
// @end // @end
bend: bend:
// main // main
main: { main: {
// [5] phi from main to main::@1 [phi:main->main::@1] // [6] phi from main to main::@1 [phi:main->main::@1]
b1_from_main: b1_from_main:
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 // [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0 ldx #0
// [5] phi (byte) idx#5 = (byte) 0 [phi:main->main::@1#1] -- vbuaa=vbuc1
lda #0
jmp b1 jmp b1
// [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1] // [6] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
b1_from_b1: b1_from_b1:
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy // [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// [5] phi (byte) idx#5 = (byte) idx#2 [phi:main::@1->main::@1#1] -- register_copy
jmp b1 jmp b1
// main::@1 // main::@1
b1: b1:
// [6] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte) idx#5 -- pbuc1_derefidx_vbuxx=vbuaa // [7] *((const byte*) SCREEN#0 + (byte) main::i#2) ← *((const byte*) idx_ptr) -- pbuc1_derefidx_vbuxx=_deref_pbuc2
lda idx_ptr
sta SCREEN,x sta SCREEN,x
// [7] (byte) idx#2 ← (byte) idx#5 + (byte) main::i#2 -- vbuaa=vbuaa_plus_vbuxx // [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 -- _deref_pbuc1=_deref_pbuc1_plus_vbuxx
stx.z $ff txa
clc clc
adc.z $ff adc idx_ptr
// [8] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx sta idx_ptr
// [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx inx
// [9] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 // [10] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #6 cpx #6
bne b1_from_b1 bne b1_from_b1
jmp breturn jmp breturn
// main::@return // main::@return
breturn: breturn:
// [10] return // [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1
lda idx_ptr
sta idx_ptr
// [12] return
rts rts
} }
// File Data // File Data
idx: .byte 0
ASSEMBLER OPTIMIZATIONS ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1 Removing instruction jmp b1
Removing instruction jmp b2
Removing instruction jmp bend Removing instruction jmp bend
Removing instruction jmp b1 Removing instruction jmp b1
Removing instruction jmp breturn Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination Succesful ASM optimization Pass5NextJumpElimination
Replacing instruction lda #0 with TXA
Replacing label b1_from_b1 with b1 Replacing label b1_from_b1 with b1
Removing instruction b1_from_bbegin: Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1: Removing instruction main_from_b1:
Removing instruction bend_from_b1: Removing instruction bend_from_b2:
Removing instruction b1_from_b1: Removing instruction b1_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction b1:
Removing instruction b2:
Removing instruction bend: Removing instruction bend:
Removing instruction b1_from_main: Removing instruction b1_from_main:
Removing instruction breturn: Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly Adding RTS to root block
Removing instruction jsr main Succesful ASM optimization Pass5AddMainRts
Succesful ASM optimization Pass5SkipBegin
Removing instruction jmp b1 Removing instruction jmp b1
Succesful ASM optimization Pass5NextJumpElimination Succesful ASM optimization Pass5NextJumpElimination
Removing instruction bbegin: Removing instruction lda idx_ptr
Succesful ASM optimization Pass5UnusedLabelElimination Succesful ASM optimization Pass5UnnecesaryLoadElimination
Removing unreachable instruction lda idx_ptr
Removing unreachable instruction sta idx_ptr
Succesful ASM optimization Pass5UnreachableCodeElimination
FINAL SYMBOL TABLE FINAL SYMBOL TABLE
(label) @1 (label) @1
(label) @2
(label) @begin (label) @begin
(label) @end (label) @end
(byte*) SCREEN (byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024 (const byte*) SCREEN#0 SCREEN = (byte*) 1024
(byte) idx memory (byte) idx memory
(byte) idx#2 memory reg byte a 7.333333333333333 (const byte*) idx_ptr idx_ptr = &(byte) idx
(byte) idx#5 memory reg byte a 16.5
(void()) main() (void()) main()
(label) main::@1 (label) main::@1
(label) main::@return (label) main::@return
@ -351,58 +360,69 @@ FINAL SYMBOL TABLE
(byte) main::i#1 reg byte x 16.5 (byte) main::i#1 reg byte x 16.5
(byte) main::i#2 reg byte x 14.666666666666666 (byte) main::i#2 reg byte x 14.666666666666666
reg byte a [ idx#5 idx#2 ]
reg byte x [ main::i#2 main::i#1 ] reg byte x [ main::i#2 main::i#1 ]
FINAL ASSEMBLER FINAL ASSEMBLER
Score: 241 Score: 323
// File Comments // 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 declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
// Upstart // Upstart
.pc = $801 "Basic" .pc = $801 "Basic"
:BasicUpstart(main) :BasicUpstart(bbegin)
.pc = $80d "Program" .pc = $80d "Program"
// Global Constants & labels // Global Constants & labels
.label idx_ptr = idx
.label SCREEN = $400 .label SCREEN = $400
// @begin // @begin
bbegin:
// idx=0
// [0] *((const byte*) idx_ptr) ← (byte) 0 -- _deref_pbuc1=vbuc2
lda #0
sta idx_ptr
// [1] phi from @begin to @1 [phi:@begin->@1] // [1] phi from @begin to @1 [phi:@begin->@1]
// @1 // @1
// [2] call main // [2] call main
// [4] phi from @1 to main [phi:@1->main] // [5] phi from @1 to main [phi:@1->main]
// [3] phi from @1 to @end [phi:@1->@end] jsr main
rts
// @2
// [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1
// [4] phi from @2 to @end [phi:@2->@end]
// @end // @end
// main // main
main: { main: {
// [5] phi from main to main::@1 [phi:main->main::@1] // [6] phi from main to main::@1 [phi:main->main::@1]
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 // [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0 ldx #0
// [5] phi (byte) idx#5 = (byte) 0 [phi:main->main::@1#1] -- vbuaa=vbuc1 // [6] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
txa // [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// [5] phi (byte) idx#5 = (byte) idx#2 [phi:main::@1->main::@1#1] -- register_copy
// main::@1 // main::@1
b1: b1:
// SCREEN[i] = idx // SCREEN[i] = idx
// [6] *((const byte*) SCREEN#0 + (byte) main::i#2) ← (byte) idx#5 -- pbuc1_derefidx_vbuxx=vbuaa // [7] *((const byte*) SCREEN#0 + (byte) main::i#2) ← *((const byte*) idx_ptr) -- pbuc1_derefidx_vbuxx=_deref_pbuc2
lda idx_ptr
sta SCREEN,x sta SCREEN,x
// idx +=i // idx +=i
// [7] (byte) idx#2 ← (byte) idx#5 + (byte) main::i#2 -- vbuaa=vbuaa_plus_vbuxx // [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 -- _deref_pbuc1=_deref_pbuc1_plus_vbuxx
stx.z $ff txa
clc clc
adc.z $ff adc idx_ptr
sta idx_ptr
// for( char i: 0..5 ) // for( char i: 0..5 )
// [8] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx // [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx inx
// [9] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 // [10] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #6 cpx #6
bne b1 bne b1
// main::@return // main::@return
// } // }
// [10] return // [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1
sta idx_ptr
// [12] return
rts rts
} }
// File Data // File Data
idx: .byte 0

View File

@ -1,11 +1,11 @@
(label) @1 (label) @1
(label) @2
(label) @begin (label) @begin
(label) @end (label) @end
(byte*) SCREEN (byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024 (const byte*) SCREEN#0 SCREEN = (byte*) 1024
(byte) idx memory (byte) idx memory
(byte) idx#2 memory reg byte a 7.333333333333333 (const byte*) idx_ptr idx_ptr = &(byte) idx
(byte) idx#5 memory reg byte a 16.5
(void()) main() (void()) main()
(label) main::@1 (label) main::@1
(label) main::@return (label) main::@return
@ -13,5 +13,4 @@
(byte) main::i#1 reg byte x 16.5 (byte) main::i#1 reg byte x 16.5
(byte) main::i#2 reg byte x 14.666666666666666 (byte) main::i#2 reg byte x 14.666666666666666
reg byte a [ idx#5 idx#2 ]
reg byte x [ main::i#2 main::i#1 ] reg byte x [ main::i#2 main::i#1 ]