From e314794f0bdfa27e8ddcd231ecd74e9556567386 Mon Sep 17 00:00:00 2001 From: Jesper Gravgaard Date: Mon, 25 Dec 2017 20:19:53 +0100 Subject: [PATCH] Implemented true recursive variable replacer that can replace into pointers/value lists. Also using this when building SSA. Prepared syntax ant type inference for building a word from 2 bytes using word w = { b1, b2 }; --- .../kickc/model/ConstantInteger.java | 2 +- .../kickc/model/PointerDereference.java | 3 + .../kickc/model/SymbolTypeArray.java | 7 +- .../kickc/model/SymbolTypeInference.java | 99 +- .../kickc/model/SymbolTypeInline.java | 37 +- .../model/{ValueArray.java => ValueList.java} | 9 +- ...ss1GenerateSingleStaticAssignmentForm.java | 88 +- .../passes/Pass2ConstantIdentification.java | 8 +- .../kickc/passes/Pass2SsaOptimization.java | 2 +- .../passes/Pass3VariableReferenceInfos.java | 4 +- .../passes/StatementSequenceGenerator.java | 2 +- .../kickc/passes/VariableReplacer.java | 451 ++-- .../dk/camelot64/kickc/test/TestPrograms.java | 8 + .../dk/camelot64/kickc/test/inline-word.kc | 12 + .../camelot64/kickc/test/inmem-const-array.kc | 18 + .../kickc/test/ref/inmem-const-array.asm | 28 + .../kickc/test/ref/inmem-const-array.cfg | 32 + .../kickc/test/ref/inmem-const-array.log | 1828 +++++++++++++++++ .../kickc/test/ref/inmem-const-array.sym | 32 + 19 files changed, 2401 insertions(+), 269 deletions(-) rename src/main/java/dk/camelot64/kickc/model/{ValueArray.java => ValueList.java} (60%) create mode 100644 src/main/java/dk/camelot64/kickc/test/inline-word.kc create mode 100644 src/main/java/dk/camelot64/kickc/test/inmem-const-array.kc create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.asm create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.cfg create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.log create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.sym diff --git a/src/main/java/dk/camelot64/kickc/model/ConstantInteger.java b/src/main/java/dk/camelot64/kickc/model/ConstantInteger.java index 53e0223ea..551285c46 100644 --- a/src/main/java/dk/camelot64/kickc/model/ConstantInteger.java +++ b/src/main/java/dk/camelot64/kickc/model/ConstantInteger.java @@ -27,7 +27,7 @@ public class ConstantInteger implements ConstantValue { } public SymbolType getType() { - ArrayList potentialTypes = new ArrayList<>(); + ArrayList potentialTypes = new ArrayList<>(); Integer number = getNumber(); for (SymbolTypeInteger typeInteger : SymbolType.getIntegerTypes()) { if(number>=typeInteger.getMinValue() && number<= typeInteger.getMaxValue()) { diff --git a/src/main/java/dk/camelot64/kickc/model/PointerDereference.java b/src/main/java/dk/camelot64/kickc/model/PointerDereference.java index 286e4af5c..259cffbd4 100644 --- a/src/main/java/dk/camelot64/kickc/model/PointerDereference.java +++ b/src/main/java/dk/camelot64/kickc/model/PointerDereference.java @@ -5,4 +5,7 @@ public interface PointerDereference extends LValue { RValue getPointer(); + void setPointer(RValue pointer); + + } diff --git a/src/main/java/dk/camelot64/kickc/model/SymbolTypeArray.java b/src/main/java/dk/camelot64/kickc/model/SymbolTypeArray.java index c1074eb8a..403e8284f 100644 --- a/src/main/java/dk/camelot64/kickc/model/SymbolTypeArray.java +++ b/src/main/java/dk/camelot64/kickc/model/SymbolTypeArray.java @@ -32,7 +32,12 @@ public class SymbolTypeArray extends SymbolTypePointer { @Override public String getTypeName() { - return getElementType().getTypeName()+"["+(size==null?"":size)+"]"; + SymbolType elementType = getElementType(); + if(elementType instanceof SymbolTypeInline) { + return "("+elementType.getTypeName()+")"+"["+(size==null?"":size)+"]"; + }else { + return elementType.getTypeName()+"["+(size==null?"":size)+"]"; + } } @Override diff --git a/src/main/java/dk/camelot64/kickc/model/SymbolTypeInference.java b/src/main/java/dk/camelot64/kickc/model/SymbolTypeInference.java index 829a3d849..bd86be383 100644 --- a/src/main/java/dk/camelot64/kickc/model/SymbolTypeInference.java +++ b/src/main/java/dk/camelot64/kickc/model/SymbolTypeInference.java @@ -1,5 +1,6 @@ package dk.camelot64.kickc.model; +import java.util.ArrayList; import java.util.Collection; /** @@ -40,7 +41,11 @@ public class SymbolTypeInference { public static SymbolType inferType(ProgramScope programScope, RValue rValue1, Operator operator, RValue rValue2) { if (rValue1 instanceof ConstantValue && rValue2 instanceof ConstantValue) { - ConstantValue value = ConstantValueCalculator.calcValue(programScope, (ConstantValue) rValue1, operator, (ConstantValue) rValue2); + ConstantValue value = ConstantValueCalculator.calcValue( + programScope, + (ConstantValue) rValue1, + operator, + (ConstantValue) rValue2); if (value != null) { return value.getType(programScope); } @@ -66,7 +71,7 @@ public class SymbolTypeInference { return SymbolType.BYTE; } } else if (Operator.HIBYTE.equals(operator)) { - if (subType instanceof SymbolTypePointer || SymbolType.WORD.equals(subType) || SymbolType.SWORD.equals(subType) ) { + if (subType instanceof SymbolTypePointer || SymbolType.WORD.equals(subType) || SymbolType.SWORD.equals(subType)) { return SymbolType.BYTE; } } else if (Operator.CAST_BYTE.equals(operator)) { @@ -89,9 +94,9 @@ public class SymbolTypeInference { return inferPlus(type1, type2); } else if (Operator.MINUS.equals(operator)) { return inferMinus(type1, type2); - } else if(Operator.SET_HIBYTE.equals(operator)) { + } else if (Operator.SET_HIBYTE.equals(operator)) { return type1; - } else if(Operator.SET_LOWBYTE.equals(operator)) { + } else if (Operator.SET_LOWBYTE.equals(operator)) { return type1; } @@ -209,14 +214,15 @@ public class SymbolTypeInference { private static boolean isInteger(SymbolType type) { if (SymbolType.BYTE.equals(type)) { return true; - } else if(SymbolType.WORD.equals(type)) { + } else if (SymbolType.WORD.equals(type)) { return true; - } else if(SymbolType.SBYTE.equals(type)) { + } else if (SymbolType.SBYTE.equals(type)) { return true; - } else if(SymbolType.SWORD.equals(type)) { - return true; - } else if(type instanceof SymbolTypeInline) { + } else if (SymbolType.SWORD.equals(type)) { return true; + } else if (type instanceof SymbolTypeInline) { + SymbolTypeInline typeInline = (SymbolTypeInline) type; + return typeInline.isByte() || typeInline.isSByte() || typeInline.isWord() || typeInline.isSWord(); } else { return false; } @@ -248,8 +254,8 @@ public class SymbolTypeInference { } else if (rValue instanceof ConstantBinary) { ConstantBinary constBin = (ConstantBinary) rValue; return inferType(symbols, constBin.getLeft(), constBin.getOperator(), constBin.getRight()); - } else if (rValue instanceof ValueArray) { - type = inferTypeArray(symbols, (ValueArray)rValue); + } else if (rValue instanceof ValueList) { + type = inferTypeList(symbols, (ValueList) rValue); } else if (rValue instanceof PointerDereference) { SymbolType pointerType = inferType(symbols, ((PointerDereference) rValue).getPointer()); if (pointerType instanceof SymbolTypePointer) { @@ -264,16 +270,16 @@ public class SymbolTypeInference { return type; } - private static SymbolType inferTypeArray(ProgramScope symbols, ValueArray array) { + private static SymbolType inferTypeList(ProgramScope symbols, ValueList list) { SymbolType elmType = null; - for (RValue elm : array.getList()) { + for (RValue elm : list.getList()) { SymbolType type = inferType(symbols, elm); - if(elmType==null) { + if (elmType == null) { elmType = type; } else { // element type already defined - check for a match - if(!typeMatch(elmType, type)) { - if(typeMatch(type, elmType)) { + if (!typeMatch(elmType, type)) { + if (typeMatch(type, elmType)) { elmType = type; } else { throw new RuntimeException("Array element has type mismatch " + elm.toString() + " not matching type " + elmType.getTypeName()); @@ -281,10 +287,18 @@ public class SymbolTypeInference { } } } - if(elmType!=null) { - return new SymbolTypeArray(elmType); + if (elmType != null) { + if ((list.getList().size() == 2 && SymbolType.isByte(elmType) || SymbolType.isSByte(elmType))) { + // Potentially a word constructor - return a composite type + ArrayList types = new ArrayList<>(); + types.add(new SymbolTypeArray(elmType)); + types.add(SymbolType.WORD); + return new SymbolTypeInline(types); + } else { + return new SymbolTypeArray(elmType); + } } else { - throw new RuntimeException("Cannot infer array element type "+array.toString()); + throw new RuntimeException("Cannot infer list element type " + list.toString()); } } @@ -314,24 +328,49 @@ public class SymbolTypeInference { // Types match directly return true; } else if (rValueType instanceof SymbolTypeInline) { - if(lValueType instanceof SymbolTypeInline) { + Collection rTypes = ((SymbolTypeInline) rValueType).getTypes(); + if (lValueType instanceof SymbolTypeInline) { // Both are inline types - RValue type must be superset of LValue - Collection lValueTypes = ((SymbolTypeInline) lValueType).getTypes(); - Collection rValueTypes = ((SymbolTypeInline) rValueType).getTypes(); - if(rValueTypes.containsAll(lValueTypes)) { - return true; - } - } else if (((SymbolTypeInline) rValueType).getTypes().contains(lValueType)) { - // Types match because the right side is a constant that matches the left side - return true; + Collection lTypes = ((SymbolTypeInline) lValueType).getTypes(); + return typeContainsMatchAll(lTypes, rTypes); + } else { + // Types match because the right side matches the left side + return typeContainsMatch(lValueType, rTypes); } } else if (lValueType instanceof SymbolTypePointer && rValueType instanceof SymbolTypePointer) { - return typeMatch(((SymbolTypePointer) lValueType).getElementType(), ((SymbolTypePointer) rValueType).getElementType()); + return typeMatch( + ((SymbolTypePointer) lValueType).getElementType(), + ((SymbolTypePointer) rValueType).getElementType()); } else if (SymbolType.STRING.equals(rValueType)) { - if(lValueType instanceof SymbolTypePointer && SymbolType.isByte(((SymbolTypePointer) lValueType).getElementType())) { + if (lValueType instanceof SymbolTypePointer && SymbolType.isByte(((SymbolTypePointer) lValueType).getElementType())) { return true; } } return false; } + + private static boolean typeContainsMatchAll(Collection lTypes, Collection rTypes) { + for (SymbolType lType : lTypes) { + if (!typeContainsMatch(lType, rTypes)) { + return false; + } + } + return true; + } + + /** + * Determine is a list of potential inferred types contains a match for another type + * @param lValueType The type (rValue) we want to find a match for in the list + * @param rTypes The list of inferred potential types + * @return true if the list has a match + */ + private static boolean typeContainsMatch(SymbolType lValueType, Collection rTypes) { + for (SymbolType rType : rTypes) { + if (typeMatch(lValueType, rType)) { + return true; + } + } + return false; + } + } diff --git a/src/main/java/dk/camelot64/kickc/model/SymbolTypeInline.java b/src/main/java/dk/camelot64/kickc/model/SymbolTypeInline.java index 27ac8bb6d..ab8ac62d7 100644 --- a/src/main/java/dk/camelot64/kickc/model/SymbolTypeInline.java +++ b/src/main/java/dk/camelot64/kickc/model/SymbolTypeInline.java @@ -3,21 +3,21 @@ package dk.camelot64.kickc.model; import java.util.Collection; /** - * Symbol Type of an inline numeric expression. Inline expressions can match multiple types depending on the actual value, - * eg. the value 27 matches both byte and signed byte (which can in turn be promoted to word/signed word) , while the value -252 only matches signed word. + * Symbol Type of an inline expression. Inline expressions can match multiple types depending on the actual value, + * eg. the value 27 matches both byte and signed byte (which can in turn be promoted to word/signed word), while the value -252 only matches signed word. */ public class SymbolTypeInline implements SymbolType { /** * All potential types for the inline constant. */ - private Collection types; + private Collection types; - public SymbolTypeInline(Collection types) { + public SymbolTypeInline(Collection types) { this.types = types; } - public Collection getTypes() { + public Collection getTypes() { return types; } @@ -25,10 +25,10 @@ public class SymbolTypeInline implements SymbolType { public String getTypeName() { StringBuilder name = new StringBuilder(); boolean first = true; - for (SymbolTypeInteger type : types) { - if(first) { + for (SymbolType type : types) { + if (first) { first = false; - } else { + } else { name.append("/"); } name.append(type); @@ -38,8 +38,12 @@ public class SymbolTypeInline implements SymbolType { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } SymbolTypeInline that = (SymbolTypeInline) o; return types != null ? types.equals(that.types) : that.types == null; } @@ -62,15 +66,28 @@ public class SymbolTypeInline implements SymbolType { return types.contains(BYTE); } + /** + * Is signed byte one of the potential types + * @return true if signed byte is a potential type + */ public boolean isSByte() { return types.contains(SBYTE); } + /** + * Is unsigned word one of the potential types + * @return true if unsigned word is a potential type + */ public boolean isWord() { return types.contains(WORD); } + /** + * Is signed word one of the potential types + * @return true if signed word is a potential type + */ public boolean isSWord() { return types.contains(SWORD); } + } diff --git a/src/main/java/dk/camelot64/kickc/model/ValueArray.java b/src/main/java/dk/camelot64/kickc/model/ValueList.java similarity index 60% rename from src/main/java/dk/camelot64/kickc/model/ValueArray.java rename to src/main/java/dk/camelot64/kickc/model/ValueList.java index e9c4caf1e..5e54a3bff 100644 --- a/src/main/java/dk/camelot64/kickc/model/ValueArray.java +++ b/src/main/java/dk/camelot64/kickc/model/ValueList.java @@ -2,12 +2,15 @@ package dk.camelot64.kickc.model; import java.util.List; -/** An array of sub-values. Only used for variable initializers. Compilation execution will typically resolve it into a constant array before ASM-generation. */ -public class ValueArray implements RValue { +/** A list of sub-values. Used for array variable initializers and word from byte constructors + * (in the future also usable for dword from byte, dword from double etc.). + * Compilation execution will resolve into a constant array, + * constant word or word constructor operator before ASM-generation. */ +public class ValueList implements RValue { private List list; - public ValueArray(List list) { + public ValueList(List list) { this.list = list; } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1GenerateSingleStaticAssignmentForm.java b/src/main/java/dk/camelot64/kickc/passes/Pass1GenerateSingleStaticAssignmentForm.java index 193fa6f13..4b4835c9a 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass1GenerateSingleStaticAssignmentForm.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass1GenerateSingleStaticAssignmentForm.java @@ -64,6 +64,27 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base { } } + /** + * Version all variable uses in the replacable value + * + * @param replacableValue The value to version variable usages in + * @param blockVersions Newest version of variables in the block. + * @param blockNewPhis New phi functions introduced in the block to create versions of variables. + */ + private void execute( + VariableReplacer.ReplacableValue replacableValue, + Map blockVersions, + Map blockNewPhis) { + RValue value = replacableValue.get(); + VariableVersion version = findOrCreateVersion(value, blockVersions, blockNewPhis); + if (version != null) { + replacableValue.set(version.getRef()); + } + for (VariableReplacer.ReplacableValue subValue : replacableValue.getSubValues()) { + execute(subValue, blockVersions, blockNewPhis); + } + } + /** * Version all uses of non-versioned non-intermediary variables */ @@ -75,49 +96,13 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base { Map blockNewPhis = new LinkedHashMap<>(); for (Statement statement : block.getStatements()) { if (statement instanceof StatementReturn) { - StatementReturn statementReturn = (StatementReturn) statement; - if (statementReturn.getValue() instanceof PointerDereferenceSimple) { - PointerDereferenceSimple deref = (PointerDereferenceSimple) ((StatementReturn) statement).getValue(); - RValue pointer = deref.getPointer(); - VariableVersion version = findOrCreateVersion(pointer, blockVersions, blockNewPhis); - if (version != null) { - deref.setPointer(version.getRef()); - } - } else { - VariableVersion version = findOrCreateVersion(statementReturn.getValue(), blockVersions, blockNewPhis); - if (version != null) { - statementReturn.setValue(version.getRef()); - } - } - } - if (statement instanceof StatementAssignment) { + execute(new VariableReplacer.ReplacableReturn((StatementReturn) statement), blockVersions, blockNewPhis); + } else if (statement instanceof StatementAssignment) { StatementAssignment assignment = (StatementAssignment) statement; - if (assignment.getrValue1() instanceof PointerDereferenceSimple) { - PointerDereferenceSimple deref = (PointerDereferenceSimple) ((StatementAssignment) statement).getrValue1(); - RValue pointer = deref.getPointer(); - VariableVersion version = findOrCreateVersion(pointer, blockVersions, blockNewPhis); - if (version != null) { - deref.setPointer(version.getRef()); - } - } else { - VariableVersion version = findOrCreateVersion(assignment.getrValue1(), blockVersions, blockNewPhis); - if (version != null) { - assignment.setrValue1(version.getRef()); - } - } - if (assignment.getrValue2() instanceof PointerDereferenceSimple) { - PointerDereferenceSimple deref = (PointerDereferenceSimple) ((StatementAssignment) statement).getrValue2(); - RValue pointer = deref.getPointer(); - VariableVersion version = findOrCreateVersion(pointer, blockVersions, blockNewPhis); - if (version != null) { - deref.setPointer(version.getRef()); - } - } else { - VariableVersion version = findOrCreateVersion(assignment.getrValue2(), blockVersions, blockNewPhis); - if (version != null) { - assignment.setrValue2(version.getRef()); - } - } + execute(new VariableReplacer.ReplacableRValue1(assignment), blockVersions, blockNewPhis); + execute(new VariableReplacer.ReplacableRValue2(assignment), blockVersions, blockNewPhis); + execute(new VariableReplacer.ReplacableLValue(assignment), blockVersions, blockNewPhis); + // Update map of versions encountered in the block LValue lValue = assignment.getlValue(); if (lValue instanceof VariableRef) { @@ -127,25 +112,6 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base { VariableVersion versioned = (VariableVersion) variable; blockVersions.put(versioned.getVersionOf(), versioned); } - } else if (lValue instanceof PointerDereferenceSimple) { - PointerDereferenceSimple deref = (PointerDereferenceSimple) lValue; - RValue pointer = deref.getPointer(); - VariableVersion version = findOrCreateVersion(pointer, blockVersions, blockNewPhis); - if (version != null) { - deref.setPointer(version.getRef()); - } - } else if (lValue instanceof PointerDereferenceIndexed) { - PointerDereferenceIndexed deref = (PointerDereferenceIndexed) lValue; - RValue pointer = deref.getPointer(); - VariableVersion version = findOrCreateVersion(pointer, blockVersions, blockNewPhis); - if (version != null) { - deref.setPointer(version.getRef()); - } - RValue index = deref.getIndex(); - VariableVersion iVersion = findOrCreateVersion(index, blockVersions, blockNewPhis); - if (iVersion != null) { - deref.setIndex(iVersion.getRef()); - } } } } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java index 3957ea525..a9713ae27 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java @@ -80,9 +80,9 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization { if (constant != null) { constants.put(variable, constant); } - } else if (assignment.getrValue2() instanceof ValueArray && assignment.getOperator() == null && assignment.getrValue1() == null) { - ValueArray valueArray = (ValueArray) assignment.getrValue2(); - List values = valueArray.getList(); + } else if (assignment.getrValue2() instanceof ValueList && assignment.getOperator() == null && assignment.getrValue1() == null) { + ValueList valueList = (ValueList) assignment.getrValue2(); + List values = valueList.getList(); boolean allConstant = true; SymbolType elementType = null; List elements = new ArrayList<>(); @@ -94,7 +94,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization { elementType = type; } else { if (!SymbolTypeInference.typeMatch(type, elementType)) { - throw new RuntimeException("Array type mismatch " + elementType + " does not match " + type + " " + valueArray.toString(getProgram())); + throw new RuntimeException("Array type mismatch " + elementType + " does not match " + type + " " + valueList.toString(getProgram())); } } elements.add(constantValue); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2SsaOptimization.java b/src/main/java/dk/camelot64/kickc/passes/Pass2SsaOptimization.java index 72959e2aa..194a173c5 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2SsaOptimization.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2SsaOptimization.java @@ -48,7 +48,7 @@ public abstract class Pass2SsaOptimization { */ public void replaceVariables(final Map aliases) { VariableReplacer replacer = new VariableReplacer(aliases); - replacer.getReplacement(getGraph()); + replacer.execute(getGraph()); } /** diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass3VariableReferenceInfos.java b/src/main/java/dk/camelot64/kickc/passes/Pass3VariableReferenceInfos.java index 6d31373ec..6c3aec5bf 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass3VariableReferenceInfos.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass3VariableReferenceInfos.java @@ -213,9 +213,9 @@ public class Pass3VariableReferenceInfos extends Pass2Base { return used; } else if (rValue instanceof VariableRef) { return Arrays.asList((VariableRef) rValue); - } else if (rValue instanceof ValueArray) { + } else if (rValue instanceof ValueList) { LinkedHashSet used = new LinkedHashSet<>(); - for (RValue value : ((ValueArray) rValue).getList()) { + for (RValue value : ((ValueList) rValue).getList()) { used.addAll(getReferenced(value)); } return used; diff --git a/src/main/java/dk/camelot64/kickc/passes/StatementSequenceGenerator.java b/src/main/java/dk/camelot64/kickc/passes/StatementSequenceGenerator.java index 478740536..122970785 100644 --- a/src/main/java/dk/camelot64/kickc/passes/StatementSequenceGenerator.java +++ b/src/main/java/dk/camelot64/kickc/passes/StatementSequenceGenerator.java @@ -455,7 +455,7 @@ public class StatementSequenceGenerator extends KickCBaseVisitor { RValue rValue = (RValue) visit(initializer); initValues.add(rValue); } - return new ValueArray(initValues); + return new ValueList(initValues); } @Override diff --git a/src/main/java/dk/camelot64/kickc/passes/VariableReplacer.java b/src/main/java/dk/camelot64/kickc/passes/VariableReplacer.java index 404729767..406ff34ad 100644 --- a/src/main/java/dk/camelot64/kickc/passes/VariableReplacer.java +++ b/src/main/java/dk/camelot64/kickc/passes/VariableReplacer.java @@ -2,10 +2,7 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.model.*; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; /** * A replacer capable to alias all usages of a variable (or constant var) with a suitable replacement @@ -18,9 +15,55 @@ public class VariableReplacer { this.aliases = aliases; } - public void getReplacement(ControlFlowGraph graph) { - ControlFlowGraphBaseVisitor visitor = new GraphReplacer(); - visitor.visitGraph(graph); + public void execute(ControlFlowGraph graph) { + //new GraphReplacer().visitGraph(graph); + for (ControlFlowBlock block : graph.getAllBlocks()) { + for (Statement statement : block.getStatements()) { + if (statement instanceof StatementAssignment) { + execute(new ReplacableLValue((StatementLValue) statement)); + execute(new ReplacableRValue1((StatementAssignment) statement)); + execute(new ReplacableRValue2((StatementAssignment) statement)); + } else if (statement instanceof StatementCall) { + execute(new ReplacableLValue((StatementLValue) statement)); + StatementCall call = (StatementCall) statement; + if(call.getParameters()!=null) { + int size = call.getParameters().size(); + for (int i = 0; i < size; i++) { + execute(new ReplacableCallParameter(call, i)); + } + } + } else if (statement instanceof StatementConditionalJump) { + execute(new ReplacableCondRValue1((StatementConditionalJump) statement)); + execute(new ReplacableCondRValue2((StatementConditionalJump) statement)); + } else if (statement instanceof StatementReturn) { + execute(new ReplacableReturn((StatementReturn) statement)); + } else if (statement instanceof StatementPhiBlock) { + for (StatementPhiBlock.PhiVariable phiVariable : ((StatementPhiBlock) statement).getPhiVariables()) { + execute(new ReplacablePhiVariable(phiVariable)); + int size = phiVariable.getValues().size(); + for (int i = 0; i < size; i++) { + execute(new ReplacablePhiValue(phiVariable, i)); + } + } + } + } + } + } + + /** + * Execute replacements inside a replacable value - and its sub-values. + * @param replacable The replacable value + */ + void execute(ReplacableValue replacable) { + if(replacable.get()!=null) { + RValue replacement = getReplacement(replacable.get()); + if(replacement!=null) { + replacable.set(replacement); + } + for (ReplacableValue subReplacable : replacable.getSubValues()) { + execute(subReplacable); + } + } } /** @@ -32,14 +75,14 @@ public class VariableReplacer { * @return The alias to use. Null if no alias exists. */ public RValue getReplacement(RValue rValue) { - if(rValue instanceof SymbolRef) { + if (rValue instanceof SymbolRef) { RValue alias = aliases.get(rValue); - if(alias!=null) { - if(alias.equals(rValue)) { + if (alias != null) { + if (alias.equals(rValue)) { return alias; } RValue replacement = getReplacement(alias); - if(replacement!=null) { + if (replacement != null) { return replacement; } else { return alias; @@ -72,166 +115,264 @@ public class VariableReplacer { } /** - * Visitor capable of handling replacements in an entire flow graph. + * Interface representing an RValue that can be replaced. + * The value may have sub-values that can also be replaced. */ - private class GraphReplacer extends ControlFlowGraphBaseVisitor { + public static abstract class ReplacableValue { - @Override - public Void visitAssignment(StatementAssignment assignment) { - LValue lValue = assignment.getlValue(); - if (getReplacement(lValue) != null) { - RValue alias = getReplacement(lValue); - if (alias instanceof LValue) { - assignment.setlValue((LValue) alias); - } else { - throw new RuntimeException("Error replacing LValue variable " + lValue + " with " + alias); - } - } - if (getReplacement(assignment.getrValue1()) != null) { - assignment.setrValue1(getReplacement(assignment.getrValue1())); - } else { - if(assignment.getrValue1() instanceof PointerDereferenceSimple) { - PointerDereferenceSimple deref = (PointerDereferenceSimple) assignment.getrValue1(); - RValue pointer = deref.getPointer(); - if (getReplacement(pointer) != null) { - deref.setPointer(getReplacement(pointer)); - } - } - } - if (getReplacement(assignment.getrValue2()) != null) { - assignment.setrValue2(getReplacement(assignment.getrValue2())); - } else { - if(assignment.getrValue2() instanceof PointerDereferenceSimple) { - PointerDereferenceSimple deref = (PointerDereferenceSimple) assignment.getrValue2(); - RValue pointer = deref.getPointer(); - if (getReplacement(pointer) != null) { - deref.setPointer(getReplacement(pointer)); - } - } - } - // Handle pointer dereference in LValue - if (lValue instanceof PointerDereferenceSimple) { - PointerDereferenceSimple deref = (PointerDereferenceSimple) lValue; - RValue pointer = deref.getPointer(); - if (getReplacement(pointer) != null) { - deref.setPointer(getReplacement(pointer)); - } - } else if (lValue instanceof PointerDereferenceIndexed) { - PointerDereferenceIndexed deref = (PointerDereferenceIndexed) lValue; - RValue pointer = deref.getPointer(); - if (getReplacement(pointer) != null) { - deref.setPointer(getReplacement(pointer)); - } - RValue index = deref.getIndex(); - if (getReplacement(index) != null) { - deref.setIndex(getReplacement(index)); - } - } - // Handle pointer dereference in RValue + public abstract RValue get(); - return null; + public abstract void set(RValue value); + + public Collection getSubValues() { + RValue value = get(); + ArrayList subValues = new ArrayList<>(); + if (value instanceof PointerDereferenceIndexed) { + subValues.add(new ReplacablePointer((PointerDereference) value)); + subValues.add(new ReplacablePointerIndex((PointerDereferenceIndexed) value)); + } else if (value instanceof PointerDereferenceSimple) { + subValues.add(new ReplacablePointer((PointerDereference) value)); + } else if (value instanceof ValueList) { + ValueList valueList = (ValueList) value; + int size = valueList.getList().size(); + for (int i = 0; i < size; i++) { + subValues.add(new ReplacableListElement(valueList, i)); + } + } + return subValues; + } + + } + + /** Replacable LValue as part of an assignment statement (or a call). */ + public static class ReplacableLValue extends ReplacableValue { + private final StatementLValue statement; + + public ReplacableLValue(StatementLValue statement) { + this.statement = statement; } @Override - public Void visitConditionalJump(StatementConditionalJump conditionalJump) { - if (getReplacement(conditionalJump.getrValue1()) != null) { - conditionalJump.setrValue1(getReplacement(conditionalJump.getrValue1())); - } else { - if (conditionalJump.getrValue1() instanceof PointerDereferenceSimple) { - PointerDereferenceSimple deref = (PointerDereferenceSimple) conditionalJump.getrValue1(); - RValue pointer = deref.getPointer(); - if (getReplacement(pointer) != null) { - deref.setPointer(getReplacement(pointer)); - } - } - } - if (getReplacement(conditionalJump.getrValue2()) != null) { - conditionalJump.setrValue2(getReplacement(conditionalJump.getrValue2())); - } else { - if (conditionalJump.getrValue2() instanceof PointerDereferenceSimple) { - PointerDereferenceSimple deref = (PointerDereferenceSimple) conditionalJump.getrValue2(); - RValue pointer = deref.getPointer(); - if (getReplacement(pointer) != null) { - deref.setPointer(getReplacement(pointer)); - } - } - } - return null; + public RValue get() { + return statement.getlValue(); } @Override - public Void visitReturn(StatementReturn aReturn) { - if (getReplacement(aReturn.getValue()) != null) { - aReturn.setValue(getReplacement(aReturn.getValue())); - } else { - if (aReturn.getValue() instanceof PointerDereferenceSimple) { - PointerDereferenceSimple deref = (PointerDereferenceSimple) aReturn.getValue(); - RValue pointer = deref.getPointer(); - if (getReplacement(pointer) != null) { - deref.setPointer(getReplacement(pointer)); - } - } - } - return null; + public void set(RValue value) { + statement.setlValue((LValue) value); + } + + } + + /** Replacable pointer inside a pointer dererence value. */ + public static class ReplacablePointer extends ReplacableValue { + private final PointerDereference pointer; + + ReplacablePointer(PointerDereference pointer) { + this.pointer = pointer; } @Override - public Void visitCall(StatementCall call) { - if (call.getParameters() != null) { - List newParams = new ArrayList<>(); - for (RValue parameter : call.getParameters()) { - RValue newParam = parameter; - if (getReplacement(parameter) != null) { - newParam = getReplacement(parameter); - } else { - if (parameter instanceof PointerDereferenceSimple) { - PointerDereferenceSimple deref = (PointerDereferenceSimple) parameter; - RValue pointer = deref.getPointer(); - if (getReplacement(pointer) != null) { - deref.setPointer(getReplacement(pointer)); - } - } - } - newParams.add(newParam); - } - call.setParameters(newParams); - } - return null; + public RValue get() { + return pointer.getPointer(); } @Override - public Void visitPhiBlock(StatementPhiBlock phi) { - for (StatementPhiBlock.PhiVariable phiVariable : phi.getPhiVariables()) { - if (getReplacement(phiVariable.getVariable()) != null) { - RValue alias = getReplacement(phiVariable.getVariable()); - if (alias instanceof LValue) { - phiVariable.setVariable((VariableRef) alias); - } - } - List phirValues = phiVariable.getValues(); - Iterator it = phirValues.iterator(); - while (it.hasNext()) { - StatementPhiBlock.PhiRValue phirValue = it.next(); - if (getReplacement(phirValue.getrValue()) != null) { - RValue alias = getReplacement(phirValue.getrValue()); - if (LValue.VOID.equals(alias)) { - it.remove(); - } else { - phirValue.setrValue(alias); - } - } else { - if(phirValue.getrValue() instanceof PointerDereferenceSimple) { - PointerDereferenceSimple deref = (PointerDereferenceSimple) phirValue.getrValue(); - RValue pointer = deref.getPointer(); - if (getReplacement(pointer) != null) { - deref.setPointer(getReplacement(pointer)); - } - } - } - } - } - return null; + public void set(RValue val) { + pointer.setPointer(val); + } + + } + + public static class ReplacableListElement extends ReplacableValue { + private ValueList list; + private int idx; + + public ReplacableListElement(ValueList list, int idx) { + this.list = list; + this.idx = idx; + } + + @Override + public RValue get() { + return list.getList().get(idx); + } + + @Override + public void set(RValue value) { + list.getList().set(idx, value); + } + + } + + /** Replacable pointer index inside a indexed pointer dererence value. */ + public static class ReplacablePointerIndex extends ReplacableValue { + private final PointerDereferenceIndexed pointer; + + ReplacablePointerIndex(PointerDereferenceIndexed pointer) { + this.pointer = pointer; + } + + @Override + public RValue get() { + return pointer.getIndex(); + } + + @Override + public void set(RValue val) { + pointer.setIndex(val); + } + + } + + public static class ReplacableRValue1 extends ReplacableValue { + private final StatementAssignment statement; + + public ReplacableRValue1(StatementAssignment statement) { + this.statement = statement; + } + + @Override + public RValue get() { + return statement.getrValue1(); + } + + @Override + public void set(RValue value) { + statement.setrValue1(value); } } + public static class ReplacableRValue2 extends ReplacableValue { + private final StatementAssignment statement; + + public ReplacableRValue2(StatementAssignment statement) { + this.statement = statement; + } + + @Override + public RValue get() { + return statement.getrValue2(); + } + + @Override + public void set(RValue value) { + statement.setrValue2(value); + } + } + + public static class ReplacableCallParameter extends ReplacableValue { + private final StatementCall call; + private final int i; + + public ReplacableCallParameter(StatementCall call, int i) { + this.call = call; + this.i = i; + } + + @Override + public RValue get() { + return call.getParameters().get(i); + } + + @Override + public void set(RValue value) { + call.getParameters().set(i, value); + } + } + + public static class ReplacableCondRValue1 extends ReplacableValue { + private final StatementConditionalJump statement; + + public ReplacableCondRValue1(StatementConditionalJump statement) { + this.statement = statement; + } + + @Override + public RValue get() { + return statement.getrValue1(); + } + + @Override + public void set(RValue value) { + statement.setrValue1(value); + } + } + + public static class ReplacableCondRValue2 extends ReplacableValue { + private final StatementConditionalJump statement; + + public ReplacableCondRValue2(StatementConditionalJump statement) { + this.statement = statement; + } + + @Override + public RValue get() { + return statement.getrValue2(); + } + + @Override + public void set(RValue value) { + statement.setrValue2(value); + } + } + + public static class ReplacableReturn extends ReplacableValue { + private final StatementReturn statement; + + public ReplacableReturn(StatementReturn statement) { + this.statement = statement; + } + + @Override + public RValue get() { + return statement.getValue(); + } + + @Override + public void set(RValue value) { + statement.setValue(value); + } + } + + public static class ReplacablePhiValue extends ReplacableValue { + private final StatementPhiBlock.PhiVariable phiVariable; + private final int i; + + public ReplacablePhiValue(StatementPhiBlock.PhiVariable phiVariable, int i) { + this.phiVariable = phiVariable; + this.i = i; + } + + @Override + public RValue get() { + return phiVariable.getValues().get(i).getrValue(); + } + + @Override + public void set(RValue value) { + phiVariable.getValues().get(i).setrValue(value); + } + } + + /** Replacable LValue as part of an assignment statement (or a call). */ + public static class ReplacablePhiVariable extends ReplacableValue { + private final StatementPhiBlock.PhiVariable phiVariable; + + public ReplacablePhiVariable(StatementPhiBlock.PhiVariable phiVariable) { + this.phiVariable = phiVariable; + } + + @Override + public RValue get() { + return phiVariable.getVariable(); + } + + @Override + public void set(RValue value) { + phiVariable.setVariable((VariableRef) value); + } + + } + } diff --git a/src/main/java/dk/camelot64/kickc/test/TestPrograms.java b/src/main/java/dk/camelot64/kickc/test/TestPrograms.java index 3abb4cee7..bd39fb02a 100644 --- a/src/main/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/main/java/dk/camelot64/kickc/test/TestPrograms.java @@ -22,6 +22,10 @@ public class TestPrograms extends TestCase { helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/"); } + public void testInlineWord() throws IOException, URISyntaxException { + compileAndCompare("inline-word"); + } + public void testSignedWords() throws IOException, URISyntaxException { compileAndCompare("signed-words"); } @@ -183,6 +187,10 @@ public class TestPrograms extends TestCase { compileAndCompare("inmemarray"); } + public void testInMemConstArray() throws IOException, URISyntaxException { + compileAndCompare("inmem-const-array"); + } + public void testInMemString() throws IOException, URISyntaxException { compileAndCompare("inmemstring"); } diff --git a/src/main/java/dk/camelot64/kickc/test/inline-word.kc b/src/main/java/dk/camelot64/kickc/test/inline-word.kc new file mode 100644 index 000000000..dac64ddff --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/inline-word.kc @@ -0,0 +1,12 @@ +const byte* SCREEN = $400; + +void main() { + byte[] his = { >SCREEN, >SCREEN+1 }; + for( byte h: 0..1) { + for (byte l: 4..7) { + word w = { his[h], l }; + byte* sc = (byte*)w; + *sc = '*'; + } + } +} \ No newline at end of file diff --git a/src/main/java/dk/camelot64/kickc/test/inmem-const-array.kc b/src/main/java/dk/camelot64/kickc/test/inmem-const-array.kc new file mode 100644 index 000000000..9f8ec3b62 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/inmem-const-array.kc @@ -0,0 +1,18 @@ +byte WHITE = 1; +byte RED = 2; +byte GREEN = 5; + +void main() { + byte[] colseq = { WHITE, RED, GREEN }; + byte* screen = $0400; + byte* cols = $d800; + byte j = 0; + for( byte i : 0..39) { + screen[i] = '*'; + cols[i] = colseq[j]; + if(++j==3) { + j=0; + } + } + +} \ No newline at end of file diff --git a/src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.asm b/src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.asm new file mode 100644 index 000000000..7ecf0a146 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.asm @@ -0,0 +1,28 @@ +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .const WHITE = 1 + .const RED = 2 + .const GREEN = 5 + jsr main +main: { + .const screen = $400 + .const cols = $d800 + ldy #0 + ldx #0 + b1: + lda #'*' + sta screen,x + lda colseq,y + sta cols,x + iny + cpy #3 + bne b2 + ldy #0 + b2: + inx + cpx #$28 + bne b1 + rts + colseq: .byte WHITE, RED, GREEN +} diff --git a/src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.cfg b/src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.cfg new file mode 100644 index 000000000..509575d02 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.cfg @@ -0,0 +1,32 @@ +@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] phi() [ ] ( main:2 [ ] ) + to:main::@1 +main::@1: scope:[main] from main main::@2 + [5] (byte) main::j#3 ← phi( main/(byte/signed byte/word/signed word) 0 main::@2/(byte) main::j#4 ) [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) + [5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@2/(byte) main::i#1 ) [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) + [6] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) + [7] (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 [ main::i#2 main::j#3 main::$0 ] ( main:2 [ main::i#2 main::j#3 main::$0 ] ) + [8] *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) + [9] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) + [10] if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@6 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) + to:main::@2 +main::@2: scope:[main] from main::@1 main::@6 + [11] (byte) main::j#4 ← phi( main::@6/(byte) main::j#1 main::@1/(byte/signed byte/word/signed word) 0 ) [ main::i#2 main::j#4 ] ( main:2 [ main::i#2 main::j#4 ] ) + [12] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) + [13] if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) + to:main::@return +main::@return: scope:[main] from main::@2 + [14] return [ ] ( main:2 [ ] ) + to:@return +main::@6: scope:[main] from main::@1 + [15] phi() [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) + to:main::@2 diff --git a/src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.log b/src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.log new file mode 100644 index 000000000..aae74b156 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.log @@ -0,0 +1,1828 @@ +byte WHITE = 1; +byte RED = 2; +byte GREEN = 5; + +void main() { + byte[] colseq = { WHITE, RED, GREEN }; + byte* screen = $0400; + byte* cols = $d800; + byte j = 0; + for( byte i : 0..39) { + screen[i] = '*'; + cols[i] = colseq[j]; + if(++j==3) { + j=0; + } + } + +} +Adding pre/post-modifier (byte) main::j ← ++ (byte) main::j +PROGRAM + (byte) WHITE ← (byte/signed byte/word/signed word) 1 + (byte) RED ← (byte/signed byte/word/signed word) 2 + (byte) GREEN ← (byte/signed byte/word/signed word) 5 +proc (void()) main() + (byte[]) main::colseq ← { (byte) WHITE, (byte) RED, (byte) GREEN } + (byte*) main::screen ← (word/signed word) 1024 + (byte*) main::cols ← (word) 55296 + (byte) main::j ← (byte/signed byte/word/signed word) 0 + (byte) main::i ← (byte/signed byte/word/signed word) 0 +main::@1: + *((byte*) main::screen + (byte) main::i) ← (byte) '*' + (byte~) main::$0 ← (byte[]) main::colseq *idx (byte) main::j + *((byte*) main::cols + (byte) main::i) ← (byte~) main::$0 + (byte) main::j ← ++ (byte) main::j + (boolean~) main::$1 ← (byte) main::j == (byte/signed byte/word/signed word) 3 + (boolean~) main::$2 ← ! (boolean~) main::$1 + if((boolean~) main::$2) goto main::@2 + (byte) main::j ← (byte/signed byte/word/signed word) 0 +main::@2: + (byte) main::i ← ++ (byte) main::i + (boolean~) main::$3 ← (byte) main::i != (byte/signed byte/word/signed word) 40 + if((boolean~) main::$3) goto main::@1 +main::@return: + return +endproc // main() + call main + +SYMBOLS +(byte) GREEN +(byte) RED +(byte) WHITE +(void()) main() +(byte~) main::$0 +(boolean~) main::$1 +(boolean~) main::$2 +(boolean~) main::$3 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte*) main::cols +(byte[]) main::colseq +(byte) main::i +(byte) main::j +(byte*) main::screen + +Promoting word/signed word to byte* in main::screen ← ((byte*)) 1024 +Promoting word to byte* in main::cols ← ((byte*)) 55296 +INITIAL CONTROL FLOW GRAPH +@begin: scope:[] from + (byte) WHITE ← (byte/signed byte/word/signed word) 1 + (byte) RED ← (byte/signed byte/word/signed word) 2 + (byte) GREEN ← (byte/signed byte/word/signed word) 5 + to:@1 +main: scope:[main] from + (byte[]) main::colseq ← { (byte) WHITE, (byte) RED, (byte) GREEN } + (byte*) main::screen ← ((byte*)) (word/signed word) 1024 + (byte*) main::cols ← ((byte*)) (word) 55296 + (byte) main::j ← (byte/signed byte/word/signed word) 0 + (byte) main::i ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + *((byte*) main::screen + (byte) main::i) ← (byte) '*' + (byte~) main::$0 ← (byte[]) main::colseq *idx (byte) main::j + *((byte*) main::cols + (byte) main::i) ← (byte~) main::$0 + (byte) main::j ← ++ (byte) main::j + (boolean~) main::$1 ← (byte) main::j == (byte/signed byte/word/signed word) 3 + (boolean~) main::$2 ← ! (boolean~) main::$1 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::i ← ++ (byte) main::i + (boolean~) main::$3 ← (byte) main::i != (byte/signed byte/word/signed word) 40 + if((boolean~) main::$3) goto main::@1 + to:main::@4 +main::@3: scope:[main] from main::@1 + (byte) main::j ← (byte/signed byte/word/signed word) 0 + to:main::@2 +main::@4: scope:[main] from main::@2 + to:main::@return +main::@return: scope:[main] from main::@4 + return + to:@return +@1: scope:[] from @begin + call main + to:@end +@end: scope:[] from @1 + +Removing empty block main::@4 +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte) WHITE ← (byte/signed byte/word/signed word) 1 + (byte) RED ← (byte/signed byte/word/signed word) 2 + (byte) GREEN ← (byte/signed byte/word/signed word) 5 + to:@1 +main: scope:[main] from + (byte[]) main::colseq ← { (byte) WHITE, (byte) RED, (byte) GREEN } + (byte*) main::screen ← ((byte*)) (word/signed word) 1024 + (byte*) main::cols ← ((byte*)) (word) 55296 + (byte) main::j ← (byte/signed byte/word/signed word) 0 + (byte) main::i ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + *((byte*) main::screen + (byte) main::i) ← (byte) '*' + (byte~) main::$0 ← (byte[]) main::colseq *idx (byte) main::j + *((byte*) main::cols + (byte) main::i) ← (byte~) main::$0 + (byte) main::j ← ++ (byte) main::j + (boolean~) main::$1 ← (byte) main::j == (byte/signed byte/word/signed word) 3 + (boolean~) main::$2 ← ! (boolean~) main::$1 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::i ← ++ (byte) main::i + (boolean~) main::$3 ← (byte) main::i != (byte/signed byte/word/signed word) 40 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte) main::j ← (byte/signed byte/word/signed word) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + 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 + (byte) WHITE ← (byte/signed byte/word/signed word) 1 + (byte) RED ← (byte/signed byte/word/signed word) 2 + (byte) GREEN ← (byte/signed byte/word/signed word) 5 + to:@1 +main: scope:[main] from @1 + (byte[]) main::colseq ← { (byte) WHITE, (byte) RED, (byte) GREEN } + (byte*) main::screen ← ((byte*)) (word/signed word) 1024 + (byte*) main::cols ← ((byte*)) (word) 55296 + (byte) main::j ← (byte/signed byte/word/signed word) 0 + (byte) main::i ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + *((byte*) main::screen + (byte) main::i) ← (byte) '*' + (byte~) main::$0 ← (byte[]) main::colseq *idx (byte) main::j + *((byte*) main::cols + (byte) main::i) ← (byte~) main::$0 + (byte) main::j ← ++ (byte) main::j + (boolean~) main::$1 ← (byte) main::j == (byte/signed byte/word/signed word) 3 + (boolean~) main::$2 ← ! (boolean~) main::$1 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::i ← ++ (byte) main::i + (boolean~) main::$3 ← (byte) main::i != (byte/signed byte/word/signed word) 40 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte) main::j ← (byte/signed byte/word/signed word) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + 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... +Completing Phi functions... +Completing Phi functions... +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (byte) WHITE#0 ← (byte/signed byte/word/signed word) 1 + (byte) RED#0 ← (byte/signed byte/word/signed word) 2 + (byte) GREEN#0 ← (byte/signed byte/word/signed word) 5 + to:@1 +main: scope:[main] from @1 + (byte) GREEN#1 ← phi( @1/(byte) GREEN#2 ) + (byte) RED#1 ← phi( @1/(byte) RED#2 ) + (byte) WHITE#1 ← phi( @1/(byte) WHITE#2 ) + (byte[]) main::colseq#0 ← { (byte) WHITE#1, (byte) RED#1, (byte) GREEN#1 } + (byte*) main::screen#0 ← ((byte*)) (word/signed word) 1024 + (byte*) main::cols#0 ← ((byte*)) (word) 55296 + (byte) main::j#0 ← (byte/signed byte/word/signed word) 0 + (byte) main::i#0 ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte*) main::cols#1 ← phi( main/(byte*) main::cols#0 main::@2/(byte*) main::cols#2 ) + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte[]) main::colseq#1 ← phi( main/(byte[]) main::colseq#0 main::@2/(byte[]) main::colseq#2 ) + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte*) main::screen#1 ← phi( main/(byte*) main::screen#0 main::@2/(byte*) main::screen#2 ) + *((byte*) main::screen#1 + (byte) main::i#2) ← (byte) '*' + (byte~) main::$0 ← (byte[]) main::colseq#1 *idx (byte) main::j#3 + *((byte*) main::cols#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + (boolean~) main::$1 ← (byte) main::j#1 == (byte/signed byte/word/signed word) 3 + (boolean~) main::$2 ← ! (boolean~) main::$1 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte*) main::cols#2 ← phi( main::@1/(byte*) main::cols#1 main::@3/(byte*) main::cols#3 ) + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte[]) main::colseq#2 ← phi( main::@1/(byte[]) main::colseq#1 main::@3/(byte[]) main::colseq#3 ) + (byte*) main::screen#2 ← phi( main::@1/(byte*) main::screen#1 main::@3/(byte*) main::screen#3 ) + (byte) main::i#3 ← phi( main::@1/(byte) main::i#2 main::@3/(byte) main::i#4 ) + (byte) main::i#1 ← ++ (byte) main::i#3 + (boolean~) main::$3 ← (byte) main::i#1 != (byte/signed byte/word/signed word) 40 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte*) main::cols#3 ← phi( main::@1/(byte*) main::cols#1 ) + (byte[]) main::colseq#3 ← phi( main::@1/(byte[]) main::colseq#1 ) + (byte*) main::screen#3 ← phi( main::@1/(byte*) main::screen#1 ) + (byte) main::i#4 ← phi( main::@1/(byte) main::i#2 ) + (byte) main::j#2 ← (byte/signed byte/word/signed word) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@1: scope:[] from @begin + (byte) GREEN#2 ← phi( @begin/(byte) GREEN#0 ) + (byte) RED#2 ← phi( @begin/(byte) RED#0 ) + (byte) WHITE#2 ← phi( @begin/(byte) WHITE#0 ) + 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 + (byte) WHITE#0 ← (byte/signed byte/word/signed word) 1 + (byte) RED#0 ← (byte/signed byte/word/signed word) 2 + (byte) GREEN#0 ← (byte/signed byte/word/signed word) 5 + to:@1 +main: scope:[main] from @1 + (byte) GREEN#1 ← phi( @1/(byte) GREEN#2 ) + (byte) RED#1 ← phi( @1/(byte) RED#2 ) + (byte) WHITE#1 ← phi( @1/(byte) WHITE#2 ) + (byte[]) main::colseq#0 ← { (byte) WHITE#1, (byte) RED#1, (byte) GREEN#1 } + (byte*) main::screen#0 ← ((byte*)) (word/signed word) 1024 + (byte*) main::cols#0 ← ((byte*)) (word) 55296 + (byte) main::j#0 ← (byte/signed byte/word/signed word) 0 + (byte) main::i#0 ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte*) main::cols#1 ← phi( main/(byte*) main::cols#0 main::@2/(byte*) main::cols#2 ) + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte[]) main::colseq#1 ← phi( main/(byte[]) main::colseq#0 main::@2/(byte[]) main::colseq#2 ) + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte*) main::screen#1 ← phi( main/(byte*) main::screen#0 main::@2/(byte*) main::screen#2 ) + *((byte*) main::screen#1 + (byte) main::i#2) ← (byte) '*' + (byte~) main::$0 ← (byte[]) main::colseq#1 *idx (byte) main::j#3 + *((byte*) main::cols#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + (boolean~) main::$1 ← (byte) main::j#1 == (byte/signed byte/word/signed word) 3 + (boolean~) main::$2 ← ! (boolean~) main::$1 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte*) main::cols#2 ← phi( main::@1/(byte*) main::cols#1 main::@3/(byte*) main::cols#3 ) + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte[]) main::colseq#2 ← phi( main::@1/(byte[]) main::colseq#1 main::@3/(byte[]) main::colseq#3 ) + (byte*) main::screen#2 ← phi( main::@1/(byte*) main::screen#1 main::@3/(byte*) main::screen#3 ) + (byte) main::i#3 ← phi( main::@1/(byte) main::i#2 main::@3/(byte) main::i#4 ) + (byte) main::i#1 ← ++ (byte) main::i#3 + (boolean~) main::$3 ← (byte) main::i#1 != (byte/signed byte/word/signed word) 40 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte*) main::cols#3 ← phi( main::@1/(byte*) main::cols#1 ) + (byte[]) main::colseq#3 ← phi( main::@1/(byte[]) main::colseq#1 ) + (byte*) main::screen#3 ← phi( main::@1/(byte*) main::screen#1 ) + (byte) main::i#4 ← phi( main::@1/(byte) main::i#2 ) + (byte) main::j#2 ← (byte/signed byte/word/signed word) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@1: scope:[] from @begin + (byte) GREEN#2 ← phi( @begin/(byte) GREEN#0 ) + (byte) RED#2 ← phi( @begin/(byte) RED#0 ) + (byte) WHITE#2 ← phi( @begin/(byte) WHITE#0 ) + 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 +(byte) GREEN +(byte) GREEN#0 +(byte) GREEN#1 +(byte) GREEN#2 +(byte) RED +(byte) RED#0 +(byte) RED#1 +(byte) RED#2 +(byte) WHITE +(byte) WHITE#0 +(byte) WHITE#1 +(byte) WHITE#2 +(void()) main() +(byte~) main::$0 +(boolean~) main::$1 +(boolean~) main::$2 +(boolean~) main::$3 +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@return +(byte*) main::cols +(byte*) main::cols#0 +(byte*) main::cols#1 +(byte*) main::cols#2 +(byte*) main::cols#3 +(byte[]) main::colseq +(byte[]) main::colseq#0 +(byte[]) main::colseq#1 +(byte[]) main::colseq#2 +(byte[]) main::colseq#3 +(byte) main::i +(byte) main::i#0 +(byte) main::i#1 +(byte) main::i#2 +(byte) main::i#3 +(byte) main::i#4 +(byte) main::j +(byte) main::j#0 +(byte) main::j#1 +(byte) main::j#2 +(byte) main::j#3 +(byte) main::j#4 +(byte*) main::screen +(byte*) main::screen#0 +(byte*) main::screen#1 +(byte*) main::screen#2 +(byte*) main::screen#3 + +Culled Empty Block (label) @2 +Succesful SSA optimization Pass2CullEmptyBlocks +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte) WHITE#0 ← (byte/signed byte/word/signed word) 1 + (byte) RED#0 ← (byte/signed byte/word/signed word) 2 + (byte) GREEN#0 ← (byte/signed byte/word/signed word) 5 + to:@1 +main: scope:[main] from @1 + (byte) GREEN#1 ← phi( @1/(byte) GREEN#2 ) + (byte) RED#1 ← phi( @1/(byte) RED#2 ) + (byte) WHITE#1 ← phi( @1/(byte) WHITE#2 ) + (byte[]) main::colseq#0 ← { (byte) WHITE#1, (byte) RED#1, (byte) GREEN#1 } + (byte*) main::screen#0 ← ((byte*)) (word/signed word) 1024 + (byte*) main::cols#0 ← ((byte*)) (word) 55296 + (byte) main::j#0 ← (byte/signed byte/word/signed word) 0 + (byte) main::i#0 ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte*) main::cols#1 ← phi( main/(byte*) main::cols#0 main::@2/(byte*) main::cols#2 ) + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte[]) main::colseq#1 ← phi( main/(byte[]) main::colseq#0 main::@2/(byte[]) main::colseq#2 ) + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte*) main::screen#1 ← phi( main/(byte*) main::screen#0 main::@2/(byte*) main::screen#2 ) + *((byte*) main::screen#1 + (byte) main::i#2) ← (byte) '*' + (byte~) main::$0 ← (byte[]) main::colseq#1 *idx (byte) main::j#3 + *((byte*) main::cols#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + (boolean~) main::$1 ← (byte) main::j#1 == (byte/signed byte/word/signed word) 3 + (boolean~) main::$2 ← ! (boolean~) main::$1 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte*) main::cols#2 ← phi( main::@1/(byte*) main::cols#1 main::@3/(byte*) main::cols#3 ) + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte[]) main::colseq#2 ← phi( main::@1/(byte[]) main::colseq#1 main::@3/(byte[]) main::colseq#3 ) + (byte*) main::screen#2 ← phi( main::@1/(byte*) main::screen#1 main::@3/(byte*) main::screen#3 ) + (byte) main::i#3 ← phi( main::@1/(byte) main::i#2 main::@3/(byte) main::i#4 ) + (byte) main::i#1 ← ++ (byte) main::i#3 + (boolean~) main::$3 ← (byte) main::i#1 != (byte/signed byte/word/signed word) 40 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte*) main::cols#3 ← phi( main::@1/(byte*) main::cols#1 ) + (byte[]) main::colseq#3 ← phi( main::@1/(byte[]) main::colseq#1 ) + (byte*) main::screen#3 ← phi( main::@1/(byte*) main::screen#1 ) + (byte) main::i#4 ← phi( main::@1/(byte) main::i#2 ) + (byte) main::j#2 ← (byte/signed byte/word/signed word) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@1: scope:[] from @begin + (byte) GREEN#2 ← phi( @begin/(byte) GREEN#0 ) + (byte) RED#2 ← phi( @begin/(byte) RED#0 ) + (byte) WHITE#2 ← phi( @begin/(byte) WHITE#0 ) + call main param-assignment + to:@end +@end: scope:[] from @1 + +Inversing boolean not (boolean~) main::$2 ← (byte) main::j#1 != (byte/signed byte/word/signed word) 3 from (boolean~) main::$1 ← (byte) main::j#1 == (byte/signed byte/word/signed word) 3 +Succesful SSA optimization Pass2UnaryNotSimplification +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte) WHITE#0 ← (byte/signed byte/word/signed word) 1 + (byte) RED#0 ← (byte/signed byte/word/signed word) 2 + (byte) GREEN#0 ← (byte/signed byte/word/signed word) 5 + to:@1 +main: scope:[main] from @1 + (byte) GREEN#1 ← phi( @1/(byte) GREEN#2 ) + (byte) RED#1 ← phi( @1/(byte) RED#2 ) + (byte) WHITE#1 ← phi( @1/(byte) WHITE#2 ) + (byte[]) main::colseq#0 ← { (byte) WHITE#1, (byte) RED#1, (byte) GREEN#1 } + (byte*) main::screen#0 ← ((byte*)) (word/signed word) 1024 + (byte*) main::cols#0 ← ((byte*)) (word) 55296 + (byte) main::j#0 ← (byte/signed byte/word/signed word) 0 + (byte) main::i#0 ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte*) main::cols#1 ← phi( main/(byte*) main::cols#0 main::@2/(byte*) main::cols#2 ) + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte[]) main::colseq#1 ← phi( main/(byte[]) main::colseq#0 main::@2/(byte[]) main::colseq#2 ) + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte*) main::screen#1 ← phi( main/(byte*) main::screen#0 main::@2/(byte*) main::screen#2 ) + *((byte*) main::screen#1 + (byte) main::i#2) ← (byte) '*' + (byte~) main::$0 ← (byte[]) main::colseq#1 *idx (byte) main::j#3 + *((byte*) main::cols#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + (boolean~) main::$2 ← (byte) main::j#1 != (byte/signed byte/word/signed word) 3 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte*) main::cols#2 ← phi( main::@1/(byte*) main::cols#1 main::@3/(byte*) main::cols#3 ) + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte[]) main::colseq#2 ← phi( main::@1/(byte[]) main::colseq#1 main::@3/(byte[]) main::colseq#3 ) + (byte*) main::screen#2 ← phi( main::@1/(byte*) main::screen#1 main::@3/(byte*) main::screen#3 ) + (byte) main::i#3 ← phi( main::@1/(byte) main::i#2 main::@3/(byte) main::i#4 ) + (byte) main::i#1 ← ++ (byte) main::i#3 + (boolean~) main::$3 ← (byte) main::i#1 != (byte/signed byte/word/signed word) 40 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte*) main::cols#3 ← phi( main::@1/(byte*) main::cols#1 ) + (byte[]) main::colseq#3 ← phi( main::@1/(byte[]) main::colseq#1 ) + (byte*) main::screen#3 ← phi( main::@1/(byte*) main::screen#1 ) + (byte) main::i#4 ← phi( main::@1/(byte) main::i#2 ) + (byte) main::j#2 ← (byte/signed byte/word/signed word) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@1: scope:[] from @begin + (byte) GREEN#2 ← phi( @begin/(byte) GREEN#0 ) + (byte) RED#2 ← phi( @begin/(byte) RED#0 ) + (byte) WHITE#2 ← phi( @begin/(byte) WHITE#0 ) + call main param-assignment + to:@end +@end: scope:[] from @1 + +Not aliassing across scopes: WHITE#1 WHITE#2 +Not aliassing across scopes: RED#1 RED#2 +Not aliassing across scopes: GREEN#1 GREEN#2 +Alias (byte) main::i#2 = (byte) main::i#4 +Alias (byte*) main::screen#1 = (byte*) main::screen#3 +Alias (byte[]) main::colseq#1 = (byte[]) main::colseq#3 +Alias (byte*) main::cols#1 = (byte*) main::cols#3 +Alias (byte) WHITE#0 = (byte) WHITE#2 +Alias (byte) RED#0 = (byte) RED#2 +Alias (byte) GREEN#0 = (byte) GREEN#2 +Succesful SSA optimization Pass2AliasElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte) WHITE#0 ← (byte/signed byte/word/signed word) 1 + (byte) RED#0 ← (byte/signed byte/word/signed word) 2 + (byte) GREEN#0 ← (byte/signed byte/word/signed word) 5 + to:@1 +main: scope:[main] from @1 + (byte) GREEN#1 ← phi( @1/(byte) GREEN#0 ) + (byte) RED#1 ← phi( @1/(byte) RED#0 ) + (byte) WHITE#1 ← phi( @1/(byte) WHITE#0 ) + (byte[]) main::colseq#0 ← { (byte) WHITE#1, (byte) RED#1, (byte) GREEN#1 } + (byte*) main::screen#0 ← ((byte*)) (word/signed word) 1024 + (byte*) main::cols#0 ← ((byte*)) (word) 55296 + (byte) main::j#0 ← (byte/signed byte/word/signed word) 0 + (byte) main::i#0 ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte*) main::cols#1 ← phi( main/(byte*) main::cols#0 main::@2/(byte*) main::cols#2 ) + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte[]) main::colseq#1 ← phi( main/(byte[]) main::colseq#0 main::@2/(byte[]) main::colseq#2 ) + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte*) main::screen#1 ← phi( main/(byte*) main::screen#0 main::@2/(byte*) main::screen#2 ) + *((byte*) main::screen#1 + (byte) main::i#2) ← (byte) '*' + (byte~) main::$0 ← (byte[]) main::colseq#1 *idx (byte) main::j#3 + *((byte*) main::cols#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + (boolean~) main::$2 ← (byte) main::j#1 != (byte/signed byte/word/signed word) 3 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte*) main::cols#2 ← phi( main::@1/(byte*) main::cols#1 main::@3/(byte*) main::cols#1 ) + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte[]) main::colseq#2 ← phi( main::@1/(byte[]) main::colseq#1 main::@3/(byte[]) main::colseq#1 ) + (byte*) main::screen#2 ← phi( main::@1/(byte*) main::screen#1 main::@3/(byte*) main::screen#1 ) + (byte) main::i#3 ← phi( main::@1/(byte) main::i#2 main::@3/(byte) main::i#2 ) + (byte) main::i#1 ← ++ (byte) main::i#3 + (boolean~) main::$3 ← (byte) main::i#1 != (byte/signed byte/word/signed word) 40 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte) main::j#2 ← (byte/signed byte/word/signed word) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Not aliassing across scopes: WHITE#1 WHITE#0 +Not aliassing across scopes: RED#1 RED#0 +Not aliassing across scopes: GREEN#1 GREEN#0 +Alias (byte) main::i#2 = (byte) main::i#3 +Alias (byte*) main::screen#1 = (byte*) main::screen#2 +Alias (byte[]) main::colseq#1 = (byte[]) main::colseq#2 +Alias (byte*) main::cols#1 = (byte*) main::cols#2 +Succesful SSA optimization Pass2AliasElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte) WHITE#0 ← (byte/signed byte/word/signed word) 1 + (byte) RED#0 ← (byte/signed byte/word/signed word) 2 + (byte) GREEN#0 ← (byte/signed byte/word/signed word) 5 + to:@1 +main: scope:[main] from @1 + (byte) GREEN#1 ← phi( @1/(byte) GREEN#0 ) + (byte) RED#1 ← phi( @1/(byte) RED#0 ) + (byte) WHITE#1 ← phi( @1/(byte) WHITE#0 ) + (byte[]) main::colseq#0 ← { (byte) WHITE#1, (byte) RED#1, (byte) GREEN#1 } + (byte*) main::screen#0 ← ((byte*)) (word/signed word) 1024 + (byte*) main::cols#0 ← ((byte*)) (word) 55296 + (byte) main::j#0 ← (byte/signed byte/word/signed word) 0 + (byte) main::i#0 ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte*) main::cols#1 ← phi( main/(byte*) main::cols#0 main::@2/(byte*) main::cols#1 ) + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte[]) main::colseq#1 ← phi( main/(byte[]) main::colseq#0 main::@2/(byte[]) main::colseq#1 ) + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte*) main::screen#1 ← phi( main/(byte*) main::screen#0 main::@2/(byte*) main::screen#1 ) + *((byte*) main::screen#1 + (byte) main::i#2) ← (byte) '*' + (byte~) main::$0 ← (byte[]) main::colseq#1 *idx (byte) main::j#3 + *((byte*) main::cols#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + (boolean~) main::$2 ← (byte) main::j#1 != (byte/signed byte/word/signed word) 3 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte) main::i#1 ← ++ (byte) main::i#2 + (boolean~) main::$3 ← (byte) main::i#1 != (byte/signed byte/word/signed word) 40 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte) main::j#2 ← (byte/signed byte/word/signed word) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Not aliassing across scopes: WHITE#1 WHITE#0 +Not aliassing across scopes: RED#1 RED#0 +Not aliassing across scopes: GREEN#1 GREEN#0 +Self Phi Eliminated (byte*) main::screen#1 +Self Phi Eliminated (byte[]) main::colseq#1 +Self Phi Eliminated (byte*) main::cols#1 +Succesful SSA optimization Pass2SelfPhiElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte) WHITE#0 ← (byte/signed byte/word/signed word) 1 + (byte) RED#0 ← (byte/signed byte/word/signed word) 2 + (byte) GREEN#0 ← (byte/signed byte/word/signed word) 5 + to:@1 +main: scope:[main] from @1 + (byte) GREEN#1 ← phi( @1/(byte) GREEN#0 ) + (byte) RED#1 ← phi( @1/(byte) RED#0 ) + (byte) WHITE#1 ← phi( @1/(byte) WHITE#0 ) + (byte[]) main::colseq#0 ← { (byte) WHITE#1, (byte) RED#1, (byte) GREEN#1 } + (byte*) main::screen#0 ← ((byte*)) (word/signed word) 1024 + (byte*) main::cols#0 ← ((byte*)) (word) 55296 + (byte) main::j#0 ← (byte/signed byte/word/signed word) 0 + (byte) main::i#0 ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte*) main::cols#1 ← phi( main/(byte*) main::cols#0 ) + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte[]) main::colseq#1 ← phi( main/(byte[]) main::colseq#0 ) + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte*) main::screen#1 ← phi( main/(byte*) main::screen#0 ) + *((byte*) main::screen#1 + (byte) main::i#2) ← (byte) '*' + (byte~) main::$0 ← (byte[]) main::colseq#1 *idx (byte) main::j#3 + *((byte*) main::cols#1 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + (boolean~) main::$2 ← (byte) main::j#1 != (byte/signed byte/word/signed word) 3 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte) main::i#1 ← ++ (byte) main::i#2 + (boolean~) main::$3 ← (byte) main::i#1 != (byte/signed byte/word/signed word) 40 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte) main::j#2 ← (byte/signed byte/word/signed word) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Redundant Phi (byte) WHITE#1 (byte) WHITE#0 +Redundant Phi (byte) RED#1 (byte) RED#0 +Redundant Phi (byte) GREEN#1 (byte) GREEN#0 +Redundant Phi (byte*) main::screen#1 (byte*) main::screen#0 +Redundant Phi (byte[]) main::colseq#1 (byte[]) main::colseq#0 +Redundant Phi (byte*) main::cols#1 (byte*) main::cols#0 +Succesful SSA optimization Pass2RedundantPhiElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte) WHITE#0 ← (byte/signed byte/word/signed word) 1 + (byte) RED#0 ← (byte/signed byte/word/signed word) 2 + (byte) GREEN#0 ← (byte/signed byte/word/signed word) 5 + to:@1 +main: scope:[main] from @1 + (byte[]) main::colseq#0 ← { (byte) WHITE#0, (byte) RED#0, (byte) GREEN#0 } + (byte*) main::screen#0 ← ((byte*)) (word/signed word) 1024 + (byte*) main::cols#0 ← ((byte*)) (word) 55296 + (byte) main::j#0 ← (byte/signed byte/word/signed word) 0 + (byte) main::i#0 ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + *((byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' + (byte~) main::$0 ← (byte[]) main::colseq#0 *idx (byte) main::j#3 + *((byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + (boolean~) main::$2 ← (byte) main::j#1 != (byte/signed byte/word/signed word) 3 + if((boolean~) main::$2) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte) main::i#1 ← ++ (byte) main::i#2 + (boolean~) main::$3 ← (byte) main::i#1 != (byte/signed byte/word/signed word) 40 + if((boolean~) main::$3) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte) main::j#2 ← (byte/signed byte/word/signed word) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Simple Condition (boolean~) main::$2 if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@2 +Simple Condition (boolean~) main::$3 if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 +Succesful SSA optimization Pass2ConditionalJumpSimplification +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte) WHITE#0 ← (byte/signed byte/word/signed word) 1 + (byte) RED#0 ← (byte/signed byte/word/signed word) 2 + (byte) GREEN#0 ← (byte/signed byte/word/signed word) 5 + to:@1 +main: scope:[main] from @1 + (byte[]) main::colseq#0 ← { (byte) WHITE#0, (byte) RED#0, (byte) GREEN#0 } + (byte*) main::screen#0 ← ((byte*)) (word/signed word) 1024 + (byte*) main::cols#0 ← ((byte*)) (word) 55296 + (byte) main::j#0 ← (byte/signed byte/word/signed word) 0 + (byte) main::i#0 ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::j#3 ← phi( main/(byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + *((byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' + (byte~) main::$0 ← (byte[]) main::colseq#0 *idx (byte) main::j#3 + *((byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte) main::j#2 ) + (byte) main::i#1 ← ++ (byte) main::i#2 + if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + (byte) main::j#2 ← (byte/signed byte/word/signed word) 0 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Constant (const byte) WHITE#0 = 1 +Constant (const byte) RED#0 = 2 +Constant (const byte) GREEN#0 = 5 +Constant (const byte*) main::screen#0 = ((byte*))1024 +Constant (const byte*) main::cols#0 = ((byte*))55296 +Constant (const byte) main::j#0 = 0 +Constant (const byte) main::i#0 = 0 +Constant (const byte) main::j#2 = 0 +Succesful SSA optimization Pass2ConstantIdentification +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (byte[]) main::colseq#0 ← { (const byte) WHITE#0, (const byte) RED#0, (const byte) GREEN#0 } + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::j#3 ← phi( main/(const byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte) main::i#2 ← phi( main/(const byte) main::i#0 main::@2/(byte) main::i#1 ) + *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' + (byte~) main::$0 ← (byte[]) main::colseq#0 *idx (byte) main::j#3 + *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(const byte) main::j#2 ) + (byte) main::i#1 ← ++ (byte) main::i#2 + if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Constant (const byte[]) main::colseq#0 = { WHITE#0, RED#0, GREEN#0 } +Succesful SSA optimization Pass2ConstantIdentification +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::j#3 ← phi( main/(const byte) main::j#0 main::@2/(byte) main::j#4 ) + (byte) main::i#2 ← phi( main/(const byte) main::i#0 main::@2/(byte) main::i#1 ) + *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' + (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 + *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(const byte) main::j#2 ) + (byte) main::i#1 ← ++ (byte) main::i#2 + if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + to:main::@2 +main::@return: scope:[main] from main::@2 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Multiple usages for variable. Not optimizing sub-constant (byte) main::j#3 +Not culling empty block because it shares successor with its predecessor. (label) main::@3 +Multiple usages for variable. Not optimizing sub-constant (byte) main::j#3 +Inlining constant with var siblings (const byte) main::j#0 +Inlining constant with var siblings (const byte) main::j#0 +Inlining constant with var siblings (const byte) main::j#0 +Inlining constant with var siblings (const byte) main::i#0 +Inlining constant with var siblings (const byte) main::i#0 +Inlining constant with var siblings (const byte) main::j#2 +Inlining constant with var siblings (const byte) main::j#2 +Inlining constant with var siblings (const byte) main::j#2 +Constant inlined main::i#0 = (byte/signed byte/word/signed word) 0 +Constant inlined main::j#0 = (byte/signed byte/word/signed word) 0 +Constant inlined main::j#2 = (byte/signed byte/word/signed word) 0 +Succesful SSA optimization Pass2ConstantInlining +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::j#3 ← phi( main/(byte/signed byte/word/signed word) 0 main::@2/(byte) main::j#4 ) + (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@2/(byte) main::i#1 ) + *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' + (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 + *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@2 + to:main::@3 +main::@2: scope:[main] from main::@1 main::@3 + (byte) main::j#4 ← phi( main::@1/(byte) main::j#1 main::@3/(byte/signed byte/word/signed word) 0 ) + (byte) main::i#1 ← ++ (byte) main::i#2 + if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 + to:main::@return +main::@3: scope:[main] from main::@1 + to:main::@2 +main::@return: scope:[main] from main::@2 + 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 +(byte) GREEN +(const byte) GREEN#0 = (byte/signed byte/word/signed word) 5 +(byte) RED +(const byte) RED#0 = (byte/signed byte/word/signed word) 2 +(byte) WHITE +(const byte) WHITE#0 = (byte/signed byte/word/signed word) 1 +(void()) main() +(byte~) main::$0 +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@return +(byte*) main::cols +(const byte*) main::cols#0 = ((byte*))(word) 55296 +(byte[]) main::colseq +(const byte[]) main::colseq#0 = { (const byte) WHITE#0, (const byte) RED#0, (const byte) GREEN#0 } +(byte) main::i +(byte) main::i#1 +(byte) main::i#2 +(byte) main::j +(byte) main::j#1 +(byte) main::j#3 +(byte) main::j#4 +(byte*) main::screen +(const byte*) main::screen#0 = ((byte*))(word/signed word) 1024 + +Block Sequence Planned @begin @1 @end main main::@1 main::@3 main::@2 main::@return +Added new block during phi lifting main::@5(between main::@2 and main::@1) +Added new block during phi lifting main::@6(between main::@1 and main::@2) +Block Sequence Planned @begin @1 @end main main::@1 main::@3 main::@2 main::@return main::@5 main::@6 +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 + to:main::@1 +main::@1: scope:[main] from main main::@5 + (byte) main::j#3 ← phi( main/(byte/signed byte/word/signed word) 0 main::@5/(byte~) main::j#5 ) + (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@5/(byte~) main::i#5 ) + *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' + (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 + *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 + (byte) main::j#1 ← ++ (byte) main::j#3 + if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@6 + to:main::@3 +main::@3: scope:[main] from main::@1 + to:main::@2 +main::@2: scope:[main] from main::@3 main::@6 + (byte) main::j#4 ← phi( main::@6/(byte~) main::j#6 main::@3/(byte/signed byte/word/signed word) 0 ) + (byte) main::i#1 ← ++ (byte) main::i#2 + if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@5 + to:main::@return +main::@return: scope:[main] from main::@2 + return + to:@return +main::@5: scope:[main] from main::@2 + (byte~) main::i#5 ← (byte) main::i#1 + (byte~) main::j#5 ← (byte) main::j#4 + to:main::@1 +main::@6: scope:[main] from main::@1 + (byte~) main::j#6 ← (byte) main::j#1 + to:main::@2 + +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +Adding NOP phi() at start of main::@3 +CALL GRAPH +Calls in [] to main:2 + +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +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] phi() [ ] + to:main::@1 +main::@1: scope:[main] from main main::@5 + [5] (byte) main::j#3 ← phi( main/(byte/signed byte/word/signed word) 0 main::@5/(byte~) main::j#5 ) [ main::i#2 main::j#3 ] + [5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@5/(byte~) main::i#5 ) [ main::i#2 main::j#3 ] + [6] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 main::j#3 ] + [7] (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 [ main::i#2 main::j#3 main::$0 ] + [8] *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::i#2 main::j#3 ] + [9] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] + [10] if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@6 [ main::i#2 main::j#1 ] + to:main::@3 +main::@3: scope:[main] from main::@1 + [11] phi() [ main::i#2 ] + to:main::@2 +main::@2: scope:[main] from main::@3 main::@6 + [12] (byte) main::j#4 ← phi( main::@6/(byte~) main::j#6 main::@3/(byte/signed byte/word/signed word) 0 ) [ main::i#2 main::j#4 ] + [13] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::j#4 main::i#1 ] + [14] if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@5 [ main::j#4 main::i#1 ] + to:main::@return +main::@return: scope:[main] from main::@2 + [15] return [ ] + to:@return +main::@5: scope:[main] from main::@2 + [16] (byte~) main::i#5 ← (byte) main::i#1 [ main::i#5 main::j#4 ] + [17] (byte~) main::j#5 ← (byte) main::j#4 [ main::i#5 main::j#5 ] + to:main::@1 +main::@6: scope:[main] from main::@1 + [18] (byte~) main::j#6 ← (byte) main::j#1 [ main::i#2 main::j#6 ] + to:main::@2 + +Created 3 initial phi equivalence classes +Coalesced [16] main::i#5 ← main::i#1 +Coalesced [17] main::j#5 ← main::j#4 +Coalesced [18] main::j#6 ← main::j#1 +Coalesced down to 2 phi equivalence classes +Culled Empty Block (label) main::@3 +Culled Empty Block (label) main::@5 +Not culling empty block because it shares successor with its predecessor. (label) main::@6 +Block Sequence Planned @begin @1 @end main main::@1 main::@2 main::@return main::@6 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +Adding NOP phi() at start of main::@6 +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +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] phi() [ ] + to:main::@1 +main::@1: scope:[main] from main main::@2 + [5] (byte) main::j#3 ← phi( main/(byte/signed byte/word/signed word) 0 main::@2/(byte) main::j#4 ) [ main::i#2 main::j#3 ] + [5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@2/(byte) main::i#1 ) [ main::i#2 main::j#3 ] + [6] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 main::j#3 ] + [7] (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 [ main::i#2 main::j#3 main::$0 ] + [8] *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::i#2 main::j#3 ] + [9] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] + [10] if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@6 [ main::i#2 main::j#1 ] + to:main::@2 +main::@2: scope:[main] from main::@1 main::@6 + [11] (byte) main::j#4 ← phi( main::@6/(byte) main::j#1 main::@1/(byte/signed byte/word/signed word) 0 ) [ main::i#2 main::j#4 ] + [12] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 main::j#4 ] + [13] if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 [ main::i#1 main::j#4 ] + to:main::@return +main::@return: scope:[main] from main::@2 + [14] return [ ] + to:@return +main::@6: scope:[main] from main::@1 + [15] phi() [ main::i#2 main::j#1 ] + to:main::@2 + +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] phi() [ ] ( main:2 [ ] ) + to:main::@1 +main::@1: scope:[main] from main main::@2 + [5] (byte) main::j#3 ← phi( main/(byte/signed byte/word/signed word) 0 main::@2/(byte) main::j#4 ) [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) + [5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@2/(byte) main::i#1 ) [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) + [6] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) + [7] (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 [ main::i#2 main::j#3 main::$0 ] ( main:2 [ main::i#2 main::j#3 main::$0 ] ) + [8] *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) + [9] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) + [10] if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@6 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) + to:main::@2 +main::@2: scope:[main] from main::@1 main::@6 + [11] (byte) main::j#4 ← phi( main::@6/(byte) main::j#1 main::@1/(byte/signed byte/word/signed word) 0 ) [ main::i#2 main::j#4 ] ( main:2 [ main::i#2 main::j#4 ] ) + [12] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) + [13] if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) + to:main::@return +main::@return: scope:[main] from main::@2 + [14] return [ ] ( main:2 [ ] ) + to:@return +main::@6: scope:[main] from main::@1 + [15] phi() [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) + to:main::@2 + +DOMINATORS +@begin dominated by @begin +@1 dominated by @1 @begin +@end dominated by @1 @begin @end +main dominated by @1 @begin main +main::@1 dominated by @1 @begin main::@1 main +main::@2 dominated by @1 @begin main::@1 main::@2 main +main::@return dominated by main::@return @1 @begin main::@1 main::@2 main +main::@6 dominated by @1 @begin main::@1 main main::@6 + +Found back edge: Loop head: main::@1 tails: main::@2 blocks: null +Populated: Loop head: main::@1 tails: main::@2 blocks: main::@2 main::@1 main::@6 +NATURAL LOOPS +Loop head: main::@1 tails: main::@2 blocks: main::@2 main::@1 main::@6 + +Found 0 loops in scope [] +Found 1 loops in scope [main] + Loop head: main::@1 tails: main::@2 blocks: main::@2 main::@1 main::@6 +NATURAL LOOPS WITH DEPTH +Loop head: main::@1 tails: main::@2 blocks: main::@2 main::@1 main::@6 depth: 1 + + +VARIABLE REGISTER WEIGHTS +(byte) GREEN +(byte) RED +(byte) WHITE +(void()) main() +(byte~) main::$0 22.0 +(byte*) main::cols +(byte[]) main::colseq +(byte) main::i +(byte) main::i#1 16.5 +(byte) main::i#2 5.5 +(byte) main::j +(byte) main::j#1 11.0 +(byte) main::j#3 8.25 +(byte) main::j#4 7.333333333333333 +(byte*) main::screen + +Initial phi equivalence classes +[ main::i#2 main::i#1 ] +[ main::j#3 main::j#4 main::j#1 ] +Added variable main::$0 to zero page equivalence class [ main::$0 ] +Complete equivalence classes +[ main::i#2 main::i#1 ] +[ main::j#3 main::j#4 main::j#1 ] +[ main::$0 ] +Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ] +Allocated zp ZP_BYTE:3 [ main::j#3 main::j#4 main::j#1 ] +Allocated zp ZP_BYTE:4 [ main::$0 ] +INITIAL ASM +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const WHITE = 1 + .const RED = 2 + .const GREEN = 5 +//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 [ ] ( ) +//SEG6 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG8 @end +bend: +//SEG9 main +main: { + .const screen = $400 + .const cols = $d800 + .label _0 = 4 + .label j = 3 + .label i = 2 + //SEG10 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG11 [5] phi (byte) main::j#3 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 + lda #0 + sta j + //SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1 + lda #0 + sta i + jmp b1 + //SEG13 [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + b1_from_b2: + //SEG14 [5] phi (byte) main::j#3 = (byte) main::j#4 [phi:main::@2->main::@1#0] -- register_copy + //SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#1] -- register_copy + jmp b1 + //SEG16 main::@1 + b1: + //SEG17 [6] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuz1=vbuc2 + lda #'*' + ldx i + sta screen,x + //SEG18 [7] (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 [ main::i#2 main::j#3 main::$0 ] ( main:2 [ main::i#2 main::j#3 main::$0 ] ) -- vbuz1=pbuc1_derefidx_vbuz2 + ldx j + lda colseq,x + sta _0 + //SEG19 [8] *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuz1=vbuz2 + lda _0 + ldx i + sta cols,x + //SEG20 [9] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuz1=_inc_vbuz1 + inc j + //SEG21 [10] if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@6 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuz1_neq_vbuc1_then_la1 + lda j + cmp #3 + bne b6_from_b1 + //SEG22 [11] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + b2_from_b1: + //SEG23 [11] phi (byte) main::j#4 = (byte/signed byte/word/signed word) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1 + lda #0 + sta j + jmp b2 + //SEG24 main::@2 + b2: + //SEG25 [12] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuz1=_inc_vbuz1 + inc i + //SEG26 [13] if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuz1_neq_vbuc1_then_la1 + lda i + cmp #$28 + bne b1_from_b2 + jmp breturn + //SEG27 main::@return + breturn: + //SEG28 [14] return [ ] ( main:2 [ ] ) + rts + //SEG29 [15] phi from main::@1 to main::@6 [phi:main::@1->main::@6] + b6_from_b1: + jmp b6 + //SEG30 main::@6 + b6: + //SEG31 [11] phi from main::@6 to main::@2 [phi:main::@6->main::@2] + b2_from_b6: + //SEG32 [11] phi (byte) main::j#4 = (byte) main::j#1 [phi:main::@6->main::@2#0] -- register_copy + jmp b2 + colseq: .byte WHITE, RED, GREEN +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [6] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ] +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::j#3 main::j#4 main::j#1 ] +Statement [6] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) always clobbers reg byte a +Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:3 [ main::j#3 main::j#4 main::j#1 ] : zp ZP_BYTE:3 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:4 [ main::$0 ] : zp ZP_BYTE:4 , reg byte a , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 26.58: zp ZP_BYTE:3 [ main::j#3 main::j#4 main::j#1 ] 22: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:4 [ main::$0 ] +Uplift Scope [] + +Uplifting [main] best 553 combination reg byte y [ main::j#3 main::j#4 main::j#1 ] reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$0 ] +Uplifting [] best 553 combination +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp b2 +Removing instruction jmp breturn +Removing instruction jmp b6 +Succesful ASM optimization Pass5NextJumpElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const WHITE = 1 + .const RED = 2 + .const GREEN = 5 +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: +//SEG4 @1 +b1: +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: +//SEG8 @end +bend: +//SEG9 main +main: { + .const screen = $400 + .const cols = $d800 + //SEG10 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG11 [5] phi (byte) main::j#3 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- vbuyy=vbuc1 + ldy #0 + //SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1 + ldx #0 + jmp b1 + //SEG13 [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + b1_from_b2: + //SEG14 [5] phi (byte) main::j#3 = (byte) main::j#4 [phi:main::@2->main::@1#0] -- register_copy + //SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#1] -- register_copy + //SEG16 main::@1 + b1: + //SEG17 [6] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuxx=vbuc2 + lda #'*' + sta screen,x + //SEG18 [7] (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 [ main::i#2 main::j#3 main::$0 ] ( main:2 [ main::i#2 main::j#3 main::$0 ] ) -- vbuaa=pbuc1_derefidx_vbuyy + lda colseq,y + //SEG19 [8] *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuxx=vbuaa + sta cols,x + //SEG20 [9] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuyy=_inc_vbuyy + iny + //SEG21 [10] if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@6 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuyy_neq_vbuc1_then_la1 + cpy #3 + bne b6_from_b1 + //SEG22 [11] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + b2_from_b1: + //SEG23 [11] phi (byte) main::j#4 = (byte/signed byte/word/signed word) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1 + ldy #0 + //SEG24 main::@2 + b2: + //SEG25 [12] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuxx=_inc_vbuxx + inx + //SEG26 [13] if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuxx_neq_vbuc1_then_la1 + cpx #$28 + bne b1_from_b2 + //SEG27 main::@return + breturn: + //SEG28 [14] return [ ] ( main:2 [ ] ) + rts + //SEG29 [15] phi from main::@1 to main::@6 [phi:main::@1->main::@6] + b6_from_b1: + //SEG30 main::@6 + b6: + //SEG31 [11] phi from main::@6 to main::@2 [phi:main::@6->main::@2] + b2_from_b6: + //SEG32 [11] phi (byte) main::j#4 = (byte) main::j#1 [phi:main::@6->main::@2#0] -- register_copy + jmp b2 + colseq: .byte WHITE, RED, GREEN +} + +Replacing label b6_from_b1 with b6 +Replacing label b1_from_b2 with b1 +Removing instruction bbegin: +Removing instruction b1_from_bbegin: +Removing instruction main_from_b1: +Removing instruction bend_from_b1: +Removing instruction b1_from_b2: +Removing instruction b6_from_b1: +Removing instruction b2_from_b6: +Succesful ASM optimization Pass5RedundantLabelElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const WHITE = 1 + .const RED = 2 + .const GREEN = 5 +//SEG2 @begin +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 @1 +b1: +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @1 to main [phi:@1->main] + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +bend: +//SEG9 main +main: { + .const screen = $400 + .const cols = $d800 + //SEG10 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG11 [5] phi (byte) main::j#3 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- vbuyy=vbuc1 + ldy #0 + //SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1 + ldx #0 + jmp b1 + //SEG13 [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + //SEG14 [5] phi (byte) main::j#3 = (byte) main::j#4 [phi:main::@2->main::@1#0] -- register_copy + //SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#1] -- register_copy + //SEG16 main::@1 + b1: + //SEG17 [6] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuxx=vbuc2 + lda #'*' + sta screen,x + //SEG18 [7] (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 [ main::i#2 main::j#3 main::$0 ] ( main:2 [ main::i#2 main::j#3 main::$0 ] ) -- vbuaa=pbuc1_derefidx_vbuyy + lda colseq,y + //SEG19 [8] *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuxx=vbuaa + sta cols,x + //SEG20 [9] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuyy=_inc_vbuyy + iny + //SEG21 [10] if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@6 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuyy_neq_vbuc1_then_la1 + cpy #3 + bne b6 + //SEG22 [11] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + b2_from_b1: + //SEG23 [11] phi (byte) main::j#4 = (byte/signed byte/word/signed word) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1 + ldy #0 + //SEG24 main::@2 + b2: + //SEG25 [12] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuxx=_inc_vbuxx + inx + //SEG26 [13] if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuxx_neq_vbuc1_then_la1 + cpx #$28 + bne b1 + //SEG27 main::@return + breturn: + //SEG28 [14] return [ ] ( main:2 [ ] ) + rts + //SEG29 [15] phi from main::@1 to main::@6 [phi:main::@1->main::@6] + //SEG30 main::@6 + b6: + //SEG31 [11] phi from main::@6 to main::@2 [phi:main::@6->main::@2] + //SEG32 [11] phi (byte) main::j#4 = (byte) main::j#1 [phi:main::@6->main::@2#0] -- register_copy + jmp b2 + colseq: .byte WHITE, RED, GREEN +} + +Removing instruction b1: +Removing instruction bend: +Removing instruction b1_from_main: +Removing instruction b2_from_b1: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const WHITE = 1 + .const RED = 2 + .const GREEN = 5 +//SEG2 @begin +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 @1 +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @1 to main [phi:@1->main] + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main +main: { + .const screen = $400 + .const cols = $d800 + //SEG10 [5] phi from main to main::@1 [phi:main->main::@1] + //SEG11 [5] phi (byte) main::j#3 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- vbuyy=vbuc1 + ldy #0 + //SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1 + ldx #0 + jmp b1 + //SEG13 [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + //SEG14 [5] phi (byte) main::j#3 = (byte) main::j#4 [phi:main::@2->main::@1#0] -- register_copy + //SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#1] -- register_copy + //SEG16 main::@1 + b1: + //SEG17 [6] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuxx=vbuc2 + lda #'*' + sta screen,x + //SEG18 [7] (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 [ main::i#2 main::j#3 main::$0 ] ( main:2 [ main::i#2 main::j#3 main::$0 ] ) -- vbuaa=pbuc1_derefidx_vbuyy + lda colseq,y + //SEG19 [8] *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuxx=vbuaa + sta cols,x + //SEG20 [9] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuyy=_inc_vbuyy + iny + //SEG21 [10] if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@6 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuyy_neq_vbuc1_then_la1 + cpy #3 + bne b6 + //SEG22 [11] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + //SEG23 [11] phi (byte) main::j#4 = (byte/signed byte/word/signed word) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1 + ldy #0 + //SEG24 main::@2 + b2: + //SEG25 [12] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuxx=_inc_vbuxx + inx + //SEG26 [13] if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuxx_neq_vbuc1_then_la1 + cpx #$28 + bne b1 + //SEG27 main::@return + //SEG28 [14] return [ ] ( main:2 [ ] ) + rts + //SEG29 [15] phi from main::@1 to main::@6 [phi:main::@1->main::@6] + //SEG30 main::@6 + b6: + //SEG31 [11] phi from main::@6 to main::@2 [phi:main::@6->main::@2] + //SEG32 [11] phi (byte) main::j#4 = (byte) main::j#1 [phi:main::@6->main::@2#0] -- register_copy + jmp b2 + colseq: .byte WHITE, RED, GREEN +} + +Skipping double jump to b2 in bne b6 +Succesful ASM optimization Pass5DoubleJumpElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const WHITE = 1 + .const RED = 2 + .const GREEN = 5 +//SEG2 @begin +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 @1 +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @1 to main [phi:@1->main] + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main +main: { + .const screen = $400 + .const cols = $d800 + //SEG10 [5] phi from main to main::@1 [phi:main->main::@1] + //SEG11 [5] phi (byte) main::j#3 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- vbuyy=vbuc1 + ldy #0 + //SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1 + ldx #0 + jmp b1 + //SEG13 [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + //SEG14 [5] phi (byte) main::j#3 = (byte) main::j#4 [phi:main::@2->main::@1#0] -- register_copy + //SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#1] -- register_copy + //SEG16 main::@1 + b1: + //SEG17 [6] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuxx=vbuc2 + lda #'*' + sta screen,x + //SEG18 [7] (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 [ main::i#2 main::j#3 main::$0 ] ( main:2 [ main::i#2 main::j#3 main::$0 ] ) -- vbuaa=pbuc1_derefidx_vbuyy + lda colseq,y + //SEG19 [8] *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuxx=vbuaa + sta cols,x + //SEG20 [9] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuyy=_inc_vbuyy + iny + //SEG21 [10] if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@6 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuyy_neq_vbuc1_then_la1 + cpy #3 + bne b2 + //SEG22 [11] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + //SEG23 [11] phi (byte) main::j#4 = (byte/signed byte/word/signed word) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1 + ldy #0 + //SEG24 main::@2 + b2: + //SEG25 [12] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuxx=_inc_vbuxx + inx + //SEG26 [13] if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuxx_neq_vbuc1_then_la1 + cpx #$28 + bne b1 + //SEG27 main::@return + //SEG28 [14] return [ ] ( main:2 [ ] ) + rts + //SEG29 [15] phi from main::@1 to main::@6 [phi:main::@1->main::@6] + //SEG30 main::@6 + b6: + //SEG31 [11] phi from main::@6 to main::@2 [phi:main::@6->main::@2] + //SEG32 [11] phi (byte) main::j#4 = (byte) main::j#1 [phi:main::@6->main::@2#0] -- register_copy + jmp b2 + colseq: .byte WHITE, RED, GREEN +} + +Removing instruction jmp b1 +Succesful ASM optimization Pass5NextJumpElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const WHITE = 1 + .const RED = 2 + .const GREEN = 5 +//SEG2 @begin +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 @1 +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @1 to main [phi:@1->main] + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main +main: { + .const screen = $400 + .const cols = $d800 + //SEG10 [5] phi from main to main::@1 [phi:main->main::@1] + //SEG11 [5] phi (byte) main::j#3 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- vbuyy=vbuc1 + ldy #0 + //SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1 + ldx #0 + //SEG13 [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + //SEG14 [5] phi (byte) main::j#3 = (byte) main::j#4 [phi:main::@2->main::@1#0] -- register_copy + //SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#1] -- register_copy + //SEG16 main::@1 + b1: + //SEG17 [6] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuxx=vbuc2 + lda #'*' + sta screen,x + //SEG18 [7] (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 [ main::i#2 main::j#3 main::$0 ] ( main:2 [ main::i#2 main::j#3 main::$0 ] ) -- vbuaa=pbuc1_derefidx_vbuyy + lda colseq,y + //SEG19 [8] *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuxx=vbuaa + sta cols,x + //SEG20 [9] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuyy=_inc_vbuyy + iny + //SEG21 [10] if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@6 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuyy_neq_vbuc1_then_la1 + cpy #3 + bne b2 + //SEG22 [11] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + //SEG23 [11] phi (byte) main::j#4 = (byte/signed byte/word/signed word) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1 + ldy #0 + //SEG24 main::@2 + b2: + //SEG25 [12] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuxx=_inc_vbuxx + inx + //SEG26 [13] if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuxx_neq_vbuc1_then_la1 + cpx #$28 + bne b1 + //SEG27 main::@return + //SEG28 [14] return [ ] ( main:2 [ ] ) + rts + //SEG29 [15] phi from main::@1 to main::@6 [phi:main::@1->main::@6] + //SEG30 main::@6 + b6: + //SEG31 [11] phi from main::@6 to main::@2 [phi:main::@6->main::@2] + //SEG32 [11] phi (byte) main::j#4 = (byte) main::j#1 [phi:main::@6->main::@2#0] -- register_copy + jmp b2 + colseq: .byte WHITE, RED, GREEN +} + +Removing instruction b6: +Succesful ASM optimization Pass5UnusedLabelElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const WHITE = 1 + .const RED = 2 + .const GREEN = 5 +//SEG2 @begin +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 @1 +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @1 to main [phi:@1->main] + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main +main: { + .const screen = $400 + .const cols = $d800 + //SEG10 [5] phi from main to main::@1 [phi:main->main::@1] + //SEG11 [5] phi (byte) main::j#3 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- vbuyy=vbuc1 + ldy #0 + //SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1 + ldx #0 + //SEG13 [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + //SEG14 [5] phi (byte) main::j#3 = (byte) main::j#4 [phi:main::@2->main::@1#0] -- register_copy + //SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#1] -- register_copy + //SEG16 main::@1 + b1: + //SEG17 [6] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuxx=vbuc2 + lda #'*' + sta screen,x + //SEG18 [7] (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 [ main::i#2 main::j#3 main::$0 ] ( main:2 [ main::i#2 main::j#3 main::$0 ] ) -- vbuaa=pbuc1_derefidx_vbuyy + lda colseq,y + //SEG19 [8] *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuxx=vbuaa + sta cols,x + //SEG20 [9] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuyy=_inc_vbuyy + iny + //SEG21 [10] if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@6 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuyy_neq_vbuc1_then_la1 + cpy #3 + bne b2 + //SEG22 [11] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + //SEG23 [11] phi (byte) main::j#4 = (byte/signed byte/word/signed word) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1 + ldy #0 + //SEG24 main::@2 + b2: + //SEG25 [12] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuxx=_inc_vbuxx + inx + //SEG26 [13] if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuxx_neq_vbuc1_then_la1 + cpx #$28 + bne b1 + //SEG27 main::@return + //SEG28 [14] return [ ] ( main:2 [ ] ) + rts + //SEG29 [15] phi from main::@1 to main::@6 [phi:main::@1->main::@6] + //SEG30 main::@6 + //SEG31 [11] phi from main::@6 to main::@2 [phi:main::@6->main::@2] + //SEG32 [11] phi (byte) main::j#4 = (byte) main::j#1 [phi:main::@6->main::@2#0] -- register_copy + jmp b2 + colseq: .byte WHITE, RED, GREEN +} + +Removing unreachable instruction jmp b2 +Succesful ASM optimization Pass5UnreachableCodeElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const WHITE = 1 + .const RED = 2 + .const GREEN = 5 +//SEG2 @begin +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 @1 +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @1 to main [phi:@1->main] + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main +main: { + .const screen = $400 + .const cols = $d800 + //SEG10 [5] phi from main to main::@1 [phi:main->main::@1] + //SEG11 [5] phi (byte) main::j#3 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- vbuyy=vbuc1 + ldy #0 + //SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1 + ldx #0 + //SEG13 [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + //SEG14 [5] phi (byte) main::j#3 = (byte) main::j#4 [phi:main::@2->main::@1#0] -- register_copy + //SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#1] -- register_copy + //SEG16 main::@1 + b1: + //SEG17 [6] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuxx=vbuc2 + lda #'*' + sta screen,x + //SEG18 [7] (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 [ main::i#2 main::j#3 main::$0 ] ( main:2 [ main::i#2 main::j#3 main::$0 ] ) -- vbuaa=pbuc1_derefidx_vbuyy + lda colseq,y + //SEG19 [8] *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuxx=vbuaa + sta cols,x + //SEG20 [9] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuyy=_inc_vbuyy + iny + //SEG21 [10] if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@6 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuyy_neq_vbuc1_then_la1 + cpy #3 + bne b2 + //SEG22 [11] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + //SEG23 [11] phi (byte) main::j#4 = (byte/signed byte/word/signed word) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1 + ldy #0 + //SEG24 main::@2 + b2: + //SEG25 [12] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuxx=_inc_vbuxx + inx + //SEG26 [13] if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuxx_neq_vbuc1_then_la1 + cpx #$28 + bne b1 + //SEG27 main::@return + //SEG28 [14] return [ ] ( main:2 [ ] ) + rts + //SEG29 [15] phi from main::@1 to main::@6 [phi:main::@1->main::@6] + //SEG30 main::@6 + //SEG31 [11] phi from main::@6 to main::@2 [phi:main::@6->main::@2] + //SEG32 [11] phi (byte) main::j#4 = (byte) main::j#1 [phi:main::@6->main::@2#0] -- register_copy + colseq: .byte WHITE, RED, GREEN +} + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(byte) GREEN +(const byte) GREEN#0 GREEN = (byte/signed byte/word/signed word) 5 +(byte) RED +(const byte) RED#0 RED = (byte/signed byte/word/signed word) 2 +(byte) WHITE +(const byte) WHITE#0 WHITE = (byte/signed byte/word/signed word) 1 +(void()) main() +(byte~) main::$0 reg byte a 22.0 +(label) main::@1 +(label) main::@2 +(label) main::@6 +(label) main::@return +(byte*) main::cols +(const byte*) main::cols#0 cols = ((byte*))(word) 55296 +(byte[]) main::colseq +(const byte[]) main::colseq#0 colseq = { (const byte) WHITE#0, (const byte) RED#0, (const byte) GREEN#0 } +(byte) main::i +(byte) main::i#1 reg byte x 16.5 +(byte) main::i#2 reg byte x 5.5 +(byte) main::j +(byte) main::j#1 reg byte y 11.0 +(byte) main::j#3 reg byte y 8.25 +(byte) main::j#4 reg byte y 7.333333333333333 +(byte*) main::screen +(const byte*) main::screen#0 screen = ((byte*))(word/signed word) 1024 + +reg byte x [ main::i#2 main::i#1 ] +reg byte y [ main::j#3 main::j#4 main::j#1 ] +reg byte a [ main::$0 ] + +FINAL CODE +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const WHITE = 1 + .const RED = 2 + .const GREEN = 5 +//SEG2 @begin +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 @1 +//SEG5 [2] call main param-assignment [ ] ( ) +//SEG6 [4] phi from @1 to main [phi:@1->main] + jsr main +//SEG7 [3] phi from @1 to @end [phi:@1->@end] +//SEG8 @end +//SEG9 main +main: { + .const screen = $400 + .const cols = $d800 + //SEG10 [5] phi from main to main::@1 [phi:main->main::@1] + //SEG11 [5] phi (byte) main::j#3 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- vbuyy=vbuc1 + ldy #0 + //SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1 + ldx #0 + //SEG13 [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + //SEG14 [5] phi (byte) main::j#3 = (byte) main::j#4 [phi:main::@2->main::@1#0] -- register_copy + //SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#1] -- register_copy + //SEG16 main::@1 + b1: + //SEG17 [6] *((const byte*) main::screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuxx=vbuc2 + lda #'*' + sta screen,x + //SEG18 [7] (byte~) main::$0 ← (const byte[]) main::colseq#0 *idx (byte) main::j#3 [ main::i#2 main::j#3 main::$0 ] ( main:2 [ main::i#2 main::j#3 main::$0 ] ) -- vbuaa=pbuc1_derefidx_vbuyy + lda colseq,y + //SEG19 [8] *((const byte*) main::cols#0 + (byte) main::i#2) ← (byte~) main::$0 [ main::i#2 main::j#3 ] ( main:2 [ main::i#2 main::j#3 ] ) -- pbuc1_derefidx_vbuxx=vbuaa + sta cols,x + //SEG20 [9] (byte) main::j#1 ← ++ (byte) main::j#3 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuyy=_inc_vbuyy + iny + //SEG21 [10] if((byte) main::j#1!=(byte/signed byte/word/signed word) 3) goto main::@6 [ main::i#2 main::j#1 ] ( main:2 [ main::i#2 main::j#1 ] ) -- vbuyy_neq_vbuc1_then_la1 + cpy #3 + bne b2 + //SEG22 [11] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + //SEG23 [11] phi (byte) main::j#4 = (byte/signed byte/word/signed word) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1 + ldy #0 + //SEG24 main::@2 + b2: + //SEG25 [12] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuxx=_inc_vbuxx + inx + //SEG26 [13] if((byte) main::i#1!=(byte/signed byte/word/signed word) 40) goto main::@1 [ main::i#1 main::j#4 ] ( main:2 [ main::i#1 main::j#4 ] ) -- vbuxx_neq_vbuc1_then_la1 + cpx #$28 + bne b1 + //SEG27 main::@return + //SEG28 [14] return [ ] ( main:2 [ ] ) + rts + //SEG29 [15] phi from main::@1 to main::@6 [phi:main::@1->main::@6] + //SEG30 main::@6 + //SEG31 [11] phi from main::@6 to main::@2 [phi:main::@6->main::@2] + //SEG32 [11] phi (byte) main::j#4 = (byte) main::j#1 [phi:main::@6->main::@2#0] -- register_copy + colseq: .byte WHITE, RED, GREEN +} + diff --git a/src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.sym b/src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.sym new file mode 100644 index 000000000..6c6ee87e2 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/inmem-const-array.sym @@ -0,0 +1,32 @@ +(label) @1 +(label) @begin +(label) @end +(byte) GREEN +(const byte) GREEN#0 GREEN = (byte/signed byte/word/signed word) 5 +(byte) RED +(const byte) RED#0 RED = (byte/signed byte/word/signed word) 2 +(byte) WHITE +(const byte) WHITE#0 WHITE = (byte/signed byte/word/signed word) 1 +(void()) main() +(byte~) main::$0 reg byte a 22.0 +(label) main::@1 +(label) main::@2 +(label) main::@6 +(label) main::@return +(byte*) main::cols +(const byte*) main::cols#0 cols = ((byte*))(word) 55296 +(byte[]) main::colseq +(const byte[]) main::colseq#0 colseq = { (const byte) WHITE#0, (const byte) RED#0, (const byte) GREEN#0 } +(byte) main::i +(byte) main::i#1 reg byte x 16.5 +(byte) main::i#2 reg byte x 5.5 +(byte) main::j +(byte) main::j#1 reg byte y 11.0 +(byte) main::j#3 reg byte y 8.25 +(byte) main::j#4 reg byte y 7.333333333333333 +(byte*) main::screen +(const byte*) main::screen#0 screen = ((byte*))(word/signed word) 1024 + +reg byte x [ main::i#2 main::i#1 ] +reg byte y [ main::j#3 main::j#4 main::j#1 ] +reg byte a [ main::$0 ]