From 4a7dd31d40c8f2314f97aa21dd06002edf1cde10 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Wed, 27 Dec 2017 21:47:07 +0100 Subject: [PATCH] Fixed word constructor detection to detect all inline word constructors. --- .../camelot64/kickc/passes/AliasReplacer.java | 3 +- .../passes/Pass1ExtractInlineStrings.java | 44 +- .../passes/Pass2FixWordConstructors.java | 67 +- .../camelot64/kickc/passes/ValueReplacer.java | 40 +- .../kickc/test/ref/bitmap-bresenham.log | 18 +- .../camelot64/kickc/test/ref/inline-word.log | 34 +- .../camelot64/kickc/test/ref/sinus-basic.log | 207 +++- .../kickc/test/ref/sinus-sprites.log | 12 +- .../kickc/test/ref/true-inline-words.asm | 26 + .../kickc/test/ref/true-inline-words.cfg | 22 + .../kickc/test/ref/true-inline-words.log | 1019 +++++++++++++++++ .../kickc/test/ref/true-inline-words.sym | 22 + .../camelot64/kickc/test/true-inline-words.kc | 21 +- 13 files changed, 1435 insertions(+), 100 deletions(-) create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/true-inline-words.asm create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/true-inline-words.cfg create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/true-inline-words.log create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/true-inline-words.sym diff --git a/src/main/java/dk/camelot64/kickc/passes/AliasReplacer.java b/src/main/java/dk/camelot64/kickc/passes/AliasReplacer.java index 9b6810fed..a7c8480d5 100644 --- a/src/main/java/dk/camelot64/kickc/passes/AliasReplacer.java +++ b/src/main/java/dk/camelot64/kickc/passes/AliasReplacer.java @@ -3,6 +3,7 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.model.*; import java.util.ArrayList; +import java.util.ListIterator; import java.util.Map; /** A {@link ValueReplacer} that replaces symbols with their alias. */ @@ -83,7 +84,7 @@ public class AliasReplacer implements ValueReplacer.Replacer { * @param replaceable The replaceable value */ @Override - public void execute(ValueReplacer.ReplaceableValue replaceable, Statement currentStmt, ControlFlowBlock currentBlock) { + public void execute(ValueReplacer.ReplaceableValue replaceable, Statement currentStmt, ListIterator stmtIt, ControlFlowBlock currentBlock) { if (replaceable.get() != null) { RValue replacement = getReplacement(replaceable.get(), aliases); if (replacement != null) { diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1ExtractInlineStrings.java b/src/main/java/dk/camelot64/kickc/passes/Pass1ExtractInlineStrings.java index 23d1d4bfd..1e57f484e 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1ExtractInlineStrings.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1ExtractInlineStrings.java @@ -15,62 +15,28 @@ public class Pass1ExtractInlineStrings extends Pass1Base { @Override public boolean step() { - ValueReplacer.executeAll(getGraph(), (replaceable, currentStmt, currentBlock) -> { + ValueReplacer.executeAll(getGraph(), (replaceable, currentStmt, stmtIt, currentBlock) -> { String nameHint = null; if(currentStmt instanceof StatementCall) { StatementCall call = (StatementCall) currentStmt; List parameters = call.getParameters(); - for (int i = 0; i < parameters.size(); i++) { + for(int i = 0; i < parameters.size(); i++) { RValue parameter = parameters.get(i); if(parameter.equals(replaceable.get())) { // The replaceable value is the parameter - use the parameter name as name hint - Procedure procedure = getProgram().getScope().getProcedure(call.getProcedure()); + Procedure procedure = Pass1ExtractInlineStrings.this.getProgram().getScope().getProcedure(call.getProcedure()); nameHint = procedure.getParameterNames().get(i); break; } } } - Scope blockScope = getProgram().getScope().getScope(currentBlock.getScope()); + Scope blockScope = Pass1ExtractInlineStrings.this.getProgram().getScope().getScope(currentBlock.getScope()); RValue value = replaceable.get(); if(value instanceof ConstantString) { - ConstantVar strConst = createStringConstantVar(blockScope, (ConstantString) replaceable.get(), nameHint); + ConstantVar strConst = Pass1ExtractInlineStrings.this.createStringConstantVar(blockScope, (ConstantString) replaceable.get(), nameHint); replaceable.set(strConst.getRef()); } }); - - /* - for (ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) { - ListIterator stmtIt = block.getStatements().listIterator(); - Scope blockScope = getProgram().getScope().getScope(block.getScope()); - while (stmtIt.hasNext()) { - Statement statement = stmtIt.next(); - if (statement instanceof StatementCall) { - StatementCall call = (StatementCall) statement; - Procedure procedure = getProgram().getScope().getProcedure(call.getProcedure()); - List parameters = call.getParameters(); - int size = parameters.size(); - for (int i = 0; i < size; i++) { - String parameterName = procedure.getParameterNames().get(i); - execute(new ValueReplacer.ReplaceableCallParameter(call, i), blockScope, parameterName); - } - } else if (statement instanceof StatementAssignment) { - StatementAssignment assignment = (StatementAssignment) statement; - if(assignment.getrValue1()==null && assignment.getOperator()==null && assignment.getrValue2() instanceof ConstantString) { - // This will be picked up later as a constant - the temporary constant variable is not needed - continue; - } - if(assignment.getrValue1() instanceof ConstantString && assignment.getrValue2() instanceof ConstantString) { - // This will be picked up later as a constant - the temporary constant variable is not needed - continue; - } - execute(new ValueReplacer.ReplaceableRValue1(assignment), blockScope, null); - execute(new ValueReplacer.ReplaceableRValue2(assignment), blockScope, null); - } else if (statement instanceof StatementReturn) { - execute(new ValueReplacer.ReplaceableReturn((StatementReturn) statement), blockScope, null); - } - } - } - */ return false; } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2FixWordConstructors.java b/src/main/java/dk/camelot64/kickc/passes/Pass2FixWordConstructors.java index 761365c60..53586fbd2 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2FixWordConstructors.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2FixWordConstructors.java @@ -2,6 +2,8 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.model.*; +import java.util.ListIterator; + /** * Identifies word constructors { b1, b2 } and replaces * them with a binary operator word w = b1 w= b2 ; @@ -14,35 +16,54 @@ public class Pass2FixWordConstructors extends Pass2SsaOptimization{ @Override public boolean step() { - boolean optimized = false; - ProgramScope programScope = getProgram().getScope(); - for (ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) { - for (Statement statement : block.getStatements()) { - if (statement instanceof StatementAssignment) { - StatementAssignment assignment = (StatementAssignment) statement; - if(assignment.getrValue1()==null && assignment.getOperator()==null) { - if(assignment.getrValue2() instanceof ValueList) { - ValueList list = (ValueList) assignment.getrValue2(); - if(list.getList().size()==2) { - // We have a simple assignment of a length 2 value list to a variable - SymbolType lType = SymbolTypeInference.inferType(programScope, assignment.getlValue()); - SymbolType elmType1 = SymbolTypeInference.inferType(programScope, list.getList().get(0)); - SymbolType elmType2 = SymbolTypeInference.inferType(programScope, list.getList().get(1)); - if(SymbolType.isWord(lType) && SymbolType.isByte(elmType1) && SymbolType.isByte(elmType2)) { - // Types are word = { byte, byte } - perform the modification - assignment.setrValue1(list.getList().get(0)); - assignment.setOperator(Operator.WORD); - assignment.setrValue2(list.getList().get(1)); - getLog().append("Fixing word constructor with " + assignment.toString()); - optimized = true; + final boolean[] optimized = {false}; + + ValueReplacer.executeAll(getGraph(), new ValueReplacer.Replacer() { + @Override + public void execute(ValueReplacer.ReplaceableValue replaceable, Statement currentStmt, ListIterator stmtIt, ControlFlowBlock currentBlock) { + RValue rValue = replaceable.get(); + if(rValue instanceof ValueList) { + ValueList list = (ValueList) rValue; + if(list.getList().size() == 2) { + // We have a simple assignment of a length 2 value list to a variable + SymbolType elmType1 = SymbolTypeInference.inferType(Pass2FixWordConstructors.this.getScope(), list.getList().get(0)); + SymbolType elmType2 = SymbolTypeInference.inferType(Pass2FixWordConstructors.this.getScope(), list.getList().get(1)); + if(SymbolType.isByte(elmType1) && SymbolType.isByte(elmType2)) { + // We have a 2-element list { byte, byte } + + // Check if we are assigning into a declared byte array + if(currentStmt instanceof StatementAssignment) { + StatementAssignment assignment = (StatementAssignment) currentStmt; + if(assignment.getrValue1() == null && assignment.getOperator() == null && assignment.getrValue2().equals(rValue)) { + SymbolType lType = SymbolTypeInference.inferType(Pass2FixWordConstructors.this.getScope(), assignment.getlValue()); + if(lType instanceof SymbolTypeArray && SymbolType.isByte(((SymbolTypeArray) lType).getElementType())) { + // We are assigning into a declared byte array - do not convert! + return; + } } } + + // Convert list to a word constructor in a new tmp variable + Scope currentScope = getScope().getScope(currentBlock.getScope()); + VariableIntermediate tmpVar = currentScope.addVariableIntermediate(); + tmpVar.setTypeInferred(SymbolType.WORD); + // Move backward - to insert before the current statement + stmtIt.previous(); + // Add assignment of the new tmpVar + StatementAssignment assignment = new StatementAssignment(tmpVar.getRef(), list.getList().get(0), Operator.WORD, list.getList().get(1)); + stmtIt.add(assignment); + // Move back before the current statement + stmtIt.next(); + // Replace current value with the reference + replaceable.set(tmpVar.getRef()); + Pass2FixWordConstructors.this.getLog().append("Fixing word constructor with " + assignment.toString()); + optimized[0] = true; } } } } - } - return optimized; + }); + return optimized[0]; } } diff --git a/src/main/java/dk/camelot64/kickc/passes/ValueReplacer.java b/src/main/java/dk/camelot64/kickc/passes/ValueReplacer.java index 067a367dc..12f06e3e8 100644 --- a/src/main/java/dk/camelot64/kickc/passes/ValueReplacer.java +++ b/src/main/java/dk/camelot64/kickc/passes/ValueReplacer.java @@ -1,9 +1,10 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.model.*; -import org.stringtemplate.v4.ST; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.ListIterator; /** * A replacer capable to alias all usages of a variable (or constant var) with a suitable replacement @@ -15,10 +16,11 @@ public class ValueReplacer { /** * Execute replacement of a replaceable value. * @param replaceable The replaceable value - * @param currentStmt The current statement that the value is a part of + * @param currentStmt The statement iterator - just past the current statement that the value is a part of. Current statment can be retrieved by calling + * @param stmtIt The statement iterator - just past the current statement. Can be used for modifying the control flow block. * @param currentBlock The current block that the value is a part of */ - void execute(ReplaceableValue replaceable, Statement currentStmt, ControlFlowBlock currentBlock); + void execute(ReplaceableValue replaceable, Statement currentStmt, ListIterator stmtIt, ControlFlowBlock currentBlock); } /** @@ -29,31 +31,33 @@ public class ValueReplacer { */ public static void executeAll(ControlFlowGraph graph, Replacer replacer) { for (ControlFlowBlock block : graph.getAllBlocks()) { - for (Statement statement : block.getStatements()) { + ListIterator statementsIt = block.getStatements().listIterator(); + while(statementsIt.hasNext()) { + Statement statement = statementsIt.next(); if (statement instanceof StatementAssignment) { - executeAll(new ReplaceableLValue((StatementLValue) statement), replacer, statement, block); - executeAll(new ReplaceableRValue1((StatementAssignment) statement), replacer, statement, block); - executeAll(new ReplaceableRValue2((StatementAssignment) statement), replacer, statement, block); + 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, block); + 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, block); + executeAll(new ReplaceableCallParameter(call, i), replacer, statement, statementsIt, block); } } } else if (statement instanceof StatementConditionalJump) { - executeAll(new ReplaceableCondRValue1((StatementConditionalJump) statement), replacer, statement, block); - executeAll(new ReplaceableCondRValue2((StatementConditionalJump) statement), replacer, statement, block); + 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, block); + 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, block); + 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, block); + executeAll(new ReplaceablePhiValue(phiVariable, i), replacer, statement, statementsIt, block); } } } @@ -66,10 +70,10 @@ public class ValueReplacer { * @param replaceable The replaceable value * @param replacer The value replacer */ - public static void executeAll(ReplaceableValue replaceable, Replacer replacer, Statement currentStmt, ControlFlowBlock currentBlock ) { - replacer.execute(replaceable, currentStmt, currentBlock); + public static void executeAll(ReplaceableValue replaceable, Replacer replacer, Statement currentStmt, ListIterator stmtIt, ControlFlowBlock currentBlock ) { + replacer.execute(replaceable, currentStmt, stmtIt, currentBlock); for (ReplaceableValue subValue : replaceable.getSubValues()) { - executeAll(subValue, replacer, currentStmt, currentBlock); + executeAll(subValue, replacer, currentStmt, stmtIt, currentBlock); } } diff --git a/src/main/java/dk/camelot64/kickc/test/ref/bitmap-bresenham.log b/src/main/java/dk/camelot64/kickc/test/ref/bitmap-bresenham.log index 8f4f06d06..194a721ae 100644 --- a/src/main/java/dk/camelot64/kickc/test/ref/bitmap-bresenham.log +++ b/src/main/java/dk/camelot64/kickc/test/ref/bitmap-bresenham.log @@ -10067,8 +10067,8 @@ Multiple usages for variable. Not optimizing sub-constant (byte) init_plot_table Multiple usages for variable. Not optimizing sub-constant (byte) init_plot_tables::y#2 Multiple usages for variable. Not optimizing sub-constant (byte) init_plot_tables::y#2 Multiple usages for variable. Not optimizing sub-constant (byte*) init_plot_tables::yoffs#2 -Fixing word constructor with plot::plotter_x#0 ← *(plot_xhi#0 + plot::x#4) w= *(plot_xlo#0 + plot::x#4) -Fixing word constructor with plot::plotter_y#0 ← *(plot_yhi#0 + plot::y#4) w= *(plot_ylo#0 + plot::y#4) +Fixing word constructor with plot::$2 ← *(plot_xhi#0 + plot::x#4) w= *(plot_xlo#0 + plot::x#4) +Fixing word constructor with plot::$3 ← *(plot_yhi#0 + plot::y#4) w= *(plot_ylo#0 + plot::y#4) Succesful SSA optimization Pass2FixWordConstructors CONTROL FLOW GRAPH @begin: scope:[] from @@ -10346,8 +10346,10 @@ line_ydxd::@return: scope:[line_ydxd] from line_ydxd::@2 plot: scope:[plot] from line_xdyd::@1 line_xdyi::@1 line_ydxd::@1 line_ydxi::@1 (byte) plot::y#4 ← phi( line_xdyd::@1/(byte) plot::y#1 line_xdyi::@1/(byte) plot::y#0 line_ydxd::@1/(byte) plot::y#3 line_ydxi::@1/(byte) plot::y#2 ) (byte) plot::x#4 ← phi( line_xdyd::@1/(byte) plot::x#1 line_xdyi::@1/(byte) plot::x#0 line_ydxd::@1/(byte) plot::x#3 line_ydxi::@1/(byte) plot::x#2 ) - (word) plot::plotter_x#0 ← *((const byte*) plot_xhi#0 + (byte) plot::x#4) w= *((const byte*) plot_xlo#0 + (byte) plot::x#4) - (word) plot::plotter_y#0 ← *((const byte*) plot_yhi#0 + (byte) plot::y#4) w= *((const byte*) plot_ylo#0 + (byte) plot::y#4) + (word~) plot::$2 ← *((const byte*) plot_xhi#0 + (byte) plot::x#4) w= *((const byte*) plot_xlo#0 + (byte) plot::x#4) + (word) plot::plotter_x#0 ← (word~) plot::$2 + (word~) plot::$3 ← *((const byte*) plot_yhi#0 + (byte) plot::y#4) w= *((const byte*) plot_ylo#0 + (byte) plot::y#4) + (word) plot::plotter_y#0 ← (word~) plot::$3 (word~) plot::$0 ← (word) plot::plotter_x#0 + (word) plot::plotter_y#0 (byte*) plot::plotter#0 ← ((byte*)) (word~) plot::$0 (byte~) plot::$1 ← *((byte*) plot::plotter#0) | *((const byte*) plot_bit#0 + (byte) plot::x#4) @@ -10703,8 +10705,10 @@ line_ydxd::@return: scope:[line_ydxd] from line_ydxd::@2 plot: scope:[plot] from line_xdyd::@1 line_xdyi::@1 line_ydxd::@1 line_ydxi::@1 (byte) plot::y#4 ← phi( line_xdyd::@1/(byte) plot::y#1 line_xdyi::@1/(byte) plot::y#0 line_ydxd::@1/(byte) plot::y#3 line_ydxi::@1/(byte) plot::y#2 ) (byte) plot::x#4 ← phi( line_xdyd::@1/(byte) plot::x#1 line_xdyi::@1/(byte) plot::x#0 line_ydxd::@1/(byte) plot::x#3 line_ydxi::@1/(byte) plot::x#2 ) - (word) plot::plotter_x#0 ← *((const byte*) plot_xhi#0 + (byte) plot::x#4) w= *((const byte*) plot_xlo#0 + (byte) plot::x#4) - (word) plot::plotter_y#0 ← *((const byte*) plot_yhi#0 + (byte) plot::y#4) w= *((const byte*) plot_ylo#0 + (byte) plot::y#4) + (word~) plot::$2 ← *((const byte*) plot_xhi#0 + (byte) plot::x#4) w= *((const byte*) plot_xlo#0 + (byte) plot::x#4) + (word) plot::plotter_x#0 ← (word~) plot::$2 + (word~) plot::$3 ← *((const byte*) plot_yhi#0 + (byte) plot::y#4) w= *((const byte*) plot_ylo#0 + (byte) plot::y#4) + (word) plot::plotter_y#0 ← (word~) plot::$3 (word~) plot::$0 ← (word) plot::plotter_x#0 + (word) plot::plotter_y#0 (byte*) plot::plotter#0 ← ((byte*)) (word~) plot::$0 (byte~) plot::$1 ← *((byte*) plot::plotter#0) | *((const byte*) plot_bit#0 + (byte) plot::x#4) @@ -10849,6 +10853,8 @@ Not aliassing across scopes: plot::y#3 line_ydxd::y#3 Not aliassing across scopes: plot::x#4 plot::x#1 Not aliassing across scopes: plot::y#4 plot::y#1 Alias (byte) lines::l#2 = (byte/word~) lines::$0 (byte/word~) lines::$1 +Alias (word) plot::plotter_x#0 = (word~) plot::$2 +Alias (word) plot::plotter_y#0 = (word~) plot::$3 Succesful SSA optimization Pass2AliasElimination CONTROL FLOW GRAPH @begin: scope:[] from diff --git a/src/main/java/dk/camelot64/kickc/test/ref/inline-word.log b/src/main/java/dk/camelot64/kickc/test/ref/inline-word.log index 7e2d89afb..a5a37170c 100644 --- a/src/main/java/dk/camelot64/kickc/test/ref/inline-word.log +++ b/src/main/java/dk/camelot64/kickc/test/ref/inline-word.log @@ -678,9 +678,41 @@ main::@return: scope:[main] from main::@3 to:@end @end: scope:[] from @1 -Fixing word constructor with main::w#0 ← *(main::his#2 + main::h#4) w= main::l#2 +Fixing word constructor with main::$8 ← *(main::his#2 + main::h#4) w= main::l#2 Succesful SSA optimization Pass2FixWordConstructors CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + to:main::@1 +main::@1: scope:[main] from main main::@3 + (byte) main::h#4 ← phi( main/(const byte) main::h#0 main::@3/(byte) main::h#1 ) + (byte[]) main::his#2 ← phi( main/(const byte[]) main::his#0 main::@3/(byte[]) main::his#2 ) + to:main::@2 +main::@2: scope:[main] from main::@1 main::@2 + (byte) main::l#2 ← phi( main::@1/(const byte) main::l#0 main::@2/(byte) main::l#1 ) + (word~) main::$8 ← *((byte[]) main::his#2 + (byte) main::h#4) w= (byte) main::l#2 + (word) main::w#0 ← (word~) main::$8 + (byte*) main::sc#0 ← ((byte*)) (word) main::w#0 + *((byte*) main::sc#0) ← (byte) '*' + (byte) main::l#1 ← ++ (byte) main::l#2 + if((byte) main::l#1!=(byte/signed byte/word/signed word) 8) goto main::@2 + to:main::@3 +main::@3: scope:[main] from main::@2 + (byte) main::h#1 ← ++ (byte) main::h#4 + if((byte) main::h#1!=(byte/signed byte/word/signed word) 3) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Alias (word) main::w#0 = (word~) main::$8 +Succesful SSA optimization Pass2AliasElimination +CONTROL FLOW GRAPH @begin: scope:[] from to:@1 main: scope:[main] from @1 diff --git a/src/main/java/dk/camelot64/kickc/test/ref/sinus-basic.log b/src/main/java/dk/camelot64/kickc/test/ref/sinus-basic.log index bc4089570..f103511ad 100644 --- a/src/main/java/dk/camelot64/kickc/test/ref/sinus-basic.log +++ b/src/main/java/dk/camelot64/kickc/test/ref/sinus-basic.log @@ -4225,7 +4225,7 @@ main::@return: scope:[main] from main::@16 to:@end @end: scope:[] from @35 -Fixing word constructor with getFAC::return#0 ← *(memHi#0) w= *(memLo#0) +Fixing word constructor with getFAC::$0 ← *(memHi#0) w= *(memLo#0) Succesful SSA optimization Pass2FixWordConstructors CONTROL FLOW GRAPH @begin: scope:[] from @@ -4306,7 +4306,8 @@ setFAC::@return: scope:[setFAC] from setFAC::@1 to:@return getFAC: scope:[getFAC] from main::@13 asm { jsr$b1aasty$festa$ff } - (word) getFAC::return#0 ← *((const byte*) memHi#0) w= *((const byte*) memLo#0) + (word~) getFAC::$0 ← *((const byte*) memHi#0) w= *((const byte*) memLo#0) + (word) getFAC::return#0 ← (word~) getFAC::$0 to:getFAC::@return getFAC::@return: scope:[getFAC] from getFAC return @@ -4435,6 +4436,208 @@ Culled Empty Block (label) main::@5 Culled Empty Block (label) @35 Succesful SSA optimization Pass2CullEmptyBlocks CONTROL FLOW GRAPH +@begin: scope:[] from + to:@34 +print_ln: scope:[print_ln] from main::@15 + to:print_ln::@1 +print_ln::@1: scope:[print_ln] from print_ln print_ln::@1 + (byte*) line_cursor#6 ← phi( print_ln/(byte*) line_cursor#13 print_ln::@1/(byte*) line_cursor#1 ) + (byte*) line_cursor#1 ← (byte*) line_cursor#6 + (byte/signed byte/word/signed word) 40 + if((byte*) line_cursor#1<(byte*) char_cursor#10) goto print_ln::@1 + to:print_ln::@return +print_ln::@return: scope:[print_ln] from print_ln::@1 + return + to:@return +print_word: scope:[print_word] from main::@14 + (byte) print_byte::b#0 ← > (word) print_word::w#0 + call print_byte param-assignment + to:print_word::@1 +print_word::@1: scope:[print_word] from print_word + (byte) print_byte::b#1 ← < (word) print_word::w#0 + call print_byte param-assignment + to:print_word::@return +print_word::@return: scope:[print_word] from print_word::@1 + return + to:@return +print_byte: scope:[print_byte] from print_word print_word::@1 + (byte*) char_cursor#31 ← phi( print_word/(byte*) char_cursor#32 print_word::@1/(byte*) char_cursor#10 ) + (byte) print_byte::b#2 ← phi( print_word/(byte) print_byte::b#0 print_word::@1/(byte) print_byte::b#1 ) + (byte~) print_byte::$0 ← (byte) print_byte::b#2 >> (byte/signed byte/word/signed word) 4 + (byte) print_char::ch#0 ← *((const byte[]) print_byte::hextab#0 + (byte~) print_byte::$0) + call print_char param-assignment + to:print_byte::@1 +print_byte::@1: scope:[print_byte] from print_byte + (byte~) print_byte::$2 ← (byte) print_byte::b#2 & (byte/signed byte/word/signed word) 15 + (byte) print_char::ch#1 ← *((const byte[]) print_byte::hextab#0 + (byte~) print_byte::$2) + call print_char param-assignment + to:print_byte::@return +print_byte::@return: scope:[print_byte] from print_byte::@1 + return + to:@return +print_char: scope:[print_char] from print_byte print_byte::@1 + (byte*) char_cursor#23 ← phi( print_byte/(byte*) char_cursor#31 print_byte::@1/(byte*) char_cursor#10 ) + (byte) print_char::ch#2 ← phi( print_byte/(byte) print_char::ch#0 print_byte::@1/(byte) print_char::ch#1 ) + *((byte*) char_cursor#23) ← (byte) print_char::ch#2 + (byte*) char_cursor#10 ← ++ (byte*) char_cursor#23 + to:print_char::@return +print_char::@return: scope:[print_char] from print_char + return + to:@return +prepareMEM: scope:[prepareMEM] from addMEMtoFAC divMEMbyFAC mulFACbyMEM setFAC setMEMtoFAC + (byte*) prepareMEM::mem#5 ← phi( addMEMtoFAC/(const byte[]) prepareMEM::mem#2 divMEMbyFAC/(const byte[]) prepareMEM::mem#3 mulFACbyMEM/(byte*) prepareMEM::mem#4 setFAC/(byte*) prepareMEM::mem#0 setMEMtoFAC/(byte*) prepareMEM::mem#1 ) + (byte~) prepareMEM::$0 ← < (byte*) prepareMEM::mem#5 + *((const byte*) memLo#0) ← (byte~) prepareMEM::$0 + (byte~) prepareMEM::$1 ← > (byte*) prepareMEM::mem#5 + *((const byte*) memHi#0) ← (byte~) prepareMEM::$1 + to:prepareMEM::@return +prepareMEM::@return: scope:[prepareMEM] from prepareMEM + return + to:@return +setFAC: scope:[setFAC] from main main::@1 main::@8 + (word) setFAC::w#3 ← phi( main/(const word) setFAC::w#0 main::@1/(word) setFAC::w#1 main::@8/(const word) setFAC::w#2 ) + (byte*) prepareMEM::mem#0 ← ((byte*)) (word) setFAC::w#3 + call prepareMEM param-assignment + to:setFAC::@1 +setFAC::@1: scope:[setFAC] from setFAC + asm { ldy$felda$ffjsr$b391 } + to:setFAC::@return +setFAC::@return: scope:[setFAC] from setFAC::@1 + return + to:@return +getFAC: scope:[getFAC] from main::@13 + asm { jsr$b1aasty$festa$ff } + (word~) getFAC::$0 ← *((const byte*) memHi#0) w= *((const byte*) memLo#0) + (word) getFAC::return#0 ← (word~) getFAC::$0 + to:getFAC::@return +getFAC::@return: scope:[getFAC] from getFAC + return + to:@return +setMEMtoFAC: scope:[setMEMtoFAC] from main::@4 main::@7 + (byte*) setMEMtoFAC::mem#2 ← phi( main::@4/(const byte[]) setMEMtoFAC::mem#0 main::@7/(const byte[]) setMEMtoFAC::mem#1 ) + (byte*) prepareMEM::mem#1 ← (byte*) setMEMtoFAC::mem#2 + call prepareMEM param-assignment + to:setMEMtoFAC::@1 +setMEMtoFAC::@1: scope:[setMEMtoFAC] from setMEMtoFAC + asm { ldx$feldy$ffjsr$bbd4 } + to:setMEMtoFAC::@return +setMEMtoFAC::@return: scope:[setMEMtoFAC] from setMEMtoFAC::@1 + return + to:@return +addMEMtoFAC: scope:[addMEMtoFAC] from main::@12 + call prepareMEM param-assignment + to:addMEMtoFAC::@1 +addMEMtoFAC::@1: scope:[addMEMtoFAC] from addMEMtoFAC + asm { lda$feldy$ffjsr$b867 } + to:addMEMtoFAC::@return +addMEMtoFAC::@return: scope:[addMEMtoFAC] from addMEMtoFAC::@1 + return + to:@return +divMEMbyFAC: scope:[divMEMbyFAC] from main::@9 + call prepareMEM param-assignment + to:divMEMbyFAC::@1 +divMEMbyFAC::@1: scope:[divMEMbyFAC] from divMEMbyFAC + asm { lda$feldy$ffjsr$bb0f } + to:divMEMbyFAC::@return +divMEMbyFAC::@return: scope:[divMEMbyFAC] from divMEMbyFAC::@1 + return + to:@return +mulFACbyMEM: scope:[mulFACbyMEM] from main::@11 main::@6 + (byte*) mulFACbyMEM::mem#2 ← phi( main::@11/(const byte[]) mulFACbyMEM::mem#1 main::@6/(const byte*) mulFACbyMEM::mem#0 ) + (byte*) prepareMEM::mem#4 ← (byte*) mulFACbyMEM::mem#2 + call prepareMEM param-assignment + to:mulFACbyMEM::@1 +mulFACbyMEM::@1: scope:[mulFACbyMEM] from mulFACbyMEM + asm { lda$feldy$ffjsr$ba28 } + to:mulFACbyMEM::@return +mulFACbyMEM::@return: scope:[mulFACbyMEM] from mulFACbyMEM::@1 + return + to:@return +sinFAC: scope:[sinFAC] from main::@10 + asm { jsr$e26b } + to:sinFAC::@return +sinFAC::@return: scope:[sinFAC] from sinFAC + return + to:@return +divFACby10: scope:[divFACby10] from main::@3 + asm { jsr$bafe } + to:divFACby10::@return +divFACby10::@return: scope:[divFACby10] from divFACby10 + return + to:@return +main: scope:[main] from @34 + call setFAC param-assignment + to:main::@3 +main::@3: scope:[main] from main + call divFACby10 param-assignment + to:main::@4 +main::@4: scope:[main] from main::@3 + call setMEMtoFAC param-assignment + to:main::@1 +main::@1: scope:[main] from main::@16 main::@4 + (byte*) line_cursor#13 ← phi( main::@16/(byte*) line_cursor#1 main::@4/(const byte*) char_cursor#0 ) + (byte*) char_cursor#32 ← phi( main::@16/(byte*) line_cursor#1 main::@4/(const byte*) char_cursor#0 ) + (byte) main::i#10 ← phi( main::@16/(byte) main::i#1 main::@4/(const byte) main::i#0 ) + (word) setFAC::w#1 ← ((word)) (byte) main::i#10 + call setFAC param-assignment + to:main::@6 +main::@6: scope:[main] from main::@1 + call mulFACbyMEM param-assignment + to:main::@7 +main::@7: scope:[main] from main::@6 + call setMEMtoFAC param-assignment + to:main::@8 +main::@8: scope:[main] from main::@7 + call setFAC param-assignment + to:main::@9 +main::@9: scope:[main] from main::@8 + call divMEMbyFAC param-assignment + to:main::@10 +main::@10: scope:[main] from main::@9 + call sinFAC param-assignment + to:main::@11 +main::@11: scope:[main] from main::@10 + call mulFACbyMEM param-assignment + to:main::@12 +main::@12: scope:[main] from main::@11 + call addMEMtoFAC param-assignment + to:main::@13 +main::@13: scope:[main] from main::@12 + call getFAC param-assignment + (word) getFAC::return#2 ← (word) getFAC::return#0 + to:main::@14 +main::@14: scope:[main] from main::@13 + (word) print_word::w#0 ← (word) getFAC::return#2 + call print_word param-assignment + to:main::@15 +main::@15: scope:[main] from main::@14 + call print_ln param-assignment + to:main::@16 +main::@16: scope:[main] from main::@15 + (byte) main::i#1 ← ++ (byte) main::i#10 + if((byte) main::i#1!=(byte/signed byte/word/signed word) 26) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@16 + return + to:@return +@34: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @34 + +Not aliassing across scopes: line_cursor#6 line_cursor#13 +Not aliassing across scopes: print_byte::b#2 print_byte::b#0 +Not aliassing across scopes: char_cursor#31 char_cursor#32 +Not aliassing across scopes: print_char::ch#2 print_char::ch#0 +Not aliassing across scopes: char_cursor#23 char_cursor#31 +Not aliassing across scopes: prepareMEM::mem#1 setMEMtoFAC::mem#2 +Not aliassing across scopes: prepareMEM::mem#4 mulFACbyMEM::mem#2 +Not aliassing across scopes: char_cursor#32 line_cursor#1 +Not aliassing across scopes: line_cursor#13 line_cursor#1 +Not aliassing across scopes: getFAC::return#2 getFAC::return#0 +Not aliassing across scopes: print_word::w#0 getFAC::return#2 +Alias (word) getFAC::return#0 = (word~) getFAC::$0 +Succesful SSA optimization Pass2AliasElimination +CONTROL FLOW GRAPH @begin: scope:[] from to:@34 print_ln: scope:[print_ln] from main::@15 diff --git a/src/main/java/dk/camelot64/kickc/test/ref/sinus-sprites.log b/src/main/java/dk/camelot64/kickc/test/ref/sinus-sprites.log index 28d345e8b..ab01130e6 100644 --- a/src/main/java/dk/camelot64/kickc/test/ref/sinus-sprites.log +++ b/src/main/java/dk/camelot64/kickc/test/ref/sinus-sprites.log @@ -12954,7 +12954,7 @@ Multiple usages for variable. Not optimizing sub-constant (byte) init::i#2 Multiple usages for variable. Not optimizing sub-constant (byte) place_sprites::spr_x#2 Multiple usages for variable. Not optimizing sub-constant (byte*) gen_sprites::spr#2 Multiple usages for variable. Not optimizing sub-constant (byte*) gen_chargen_sprite::sprite#4 -Fixing word constructor with getFAC::return#0 ← *(memHi#0) w= *(memLo#0) +Fixing word constructor with getFAC::$0 ← *(memHi#0) w= *(memLo#0) Succesful SSA optimization Pass2FixWordConstructors CONTROL FLOW GRAPH @begin: scope:[] from @@ -12982,7 +12982,8 @@ setFAC::@return: scope:[setFAC] from setFAC::@1 to:@return getFAC: scope:[getFAC] from gen_sintab::@21 asm { jsr$b1aasty$festa$ff } - (word) getFAC::return#0 ← *((const byte*) memHi#0) w= *((const byte*) memLo#0) + (word~) getFAC::$0 ← *((const byte*) memHi#0) w= *((const byte*) memLo#0) + (word) getFAC::return#0 ← (word~) getFAC::$0 to:getFAC::@return getFAC::@return: scope:[getFAC] from getFAC return @@ -13444,7 +13445,8 @@ setFAC::@return: scope:[setFAC] from setFAC::@1 to:@return getFAC: scope:[getFAC] from gen_sintab::@21 asm { jsr$b1aasty$festa$ff } - (word) getFAC::return#0 ← *((const byte*) memHi#0) w= *((const byte*) memLo#0) + (word~) getFAC::$0 ← *((const byte*) memHi#0) w= *((const byte*) memLo#0) + (word) getFAC::return#0 ← (word~) getFAC::$0 to:getFAC::@return getFAC::@return: scope:[getFAC] from getFAC return @@ -13917,7 +13919,8 @@ setFAC::@return: scope:[setFAC] from setFAC::@1 to:@return getFAC: scope:[getFAC] from gen_sintab::@21 asm { jsr$b1aasty$festa$ff } - (word) getFAC::return#0 ← *((const byte*) memHi#0) w= *((const byte*) memLo#0) + (word~) getFAC::$0 ← *((const byte*) memHi#0) w= *((const byte*) memLo#0) + (word) getFAC::return#0 ← (word~) getFAC::$0 to:getFAC::@return getFAC::@return: scope:[getFAC] from getFAC return @@ -14353,6 +14356,7 @@ Not aliassing across scopes: gen_chargen_sprite::sprite#11 gen_chargen_sprite::s Not aliassing across scopes: progress_cursor#34 progress_cursor#22 Not aliassing across scopes: getFAC::return#2 getFAC::return#0 Not aliassing across scopes: gen_sintab::$23 getFAC::return#2 +Alias (word) getFAC::return#0 = (word~) getFAC::$0 Alias (byte) init::i#2 = (byte/word~) init::$1 Succesful SSA optimization Pass2AliasElimination CONTROL FLOW GRAPH diff --git a/src/main/java/dk/camelot64/kickc/test/ref/true-inline-words.asm b/src/main/java/dk/camelot64/kickc/test/ref/true-inline-words.asm new file mode 100644 index 000000000..323039042 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/true-inline-words.asm @@ -0,0 +1,26 @@ +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + jsr main +main: { + .const b = 4 + .const pos = $501 + .const bgcol = $d021 + .const w = b*$100+0 + .const w2 = 1*$100+1+w+0*$100+0 + .const sc = w2 + lda bs+1 + sta sc + lda pos + cmp #'m' + bne b1 + lda #5 + sta bgcol + breturn: + rts + b1: + lda #2 + sta bgcol + jmp breturn + bs: .byte 'c', 'm' +} diff --git a/src/main/java/dk/camelot64/kickc/test/ref/true-inline-words.cfg b/src/main/java/dk/camelot64/kickc/test/ref/true-inline-words.cfg new file mode 100644 index 000000000..ba89b2549 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/true-inline-words.cfg @@ -0,0 +1,22 @@ +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@1 +@1: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @1 + [3] phi() [ ] ( ) +main: scope:[main] from @1 + [4] *((const byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) [ ] ( main:2 [ ] ) + [5] if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 [ ] ( main:2 [ ] ) + to:main::@3 +main::@3: scope:[main] from main + [6] *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 [ ] ( main:2 [ ] ) + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + [7] return [ ] ( main:2 [ ] ) + to:@return +main::@1: scope:[main] from main + [8] *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 [ ] ( main:2 [ ] ) + to:main::@return diff --git a/src/main/java/dk/camelot64/kickc/test/ref/true-inline-words.log b/src/main/java/dk/camelot64/kickc/test/ref/true-inline-words.log new file mode 100644 index 000000000..7f0806fce --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/true-inline-words.log @@ -0,0 +1,1019 @@ + +void main() { + byte[] bs = { 'c', 'm' }; // constant byte array + byte b = 4; // constant byte + word w = { b, 0 }; // constant inline word + word w2 = { 1, 1 } + w + { 0, 0 }; // constant inline words inside expression + byte* sc = w2; // implicit cast to (byte*) + *sc = bs[1]; // In the end $501 is set to 'c' + + // Test the result + byte* pos = $501; + byte* bgcol = $d021; + if(*pos=='m') { + *bgcol = 5; + } else { + *bgcol = 2; + } +} + + +PROGRAM +proc (void()) main() + (byte[]) main::bs ← { (byte) 'c', (byte) 'm' } + (byte) main::b ← (byte/signed byte/word/signed word) 4 + (word) main::w ← { (byte) main::b, (byte/signed byte/word/signed word) 0 } + (word~) main::$0 ← { (byte/signed byte/word/signed word) 1, (byte/signed byte/word/signed word) 1 } + (word) main::w + (word~) main::$1 ← (word~) main::$0 + { (byte/signed byte/word/signed word) 0, (byte/signed byte/word/signed word) 0 } + (word) main::w2 ← (word~) main::$1 + (byte*) main::sc ← (word) main::w2 + *((byte*) main::sc) ← *((byte[]) main::bs + (byte/signed byte/word/signed word) 1) + (byte*) main::pos ← (word/signed word) 1281 + (byte*) main::bgcol ← (word) 53281 + (boolean~) main::$2 ← *((byte*) main::pos) == (byte) 'm' + (boolean~) main::$3 ← ! (boolean~) main::$2 + if((boolean~) main::$3) goto main::@1 + *((byte*) main::bgcol) ← (byte/signed byte/word/signed word) 5 + goto main::@2 +main::@1: + *((byte*) main::bgcol) ← (byte/signed byte/word/signed word) 2 +main::@2: +main::@return: + return +endproc // main() + call main + +SYMBOLS +(void()) main() +(word~) main::$0 +(word~) main::$1 +(boolean~) main::$2 +(boolean~) main::$3 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte) main::b +(byte*) main::bgcol +(byte[]) main::bs +(byte*) main::pos +(byte*) main::sc +(word) main::w +(word) main::w2 + +Promoting word to byte* in main::sc ← ((byte*)) main::w2 +Promoting word/signed word to byte* in main::pos ← ((byte*)) 1281 +Promoting word to byte* in main::bgcol ← ((byte*)) 53281 +INITIAL CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from + (byte[]) main::bs ← { (byte) 'c', (byte) 'm' } + (byte) main::b ← (byte/signed byte/word/signed word) 4 + (word) main::w ← { (byte) main::b, (byte/signed byte/word/signed word) 0 } + (word~) main::$0 ← { (byte/signed byte/word/signed word) 1, (byte/signed byte/word/signed word) 1 } + (word) main::w + (word~) main::$1 ← (word~) main::$0 + { (byte/signed byte/word/signed word) 0, (byte/signed byte/word/signed word) 0 } + (word) main::w2 ← (word~) main::$1 + (byte*) main::sc ← ((byte*)) (word) main::w2 + *((byte*) main::sc) ← *((byte[]) main::bs + (byte/signed byte/word/signed word) 1) + (byte*) main::pos ← ((byte*)) (word/signed word) 1281 + (byte*) main::bgcol ← ((byte*)) (word) 53281 + (boolean~) main::$2 ← *((byte*) main::pos) == (byte) 'm' + (boolean~) main::$3 ← ! (boolean~) main::$2 + if((boolean~) main::$3) goto main::@1 + to:main::@3 +main::@1: scope:[main] from main main::@4 + *((byte*) main::bgcol) ← (byte/signed byte/word/signed word) 2 + to:main::@2 +main::@3: scope:[main] from main + *((byte*) main::bgcol) ← (byte/signed byte/word/signed word) 5 + to:main::@2 +main::@2: scope:[main] from main::@1 main::@3 + to:main::@return +main::@4: scope:[main] from + to:main::@1 +main::@return: scope:[main] from main::@2 + return + to:@return +@1: scope:[] from @begin + call main + to:@end +@end: scope:[] from @1 + +Removing empty block main::@2 +Removing empty block main::@4 +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from + (byte[]) main::bs ← { (byte) 'c', (byte) 'm' } + (byte) main::b ← (byte/signed byte/word/signed word) 4 + (word) main::w ← { (byte) main::b, (byte/signed byte/word/signed word) 0 } + (word~) main::$0 ← { (byte/signed byte/word/signed word) 1, (byte/signed byte/word/signed word) 1 } + (word) main::w + (word~) main::$1 ← (word~) main::$0 + { (byte/signed byte/word/signed word) 0, (byte/signed byte/word/signed word) 0 } + (word) main::w2 ← (word~) main::$1 + (byte*) main::sc ← ((byte*)) (word) main::w2 + *((byte*) main::sc) ← *((byte[]) main::bs + (byte/signed byte/word/signed word) 1) + (byte*) main::pos ← ((byte*)) (word/signed word) 1281 + (byte*) main::bgcol ← ((byte*)) (word) 53281 + (boolean~) main::$2 ← *((byte*) main::pos) == (byte) 'm' + (boolean~) main::$3 ← ! (boolean~) main::$2 + if((boolean~) main::$3) goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + *((byte*) main::bgcol) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + *((byte*) main::bgcol) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main + to:@end +@end: scope:[] from @1 + +PROCEDURE MODIFY VARIABLE ANALYSIS + +CONTROL FLOW GRAPH WITH ASSIGNMENT CALL +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte[]) main::bs ← { (byte) 'c', (byte) 'm' } + (byte) main::b ← (byte/signed byte/word/signed word) 4 + (word) main::w ← { (byte) main::b, (byte/signed byte/word/signed word) 0 } + (word~) main::$0 ← { (byte/signed byte/word/signed word) 1, (byte/signed byte/word/signed word) 1 } + (word) main::w + (word~) main::$1 ← (word~) main::$0 + { (byte/signed byte/word/signed word) 0, (byte/signed byte/word/signed word) 0 } + (word) main::w2 ← (word~) main::$1 + (byte*) main::sc ← ((byte*)) (word) main::w2 + *((byte*) main::sc) ← *((byte[]) main::bs + (byte/signed byte/word/signed word) 1) + (byte*) main::pos ← ((byte*)) (word/signed word) 1281 + (byte*) main::bgcol ← ((byte*)) (word) 53281 + (boolean~) main::$2 ← *((byte*) main::pos) == (byte) 'm' + (boolean~) main::$3 ← ! (boolean~) main::$2 + if((boolean~) main::$3) goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + *((byte*) main::bgcol) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + *((byte*) main::bgcol) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +Completing Phi functions... +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte[]) main::bs#0 ← { (byte) 'c', (byte) 'm' } + (byte) main::b#0 ← (byte/signed byte/word/signed word) 4 + (word) main::w#0 ← { (byte) main::b#0, (byte/signed byte/word/signed word) 0 } + (word~) main::$0 ← { (byte/signed byte/word/signed word) 1, (byte/signed byte/word/signed word) 1 } + (word) main::w#0 + (word~) main::$1 ← (word~) main::$0 + { (byte/signed byte/word/signed word) 0, (byte/signed byte/word/signed word) 0 } + (word) main::w2#0 ← (word~) main::$1 + (byte*) main::sc#0 ← ((byte*)) (word) main::w2#0 + *((byte*) main::sc#0) ← *((byte[]) main::bs#0 + (byte/signed byte/word/signed word) 1) + (byte*) main::pos#0 ← ((byte*)) (word/signed word) 1281 + (byte*) main::bgcol#0 ← ((byte*)) (word) 53281 + (boolean~) main::$2 ← *((byte*) main::pos#0) == (byte) 'm' + (boolean~) main::$3 ← ! (boolean~) main::$2 + if((boolean~) main::$3) goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + (byte*) main::bgcol#1 ← phi( main/(byte*) main::bgcol#0 ) + *((byte*) main::bgcol#1) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + (byte*) main::bgcol#2 ← phi( main/(byte*) main::bgcol#0 ) + *((byte*) main::bgcol#2) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte[]) main::bs#0 ← { (byte) 'c', (byte) 'm' } + (byte) main::b#0 ← (byte/signed byte/word/signed word) 4 + (word) main::w#0 ← { (byte) main::b#0, (byte/signed byte/word/signed word) 0 } + (word~) main::$0 ← { (byte/signed byte/word/signed word) 1, (byte/signed byte/word/signed word) 1 } + (word) main::w#0 + (word~) main::$1 ← (word~) main::$0 + { (byte/signed byte/word/signed word) 0, (byte/signed byte/word/signed word) 0 } + (word) main::w2#0 ← (word~) main::$1 + (byte*) main::sc#0 ← ((byte*)) (word) main::w2#0 + *((byte*) main::sc#0) ← *((byte[]) main::bs#0 + (byte/signed byte/word/signed word) 1) + (byte*) main::pos#0 ← ((byte*)) (word/signed word) 1281 + (byte*) main::bgcol#0 ← ((byte*)) (word) 53281 + (boolean~) main::$2 ← *((byte*) main::pos#0) == (byte) 'm' + (boolean~) main::$3 ← ! (boolean~) main::$2 + if((boolean~) main::$3) goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + (byte*) main::bgcol#1 ← phi( main/(byte*) main::bgcol#0 ) + *((byte*) main::bgcol#1) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + (byte*) main::bgcol#2 ← phi( main/(byte*) main::bgcol#0 ) + *((byte*) main::bgcol#2) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +INITIAL SSA SYMBOL TABLE +(label) @1 +(label) @2 +(label) @begin +(label) @end +(void()) main() +(word~) main::$0 +(word~) main::$1 +(boolean~) main::$2 +(boolean~) main::$3 +(label) main::@1 +(label) main::@3 +(label) main::@return +(byte) main::b +(byte) main::b#0 +(byte*) main::bgcol +(byte*) main::bgcol#0 +(byte*) main::bgcol#1 +(byte*) main::bgcol#2 +(byte[]) main::bs +(byte[]) main::bs#0 +(byte*) main::pos +(byte*) main::pos#0 +(byte*) main::sc +(byte*) main::sc#0 +(word) main::w +(word) main::w#0 +(word) main::w2 +(word) main::w2#0 + +Culled Empty Block (label) @2 +Succesful SSA optimization Pass2CullEmptyBlocks +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte[]) main::bs#0 ← { (byte) 'c', (byte) 'm' } + (byte) main::b#0 ← (byte/signed byte/word/signed word) 4 + (word) main::w#0 ← { (byte) main::b#0, (byte/signed byte/word/signed word) 0 } + (word~) main::$0 ← { (byte/signed byte/word/signed word) 1, (byte/signed byte/word/signed word) 1 } + (word) main::w#0 + (word~) main::$1 ← (word~) main::$0 + { (byte/signed byte/word/signed word) 0, (byte/signed byte/word/signed word) 0 } + (word) main::w2#0 ← (word~) main::$1 + (byte*) main::sc#0 ← ((byte*)) (word) main::w2#0 + *((byte*) main::sc#0) ← *((byte[]) main::bs#0 + (byte/signed byte/word/signed word) 1) + (byte*) main::pos#0 ← ((byte*)) (word/signed word) 1281 + (byte*) main::bgcol#0 ← ((byte*)) (word) 53281 + (boolean~) main::$2 ← *((byte*) main::pos#0) == (byte) 'm' + (boolean~) main::$3 ← ! (boolean~) main::$2 + if((boolean~) main::$3) goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + (byte*) main::bgcol#1 ← phi( main/(byte*) main::bgcol#0 ) + *((byte*) main::bgcol#1) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + (byte*) main::bgcol#2 ← phi( main/(byte*) main::bgcol#0 ) + *((byte*) main::bgcol#2) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Inversing boolean not (boolean~) main::$3 ← *((byte*) main::pos#0) != (byte) 'm' from (boolean~) main::$2 ← *((byte*) main::pos#0) == (byte) 'm' +Succesful SSA optimization Pass2UnaryNotSimplification +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte[]) main::bs#0 ← { (byte) 'c', (byte) 'm' } + (byte) main::b#0 ← (byte/signed byte/word/signed word) 4 + (word) main::w#0 ← { (byte) main::b#0, (byte/signed byte/word/signed word) 0 } + (word~) main::$0 ← { (byte/signed byte/word/signed word) 1, (byte/signed byte/word/signed word) 1 } + (word) main::w#0 + (word~) main::$1 ← (word~) main::$0 + { (byte/signed byte/word/signed word) 0, (byte/signed byte/word/signed word) 0 } + (word) main::w2#0 ← (word~) main::$1 + (byte*) main::sc#0 ← ((byte*)) (word) main::w2#0 + *((byte*) main::sc#0) ← *((byte[]) main::bs#0 + (byte/signed byte/word/signed word) 1) + (byte*) main::pos#0 ← ((byte*)) (word/signed word) 1281 + (byte*) main::bgcol#0 ← ((byte*)) (word) 53281 + (boolean~) main::$3 ← *((byte*) main::pos#0) != (byte) 'm' + if((boolean~) main::$3) goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + (byte*) main::bgcol#1 ← phi( main/(byte*) main::bgcol#0 ) + *((byte*) main::bgcol#1) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + (byte*) main::bgcol#2 ← phi( main/(byte*) main::bgcol#0 ) + *((byte*) main::bgcol#2) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Alias (word) main::w2#0 = (word~) main::$1 +Alias (byte*) main::bgcol#0 = (byte*) main::bgcol#1 (byte*) main::bgcol#2 +Succesful SSA optimization Pass2AliasElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte[]) main::bs#0 ← { (byte) 'c', (byte) 'm' } + (byte) main::b#0 ← (byte/signed byte/word/signed word) 4 + (word) main::w#0 ← { (byte) main::b#0, (byte/signed byte/word/signed word) 0 } + (word~) main::$0 ← { (byte/signed byte/word/signed word) 1, (byte/signed byte/word/signed word) 1 } + (word) main::w#0 + (word) main::w2#0 ← (word~) main::$0 + { (byte/signed byte/word/signed word) 0, (byte/signed byte/word/signed word) 0 } + (byte*) main::sc#0 ← ((byte*)) (word) main::w2#0 + *((byte*) main::sc#0) ← *((byte[]) main::bs#0 + (byte/signed byte/word/signed word) 1) + (byte*) main::pos#0 ← ((byte*)) (word/signed word) 1281 + (byte*) main::bgcol#0 ← ((byte*)) (word) 53281 + (boolean~) main::$3 ← *((byte*) main::pos#0) != (byte) 'm' + if((boolean~) main::$3) goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + *((byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + *((byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Simple Condition (boolean~) main::$3 if(*((byte*) main::pos#0)!=(byte) 'm') goto main::@1 +Succesful SSA optimization Pass2ConditionalJumpSimplification +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte[]) main::bs#0 ← { (byte) 'c', (byte) 'm' } + (byte) main::b#0 ← (byte/signed byte/word/signed word) 4 + (word) main::w#0 ← { (byte) main::b#0, (byte/signed byte/word/signed word) 0 } + (word~) main::$0 ← { (byte/signed byte/word/signed word) 1, (byte/signed byte/word/signed word) 1 } + (word) main::w#0 + (word) main::w2#0 ← (word~) main::$0 + { (byte/signed byte/word/signed word) 0, (byte/signed byte/word/signed word) 0 } + (byte*) main::sc#0 ← ((byte*)) (word) main::w2#0 + *((byte*) main::sc#0) ← *((byte[]) main::bs#0 + (byte/signed byte/word/signed word) 1) + (byte*) main::pos#0 ← ((byte*)) (word/signed word) 1281 + (byte*) main::bgcol#0 ← ((byte*)) (word) 53281 + if(*((byte*) main::pos#0)!=(byte) 'm') goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + *((byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + *((byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Constant (const byte[]) main::bs#0 = { 'c', 'm' } +Constant (const byte) main::b#0 = 4 +Constant (const byte*) main::pos#0 = ((byte*))1281 +Constant (const byte*) main::bgcol#0 = ((byte*))53281 +Succesful SSA optimization Pass2ConstantIdentification +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (word) main::w#0 ← { (const byte) main::b#0, (byte/signed byte/word/signed word) 0 } + (word~) main::$0 ← { (byte/signed byte/word/signed word) 1, (byte/signed byte/word/signed word) 1 } + (word) main::w#0 + (word) main::w2#0 ← (word~) main::$0 + { (byte/signed byte/word/signed word) 0, (byte/signed byte/word/signed word) 0 } + (byte*) main::sc#0 ← ((byte*)) (word) main::w2#0 + *((byte*) main::sc#0) ← *((const byte[]) main::bs#0 + (byte/signed byte/word/signed word) 1) + if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Consolidated array index constant in *(main::bs#0+1) +Succesful SSA optimization Pass2ConstantAdditionElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (word) main::w#0 ← { (const byte) main::b#0, (byte/signed byte/word/signed word) 0 } + (word~) main::$0 ← { (byte/signed byte/word/signed word) 1, (byte/signed byte/word/signed word) 1 } + (word) main::w#0 + (word) main::w2#0 ← (word~) main::$0 + { (byte/signed byte/word/signed word) 0, (byte/signed byte/word/signed word) 0 } + (byte*) main::sc#0 ← ((byte*)) (word) main::w2#0 + *((byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) + if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Fixing word constructor with main::$4 ← main::b#0 w= 0 +Fixing word constructor with main::$5 ← 1 w= 1 +Fixing word constructor with main::$6 ← 0 w= 0 +Succesful SSA optimization Pass2FixWordConstructors +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (word~) main::$4 ← (const byte) main::b#0 w= (byte/signed byte/word/signed word) 0 + (word) main::w#0 ← (word~) main::$4 + (word~) main::$5 ← (byte/signed byte/word/signed word) 1 w= (byte/signed byte/word/signed word) 1 + (word~) main::$0 ← (word~) main::$5 + (word) main::w#0 + (word~) main::$6 ← (byte/signed byte/word/signed word) 0 w= (byte/signed byte/word/signed word) 0 + (word) main::w2#0 ← (word~) main::$0 + (word~) main::$6 + (byte*) main::sc#0 ← ((byte*)) (word) main::w2#0 + *((byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) + if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Alias (word) main::w#0 = (word~) main::$4 +Succesful SSA optimization Pass2AliasElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (word) main::w#0 ← (const byte) main::b#0 w= (byte/signed byte/word/signed word) 0 + (word~) main::$5 ← (byte/signed byte/word/signed word) 1 w= (byte/signed byte/word/signed word) 1 + (word~) main::$0 ← (word~) main::$5 + (word) main::w#0 + (word~) main::$6 ← (byte/signed byte/word/signed word) 0 w= (byte/signed byte/word/signed word) 0 + (word) main::w2#0 ← (word~) main::$0 + (word~) main::$6 + (byte*) main::sc#0 ← ((byte*)) (word) main::w2#0 + *((byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) + if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Constant (const word) main::w#0 = main::b#0*256+0 +Constant (const word) main::$5 = 1*256+1 +Constant (const word) main::$6 = 0*256+0 +Succesful SSA optimization Pass2ConstantIdentification +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (word~) main::$0 ← (const word) main::$5 + (const word) main::w#0 + (word) main::w2#0 ← (word~) main::$0 + (const word) main::$6 + (byte*) main::sc#0 ← ((byte*)) (word) main::w2#0 + *((byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) + if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Constant (const word) main::$0 = main::$5+main::w#0 +Succesful SSA optimization Pass2ConstantIdentification +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (word) main::w2#0 ← (const word) main::$0 + (const word) main::$6 + (byte*) main::sc#0 ← ((byte*)) (word) main::w2#0 + *((byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) + if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Constant (const word) main::w2#0 = main::$0+main::$6 +Succesful SSA optimization Pass2ConstantIdentification +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte*) main::sc#0 ← ((byte*)) (const word) main::w2#0 + *((byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) + if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Constant (const byte*) main::sc#0 = ((byte*))main::w2#0 +Succesful SSA optimization Pass2ConstantIdentification +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + *((const byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) + if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Constant inlined main::$5 = (byte/signed byte/word/signed word) 1*(word/signed word) 256+(byte/signed byte/word/signed word) 1 +Constant inlined main::$6 = (byte/signed byte/word/signed word) 0*(word/signed word) 256+(byte/signed byte/word/signed word) 0 +Constant inlined main::$0 = (byte/signed byte/word/signed word) 1*(word/signed word) 256+(byte/signed byte/word/signed word) 1+(const word) main::w#0 +Succesful SSA optimization Pass2ConstantInlining +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + *((const byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) + if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 + to:main::@3 +main::@1: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 + to:main::@return +main::@3: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@1 +(label) main::@3 +(label) main::@return +(byte) main::b +(const byte) main::b#0 = (byte/signed byte/word/signed word) 4 +(byte*) main::bgcol +(const byte*) main::bgcol#0 = ((byte*))(word) 53281 +(byte[]) main::bs +(const byte[]) main::bs#0 = { (byte) 'c', (byte) 'm' } +(byte*) main::pos +(const byte*) main::pos#0 = ((byte*))(word/signed word) 1281 +(byte*) main::sc +(const byte*) main::sc#0 = ((byte*))(const word) main::w2#0 +(word) main::w +(const word) main::w#0 = (const byte) main::b#0*(word/signed word) 256+(byte/signed byte/word/signed word) 0 +(word) main::w2 +(const word) main::w2#0 = (byte/signed byte/word/signed word) 1*(word/signed word) 256+(byte/signed byte/word/signed word) 1+(const word) main::w#0+(byte/signed byte/word/signed word) 0*(word/signed word) 256+(byte/signed byte/word/signed word) 0 + +Block Sequence Planned @begin @1 @end main main::@3 main::@return main::@1 +Block Sequence Planned @begin @1 @end main main::@3 main::@return main::@1 +CONTROL FLOW GRAPH - PHI LIFTED +@begin: scope:[] from + to:@1 +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 +main: scope:[main] from @1 + *((const byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) + if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 + to:main::@3 +main::@3: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + return + to:@return +main::@1: scope:[main] from main + *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 + to:main::@return + +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +CALL GRAPH +Calls in [] to main:2 + +Propagating live ranges... +CONTROL FLOW GRAPH - LIVE RANGES FOUND +@begin: scope:[] from + [0] phi() [ ] + to:@1 +@1: scope:[] from @begin + [1] phi() [ ] + [2] call main param-assignment [ ] + to:@end +@end: scope:[] from @1 + [3] phi() [ ] +main: scope:[main] from @1 + [4] *((const byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) [ ] + [5] if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 [ ] + to:main::@3 +main::@3: scope:[main] from main + [6] *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 [ ] + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + [7] return [ ] + to:@return +main::@1: scope:[main] from main + [8] *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 [ ] + to:main::@return + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Block Sequence Planned @begin @1 @end main main::@3 main::@return main::@1 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Propagating live ranges... +CONTROL FLOW GRAPH - BEFORE EFFECTIVE LIVE RANGES +@begin: scope:[] from + [0] phi() [ ] + to:@1 +@1: scope:[] from @begin + [1] phi() [ ] + [2] call main param-assignment [ ] + to:@end +@end: scope:[] from @1 + [3] phi() [ ] +main: scope:[main] from @1 + [4] *((const byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) [ ] + [5] if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 [ ] + to:main::@3 +main::@3: scope:[main] from main + [6] *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 [ ] + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + [7] return [ ] + to:@return +main::@1: scope:[main] from main + [8] *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 [ ] + to:main::@return + +CONTROL FLOW GRAPH - PHI MEM COALESCED +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@1 +@1: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @1 + [3] phi() [ ] ( ) +main: scope:[main] from @1 + [4] *((const byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) [ ] ( main:2 [ ] ) + [5] if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 [ ] ( main:2 [ ] ) + to:main::@3 +main::@3: scope:[main] from main + [6] *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 [ ] ( main:2 [ ] ) + to:main::@return +main::@return: scope:[main] from main::@1 main::@3 + [7] return [ ] ( main:2 [ ] ) + to:@return +main::@1: scope:[main] from main + [8] *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 [ ] ( main:2 [ ] ) + to:main::@return + +DOMINATORS +@begin dominated by @begin +@1 dominated by @1 @begin +@end dominated by @1 @begin @end +main dominated by @1 @begin main +main::@3 dominated by @1 @begin main main::@3 +main::@return dominated by main::@return @1 @begin main +main::@1 dominated by @1 @begin main::@1 main + +NATURAL LOOPS + +Found 0 loops in scope [] +Found 0 loops in scope [main] +NATURAL LOOPS WITH DEPTH + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte) main::b +(byte*) main::bgcol +(byte[]) main::bs +(byte*) main::pos +(byte*) main::sc +(word) main::w +(word) main::w2 + +Initial phi equivalence classes +Complete equivalence classes +INITIAL ASM +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG4 @1 +b1: +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG7 @end +bend: +//SEG8 main +main: { + .const b = 4 + .const pos = $501 + .const bgcol = $d021 + .const w = b*$100+0 + .const w2 = 1*$100+1+w+0*$100+0 + .const sc = w2 + //SEG9 [4] *((const byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) [ ] ( main:2 [ ] ) -- _deref_pbuc1=_deref_pbuc2 + lda bs+1 + sta sc + //SEG10 [5] if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 [ ] ( main:2 [ ] ) -- _deref_pbuc1_neq_vbuc2_then_la1 + lda pos + cmp #'m' + bne b1 + jmp b3 + //SEG11 main::@3 + b3: + //SEG12 [6] *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #5 + sta bgcol + jmp breturn + //SEG13 main::@return + breturn: + //SEG14 [7] return [ ] ( main:2 [ ] ) + rts + //SEG15 main::@1 + b1: + //SEG16 [8] *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #2 + sta bgcol + jmp breturn + bs: .byte 'c', 'm' +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] *((const byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [5] if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [6] *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [8] *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 [ ] ( main:2 [ ] ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [] + +Uplifting [main] best 55 combination +Uplifting [] best 55 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG4 @1 +b1: +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG7 @end +bend: +//SEG8 main +main: { + .const b = 4 + .const pos = $501 + .const bgcol = $d021 + .const w = b*$100+0 + .const w2 = 1*$100+1+w+0*$100+0 + .const sc = w2 + //SEG9 [4] *((const byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) [ ] ( main:2 [ ] ) -- _deref_pbuc1=_deref_pbuc2 + lda bs+1 + sta sc + //SEG10 [5] if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 [ ] ( main:2 [ ] ) -- _deref_pbuc1_neq_vbuc2_then_la1 + lda pos + cmp #'m' + bne b1 + jmp b3 + //SEG11 main::@3 + b3: + //SEG12 [6] *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #5 + sta bgcol + jmp breturn + //SEG13 main::@return + breturn: + //SEG14 [7] return [ ] ( main:2 [ ] ) + rts + //SEG15 main::@1 + b1: + //SEG16 [8] *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #2 + sta bgcol + jmp breturn + bs: .byte 'c', 'm' +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp b3 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +Removing instruction b1_from_bbegin: +Removing instruction bend_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction b1: +Removing instruction bend: +Removing instruction b3: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@1 +(label) main::@3 +(label) main::@return +(byte) main::b +(const byte) main::b#0 b = (byte/signed byte/word/signed word) 4 +(byte*) main::bgcol +(const byte*) main::bgcol#0 bgcol = ((byte*))(word) 53281 +(byte[]) main::bs +(const byte[]) main::bs#0 bs = { (byte) 'c', (byte) 'm' } +(byte*) main::pos +(const byte*) main::pos#0 pos = ((byte*))(word/signed word) 1281 +(byte*) main::sc +(const byte*) main::sc#0 sc = ((byte*))(const word) main::w2#0 +(word) main::w +(const word) main::w#0 w = (const byte) main::b#0*(word/signed word) 256+(byte/signed byte/word/signed word) 0 +(word) main::w2 +(const word) main::w2#0 w2 = (byte/signed byte/word/signed word) 1*(word/signed word) 256+(byte/signed byte/word/signed word) 1+(const word) main::w#0+(byte/signed byte/word/signed word) 0*(word/signed word) 256+(byte/signed byte/word/signed word) 0 + + +FINAL CODE +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 @1 +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +//SEG7 @end +//SEG8 main +main: { + .const b = 4 + .const pos = $501 + .const bgcol = $d021 + .const w = b*$100+0 + .const w2 = 1*$100+1+w+0*$100+0 + .const sc = w2 + //SEG9 [4] *((const byte*) main::sc#0) ← *((const byte[]) main::bs#0+(byte/signed byte/word/signed word) 1) [ ] ( main:2 [ ] ) -- _deref_pbuc1=_deref_pbuc2 + lda bs+1 + sta sc + //SEG10 [5] if(*((const byte*) main::pos#0)!=(byte) 'm') goto main::@1 [ ] ( main:2 [ ] ) -- _deref_pbuc1_neq_vbuc2_then_la1 + lda pos + cmp #'m' + bne b1 + //SEG11 main::@3 + //SEG12 [6] *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 5 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #5 + sta bgcol + //SEG13 main::@return + breturn: + //SEG14 [7] return [ ] ( main:2 [ ] ) + rts + //SEG15 main::@1 + b1: + //SEG16 [8] *((const byte*) main::bgcol#0) ← (byte/signed byte/word/signed word) 2 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #2 + sta bgcol + jmp breturn + bs: .byte 'c', 'm' +} + diff --git a/src/main/java/dk/camelot64/kickc/test/ref/true-inline-words.sym b/src/main/java/dk/camelot64/kickc/test/ref/true-inline-words.sym new file mode 100644 index 000000000..43613aa4d --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/true-inline-words.sym @@ -0,0 +1,22 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@1 +(label) main::@3 +(label) main::@return +(byte) main::b +(const byte) main::b#0 b = (byte/signed byte/word/signed word) 4 +(byte*) main::bgcol +(const byte*) main::bgcol#0 bgcol = ((byte*))(word) 53281 +(byte[]) main::bs +(const byte[]) main::bs#0 bs = { (byte) 'c', (byte) 'm' } +(byte*) main::pos +(const byte*) main::pos#0 pos = ((byte*))(word/signed word) 1281 +(byte*) main::sc +(const byte*) main::sc#0 sc = ((byte*))(const word) main::w2#0 +(word) main::w +(const word) main::w#0 w = (const byte) main::b#0*(word/signed word) 256+(byte/signed byte/word/signed word) 0 +(word) main::w2 +(const word) main::w2#0 w2 = (byte/signed byte/word/signed word) 1*(word/signed word) 256+(byte/signed byte/word/signed word) 1+(const word) main::w#0+(byte/signed byte/word/signed word) 0*(word/signed word) 256+(byte/signed byte/word/signed word) 0 + diff --git a/src/main/java/dk/camelot64/kickc/test/true-inline-words.kc b/src/main/java/dk/camelot64/kickc/test/true-inline-words.kc index 6720c4267..b9d96a0b6 100644 --- a/src/main/java/dk/camelot64/kickc/test/true-inline-words.kc +++ b/src/main/java/dk/camelot64/kickc/test/true-inline-words.kc @@ -1,10 +1,19 @@ void main() { - byte[] bs = { 'c', 'm' }; // constant byte array - byte b = 4; // constant byte - word w = { b, 0 }; // constant inline word - word w2 = { 1, 1 } + w; // constant inline word inside expression - byte* sc = w2; // implicit cast to (byte*) - *sc = bs[0]; + byte[] bs = { 'c', 'm' }; // constant byte array + byte b = 4; // constant byte + word w = { b, 0 }; // constant inline word + word w2 = { 1, 1 } + w + { 0, 0 }; // constant inline words inside expression + byte* sc = w2; // implicit cast to (byte*) + *sc = bs[1]; // In the end $501 is set to 'c' + + // Test the result + byte* pos = $501; + byte* bgcol = $d021; + if(*pos=='m') { + *bgcol = 5; + } else { + *bgcol = 2; + } }