1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-12-29 08:31:03 +00:00

Fixed problem caused when the same resource is decalred twice in inline kickasm. Closes #537

This commit is contained in:
jespergravgaard 2020-10-11 15:47:10 +02:00
parent 4fd5e18bd0
commit cb1ae7bd30
14 changed files with 1087 additions and 18830 deletions

File diff suppressed because it is too large Load Diff

View File

@ -697,7 +697,8 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
File resourceFile = SourceLoader.loadFile(resourceName, currentPath, new ArrayList<>()); File resourceFile = SourceLoader.loadFile(resourceName, currentPath, new ArrayList<>());
if(resourceFile == null) if(resourceFile == null)
throw new CompileError("File not found " + resourceName); throw new CompileError("File not found " + resourceName);
program.addAsmResourceFile(resourceFile.toPath()); if(!program.getAsmResourceFiles().contains(resourceFile.toPath()))
program.addAsmResourceFile(resourceFile.toPath());
if(program.getLog().isVerboseParse()) { if(program.getLog().isVerboseParse()) {
program.getLog().append("Added resource " + resourceFile.getPath().replace('\\', '/')); program.getLog().append("Added resource " + resourceFile.getPath().replace('\\', '/'));
} }

View File

@ -57,10 +57,10 @@ public class Pass1CallPhiReturn {
* Handle PHI-call by assigning return value to LValue and updating all variables modified inside the procedure. * Handle PHI-call by assigning return value to LValue and updating all variables modified inside the procedure.
* @param call The call statement * @param call The call statement
* @param procedure The procedure * @param procedure The procedure
* @param block The block containing the call * @param callBlock The block containing the call
* @param stmtIt Iterator used for adding statements * @param stmtIt Iterator used for adding statements
*/ */
void handlePhiCall(StatementCall call, Procedure procedure, ControlFlowBlock block, ListIterator<Statement> stmtIt) { void handlePhiCall(StatementCall call, Procedure procedure, ControlFlowBlock callBlock, ListIterator<Statement> stmtIt) {
// Generate return value assignment (call finalize) // Generate return value assignment (call finalize)
if(!SymbolType.VOID.equals(procedure.getReturnType())) { if(!SymbolType.VOID.equals(procedure.getReturnType())) {
// Find return variable final version // Find return variable final version
@ -90,7 +90,7 @@ public class Pass1CallPhiReturn {
} }
// Patch versions of rValues in assignments for vars modified in the call (call finalize) // Patch versions of rValues in assignments for vars modified in the call (call finalize)
LabelRef successor = block.getDefaultSuccessor(); LabelRef successor = callBlock.getDefaultSuccessor();
ControlFlowBlock successorBlock = program.getGraph().getBlock(successor); ControlFlowBlock successorBlock = program.getGraph().getBlock(successor);
Set<VariableRef> modifiedVars = program.getProcedureModifiedVars().getModifiedVars(procedure.getRef()); Set<VariableRef> modifiedVars = program.getProcedureModifiedVars().getModifiedVars(procedure.getRef());
for(Statement statement : successorBlock.getStatements()) { for(Statement statement : successorBlock.getStatements()) {
@ -101,7 +101,7 @@ public class Pass1CallPhiReturn {
VariableRef unversionedVar = new VariableRef(phiVar.getFullNameUnversioned()); VariableRef unversionedVar = new VariableRef(phiVar.getFullNameUnversioned());
if(modifiedVars.contains(unversionedVar)) { if(modifiedVars.contains(unversionedVar)) {
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) { for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
if(phiRValue.getPredecessor().equals(block.getLabel())) { if(phiRValue.getPredecessor().equals(callBlock.getLabel())) {
VariableRef procReturnVersion = findReturnVersion(procedure, unversionedVar); VariableRef procReturnVersion = findReturnVersion(procedure, unversionedVar);
phiRValue.setrValue(procReturnVersion); phiRValue.setrValue(procReturnVersion);
} }

View File

@ -83,7 +83,7 @@ public class Unroller {
Map<LabelRef, SymbolVariableRef> varVersions = new LinkedHashMap<>(); Map<LabelRef, SymbolVariableRef> varVersions = new LinkedHashMap<>();
reVersionAllUsages(origVarRef, newPhis, varVersions); reVersionAllUsages(origVarRef, newPhis, varVersions);
if(program.getLog().isVerboseLoopUnroll()) { if(program.getLog().isVerboseLoopUnroll()) {
program.getLog().append("Created new versions for " + origVarRef + ")"); program.getLog().append("Created new versions for " + origVarRef );
//program.getLog().append(program.getGraph().toString(program)); //program.getLog().append(program.getGraph().toString(program));
} }
// Recursively fill out & add PHI-functions until they have propagated everywhere needed // Recursively fill out & add PHI-functions until they have propagated everywhere needed

View File

@ -44,6 +44,11 @@ public class TestPrograms {
public TestPrograms() { public TestPrograms() {
} }
@Test
public void testLoopHeadTrivial1() throws IOException, URISyntaxException {
compileAndCompare("loophead-trivial-1.c");
}
@Test @Test
public void testStrengthReduction1() throws IOException, URISyntaxException { public void testStrengthReduction1() throws IOException, URISyntaxException {
compileAndCompare("strength-reduction-1.c"); compileAndCompare("strength-reduction-1.c");
@ -1291,13 +1296,13 @@ public class TestPrograms {
// TODO: Fix loop head problem! https://gitlab.com/camelot/kickc/issues/290 // TODO: Fix loop head problem! https://gitlab.com/camelot/kickc/issues/290
@Test @Test
public void testLoopheadProblem2() throws IOException, URISyntaxException { public void testLoopheadProblem2() throws IOException, URISyntaxException {
compileAndCompare("loophead-problem-2.c"); compileAndCompare("loophead-problem-2.c", log().verboseLoopUnroll());
} }
// TODO: Fix loop head problem! https://gitlab.com/camelot/kickc/issues/261 // TODO: Fix loop head problem! https://gitlab.com/camelot/kickc/issues/261
@Test @Test
public void testLoopheadProblem() throws IOException, URISyntaxException { public void testLoopheadProblem() throws IOException, URISyntaxException {
compileAndCompare("loophead-problem.c"); compileAndCompare("loophead-problem.c", log().verboseLoopUnroll());
} }
@Test @Test
@ -1440,6 +1445,11 @@ public class TestPrograms {
compileAndCompare("inline-asm-param.c"); compileAndCompare("inline-asm-param.c");
} }
@Test
public void testDyppa2() throws IOException, URISyntaxException {
compileAndCompare("complex/dyppa2/dyppa2.c", log());
}
@Test @Test
public void testAtariTempest() throws IOException, URISyntaxException { public void testAtariTempest() throws IOException, URISyntaxException {
compileAndCompare("complex/ataritempest/ataritempest.c"); compileAndCompare("complex/ataritempest/ataritempest.c");

View File

@ -0,0 +1,10 @@
// Test a trivial loop head constant
// For trivially constant loop heads for(;;) loops can be written to run body before comparison
// The simplest possible for-loop with a constant loop head.
char * const SCREEN = 0x0400;
void main() {
for(char i=0;i<40;i++)
SCREEN[i] = '*';
}

View File

@ -0,0 +1,69 @@
// Chunky DYPP with arbitrary sinus
// First implemented as dyppa.asm in 2011
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const OFFSET_STRUCT_MOS6569_VICII_MEMORY = $18
// The VIC-II MOS 6567/6569
.label VICII = $d000
// Default address of screen character matrix
.label DEFAULT_SCREEN = $400
main: {
.const toD0181_return = (>(DEFAULT_SCREEN&$3fff)*4)|(>DYPPA_CHARSET)/4&$f
// VICII->MEMORY = toD018(DEFAULT_SCREEN, DYPPA_CHARSET)
lda #toD0181_return
sta VICII+OFFSET_STRUCT_MOS6569_VICII_MEMORY
// memset(DEFAULT_SCREEN, DYPPA_TABLE[0], 1000)
ldx DYPPA_TABLE
jsr memset
__b1:
// (*(DEFAULT_SCREEN+999))++;
inc DEFAULT_SCREEN+$3e7
jmp __b1
}
// Copies the character c (an unsigned char) to the first num characters of the object pointed to by the argument str.
// memset(byte register(X) c)
memset: {
.const num = $3e8
.label str = DEFAULT_SCREEN
.label end = str+num
.label dst = 2
lda #<str
sta.z dst
lda #>str
sta.z dst+1
__b1:
// for(char* dst = str; dst!=end; dst++)
lda.z dst+1
cmp #>end
bne __b2
lda.z dst
cmp #<end
bne __b2
// }
rts
__b2:
// *dst = c
txa
ldy #0
sta (dst),y
// for(char* dst = str; dst!=end; dst++)
inc.z dst
bne !+
inc.z dst+1
!:
jmp __b1
}
// The DYPPA tables mapping the slopes, offsets and pixels to the right character in the charset
// for(offset:0..7) for(slope:0..f) for(pixels: 0..f) glyph_id(offset,slope,pixels)
.align $100
DYPPA_TABLE:
.var dyppaFile2 = LoadBinary("dyppacharset.bin", "Charset=$000,Tables=$800")
.fill dyppaFile2.getTablesSize(), dyppaFile2.getTables(i)
.pc = $2000 "DYPPA_CHARSET"
// The DYPPA charset containing the sloped offset characters
DYPPA_CHARSET:
.var dyppaFile = LoadBinary("dyppacharset.bin", "Charset=$000,Tables=$800")
.fill dyppaFile.getCharsetSize(), dyppaFile.getCharset(i)

View File

@ -0,0 +1,32 @@
void main()
main: scope:[main] from
[0] phi()
to:main::toD0181
main::toD0181: scope:[main] from main
[1] phi()
to:main::@2
main::@2: scope:[main] from main::toD0181
[2] *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_MEMORY) = main::toD0181_return#0
[3] memset::c#0 = *DYPPA_TABLE
[4] call memset
to:main::@1
main::@1: scope:[main] from main::@1 main::@2
[5] *(DEFAULT_SCREEN+$3e7) = ++ *(DEFAULT_SCREEN+$3e7)
to:main::@1
void* memset(void* memset::str , byte memset::c , word memset::num)
memset: scope:[memset] from main::@2
[6] phi()
to:memset::@1
memset::@1: scope:[memset] from memset memset::@2
[7] memset::dst#2 = phi( memset/(byte*)memset::str#0, memset::@2/memset::dst#1 )
[8] if(memset::dst#2!=memset::end#0) goto memset::@2
to:memset::@return
memset::@return: scope:[memset] from memset::@1
[9] return
to:@return
memset::@2: scope:[memset] from memset::@1
[10] *memset::dst#2 = memset::c#0
[11] memset::dst#1 = ++ memset::dst#2
to:memset::@1

View File

@ -0,0 +1,663 @@
Inlined call vicSelectGfxBank::$0 = call toDd00 vicSelectGfxBank::gfx
Inlined call main::$0 = call toD018 DEFAULT_SCREEN DYPPA_CHARSET
CONTROL FLOW GRAPH SSA
void* memset(void* memset::str , byte memset::c , word memset::num)
memset: scope:[memset] from main::@2
memset::c#4 = phi( main::@2/memset::c#0 )
memset::str#3 = phi( main::@2/memset::str#0 )
memset::num#1 = phi( main::@2/memset::num#0 )
memset::$0 = memset::num#1 > 0
memset::$1 = ! memset::$0
if(memset::$1) goto memset::@1
to:memset::@2
memset::@1: scope:[memset] from memset memset::@3
memset::str#1 = phi( memset/memset::str#3, memset::@3/memset::str#4 )
memset::return#0 = memset::str#1
to:memset::@return
memset::@2: scope:[memset] from memset
memset::c#3 = phi( memset/memset::c#4 )
memset::num#2 = phi( memset/memset::num#1 )
memset::str#2 = phi( memset/memset::str#3 )
memset::$4 = (byte*)memset::str#2
memset::$2 = memset::$4 + memset::num#2
memset::end#0 = memset::$2
memset::dst#0 = ((byte*)) memset::str#2
to:memset::@3
memset::@3: scope:[memset] from memset::@2 memset::@4
memset::c#2 = phi( memset::@2/memset::c#3, memset::@4/memset::c#1 )
memset::str#4 = phi( memset::@2/memset::str#2, memset::@4/memset::str#5 )
memset::end#1 = phi( memset::@2/memset::end#0, memset::@4/memset::end#2 )
memset::dst#2 = phi( memset::@2/memset::dst#0, memset::@4/memset::dst#1 )
memset::$3 = memset::dst#2 != memset::end#1
if(memset::$3) goto memset::@4
to:memset::@1
memset::@4: scope:[memset] from memset::@3
memset::str#5 = phi( memset::@3/memset::str#4 )
memset::end#2 = phi( memset::@3/memset::end#1 )
memset::dst#3 = phi( memset::@3/memset::dst#2 )
memset::c#1 = phi( memset::@3/memset::c#2 )
*memset::dst#3 = memset::c#1
memset::dst#1 = ++ memset::dst#3
to:memset::@3
memset::@return: scope:[memset] from memset::@1
memset::return#3 = phi( memset::@1/memset::return#0 )
memset::return#1 = memset::return#3
return
to:@return
void main()
main: scope:[main] from __start
main::toD0181_screen#0 = DEFAULT_SCREEN
main::toD0181_gfx#0 = DYPPA_CHARSET
to:main::toD0181
main::toD0181: scope:[main] from main
main::toD0181_gfx#1 = phi( main/main::toD0181_gfx#0 )
main::toD0181_screen#1 = phi( main/main::toD0181_screen#0 )
main::toD0181_$7 = (word)main::toD0181_screen#1
main::toD0181_$0 = main::toD0181_$7 & $3fff
main::toD0181_$1 = main::toD0181_$0 * 4
main::toD0181_$2 = > main::toD0181_$1
main::toD0181_$3 = > (word)main::toD0181_gfx#1
main::toD0181_$4 = main::toD0181_$3 / 4
main::toD0181_$5 = main::toD0181_$4 & $f
main::toD0181_$6 = main::toD0181_$2 | main::toD0181_$5
main::toD0181_return#0 = main::toD0181_$6
to:main::toD0181_@return
main::toD0181_@return: scope:[main] from main::toD0181
main::toD0181_return#2 = phi( main::toD0181/main::toD0181_return#0 )
main::toD0181_return#1 = main::toD0181_return#2
to:main::@2
main::@2: scope:[main] from main::toD0181_@return
main::toD0181_return#3 = phi( main::toD0181_@return/main::toD0181_return#1 )
main::$0 = main::toD0181_return#3
*((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_MEMORY) = main::$0
memset::str#0 = (void*)DEFAULT_SCREEN
memset::c#0 = DYPPA_TABLE[0]
memset::num#0 = $3e8
call memset
memset::return#2 = memset::return#1
to:main::@3
main::@3: scope:[main] from main::@2
to:main::@1
main::@1: scope:[main] from main::@1 main::@3
*(DEFAULT_SCREEN+$3e7) = ++ *(DEFAULT_SCREEN+$3e7)
to:main::@1
main::@return: scope:[main] from
return
to:@return
void __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
const nomodify byte* DEFAULT_SCREEN = (byte*)$400
const byte* DYPPA_CHARSET[$800] = kickasm {{ .var dyppaFile = LoadBinary("dyppacharset.bin", "Charset=$000,Tables=$800")
.fill dyppaFile.getCharsetSize(), dyppaFile.getCharset(i)
}}
const byte* DYPPA_TABLE[$800] = kickasm {{ .var dyppaFile2 = LoadBinary("dyppacharset.bin", "Charset=$000,Tables=$800")
.fill dyppaFile2.getTablesSize(), dyppaFile2.getTables(i)
}}
const byte OFFSET_STRUCT_MOS6569_VICII_MEMORY = $18
const nomodify struct MOS6569_VICII* VICII = (struct MOS6569_VICII*)$d000
void __start()
void main()
byte~ main::$0
number~ main::toD0181_$0
number~ main::toD0181_$1
number~ main::toD0181_$2
byte~ main::toD0181_$3
number~ main::toD0181_$4
number~ main::toD0181_$5
number~ main::toD0181_$6
word~ main::toD0181_$7
byte* main::toD0181_gfx
byte* main::toD0181_gfx#0
byte* main::toD0181_gfx#1
byte main::toD0181_return
byte main::toD0181_return#0
byte main::toD0181_return#1
byte main::toD0181_return#2
byte main::toD0181_return#3
byte* main::toD0181_screen
byte* main::toD0181_screen#0
byte* main::toD0181_screen#1
void* memset(void* memset::str , byte memset::c , word memset::num)
bool~ memset::$0
bool~ memset::$1
byte*~ memset::$2
bool~ memset::$3
byte*~ memset::$4
byte memset::c
byte memset::c#0
byte memset::c#1
byte memset::c#2
byte memset::c#3
byte memset::c#4
byte* memset::dst
byte* memset::dst#0
byte* memset::dst#1
byte* memset::dst#2
byte* memset::dst#3
byte* memset::end
byte* memset::end#0
byte* memset::end#1
byte* memset::end#2
word memset::num
word memset::num#0
word memset::num#1
word memset::num#2
void* memset::return
void* memset::return#0
void* memset::return#1
void* memset::return#2
void* memset::return#3
void* memset::str
void* memset::str#0
void* memset::str#1
void* memset::str#2
void* memset::str#3
void* memset::str#4
void* memset::str#5
Adding number conversion cast (unumber) 0 in memset::$0 = memset::num#1 > 0
Adding number conversion cast (unumber) $3fff in main::toD0181_$0 = main::toD0181_$7 & $3fff
Adding number conversion cast (unumber) main::toD0181_$0 in main::toD0181_$0 = main::toD0181_$7 & (unumber)$3fff
Adding number conversion cast (unumber) 4 in main::toD0181_$1 = main::toD0181_$0 * 4
Adding number conversion cast (unumber) main::toD0181_$1 in main::toD0181_$1 = main::toD0181_$0 * (unumber)4
Adding number conversion cast (unumber) main::toD0181_$2 in main::toD0181_$2 = > main::toD0181_$1
Adding number conversion cast (unumber) 4 in main::toD0181_$4 = main::toD0181_$3 / 4
Adding number conversion cast (unumber) main::toD0181_$4 in main::toD0181_$4 = main::toD0181_$3 / (unumber)4
Adding number conversion cast (unumber) $f in main::toD0181_$5 = main::toD0181_$4 & $f
Adding number conversion cast (unumber) main::toD0181_$5 in main::toD0181_$5 = main::toD0181_$4 & (unumber)$f
Adding number conversion cast (unumber) main::toD0181_$6 in main::toD0181_$6 = main::toD0181_$2 | main::toD0181_$5
Adding number conversion cast (unumber) 0 in memset::c#0 = DYPPA_TABLE[0]
Adding number conversion cast (unumber) $3e8 in memset::num#0 = $3e8
Adding number conversion cast (unumber) $3e7 in *(DEFAULT_SCREEN+$3e7) = ++ *(DEFAULT_SCREEN+$3e7)
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast memset::dst#0 = (byte*)memset::str#2
Inlining cast memset::num#0 = (unumber)$3e8
Successful SSA optimization Pass2InlineCast
Simplifying constant pointer cast (struct MOS6569_VICII*) 53248
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Simplifying constant integer cast $3fff
Simplifying constant integer cast 4
Simplifying constant integer cast 4
Simplifying constant integer cast $f
Simplifying constant integer cast 0
Simplifying constant integer cast $3e8
Simplifying constant integer cast $3e7
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type 0
Finalized unsigned number type $3fff
Finalized unsigned number type 4
Finalized unsigned number type 4
Finalized unsigned number type $f
Finalized unsigned number type 0
Finalized unsigned number type $3e8
Finalized unsigned number type $3e7
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inferred type updated to word in main::toD0181_$0 = main::toD0181_$7 & $3fff
Inferred type updated to word in main::toD0181_$1 = main::toD0181_$0 * 4
Inferred type updated to byte in main::toD0181_$2 = > main::toD0181_$1
Inferred type updated to byte in main::toD0181_$4 = main::toD0181_$3 / 4
Inferred type updated to byte in main::toD0181_$5 = main::toD0181_$4 & $f
Inferred type updated to byte in main::toD0181_$6 = main::toD0181_$2 | main::toD0181_$5
Inversing boolean not [2] memset::$1 = memset::num#1 <= 0 from [1] memset::$0 = memset::num#1 > 0
Successful SSA optimization Pass2UnaryNotSimplification
Alias memset::return#0 = memset::str#1 memset::return#3 memset::return#1
Alias memset::str#2 = memset::str#3
Alias memset::num#1 = memset::num#2
Alias memset::c#3 = memset::c#4
Alias memset::end#0 = memset::$2
Alias memset::c#1 = memset::c#2
Alias memset::dst#2 = memset::dst#3
Alias memset::end#1 = memset::end#2
Alias memset::str#4 = memset::str#5
Alias main::toD0181_screen#0 = main::toD0181_screen#1
Alias main::toD0181_gfx#0 = main::toD0181_gfx#1
Alias main::toD0181_return#0 = main::toD0181_$6 main::toD0181_return#2 main::toD0181_return#1 main::toD0181_return#3 main::$0
Successful SSA optimization Pass2AliasElimination
Identical Phi Values memset::num#1 memset::num#0
Identical Phi Values memset::str#2 memset::str#0
Identical Phi Values memset::c#3 memset::c#0
Identical Phi Values memset::end#1 memset::end#0
Identical Phi Values memset::str#4 memset::str#2
Identical Phi Values memset::c#1 memset::c#3
Successful SSA optimization Pass2IdenticalPhiElimination
Identical Phi Values memset::return#0 memset::str#0
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition memset::$1 [2] if(memset::num#0<=0) goto memset::@1
Simple Condition memset::$3 [9] if(memset::dst#2!=memset::end#0) goto memset::@4
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant main::toD0181_screen#0 = DEFAULT_SCREEN
Constant main::toD0181_gfx#0 = DYPPA_CHARSET
Constant memset::str#0 = (void*)DEFAULT_SCREEN
Constant memset::num#0 = $3e8
Successful SSA optimization Pass2ConstantIdentification
Constant memset::$4 = (byte*)memset::str#0
Constant memset::dst#0 = (byte*)memset::str#0
Constant main::toD0181_$7 = (word)main::toD0181_screen#0
Constant memset::return#2 = memset::str#0
Successful SSA optimization Pass2ConstantIdentification
Constant value identified (word)main::toD0181_gfx#0 in [19] main::toD0181_$3 = > (word)main::toD0181_gfx#0
Successful SSA optimization Pass2ConstantValues
if() condition always false - eliminating [2] if(memset::num#0<=0) goto memset::@1
Successful SSA optimization Pass2ConstantIfs
Simplifying expression containing zero DYPPA_TABLE in [25] memset::c#0 = DYPPA_TABLE[0]
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused constant memset::return#2
Successful SSA optimization PassNEliminateUnusedVars
Removing unused block main::@return
Successful SSA optimization Pass2EliminateUnusedBlocks
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Constant right-side identified [0] memset::end#0 = memset::$4 + memset::num#0
Constant right-side identified [6] main::toD0181_$0 = main::toD0181_$7 & $3fff
Constant right-side identified [9] main::toD0181_$3 = > (word)main::toD0181_gfx#0
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant memset::end#0 = memset::$4+memset::num#0
Constant main::toD0181_$0 = main::toD0181_$7&$3fff
Constant main::toD0181_$3 = >(word)main::toD0181_gfx#0
Successful SSA optimization Pass2ConstantIdentification
Constant right-side identified [5] main::toD0181_$1 = main::toD0181_$0 * 4
Constant right-side identified [7] main::toD0181_$4 = main::toD0181_$3 / 4
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant main::toD0181_$1 = main::toD0181_$0*4
Constant main::toD0181_$4 = main::toD0181_$3/4
Successful SSA optimization Pass2ConstantIdentification
Constant right-side identified [5] main::toD0181_$2 = > main::toD0181_$1
Constant right-side identified [6] main::toD0181_$5 = main::toD0181_$4 & $f
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant main::toD0181_$2 = >main::toD0181_$1
Constant main::toD0181_$5 = main::toD0181_$4&$f
Successful SSA optimization Pass2ConstantIdentification
Constant right-side identified [5] main::toD0181_return#0 = main::toD0181_$2 | main::toD0181_$5
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant main::toD0181_return#0 = main::toD0181_$2|main::toD0181_$5
Successful SSA optimization Pass2ConstantIdentification
Inlining constant with var siblings memset::dst#0
Constant inlined main::toD0181_screen#0 = DEFAULT_SCREEN
Constant inlined main::toD0181_gfx#0 = DYPPA_CHARSET
Constant inlined main::toD0181_$7 = (word)DEFAULT_SCREEN
Constant inlined memset::$4 = (byte*)memset::str#0
Constant inlined main::toD0181_$2 = >(word)DEFAULT_SCREEN&$3fff*4
Constant inlined main::toD0181_$1 = (word)DEFAULT_SCREEN&$3fff*4
Constant inlined main::toD0181_$0 = (word)DEFAULT_SCREEN&$3fff
Constant inlined memset::dst#0 = (byte*)memset::str#0
Constant inlined main::toD0181_$5 = >(word)DYPPA_CHARSET/4&$f
Constant inlined main::toD0181_$4 = >(word)DYPPA_CHARSET/4
Constant inlined main::toD0181_$3 = >(word)DYPPA_CHARSET
Successful SSA optimization Pass2ConstantInlining
Adding NOP phi() at start of main
Adding NOP phi() at start of main::toD0181
Adding NOP phi() at start of main::toD0181_@return
Adding NOP phi() at start of main::@3
Adding NOP phi() at start of memset
Adding NOP phi() at start of memset::@2
Adding NOP phi() at start of memset::@1
CALL GRAPH
Calls in [main] to memset:5
Created 1 initial phi equivalence classes
Coalesced [16] memset::dst#4 = memset::dst#1
Coalesced down to 1 phi equivalence classes
Culled Empty Block label main::toD0181_@return
Culled Empty Block label main::@3
Culled Empty Block label memset::@2
Culled Empty Block label memset::@1
Renumbering block memset::@3 to memset::@1
Renumbering block memset::@4 to memset::@2
Adding NOP phi() at start of main
Adding NOP phi() at start of main::toD0181
Adding NOP phi() at start of memset
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] phi()
to:main::toD0181
main::toD0181: scope:[main] from main
[1] phi()
to:main::@2
main::@2: scope:[main] from main::toD0181
[2] *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_MEMORY) = main::toD0181_return#0
[3] memset::c#0 = *DYPPA_TABLE
[4] call memset
to:main::@1
main::@1: scope:[main] from main::@1 main::@2
[5] *(DEFAULT_SCREEN+$3e7) = ++ *(DEFAULT_SCREEN+$3e7)
to:main::@1
void* memset(void* memset::str , byte memset::c , word memset::num)
memset: scope:[memset] from main::@2
[6] phi()
to:memset::@1
memset::@1: scope:[memset] from memset memset::@2
[7] memset::dst#2 = phi( memset/(byte*)memset::str#0, memset::@2/memset::dst#1 )
[8] if(memset::dst#2!=memset::end#0) goto memset::@2
to:memset::@return
memset::@return: scope:[memset] from memset::@1
[9] return
to:@return
memset::@2: scope:[memset] from memset::@1
[10] *memset::dst#2 = memset::c#0
[11] memset::dst#1 = ++ memset::dst#2
to:memset::@1
VARIABLE REGISTER WEIGHTS
void main()
byte* main::toD0181_gfx
byte main::toD0181_return
byte* main::toD0181_screen
void* memset(void* memset::str , byte memset::c , word memset::num)
byte memset::c
byte memset::c#0 17.166666666666664
byte* memset::dst
byte* memset::dst#1 202.0
byte* memset::dst#2 134.66666666666666
byte* memset::end
word memset::num
void* memset::return
void* memset::str
Initial phi equivalence classes
[ memset::dst#2 memset::dst#1 ]
Added variable memset::c#0 to live range equivalence class [ memset::c#0 ]
Complete equivalence classes
[ memset::dst#2 memset::dst#1 ]
[ memset::c#0 ]
Allocated zp[2]:2 [ memset::dst#2 memset::dst#1 ]
Allocated zp[1]:4 [ memset::c#0 ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [2] *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_MEMORY) = main::toD0181_return#0 [ ] ( [ ] { } ) always clobbers reg byte a
Statement [8] if(memset::dst#2!=memset::end#0) goto memset::@2 [ memset::c#0 memset::dst#2 ] ( memset:4 [ memset::c#0 memset::dst#2 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:4 [ memset::c#0 ]
Statement [10] *memset::dst#2 = memset::c#0 [ memset::c#0 memset::dst#2 ] ( memset:4 [ memset::c#0 memset::dst#2 ] { } ) always clobbers reg byte a reg byte y
Removing always clobbered register reg byte y as potential for zp[1]:4 [ memset::c#0 ]
Statement [2] *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_MEMORY) = main::toD0181_return#0 [ ] ( [ ] { } ) always clobbers reg byte a
Statement [8] if(memset::dst#2!=memset::end#0) goto memset::@2 [ memset::c#0 memset::dst#2 ] ( memset:4 [ memset::c#0 memset::dst#2 ] { } ) always clobbers reg byte a
Statement [10] *memset::dst#2 = memset::c#0 [ memset::c#0 memset::dst#2 ] ( memset:4 [ memset::c#0 memset::dst#2 ] { } ) always clobbers reg byte a reg byte y
Potential registers zp[2]:2 [ memset::dst#2 memset::dst#1 ] : zp[2]:2 ,
Potential registers zp[1]:4 [ memset::c#0 ] : zp[1]:4 , reg byte x ,
REGISTER UPLIFT SCOPES
Uplift Scope [memset] 336.67: zp[2]:2 [ memset::dst#2 memset::dst#1 ] 17.17: zp[1]:4 [ memset::c#0 ]
Uplift Scope [MOS6526_CIA]
Uplift Scope [MOS6569_VICII]
Uplift Scope [MOS6581_SID]
Uplift Scope [main]
Uplift Scope []
Uplifting [memset] best 713 combination zp[2]:2 [ memset::dst#2 memset::dst#1 ] reg byte x [ memset::c#0 ]
Uplifting [MOS6526_CIA] best 713 combination
Uplifting [MOS6569_VICII] best 713 combination
Uplifting [MOS6581_SID] best 713 combination
Uplifting [main] best 713 combination
Uplifting [] best 713 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Chunky DYPP with arbitrary sinus
// First implemented as dyppa.asm in 2011
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_MOS6569_VICII_MEMORY = $18
// The VIC-II MOS 6567/6569
.label VICII = $d000
// Default address of screen character matrix
.label DEFAULT_SCREEN = $400
// main
main: {
.const toD0181_return = (>(DEFAULT_SCREEN&$3fff)*4)|(>DYPPA_CHARSET)/4&$f
// [1] phi from main to main::toD0181 [phi:main->main::toD0181]
toD0181_from_main:
jmp toD0181
// main::toD0181
toD0181:
jmp __b2
// main::@2
__b2:
// [2] *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_MEMORY) = main::toD0181_return#0 -- _deref_pbuc1=vbuc2
lda #toD0181_return
sta VICII+OFFSET_STRUCT_MOS6569_VICII_MEMORY
// [3] memset::c#0 = *DYPPA_TABLE -- vbuxx=_deref_pbuc1
ldx DYPPA_TABLE
// [4] call memset
// [6] phi from main::@2 to memset [phi:main::@2->memset]
memset_from___b2:
jsr memset
jmp __b1
// main::@1
__b1:
// [5] *(DEFAULT_SCREEN+$3e7) = ++ *(DEFAULT_SCREEN+$3e7) -- _deref_pbuc1=_inc__deref_pbuc1
inc DEFAULT_SCREEN+$3e7
jmp __b1
}
// memset
// Copies the character c (an unsigned char) to the first num characters of the object pointed to by the argument str.
// memset(byte register(X) c)
memset: {
.const num = $3e8
.label str = DEFAULT_SCREEN
.label end = str+num
.label dst = 2
// [7] phi from memset to memset::@1 [phi:memset->memset::@1]
__b1_from_memset:
// [7] phi memset::dst#2 = (byte*)memset::str#0 [phi:memset->memset::@1#0] -- pbuz1=pbuc1
lda #<str
sta.z dst
lda #>str
sta.z dst+1
jmp __b1
// memset::@1
__b1:
// [8] if(memset::dst#2!=memset::end#0) goto memset::@2 -- pbuz1_neq_pbuc1_then_la1
lda.z dst+1
cmp #>end
bne __b2
lda.z dst
cmp #<end
bne __b2
jmp __breturn
// memset::@return
__breturn:
// [9] return
rts
// memset::@2
__b2:
// [10] *memset::dst#2 = memset::c#0 -- _deref_pbuz1=vbuxx
txa
ldy #0
sta (dst),y
// [11] memset::dst#1 = ++ memset::dst#2 -- pbuz1=_inc_pbuz1
inc.z dst
bne !+
inc.z dst+1
!:
// [7] phi from memset::@2 to memset::@1 [phi:memset::@2->memset::@1]
__b1_from___b2:
// [7] phi memset::dst#2 = memset::dst#1 [phi:memset::@2->memset::@1#0] -- register_copy
jmp __b1
}
// File Data
// The DYPPA tables mapping the slopes, offsets and pixels to the right character in the charset
// for(offset:0..7) for(slope:0..f) for(pixels: 0..f) glyph_id(offset,slope,pixels)
.align $100
DYPPA_TABLE:
.var dyppaFile2 = LoadBinary("dyppacharset.bin", "Charset=$000,Tables=$800")
.fill dyppaFile2.getTablesSize(), dyppaFile2.getTables(i)
.pc = $2000 "DYPPA_CHARSET"
// The DYPPA charset containing the sloped offset characters
DYPPA_CHARSET:
.var dyppaFile = LoadBinary("dyppacharset.bin", "Charset=$000,Tables=$800")
.fill dyppaFile.getCharsetSize(), dyppaFile.getCharset(i)
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp toD0181
Removing instruction jmp __b2
Removing instruction jmp __b1
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction toD0181_from_main:
Removing instruction toD0181:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __b2:
Removing instruction memset_from___b2:
Removing instruction __b1_from_memset:
Removing instruction __breturn:
Removing instruction __b1_from___b2:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
const nomodify byte* DEFAULT_SCREEN = (byte*) 1024
const byte* DYPPA_CHARSET[$800] = kickasm {{ .var dyppaFile = LoadBinary("dyppacharset.bin", "Charset=$000,Tables=$800")
.fill dyppaFile.getCharsetSize(), dyppaFile.getCharset(i)
}}
const byte* DYPPA_TABLE[$800] = kickasm {{ .var dyppaFile2 = LoadBinary("dyppacharset.bin", "Charset=$000,Tables=$800")
.fill dyppaFile2.getTablesSize(), dyppaFile2.getTables(i)
}}
const byte OFFSET_STRUCT_MOS6569_VICII_MEMORY = $18
const nomodify struct MOS6569_VICII* VICII = (struct MOS6569_VICII*) 53248
void main()
byte* main::toD0181_gfx
byte main::toD0181_return
const byte main::toD0181_return#0 toD0181_return = >(word)DEFAULT_SCREEN&$3fff*4|>(word)DYPPA_CHARSET/4&$f
byte* main::toD0181_screen
void* memset(void* memset::str , byte memset::c , word memset::num)
byte memset::c
byte memset::c#0 reg byte x 17.166666666666664
byte* memset::dst
byte* memset::dst#1 dst zp[2]:2 202.0
byte* memset::dst#2 dst zp[2]:2 134.66666666666666
byte* memset::end
const byte* memset::end#0 end = (byte*)memset::str#0+memset::num#0
word memset::num
const word memset::num#0 num = $3e8
void* memset::return
void* memset::str
const void* memset::str#0 str = (void*)DEFAULT_SCREEN
zp[2]:2 [ memset::dst#2 memset::dst#1 ]
reg byte x [ memset::c#0 ]
FINAL ASSEMBLER
Score: 617
// File Comments
// Chunky DYPP with arbitrary sinus
// First implemented as dyppa.asm in 2011
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_MOS6569_VICII_MEMORY = $18
// The VIC-II MOS 6567/6569
.label VICII = $d000
// Default address of screen character matrix
.label DEFAULT_SCREEN = $400
// main
main: {
.const toD0181_return = (>(DEFAULT_SCREEN&$3fff)*4)|(>DYPPA_CHARSET)/4&$f
// [1] phi from main to main::toD0181 [phi:main->main::toD0181]
// main::toD0181
// main::@2
// VICII->MEMORY = toD018(DEFAULT_SCREEN, DYPPA_CHARSET)
// [2] *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_MEMORY) = main::toD0181_return#0 -- _deref_pbuc1=vbuc2
lda #toD0181_return
sta VICII+OFFSET_STRUCT_MOS6569_VICII_MEMORY
// memset(DEFAULT_SCREEN, DYPPA_TABLE[0], 1000)
// [3] memset::c#0 = *DYPPA_TABLE -- vbuxx=_deref_pbuc1
ldx DYPPA_TABLE
// [4] call memset
// [6] phi from main::@2 to memset [phi:main::@2->memset]
jsr memset
// main::@1
__b1:
// (*(DEFAULT_SCREEN+999))++;
// [5] *(DEFAULT_SCREEN+$3e7) = ++ *(DEFAULT_SCREEN+$3e7) -- _deref_pbuc1=_inc__deref_pbuc1
inc DEFAULT_SCREEN+$3e7
jmp __b1
}
// memset
// Copies the character c (an unsigned char) to the first num characters of the object pointed to by the argument str.
// memset(byte register(X) c)
memset: {
.const num = $3e8
.label str = DEFAULT_SCREEN
.label end = str+num
.label dst = 2
// [7] phi from memset to memset::@1 [phi:memset->memset::@1]
// [7] phi memset::dst#2 = (byte*)memset::str#0 [phi:memset->memset::@1#0] -- pbuz1=pbuc1
lda #<str
sta.z dst
lda #>str
sta.z dst+1
// memset::@1
__b1:
// for(char* dst = str; dst!=end; dst++)
// [8] if(memset::dst#2!=memset::end#0) goto memset::@2 -- pbuz1_neq_pbuc1_then_la1
lda.z dst+1
cmp #>end
bne __b2
lda.z dst
cmp #<end
bne __b2
// memset::@return
// }
// [9] return
rts
// memset::@2
__b2:
// *dst = c
// [10] *memset::dst#2 = memset::c#0 -- _deref_pbuz1=vbuxx
txa
ldy #0
sta (dst),y
// for(char* dst = str; dst!=end; dst++)
// [11] memset::dst#1 = ++ memset::dst#2 -- pbuz1=_inc_pbuz1
inc.z dst
bne !+
inc.z dst+1
!:
// [7] phi from memset::@2 to memset::@1 [phi:memset::@2->memset::@1]
// [7] phi memset::dst#2 = memset::dst#1 [phi:memset::@2->memset::@1#0] -- register_copy
jmp __b1
}
// File Data
// The DYPPA tables mapping the slopes, offsets and pixels to the right character in the charset
// for(offset:0..7) for(slope:0..f) for(pixels: 0..f) glyph_id(offset,slope,pixels)
.align $100
DYPPA_TABLE:
.var dyppaFile2 = LoadBinary("dyppacharset.bin", "Charset=$000,Tables=$800")
.fill dyppaFile2.getTablesSize(), dyppaFile2.getTables(i)
.pc = $2000 "DYPPA_CHARSET"
// The DYPPA charset containing the sloped offset characters
DYPPA_CHARSET:
.var dyppaFile = LoadBinary("dyppacharset.bin", "Charset=$000,Tables=$800")
.fill dyppaFile.getCharsetSize(), dyppaFile.getCharset(i)

View File

@ -0,0 +1,30 @@
const nomodify byte* DEFAULT_SCREEN = (byte*) 1024
const byte* DYPPA_CHARSET[$800] = kickasm {{ .var dyppaFile = LoadBinary("dyppacharset.bin", "Charset=$000,Tables=$800")
.fill dyppaFile.getCharsetSize(), dyppaFile.getCharset(i)
}}
const byte* DYPPA_TABLE[$800] = kickasm {{ .var dyppaFile2 = LoadBinary("dyppacharset.bin", "Charset=$000,Tables=$800")
.fill dyppaFile2.getTablesSize(), dyppaFile2.getTables(i)
}}
const byte OFFSET_STRUCT_MOS6569_VICII_MEMORY = $18
const nomodify struct MOS6569_VICII* VICII = (struct MOS6569_VICII*) 53248
void main()
byte* main::toD0181_gfx
byte main::toD0181_return
const byte main::toD0181_return#0 toD0181_return = >(word)DEFAULT_SCREEN&$3fff*4|>(word)DYPPA_CHARSET/4&$f
byte* main::toD0181_screen
void* memset(void* memset::str , byte memset::c , word memset::num)
byte memset::c
byte memset::c#0 reg byte x 17.166666666666664
byte* memset::dst
byte* memset::dst#1 dst zp[2]:2 202.0
byte* memset::dst#2 dst zp[2]:2 134.66666666666666
byte* memset::end
const byte* memset::end#0 end = (byte*)memset::str#0+memset::num#0
word memset::num
const word memset::num#0 num = $3e8
void* memset::return
void* memset::str
const void* memset::str#0 str = (void*)DEFAULT_SCREEN
zp[2]:2 [ memset::dst#2 memset::dst#1 ]
reg byte x [ memset::c#0 ]

View File

@ -0,0 +1,23 @@
// Test a trivial loop head constant
// For trivially constant loop heads for(;;) loops can be written to run body before comparison
// The simplest possible for-loop with a constant loop head.
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label SCREEN = $400
main: {
ldx #0
__b1:
// for(char i=0;i<40;i++)
cpx #$28
bcc __b2
// }
rts
__b2:
// SCREEN[i] = '*'
lda #'*'
sta SCREEN,x
// for(char i=0;i<40;i++)
inx
jmp __b1
}

View File

@ -0,0 +1,16 @@
void main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[1] main::i#2 = phi( main/0, main::@2/main::i#1 )
[2] if(main::i#2<$28) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1
[4] SCREEN[main::i#2] = '*'
[5] main::i#1 = ++ main::i#2
to:main::@1

View File

@ -0,0 +1,218 @@
CONTROL FLOW GRAPH SSA
void main()
main: scope:[main] from __start
main::i#0 = 0
to:main::@1
main::@1: scope:[main] from main main::@2
main::i#2 = phi( main/main::i#0, main::@2/main::i#1 )
main::$0 = main::i#2 < $28
if(main::$0) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
main::i#3 = phi( main::@1/main::i#2 )
SCREEN[main::i#3] = '*'
main::i#1 = ++ main::i#3
to:main::@1
main::@return: scope:[main] from main::@1
return
to:@return
void __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
const nomodify byte* SCREEN = (byte*)$400
void __start()
void main()
bool~ main::$0
byte main::i
byte main::i#0
byte main::i#1
byte main::i#2
byte main::i#3
Adding number conversion cast (unumber) $28 in main::$0 = main::i#2 < $28
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast $28
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type $28
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias main::i#2 = main::i#3
Successful SSA optimization Pass2AliasElimination
Simple Condition main::$0 [3] if(main::i#2<$28) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Inlining constant with var siblings main::i#0
Constant inlined main::i#0 = 0
Successful SSA optimization Pass2ConstantInlining
Adding NOP phi() at start of main
CALL GRAPH
Created 1 initial phi equivalence classes
Coalesced [6] main::i#4 = main::i#1
Coalesced down to 1 phi equivalence classes
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[1] main::i#2 = phi( main/0, main::@2/main::i#1 )
[2] if(main::i#2<$28) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1
[4] SCREEN[main::i#2] = '*'
[5] main::i#1 = ++ main::i#2
to:main::@1
VARIABLE REGISTER WEIGHTS
void main()
byte main::i
byte main::i#1 22.0
byte main::i#2 14.666666666666666
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
Allocated zp[1]:2 [ main::i#2 main::i#1 ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] SCREEN[main::i#2] = '*' [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ]
Statement [4] SCREEN[main::i#2] = '*' [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 36.67: zp[1]:2 [ main::i#2 main::i#1 ]
Uplift Scope []
Uplifting [main] best 251 combination reg byte x [ main::i#2 main::i#1 ]
Uplifting [] best 251 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test a trivial loop head constant
// For trivially constant loop heads for(;;) loops can be written to run body before comparison
// The simplest possible for-loop with a constant loop head.
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// main
main: {
// [1] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [1] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
jmp __b1
// main::@1
__b1:
// [2] if(main::i#2<$28) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
cpx #$28
bcc __b2
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
// main::@2
__b2:
// [4] SCREEN[main::i#2] = '*' -- pbuc1_derefidx_vbuxx=vbuc2
lda #'*'
sta SCREEN,x
// [5] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx
inx
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [1] phi main::i#2 = main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __b1_from_main:
Removing instruction __breturn:
Removing instruction __b1_from___b2:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
const nomodify byte* SCREEN = (byte*) 1024
void main()
byte main::i
byte main::i#1 reg byte x 22.0
byte main::i#2 reg byte x 14.666666666666666
reg byte x [ main::i#2 main::i#1 ]
FINAL ASSEMBLER
Score: 191
// File Comments
// Test a trivial loop head constant
// For trivially constant loop heads for(;;) loops can be written to run body before comparison
// The simplest possible for-loop with a constant loop head.
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// main
main: {
// [1] phi from main to main::@1 [phi:main->main::@1]
// [1] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
// main::@1
__b1:
// for(char i=0;i<40;i++)
// [2] if(main::i#2<$28) goto main::@2 -- vbuxx_lt_vbuc1_then_la1
cpx #$28
bcc __b2
// main::@return
// }
// [3] return
rts
// main::@2
__b2:
// SCREEN[i] = '*'
// [4] SCREEN[main::i#2] = '*' -- pbuc1_derefidx_vbuxx=vbuc2
lda #'*'
sta SCREEN,x
// for(char i=0;i<40;i++)
// [5] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx
inx
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
// [1] phi main::i#2 = main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data

View File

@ -0,0 +1,7 @@
const nomodify byte* SCREEN = (byte*) 1024
void main()
byte main::i
byte main::i#1 reg byte x 22.0
byte main::i#2 reg byte x 14.666666666666666
reg byte x [ main::i#2 main::i#1 ]