diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2AliasElimination.java b/src/main/java/dk/camelot64/kickc/passes/Pass2AliasElimination.java index d0a5a4b52..528127289 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2AliasElimination.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2AliasElimination.java @@ -212,12 +212,13 @@ public class Pass2AliasElimination extends Pass2SsaOptimization { } } } else if(statement instanceof StatementPhiBlock) { + boolean modified = false; StatementPhiBlock phiBlock = (StatementPhiBlock) statement; Iterator variableIterator = phiBlock.getPhiVariables().iterator(); while(variableIterator.hasNext()) { StatementPhiBlock.PhiVariable phiVariable = variableIterator.next(); AliasSet aliasSet = aliases.findAliasSet(phiVariable.getVariable()); - if(aliasSet != null) { + if(aliasSet != null && phiVariable.getValues().size()>0) { boolean remove = true; for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) { if(!aliasSet.contains(phiRValue.getrValue())) { @@ -227,10 +228,11 @@ public class Pass2AliasElimination extends Pass2SsaOptimization { } if(remove) { variableIterator.remove(); + modified = true; } } } - if(phiBlock.getPhiVariables().size() == 0) { + if(modified && phiBlock.getPhiVariables().size() == 0) { iterator.remove(); } } diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index caaaccb80..63aabb4f2 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -84,30 +84,30 @@ public class TestPrograms { compileAndCompare("examples/tetris/tetris"); } + @Test + public void testVarInitProblem() throws IOException, URISyntaxException { + compileAndCompare("var-init-problem"); + } + /* - @Test - public void testVarInitProblem() throws IOException, URISyntaxException { - compileAndCompare("var-init-problem"); - } + @Test + public void testConstIfProblem() throws IOException, URISyntaxException { + compileAndCompare("const-if-problem"); + } - @Test - public void testConstIfProblem() throws IOException, URISyntaxException { - compileAndCompare("const-if-problem"); - } + @Test + public void testTetrisNullPointer() throws IOException, URISyntaxException { + compileAndCompare("tetris-npe"); + } - @Test - public void testTetrisNullPointer() throws IOException, URISyntaxException { - compileAndCompare("tetris-npe"); - } - - //@Test - //public void testUnrollCall() throws IOException, URISyntaxException { - // compileAndCompare("unroll-call"); - //} + //@Test + //public void testUnrollCall() throws IOException, URISyntaxException { + // compileAndCompare("unroll-call"); + //} - */ +*/ @Test public void testFastMultiply8() throws IOException, URISyntaxException { compileAndCompare("examples/fastmultiply/fastmultiply8.kc"); @@ -1182,6 +1182,7 @@ public class TestPrograms { /** * Ensures that the path to the passed file is created. + * * @param file The file to create a path for */ private void mkPath(File file) { @@ -1203,5 +1204,4 @@ public class TestPrograms { } - } \ No newline at end of file diff --git a/src/test/ref/var-init-problem.asm b/src/test/ref/var-init-problem.asm new file mode 100644 index 000000000..50225daec --- /dev/null +++ b/src/test/ref/var-init-problem.asm @@ -0,0 +1,9 @@ +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label screen = $400 +main: { + lda #'a' + sta screen + rts +} diff --git a/src/test/ref/var-init-problem.cfg b/src/test/ref/var-init-problem.cfg new file mode 100644 index 000000000..0f943b72c --- /dev/null +++ b/src/test/ref/var-init-problem.cfg @@ -0,0 +1,15 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] *((const byte*) screen#0) ← (byte) 'a' + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return diff --git a/src/test/ref/var-init-problem.log b/src/test/ref/var-init-problem.log new file mode 100644 index 000000000..5b20bee8c --- /dev/null +++ b/src/test/ref/var-init-problem.log @@ -0,0 +1,218 @@ + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (byte*) screen#6 ← phi( ) + to:@1 +main: scope:[main] from @1 + (byte*) screen#0 ← ((byte*)) (word/signed word/dword/signed dword) 1024 + *((byte*) screen#0) ← (byte) 'a' + to:main::@return +main::@return: scope:[main] from main + (byte*) screen#3 ← phi( main/(byte*) screen#0 ) + (byte*) screen#1 ← (byte*) screen#3 + return + to:@return +@1: scope:[] from @begin + (byte*) screen#5 ← phi( @begin/(byte*) screen#6 ) + call main + to:@2 +@2: scope:[] from @1 + (byte*) screen#4 ← phi( @1/(byte*) screen#1 ) + (byte*) screen#2 ← (byte*) screen#4 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(byte*) screen +(byte*) screen#0 +(byte*) screen#1 +(byte*) screen#2 +(byte*) screen#3 +(byte*) screen#4 +(byte*) screen#5 +(byte*) screen#6 + +Alias (byte*) screen#0 = (byte*) screen#3 (byte*) screen#1 +Alias (byte*) screen#5 = (byte*) screen#6 +Alias (byte*) screen#2 = (byte*) screen#4 +Successful SSA optimization Pass2AliasElimination +Redundant Phi (byte*) screen#5 VOID +Redundant Phi (byte*) screen#2 (byte*) screen#0 +Successful SSA optimization Pass2RedundantPhiElimination +Constant (const byte*) screen#0 = ((byte*))1024 +Successful SSA optimization Pass2ConstantIdentification +Culled Empty Block (label) @2 +Successful SSA optimization Pass2CullEmptyBlocks +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +CALL GRAPH +Calls in [] to main:2 + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] *((const byte*) screen#0) ← (byte) 'a' + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte*) screen + +Initial phi equivalence classes +Complete equivalence classes + +INITIAL ASM +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .label screen = $400 +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG4 @1 +b1: +//SEG5 [2] call main + jsr main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG7 @end +bend: +//SEG8 main +main: { + //SEG9 [4] *((const byte*) screen#0) ← (byte) 'a' -- _deref_pbuc1=vbuc2 + lda #'a' + sta screen + jmp breturn + //SEG10 main::@return + breturn: + //SEG11 [5] return + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] *((const byte*) screen#0) ← (byte) 'a' [ ] ( main:2 [ ] ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [] + +Uplifting [main] best 27 combination +Uplifting [] best 27 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .label screen = $400 +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG4 @1 +b1: +//SEG5 [2] call main + jsr main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG7 @end +bend: +//SEG8 main +main: { + //SEG9 [4] *((const byte*) screen#0) ← (byte) 'a' -- _deref_pbuc1=vbuc2 + lda #'a' + sta screen + jmp breturn + //SEG10 main::@return + breturn: + //SEG11 [5] return + rts +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction bend_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(byte*) screen +(const byte*) screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1024 + + + +FINAL ASSEMBLER +Score: 12 + +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .label screen = $400 +//SEG2 @begin +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 @1 +//SEG5 [2] call main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +//SEG7 @end +//SEG8 main +main: { + //SEG9 [4] *((const byte*) screen#0) ← (byte) 'a' -- _deref_pbuc1=vbuc2 + lda #'a' + sta screen + //SEG10 main::@return + //SEG11 [5] return + rts +} + diff --git a/src/test/ref/var-init-problem.sym b/src/test/ref/var-init-problem.sym new file mode 100644 index 000000000..0c1483dbb --- /dev/null +++ b/src/test/ref/var-init-problem.sym @@ -0,0 +1,8 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(byte*) screen +(const byte*) screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1024 +