1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-23 23:32:55 +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);
}
program.setFileName(fileName);
initAsmFragmentSynthesizer();
try {
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.
* <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>CONSTANT-variables are constant.
* </ul>
**/
public enum StorageStrategy { REGISTER, MEMORY, CONSTANT }
public enum StorageStrategy {PHI_REGISTER, MEMORY, CONSTANT }
/** The storage strategy for the variable. */
private StorageStrategy storageStrategy;
@ -82,7 +82,7 @@ public abstract class SymbolVariable implements Symbol {
this.inferredType = false;
this.comments = new ArrayList<>();
this.dataSegment = dataSegment;
this.storageStrategy = StorageStrategy.REGISTER;
this.storageStrategy = StorageStrategy.PHI_REGISTER;
setFullName();
}

View File

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

View File

@ -433,6 +433,7 @@ public class Pass4CodeGeneration {
Scope scope = program.getScope().getScope(scopeRef);
Collection<ConstantVar> scopeConstants = scope.getAllConstants(false);
Set<String> added = new LinkedHashSet<>();
// Add all constants arrays incl. strings with data
for(ConstantVar constantVar : scopeConstants) {
if(hasData(constantVar)) {
// Skip if already added
@ -461,6 +462,31 @@ public class Pass4CodeGeneration {
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() {
}
/*
@Test
public void testDelcaredMemoryVar0() throws IOException, URISyntaxException {
compileAndCompare("declared-memory-var-0", log().verboseParse().verboseCreateSsa());
public void testDeclaredMemoryVar0() throws IOException, URISyntaxException {
compileAndCompare("declared-memory-var-0", log());
}
*/
/*
@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)
memory char idx=0;
memory char idx;
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)
.pc = $801 "Basic"
:BasicUpstart(main)
:BasicUpstart(bbegin)
.pc = $80d "Program"
.label idx_ptr = idx
.label SCREEN = $400
bbegin:
lda #0
sta idx_ptr
jsr main
rts
main: {
ldx #0
txa
b1:
lda idx_ptr
sta SCREEN,x
stx.z $ff
txa
clc
adc.z $ff
adc idx_ptr
sta idx_ptr
inx
cpx #6
bne b1
sta idx_ptr
rts
}
idx: .byte 0

View File

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

View File

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

View File

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