diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index e09e701f7..6dedd5217 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -129,6 +129,8 @@ public class Compiler { new Pass1AssertUsedVars(program).execute(); new Pass1ProcedureInline(program).execute(); + //getLog().append("INLINED CONTROL FLOW GRAPH"); + //getLog().append(program.getGraph().toString(program)); new Pass1EliminateUncalledProcedures(program).execute(); new PassNEliminateUnusedVars(program).execute(); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1ProcedureInline.java b/src/main/java/dk/camelot64/kickc/passes/Pass1ProcedureInline.java index be0ad2365..1098f3c6d 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1ProcedureInline.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1ProcedureInline.java @@ -3,11 +3,9 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.model.CompileError; import dk.camelot64.kickc.model.ControlFlowBlock; import dk.camelot64.kickc.model.Program; -import dk.camelot64.kickc.model.statements.Statement; -import dk.camelot64.kickc.model.statements.StatementAssignment; -import dk.camelot64.kickc.model.statements.StatementCall; -import dk.camelot64.kickc.model.statements.StatementReturn; +import dk.camelot64.kickc.model.statements.*; import dk.camelot64.kickc.model.symbols.*; +import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.values.*; import java.util.List; @@ -69,29 +67,31 @@ public class Pass1ProcedureInline extends Pass1Base { // Set successors if(procedureBlock.getDefaultSuccessor() != null) { LabelRef procBlockSuccessorRef = procedureBlock.getDefaultSuccessor(); - if(procBlockSuccessorRef.getFullName().equals(SymbolRef.PROCEXIT_BLOCK_NAME)) { - // Set successor of the @return block to the rest block - inlineBlock.setDefaultSuccessor(restBlockLabel.getRef()); - } else { - Label procBlockSuccessor = getScope().getLabel(procBlockSuccessorRef); - String inlinedSuccessorName = getInlineSymbolName(procedure, procBlockSuccessor, serial); - Label inlinedSuccessorLabel = callScope.getLabel(inlinedSuccessorName); - inlineBlock.setDefaultSuccessor(inlinedSuccessorLabel.getRef()); - } + LabelRef inlinedSuccessor = inlineSuccessor(procBlockSuccessorRef, procedure, callScope, serial, restBlockLabel); + inlineBlock.setDefaultSuccessor(inlinedSuccessor); } if(procedureBlock.getConditionalSuccessor() != null) { - throw new CompileError("Not implemented Inline function conditional successors"); + LabelRef procBlockSuccessorRef = procedureBlock.getConditionalSuccessor(); + LabelRef inlinedSuccessor = inlineSuccessor(procBlockSuccessorRef, procedure, callScope, serial, restBlockLabel); + inlineBlock.setConditionalSuccessor(inlinedSuccessor); } } // Create a new block for the rest of the calling block ControlFlowBlock restBlock = new ControlFlowBlock(restBlockLabel.getRef(), callScope.getRef()); blocksIt.add(restBlock); // Generate return assignment - if(call.getlValue() != null) { + if(!procedure.getReturnType().equals(SymbolType.VOID)) { Variable procReturnVar = procedure.getVariable("return"); String inlinedReturnVarName = getInlineSymbolName(procedure, procReturnVar, serial); Variable inlinedReturnVar = callScope.getVariable(inlinedReturnVarName); restBlock.addStatement(new StatementAssignment(call.getlValue(), inlinedReturnVar.getRef())); + } else { + // Remove the tmp var receiving the result + LValue lValue = call.getlValue(); + if(lValue instanceof VariableRef) { + callScope.remove(getScope().getVariable((VariableRef) lValue)); + call.setlValue(null); + } } // Copy the rest of the calling block to the new block while(statementsIt.hasNext()) { @@ -116,6 +116,20 @@ public class Pass1ProcedureInline extends Pass1Base { return false; } + private LabelRef inlineSuccessor(LabelRef procBlockSuccessorRef, Procedure procedure, Scope callScope, int serial, Label restBlockLabel) { + LabelRef inlinedSuccessor; + if(procBlockSuccessorRef.getFullName().equals(SymbolRef.PROCEXIT_BLOCK_NAME)) { + // Set successor of the @return block to the rest block + inlinedSuccessor = restBlockLabel.getRef(); + } else { + Label procBlockSuccessor = getScope().getLabel(procBlockSuccessorRef); + String inlinedSuccessorName = getInlineSymbolName(procedure, procBlockSuccessor, serial); + Label inlinedSuccessorLabel = callScope.getLabel(inlinedSuccessorName); + inlinedSuccessor = inlinedSuccessorLabel.getRef(); + } + return inlinedSuccessor; + } + /** * Find the next inline serial number for the procedure being inlined in the calling scope. @@ -150,54 +164,66 @@ public class Pass1ProcedureInline extends Pass1Base { Statement inlinedStatement; if(procStatement instanceof StatementAssignment) { StatementAssignment procAssignment = (StatementAssignment) procStatement; - LValue inlineLValue = inlineLValue(procAssignment.getlValue(), procedure, callScope, serial); - RValue inlineRValue1 = inlineRValue(procAssignment.getrValue1(), procedure, callScope, serial); - RValue inlineRValue2 = inlineRValue(procAssignment.getrValue2(), procedure, callScope, serial); - inlinedStatement = new StatementAssignment(inlineLValue, inlineRValue1, procAssignment.getOperator(), inlineRValue2); + inlinedStatement = new StatementAssignment(procAssignment.getlValue(), procAssignment.getrValue1(), procAssignment.getOperator(), procAssignment.getrValue2()); + } else if(procStatement instanceof StatementConditionalJump) { + StatementConditionalJump procConditional = (StatementConditionalJump) procStatement; + LabelRef procDestinationRef = procConditional.getDestination(); + Label procDestination = getScope().getLabel(procDestinationRef); + Label inlinedDest = procDestination; + if(procDestination.getScope().equals(procedure)) { + String inlineSymbolName = getInlineSymbolName(procedure, procDestination, serial); + inlinedDest = callScope.getLabel(inlineSymbolName); + } + inlinedStatement = new StatementConditionalJump(procConditional.getrValue1(), procConditional.getOperator(), procConditional.getrValue2(), inlinedDest.getRef()); } else if(procStatement instanceof StatementReturn) { // No statement needed return null; } else { throw new CompileError("Statement type of Inline function not handled " + procStatement); } + if(inlinedStatement!=null) { + ValueReplacer.executeAll(inlinedStatement, new RValueInliner(procedure, serial, callScope), null, null); + } return inlinedStatement; } /** - * Find/create a new LValue to use when inlining an LValue from a procedure - * - * @param lValue The LValue bein used inside the procedure being inlined - * @param serial The serial number (counted up for each inlined call to the same function within the called calling scope). - * @return The LValue to use where the procedure is inlined. + * Ensures that all VariableRefs pointing to variables in the procedure being inlined are converted to refs to the new inlined variables + * Also copies all intermediate RValue objects to ensure they are not references to objects from the original statements in the procedure being inlined */ - private LValue inlineLValue(LValue lValue, Procedure procedure, Scope callScope, int serial) { - return (LValue) inlineRValue(lValue, procedure, callScope, serial); - } + private class RValueInliner implements ValueReplacer.Replacer { - /** - * Find/create a new RValue to use when inlining an RValue from a procedure - * - * @param rValue The RValue bein used inside the procedure being inlined - * @param serial The serial number (counted up for each inlined call to the same function within the called calling scope). - * @return The RValue to use where the procedure is inlined. - */ - private RValue inlineRValue(RValue rValue, Procedure procedure, Scope callScope, int serial) { - if(rValue == null) { - return null; - } else if(rValue instanceof VariableRef) { - VariableRef procVarRef = (VariableRef) rValue; - Variable procVar = getScope().getVariable(procVarRef); - if(procVar.getScope().equals(procedure)) { - String inlineSymbolName = getInlineSymbolName(procedure, procVar, serial); - Variable inlineVar = callScope.getVariable(inlineSymbolName); - return inlineVar.getRef(); - } else { - return procVarRef; + /** The scope where the precedure is being inlined into. */ + private final Scope callScope; + /** The procedure being inlined. */ + private final Procedure procedure; + /** The serial number (counted up for each inlined call to the same function within the called calling scope) */ + private final int serial; + + public RValueInliner(Procedure procedure, int serial, Scope callScope) { + this.procedure = procedure; + this.serial = serial; + this.callScope = callScope; + } + + @Override + public void execute(ValueReplacer.ReplaceableValue replaceable, Statement currentStmt, ListIterator stmtIt, ControlFlowBlock currentBlock) { + RValue rValue = replaceable.get(); + if(rValue instanceof VariableRef) { + VariableRef procVarRef = (VariableRef) rValue; + Variable procVar = Pass1ProcedureInline.this.getScope().getVariable(procVarRef); + if(procVar.getScope().equals(procedure)) { + String inlineSymbolName = Pass1ProcedureInline.this.getInlineSymbolName(procedure, procVar, serial); + Variable inlineVar = callScope.getVariable(inlineSymbolName); + replaceable.set(inlineVar.getRef()); + } + } else if(rValue instanceof PointerDereferenceSimple) { + replaceable.set(new PointerDereferenceSimple(((PointerDereferenceSimple) rValue).getPointer())); + } else if(rValue instanceof PointerDereferenceIndexed) { + replaceable.set(new PointerDereferenceIndexed(((PointerDereferenceIndexed) rValue).getPointer(), ((PointerDereferenceIndexed) rValue).getIndex())); + } else if(rValue instanceof CastValue) { + replaceable.set(new CastValue(((CastValue) rValue).getToType(), ((CastValue) rValue).getValue())); } - } else if(rValue instanceof ConstantValue) { - return rValue; - } else { - throw new CompileError("Symbol Type of Inline function not handled " + rValue); } } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2UnaryNotSimplification.java b/src/main/java/dk/camelot64/kickc/passes/Pass2UnaryNotSimplification.java index e89b72336..d9153450d 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2UnaryNotSimplification.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2UnaryNotSimplification.java @@ -50,7 +50,7 @@ public class Pass2UnaryNotSimplification extends Pass2SsaOptimization { ) { VariableRef tempVar = (VariableRef) assignment.getrValue2(); StatementAssignment tempAssignment = assignments.get(tempVar); - if(usages.get(tempVar) == 1 && tempAssignment.getOperator() != null) { + if(usages.get(tempVar) == 1 && tempAssignment!=null && tempAssignment.getOperator() != null) { switch(tempAssignment.getOperator().getOperator()) { case "<": createInverse(">=", assignment, tempAssignment); diff --git a/src/main/java/dk/camelot64/kickc/passes/ValueReplacer.java b/src/main/java/dk/camelot64/kickc/passes/ValueReplacer.java index 098fec45b..3f5cd6fd4 100644 --- a/src/main/java/dk/camelot64/kickc/passes/ValueReplacer.java +++ b/src/main/java/dk/camelot64/kickc/passes/ValueReplacer.java @@ -24,32 +24,42 @@ public class ValueReplacer { ListIterator statementsIt = block.getStatements().listIterator(); while(statementsIt.hasNext()) { Statement statement = statementsIt.next(); - if(statement instanceof StatementAssignment) { - executeAll(new ReplaceableLValue((StatementLValue) statement), replacer, statement, statementsIt, block); - executeAll(new ReplaceableRValue1((StatementAssignment) statement), replacer, statement, statementsIt, block); - executeAll(new ReplaceableRValue2((StatementAssignment) statement), replacer, statement, statementsIt, block); - } else if(statement instanceof StatementCall) { - executeAll(new ReplaceableLValue((StatementLValue) statement), replacer, statement, statementsIt, block); - StatementCall call = (StatementCall) statement; - if(call.getParameters() != null) { - int size = call.getParameters().size(); - for(int i = 0; i < size; i++) { - executeAll(new ReplaceableCallParameter(call, i), replacer, statement, statementsIt, block); - } - } - } else if(statement instanceof StatementConditionalJump) { - executeAll(new ReplaceableCondRValue1((StatementConditionalJump) statement), replacer, statement, statementsIt, block); - executeAll(new ReplaceableCondRValue2((StatementConditionalJump) statement), replacer, statement, statementsIt, block); - } else if(statement instanceof StatementReturn) { - executeAll(new ReplaceableReturn((StatementReturn) statement), replacer, statement, statementsIt, block); - } else if(statement instanceof StatementPhiBlock) { - for(StatementPhiBlock.PhiVariable phiVariable : ((StatementPhiBlock) statement).getPhiVariables()) { - executeAll(new ReplaceablePhiVariable(phiVariable), replacer, statement, statementsIt, block); - int size = phiVariable.getValues().size(); - for(int i = 0; i < size; i++) { - executeAll(new ReplaceablePhiValue(phiVariable, i), replacer, statement, statementsIt, block); - } - } + executeAll(statement, replacer, statementsIt, block); + } + } + } + + /** + * Execute a replacer on all replaceable values in a statement + * + * @param statement The statement + * @param replacer The replacer to execute + */ + public static void executeAll(Statement statement, Replacer replacer, ListIterator statementsIt, ControlFlowBlock block) { + if(statement instanceof StatementAssignment) { + executeAll(new ReplaceableLValue((StatementLValue) statement), replacer, statement, statementsIt, block); + executeAll(new ReplaceableRValue1((StatementAssignment) statement), replacer, statement, statementsIt, block); + executeAll(new ReplaceableRValue2((StatementAssignment) statement), replacer, statement, statementsIt, block); + } else if(statement instanceof StatementCall) { + executeAll(new ReplaceableLValue((StatementLValue) statement), replacer, statement, statementsIt, block); + StatementCall call = (StatementCall) statement; + if(call.getParameters() != null) { + int size = call.getParameters().size(); + for(int i = 0; i < size; i++) { + executeAll(new ReplaceableCallParameter(call, i), replacer, statement, statementsIt, block); + } + } + } else if(statement instanceof StatementConditionalJump) { + executeAll(new ReplaceableCondRValue1((StatementConditionalJump) statement), replacer, statement, statementsIt, block); + executeAll(new ReplaceableCondRValue2((StatementConditionalJump) statement), replacer, statement, statementsIt, block); + } else if(statement instanceof StatementReturn) { + executeAll(new ReplaceableReturn((StatementReturn) statement), replacer, statement, statementsIt, block); + } else if(statement instanceof StatementPhiBlock) { + for(StatementPhiBlock.PhiVariable phiVariable : ((StatementPhiBlock) statement).getPhiVariables()) { + executeAll(new ReplaceablePhiVariable(phiVariable), replacer, statement, statementsIt, block); + int size = phiVariable.getValues().size(); + for(int i = 0; i < size; i++) { + executeAll(new ReplaceablePhiValue(phiVariable, i), replacer, statement, statementsIt, block); } } } diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index ec3e26926..5befa4a52 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -44,11 +44,26 @@ public class TestPrograms { AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false); } + @Test + public void testInlineFunctionPrint() throws IOException, URISyntaxException { + compileAndCompare("inline-function-print"); + } + + @Test + public void testInlineFunctionIf() throws IOException, URISyntaxException { + compileAndCompare("inline-function-if"); + } + @Test public void testInlineFunction() throws IOException, URISyntaxException { compileAndCompare("inline-function"); } + @Test + public void testInlineFunctionMin() throws IOException, URISyntaxException { + compileAndCompare("inline-function-min"); + } + @Test public void testCompoundAssignment() throws IOException, URISyntaxException { compileAndCompare("compound-assignment"); diff --git a/src/test/java/dk/camelot64/kickc/test/kc/inline-function-if.kc b/src/test/java/dk/camelot64/kickc/test/kc/inline-function-if.kc new file mode 100644 index 000000000..8e0cd117a --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/kc/inline-function-if.kc @@ -0,0 +1,17 @@ +// Test inlining a slightly complex print function (containing an if) + +byte* screen = $400; + +void main() { + screen[0] = toUpper('c',true); + screen[1] = toUpper('m',false); +} + +inline byte toUpper(byte ch, bool bo) { + byte res = ch; + if(bo) { + res += $40; + } + return res; +} + diff --git a/src/test/java/dk/camelot64/kickc/test/kc/inline-function-min.kc b/src/test/java/dk/camelot64/kickc/test/kc/inline-function-min.kc new file mode 100644 index 000000000..9e03aed12 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/kc/inline-function-min.kc @@ -0,0 +1,13 @@ +// Test minimal inline function + +byte* screen = $0400; + +void main() { + screen[0] = sum(2, 1); + screen[1] = sum(10, 3); + screen[2] = sum(4, 8); +} + +inline byte sum( byte a, byte b) { + return a+b; +} \ No newline at end of file diff --git a/src/test/java/dk/camelot64/kickc/test/kc/inline-function-print.kc b/src/test/java/dk/camelot64/kickc/test/kc/inline-function-print.kc new file mode 100644 index 000000000..6830d19c9 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/kc/inline-function-print.kc @@ -0,0 +1,18 @@ +// TEst inlining a slightly complex print function (containing a loop) + +byte* screen = $400; + +void main() { + byte* hello = "hello world!@"; + print(screen, hello); + print(screen+2*40, hello); +} + +inline void print(byte* at, byte* msg) { + byte j=0; + for(byte i=0; msg[i]!='@'; i++) { + at[j] = msg[i]; + j += 2; + } +} + diff --git a/src/test/java/dk/camelot64/kickc/test/ref/inline-function-if.asm b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-if.asm new file mode 100644 index 000000000..7a881d74d --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-if.asm @@ -0,0 +1,15 @@ +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label screen = $400 + jsr main +main: { + .const toUpper1_ch = 'c' + .const toUpper2_ch = 'm' + .const toUpper1_res = toUpper1_ch+$40 + lda #toUpper1_res + sta screen+0 + lda #toUpper2_ch + sta screen+1 + rts +} diff --git a/src/test/java/dk/camelot64/kickc/test/ref/inline-function-if.cfg b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-if.cfg new file mode 100644 index 000000000..889ca87cd --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-if.cfg @@ -0,0 +1,27 @@ +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@2 +@2: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @2 + [3] phi() [ ] ( ) +main: scope:[main] from @2 + [4] phi() [ ] ( main:2 [ ] ) + to:main::toUpper1 +main::toUpper1: scope:[main] from main + [5] phi() [ ] ( main:2 [ ] ) + to:main::@1 +main::@1: scope:[main] from main::toUpper1 + [6] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (const byte) main::toUpper1_res#1 [ ] ( main:2 [ ] ) + to:main::toUpper2 +main::toUpper2: scope:[main] from main::@1 + [7] phi() [ ] ( main:2 [ ] ) + to:main::@2 +main::@2: scope:[main] from main::toUpper2 + [8] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::toUpper2_ch#0 [ ] ( main:2 [ ] ) + to:main::@return +main::@return: scope:[main] from main::@2 + [9] return [ ] ( main:2 [ ] ) + to:@return diff --git a/src/test/java/dk/camelot64/kickc/test/ref/inline-function-if.log b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-if.log new file mode 100644 index 000000000..064f972a3 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-if.log @@ -0,0 +1,607 @@ +PARSING src/test/java/dk/camelot64/kickc/test/kc/inline-function-if.kc +// Test inlining a slightly complex print function (containing an if) + +byte* screen = $400; + +void main() { + screen[0] = toUpper('c',true); + screen[1] = toUpper('m',false); +} + +inline byte toUpper(byte ch, bool bo) { + byte res = ch; + if(bo) { + res += $40; + } + return res; +} + + +SYMBOLS +(label) @1 +(label) @2 +(label) @begin +(label) @end +(void()) main() +(byte~) main::$0 +(byte~) main::$1 +(label) main::@return +(byte*) screen +inline (byte()) toUpper((byte) toUpper::ch , (bool) toUpper::bo) +(bool~) toUpper::$0 +(label) toUpper::@1 +(label) toUpper::@2 +(label) toUpper::@3 +(label) toUpper::@return +(bool) toUpper::bo +(byte) toUpper::ch +(byte) toUpper::res +(byte) toUpper::return + +Promoting word/signed word/dword/signed dword to byte* in screen ← ((byte*)) 1024 +INITIAL CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) screen ← ((byte*)) (word/signed word/dword/signed dword) 1024 + to:@1 +main: scope:[main] from + (byte~) main::$0 ← call toUpper (byte) 'c' true + *((byte*) screen + (byte/signed byte/word/signed word/dword/signed dword) 0) ← (byte~) main::$0 + (byte~) main::$1 ← call toUpper (byte) 'm' false + *((byte*) screen + (byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$1 + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + to:@2 +toUpper: scope:[toUpper] from + (byte) toUpper::res ← (byte) toUpper::ch + (bool~) toUpper::$0 ← ! (bool) toUpper::bo + if((bool~) toUpper::$0) goto toUpper::@1 + to:toUpper::@2 +toUpper::@1: scope:[toUpper] from toUpper toUpper::@2 + (byte) toUpper::return ← (byte) toUpper::res + to:toUpper::@return +toUpper::@2: scope:[toUpper] from toUpper + (byte) toUpper::res ← (byte) toUpper::res + (byte/signed byte/word/signed word/dword/signed dword) 64 + to:toUpper::@1 +toUpper::@return: scope:[toUpper] from toUpper::@1 toUpper::@3 + (byte) toUpper::return ← (byte) toUpper::return + return (byte) toUpper::return + to:@return +toUpper::@3: scope:[toUpper] from + to:toUpper::@return +@2: scope:[] from @1 + call main + to:@end +@end: scope:[] from @2 + +Inlined call (byte~) main::$0 ← call toUpper (byte) 'c' true +Inlined call (byte~) main::$1 ← call toUpper (byte) 'm' false +Removing unused procedure toUpper +Removing empty block main::toUpper1_@3 +Removing empty block main::toUpper2_@3 +Removing empty block @1 +PROCEDURE MODIFY VARIABLE ANALYSIS + +Completing Phi functions... +Completing Phi functions... +Completing Phi functions... +Completing Phi functions... +Completing Phi functions... +Completing Phi functions... + +CONTROL FLOW GRAPH SSA WITH ASSIGNMENT CALL & RETURN +@begin: scope:[] from + (byte*) screen#0 ← ((byte*)) (word/signed word/dword/signed dword) 1024 + to:@2 +main: scope:[main] from @2 + (byte*) screen#11 ← phi( @2/(byte*) screen#12 ) + (byte) main::toUpper1_ch#0 ← (byte) 'c' + (bool) main::toUpper1_bo#0 ← true + to:main::toUpper1 +main::toUpper1: scope:[main] from main + (byte*) screen#7 ← phi( main/(byte*) screen#11 ) + (bool) main::toUpper1_bo#1 ← phi( main/(bool) main::toUpper1_bo#0 ) + (byte) main::toUpper1_ch#1 ← phi( main/(byte) main::toUpper1_ch#0 ) + (byte) main::toUpper1_res#0 ← (byte) main::toUpper1_ch#1 + (bool) main::toUpper1_$0#0 ← ! (bool) main::toUpper1_bo#1 + if((bool) main::toUpper1_$0#0) goto main::toUpper1_@1 + to:main::toUpper1_@2 +main::toUpper1_@1: scope:[main] from main::toUpper1 main::toUpper1_@2 + (byte*) screen#5 ← phi( main::toUpper1/(byte*) screen#7 main::toUpper1_@2/(byte*) screen#8 ) + (byte) main::toUpper1_res#2 ← phi( main::toUpper1/(byte) main::toUpper1_res#0 main::toUpper1_@2/(byte) main::toUpper1_res#1 ) + (byte) main::toUpper1_return#0 ← (byte) main::toUpper1_res#2 + to:main::toUpper1_@return +main::toUpper1_@2: scope:[main] from main::toUpper1 + (byte*) screen#8 ← phi( main::toUpper1/(byte*) screen#7 ) + (byte) main::toUpper1_res#3 ← phi( main::toUpper1/(byte) main::toUpper1_res#0 ) + (byte) main::toUpper1_res#1 ← (byte) main::toUpper1_res#3 + (byte/signed byte/word/signed word/dword/signed dword) 64 + to:main::toUpper1_@1 +main::toUpper1_@return: scope:[main] from main::toUpper1_@1 + (byte*) screen#3 ← phi( main::toUpper1_@1/(byte*) screen#5 ) + (byte) main::toUpper1_return#2 ← phi( main::toUpper1_@1/(byte) main::toUpper1_return#0 ) + (byte) main::toUpper1_return#1 ← (byte) main::toUpper1_return#2 + to:main::@1 +main::@1: scope:[main] from main::toUpper1_@return + (byte*) screen#1 ← phi( main::toUpper1_@return/(byte*) screen#3 ) + (byte) main::toUpper1_return#3 ← phi( main::toUpper1_@return/(byte) main::toUpper1_return#1 ) + (byte~) main::$0 ← (byte) main::toUpper1_return#3 + *((byte*) screen#1 + (byte/signed byte/word/signed word/dword/signed dword) 0) ← (byte~) main::$0 + (byte) main::toUpper2_ch#0 ← (byte) 'm' + (bool) main::toUpper2_bo#0 ← false + to:main::toUpper2 +main::toUpper2: scope:[main] from main::@1 + (byte*) screen#9 ← phi( main::@1/(byte*) screen#1 ) + (bool) main::toUpper2_bo#1 ← phi( main::@1/(bool) main::toUpper2_bo#0 ) + (byte) main::toUpper2_ch#1 ← phi( main::@1/(byte) main::toUpper2_ch#0 ) + (byte) main::toUpper2_res#0 ← (byte) main::toUpper2_ch#1 + (bool) main::toUpper2_$0#0 ← ! (bool) main::toUpper2_bo#1 + if((bool) main::toUpper2_$0#0) goto main::toUpper2_@1 + to:main::toUpper2_@2 +main::toUpper2_@1: scope:[main] from main::toUpper2 main::toUpper2_@2 + (byte*) screen#6 ← phi( main::toUpper2/(byte*) screen#9 main::toUpper2_@2/(byte*) screen#10 ) + (byte) main::toUpper2_res#2 ← phi( main::toUpper2/(byte) main::toUpper2_res#0 main::toUpper2_@2/(byte) main::toUpper2_res#1 ) + (byte) main::toUpper2_return#0 ← (byte) main::toUpper2_res#2 + to:main::toUpper2_@return +main::toUpper2_@2: scope:[main] from main::toUpper2 + (byte*) screen#10 ← phi( main::toUpper2/(byte*) screen#9 ) + (byte) main::toUpper2_res#3 ← phi( main::toUpper2/(byte) main::toUpper2_res#0 ) + (byte) main::toUpper2_res#1 ← (byte) main::toUpper2_res#3 + (byte/signed byte/word/signed word/dword/signed dword) 64 + to:main::toUpper2_@1 +main::toUpper2_@return: scope:[main] from main::toUpper2_@1 + (byte*) screen#4 ← phi( main::toUpper2_@1/(byte*) screen#6 ) + (byte) main::toUpper2_return#2 ← phi( main::toUpper2_@1/(byte) main::toUpper2_return#0 ) + (byte) main::toUpper2_return#1 ← (byte) main::toUpper2_return#2 + to:main::@2 +main::@2: scope:[main] from main::toUpper2_@return + (byte*) screen#2 ← phi( main::toUpper2_@return/(byte*) screen#4 ) + (byte) main::toUpper2_return#3 ← phi( main::toUpper2_@return/(byte) main::toUpper2_return#1 ) + (byte~) main::$1 ← (byte) main::toUpper2_return#3 + *((byte*) screen#2 + (byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$1 + to:main::@return +main::@return: scope:[main] from main::@2 + return + to:@return +@2: scope:[] from @begin + (byte*) screen#12 ← phi( @begin/(byte*) screen#0 ) + call main param-assignment + to:@3 +@3: scope:[] from @2 + to:@end +@end: scope:[] from @3 + +SYMBOL TABLE SSA +(label) @2 +(label) @3 +(label) @begin +(label) @end +(void()) main() +(byte~) main::$0 +(byte~) main::$1 +(label) main::@1 +(label) main::@2 +(label) main::@return +(label) main::toUpper1 +(bool~) main::toUpper1_$0 +(bool) main::toUpper1_$0#0 +(label) main::toUpper1_@1 +(label) main::toUpper1_@2 +(label) main::toUpper1_@return +(bool) main::toUpper1_bo +(bool) main::toUpper1_bo#0 +(bool) main::toUpper1_bo#1 +(byte) main::toUpper1_ch +(byte) main::toUpper1_ch#0 +(byte) main::toUpper1_ch#1 +(byte) main::toUpper1_res +(byte) main::toUpper1_res#0 +(byte) main::toUpper1_res#1 +(byte) main::toUpper1_res#2 +(byte) main::toUpper1_res#3 +(byte) main::toUpper1_return +(byte) main::toUpper1_return#0 +(byte) main::toUpper1_return#1 +(byte) main::toUpper1_return#2 +(byte) main::toUpper1_return#3 +(label) main::toUpper2 +(bool~) main::toUpper2_$0 +(bool) main::toUpper2_$0#0 +(label) main::toUpper2_@1 +(label) main::toUpper2_@2 +(label) main::toUpper2_@return +(bool) main::toUpper2_bo +(bool) main::toUpper2_bo#0 +(bool) main::toUpper2_bo#1 +(byte) main::toUpper2_ch +(byte) main::toUpper2_ch#0 +(byte) main::toUpper2_ch#1 +(byte) main::toUpper2_res +(byte) main::toUpper2_res#0 +(byte) main::toUpper2_res#1 +(byte) main::toUpper2_res#2 +(byte) main::toUpper2_res#3 +(byte) main::toUpper2_return +(byte) main::toUpper2_return#0 +(byte) main::toUpper2_return#1 +(byte) main::toUpper2_return#2 +(byte) main::toUpper2_return#3 +(byte*) screen +(byte*) screen#0 +(byte*) screen#1 +(byte*) screen#10 +(byte*) screen#11 +(byte*) screen#12 +(byte*) screen#2 +(byte*) screen#3 +(byte*) screen#4 +(byte*) screen#5 +(byte*) screen#6 +(byte*) screen#7 +(byte*) screen#8 +(byte*) screen#9 + +OPTIMIZING CONTROL FLOW GRAPH +Culled Empty Block (label) @3 +Succesful SSA optimization Pass2CullEmptyBlocks +Not aliassing across scopes: screen#11 screen#12 +Alias (byte) main::toUpper1_ch#0 = (byte) main::toUpper1_ch#1 (byte) main::toUpper1_res#0 (byte) main::toUpper1_res#3 +Alias (bool) main::toUpper1_bo#0 = (bool) main::toUpper1_bo#1 +Alias (byte*) screen#11 = (byte*) screen#7 (byte*) screen#8 +Alias (byte) main::toUpper1_return#0 = (byte) main::toUpper1_res#2 (byte) main::toUpper1_return#2 (byte) main::toUpper1_return#1 (byte) main::toUpper1_return#3 (byte~) main::$0 +Alias (byte*) screen#1 = (byte*) screen#3 (byte*) screen#5 (byte*) screen#9 (byte*) screen#10 +Alias (byte) main::toUpper2_ch#0 = (byte) main::toUpper2_ch#1 (byte) main::toUpper2_res#0 (byte) main::toUpper2_res#3 +Alias (bool) main::toUpper2_bo#0 = (bool) main::toUpper2_bo#1 +Alias (byte) main::toUpper2_return#0 = (byte) main::toUpper2_res#2 (byte) main::toUpper2_return#2 (byte) main::toUpper2_return#1 (byte) main::toUpper2_return#3 (byte~) main::$1 +Alias (byte*) screen#2 = (byte*) screen#4 (byte*) screen#6 +Alias (byte*) screen#0 = (byte*) screen#12 +Succesful SSA optimization Pass2AliasElimination +Not aliassing across scopes: screen#11 screen#0 +Alias (byte*) screen#1 = (byte*) screen#11 (byte*) screen#2 +Succesful SSA optimization Pass2AliasElimination +Not aliassing across scopes: screen#1 screen#0 +Redundant Phi (byte*) screen#1 (byte*) screen#0 +Succesful SSA optimization Pass2RedundantPhiElimination +Rewriting ! if()-condition to reversed if() (bool) main::toUpper1_$0#0 ← ! (bool) main::toUpper1_bo#0 +Succesful SSA optimization Pass2ConditionalAndOrRewriting +Rewriting ! if()-condition to reversed if() (bool) main::toUpper2_$0#0 ← ! (bool) main::toUpper2_bo#0 +Succesful SSA optimization Pass2ConditionalAndOrRewriting +Constant (const byte*) screen#0 = ((byte*))1024 +Constant (const byte) main::toUpper1_ch#0 = 'c' +Constant (const bool) main::toUpper1_bo#0 = true +Constant (const byte) main::toUpper2_ch#0 = 'm' +Constant (const bool) main::toUpper2_bo#0 = false +Succesful SSA optimization Pass2ConstantIdentification +Constant (const byte) main::toUpper1_res#1 = main::toUpper1_ch#0+64 +Constant (const byte) main::toUpper2_res#1 = main::toUpper2_ch#0+64 +Succesful SSA optimization Pass2ConstantIdentification +Consolidated array index constant in *(screen#0+0) +Consolidated array index constant in *(screen#0+1) +Succesful SSA optimization Pass2ConstantAdditionElimination +Removing PHI-reference to removed block (main::toUpper1) in block main::toUpper1_@1 +if() condition always true - replacing block destination if((const bool) main::toUpper1_bo#0) goto main::toUpper1_@2 +if() condition always false - eliminating if((const bool) main::toUpper2_bo#0) goto main::toUpper2_@2 +Succesful SSA optimization Pass2ConstantIfs +Eliminating unused constant (const bool) main::toUpper1_bo#0 +Eliminating unused constant (const bool) main::toUpper2_bo#0 +Succesful SSA optimization PassNEliminateUnusedVars +Removing PHI-reference to removed block (main::toUpper2_@2) in block main::toUpper2_@1 +Removing unused block main::toUpper2_@2 +Succesful SSA optimization Pass2EliminateUnusedBlocks +Culled Empty Block (label) main::toUpper1_@2 +Culled Empty Block (label) main::toUpper1_@return +Culled Empty Block (label) main::toUpper2_@return +Succesful SSA optimization Pass2CullEmptyBlocks +Redundant Phi (byte) main::toUpper1_return#0 (const byte) main::toUpper1_res#1 +Redundant Phi (byte) main::toUpper2_return#0 (const byte) main::toUpper2_ch#0 +Succesful SSA optimization Pass2RedundantPhiElimination +Eliminating unused constant (const byte) main::toUpper2_res#1 +Succesful SSA optimization PassNEliminateUnusedVars +Culled Empty Block (label) main::toUpper1_@1 +Culled Empty Block (label) main::toUpper2_@1 +Succesful SSA optimization Pass2CullEmptyBlocks +OPTIMIZING CONTROL FLOW GRAPH +Block Sequence Planned @begin @2 @end main main::toUpper1 main::@1 main::toUpper2 main::@2 main::@return +Block Sequence Planned @begin @2 @end main main::toUpper1 main::@1 main::toUpper2 main::@2 main::@return +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +Adding NOP phi() at start of main::toUpper1 +Adding NOP phi() at start of main::toUpper2 +CALL GRAPH +Calls in [] to main:2 + +Propagating live ranges... +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Block Sequence Planned @begin @2 @end main main::toUpper1 main::@1 main::toUpper2 main::@2 main::@return +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +Adding NOP phi() at start of main::toUpper1 +Adding NOP phi() at start of main::toUpper2 +Propagating live ranges... + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@2 +@2: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @2 + [3] phi() [ ] ( ) +main: scope:[main] from @2 + [4] phi() [ ] ( main:2 [ ] ) + to:main::toUpper1 +main::toUpper1: scope:[main] from main + [5] phi() [ ] ( main:2 [ ] ) + to:main::@1 +main::@1: scope:[main] from main::toUpper1 + [6] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (const byte) main::toUpper1_res#1 [ ] ( main:2 [ ] ) + to:main::toUpper2 +main::toUpper2: scope:[main] from main::@1 + [7] phi() [ ] ( main:2 [ ] ) + to:main::@2 +main::@2: scope:[main] from main::toUpper2 + [8] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::toUpper2_ch#0 [ ] ( main:2 [ ] ) + to:main::@return +main::@return: scope:[main] from main::@2 + [9] return [ ] ( main:2 [ ] ) + to:@return + +DOMINATORS +@begin dominated by @begin +@2 dominated by @2 @begin +@end dominated by @2 @begin @end +main dominated by @2 @begin main +main::toUpper1 dominated by @2 main::toUpper1 @begin main +main::@1 dominated by @2 main::toUpper1 @begin main::@1 main +main::toUpper2 dominated by @2 main::toUpper1 @begin main::toUpper2 main::@1 main +main::@2 dominated by @2 main::toUpper1 @begin main::toUpper2 main::@1 main::@2 main +main::@return dominated by main::@return @2 main::toUpper1 @begin main::toUpper2 main::@1 main::@2 main + +NATURAL LOOPS + +NATURAL LOOPS WITH DEPTH +Found 0 loops in scope [] +Found 0 loops in scope [main] + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(bool~) main::toUpper1_$0 +(bool) main::toUpper1_bo +(byte) main::toUpper1_ch +(byte) main::toUpper1_res +(byte) main::toUpper1_return +(bool~) main::toUpper2_$0 +(bool) main::toUpper2_bo +(byte) main::toUpper2_ch +(byte) main::toUpper2_res +(byte) main::toUpper2_return +(byte*) screen + +Initial phi equivalence classes +Complete equivalence classes + +INITIAL ASM +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .label screen = $400 +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @2 [phi:@begin->@2] +b2_from_bbegin: + jmp b2 +//SEG4 @2 +b2: +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @2 to main [phi:@2->main] +main_from_b2: + jsr main +//SEG7 [3] phi from @2 to @end [phi:@2->@end] +bend_from_b2: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .const toUpper1_ch = 'c' + .const toUpper2_ch = 'm' + .const toUpper1_res = toUpper1_ch+$40 + //SEG10 [5] phi from main to main::toUpper1 [phi:main->main::toUpper1] + toUpper1_from_main: + jmp toUpper1 + //SEG11 main::toUpper1 + toUpper1: + jmp b1 + //SEG12 main::@1 + b1: + //SEG13 [6] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (const byte) main::toUpper1_res#1 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #toUpper1_res + sta screen+0 + //SEG14 [7] phi from main::@1 to main::toUpper2 [phi:main::@1->main::toUpper2] + toUpper2_from_b1: + jmp toUpper2 + //SEG15 main::toUpper2 + toUpper2: + jmp b2 + //SEG16 main::@2 + b2: + //SEG17 [8] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::toUpper2_ch#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #toUpper2_ch + sta screen+1 + jmp breturn + //SEG18 main::@return + breturn: + //SEG19 [9] return [ ] ( main:2 [ ] ) + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [6] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (const byte) main::toUpper1_res#1 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [8] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::toUpper2_ch#0 [ ] ( main:2 [ ] ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [] + +Uplifting [main] best 99 combination +Uplifting [] best 99 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .label screen = $400 +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @2 [phi:@begin->@2] +b2_from_bbegin: + jmp b2 +//SEG4 @2 +b2: +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @2 to main [phi:@2->main] +main_from_b2: + jsr main +//SEG7 [3] phi from @2 to @end [phi:@2->@end] +bend_from_b2: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .const toUpper1_ch = 'c' + .const toUpper2_ch = 'm' + .const toUpper1_res = toUpper1_ch+$40 + //SEG10 [5] phi from main to main::toUpper1 [phi:main->main::toUpper1] + toUpper1_from_main: + jmp toUpper1 + //SEG11 main::toUpper1 + toUpper1: + jmp b1 + //SEG12 main::@1 + b1: + //SEG13 [6] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (const byte) main::toUpper1_res#1 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #toUpper1_res + sta screen+0 + //SEG14 [7] phi from main::@1 to main::toUpper2 [phi:main::@1->main::toUpper2] + toUpper2_from_b1: + jmp toUpper2 + //SEG15 main::toUpper2 + toUpper2: + jmp b2 + //SEG16 main::@2 + b2: + //SEG17 [8] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::toUpper2_ch#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #toUpper2_ch + sta screen+1 + jmp breturn + //SEG18 main::@return + breturn: + //SEG19 [9] return [ ] ( main:2 [ ] ) + rts +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b2 +Removing instruction jmp bend +Removing instruction jmp toUpper1 +Removing instruction jmp b1 +Removing instruction jmp toUpper2 +Removing instruction jmp b2 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +Removing instruction b2_from_bbegin: +Removing instruction main_from_b2: +Removing instruction bend_from_b2: +Removing instruction toUpper1_from_main: +Removing instruction toUpper1: +Removing instruction toUpper2_from_b1: +Removing instruction toUpper2: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction b2: +Removing instruction bend: +Removing instruction b1: +Removing instruction b2: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @2 +(label) @begin +(label) @end +(void()) main() +(label) main::@1 +(label) main::@2 +(label) main::@return +(label) main::toUpper1 +(bool~) main::toUpper1_$0 +(bool) main::toUpper1_bo +(byte) main::toUpper1_ch +(const byte) main::toUpper1_ch#0 toUpper1_ch = (byte) 'c' +(byte) main::toUpper1_res +(const byte) main::toUpper1_res#1 toUpper1_res = (const byte) main::toUpper1_ch#0+(byte/signed byte/word/signed word/dword/signed dword) 64 +(byte) main::toUpper1_return +(label) main::toUpper2 +(bool~) main::toUpper2_$0 +(bool) main::toUpper2_bo +(byte) main::toUpper2_ch +(const byte) main::toUpper2_ch#0 toUpper2_ch = (byte) 'm' +(byte) main::toUpper2_res +(byte) main::toUpper2_return +(byte*) screen +(const byte*) screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1024 + + + +FINAL ASSEMBLER +Score: 24 + +//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 @2 [phi:@begin->@2] +//SEG4 @2 +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @2 to main [phi:@2->main] + jsr main +//SEG7 [3] phi from @2 to @end [phi:@2->@end] +//SEG8 @end +//SEG9 main +main: { + .const toUpper1_ch = 'c' + .const toUpper2_ch = 'm' + .const toUpper1_res = toUpper1_ch+$40 + //SEG10 [5] phi from main to main::toUpper1 [phi:main->main::toUpper1] + //SEG11 main::toUpper1 + //SEG12 main::@1 + //SEG13 [6] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (const byte) main::toUpper1_res#1 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #toUpper1_res + sta screen+0 + //SEG14 [7] phi from main::@1 to main::toUpper2 [phi:main::@1->main::toUpper2] + //SEG15 main::toUpper2 + //SEG16 main::@2 + //SEG17 [8] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::toUpper2_ch#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #toUpper2_ch + sta screen+1 + //SEG18 main::@return + //SEG19 [9] return [ ] ( main:2 [ ] ) + rts +} + diff --git a/src/test/java/dk/camelot64/kickc/test/ref/inline-function-if.sym b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-if.sym new file mode 100644 index 000000000..044c75bf5 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-if.sym @@ -0,0 +1,25 @@ +(label) @2 +(label) @begin +(label) @end +(void()) main() +(label) main::@1 +(label) main::@2 +(label) main::@return +(label) main::toUpper1 +(bool~) main::toUpper1_$0 +(bool) main::toUpper1_bo +(byte) main::toUpper1_ch +(const byte) main::toUpper1_ch#0 toUpper1_ch = (byte) 'c' +(byte) main::toUpper1_res +(const byte) main::toUpper1_res#1 toUpper1_res = (const byte) main::toUpper1_ch#0+(byte/signed byte/word/signed word/dword/signed dword) 64 +(byte) main::toUpper1_return +(label) main::toUpper2 +(bool~) main::toUpper2_$0 +(bool) main::toUpper2_bo +(byte) main::toUpper2_ch +(const byte) main::toUpper2_ch#0 toUpper2_ch = (byte) 'm' +(byte) main::toUpper2_res +(byte) main::toUpper2_return +(byte*) screen +(const byte*) screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1024 + diff --git a/src/test/java/dk/camelot64/kickc/test/ref/inline-function-min.asm b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-min.asm new file mode 100644 index 000000000..d380858d0 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-min.asm @@ -0,0 +1,23 @@ +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label screen = $400 + jsr main +main: { + .const sum1_a = 2 + .const sum1_b = 1 + .const sum2_a = $a + .const sum2_b = 3 + .const sum3_a = 4 + .const sum3_b = 8 + .const sum1_return = sum1_a+sum1_b + .const sum2_return = sum2_a+sum2_b + .const sum3_return = sum3_a+sum3_b + lda #sum1_return + sta screen+0 + lda #sum2_return + sta screen+1 + lda #sum3_return + sta screen+2 + rts +} diff --git a/src/test/java/dk/camelot64/kickc/test/ref/inline-function-min.cfg b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-min.cfg new file mode 100644 index 000000000..a849117cf --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-min.cfg @@ -0,0 +1,33 @@ +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@2 +@2: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @2 + [3] phi() [ ] ( ) +main: scope:[main] from @2 + [4] phi() [ ] ( main:2 [ ] ) + to:main::sum1 +main::sum1: scope:[main] from main + [5] phi() [ ] ( main:2 [ ] ) + to:main::@1 +main::@1: scope:[main] from main::sum1 + [6] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (const byte) main::sum1_return#0 [ ] ( main:2 [ ] ) + to:main::sum2 +main::sum2: scope:[main] from main::@1 + [7] phi() [ ] ( main:2 [ ] ) + to:main::@2 +main::@2: scope:[main] from main::sum2 + [8] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::sum2_return#0 [ ] ( main:2 [ ] ) + to:main::sum3 +main::sum3: scope:[main] from main::@2 + [9] phi() [ ] ( main:2 [ ] ) + to:main::@3 +main::@3: scope:[main] from main::sum3 + [10] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (const byte) main::sum3_return#0 [ ] ( main:2 [ ] ) + to:main::@return +main::@return: scope:[main] from main::@3 + [11] return [ ] ( main:2 [ ] ) + to:@return diff --git a/src/test/java/dk/camelot64/kickc/test/ref/inline-function-min.log b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-min.log new file mode 100644 index 000000000..e158bdca2 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-min.log @@ -0,0 +1,650 @@ +PARSING src/test/java/dk/camelot64/kickc/test/kc/inline-function-min.kc +// Test minimal inline function + +byte* screen = $0400; + +void main() { + screen[0] = sum(2, 1); + screen[1] = sum(10, 3); + screen[2] = sum(4, 8); +} + +inline byte sum( byte a, byte b) { + return a+b; +} +SYMBOLS +(label) @1 +(label) @2 +(label) @begin +(label) @end +(void()) main() +(byte~) main::$0 +(byte~) main::$1 +(byte~) main::$2 +(label) main::@return +(byte*) screen +inline (byte()) sum((byte) sum::a , (byte) sum::b) +(byte~) sum::$0 +(label) sum::@1 +(label) sum::@return +(byte) sum::a +(byte) sum::b +(byte) sum::return + +Promoting word/signed word/dword/signed dword to byte* in screen ← ((byte*)) 1024 +INITIAL CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) screen ← ((byte*)) (word/signed word/dword/signed dword) 1024 + to:@1 +main: scope:[main] from + (byte~) main::$0 ← call sum (byte/signed byte/word/signed word/dword/signed dword) 2 (byte/signed byte/word/signed word/dword/signed dword) 1 + *((byte*) screen + (byte/signed byte/word/signed word/dword/signed dword) 0) ← (byte~) main::$0 + (byte~) main::$1 ← call sum (byte/signed byte/word/signed word/dword/signed dword) 10 (byte/signed byte/word/signed word/dword/signed dword) 3 + *((byte*) screen + (byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$1 + (byte~) main::$2 ← call sum (byte/signed byte/word/signed word/dword/signed dword) 4 (byte/signed byte/word/signed word/dword/signed dword) 8 + *((byte*) screen + (byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte~) main::$2 + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + to:@2 +sum: scope:[sum] from + (byte~) sum::$0 ← (byte) sum::a + (byte) sum::b + (byte) sum::return ← (byte~) sum::$0 + to:sum::@return +sum::@return: scope:[sum] from sum sum::@1 + (byte) sum::return ← (byte) sum::return + return (byte) sum::return + to:@return +sum::@1: scope:[sum] from + to:sum::@return +@2: scope:[] from @1 + call main + to:@end +@end: scope:[] from @2 + +Inlined call (byte~) main::$0 ← call sum (byte/signed byte/word/signed word/dword/signed dword) 2 (byte/signed byte/word/signed word/dword/signed dword) 1 +Inlined call (byte~) main::$1 ← call sum (byte/signed byte/word/signed word/dword/signed dword) 10 (byte/signed byte/word/signed word/dword/signed dword) 3 +Inlined call (byte~) main::$2 ← call sum (byte/signed byte/word/signed word/dword/signed dword) 4 (byte/signed byte/word/signed word/dword/signed dword) 8 +Removing unused procedure sum +Removing empty block main::sum1_@1 +Removing empty block main::sum2_@1 +Removing empty block main::sum3_@1 +Removing empty block @1 +PROCEDURE MODIFY VARIABLE ANALYSIS + +Completing Phi functions... +Completing Phi functions... +Completing Phi functions... +Completing Phi functions... +Completing Phi functions... + +CONTROL FLOW GRAPH SSA WITH ASSIGNMENT CALL & RETURN +@begin: scope:[] from + (byte*) screen#0 ← ((byte*)) (word/signed word/dword/signed dword) 1024 + to:@2 +main: scope:[main] from @2 + (byte*) screen#10 ← phi( @2/(byte*) screen#11 ) + (byte) main::sum1_a#0 ← (byte/signed byte/word/signed word/dword/signed dword) 2 + (byte) main::sum1_b#0 ← (byte/signed byte/word/signed word/dword/signed dword) 1 + to:main::sum1 +main::sum1: scope:[main] from main + (byte*) screen#7 ← phi( main/(byte*) screen#10 ) + (byte) main::sum1_b#1 ← phi( main/(byte) main::sum1_b#0 ) + (byte) main::sum1_a#1 ← phi( main/(byte) main::sum1_a#0 ) + (byte) main::sum1_$0#0 ← (byte) main::sum1_a#1 + (byte) main::sum1_b#1 + (byte) main::sum1_return#0 ← (byte) main::sum1_$0#0 + to:main::sum1_@return +main::sum1_@return: scope:[main] from main::sum1 + (byte*) screen#4 ← phi( main::sum1/(byte*) screen#7 ) + (byte) main::sum1_return#2 ← phi( main::sum1/(byte) main::sum1_return#0 ) + (byte) main::sum1_return#1 ← (byte) main::sum1_return#2 + to:main::@1 +main::@1: scope:[main] from main::sum1_@return + (byte*) screen#1 ← phi( main::sum1_@return/(byte*) screen#4 ) + (byte) main::sum1_return#3 ← phi( main::sum1_@return/(byte) main::sum1_return#1 ) + (byte~) main::$0 ← (byte) main::sum1_return#3 + *((byte*) screen#1 + (byte/signed byte/word/signed word/dword/signed dword) 0) ← (byte~) main::$0 + (byte) main::sum2_a#0 ← (byte/signed byte/word/signed word/dword/signed dword) 10 + (byte) main::sum2_b#0 ← (byte/signed byte/word/signed word/dword/signed dword) 3 + to:main::sum2 +main::sum2: scope:[main] from main::@1 + (byte*) screen#8 ← phi( main::@1/(byte*) screen#1 ) + (byte) main::sum2_b#1 ← phi( main::@1/(byte) main::sum2_b#0 ) + (byte) main::sum2_a#1 ← phi( main::@1/(byte) main::sum2_a#0 ) + (byte) main::sum2_$0#0 ← (byte) main::sum2_a#1 + (byte) main::sum2_b#1 + (byte) main::sum2_return#0 ← (byte) main::sum2_$0#0 + to:main::sum2_@return +main::sum2_@return: scope:[main] from main::sum2 + (byte*) screen#5 ← phi( main::sum2/(byte*) screen#8 ) + (byte) main::sum2_return#2 ← phi( main::sum2/(byte) main::sum2_return#0 ) + (byte) main::sum2_return#1 ← (byte) main::sum2_return#2 + to:main::@2 +main::@2: scope:[main] from main::sum2_@return + (byte*) screen#2 ← phi( main::sum2_@return/(byte*) screen#5 ) + (byte) main::sum2_return#3 ← phi( main::sum2_@return/(byte) main::sum2_return#1 ) + (byte~) main::$1 ← (byte) main::sum2_return#3 + *((byte*) screen#2 + (byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte~) main::$1 + (byte) main::sum3_a#0 ← (byte/signed byte/word/signed word/dword/signed dword) 4 + (byte) main::sum3_b#0 ← (byte/signed byte/word/signed word/dword/signed dword) 8 + to:main::sum3 +main::sum3: scope:[main] from main::@2 + (byte*) screen#9 ← phi( main::@2/(byte*) screen#2 ) + (byte) main::sum3_b#1 ← phi( main::@2/(byte) main::sum3_b#0 ) + (byte) main::sum3_a#1 ← phi( main::@2/(byte) main::sum3_a#0 ) + (byte) main::sum3_$0#0 ← (byte) main::sum3_a#1 + (byte) main::sum3_b#1 + (byte) main::sum3_return#0 ← (byte) main::sum3_$0#0 + to:main::sum3_@return +main::sum3_@return: scope:[main] from main::sum3 + (byte*) screen#6 ← phi( main::sum3/(byte*) screen#9 ) + (byte) main::sum3_return#2 ← phi( main::sum3/(byte) main::sum3_return#0 ) + (byte) main::sum3_return#1 ← (byte) main::sum3_return#2 + to:main::@3 +main::@3: scope:[main] from main::sum3_@return + (byte*) screen#3 ← phi( main::sum3_@return/(byte*) screen#6 ) + (byte) main::sum3_return#3 ← phi( main::sum3_@return/(byte) main::sum3_return#1 ) + (byte~) main::$2 ← (byte) main::sum3_return#3 + *((byte*) screen#3 + (byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte~) main::$2 + to:main::@return +main::@return: scope:[main] from main::@3 + return + to:@return +@2: scope:[] from @begin + (byte*) screen#11 ← phi( @begin/(byte*) screen#0 ) + call main param-assignment + to:@3 +@3: scope:[] from @2 + to:@end +@end: scope:[] from @3 + +SYMBOL TABLE SSA +(label) @2 +(label) @3 +(label) @begin +(label) @end +(void()) main() +(byte~) main::$0 +(byte~) main::$1 +(byte~) main::$2 +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@return +(label) main::sum1 +(byte~) main::sum1_$0 +(byte) main::sum1_$0#0 +(label) main::sum1_@return +(byte) main::sum1_a +(byte) main::sum1_a#0 +(byte) main::sum1_a#1 +(byte) main::sum1_b +(byte) main::sum1_b#0 +(byte) main::sum1_b#1 +(byte) main::sum1_return +(byte) main::sum1_return#0 +(byte) main::sum1_return#1 +(byte) main::sum1_return#2 +(byte) main::sum1_return#3 +(label) main::sum2 +(byte~) main::sum2_$0 +(byte) main::sum2_$0#0 +(label) main::sum2_@return +(byte) main::sum2_a +(byte) main::sum2_a#0 +(byte) main::sum2_a#1 +(byte) main::sum2_b +(byte) main::sum2_b#0 +(byte) main::sum2_b#1 +(byte) main::sum2_return +(byte) main::sum2_return#0 +(byte) main::sum2_return#1 +(byte) main::sum2_return#2 +(byte) main::sum2_return#3 +(label) main::sum3 +(byte~) main::sum3_$0 +(byte) main::sum3_$0#0 +(label) main::sum3_@return +(byte) main::sum3_a +(byte) main::sum3_a#0 +(byte) main::sum3_a#1 +(byte) main::sum3_b +(byte) main::sum3_b#0 +(byte) main::sum3_b#1 +(byte) main::sum3_return +(byte) main::sum3_return#0 +(byte) main::sum3_return#1 +(byte) main::sum3_return#2 +(byte) main::sum3_return#3 +(byte*) screen +(byte*) screen#0 +(byte*) screen#1 +(byte*) screen#10 +(byte*) screen#11 +(byte*) screen#2 +(byte*) screen#3 +(byte*) screen#4 +(byte*) screen#5 +(byte*) screen#6 +(byte*) screen#7 +(byte*) screen#8 +(byte*) screen#9 + +OPTIMIZING CONTROL FLOW GRAPH +Culled Empty Block (label) @3 +Succesful SSA optimization Pass2CullEmptyBlocks +Not aliassing across scopes: screen#10 screen#11 +Alias (byte) main::sum1_a#0 = (byte) main::sum1_a#1 +Alias (byte) main::sum1_b#0 = (byte) main::sum1_b#1 +Alias (byte*) screen#1 = (byte*) screen#7 (byte*) screen#10 (byte*) screen#4 (byte*) screen#8 (byte*) screen#5 (byte*) screen#2 (byte*) screen#9 (byte*) screen#6 (byte*) screen#3 +Alias (byte) main::sum1_return#0 = (byte) main::sum1_$0#0 (byte) main::sum1_return#2 (byte) main::sum1_return#1 (byte) main::sum1_return#3 (byte~) main::$0 +Alias (byte) main::sum2_a#0 = (byte) main::sum2_a#1 +Alias (byte) main::sum2_b#0 = (byte) main::sum2_b#1 +Alias (byte) main::sum2_return#0 = (byte) main::sum2_$0#0 (byte) main::sum2_return#2 (byte) main::sum2_return#1 (byte) main::sum2_return#3 (byte~) main::$1 +Alias (byte) main::sum3_a#0 = (byte) main::sum3_a#1 +Alias (byte) main::sum3_b#0 = (byte) main::sum3_b#1 +Alias (byte) main::sum3_return#0 = (byte) main::sum3_$0#0 (byte) main::sum3_return#2 (byte) main::sum3_return#1 (byte) main::sum3_return#3 (byte~) main::$2 +Alias (byte*) screen#0 = (byte*) screen#11 +Succesful SSA optimization Pass2AliasElimination +Not aliassing across scopes: screen#1 screen#0 +Redundant Phi (byte*) screen#1 (byte*) screen#0 +Succesful SSA optimization Pass2RedundantPhiElimination +Constant (const byte*) screen#0 = ((byte*))1024 +Constant (const byte) main::sum1_a#0 = 2 +Constant (const byte) main::sum1_b#0 = 1 +Constant (const byte) main::sum2_a#0 = 10 +Constant (const byte) main::sum2_b#0 = 3 +Constant (const byte) main::sum3_a#0 = 4 +Constant (const byte) main::sum3_b#0 = 8 +Succesful SSA optimization Pass2ConstantIdentification +Constant (const byte) main::sum1_return#0 = main::sum1_a#0+main::sum1_b#0 +Constant (const byte) main::sum2_return#0 = main::sum2_a#0+main::sum2_b#0 +Constant (const byte) main::sum3_return#0 = main::sum3_a#0+main::sum3_b#0 +Succesful SSA optimization Pass2ConstantIdentification +Consolidated array index constant in *(screen#0+0) +Consolidated array index constant in *(screen#0+1) +Consolidated array index constant in *(screen#0+2) +Succesful SSA optimization Pass2ConstantAdditionElimination +Culled Empty Block (label) main::sum1_@return +Culled Empty Block (label) main::sum2_@return +Culled Empty Block (label) main::sum3_@return +Succesful SSA optimization Pass2CullEmptyBlocks +OPTIMIZING CONTROL FLOW GRAPH +Block Sequence Planned @begin @2 @end main main::sum1 main::@1 main::sum2 main::@2 main::sum3 main::@3 main::@return +Block Sequence Planned @begin @2 @end main main::sum1 main::@1 main::sum2 main::@2 main::sum3 main::@3 main::@return +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +Adding NOP phi() at start of main::sum1 +Adding NOP phi() at start of main::sum2 +Adding NOP phi() at start of main::sum3 +CALL GRAPH +Calls in [] to main:2 + +Propagating live ranges... +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Block Sequence Planned @begin @2 @end main main::sum1 main::@1 main::sum2 main::@2 main::sum3 main::@3 main::@return +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +Adding NOP phi() at start of main::sum1 +Adding NOP phi() at start of main::sum2 +Adding NOP phi() at start of main::sum3 +Propagating live ranges... + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@2 +@2: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @2 + [3] phi() [ ] ( ) +main: scope:[main] from @2 + [4] phi() [ ] ( main:2 [ ] ) + to:main::sum1 +main::sum1: scope:[main] from main + [5] phi() [ ] ( main:2 [ ] ) + to:main::@1 +main::@1: scope:[main] from main::sum1 + [6] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (const byte) main::sum1_return#0 [ ] ( main:2 [ ] ) + to:main::sum2 +main::sum2: scope:[main] from main::@1 + [7] phi() [ ] ( main:2 [ ] ) + to:main::@2 +main::@2: scope:[main] from main::sum2 + [8] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::sum2_return#0 [ ] ( main:2 [ ] ) + to:main::sum3 +main::sum3: scope:[main] from main::@2 + [9] phi() [ ] ( main:2 [ ] ) + to:main::@3 +main::@3: scope:[main] from main::sum3 + [10] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (const byte) main::sum3_return#0 [ ] ( main:2 [ ] ) + to:main::@return +main::@return: scope:[main] from main::@3 + [11] return [ ] ( main:2 [ ] ) + to:@return + +DOMINATORS +@begin dominated by @begin +@2 dominated by @2 @begin +@end dominated by @2 @begin @end +main dominated by @2 @begin main +main::sum1 dominated by @2 @begin main::sum1 main +main::@1 dominated by @2 @begin main::sum1 main::@1 main +main::sum2 dominated by @2 @begin main::sum1 main::@1 main main::sum2 +main::@2 dominated by @2 @begin main::sum1 main::@1 main::@2 main main::sum2 +main::sum3 dominated by @2 @begin main::sum1 main::@1 main::@2 main main::sum2 main::sum3 +main::@3 dominated by @2 @begin main::sum1 main::@1 main::@2 main main::sum2 main::sum3 main::@3 +main::@return dominated by main::@return @2 @begin main::sum1 main::@1 main::@2 main main::sum2 main::sum3 main::@3 + +NATURAL LOOPS + +NATURAL LOOPS WITH DEPTH +Found 0 loops in scope [] +Found 0 loops in scope [main] + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte~) main::sum1_$0 +(byte) main::sum1_a +(byte) main::sum1_b +(byte) main::sum1_return +(byte~) main::sum2_$0 +(byte) main::sum2_a +(byte) main::sum2_b +(byte) main::sum2_return +(byte~) main::sum3_$0 +(byte) main::sum3_a +(byte) main::sum3_b +(byte) main::sum3_return +(byte*) screen + +Initial phi equivalence classes +Complete equivalence classes + +INITIAL ASM +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .label screen = $400 +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @2 [phi:@begin->@2] +b2_from_bbegin: + jmp b2 +//SEG4 @2 +b2: +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @2 to main [phi:@2->main] +main_from_b2: + jsr main +//SEG7 [3] phi from @2 to @end [phi:@2->@end] +bend_from_b2: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .const sum1_a = 2 + .const sum1_b = 1 + .const sum2_a = $a + .const sum2_b = 3 + .const sum3_a = 4 + .const sum3_b = 8 + .const sum1_return = sum1_a+sum1_b + .const sum2_return = sum2_a+sum2_b + .const sum3_return = sum3_a+sum3_b + //SEG10 [5] phi from main to main::sum1 [phi:main->main::sum1] + sum1_from_main: + jmp sum1 + //SEG11 main::sum1 + sum1: + jmp b1 + //SEG12 main::@1 + b1: + //SEG13 [6] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (const byte) main::sum1_return#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #sum1_return + sta screen+0 + //SEG14 [7] phi from main::@1 to main::sum2 [phi:main::@1->main::sum2] + sum2_from_b1: + jmp sum2 + //SEG15 main::sum2 + sum2: + jmp b2 + //SEG16 main::@2 + b2: + //SEG17 [8] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::sum2_return#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #sum2_return + sta screen+1 + //SEG18 [9] phi from main::@2 to main::sum3 [phi:main::@2->main::sum3] + sum3_from_b2: + jmp sum3 + //SEG19 main::sum3 + sum3: + jmp b3 + //SEG20 main::@3 + b3: + //SEG21 [10] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (const byte) main::sum3_return#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #sum3_return + sta screen+2 + jmp breturn + //SEG22 main::@return + breturn: + //SEG23 [11] return [ ] ( main:2 [ ] ) + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [6] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (const byte) main::sum1_return#0 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [8] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::sum2_return#0 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [10] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (const byte) main::sum3_return#0 [ ] ( main:2 [ ] ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [] + +Uplifting [main] best 138 combination +Uplifting [] best 138 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .label screen = $400 +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @2 [phi:@begin->@2] +b2_from_bbegin: + jmp b2 +//SEG4 @2 +b2: +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @2 to main [phi:@2->main] +main_from_b2: + jsr main +//SEG7 [3] phi from @2 to @end [phi:@2->@end] +bend_from_b2: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .const sum1_a = 2 + .const sum1_b = 1 + .const sum2_a = $a + .const sum2_b = 3 + .const sum3_a = 4 + .const sum3_b = 8 + .const sum1_return = sum1_a+sum1_b + .const sum2_return = sum2_a+sum2_b + .const sum3_return = sum3_a+sum3_b + //SEG10 [5] phi from main to main::sum1 [phi:main->main::sum1] + sum1_from_main: + jmp sum1 + //SEG11 main::sum1 + sum1: + jmp b1 + //SEG12 main::@1 + b1: + //SEG13 [6] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (const byte) main::sum1_return#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #sum1_return + sta screen+0 + //SEG14 [7] phi from main::@1 to main::sum2 [phi:main::@1->main::sum2] + sum2_from_b1: + jmp sum2 + //SEG15 main::sum2 + sum2: + jmp b2 + //SEG16 main::@2 + b2: + //SEG17 [8] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::sum2_return#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #sum2_return + sta screen+1 + //SEG18 [9] phi from main::@2 to main::sum3 [phi:main::@2->main::sum3] + sum3_from_b2: + jmp sum3 + //SEG19 main::sum3 + sum3: + jmp b3 + //SEG20 main::@3 + b3: + //SEG21 [10] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (const byte) main::sum3_return#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #sum3_return + sta screen+2 + jmp breturn + //SEG22 main::@return + breturn: + //SEG23 [11] return [ ] ( main:2 [ ] ) + rts +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b2 +Removing instruction jmp bend +Removing instruction jmp sum1 +Removing instruction jmp b1 +Removing instruction jmp sum2 +Removing instruction jmp b2 +Removing instruction jmp sum3 +Removing instruction jmp b3 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +Removing instruction b2_from_bbegin: +Removing instruction main_from_b2: +Removing instruction bend_from_b2: +Removing instruction sum1_from_main: +Removing instruction sum1: +Removing instruction sum2_from_b1: +Removing instruction sum2: +Removing instruction sum3_from_b2: +Removing instruction sum3: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction b2: +Removing instruction bend: +Removing instruction b1: +Removing instruction b2: +Removing instruction b3: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @2 +(label) @begin +(label) @end +(void()) main() +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@return +(label) main::sum1 +(byte~) main::sum1_$0 +(byte) main::sum1_a +(const byte) main::sum1_a#0 sum1_a = (byte/signed byte/word/signed word/dword/signed dword) 2 +(byte) main::sum1_b +(const byte) main::sum1_b#0 sum1_b = (byte/signed byte/word/signed word/dword/signed dword) 1 +(byte) main::sum1_return +(const byte) main::sum1_return#0 sum1_return = (const byte) main::sum1_a#0+(const byte) main::sum1_b#0 +(label) main::sum2 +(byte~) main::sum2_$0 +(byte) main::sum2_a +(const byte) main::sum2_a#0 sum2_a = (byte/signed byte/word/signed word/dword/signed dword) 10 +(byte) main::sum2_b +(const byte) main::sum2_b#0 sum2_b = (byte/signed byte/word/signed word/dword/signed dword) 3 +(byte) main::sum2_return +(const byte) main::sum2_return#0 sum2_return = (const byte) main::sum2_a#0+(const byte) main::sum2_b#0 +(label) main::sum3 +(byte~) main::sum3_$0 +(byte) main::sum3_a +(const byte) main::sum3_a#0 sum3_a = (byte/signed byte/word/signed word/dword/signed dword) 4 +(byte) main::sum3_b +(const byte) main::sum3_b#0 sum3_b = (byte/signed byte/word/signed word/dword/signed dword) 8 +(byte) main::sum3_return +(const byte) main::sum3_return#0 sum3_return = (const byte) main::sum3_a#0+(const byte) main::sum3_b#0 +(byte*) screen +(const byte*) screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1024 + + + +FINAL ASSEMBLER +Score: 30 + +//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 @2 [phi:@begin->@2] +//SEG4 @2 +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @2 to main [phi:@2->main] + jsr main +//SEG7 [3] phi from @2 to @end [phi:@2->@end] +//SEG8 @end +//SEG9 main +main: { + .const sum1_a = 2 + .const sum1_b = 1 + .const sum2_a = $a + .const sum2_b = 3 + .const sum3_a = 4 + .const sum3_b = 8 + .const sum1_return = sum1_a+sum1_b + .const sum2_return = sum2_a+sum2_b + .const sum3_return = sum3_a+sum3_b + //SEG10 [5] phi from main to main::sum1 [phi:main->main::sum1] + //SEG11 main::sum1 + //SEG12 main::@1 + //SEG13 [6] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 0) ← (const byte) main::sum1_return#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #sum1_return + sta screen+0 + //SEG14 [7] phi from main::@1 to main::sum2 [phi:main::@1->main::sum2] + //SEG15 main::sum2 + //SEG16 main::@2 + //SEG17 [8] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (const byte) main::sum2_return#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #sum2_return + sta screen+1 + //SEG18 [9] phi from main::@2 to main::sum3 [phi:main::@2->main::sum3] + //SEG19 main::sum3 + //SEG20 main::@3 + //SEG21 [10] *((const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (const byte) main::sum3_return#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #sum3_return + sta screen+2 + //SEG22 main::@return + //SEG23 [11] return [ ] ( main:2 [ ] ) + rts +} + diff --git a/src/test/java/dk/camelot64/kickc/test/ref/inline-function-min.sym b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-min.sym new file mode 100644 index 000000000..c3eee54e7 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-min.sym @@ -0,0 +1,35 @@ +(label) @2 +(label) @begin +(label) @end +(void()) main() +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@return +(label) main::sum1 +(byte~) main::sum1_$0 +(byte) main::sum1_a +(const byte) main::sum1_a#0 sum1_a = (byte/signed byte/word/signed word/dword/signed dword) 2 +(byte) main::sum1_b +(const byte) main::sum1_b#0 sum1_b = (byte/signed byte/word/signed word/dword/signed dword) 1 +(byte) main::sum1_return +(const byte) main::sum1_return#0 sum1_return = (const byte) main::sum1_a#0+(const byte) main::sum1_b#0 +(label) main::sum2 +(byte~) main::sum2_$0 +(byte) main::sum2_a +(const byte) main::sum2_a#0 sum2_a = (byte/signed byte/word/signed word/dword/signed dword) 10 +(byte) main::sum2_b +(const byte) main::sum2_b#0 sum2_b = (byte/signed byte/word/signed word/dword/signed dword) 3 +(byte) main::sum2_return +(const byte) main::sum2_return#0 sum2_return = (const byte) main::sum2_a#0+(const byte) main::sum2_b#0 +(label) main::sum3 +(byte~) main::sum3_$0 +(byte) main::sum3_a +(const byte) main::sum3_a#0 sum3_a = (byte/signed byte/word/signed word/dword/signed dword) 4 +(byte) main::sum3_b +(const byte) main::sum3_b#0 sum3_b = (byte/signed byte/word/signed word/dword/signed dword) 8 +(byte) main::sum3_return +(const byte) main::sum3_return#0 sum3_return = (const byte) main::sum3_a#0+(const byte) main::sum3_b#0 +(byte*) screen +(const byte*) screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1024 + diff --git a/src/test/java/dk/camelot64/kickc/test/ref/inline-function-print.asm b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-print.asm new file mode 100644 index 000000000..357e80b2d --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-print.asm @@ -0,0 +1,32 @@ +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label screen = $400 + jsr main +main: { + .label print2_at = screen+2*$28 + ldx #0 + ldy #0 + print1_b1: + lda print1_msg,y + sta screen,x + inx + inx + iny + lda print1_msg,y + cmp #'@' + bne print1_b1 + ldx #0 + ldy #0 + print2_b1: + lda print1_msg,y + sta print2_at,x + inx + inx + iny + lda print1_msg,y + cmp #'@' + bne print2_b1 + rts + print1_msg: .text "hello world!@" +} diff --git a/src/test/java/dk/camelot64/kickc/test/ref/inline-function-print.cfg b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-print.cfg new file mode 100644 index 000000000..9fa0631f5 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-print.cfg @@ -0,0 +1,37 @@ +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@2 +@2: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @2 + [3] phi() [ ] ( ) +main: scope:[main] from @2 + [4] phi() [ ] ( main:2 [ ] ) + to:main::print1 +main::print1: scope:[main] from main + [5] phi() [ ] ( main:2 [ ] ) + to:main::print1_@1 +main::print1_@1: scope:[main] from main::print1 main::print1_@1 + [6] (byte) main::print1_j#2 ← phi( main::print1/(byte/signed byte/word/signed word/dword/signed dword) 0 main::print1_@1/(byte) main::print1_j#1 ) [ main::print1_i#2 main::print1_j#2 ] ( main:2 [ main::print1_i#2 main::print1_j#2 ] ) + [6] (byte) main::print1_i#2 ← phi( main::print1/(byte/signed byte/word/signed word/dword/signed dword) 0 main::print1_@1/(byte) main::print1_i#1 ) [ main::print1_i#2 main::print1_j#2 ] ( main:2 [ main::print1_i#2 main::print1_j#2 ] ) + [7] *((const byte*) screen#0 + (byte) main::print1_j#2) ← *((const string) main::print1_msg#0 + (byte) main::print1_i#2) [ main::print1_i#2 main::print1_j#2 ] ( main:2 [ main::print1_i#2 main::print1_j#2 ] ) + [8] (byte) main::print1_j#1 ← (byte) main::print1_j#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 [ main::print1_i#2 main::print1_j#1 ] ( main:2 [ main::print1_i#2 main::print1_j#1 ] ) + [9] (byte) main::print1_i#1 ← ++ (byte) main::print1_i#2 [ main::print1_i#1 main::print1_j#1 ] ( main:2 [ main::print1_i#1 main::print1_j#1 ] ) + [10] if(*((const string) main::print1_msg#0 + (byte) main::print1_i#1)!=(byte) '@') goto main::print1_@1 [ main::print1_i#1 main::print1_j#1 ] ( main:2 [ main::print1_i#1 main::print1_j#1 ] ) + to:main::print2 +main::print2: scope:[main] from main::print1_@1 + [11] phi() [ ] ( main:2 [ ] ) + to:main::print2_@1 +main::print2_@1: scope:[main] from main::print2 main::print2_@1 + [12] (byte) main::print2_j#2 ← phi( main::print2/(byte/signed byte/word/signed word/dword/signed dword) 0 main::print2_@1/(byte) main::print2_j#1 ) [ main::print2_i#2 main::print2_j#2 ] ( main:2 [ main::print2_i#2 main::print2_j#2 ] ) + [12] (byte) main::print2_i#2 ← phi( main::print2/(byte/signed byte/word/signed word/dword/signed dword) 0 main::print2_@1/(byte) main::print2_i#1 ) [ main::print2_i#2 main::print2_j#2 ] ( main:2 [ main::print2_i#2 main::print2_j#2 ] ) + [13] *((const byte*) main::print2_at#0 + (byte) main::print2_j#2) ← *((const string) main::print1_msg#0 + (byte) main::print2_i#2) [ main::print2_i#2 main::print2_j#2 ] ( main:2 [ main::print2_i#2 main::print2_j#2 ] ) + [14] (byte) main::print2_j#1 ← (byte) main::print2_j#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 [ main::print2_i#2 main::print2_j#1 ] ( main:2 [ main::print2_i#2 main::print2_j#1 ] ) + [15] (byte) main::print2_i#1 ← ++ (byte) main::print2_i#2 [ main::print2_i#1 main::print2_j#1 ] ( main:2 [ main::print2_i#1 main::print2_j#1 ] ) + [16] if(*((const string) main::print1_msg#0 + (byte) main::print2_i#1)!=(byte) '@') goto main::print2_@1 [ main::print2_i#1 main::print2_j#1 ] ( main:2 [ main::print2_i#1 main::print2_j#1 ] ) + to:main::@return +main::@return: scope:[main] from main::print2_@1 + [17] return [ ] ( main:2 [ ] ) + to:@return diff --git a/src/test/java/dk/camelot64/kickc/test/ref/inline-function-print.log b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-print.log new file mode 100644 index 000000000..e07ac0260 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-print.log @@ -0,0 +1,815 @@ +PARSING src/test/java/dk/camelot64/kickc/test/kc/inline-function-print.kc +// TEst inlining a slightly complex print function (containing a loop) + +byte* screen = $400; + +void main() { + byte* hello = "hello world!@"; + print(screen, hello); + print(screen+2*40, hello); +} + +inline void print(byte* at, byte* msg) { + byte j=0; + for(byte i=0; msg[i]!='@'; i++) { + at[j] = msg[i]; + j += 2; + } +} + + +Adding pre/post-modifier (byte) print::i ← ++ (byte) print::i +SYMBOLS +(label) @1 +(label) @2 +(label) @begin +(label) @end +(void()) main() +(void~) main::$0 +(byte/signed byte/word/signed word/dword/signed dword~) main::$1 +(byte*~) main::$2 +(void~) main::$3 +(label) main::@return +(byte*) main::hello +inline (void()) print((byte*) print::at , (byte*) print::msg) +(bool~) print::$0 +(label) print::@1 +(label) print::@2 +(label) print::@return +(byte*) print::at +(byte) print::i +(byte) print::j +(byte*) print::msg +(byte*) screen + +Promoting word/signed word/dword/signed dword to byte* in screen ← ((byte*)) 1024 +INITIAL CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) screen ← ((byte*)) (word/signed word/dword/signed dword) 1024 + to:@1 +main: scope:[main] from + (byte*) main::hello ← (string) "hello world!@" + (void~) main::$0 ← call print (byte*) screen (byte*) main::hello + (byte/signed byte/word/signed word/dword/signed dword~) main::$1 ← (byte/signed byte/word/signed word/dword/signed dword) 2 * (byte/signed byte/word/signed word/dword/signed dword) 40 + (byte*~) main::$2 ← (byte*) screen + (byte/signed byte/word/signed word/dword/signed dword~) main::$1 + (void~) main::$3 ← call print (byte*~) main::$2 (byte*) main::hello + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + to:@2 +print: scope:[print] from + (byte) print::j ← (byte/signed byte/word/signed word/dword/signed dword) 0 + (byte) print::i ← (byte/signed byte/word/signed word/dword/signed dword) 0 + to:print::@1 +print::@1: scope:[print] from print print::@1 + *((byte*) print::at + (byte) print::j) ← *((byte*) print::msg + (byte) print::i) + (byte) print::j ← (byte) print::j + (byte/signed byte/word/signed word/dword/signed dword) 2 + (byte) print::i ← ++ (byte) print::i + (bool~) print::$0 ← *((byte*) print::msg + (byte) print::i) != (byte) '@' + if((bool~) print::$0) goto print::@1 + to:print::@2 +print::@2: scope:[print] from print::@1 + to:print::@return +print::@return: scope:[print] from print::@2 + return + to:@return +@2: scope:[] from @1 + call main + to:@end +@end: scope:[] from @2 + +Inlined call call print (byte*) screen (byte*) main::hello +Inlined call call print (byte*~) main::$2 (byte*) main::hello +Removing unused procedure print +Creating constant string variable for inline (const string) main::$4 "hello world!@" +Removing empty block main::print1_@2 +Removing empty block main::print1_@return +Removing empty block main::print2_@2 +Removing empty block main::print2_@return +Removing empty block main::@2 +Removing empty block @1 +PROCEDURE MODIFY VARIABLE ANALYSIS + +Completing Phi functions... +Completing Phi functions... +Completing Phi functions... + +CONTROL FLOW GRAPH SSA WITH ASSIGNMENT CALL & RETURN +@begin: scope:[] from + (byte*) screen#0 ← ((byte*)) (word/signed word/dword/signed dword) 1024 + to:@2 +main: scope:[main] from @2 + (byte*) screen#1 ← phi( @2/(byte*) screen#3 ) + (byte*) main::hello#0 ← (const string) main::$4 + (byte*) main::print1_at#0 ← (byte*) screen#1 + (byte*) main::print1_msg#0 ← (byte*) main::hello#0 + to:main::print1 +main::print1: scope:[main] from main + (byte*) main::hello#3 ← phi( main/(byte*) main::hello#0 ) + (byte*) screen#5 ← phi( main/(byte*) screen#1 ) + (byte*) main::print1_at#2 ← phi( main/(byte*) main::print1_at#0 ) + (byte*) main::print1_msg#2 ← phi( main/(byte*) main::print1_msg#0 ) + (byte) main::print1_j#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 + (byte) main::print1_i#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 + to:main::print1_@1 +main::print1_@1: scope:[main] from main::print1 main::print1_@1 + (byte*) main::hello#2 ← phi( main::print1/(byte*) main::hello#3 main::print1_@1/(byte*) main::hello#2 ) + (byte*) screen#4 ← phi( main::print1/(byte*) screen#5 main::print1_@1/(byte*) screen#4 ) + (byte) main::print1_j#2 ← phi( main::print1/(byte) main::print1_j#0 main::print1_@1/(byte) main::print1_j#1 ) + (byte*) main::print1_at#1 ← phi( main::print1/(byte*) main::print1_at#2 main::print1_@1/(byte*) main::print1_at#1 ) + (byte) main::print1_i#2 ← phi( main::print1/(byte) main::print1_i#0 main::print1_@1/(byte) main::print1_i#1 ) + (byte*) main::print1_msg#1 ← phi( main::print1/(byte*) main::print1_msg#2 main::print1_@1/(byte*) main::print1_msg#1 ) + *((byte*) main::print1_at#1 + (byte) main::print1_j#2) ← *((byte*) main::print1_msg#1 + (byte) main::print1_i#2) + (byte) main::print1_j#1 ← (byte) main::print1_j#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 + (byte) main::print1_i#1 ← ++ (byte) main::print1_i#2 + (bool) main::print1_$0#0 ← *((byte*) main::print1_msg#1 + (byte) main::print1_i#1) != (byte) '@' + if((bool) main::print1_$0#0) goto main::print1_@1 + to:main::@1 +main::@1: scope:[main] from main::print1_@1 + (byte*) main::hello#1 ← phi( main::print1_@1/(byte*) main::hello#2 ) + (byte*) screen#2 ← phi( main::print1_@1/(byte*) screen#4 ) + (byte/signed byte/word/signed word/dword/signed dword~) main::$1 ← (byte/signed byte/word/signed word/dword/signed dword) 2 * (byte/signed byte/word/signed word/dword/signed dword) 40 + (byte*~) main::$2 ← (byte*) screen#2 + (byte/signed byte/word/signed word/dword/signed dword~) main::$1 + (byte*) main::print2_at#0 ← (byte*~) main::$2 + (byte*) main::print2_msg#0 ← (byte*) main::hello#1 + to:main::print2 +main::print2: scope:[main] from main::@1 + (byte*) main::print2_at#2 ← phi( main::@1/(byte*) main::print2_at#0 ) + (byte*) main::print2_msg#2 ← phi( main::@1/(byte*) main::print2_msg#0 ) + (byte) main::print2_j#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 + (byte) main::print2_i#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 + to:main::print2_@1 +main::print2_@1: scope:[main] from main::print2 main::print2_@1 + (byte) main::print2_j#2 ← phi( main::print2/(byte) main::print2_j#0 main::print2_@1/(byte) main::print2_j#1 ) + (byte*) main::print2_at#1 ← phi( main::print2/(byte*) main::print2_at#2 main::print2_@1/(byte*) main::print2_at#1 ) + (byte) main::print2_i#2 ← phi( main::print2/(byte) main::print2_i#0 main::print2_@1/(byte) main::print2_i#1 ) + (byte*) main::print2_msg#1 ← phi( main::print2/(byte*) main::print2_msg#2 main::print2_@1/(byte*) main::print2_msg#1 ) + *((byte*) main::print2_at#1 + (byte) main::print2_j#2) ← *((byte*) main::print2_msg#1 + (byte) main::print2_i#2) + (byte) main::print2_j#1 ← (byte) main::print2_j#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 + (byte) main::print2_i#1 ← ++ (byte) main::print2_i#2 + (bool) main::print2_$0#0 ← *((byte*) main::print2_msg#1 + (byte) main::print2_i#1) != (byte) '@' + if((bool) main::print2_$0#0) goto main::print2_@1 + to:main::@return +main::@return: scope:[main] from main::print2_@1 + return + to:@return +@2: scope:[] from @begin + (byte*) screen#3 ← phi( @begin/(byte*) screen#0 ) + call main param-assignment + to:@3 +@3: scope:[] from @2 + to:@end +@end: scope:[] from @3 + +SYMBOL TABLE SSA +(label) @2 +(label) @3 +(label) @begin +(label) @end +(void()) main() +(byte/signed byte/word/signed word/dword/signed dword~) main::$1 +(byte*~) main::$2 +(const string) main::$4 = (string) "hello world!@" +(label) main::@1 +(label) main::@return +(byte*) main::hello +(byte*) main::hello#0 +(byte*) main::hello#1 +(byte*) main::hello#2 +(byte*) main::hello#3 +(label) main::print1 +(bool~) main::print1_$0 +(bool) main::print1_$0#0 +(label) main::print1_@1 +(byte*) main::print1_at +(byte*) main::print1_at#0 +(byte*) main::print1_at#1 +(byte*) main::print1_at#2 +(byte) main::print1_i +(byte) main::print1_i#0 +(byte) main::print1_i#1 +(byte) main::print1_i#2 +(byte) main::print1_j +(byte) main::print1_j#0 +(byte) main::print1_j#1 +(byte) main::print1_j#2 +(byte*) main::print1_msg +(byte*) main::print1_msg#0 +(byte*) main::print1_msg#1 +(byte*) main::print1_msg#2 +(label) main::print2 +(bool~) main::print2_$0 +(bool) main::print2_$0#0 +(label) main::print2_@1 +(byte*) main::print2_at +(byte*) main::print2_at#0 +(byte*) main::print2_at#1 +(byte*) main::print2_at#2 +(byte) main::print2_i +(byte) main::print2_i#0 +(byte) main::print2_i#1 +(byte) main::print2_i#2 +(byte) main::print2_j +(byte) main::print2_j#0 +(byte) main::print2_j#1 +(byte) main::print2_j#2 +(byte*) main::print2_msg +(byte*) main::print2_msg#0 +(byte*) main::print2_msg#1 +(byte*) main::print2_msg#2 +(byte*) screen +(byte*) screen#0 +(byte*) screen#1 +(byte*) screen#2 +(byte*) screen#3 +(byte*) screen#4 +(byte*) screen#5 + +OPTIMIZING CONTROL FLOW GRAPH +Culled Empty Block (label) @3 +Succesful SSA optimization Pass2CullEmptyBlocks +Not aliassing across scopes: screen#1 screen#3 +Not aliassing across scopes: main::print1_at#0 screen#1 +Alias (byte*) main::print1_msg#0 = (byte*) main::hello#0 (byte*) main::print1_msg#2 (byte*) main::hello#3 +Alias (byte*) main::print1_at#0 = (byte*) main::print1_at#2 +Alias (byte*) screen#1 = (byte*) screen#5 +Alias (byte*) screen#2 = (byte*) screen#4 +Alias (byte*) main::hello#1 = (byte*) main::hello#2 (byte*) main::print2_msg#0 (byte*) main::print2_msg#2 +Alias (byte*) main::print2_at#0 = (byte*~) main::$2 (byte*) main::print2_at#2 +Alias (byte*) screen#0 = (byte*) screen#3 +Succesful SSA optimization Pass2AliasElimination +Not aliassing across scopes: screen#1 screen#0 +Not aliassing across scopes: main::print1_at#0 screen#1 +Self Phi Eliminated (byte*) main::print1_msg#1 +Self Phi Eliminated (byte*) main::print1_at#1 +Self Phi Eliminated (byte*) screen#2 +Self Phi Eliminated (byte*) main::hello#1 +Self Phi Eliminated (byte*) main::print2_msg#1 +Self Phi Eliminated (byte*) main::print2_at#1 +Succesful SSA optimization Pass2SelfPhiElimination +Redundant Phi (byte*) screen#1 (byte*) screen#0 +Redundant Phi (byte*) main::print1_msg#1 (byte*) main::print1_msg#0 +Redundant Phi (byte*) main::print1_at#1 (byte*) main::print1_at#0 +Redundant Phi (byte*) screen#2 (byte*) screen#1 +Redundant Phi (byte*) main::hello#1 (byte*) main::print1_msg#0 +Redundant Phi (byte*) main::print2_msg#1 (byte*) main::hello#1 +Redundant Phi (byte*) main::print2_at#1 (byte*) main::print2_at#0 +Succesful SSA optimization Pass2RedundantPhiElimination +Simple Condition (bool) main::print1_$0#0 if(*((byte*) main::print1_msg#0 + (byte) main::print1_i#1)!=(byte) '@') goto main::print1_@1 +Simple Condition (bool) main::print2_$0#0 if(*((byte*) main::print1_msg#0 + (byte) main::print2_i#1)!=(byte) '@') goto main::print2_@1 +Succesful SSA optimization Pass2ConditionalJumpSimplification +Constant (const byte*) screen#0 = ((byte*))1024 +Constant (const string) main::print1_msg#0 = main::$4 +Constant (const byte) main::print1_j#0 = 0 +Constant (const byte) main::print1_i#0 = 0 +Constant (const byte/signed byte/word/signed word/dword/signed dword) main::$1 = 2*40 +Constant (const byte) main::print2_j#0 = 0 +Constant (const byte) main::print2_i#0 = 0 +Succesful SSA optimization Pass2ConstantIdentification +Constant (const byte*) main::print1_at#0 = screen#0 +Constant (const byte*) main::print2_at#0 = screen#0+main::$1 +Succesful SSA optimization Pass2ConstantIdentification +Culled Empty Block (label) main::@1 +Succesful SSA optimization Pass2CullEmptyBlocks +OPTIMIZING CONTROL FLOW GRAPH +Inlining constant with var siblings (const byte) main::print1_j#0 +Inlining constant with var siblings (const byte) main::print1_j#0 +Inlining constant with var siblings (const byte) main::print1_i#0 +Inlining constant with var siblings (const byte) main::print1_i#0 +Inlining constant with var siblings (const byte) main::print2_j#0 +Inlining constant with var siblings (const byte) main::print2_j#0 +Inlining constant with var siblings (const byte) main::print2_i#0 +Inlining constant with var siblings (const byte) main::print2_i#0 +Constant inlined main::print2_j#0 = (byte/signed byte/word/signed word/dword/signed dword) 0 +Constant inlined main::print1_at#0 = (const byte*) screen#0 +Constant inlined main::print2_i#0 = (byte/signed byte/word/signed word/dword/signed dword) 0 +Constant inlined main::$1 = (byte/signed byte/word/signed word/dword/signed dword) 2*(byte/signed byte/word/signed word/dword/signed dword) 40 +Constant inlined main::$4 = (const string) main::print1_msg#0 +Constant inlined main::print1_i#0 = (byte/signed byte/word/signed word/dword/signed dword) 0 +Constant inlined main::print1_j#0 = (byte/signed byte/word/signed word/dword/signed dword) 0 +Succesful SSA optimization Pass2ConstantInlining +Block Sequence Planned @begin @2 @end main main::print1 main::print1_@1 main::print2 main::print2_@1 main::@return +Added new block during phi lifting main::@3(between main::print1_@1 and main::print1_@1) +Added new block during phi lifting main::@4(between main::print2_@1 and main::print2_@1) +Block Sequence Planned @begin @2 @end main main::print1 main::print1_@1 main::print2 main::print2_@1 main::@return main::@4 main::@3 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +Adding NOP phi() at start of main::print1 +Adding NOP phi() at start of main::print2 +CALL GRAPH +Calls in [] to main:2 + +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +Created 4 initial phi equivalence classes +Coalesced [18] main::print2_i#3 ← main::print2_i#1 +Coalesced [19] main::print2_j#3 ← main::print2_j#1 +Coalesced [20] main::print1_i#3 ← main::print1_i#1 +Coalesced [21] main::print1_j#3 ← main::print1_j#1 +Coalesced down to 4 phi equivalence classes +Culled Empty Block (label) main::@4 +Culled Empty Block (label) main::@3 +Block Sequence Planned @begin @2 @end main main::print1 main::print1_@1 main::print2 main::print2_@1 main::@return +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +Adding NOP phi() at start of main::print1 +Adding NOP phi() at start of main::print2 +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@2 +@2: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @2 + [3] phi() [ ] ( ) +main: scope:[main] from @2 + [4] phi() [ ] ( main:2 [ ] ) + to:main::print1 +main::print1: scope:[main] from main + [5] phi() [ ] ( main:2 [ ] ) + to:main::print1_@1 +main::print1_@1: scope:[main] from main::print1 main::print1_@1 + [6] (byte) main::print1_j#2 ← phi( main::print1/(byte/signed byte/word/signed word/dword/signed dword) 0 main::print1_@1/(byte) main::print1_j#1 ) [ main::print1_i#2 main::print1_j#2 ] ( main:2 [ main::print1_i#2 main::print1_j#2 ] ) + [6] (byte) main::print1_i#2 ← phi( main::print1/(byte/signed byte/word/signed word/dword/signed dword) 0 main::print1_@1/(byte) main::print1_i#1 ) [ main::print1_i#2 main::print1_j#2 ] ( main:2 [ main::print1_i#2 main::print1_j#2 ] ) + [7] *((const byte*) screen#0 + (byte) main::print1_j#2) ← *((const string) main::print1_msg#0 + (byte) main::print1_i#2) [ main::print1_i#2 main::print1_j#2 ] ( main:2 [ main::print1_i#2 main::print1_j#2 ] ) + [8] (byte) main::print1_j#1 ← (byte) main::print1_j#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 [ main::print1_i#2 main::print1_j#1 ] ( main:2 [ main::print1_i#2 main::print1_j#1 ] ) + [9] (byte) main::print1_i#1 ← ++ (byte) main::print1_i#2 [ main::print1_i#1 main::print1_j#1 ] ( main:2 [ main::print1_i#1 main::print1_j#1 ] ) + [10] if(*((const string) main::print1_msg#0 + (byte) main::print1_i#1)!=(byte) '@') goto main::print1_@1 [ main::print1_i#1 main::print1_j#1 ] ( main:2 [ main::print1_i#1 main::print1_j#1 ] ) + to:main::print2 +main::print2: scope:[main] from main::print1_@1 + [11] phi() [ ] ( main:2 [ ] ) + to:main::print2_@1 +main::print2_@1: scope:[main] from main::print2 main::print2_@1 + [12] (byte) main::print2_j#2 ← phi( main::print2/(byte/signed byte/word/signed word/dword/signed dword) 0 main::print2_@1/(byte) main::print2_j#1 ) [ main::print2_i#2 main::print2_j#2 ] ( main:2 [ main::print2_i#2 main::print2_j#2 ] ) + [12] (byte) main::print2_i#2 ← phi( main::print2/(byte/signed byte/word/signed word/dword/signed dword) 0 main::print2_@1/(byte) main::print2_i#1 ) [ main::print2_i#2 main::print2_j#2 ] ( main:2 [ main::print2_i#2 main::print2_j#2 ] ) + [13] *((const byte*) main::print2_at#0 + (byte) main::print2_j#2) ← *((const string) main::print1_msg#0 + (byte) main::print2_i#2) [ main::print2_i#2 main::print2_j#2 ] ( main:2 [ main::print2_i#2 main::print2_j#2 ] ) + [14] (byte) main::print2_j#1 ← (byte) main::print2_j#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 [ main::print2_i#2 main::print2_j#1 ] ( main:2 [ main::print2_i#2 main::print2_j#1 ] ) + [15] (byte) main::print2_i#1 ← ++ (byte) main::print2_i#2 [ main::print2_i#1 main::print2_j#1 ] ( main:2 [ main::print2_i#1 main::print2_j#1 ] ) + [16] if(*((const string) main::print1_msg#0 + (byte) main::print2_i#1)!=(byte) '@') goto main::print2_@1 [ main::print2_i#1 main::print2_j#1 ] ( main:2 [ main::print2_i#1 main::print2_j#1 ] ) + to:main::@return +main::@return: scope:[main] from main::print2_@1 + [17] return [ ] ( main:2 [ ] ) + to:@return + +DOMINATORS +@begin dominated by @begin +@2 dominated by @2 @begin +@end dominated by @2 @begin @end +main dominated by @2 @begin main +main::print1 dominated by @2 @begin main main::print1 +main::print1_@1 dominated by @2 @begin main::print1_@1 main main::print1 +main::print2 dominated by @2 @begin main::print1_@1 main::print2 main main::print1 +main::print2_@1 dominated by @2 @begin main::print1_@1 main::print2_@1 main::print2 main main::print1 +main::@return dominated by main::@return @2 @begin main::print1_@1 main::print2_@1 main::print2 main main::print1 + +NATURAL LOOPS +Found back edge: Loop head: main::print1_@1 tails: main::print1_@1 blocks: null +Found back edge: Loop head: main::print2_@1 tails: main::print2_@1 blocks: null +Populated: Loop head: main::print1_@1 tails: main::print1_@1 blocks: main::print1_@1 +Populated: Loop head: main::print2_@1 tails: main::print2_@1 blocks: main::print2_@1 +Loop head: main::print1_@1 tails: main::print1_@1 blocks: main::print1_@1 +Loop head: main::print2_@1 tails: main::print2_@1 blocks: main::print2_@1 + +NATURAL LOOPS WITH DEPTH +Found 0 loops in scope [] +Found 2 loops in scope [main] + Loop head: main::print1_@1 tails: main::print1_@1 blocks: main::print1_@1 + Loop head: main::print2_@1 tails: main::print2_@1 blocks: main::print2_@1 +Loop head: main::print1_@1 tails: main::print1_@1 blocks: main::print1_@1 depth: 1 +Loop head: main::print2_@1 tails: main::print2_@1 blocks: main::print2_@1 depth: 1 + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte*) main::hello +(bool~) main::print1_$0 +(byte*) main::print1_at +(byte) main::print1_i +(byte) main::print1_i#1 16.5 +(byte) main::print1_i#2 11.0 +(byte) main::print1_j +(byte) main::print1_j#1 7.333333333333333 +(byte) main::print1_j#2 16.5 +(byte*) main::print1_msg +(bool~) main::print2_$0 +(byte*) main::print2_at +(byte) main::print2_i +(byte) main::print2_i#1 16.5 +(byte) main::print2_i#2 11.0 +(byte) main::print2_j +(byte) main::print2_j#1 7.333333333333333 +(byte) main::print2_j#2 16.5 +(byte*) main::print2_msg +(byte*) screen + +Initial phi equivalence classes +[ main::print1_i#2 main::print1_i#1 ] +[ main::print1_j#2 main::print1_j#1 ] +[ main::print2_i#2 main::print2_i#1 ] +[ main::print2_j#2 main::print2_j#1 ] +Complete equivalence classes +[ main::print1_i#2 main::print1_i#1 ] +[ main::print1_j#2 main::print1_j#1 ] +[ main::print2_i#2 main::print2_i#1 ] +[ main::print2_j#2 main::print2_j#1 ] +Allocated zp ZP_BYTE:2 [ main::print1_i#2 main::print1_i#1 ] +Allocated zp ZP_BYTE:3 [ main::print1_j#2 main::print1_j#1 ] +Allocated zp ZP_BYTE:4 [ main::print2_i#2 main::print2_i#1 ] +Allocated zp ZP_BYTE:5 [ main::print2_j#2 main::print2_j#1 ] + +INITIAL ASM +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .label screen = $400 +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @2 [phi:@begin->@2] +b2_from_bbegin: + jmp b2 +//SEG4 @2 +b2: +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @2 to main [phi:@2->main] +main_from_b2: + jsr main +//SEG7 [3] phi from @2 to @end [phi:@2->@end] +bend_from_b2: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .label print2_at = screen+2*$28 + .label print1_j = 3 + .label print1_i = 2 + .label print2_j = 5 + .label print2_i = 4 + //SEG10 [5] phi from main to main::print1 [phi:main->main::print1] + print1_from_main: + jmp print1 + //SEG11 main::print1 + print1: + //SEG12 [6] phi from main::print1 to main::print1_@1 [phi:main::print1->main::print1_@1] + print1_b1_from_print1: + //SEG13 [6] phi (byte) main::print1_j#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::print1->main::print1_@1#0] -- vbuz1=vbuc1 + lda #0 + sta print1_j + //SEG14 [6] phi (byte) main::print1_i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::print1->main::print1_@1#1] -- vbuz1=vbuc1 + lda #0 + sta print1_i + jmp print1_b1 + //SEG15 [6] phi from main::print1_@1 to main::print1_@1 [phi:main::print1_@1->main::print1_@1] + print1_b1_from_print1_b1: + //SEG16 [6] phi (byte) main::print1_j#2 = (byte) main::print1_j#1 [phi:main::print1_@1->main::print1_@1#0] -- register_copy + //SEG17 [6] phi (byte) main::print1_i#2 = (byte) main::print1_i#1 [phi:main::print1_@1->main::print1_@1#1] -- register_copy + jmp print1_b1 + //SEG18 main::print1_@1 + print1_b1: + //SEG19 [7] *((const byte*) screen#0 + (byte) main::print1_j#2) ← *((const string) main::print1_msg#0 + (byte) main::print1_i#2) [ main::print1_i#2 main::print1_j#2 ] ( main:2 [ main::print1_i#2 main::print1_j#2 ] ) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz2 + ldy print1_i + lda print1_msg,y + ldy print1_j + sta screen,y + //SEG20 [8] (byte) main::print1_j#1 ← (byte) main::print1_j#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 [ main::print1_i#2 main::print1_j#1 ] ( main:2 [ main::print1_i#2 main::print1_j#1 ] ) -- vbuz1=vbuz1_plus_2 + lda print1_j + clc + adc #2 + sta print1_j + //SEG21 [9] (byte) main::print1_i#1 ← ++ (byte) main::print1_i#2 [ main::print1_i#1 main::print1_j#1 ] ( main:2 [ main::print1_i#1 main::print1_j#1 ] ) -- vbuz1=_inc_vbuz1 + inc print1_i + //SEG22 [10] if(*((const string) main::print1_msg#0 + (byte) main::print1_i#1)!=(byte) '@') goto main::print1_@1 [ main::print1_i#1 main::print1_j#1 ] ( main:2 [ main::print1_i#1 main::print1_j#1 ] ) -- pbuc1_derefidx_vbuz1_neq_vbuc2_then_la1 + ldy print1_i + lda print1_msg,y + cmp #'@' + bne print1_b1_from_print1_b1 + //SEG23 [11] phi from main::print1_@1 to main::print2 [phi:main::print1_@1->main::print2] + print2_from_print1_b1: + jmp print2 + //SEG24 main::print2 + print2: + //SEG25 [12] phi from main::print2 to main::print2_@1 [phi:main::print2->main::print2_@1] + print2_b1_from_print2: + //SEG26 [12] phi (byte) main::print2_j#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::print2->main::print2_@1#0] -- vbuz1=vbuc1 + lda #0 + sta print2_j + //SEG27 [12] phi (byte) main::print2_i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::print2->main::print2_@1#1] -- vbuz1=vbuc1 + lda #0 + sta print2_i + jmp print2_b1 + //SEG28 [12] phi from main::print2_@1 to main::print2_@1 [phi:main::print2_@1->main::print2_@1] + print2_b1_from_print2_b1: + //SEG29 [12] phi (byte) main::print2_j#2 = (byte) main::print2_j#1 [phi:main::print2_@1->main::print2_@1#0] -- register_copy + //SEG30 [12] phi (byte) main::print2_i#2 = (byte) main::print2_i#1 [phi:main::print2_@1->main::print2_@1#1] -- register_copy + jmp print2_b1 + //SEG31 main::print2_@1 + print2_b1: + //SEG32 [13] *((const byte*) main::print2_at#0 + (byte) main::print2_j#2) ← *((const string) main::print1_msg#0 + (byte) main::print2_i#2) [ main::print2_i#2 main::print2_j#2 ] ( main:2 [ main::print2_i#2 main::print2_j#2 ] ) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz2 + ldy print2_i + lda print1_msg,y + ldy print2_j + sta print2_at,y + //SEG33 [14] (byte) main::print2_j#1 ← (byte) main::print2_j#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 [ main::print2_i#2 main::print2_j#1 ] ( main:2 [ main::print2_i#2 main::print2_j#1 ] ) -- vbuz1=vbuz1_plus_2 + lda print2_j + clc + adc #2 + sta print2_j + //SEG34 [15] (byte) main::print2_i#1 ← ++ (byte) main::print2_i#2 [ main::print2_i#1 main::print2_j#1 ] ( main:2 [ main::print2_i#1 main::print2_j#1 ] ) -- vbuz1=_inc_vbuz1 + inc print2_i + //SEG35 [16] if(*((const string) main::print1_msg#0 + (byte) main::print2_i#1)!=(byte) '@') goto main::print2_@1 [ main::print2_i#1 main::print2_j#1 ] ( main:2 [ main::print2_i#1 main::print2_j#1 ] ) -- pbuc1_derefidx_vbuz1_neq_vbuc2_then_la1 + ldy print2_i + lda print1_msg,y + cmp #'@' + bne print2_b1_from_print2_b1 + jmp breturn + //SEG36 main::@return + breturn: + //SEG37 [17] return [ ] ( main:2 [ ] ) + rts + print1_msg: .text "hello world!@" +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [7] *((const byte*) screen#0 + (byte) main::print1_j#2) ← *((const string) main::print1_msg#0 + (byte) main::print1_i#2) [ main::print1_i#2 main::print1_j#2 ] ( main:2 [ main::print1_i#2 main::print1_j#2 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::print1_i#2 main::print1_i#1 ] +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::print1_j#2 main::print1_j#1 ] +Statement [10] if(*((const string) main::print1_msg#0 + (byte) main::print1_i#1)!=(byte) '@') goto main::print1_@1 [ main::print1_i#1 main::print1_j#1 ] ( main:2 [ main::print1_i#1 main::print1_j#1 ] ) always clobbers reg byte a +Statement [13] *((const byte*) main::print2_at#0 + (byte) main::print2_j#2) ← *((const string) main::print1_msg#0 + (byte) main::print2_i#2) [ main::print2_i#2 main::print2_j#2 ] ( main:2 [ main::print2_i#2 main::print2_j#2 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::print2_i#2 main::print2_i#1 ] +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:5 [ main::print2_j#2 main::print2_j#1 ] +Statement [16] if(*((const string) main::print1_msg#0 + (byte) main::print2_i#1)!=(byte) '@') goto main::print2_@1 [ main::print2_i#1 main::print2_j#1 ] ( main:2 [ main::print2_i#1 main::print2_j#1 ] ) always clobbers reg byte a +Statement [7] *((const byte*) screen#0 + (byte) main::print1_j#2) ← *((const string) main::print1_msg#0 + (byte) main::print1_i#2) [ main::print1_i#2 main::print1_j#2 ] ( main:2 [ main::print1_i#2 main::print1_j#2 ] ) always clobbers reg byte a +Statement [10] if(*((const string) main::print1_msg#0 + (byte) main::print1_i#1)!=(byte) '@') goto main::print1_@1 [ main::print1_i#1 main::print1_j#1 ] ( main:2 [ main::print1_i#1 main::print1_j#1 ] ) always clobbers reg byte a +Statement [13] *((const byte*) main::print2_at#0 + (byte) main::print2_j#2) ← *((const string) main::print1_msg#0 + (byte) main::print2_i#2) [ main::print2_i#2 main::print2_j#2 ] ( main:2 [ main::print2_i#2 main::print2_j#2 ] ) always clobbers reg byte a +Statement [16] if(*((const string) main::print1_msg#0 + (byte) main::print2_i#1)!=(byte) '@') goto main::print2_@1 [ main::print2_i#1 main::print2_j#1 ] ( main:2 [ main::print2_i#1 main::print2_j#1 ] ) always clobbers reg byte a +Potential registers zp ZP_BYTE:2 [ main::print1_i#2 main::print1_i#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:3 [ main::print1_j#2 main::print1_j#1 ] : zp ZP_BYTE:3 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:4 [ main::print2_i#2 main::print2_i#1 ] : zp ZP_BYTE:4 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:5 [ main::print2_j#2 main::print2_j#1 ] : zp ZP_BYTE:5 , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 27.5: zp ZP_BYTE:2 [ main::print1_i#2 main::print1_i#1 ] 27.5: zp ZP_BYTE:4 [ main::print2_i#2 main::print2_i#1 ] 23.83: zp ZP_BYTE:3 [ main::print1_j#2 main::print1_j#1 ] 23.83: zp ZP_BYTE:5 [ main::print2_j#2 main::print2_j#1 ] +Uplift Scope [] + +Uplifting [main] best 744 combination reg byte y [ main::print1_i#2 main::print1_i#1 ] reg byte y [ main::print2_i#2 main::print2_i#1 ] reg byte x [ main::print1_j#2 main::print1_j#1 ] reg byte x [ main::print2_j#2 main::print2_j#1 ] +Uplifting [] best 744 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .label screen = $400 +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @2 [phi:@begin->@2] +b2_from_bbegin: + jmp b2 +//SEG4 @2 +b2: +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @2 to main [phi:@2->main] +main_from_b2: + jsr main +//SEG7 [3] phi from @2 to @end [phi:@2->@end] +bend_from_b2: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .label print2_at = screen+2*$28 + //SEG10 [5] phi from main to main::print1 [phi:main->main::print1] + print1_from_main: + jmp print1 + //SEG11 main::print1 + print1: + //SEG12 [6] phi from main::print1 to main::print1_@1 [phi:main::print1->main::print1_@1] + print1_b1_from_print1: + //SEG13 [6] phi (byte) main::print1_j#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::print1->main::print1_@1#0] -- vbuxx=vbuc1 + ldx #0 + //SEG14 [6] phi (byte) main::print1_i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::print1->main::print1_@1#1] -- vbuyy=vbuc1 + ldy #0 + jmp print1_b1 + //SEG15 [6] phi from main::print1_@1 to main::print1_@1 [phi:main::print1_@1->main::print1_@1] + print1_b1_from_print1_b1: + //SEG16 [6] phi (byte) main::print1_j#2 = (byte) main::print1_j#1 [phi:main::print1_@1->main::print1_@1#0] -- register_copy + //SEG17 [6] phi (byte) main::print1_i#2 = (byte) main::print1_i#1 [phi:main::print1_@1->main::print1_@1#1] -- register_copy + jmp print1_b1 + //SEG18 main::print1_@1 + print1_b1: + //SEG19 [7] *((const byte*) screen#0 + (byte) main::print1_j#2) ← *((const string) main::print1_msg#0 + (byte) main::print1_i#2) [ main::print1_i#2 main::print1_j#2 ] ( main:2 [ main::print1_i#2 main::print1_j#2 ] ) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuyy + lda print1_msg,y + sta screen,x + //SEG20 [8] (byte) main::print1_j#1 ← (byte) main::print1_j#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 [ main::print1_i#2 main::print1_j#1 ] ( main:2 [ main::print1_i#2 main::print1_j#1 ] ) -- vbuxx=vbuxx_plus_2 + inx + inx + //SEG21 [9] (byte) main::print1_i#1 ← ++ (byte) main::print1_i#2 [ main::print1_i#1 main::print1_j#1 ] ( main:2 [ main::print1_i#1 main::print1_j#1 ] ) -- vbuyy=_inc_vbuyy + iny + //SEG22 [10] if(*((const string) main::print1_msg#0 + (byte) main::print1_i#1)!=(byte) '@') goto main::print1_@1 [ main::print1_i#1 main::print1_j#1 ] ( main:2 [ main::print1_i#1 main::print1_j#1 ] ) -- pbuc1_derefidx_vbuyy_neq_vbuc2_then_la1 + lda print1_msg,y + cmp #'@' + bne print1_b1_from_print1_b1 + //SEG23 [11] phi from main::print1_@1 to main::print2 [phi:main::print1_@1->main::print2] + print2_from_print1_b1: + jmp print2 + //SEG24 main::print2 + print2: + //SEG25 [12] phi from main::print2 to main::print2_@1 [phi:main::print2->main::print2_@1] + print2_b1_from_print2: + //SEG26 [12] phi (byte) main::print2_j#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::print2->main::print2_@1#0] -- vbuxx=vbuc1 + ldx #0 + //SEG27 [12] phi (byte) main::print2_i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::print2->main::print2_@1#1] -- vbuyy=vbuc1 + ldy #0 + jmp print2_b1 + //SEG28 [12] phi from main::print2_@1 to main::print2_@1 [phi:main::print2_@1->main::print2_@1] + print2_b1_from_print2_b1: + //SEG29 [12] phi (byte) main::print2_j#2 = (byte) main::print2_j#1 [phi:main::print2_@1->main::print2_@1#0] -- register_copy + //SEG30 [12] phi (byte) main::print2_i#2 = (byte) main::print2_i#1 [phi:main::print2_@1->main::print2_@1#1] -- register_copy + jmp print2_b1 + //SEG31 main::print2_@1 + print2_b1: + //SEG32 [13] *((const byte*) main::print2_at#0 + (byte) main::print2_j#2) ← *((const string) main::print1_msg#0 + (byte) main::print2_i#2) [ main::print2_i#2 main::print2_j#2 ] ( main:2 [ main::print2_i#2 main::print2_j#2 ] ) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuyy + lda print1_msg,y + sta print2_at,x + //SEG33 [14] (byte) main::print2_j#1 ← (byte) main::print2_j#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 [ main::print2_i#2 main::print2_j#1 ] ( main:2 [ main::print2_i#2 main::print2_j#1 ] ) -- vbuxx=vbuxx_plus_2 + inx + inx + //SEG34 [15] (byte) main::print2_i#1 ← ++ (byte) main::print2_i#2 [ main::print2_i#1 main::print2_j#1 ] ( main:2 [ main::print2_i#1 main::print2_j#1 ] ) -- vbuyy=_inc_vbuyy + iny + //SEG35 [16] if(*((const string) main::print1_msg#0 + (byte) main::print2_i#1)!=(byte) '@') goto main::print2_@1 [ main::print2_i#1 main::print2_j#1 ] ( main:2 [ main::print2_i#1 main::print2_j#1 ] ) -- pbuc1_derefidx_vbuyy_neq_vbuc2_then_la1 + lda print1_msg,y + cmp #'@' + bne print2_b1_from_print2_b1 + jmp breturn + //SEG36 main::@return + breturn: + //SEG37 [17] return [ ] ( main:2 [ ] ) + rts + print1_msg: .text "hello world!@" +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b2 +Removing instruction jmp bend +Removing instruction jmp print1 +Removing instruction jmp print1_b1 +Removing instruction jmp print2 +Removing instruction jmp print2_b1 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Replacing label print1_b1_from_print1_b1 with print1_b1 +Replacing label print2_b1_from_print2_b1 with print2_b1 +Removing instruction bbegin: +Removing instruction b2_from_bbegin: +Removing instruction main_from_b2: +Removing instruction bend_from_b2: +Removing instruction print1_from_main: +Removing instruction print1_b1_from_print1: +Removing instruction print1_b1_from_print1_b1: +Removing instruction print2_from_print1_b1: +Removing instruction print2_b1_from_print2: +Removing instruction print2_b1_from_print2_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction b2: +Removing instruction bend: +Removing instruction print1: +Removing instruction print2: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Removing instruction jmp print1_b1 +Removing instruction jmp print2_b1 +Succesful ASM optimization Pass5NextJumpElimination + +FINAL SYMBOL TABLE +(label) @2 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(byte*) main::hello +(label) main::print1 +(bool~) main::print1_$0 +(label) main::print1_@1 +(byte*) main::print1_at +(byte) main::print1_i +(byte) main::print1_i#1 reg byte y 16.5 +(byte) main::print1_i#2 reg byte y 11.0 +(byte) main::print1_j +(byte) main::print1_j#1 reg byte x 7.333333333333333 +(byte) main::print1_j#2 reg byte x 16.5 +(byte*) main::print1_msg +(const string) main::print1_msg#0 print1_msg = (string) "hello world!@" +(label) main::print2 +(bool~) main::print2_$0 +(label) main::print2_@1 +(byte*) main::print2_at +(const byte*) main::print2_at#0 print2_at = (const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 2*(byte/signed byte/word/signed word/dword/signed dword) 40 +(byte) main::print2_i +(byte) main::print2_i#1 reg byte y 16.5 +(byte) main::print2_i#2 reg byte y 11.0 +(byte) main::print2_j +(byte) main::print2_j#1 reg byte x 7.333333333333333 +(byte) main::print2_j#2 reg byte x 16.5 +(byte*) main::print2_msg +(byte*) screen +(const byte*) screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1024 + +reg byte y [ main::print1_i#2 main::print1_i#1 ] +reg byte x [ main::print1_j#2 main::print1_j#1 ] +reg byte y [ main::print2_i#2 main::print2_i#1 ] +reg byte x [ main::print2_j#2 main::print2_j#1 ] + + +FINAL ASSEMBLER +Score: 582 + +//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 @2 [phi:@begin->@2] +//SEG4 @2 +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @2 to main [phi:@2->main] + jsr main +//SEG7 [3] phi from @2 to @end [phi:@2->@end] +//SEG8 @end +//SEG9 main +main: { + .label print2_at = screen+2*$28 + //SEG10 [5] phi from main to main::print1 [phi:main->main::print1] + //SEG11 main::print1 + //SEG12 [6] phi from main::print1 to main::print1_@1 [phi:main::print1->main::print1_@1] + //SEG13 [6] phi (byte) main::print1_j#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::print1->main::print1_@1#0] -- vbuxx=vbuc1 + ldx #0 + //SEG14 [6] phi (byte) main::print1_i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::print1->main::print1_@1#1] -- vbuyy=vbuc1 + ldy #0 + //SEG15 [6] phi from main::print1_@1 to main::print1_@1 [phi:main::print1_@1->main::print1_@1] + //SEG16 [6] phi (byte) main::print1_j#2 = (byte) main::print1_j#1 [phi:main::print1_@1->main::print1_@1#0] -- register_copy + //SEG17 [6] phi (byte) main::print1_i#2 = (byte) main::print1_i#1 [phi:main::print1_@1->main::print1_@1#1] -- register_copy + //SEG18 main::print1_@1 + print1_b1: + //SEG19 [7] *((const byte*) screen#0 + (byte) main::print1_j#2) ← *((const string) main::print1_msg#0 + (byte) main::print1_i#2) [ main::print1_i#2 main::print1_j#2 ] ( main:2 [ main::print1_i#2 main::print1_j#2 ] ) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuyy + lda print1_msg,y + sta screen,x + //SEG20 [8] (byte) main::print1_j#1 ← (byte) main::print1_j#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 [ main::print1_i#2 main::print1_j#1 ] ( main:2 [ main::print1_i#2 main::print1_j#1 ] ) -- vbuxx=vbuxx_plus_2 + inx + inx + //SEG21 [9] (byte) main::print1_i#1 ← ++ (byte) main::print1_i#2 [ main::print1_i#1 main::print1_j#1 ] ( main:2 [ main::print1_i#1 main::print1_j#1 ] ) -- vbuyy=_inc_vbuyy + iny + //SEG22 [10] if(*((const string) main::print1_msg#0 + (byte) main::print1_i#1)!=(byte) '@') goto main::print1_@1 [ main::print1_i#1 main::print1_j#1 ] ( main:2 [ main::print1_i#1 main::print1_j#1 ] ) -- pbuc1_derefidx_vbuyy_neq_vbuc2_then_la1 + lda print1_msg,y + cmp #'@' + bne print1_b1 + //SEG23 [11] phi from main::print1_@1 to main::print2 [phi:main::print1_@1->main::print2] + //SEG24 main::print2 + //SEG25 [12] phi from main::print2 to main::print2_@1 [phi:main::print2->main::print2_@1] + //SEG26 [12] phi (byte) main::print2_j#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::print2->main::print2_@1#0] -- vbuxx=vbuc1 + ldx #0 + //SEG27 [12] phi (byte) main::print2_i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main::print2->main::print2_@1#1] -- vbuyy=vbuc1 + ldy #0 + //SEG28 [12] phi from main::print2_@1 to main::print2_@1 [phi:main::print2_@1->main::print2_@1] + //SEG29 [12] phi (byte) main::print2_j#2 = (byte) main::print2_j#1 [phi:main::print2_@1->main::print2_@1#0] -- register_copy + //SEG30 [12] phi (byte) main::print2_i#2 = (byte) main::print2_i#1 [phi:main::print2_@1->main::print2_@1#1] -- register_copy + //SEG31 main::print2_@1 + print2_b1: + //SEG32 [13] *((const byte*) main::print2_at#0 + (byte) main::print2_j#2) ← *((const string) main::print1_msg#0 + (byte) main::print2_i#2) [ main::print2_i#2 main::print2_j#2 ] ( main:2 [ main::print2_i#2 main::print2_j#2 ] ) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuyy + lda print1_msg,y + sta print2_at,x + //SEG33 [14] (byte) main::print2_j#1 ← (byte) main::print2_j#2 + (byte/signed byte/word/signed word/dword/signed dword) 2 [ main::print2_i#2 main::print2_j#1 ] ( main:2 [ main::print2_i#2 main::print2_j#1 ] ) -- vbuxx=vbuxx_plus_2 + inx + inx + //SEG34 [15] (byte) main::print2_i#1 ← ++ (byte) main::print2_i#2 [ main::print2_i#1 main::print2_j#1 ] ( main:2 [ main::print2_i#1 main::print2_j#1 ] ) -- vbuyy=_inc_vbuyy + iny + //SEG35 [16] if(*((const string) main::print1_msg#0 + (byte) main::print2_i#1)!=(byte) '@') goto main::print2_@1 [ main::print2_i#1 main::print2_j#1 ] ( main:2 [ main::print2_i#1 main::print2_j#1 ] ) -- pbuc1_derefidx_vbuyy_neq_vbuc2_then_la1 + lda print1_msg,y + cmp #'@' + bne print2_b1 + //SEG36 main::@return + //SEG37 [17] return [ ] ( main:2 [ ] ) + rts + print1_msg: .text "hello world!@" +} + diff --git a/src/test/java/dk/camelot64/kickc/test/ref/inline-function-print.sym b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-print.sym new file mode 100644 index 000000000..52fe8fbad --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/inline-function-print.sym @@ -0,0 +1,37 @@ +(label) @2 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(byte*) main::hello +(label) main::print1 +(bool~) main::print1_$0 +(label) main::print1_@1 +(byte*) main::print1_at +(byte) main::print1_i +(byte) main::print1_i#1 reg byte y 16.5 +(byte) main::print1_i#2 reg byte y 11.0 +(byte) main::print1_j +(byte) main::print1_j#1 reg byte x 7.333333333333333 +(byte) main::print1_j#2 reg byte x 16.5 +(byte*) main::print1_msg +(const string) main::print1_msg#0 print1_msg = (string) "hello world!@" +(label) main::print2 +(bool~) main::print2_$0 +(label) main::print2_@1 +(byte*) main::print2_at +(const byte*) main::print2_at#0 print2_at = (const byte*) screen#0+(byte/signed byte/word/signed word/dword/signed dword) 2*(byte/signed byte/word/signed word/dword/signed dword) 40 +(byte) main::print2_i +(byte) main::print2_i#1 reg byte y 16.5 +(byte) main::print2_i#2 reg byte y 11.0 +(byte) main::print2_j +(byte) main::print2_j#1 reg byte x 7.333333333333333 +(byte) main::print2_j#2 reg byte x 16.5 +(byte*) main::print2_msg +(byte*) screen +(const byte*) screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1024 + +reg byte y [ main::print1_i#2 main::print1_i#1 ] +reg byte x [ main::print1_j#2 main::print1_j#1 ] +reg byte y [ main::print2_i#2 main::print2_i#1 ] +reg byte x [ main::print2_j#2 main::print2_j#1 ]