diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragment.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstance.java similarity index 98% rename from src/main/java/dk/camelot64/kickc/fragment/AsmFragment.java rename to src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstance.java index 0b1f54343..87d3191a5 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragment.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstance.java @@ -10,7 +10,7 @@ import java.util.ArrayList; import java.util.Map; /** ASM Code Fragment with register/variable bindings that can be used for generating ASM code for a specific statement . */ -public class AsmFragment { +public class AsmFragmentInstance { /** The symbol table. */ private Program program; @@ -27,7 +27,7 @@ public class AsmFragment { /** The scope containing the fragment. Used when referencing symbols defined in other scopes. */ private ScopeRef codeScopeRef; - public AsmFragment( + public AsmFragmentInstance( Program program, String name, ScopeRef codeScopeRef, @@ -134,9 +134,9 @@ public class AsmFragment { private String name; private AsmProgram program; - private AsmFragment bindings; + private AsmFragmentInstance bindings; - public AsmSequenceGenerator(String name, AsmFragment bindings, AsmProgram program) { + public AsmSequenceGenerator(String name, AsmFragmentInstance bindings, AsmProgram program) { this.name = name; this.bindings = bindings; this.program = program; diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentSignature.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java similarity index 88% rename from src/main/java/dk/camelot64/kickc/fragment/AsmFragmentSignature.java rename to src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java index 35ee1722b..d9f00f7f5 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentSignature.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java @@ -6,9 +6,9 @@ import java.util.LinkedHashMap; import java.util.Map; /** - * A fragment signature generated from a {@link Statement} used to load/synthesize an AsmFragent for creating ASM code for the statement + * A fragment specification generated from a {@link Statement} used to load/synthesize an {@link AsmFragmentInstance} for creating ASM code for the statement */ -public class AsmFragmentSignature { +public class AsmFragmentInstanceSpec { /** * The symbol table. @@ -16,7 +16,7 @@ public class AsmFragmentSignature { private Program program; /** - * The string signature/name of the fragment fragment. + * The string signature/name of the fragment template. */ private String signature; @@ -37,7 +37,7 @@ public class AsmFragmentSignature { private int nextConstByteIdx = 1; private int nextLabelIdx = 1; - public AsmFragmentSignature( + public AsmFragmentInstanceSpec( StatementConditionalJump conditionalJump, ControlFlowBlock block, Program program, @@ -49,7 +49,7 @@ public class AsmFragmentSignature { setSignature(conditionalJumpSignature); } - public AsmFragmentSignature(StatementAssignment assignment, Program program) { + public AsmFragmentInstanceSpec(StatementAssignment assignment, Program program) { this.codeScopeRef = program.getStatementInfos().getBlock(assignment).getScope(); this.bindings = new LinkedHashMap<>(); this.program = program; @@ -60,14 +60,14 @@ public class AsmFragmentSignature { assignment.getrValue2())); } - public AsmFragmentSignature(LValue lValue, RValue rValue, Program program, ScopeRef codeScopeRef) { + public AsmFragmentInstanceSpec(LValue lValue, RValue rValue, Program program, ScopeRef codeScopeRef) { this.codeScopeRef = codeScopeRef; this.bindings = new LinkedHashMap<>(); this.program = program; setSignature(assignmentSignature(lValue, null, null, rValue)); } - public AsmFragmentSignature(StatementAssignment assignment, StatementAssignment assignmentAlu, Program program) { + public AsmFragmentInstanceSpec(StatementAssignment assignment, StatementAssignment assignmentAlu, Program program) { this.codeScopeRef = program.getStatementInfos().getBlock(assignment).getScope(); this.bindings = new LinkedHashMap<>(); this.program = program; @@ -81,14 +81,14 @@ public class AsmFragmentSignature { private String assignmentWithAluSignature(StatementAssignment assignment, StatementAssignment assignmentAlu) { this.codeScopeRef = program.getStatementInfos().getBlock(assignment).getScope(); if(!(assignment.getrValue2() instanceof VariableRef)) { - throw new AsmFragment.AluNotApplicableException("Error! ALU register only allowed as rValue2. " + assignment); + throw new AsmFragmentInstance.AluNotApplicableException("Error! ALU register only allowed as rValue2. " + assignment); } VariableRef assignmentRValue2 = (VariableRef) assignment.getrValue2(); Variable assignmentRValue2Var = program.getSymbolInfos().getVariable(assignmentRValue2); Registers.Register rVal2Register = assignmentRValue2Var.getAllocation(); if(!rVal2Register.getType().equals(Registers.RegisterType.REG_ALU)) { - throw new AsmFragment.AluNotApplicableException("Error! ALU register only allowed as rValue2. " + assignment); + throw new AsmFragmentInstance.AluNotApplicableException("Error! ALU register only allowed as rValue2. " + assignment); } StringBuilder signature = new StringBuilder(); signature.append(bind(assignment.getlValue())); @@ -309,7 +309,7 @@ public class AsmFragmentSignature { } else if(Registers.RegisterType.REG_Y_BYTE.equals(register.getType())) { return "yy"; } else if(Registers.RegisterType.REG_ALU.equals(register.getType())) { - throw new AsmFragment.AluNotApplicableException(); + throw new AsmFragmentInstance.AluNotApplicableException(); } else { throw new RuntimeException("Not implemented " + register.getType()); } @@ -363,4 +363,24 @@ public class AsmFragmentSignature { str.append(") "); return str.toString(); } + + @Override + public boolean equals(Object o) { + if(this == o) return true; + if(o == null || getClass() != o.getClass()) return false; + + AsmFragmentInstanceSpec that = (AsmFragmentInstanceSpec) o; + + if(signature != null ? !signature.equals(that.signature) : that.signature != null) return false; + if(bindings != null ? !bindings.equals(that.bindings) : that.bindings != null) return false; + return codeScopeRef != null ? codeScopeRef.equals(that.codeScopeRef) : that.codeScopeRef == null; + } + + @Override + public int hashCode() { + int result = signature != null ? signature.hashCode() : 0; + result = 31 * result + (bindings != null ? bindings.hashCode() : 0); + result = 31 * result + (codeScopeRef != null ? codeScopeRef.hashCode() : 0); + return result; + } } diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentManager.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentManager.java deleted file mode 100644 index 0eeb6e57a..000000000 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentManager.java +++ /dev/null @@ -1,562 +0,0 @@ -package dk.camelot64.kickc.fragment; - -import dk.camelot64.kickc.CompileLog; -import dk.camelot64.kickc.asm.AsmProgram; -import org.antlr.v4.runtime.CharStream; -import org.antlr.v4.runtime.CharStreams; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.*; - -/** - * Provides fragments from their signature. - *

- * The first priority is loading a fragment file from the fragment-folder. - * If no fragment file is found for the signature the manager attempts to synthesise a fragment from another fragment. - */ -public class AsmFragmentManager { - - /** Cache for the best fragment templates. Maps signature to the best fragment template for the signature. */ - private static Map bestFragmentCache = new HashMap<>(); - - /** Caches all asm fragment templates for all encountered signatures. */ - private static Map> fragmentTemplateCache = new LinkedHashMap<>(); - - /** Special singleton representing that the fragment can not be synthesized or loaded. */ - private static AsmFragmentTemplate UNKNOWN = new AsmFragmentTemplate("UNKNOWN", null); - /** - * All the synthesize rules available. - */ - private static List fragmentSyntheses; - - static Map> getFragmentTemplateCache() { - return fragmentTemplateCache; - } - - public static AsmFragment getFragment(AsmFragmentSignature signature, CompileLog log) { - AsmFragmentTemplate bestTemplate = bestFragmentCache.get(signature.getSignature()); - if(bestTemplate == UNKNOWN) { - if(log.isVerboseFragmentLog()) { - log.append("Unknown fragment " + signature.getSignature()); - } - throw new UnknownFragmentException(signature.getSignature()); - } - if(bestTemplate == null) { - AsmFragmentTemplateSynthesizer synthesizer = new AsmFragmentTemplateSynthesizer(signature.getSignature(), log); - List candidates = synthesizer.loadOrSynthesizeFragment(signature.getSignature(), new AsmSynthesisPath()); - if(candidates.size() == 0) { - if(log.isVerboseFragmentLog()) { - log.append("Unknown fragment " + signature.toString()); - } - bestFragmentCache.put(signature.getSignature(), UNKNOWN); - throw new UnknownFragmentException(signature.getSignature()); - } - double minScore = Double.MAX_VALUE; - double maxScore = Double.MIN_VALUE; - AsmFragmentTemplate maxTemplate = null; - for(AsmFragmentTemplate candidateTemplate : candidates) { - AsmFragment candidateFragment = new AsmFragment( - signature.getProgram(), - signature.getSignature(), - signature.getCodeScope(), - candidateTemplate, - signature.getBindings()); - AsmProgram candidateAsm = new AsmProgram(); - candidateAsm.startSegment(null, signature.toString()); - candidateFragment.generate(candidateAsm); - double score = candidateAsm.getCycles(); - if(score < minScore) { - minScore = score; - bestTemplate = candidateTemplate; - } - if(score > maxScore) { - maxScore = score; - maxTemplate = candidateTemplate; - } - } - if(log.isVerboseFragmentLog()) { - log.append("Found fragment " + bestTemplate.getName() + " score: " + minScore + " from " + candidates.size() + " candidates"); - } - bestFragmentCache.put(signature.getSignature(), bestTemplate); - } - // Count usages - AsmFragmentUsages.incUsage(bestTemplate); - // Return the resulting fragment instance - return new AsmFragment( - signature.getProgram(), - signature.getSignature(), - signature.getCodeScope(), - bestTemplate, - signature.getBindings()); - } - - /** - * Look for a fragment on the disk. - * - * @param signature The fragment signature - * @return The fragment file contents. Null if the fragment is not on the disk. - */ - private static CharStream loadFragment(String signature) { - ClassLoader classLoader = AsmFragmentManager.class.getClassLoader(); - URL fragmentUrl = classLoader.getResource("dk/camelot64/kickc/fragment/asm/" + signature + ".asm"); - if(fragmentUrl == null) { - return null; - } - try { - InputStream fragmentStream = fragmentUrl.openStream(); - return CharStreams.fromStream(fragmentStream); - } catch(IOException e) { - throw new RuntimeException("Error loading fragment file " + fragmentUrl); - } - } - - static File[] allFragmentFiles() { - ClassLoader classLoader = AsmFragmentManager.class.getClassLoader(); - String path = classLoader.getResource("dk/camelot64/kickc/fragment/asm/").getPath(); - return new File(path).listFiles((dir, name) -> name.endsWith(".asm")); - - } - - private static List getFragmentSyntheses() { - if(fragmentSyntheses == null) { - fragmentSyntheses = initFragmentSyntheses(); - } - return fragmentSyntheses; - } - - private static List initFragmentSyntheses() { - Map mapZ = new LinkedHashMap<>(); - mapZ.put("z2", "z1"); - mapZ.put("z3", "z2"); - Map mapZ2 = new LinkedHashMap<>(); - mapZ2.put("z3", "z1"); - Map mapZ3 = new LinkedHashMap<>(); - mapZ3.put("z3", "z2"); - Map mapC = new LinkedHashMap<>(); - mapC.put("c2", "c1"); - mapC.put("c3", "c2"); - Map mapC3 = new LinkedHashMap<>(); - mapC3.put("c3", "c2"); - Map mapZC = new LinkedHashMap<>(); - mapZC.putAll(mapZ); - mapZC.putAll(mapC); - Map mapSToU = new LinkedHashMap<>(); - mapSToU.put("vbsz1", "vbuz1"); - mapSToU.put("vbsz2", "vbuz2"); - mapSToU.put("vbsz3", "vbuz3"); - mapSToU.put("vbsc1", "vbuc1"); - mapSToU.put("vbsc2", "vbuc2"); - mapSToU.put("vbsc3", "vbuc3"); - mapSToU.put("vbsaa", "vbuaa"); - mapSToU.put("vbsxx", "vbuxx"); - mapSToU.put("vbsyy", "vbuyy"); - mapSToU.put("vwsz1", "vwuz1"); - mapSToU.put("vwsz2", "vwuz2"); - mapSToU.put("vwsz3", "vwuz3"); - mapSToU.put("vwsc1", "vwuc1"); - mapSToU.put("vwsc2", "vwuc2"); - mapSToU.put("vwsc3", "vwuc3"); - - List synths = new ArrayList<>(); - - // NEW STYLE REWRITES - Utilizes that all combinations are tried - - // Replace first AA with XX - synths.add(new AsmFragmentSynthesis("(.*vb.)aa(.*)", "...aa=.*|.*xx.*", "tax", "$1xx$2", null, null)); - // Replace two AAs with XX - synths.add(new AsmFragmentSynthesis("(.*vb.)aa(.*vb.)aa(.*)", "...aa=.*|.*xx.*", "tax", "$1xx$2xx$3", null, null)); - // Replace second (not first) AA with XX - synths.add(new AsmFragmentSynthesis("(.*)aa(.*vb.)aa(.*)", "...aa=.*|.*xx.*", "tax", "$1aa$2xx$3", null, null)); - - // Replace first AA with YY - synths.add(new AsmFragmentSynthesis("(.*vb.)aa(.*)", "...aa=.*|.*yy.*", "tay", "$1yy$2", null, null)); - // Replace two AAs with YY - synths.add(new AsmFragmentSynthesis("(.*vb.)aa(.*vb.)aa(.*)", "...aa=.*|.*yy.*", "tay", "$1yy$2yy$3", null, null)); - // Replace second (not first) AA with YY - synths.add(new AsmFragmentSynthesis("(.*)aa(.*vb.)aa(.*)", "...aa=.*|.*yy.*", "tay", "$1aa$2yy$3", null, null)); - - // Replace first XX with AA - synths.add(new AsmFragmentSynthesis("(.*vb.)xx(.*)", "...xx=.*|.*aa.*", "txa", "$1aa$2", null, null)); - // Replace two XXs with AA - synths.add(new AsmFragmentSynthesis("(.*vb.)xx(.*vb.)xx(.*)", "...xx=.*|.*aa.*", "txa", "$1aa$2aa$3", null, null)); - // Replace second (not first) XX with AA - synths.add(new AsmFragmentSynthesis("(.*)xx(.*vb.)xx(.*)", "...xx=.*|.*aa.*", "txa", "$1xx$2aa$3", null, null)); - - // Replace first YY with AA - synths.add(new AsmFragmentSynthesis("(.*vb.)yy(.*)", "...yy=.*|.*aa.*", "tya", "$1aa$2", null, null)); - // Replace two YYs with AA - synths.add(new AsmFragmentSynthesis("(.*vb.)yy(.*vb.)yy(.*)", "...yy=.*|.*aa.*", "tya", "$1aa$2aa$3", null, null)); - // Replace second (not first) YY with AA - synths.add(new AsmFragmentSynthesis("(.*)yy(.*vb.)yy(.*)", "...yy=.*|.*aa.*", "tya", "$1yy$2aa$3", null, null)); - - // Replace Z1 with AA (only one) - synths.add(new AsmFragmentSynthesis("(.*vb.)z1(.*)", "...z1=.*|.*z1.*z1.*|.*aa.*", "lda {z1}", "$1aa$2", null, mapZ)); - // Replace two Z1s with AA - synths.add(new AsmFragmentSynthesis("(.*vb.)z1(.*vb.)z1(.*)", "...z1=.*|.*z1.*z1.*z1.*|.*aa.*", "lda {z1}", "$1aa$2aa$3", null, mapZ)); - // Replace first (not second) Z1 with AA - synths.add(new AsmFragmentSynthesis("(.*vb.)z1(.*)z1(.*)", "...z1=.*|.*aa.*", "lda {z1}", "$1aa$2z1$3", null, null)); - // Replace second (not first) Z1 with AA - synths.add(new AsmFragmentSynthesis("(.*)z1(.*vb.)z1(.*)", "...z1=.*|.*aa.*", "lda {z1}", "$1z1$2aa$3", null, null)); - - // Replace Z1 with YY (only one) - synths.add(new AsmFragmentSynthesis("(.*vb.)z1(.*)", "...z1=.*|.*z1.*z1.*|.*yy.*", "ldy {z1}", "$1yy$2", null, mapZ)); - // Replace two Z1s with YY - synths.add(new AsmFragmentSynthesis("(.*vb.)z1(.*vb.)z1(.*)", "...z1=.*|.*z1.*z1.*z1.*|.*yy.*", "ldy {z1}", "$1yy$2yy$3", null, mapZ)); - // Replace first (not second) Z1 with YY - synths.add(new AsmFragmentSynthesis("(.*vb.)z1(.*)z1(.*)", "...z1=.*|.*yy.*", "ldy {z1}", "$1yy$2z1$3", null, null)); - // Replace second (not first) Z1 with YY - synths.add(new AsmFragmentSynthesis("(.*)z1(.*vb.)z1(.*)", "...z1=.*|.*yy.*", "ldy {z1}", "$1z1$2yy$3", null, null)); - - // Replace Z1 with XX (only one) - synths.add(new AsmFragmentSynthesis("(.*vb.)z1(.*)", "...z1=.*|.*z1.*z1.*|.*xx.*", "ldx {z1}", "$1xx$2", null, mapZ)); - // Replace two Z1s with XX - synths.add(new AsmFragmentSynthesis("(.*vb.)z1(.*vb.)z1(.*)", "...z1=.*|.*z1.*z1.*z1.*|.*xx.*", "ldx {z1}", "$1xx$2xx$3", null, mapZ)); - // Replace first (not second) Z1 with XX - synths.add(new AsmFragmentSynthesis("(.*vb.)z1(.*)z1(.*)", "...z1=.*|.*xx.*", "ldx {z1}", "$1xx$2z1$3", null, null)); - // Replace second (not first) Z1 with XX - synths.add(new AsmFragmentSynthesis("(.*)z1(.*vb.)z1(.*)", "...z1=.*|.*xx.*", "ldx {z1}", "$1z1$2xx$3", null, null)); - - // Replace Z2 with AA (only one) - synths.add(new AsmFragmentSynthesis("(.*vb.)z2(.*)", "...z2=.*|.*z2.*z2.*|.*aa.*", "lda {z2}", "$1aa$2", null, mapZ3)); - // Replace two Z2s with AA - synths.add(new AsmFragmentSynthesis("(.*vb.)z2(.*vb.)z2(.*)", "...z2=.*|.*z2.*z2.*z2.*|.*aa.*", "lda {z2}", "$1aa$2aa$3", null, mapZ3)); - // Replace first (of 2) Z2 with AA - synths.add(new AsmFragmentSynthesis("(.*vb.)z2(.*)z2(.*)", "...z2=.*|.*aa.*", "lda {z2}", "$1aa$2z2$3", null, null)); - // Replace second (of 2) Z2 with AA - synths.add(new AsmFragmentSynthesis("(.*)z2(.*vb.)z2(.*)", "...z2=.*|.*aa.*", "lda {z2}", "$1z2$2aa$3", null, null)); - - // Replace Z2 with YY (only one) - synths.add(new AsmFragmentSynthesis("(.*vb.)z2(.*)", "...z2=.*|.*z2.*z2.*|.*yy.*", "ldy {z2}", "$1yy$2", null, mapZ3)); - // Replace two Z2s with YY - synths.add(new AsmFragmentSynthesis("(.*vb.)z2(.*vb.)z2(.*)", "...z2=.*|.*z2.*z2.*z2.*|.*yy.*", "ldy {z2}", "$1yy$2yy$3", null, mapZ3)); - // Replace first (of 2) Z2 with YY - synths.add(new AsmFragmentSynthesis("(.*vb.)z2(.*)z2(.*)", "...z2=.*|.*yy.*", "ldy {z2}", "$1yy$2z2$3", null, null)); - // Replace second (of 2) Z2 with YY - synths.add(new AsmFragmentSynthesis("(.*)z2(.*vb.)z2(.*)", "...z2=.*|.*yy.*", "ldy {z2}", "$1z2$2yy$3", null, null)); - - // Replace Z2 with XX(only one) - synths.add(new AsmFragmentSynthesis("(.*vb.)z2(.*)", "...z2=.*|.*z2.*z2.*|.*xx.*", "ldx {z2}", "$1xx$2", null, mapZ3)); - // Replace two Z2s with XX - synths.add(new AsmFragmentSynthesis("(.*vb.)z2(.*vb.)z2(.*)", "...z2=.*|.*z2.*z2.*z2.*|.*xx.*", "ldx {z2}", "$1xx$2xx$3", null, mapZ3)); - // Replace first (of 2) Z2 with XX - synths.add(new AsmFragmentSynthesis("(.*vb.)z2(.*)z2(.*)", "...z2=.*|.*xx.*", "ldx {z2}", "$1xx$2z2$3", null, null)); - // Replace second (of 2) Z2 with XX - synths.add(new AsmFragmentSynthesis("(.*)z2(.*vb.)z2(.*)", "...z2=.*|.*xx.*", "ldx {z2}", "$1z2$2xx$3", null, null)); - - // Rewrite comparisons < to > - //synths.add(new AsmFragmentSynthesis("(.*)_gt_(.*)_then_(.*)", null, null, "$2_lt_$1_then_$3", null, null)); - // Rewrite comparisons > to < - //synths.add(new AsmFragmentSynthesis("(.*)_lt_(.*)_then_(.*)", null, null, "$2_gt_$1_then_$3", null, null)); - // Rewrite comparisons <= to >= - //synths.add(new AsmFragmentSynthesis("(.*)_le_(.*)_then_(.*)", null, null, "$2_ge_$1_then_$3", null, null)); - // Rewrite comparisons >= to <= - //synths.add(new AsmFragmentSynthesis("(.*)_ge_(.*)_then_(.*)", null, null, "$2_le_$1_then_$3", null, null)); - // Rewrite comparisons swap == - //synths.add(new AsmFragmentSynthesis("(.*)_eq_(.*)_then_(.*)", null, null, "$2_eq_$1_then_$3", null, null)); - // Rewrite comparisons swap != - //synths.add(new AsmFragmentSynthesis("(.*)_neq_(.*)_then_(.*)", null, null, "$2_neq_$1_then_$3", null, null)); - - - // OLD STYLE REWRITES - written when only one rule could be taken - - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_(band|bor|bxor|plus)_(vb.aa)", ".*=vb.aa_.*", null, "$1=$4_$3_$2", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_(band|bor|bxor|plus)_(vb.xx)", ".*=vb.[ax][ax]_.*", null, "$1=$4_$3_$2", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_(band|bor|bxor|plus)_(vb.yy)", ".*=vb.[axy][axy]_.*", null, "$1=$4_$3_$2", null, null)); - - synths.add(new AsmFragmentSynthesis("vbuxx=(.*)", null, null, "vbuaa=$1", "tax\n", null)); - synths.add(new AsmFragmentSynthesis("vbsxx=(.*)", null, null, "vbsaa=$1", "tax\n", null)); - synths.add(new AsmFragmentSynthesis("vbuyy=(.*)", null, null, "vbuaa=$1", "tay\n", null)); - synths.add(new AsmFragmentSynthesis("vbsyy=(.*)", null, null, "vbsaa=$1", "tay\n", null)); - synths.add(new AsmFragmentSynthesis("vbuz1=(.*)", ".*=.*vb.z1.*", null, "vbuaa=$1", "sta {z1}\n", mapZ)); - synths.add(new AsmFragmentSynthesis("vbsz1=(.*)", ".*=.*vb.z1.*", null, "vbsaa=$1", "sta {z1}\n", mapZ)); - synths.add(new AsmFragmentSynthesis("_deref_pb(.)c1=(.*)", ".*c1.*c1.*", null, "vb$1aa=$2", "sta {c1}\n", mapC)); - synths.add(new AsmFragmentSynthesis("_deref_pb(.)c1=(.*c1.*)", null, null, "vb$1aa=$2", "sta {c1}\n", null)); - synths.add(new AsmFragmentSynthesis("_deref_pbuz1=(.*)", ".*z1.*z1.*", null, "vbuaa=$1", "ldy #0\n" + "sta ({z1}),y\n", mapZ)); - synths.add(new AsmFragmentSynthesis("_deref_pbuz1=(.*z1.*)", null, null, "vbuaa=$1", "ldy #0\n" + "sta ({z1}),y\n", null)); - - synths.add(new AsmFragmentSynthesis("pb(.)c1_derefidx_vbuz1=(.*)", ".*z1.*z1.*|.*c1.*c1.*", null, "vb$1aa=$2", "ldx {z1}\n" + "sta {c1},x\n", mapZC)); - synths.add(new AsmFragmentSynthesis("pb(.)c1_derefidx_vbuyy=(.*)", ".*c1.*c1.*", null, "vb$1aa=$2", "sta {c1},y\n", mapC)); - synths.add(new AsmFragmentSynthesis("pb(.)c1_derefidx_vbuxx=(.*)", ".*c1.*c1.*", null, "vb$1aa=$2", "sta {c1},x\n", mapC)); - synths.add(new AsmFragmentSynthesis("pb(.)z1_derefidx_vbuz2=(.*)", ".*z1.*z1.*|.*z2.*z2.*", null, "vb$1aa=$2", "ldy {z2}\n" + "sta ({z1}),y\n", mapZ2)); - - synths.add(new AsmFragmentSynthesis("(.*)=_deref_pb(.)c1(.*)", ".*=.*aa.*", "lda {c1}\n", "$1=vb$2aa$3", null, mapC)); - synths.add(new AsmFragmentSynthesis("(.*)=_deref_pb(.)z1(.*)", ".*z1.*z1.*|.*=.*aa.*|.*=.*yy.*", "ldy #0\n" + "lda ({z1}),y\n", "$1=vb$2aa$3", null, mapZ)); - - // Convert array indexing with A register to X/Y register by prefixing tax/tay (..._derefidx_vbuaa... -> ..._derefidx_vbuxx... /... _derefidx_vbuyy... ) - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_derefidx_vbuaa(.*)", ".*=.*xx.*", "tax\n", "$1=$2_derefidx_vbuxx$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_derefidx_vbuaa(.*)", ".*=.*yy.*", "tay\n", "$1=$2_derefidx_vbuyy$3", null, null)); - // Convert array indexing with zero page to x/y register by prefixing ldx z1 / ldy z1 ( ..._derefidx_vbuzn... -> ..._derefidx_vbuxx... / ..._derefidx_vbuyy... ) - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_derefidx_vbuz1(.*)", ".*=.*xx.*|.*z1.*z1.*", "ldx {z1}\n", "$1=$2_derefidx_vbuxx$3", null, mapZ)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_derefidx_vbuz1(.*)", ".*=.*yy.*|.*z1.*z1.*", "ldy {z1}\n", "$1=$2_derefidx_vbuyy$3", null, mapZ)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_derefidx_vbuz2(.*)", ".*=.*xx.*|.*z2.*z2.*", "ldx {z2}\n", "$1=$2_derefidx_vbuxx$3", null, mapZ3)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_derefidx_vbuz2(.*)", ".*=.*yy.*|.*z2.*z2.*", "ldy {z2}\n", "$1=$2_derefidx_vbuyy$3", null, mapZ3)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_derefidx_vbuz3(.*)", ".*=.*yy.*", "ldy {z3}\n", "$1=$2_derefidx_vbuyy$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_derefidx_vbuz3(.*)", ".*=.*xx.*", "ldx {z3}\n", "$1=$2_derefidx_vbuxx$3", null, null)); - // Convert array indexing twice with A/zp1/zp2 to X/Y register with a ldx/ldy prefix ( ..._derefidx_vbunn..._derefidx_vbunn... -> ..._derefidx_vbuxx..._derefidx_vbuxx... ) - synths.add(new AsmFragmentSynthesis("(.*)_derefidx_vbuaa(.*)_derefidx_vbuaa(.*)", ".*aa.*aa.*aa.*|.*xx.*", null, "$1_derefidx_vbuxx$2_derefidx_vbuxx$3", "tax\n", null)); - synths.add(new AsmFragmentSynthesis("(.*)_derefidx_vbuaa(.*)_derefidx_vbuaa(.*)", ".*aa.*aa.*aa.*|.*yy.*", null, "$1_derefidx_vbuyy$2_derefidx_vbuyy$3", "tay\n", null)); - synths.add(new AsmFragmentSynthesis("(.*)_derefidx_vbuz1(.*)_derefidx_vbuz1(.*)", ".*z1.*z1.*z1.*|.*xx.*", null, "$1_derefidx_vbuxx$2_derefidx_vbuxx$3", "ldx {z1}\n", mapZ)); - synths.add(new AsmFragmentSynthesis("(.*)_derefidx_vbuz1(.*)_derefidx_vbuz1(.*)", ".*z1.*z1.*z1.*|.*yy.*", null, "$1_derefidx_vbuyy$2_derefidx_vbuyy$3", "ldy {z1}\n", mapZ)); - synths.add(new AsmFragmentSynthesis("(.*)_derefidx_vbuz2(.*)_derefidx_vbuz2(.*)", ".*z2.*z2.*z2.*|.*xx.*", null, "$1_derefidx_vbuxx$2_derefidx_vbuxx$3", "ldx {z2}\n", mapZ)); - synths.add(new AsmFragmentSynthesis("(.*)_derefidx_vbuz2(.*)_derefidx_vbuz2(.*)", ".*z2.*z2.*z2.*|.*yy.*", null, "$1_derefidx_vbuyy$2_derefidx_vbuyy$3", "ldy {z2}\n", mapZ)); - synths.add(new AsmFragmentSynthesis("pb(.)c1_derefidx_vbuz1=(.*c1.*)", ".*z1.*z1.*", null, "vb$1aa=$2", "ldx {z1}\n" + "sta {c1},x\n", mapZ)); - synths.add(new AsmFragmentSynthesis("pb(.)c1_derefidx_vbuz1=(.*z1.*)", ".*c1.*c1.*", null, "vb$1aa=$2", "ldx {z1}\n" + "sta {c1},x\n", mapC)); - - // Convert X/Y-based array indexing of a constant pointer into A-register by prefixing lda cn,x / lda cn,y ( ...pb.c1_derefidx_vbuxx... / ...pb.c1_derefidx_vbuyy... -> ...vb.aa... ) - synths.add(new AsmFragmentSynthesis("(.*)=(.*)pb(.)c1_derefidx_vbuxx(.*)", ".*=.*aa.*|.*c1.*c1.*", "lda {c1},x\n", "$1=$2vb$3aa$4", null, mapC)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*c1.*)pb(.)c1_derefidx_vbuxx(.*)", ".*=.*aa.*", "lda {c1},x\n", "$1=$2vb$3aa$4", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)pb(.)c1_derefidx_vbuxx(.*c1.*)", ".*=.*aa.*", "lda {c1},x\n", "$1=$2vb$3aa$4", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)pb(.)c1_derefidx_vbuyy(.*)", ".*=.*aa.*|.*c1.*c1.*", "lda {c1},y\n", "$1=$2vb$3aa$4", null, mapC)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*c1.*)pb(.)c1_derefidx_vbuyy(.*)", ".*=.*aa.*", "lda {c1},y\n", "$1=$2vb$3aa$4", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)pb(.)c1_derefidx_vbuyy(.*c1.*)", ".*=.*aa.*", "lda {c1},y\n", "$1=$2vb$3aa$4", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)pb(.)c2_derefidx_vbuxx(.*)", ".*=.*aa.*|.*c2.*c2.*", "lda {c2},x\n", "$1=$2vb$3aa$4", null, mapC3)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*c2.*)pb(.)c2_derefidx_vbuxx(.*)", ".*=.*aa.*", "lda {c2},x\n", "$1=$2vb$3aa$4", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)pb(.)c2_derefidx_vbuxx(.*c2.*)", ".*=.*aa.*", "lda {c2},x\n", "$1=$2vb$3aa$4", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)pb(.)c2_derefidx_vbuyy(.*)", ".*=.*aa.*|.*c2.*c2.*", "lda {c2},y\n", "$1=$2vb$3aa$4", null, mapC3)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*c2.*)pb(.)c2_derefidx_vbuyy(.*)", ".*=.*aa.*", "lda {c2},y\n", "$1=$2vb$3aa$4", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)pb(.)c2_derefidx_vbuyy(.*c2.*)", ".*=.*aa.*", "lda {c2},y\n", "$1=$2vb$3aa$4", null, null)); - - // Convert zeropage/constants/X/Y in assignments to A-register using LDA/TXA/TYA prefix - synths.add(new AsmFragmentSynthesis("(.*)=(.*)vbuz1(.*)", ".*z1.*=.*|.*=.*aa.*|.*z1.*z1.*", "lda {z1}\n", "$1=$2vbuaa$3", null, mapZ)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)vbsz1(.*)", ".*z1.*=.*|.*=.*aa.*|.*z1.*z1.*", "lda {z1}\n", "$1=$2vbsaa$3", null, mapZ)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)vbuz2(.*)", ".*z2.*=.*|.*=.*aa.*|.*z2.*z2.*|.*z3.*", "lda {z2}\n", "$1=$2vbuaa$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)vbsz2(.*)", ".*z2.*=.*|.*=.*aa.*|.*z2.*z2.*|.*z3.*", "lda {z2}\n", "$1=$2vbsaa$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)vbuz2(.*z3.*)", ".*z2.*=.*|.*=.*aa.*|.*z2.*z2.*|.*z3.*", "lda {z2}\n", "$1=$2vbuaa$3", null, mapZ3)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)vbsz2(.*z3.*)", ".*z2.*=.*|.*=.*aa.*|.*z2.*z2.*|.*z3.*", "lda {z2}\n", "$1=$2vbsaa$3", null, mapZ3)); - - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_vbuxx", ".*=.*[ax][ax].*xx|.*derefidx_vb.xx", "txa\n", "$1=$2_vbuaa", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_vbsxx", ".*=.*[ax][ax].*xx|.*derefidx_vb.xx", "txa\n", "$1=$2_vbsaa", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_vbuyy", ".*=.*[ay][ay].*yy|.*derefidx_vb.yy", "tya\n", "$1=$2_vbuaa", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_vbsyy", ".*=-*[ay][ay].*yy|.*derefidx_vb.yy", "tya\n", "$1=$2_vbsaa", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_vbuz1", ".*=.*aa.*|.*z1.*z1.*", "lda {z1}\n", "$1=$2_vbuaa", null, mapZ)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_vbsz1", ".*=.*aa.*|.*z1.*z1.*", "lda {z1}\n", "$1=$2_vbsaa", null, mapZ)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_vbuz2", ".*=.*aa.*|.*z2.*z2.*", "lda {z2}\n", "$1=$2_vbuaa", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_vbuz3", ".*=.*aa.*|.*z3.*z3.*", "lda {z3}\n", "$1=$2_vbuaa", null, null)); - - synths.add(new AsmFragmentSynthesis("vbuz1=vbuz1(.*)", ".*=.*vb.aa.*|.*z1.*z1.*z1.*", "lda {z1}\n", "vbuaa=vbuaa$1", "sta {z1}\n", mapZ)); - synths.add(new AsmFragmentSynthesis("vbsz1=vbsz1(.*)", ".*=.*vb.aa.*|.*z1.*z1.*z1.*", "lda {z1}\n", "vbsaa=vbsaa$1", "sta {z1}\n", mapZ)); - - synths.add(new AsmFragmentSynthesis("vbuz1_(lt|gt|le|ge|eq|neq)_(.*)", ".*vb.aa.*|.*z1.*z1.*", "lda {z1}\n", "vbuaa_$1_$2", null, mapZ)); - synths.add(new AsmFragmentSynthesis("vbsz1_(lt|gt|le|ge|eq|neq)_(.*)", ".*vb.aa.*|.*z1.*z1.*", "lda {z1}\n", "vbsaa_$1_$2", null, mapZ)); - synths.add(new AsmFragmentSynthesis("_deref_pb(.)c1_(lt|gt|le|ge|eq|neq)_(.*)", ".*vb.aa.*", "lda {c1}\n", "vb$1aa_$2_$3", null, mapC)); - synths.add(new AsmFragmentSynthesis("_deref_pb(.)z1_(lt|gt|le|ge|eq|neq)_(.*)", ".*vb.aa.*|.*vb.yy.*|.*z1.*z1.*", "ldy #0\n" + "lda ({z1}),y\n", "vb$1aa_$2_$3", null, mapZ)); - - synths.add(new AsmFragmentSynthesis("(.*)_derefidx_vbuz1_(.*)", ".*z1.*z1.*|.*.yy.*", "ldy {z1}\n", "$1_derefidx_vbuyy_$2", null, mapZ)); - - - synths.add(new AsmFragmentSynthesis("(.*)_derefidx_vbuz1_(lt|gt|le|ge|eq|neq)_(.*)", ".*z1.*z1.*|.*vb.xx.*", "ldx {z1}\n", "$1_derefidx_vbuxx_$2_$3", null, mapZ)); - synths.add(new AsmFragmentSynthesis("pb(.)c1_derefidx_vbuyy_(lt|gt|le|ge|eq|neq)_(.*)", ".*c1.*c1.*|.*aa.*", "lda {c1},y\n", "vb$1aa_$2_$3", null, mapC)); - synths.add(new AsmFragmentSynthesis("pb(.)c1_derefidx_vbuyy_(lt|gt|le|ge|eq|neq)_(.*c1.*)", ".*aa.*", "lda {c1},y\n", "vb$1aa_$2_$3", null, null)); - synths.add(new AsmFragmentSynthesis("pb(.)c1_derefidx_vbuxx_(lt|gt|le|ge|eq|neq)_(.*)", ".*c1.*c1.*|.*aa.*", "lda {c1},x\n", "vb$1aa_$2_$3", null, mapC)); - synths.add(new AsmFragmentSynthesis("pb(.)c1_derefidx_vbuxx_(lt|gt|le|ge|eq|neq)_(.*c1.*)", ".*aa.*", "lda {c1},x\n", "vb$1aa_$2_$3", null, null)); - - synths.add(new AsmFragmentSynthesis("(.*)_ge_(vb.aa)_then_(.*)", ".*vb.aa.*_ge.*", null, "$2_le_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_ge_(vb.xx)_then_(.*)", ".*vb.[ax][ax].*_ge.*", null, "$2_le_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_ge_(vb.yy)_then_(.*)", ".*vb.[axy][axy].*_ge.*", null, "$2_le_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_lt_(vb.aa)_then_(.*)", ".*vb.aa.*_lt.*", null, "$2_gt_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_lt_(vb.xx)_then_(.*)", ".*vb.[ax][ax].*_lt.*", null, "$2_gt_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_lt_(vb.yy)_then_(.*)", ".*vb.[axy][axy].*_lt.*", null, "$2_gt_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_gt_(vb.aa)_then_(.*)", ".*vb.aa.*_gt.*", null, "$2_lt_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_gt_(vb.xx)_then_(.*)", ".*vb.[ax][ax].*_gt.*", null, "$2_lt_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_gt_(vb.yy)_then_(.*)", ".*vb.[axy][axy].*_gt.*", null, "$2_lt_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_le_(vb.aa)_then_(.*)", ".*vb.aa.*_le.*", null, "$2_ge_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_le_(vb.xx)_then_(.*)", ".*vb.[ax][ax].*_le.*", null, "$2_ge_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_le_(vb.yy)_then_(.*)", ".*vb.[axy][axy].*_le.*", null, "$2_ge_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_neq_(vb.aa)_then_(.*)", ".*vb.aa.*_neq.*", null, "$2_neq_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_neq_(vb.xx)_then_(.*)", ".*vb.[ax][ax].*_neq.*", null, "$2_neq_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_neq_(vb.yy)_then_(.*)", ".*vb.[axy][axy].*_neq.*", null, "$2_neq_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_eq_(vb.aa)_then_(.*)", ".*vb.aa.*_eq.*", null, "$2_eq_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_eq_(vb.xx)_then_(.*)", ".*vb.[ax][ax].*_eq.*", null, "$2_eq_$1_then_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)_eq_(vb.yy)_then_(.*)", ".*vb.[axy][axy].*_eq.*", null, "$2_eq_$1_then_$3", null, null)); - - // Use unsigned ASM to synthesize signed ASM ( ...vbs... -> ...vbu... ) - synths.add(new AsmFragmentSynthesis("(vbsz.|vbsc.|vbsaa|vbsxx|vbsyy)_(eq|neq)_(vbsz.|vbsc.|vbsaa|vbsxx|vbsyy)_then_(.*)", null, null, "$1_$2_$3_then_$4", null, mapSToU)); - synths.add(new AsmFragmentSynthesis("(vbsz.|vbsc.|vbsaa|vbsxx|vbsyy)=(vbsz.|vbsc.|vbsaa|vbsxx|vbsyy)", null, null, "$1=$2", null, mapSToU)); - synths.add(new AsmFragmentSynthesis("(vbsz.|vbsc.|vbsaa|vbsxx|vbsyy)=(vbsz.|vbsc.|vbsaa|vbsxx|vbsyy)_(plus|band|bxor|bor)_(vbsz.|csoby.|vbsaa|vbsxx|vbsyy)", null, null, "$1=$2_$3_$4", null, mapSToU)); - synths.add(new AsmFragmentSynthesis("(vbsz.|vbsc.|vbsaa|vbsxx|vbsyy)=_(inc|dec)_(vbsz.|vbsc.|vbsaa|vbsxx|vbsyy)", null, null, "$1=_$2_$3", null, mapSToU)); - synths.add(new AsmFragmentSynthesis("(vwsz.|vwsc.)_(eq|neq)_(vwsz.|vwsc.)_then_(.*)", null, null, "$1_$2_$3_then_$4", null, mapSToU)); - synths.add(new AsmFragmentSynthesis("(vwsz.)=(vwsz.|vwsc.)", null, null, "$1=$2", null, mapSToU)); - synths.add(new AsmFragmentSynthesis("(v.sz.)=(v.s..)_(band|bxor|bor)_(v.s..)", null, null, "$1=$2_$3_$4", null, mapSToU)); - synths.add(new AsmFragmentSynthesis("(vbuz.|vbuaa|vbuxx|vbuyy)=_(lo|hi)_vws(z.|c.)", null, null, "$1=_$2_vwu$3", null, mapSToU)); - - // Use constant word ASM to synthesize unsigned constant byte ASM ( ...vb.c... -> vw.c... ) - synths.add(new AsmFragmentSynthesis("(vwuz.)=(vwuz.)_(plus|minus|band|bxor|bor)_vb.c(.)", null, null, "$1=$2_$3_vwuc$4", null, null)); - synths.add(new AsmFragmentSynthesis("(vwuz.)=vb.c(.)_(plus|minus|band|bxor|bor)_(vwuz.)", null, null, "$1=vwuc$2_$3_$4", null, null)); - synths.add(new AsmFragmentSynthesis("(vwsz.)=(vwsz.)_(plus|minus|band|bxor|bor)_vb.c(.)", null, null, "$1=$2_$3_vwsc$4", null, null)); - synths.add(new AsmFragmentSynthesis("(vwsz.)=vb.c(.)_(plus|minus|band|bxor|bor)_(vwsz.)", null, null, "$1=vwsc$2_$3_$4", null, null)); - - // Move constant words to the end of the ASM signature for symmetric operators ( ...vw.c...vw.z... -> ...vw.z...vw.c... ) - synths.add(new AsmFragmentSynthesis("(vwuz.)=(vwuc.)_(plus|band|bxor|bor)_(vwuz.)", null, null, "$1=$4_$3_$2", null, null)); - synths.add(new AsmFragmentSynthesis("(vwsz.)=(vwsc.)_(plus|band|bxor|bor)_(vwsz.)", null, null, "$1=$4_$3_$2", null, null)); - - // Use Z1/Z2 ASM to synthesize Z1-only code ( ...z1...z1... -> ...z1...z2... ) - synths.add(new AsmFragmentSynthesis("(v..)z1=(v..)z1_(plus|minus|band|bxor|bor)_(.*)", ".*z2.*", null, "$1z1=$2z2_$3_$4", null, mapZ, false)); - synths.add(new AsmFragmentSynthesis("(v..)z1=(.*)_(plus|minus|band|bxor|bor)_(v..)z1", ".*z2.*", null, "$1z1=$2_$3_$4z2", null, mapZ, false)); - synths.add(new AsmFragmentSynthesis("(v..)z1=_(neg|lo|hi)_(v..)z1", ".*z2.*", null, "$1z1=_$2_$3z2", null, mapZ, false)); - - // Convert INC/DEC to +1/-1 ( ..._inc_xxx... -> ...xxx_plus_1_... / ..._dec_xxx... -> ...xxx_minus_1_... ) - synths.add(new AsmFragmentSynthesis("vb(.)aa=_inc_(.*)", null, null, "vb$1aa=$2_plus_1", null, null)); - synths.add(new AsmFragmentSynthesis("vb(.)aa=_dec_(.*)", null, null, "vb$1aa=$2_minus_1", null, null)); - - // Synthesize XX/YY using AA - synths.add(new AsmFragmentSynthesis("(.*)=(.*)vbuxx(.*)", ".*=.*aa.*|.*derefidx_vb.xx.*", "txa\n", "$1=$2vbuaa$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)vbsxx(.*)", ".*=.*aa.*|.*derefidx_vb.xx.*", "txa\n", "$1=$2vbsaa$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)vbuyy(.*)", ".*=.*aa.*|.*derefidx_vb.yy.*", "tya\n", "$1=$2vbuaa$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)vbsyy(.*)", ".*=.*aa.*|.*derefidx_vb.yy.*", "tya\n", "$1=$2vbsaa$3", null, null)); - // Synthesize constants using AA - synths.add(new AsmFragmentSynthesis("(.*)=(.*)vbuc1(.*)", ".*=.*aa.*|.*c1.*c1.*|.*c1_deref.*", "lda #{c1}\n", "$1=$2vbuaa$3", null, mapC)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)vbsc1(.*)", ".*=.*aa.*|.*c1.*c1.*|.*c1_deref.*", "lda #{c1}\n", "$1=$2vbsaa$3", null, mapC)); - - // Synthesize some constant pointers as constant words - synths.add(new AsmFragmentSynthesis("(.*)_(lt|gt|le|ge|eq|neq)_p..([cz].)_then_(.*)", null, null, "$1_$2_vwu$3_then_$4", null, null)); - synths.add(new AsmFragmentSynthesis("p..([cz].)_(lt|gt|le|ge|eq|neq)_(.*)", null, null, "vwu$1_$2_$3", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=p..([zc].)", null, null, "$1=vwu$2", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=(.*)_(plus|minus|bor|bxor)_p..([cz].)", null, null, "$1=$2_$3_vwu$4", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=p..([cz].)_(plus|minus|bor|bxor)_(.*)", null, null, "$1=vwu$2_$3_$4", null, null)); - synths.add(new AsmFragmentSynthesis("p..([cz].)=(.*)_(sethi|setlo|plus|minus)_(.*)", null, null, "vwu$1=$2_$3_$4", null, null)); - synths.add(new AsmFragmentSynthesis("(.*)=p..([cz].)_(sethi|setlo|plus|minus)_(.*)", null, null, "$1=vwu$2_$3_$4", null, null)); - - return synths; - } - - /** - * The synthesis path describes the different signatures being attempted to synthesize a fragment. - * Used to avoid infinite loops during synthesis. - */ - static class AsmSynthesisPath { - - private ArrayDeque signatures; - - public AsmSynthesisPath() { - this.signatures = new ArrayDeque<>(); - } - - private AsmSynthesisPath(ArrayDeque signatures) { - this.signatures = signatures; - } - - AsmSynthesisPath add(String signature) { - ArrayDeque signatures = new ArrayDeque<>(this.signatures); - signatures.add(signature); - return new AsmSynthesisPath(signatures); - } - - boolean has(String signature) { - return signatures.contains(signature); - } - - @Override - public String toString() { - StringBuilder str = new StringBuilder(); - boolean first = true; - for(String signature : signatures) { - if(first) { - first = false; - } else { - str.append(" < "); - } - str.append(signature); - } - return str.toString(); - } - } - - /** - * Capable of creating fragments from signatures by loading them or synthesizing them from other smaller fragments. - *

- * The synthesizer tries a lot of different combinations and keeps track of what has already been attempted. - */ - static class AsmFragmentTemplateSynthesizer { - - /** Signature of the fragment being synthesized. */ - private String creating; - - /** The log. */ - private CompileLog log; - - AsmFragmentTemplateSynthesizer(String creating, CompileLog log) { - this.creating = creating; - this.log = log; - } - - List loadOrSynthesizeFragment(String signature, AsmSynthesisPath path) { - if(path.has(signature)) { - // Synthesis loop - stop it here - if(log.isVerboseFragmentLog()) { - log.append("Finding fragment " + path.toString() + " - Stopping synthesis loop at " + signature); - } - return new ArrayList<>(); - } - // Add the current signature to the path - path = path.add(signature); - if(fragmentTemplateCache.get(signature) != null) { - if(log.isVerboseFragmentLog()) { - log.append("Finding fragment " + path.toString() + " - Using cached " + signature); - } - return fragmentTemplateCache.get(signature); - } - if(log.isVerboseFragmentLog()) { - log.append("Finding fragment " + path.toString() + " - Attempting " + signature); - } - List candidates = new ArrayList<>(); - // Synthesize the fragment from other fragments - List synths = getFragmentSyntheses(); - for(AsmFragmentSynthesis synth : synths) { - List synthesized = synth.synthesize(signature, path, this); - if(synthesized != null) { - if(log.isVerboseFragmentLog() && synthesized.size() > 0) { - log.append("Finding fragment " + path.toString() + " - Successfully synthesized " + synthesized.size() + " fragments "); - } - candidates.addAll(synthesized); - } - } - // Load the fragment from disk - CharStream fragmentCharStream = loadFragment(signature); - if(fragmentCharStream != null) { - try { - String body = fragmentCharStream.toString(); - candidates.add(new AsmFragmentTemplate(signature, body)); - - } catch(StringIndexOutOfBoundsException e) { - throw new RuntimeException("Problem reading fragment file " + signature, e); - } - if(log.isVerboseFragmentLog()) { - log.append("Finding fragment " + path.toString() + " - Successfully loaded " + signature + ".asm"); - } - } - if(candidates.size() == 0) { - if(log.isVerboseFragmentLog()) { - log.append("Finding fragment " + path.toString() + " - No synthesis/file found!"); - } - } - fragmentTemplateCache.put(signature, candidates); - return candidates; - } - - public String getCreating() { - return creating; - } - - public CompileLog getLog() { - return log; - } - } - - public static class UnknownFragmentException extends RuntimeException { - - private String fragmentSignature; - - UnknownFragmentException(String signature) { - super("Fragment not found " + signature ); - this.fragmentSignature = signature; - } - - public String getFragmentSignature() { - return fragmentSignature; - } - } - -} diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplate.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplate.java index 6b24feefc..bb3d563b0 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplate.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplate.java @@ -19,7 +19,7 @@ public class AsmFragmentTemplate { /** The parsed ASM lines. Initially null. Will be non-null, is the template is ever used to generate ASM code. */ private KickCParser.AsmLinesContext bodyAsm; /** The synthesis that created the fragment. null if the fragment template was loaded. */ - private AsmFragmentSynthesis synthesis; + private AsmFragmentTemplateSynthesisRule synthesis; /** The sub fragment template that the synthesis modified to create this. null if the fragment template was loaded. */ private AsmFragmentTemplate subFragment; @@ -30,7 +30,7 @@ public class AsmFragmentTemplate { this.file = true; } - AsmFragmentTemplate(String signature, String body, AsmFragmentSynthesis synthesis, AsmFragmentTemplate subFragment) { + AsmFragmentTemplate(String signature, String body, AsmFragmentTemplateSynthesisRule synthesis, AsmFragmentTemplate subFragment) { this.signature = signature; this.body = body; this.synthesis = synthesis; @@ -89,7 +89,7 @@ public class AsmFragmentTemplate { return file; } - public AsmFragmentSynthesis getSynthesis() { + public AsmFragmentTemplateSynthesisRule getSynthesis() { return synthesis; } diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateManager.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateManager.java new file mode 100644 index 000000000..e94452ecf --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateManager.java @@ -0,0 +1,570 @@ +package dk.camelot64.kickc.fragment; + +import dk.camelot64.kickc.CompileLog; +import dk.camelot64.kickc.asm.AsmProgram; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.CharStreams; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.*; + +/** + * Provides fragments from their signature. + *

+ * The first priority is loading a fragment file from the fragment-folder. + * If no fragment file is found for the signature the manager attempts to synthesise a fragment from another fragment. + */ +public class AsmFragmentTemplateManager { + + /** Cache for the best fragment templates. Maps signature to the best fragment template for the signature. */ + private static Map bestFragmentCache = new HashMap<>(); + + /** Caches all asm fragment templates for all encountered signatures. */ + private static Map> fragmentTemplateCache = new LinkedHashMap<>(); + + /** Special singleton representing that the fragment can not be synthesized or loaded. */ + private static AsmFragmentTemplate UNKNOWN = new AsmFragmentTemplate("UNKNOWN", null); + /** + * All the synthesize rules available. + */ + private static List fragmentSyntheses; + + static Map> getFragmentTemplateCache() { + return fragmentTemplateCache; + } + + public static AsmFragmentInstance getFragment(AsmFragmentInstanceSpec instanceSpec, CompileLog log) { + AsmFragmentTemplate bestTemplate = bestFragmentCache.get(instanceSpec.getSignature()); + if(bestTemplate == UNKNOWN) { + if(log.isVerboseFragmentLog()) { + log.append("Unknown fragment " + instanceSpec.getSignature()); + } + throw new UnknownFragmentException(instanceSpec); + } + if(bestTemplate == null) { + AsmFragmentTemplateSynthesizer synthesizer = new AsmFragmentTemplateSynthesizer(instanceSpec.getSignature(), log); + List candidates = synthesizer.loadOrSynthesizeFragment(instanceSpec.getSignature(), new AsmSynthesisPath()); + if(candidates.size() == 0) { + if(log.isVerboseFragmentLog()) { + log.append("Unknown fragment " + instanceSpec.getSignature()); + } + bestFragmentCache.put(instanceSpec.getSignature(), UNKNOWN); + throw new UnknownFragmentException(instanceSpec); + } + double minScore = Double.MAX_VALUE; + double maxScore = Double.MIN_VALUE; + AsmFragmentTemplate maxTemplate = null; + for(AsmFragmentTemplate candidateTemplate : candidates) { + AsmFragmentInstance candidateFragment = new AsmFragmentInstance( + instanceSpec.getProgram(), + instanceSpec.getSignature(), + instanceSpec.getCodeScope(), + candidateTemplate, + instanceSpec.getBindings()); + AsmProgram candidateAsm = new AsmProgram(); + candidateAsm.startSegment(null, instanceSpec.toString()); + candidateFragment.generate(candidateAsm); + double score = candidateAsm.getCycles(); + if(score < minScore) { + minScore = score; + bestTemplate = candidateTemplate; + } + if(score > maxScore) { + maxScore = score; + maxTemplate = candidateTemplate; + } + } + if(log.isVerboseFragmentLog()) { + log.append("Found fragment " + bestTemplate.getName() + " score: " + minScore + " from " + candidates.size() + " candidates"); + } + bestFragmentCache.put(instanceSpec.getSignature(), bestTemplate); + } + // Count usages + AsmFragmentTemplateUsages.incUsage(bestTemplate); + // Return the resulting fragment instance + return new AsmFragmentInstance( + instanceSpec.getProgram(), + instanceSpec.getSignature(), + instanceSpec.getCodeScope(), + bestTemplate, + instanceSpec.getBindings()); + } + + /** + * Look for a fragment on the disk. + * + * @param signature The fragment signature + * @return The fragment file contents. Null if the fragment is not on the disk. + */ + private static CharStream loadFragment(String signature) { + ClassLoader classLoader = AsmFragmentTemplateManager.class.getClassLoader(); + URL fragmentUrl = classLoader.getResource("dk/camelot64/kickc/fragment/asm/" + signature + ".asm"); + if(fragmentUrl == null) { + return null; + } + try { + InputStream fragmentStream = fragmentUrl.openStream(); + return CharStreams.fromStream(fragmentStream); + } catch(IOException e) { + throw new RuntimeException("Error loading fragment file " + fragmentUrl); + } + } + + static File[] allFragmentFiles() { + ClassLoader classLoader = AsmFragmentTemplateManager.class.getClassLoader(); + String path = classLoader.getResource("dk/camelot64/kickc/fragment/asm/").getPath(); + return new File(path).listFiles((dir, name) -> name.endsWith(".asm")); + + } + + private static List getFragmentSyntheses() { + if(fragmentSyntheses == null) { + fragmentSyntheses = initFragmentSyntheses(); + } + return fragmentSyntheses; + } + + private static List initFragmentSyntheses() { + Map mapZ = new LinkedHashMap<>(); + mapZ.put("z2", "z1"); + mapZ.put("z3", "z2"); + Map mapZ2 = new LinkedHashMap<>(); + mapZ2.put("z3", "z1"); + Map mapZ3 = new LinkedHashMap<>(); + mapZ3.put("z3", "z2"); + Map mapC = new LinkedHashMap<>(); + mapC.put("c2", "c1"); + mapC.put("c3", "c2"); + Map mapC3 = new LinkedHashMap<>(); + mapC3.put("c3", "c2"); + Map mapZC = new LinkedHashMap<>(); + mapZC.putAll(mapZ); + mapZC.putAll(mapC); + Map mapSToU = new LinkedHashMap<>(); + mapSToU.put("vbsz1", "vbuz1"); + mapSToU.put("vbsz2", "vbuz2"); + mapSToU.put("vbsz3", "vbuz3"); + mapSToU.put("vbsc1", "vbuc1"); + mapSToU.put("vbsc2", "vbuc2"); + mapSToU.put("vbsc3", "vbuc3"); + mapSToU.put("vbsaa", "vbuaa"); + mapSToU.put("vbsxx", "vbuxx"); + mapSToU.put("vbsyy", "vbuyy"); + mapSToU.put("vwsz1", "vwuz1"); + mapSToU.put("vwsz2", "vwuz2"); + mapSToU.put("vwsz3", "vwuz3"); + mapSToU.put("vwsc1", "vwuc1"); + mapSToU.put("vwsc2", "vwuc2"); + mapSToU.put("vwsc3", "vwuc3"); + + List synths = new ArrayList<>(); + + // NEW STYLE REWRITES - Utilizes that all combinations are tried + + // Replace first AA with XX + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)aa(.*)", "...aa=.*|.*xx.*", "tax", "$1xx$2", null, null)); + // Replace two AAs with XX + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)aa(.*vb.)aa(.*)", "...aa=.*|.*xx.*", "tax", "$1xx$2xx$3", null, null)); + // Replace second (not first) AA with XX + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)aa(.*vb.)aa(.*)", "...aa=.*|.*xx.*", "tax", "$1aa$2xx$3", null, null)); + + // Replace first AA with YY + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)aa(.*)", "...aa=.*|.*yy.*", "tay", "$1yy$2", null, null)); + // Replace two AAs with YY + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)aa(.*vb.)aa(.*)", "...aa=.*|.*yy.*", "tay", "$1yy$2yy$3", null, null)); + // Replace second (not first) AA with YY + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)aa(.*vb.)aa(.*)", "...aa=.*|.*yy.*", "tay", "$1aa$2yy$3", null, null)); + + // Replace first XX with AA + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)xx(.*)", "...xx=.*|.*aa.*", "txa", "$1aa$2", null, null)); + // Replace two XXs with AA + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)xx(.*vb.)xx(.*)", "...xx=.*|.*aa.*", "txa", "$1aa$2aa$3", null, null)); + // Replace second (not first) XX with AA + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)xx(.*vb.)xx(.*)", "...xx=.*|.*aa.*", "txa", "$1xx$2aa$3", null, null)); + + // Replace first YY with AA + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)yy(.*)", "...yy=.*|.*aa.*", "tya", "$1aa$2", null, null)); + // Replace two YYs with AA + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)yy(.*vb.)yy(.*)", "...yy=.*|.*aa.*", "tya", "$1aa$2aa$3", null, null)); + // Replace second (not first) YY with AA + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)yy(.*vb.)yy(.*)", "...yy=.*|.*aa.*", "tya", "$1yy$2aa$3", null, null)); + + // Replace Z1 with AA (only one) + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z1(.*)", "...z1=.*|.*z1.*z1.*|.*aa.*", "lda {z1}", "$1aa$2", null, mapZ)); + // Replace two Z1s with AA + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z1(.*vb.)z1(.*)", "...z1=.*|.*z1.*z1.*z1.*|.*aa.*", "lda {z1}", "$1aa$2aa$3", null, mapZ)); + // Replace first (not second) Z1 with AA + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z1(.*)z1(.*)", "...z1=.*|.*aa.*", "lda {z1}", "$1aa$2z1$3", null, null)); + // Replace second (not first) Z1 with AA + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)z1(.*vb.)z1(.*)", "...z1=.*|.*aa.*", "lda {z1}", "$1z1$2aa$3", null, null)); + + // Replace Z1 with YY (only one) + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z1(.*)", "...z1=.*|.*z1.*z1.*|.*yy.*", "ldy {z1}", "$1yy$2", null, mapZ)); + // Replace two Z1s with YY + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z1(.*vb.)z1(.*)", "...z1=.*|.*z1.*z1.*z1.*|.*yy.*", "ldy {z1}", "$1yy$2yy$3", null, mapZ)); + // Replace first (not second) Z1 with YY + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z1(.*)z1(.*)", "...z1=.*|.*yy.*", "ldy {z1}", "$1yy$2z1$3", null, null)); + // Replace second (not first) Z1 with YY + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)z1(.*vb.)z1(.*)", "...z1=.*|.*yy.*", "ldy {z1}", "$1z1$2yy$3", null, null)); + + // Replace Z1 with XX (only one) + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z1(.*)", "...z1=.*|.*z1.*z1.*|.*xx.*", "ldx {z1}", "$1xx$2", null, mapZ)); + // Replace two Z1s with XX + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z1(.*vb.)z1(.*)", "...z1=.*|.*z1.*z1.*z1.*|.*xx.*", "ldx {z1}", "$1xx$2xx$3", null, mapZ)); + // Replace first (not second) Z1 with XX + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z1(.*)z1(.*)", "...z1=.*|.*xx.*", "ldx {z1}", "$1xx$2z1$3", null, null)); + // Replace second (not first) Z1 with XX + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)z1(.*vb.)z1(.*)", "...z1=.*|.*xx.*", "ldx {z1}", "$1z1$2xx$3", null, null)); + + // Replace Z2 with AA (only one) + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z2(.*)", "...z2=.*|.*z2.*z2.*|.*aa.*", "lda {z2}", "$1aa$2", null, mapZ3)); + // Replace two Z2s with AA + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z2(.*vb.)z2(.*)", "...z2=.*|.*z2.*z2.*z2.*|.*aa.*", "lda {z2}", "$1aa$2aa$3", null, mapZ3)); + // Replace first (of 2) Z2 with AA + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z2(.*)z2(.*)", "...z2=.*|.*aa.*", "lda {z2}", "$1aa$2z2$3", null, null)); + // Replace second (of 2) Z2 with AA + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)z2(.*vb.)z2(.*)", "...z2=.*|.*aa.*", "lda {z2}", "$1z2$2aa$3", null, null)); + + // Replace Z2 with YY (only one) + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z2(.*)", "...z2=.*|.*z2.*z2.*|.*yy.*", "ldy {z2}", "$1yy$2", null, mapZ3)); + // Replace two Z2s with YY + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z2(.*vb.)z2(.*)", "...z2=.*|.*z2.*z2.*z2.*|.*yy.*", "ldy {z2}", "$1yy$2yy$3", null, mapZ3)); + // Replace first (of 2) Z2 with YY + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z2(.*)z2(.*)", "...z2=.*|.*yy.*", "ldy {z2}", "$1yy$2z2$3", null, null)); + // Replace second (of 2) Z2 with YY + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)z2(.*vb.)z2(.*)", "...z2=.*|.*yy.*", "ldy {z2}", "$1z2$2yy$3", null, null)); + + // Replace Z2 with XX(only one) + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z2(.*)", "...z2=.*|.*z2.*z2.*|.*xx.*", "ldx {z2}", "$1xx$2", null, mapZ3)); + // Replace two Z2s with XX + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z2(.*vb.)z2(.*)", "...z2=.*|.*z2.*z2.*z2.*|.*xx.*", "ldx {z2}", "$1xx$2xx$3", null, mapZ3)); + // Replace first (of 2) Z2 with XX + synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z2(.*)z2(.*)", "...z2=.*|.*xx.*", "ldx {z2}", "$1xx$2z2$3", null, null)); + // Replace second (of 2) Z2 with XX + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)z2(.*vb.)z2(.*)", "...z2=.*|.*xx.*", "ldx {z2}", "$1z2$2xx$3", null, null)); + + // Rewrite comparisons < to > + //synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_gt_(.*)_then_(.*)", null, null, "$2_lt_$1_then_$3", null, null)); + // Rewrite comparisons > to < + //synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_lt_(.*)_then_(.*)", null, null, "$2_gt_$1_then_$3", null, null)); + // Rewrite comparisons <= to >= + //synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_le_(.*)_then_(.*)", null, null, "$2_ge_$1_then_$3", null, null)); + // Rewrite comparisons >= to <= + //synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_ge_(.*)_then_(.*)", null, null, "$2_le_$1_then_$3", null, null)); + // Rewrite comparisons swap == + //synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_eq_(.*)_then_(.*)", null, null, "$2_eq_$1_then_$3", null, null)); + // Rewrite comparisons swap != + //synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_neq_(.*)_then_(.*)", null, null, "$2_neq_$1_then_$3", null, null)); + + + // OLD STYLE REWRITES - written when only one rule could be taken + + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_(band|bor|bxor|plus)_(vb.aa)", ".*=vb.aa_.*", null, "$1=$4_$3_$2", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_(band|bor|bxor|plus)_(vb.xx)", ".*=vb.[ax][ax]_.*", null, "$1=$4_$3_$2", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_(band|bor|bxor|plus)_(vb.yy)", ".*=vb.[axy][axy]_.*", null, "$1=$4_$3_$2", null, null)); + + synths.add(new AsmFragmentTemplateSynthesisRule("vbuxx=(.*)", null, null, "vbuaa=$1", "tax\n", null)); + synths.add(new AsmFragmentTemplateSynthesisRule("vbsxx=(.*)", null, null, "vbsaa=$1", "tax\n", null)); + synths.add(new AsmFragmentTemplateSynthesisRule("vbuyy=(.*)", null, null, "vbuaa=$1", "tay\n", null)); + synths.add(new AsmFragmentTemplateSynthesisRule("vbsyy=(.*)", null, null, "vbsaa=$1", "tay\n", null)); + synths.add(new AsmFragmentTemplateSynthesisRule("vbuz1=(.*)", ".*=.*vb.z1.*", null, "vbuaa=$1", "sta {z1}\n", mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("vbsz1=(.*)", ".*=.*vb.z1.*", null, "vbsaa=$1", "sta {z1}\n", mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("_deref_pb(.)c1=(.*)", ".*c1.*c1.*", null, "vb$1aa=$2", "sta {c1}\n", mapC)); + synths.add(new AsmFragmentTemplateSynthesisRule("_deref_pb(.)c1=(.*c1.*)", null, null, "vb$1aa=$2", "sta {c1}\n", null)); + synths.add(new AsmFragmentTemplateSynthesisRule("_deref_pbuz1=(.*)", ".*z1.*z1.*", null, "vbuaa=$1", "ldy #0\n" + "sta ({z1}),y\n", mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("_deref_pbuz1=(.*z1.*)", null, null, "vbuaa=$1", "ldy #0\n" + "sta ({z1}),y\n", null)); + + synths.add(new AsmFragmentTemplateSynthesisRule("pb(.)c1_derefidx_vbuz1=(.*)", ".*z1.*z1.*|.*c1.*c1.*", null, "vb$1aa=$2", "ldx {z1}\n" + "sta {c1},x\n", mapZC)); + synths.add(new AsmFragmentTemplateSynthesisRule("pb(.)c1_derefidx_vbuyy=(.*)", ".*c1.*c1.*", null, "vb$1aa=$2", "sta {c1},y\n", mapC)); + synths.add(new AsmFragmentTemplateSynthesisRule("pb(.)c1_derefidx_vbuxx=(.*)", ".*c1.*c1.*", null, "vb$1aa=$2", "sta {c1},x\n", mapC)); + synths.add(new AsmFragmentTemplateSynthesisRule("pb(.)z1_derefidx_vbuz2=(.*)", ".*z1.*z1.*|.*z2.*z2.*", null, "vb$1aa=$2", "ldy {z2}\n" + "sta ({z1}),y\n", mapZ2)); + + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=_deref_pb(.)c1(.*)", ".*=.*aa.*", "lda {c1}\n", "$1=vb$2aa$3", null, mapC)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=_deref_pb(.)z1(.*)", ".*z1.*z1.*|.*=.*aa.*|.*=.*yy.*", "ldy #0\n" + "lda ({z1}),y\n", "$1=vb$2aa$3", null, mapZ)); + + // Convert array indexing with A register to X/Y register by prefixing tax/tay (..._derefidx_vbuaa... -> ..._derefidx_vbuxx... /... _derefidx_vbuyy... ) + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_derefidx_vbuaa(.*)", ".*=.*xx.*", "tax\n", "$1=$2_derefidx_vbuxx$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_derefidx_vbuaa(.*)", ".*=.*yy.*", "tay\n", "$1=$2_derefidx_vbuyy$3", null, null)); + // Convert array indexing with zero page to x/y register by prefixing ldx z1 / ldy z1 ( ..._derefidx_vbuzn... -> ..._derefidx_vbuxx... / ..._derefidx_vbuyy... ) + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_derefidx_vbuz1(.*)", ".*=.*xx.*|.*z1.*z1.*", "ldx {z1}\n", "$1=$2_derefidx_vbuxx$3", null, mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_derefidx_vbuz1(.*)", ".*=.*yy.*|.*z1.*z1.*", "ldy {z1}\n", "$1=$2_derefidx_vbuyy$3", null, mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_derefidx_vbuz2(.*)", ".*=.*xx.*|.*z2.*z2.*", "ldx {z2}\n", "$1=$2_derefidx_vbuxx$3", null, mapZ3)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_derefidx_vbuz2(.*)", ".*=.*yy.*|.*z2.*z2.*", "ldy {z2}\n", "$1=$2_derefidx_vbuyy$3", null, mapZ3)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_derefidx_vbuz3(.*)", ".*=.*yy.*", "ldy {z3}\n", "$1=$2_derefidx_vbuyy$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_derefidx_vbuz3(.*)", ".*=.*xx.*", "ldx {z3}\n", "$1=$2_derefidx_vbuxx$3", null, null)); + // Convert array indexing twice with A/zp1/zp2 to X/Y register with a ldx/ldy prefix ( ..._derefidx_vbunn..._derefidx_vbunn... -> ..._derefidx_vbuxx..._derefidx_vbuxx... ) + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_derefidx_vbuaa(.*)_derefidx_vbuaa(.*)", ".*aa.*aa.*aa.*|.*xx.*", null, "$1_derefidx_vbuxx$2_derefidx_vbuxx$3", "tax\n", null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_derefidx_vbuaa(.*)_derefidx_vbuaa(.*)", ".*aa.*aa.*aa.*|.*yy.*", null, "$1_derefidx_vbuyy$2_derefidx_vbuyy$3", "tay\n", null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_derefidx_vbuz1(.*)_derefidx_vbuz1(.*)", ".*z1.*z1.*z1.*|.*xx.*", null, "$1_derefidx_vbuxx$2_derefidx_vbuxx$3", "ldx {z1}\n", mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_derefidx_vbuz1(.*)_derefidx_vbuz1(.*)", ".*z1.*z1.*z1.*|.*yy.*", null, "$1_derefidx_vbuyy$2_derefidx_vbuyy$3", "ldy {z1}\n", mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_derefidx_vbuz2(.*)_derefidx_vbuz2(.*)", ".*z2.*z2.*z2.*|.*xx.*", null, "$1_derefidx_vbuxx$2_derefidx_vbuxx$3", "ldx {z2}\n", mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_derefidx_vbuz2(.*)_derefidx_vbuz2(.*)", ".*z2.*z2.*z2.*|.*yy.*", null, "$1_derefidx_vbuyy$2_derefidx_vbuyy$3", "ldy {z2}\n", mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("pb(.)c1_derefidx_vbuz1=(.*c1.*)", ".*z1.*z1.*", null, "vb$1aa=$2", "ldx {z1}\n" + "sta {c1},x\n", mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("pb(.)c1_derefidx_vbuz1=(.*z1.*)", ".*c1.*c1.*", null, "vb$1aa=$2", "ldx {z1}\n" + "sta {c1},x\n", mapC)); + + // Convert X/Y-based array indexing of a constant pointer into A-register by prefixing lda cn,x / lda cn,y ( ...pb.c1_derefidx_vbuxx... / ...pb.c1_derefidx_vbuyy... -> ...vb.aa... ) + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)pb(.)c1_derefidx_vbuxx(.*)", ".*=.*aa.*|.*c1.*c1.*", "lda {c1},x\n", "$1=$2vb$3aa$4", null, mapC)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*c1.*)pb(.)c1_derefidx_vbuxx(.*)", ".*=.*aa.*", "lda {c1},x\n", "$1=$2vb$3aa$4", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)pb(.)c1_derefidx_vbuxx(.*c1.*)", ".*=.*aa.*", "lda {c1},x\n", "$1=$2vb$3aa$4", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)pb(.)c1_derefidx_vbuyy(.*)", ".*=.*aa.*|.*c1.*c1.*", "lda {c1},y\n", "$1=$2vb$3aa$4", null, mapC)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*c1.*)pb(.)c1_derefidx_vbuyy(.*)", ".*=.*aa.*", "lda {c1},y\n", "$1=$2vb$3aa$4", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)pb(.)c1_derefidx_vbuyy(.*c1.*)", ".*=.*aa.*", "lda {c1},y\n", "$1=$2vb$3aa$4", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)pb(.)c2_derefidx_vbuxx(.*)", ".*=.*aa.*|.*c2.*c2.*", "lda {c2},x\n", "$1=$2vb$3aa$4", null, mapC3)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*c2.*)pb(.)c2_derefidx_vbuxx(.*)", ".*=.*aa.*", "lda {c2},x\n", "$1=$2vb$3aa$4", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)pb(.)c2_derefidx_vbuxx(.*c2.*)", ".*=.*aa.*", "lda {c2},x\n", "$1=$2vb$3aa$4", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)pb(.)c2_derefidx_vbuyy(.*)", ".*=.*aa.*|.*c2.*c2.*", "lda {c2},y\n", "$1=$2vb$3aa$4", null, mapC3)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*c2.*)pb(.)c2_derefidx_vbuyy(.*)", ".*=.*aa.*", "lda {c2},y\n", "$1=$2vb$3aa$4", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)pb(.)c2_derefidx_vbuyy(.*c2.*)", ".*=.*aa.*", "lda {c2},y\n", "$1=$2vb$3aa$4", null, null)); + + // Convert zeropage/constants/X/Y in assignments to A-register using LDA/TXA/TYA prefix + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vbuz1(.*)", ".*z1.*=.*|.*=.*aa.*|.*z1.*z1.*", "lda {z1}\n", "$1=$2vbuaa$3", null, mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vbsz1(.*)", ".*z1.*=.*|.*=.*aa.*|.*z1.*z1.*", "lda {z1}\n", "$1=$2vbsaa$3", null, mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vbuz2(.*)", ".*z2.*=.*|.*=.*aa.*|.*z2.*z2.*|.*z3.*", "lda {z2}\n", "$1=$2vbuaa$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vbsz2(.*)", ".*z2.*=.*|.*=.*aa.*|.*z2.*z2.*|.*z3.*", "lda {z2}\n", "$1=$2vbsaa$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vbuz2(.*z3.*)", ".*z2.*=.*|.*=.*aa.*|.*z2.*z2.*|.*z3.*", "lda {z2}\n", "$1=$2vbuaa$3", null, mapZ3)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vbsz2(.*z3.*)", ".*z2.*=.*|.*=.*aa.*|.*z2.*z2.*|.*z3.*", "lda {z2}\n", "$1=$2vbsaa$3", null, mapZ3)); + + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_vbuxx", ".*=.*[ax][ax].*xx|.*derefidx_vb.xx", "txa\n", "$1=$2_vbuaa", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_vbsxx", ".*=.*[ax][ax].*xx|.*derefidx_vb.xx", "txa\n", "$1=$2_vbsaa", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_vbuyy", ".*=.*[ay][ay].*yy|.*derefidx_vb.yy", "tya\n", "$1=$2_vbuaa", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_vbsyy", ".*=-*[ay][ay].*yy|.*derefidx_vb.yy", "tya\n", "$1=$2_vbsaa", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_vbuz1", ".*=.*aa.*|.*z1.*z1.*", "lda {z1}\n", "$1=$2_vbuaa", null, mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_vbsz1", ".*=.*aa.*|.*z1.*z1.*", "lda {z1}\n", "$1=$2_vbsaa", null, mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_vbuz2", ".*=.*aa.*|.*z2.*z2.*", "lda {z2}\n", "$1=$2_vbuaa", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_vbuz3", ".*=.*aa.*|.*z3.*z3.*", "lda {z3}\n", "$1=$2_vbuaa", null, null)); + + synths.add(new AsmFragmentTemplateSynthesisRule("vbuz1=vbuz1(.*)", ".*=.*vb.aa.*|.*z1.*z1.*z1.*", "lda {z1}\n", "vbuaa=vbuaa$1", "sta {z1}\n", mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("vbsz1=vbsz1(.*)", ".*=.*vb.aa.*|.*z1.*z1.*z1.*", "lda {z1}\n", "vbsaa=vbsaa$1", "sta {z1}\n", mapZ)); + + synths.add(new AsmFragmentTemplateSynthesisRule("vbuz1_(lt|gt|le|ge|eq|neq)_(.*)", ".*vb.aa.*|.*z1.*z1.*", "lda {z1}\n", "vbuaa_$1_$2", null, mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("vbsz1_(lt|gt|le|ge|eq|neq)_(.*)", ".*vb.aa.*|.*z1.*z1.*", "lda {z1}\n", "vbsaa_$1_$2", null, mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("_deref_pb(.)c1_(lt|gt|le|ge|eq|neq)_(.*)", ".*vb.aa.*", "lda {c1}\n", "vb$1aa_$2_$3", null, mapC)); + synths.add(new AsmFragmentTemplateSynthesisRule("_deref_pb(.)z1_(lt|gt|le|ge|eq|neq)_(.*)", ".*vb.aa.*|.*vb.yy.*|.*z1.*z1.*", "ldy #0\n" + "lda ({z1}),y\n", "vb$1aa_$2_$3", null, mapZ)); + + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_derefidx_vbuz1_(.*)", ".*z1.*z1.*|.*.yy.*", "ldy {z1}\n", "$1_derefidx_vbuyy_$2", null, mapZ)); + + + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_derefidx_vbuz1_(lt|gt|le|ge|eq|neq)_(.*)", ".*z1.*z1.*|.*vb.xx.*", "ldx {z1}\n", "$1_derefidx_vbuxx_$2_$3", null, mapZ)); + synths.add(new AsmFragmentTemplateSynthesisRule("pb(.)c1_derefidx_vbuyy_(lt|gt|le|ge|eq|neq)_(.*)", ".*c1.*c1.*|.*aa.*", "lda {c1},y\n", "vb$1aa_$2_$3", null, mapC)); + synths.add(new AsmFragmentTemplateSynthesisRule("pb(.)c1_derefidx_vbuyy_(lt|gt|le|ge|eq|neq)_(.*c1.*)", ".*aa.*", "lda {c1},y\n", "vb$1aa_$2_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("pb(.)c1_derefidx_vbuxx_(lt|gt|le|ge|eq|neq)_(.*)", ".*c1.*c1.*|.*aa.*", "lda {c1},x\n", "vb$1aa_$2_$3", null, mapC)); + synths.add(new AsmFragmentTemplateSynthesisRule("pb(.)c1_derefidx_vbuxx_(lt|gt|le|ge|eq|neq)_(.*c1.*)", ".*aa.*", "lda {c1},x\n", "vb$1aa_$2_$3", null, null)); + + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_ge_(vb.aa)_then_(.*)", ".*vb.aa.*_ge.*", null, "$2_le_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_ge_(vb.xx)_then_(.*)", ".*vb.[ax][ax].*_ge.*", null, "$2_le_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_ge_(vb.yy)_then_(.*)", ".*vb.[axy][axy].*_ge.*", null, "$2_le_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_lt_(vb.aa)_then_(.*)", ".*vb.aa.*_lt.*", null, "$2_gt_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_lt_(vb.xx)_then_(.*)", ".*vb.[ax][ax].*_lt.*", null, "$2_gt_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_lt_(vb.yy)_then_(.*)", ".*vb.[axy][axy].*_lt.*", null, "$2_gt_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_gt_(vb.aa)_then_(.*)", ".*vb.aa.*_gt.*", null, "$2_lt_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_gt_(vb.xx)_then_(.*)", ".*vb.[ax][ax].*_gt.*", null, "$2_lt_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_gt_(vb.yy)_then_(.*)", ".*vb.[axy][axy].*_gt.*", null, "$2_lt_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_le_(vb.aa)_then_(.*)", ".*vb.aa.*_le.*", null, "$2_ge_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_le_(vb.xx)_then_(.*)", ".*vb.[ax][ax].*_le.*", null, "$2_ge_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_le_(vb.yy)_then_(.*)", ".*vb.[axy][axy].*_le.*", null, "$2_ge_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_neq_(vb.aa)_then_(.*)", ".*vb.aa.*_neq.*", null, "$2_neq_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_neq_(vb.xx)_then_(.*)", ".*vb.[ax][ax].*_neq.*", null, "$2_neq_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_neq_(vb.yy)_then_(.*)", ".*vb.[axy][axy].*_neq.*", null, "$2_neq_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_eq_(vb.aa)_then_(.*)", ".*vb.aa.*_eq.*", null, "$2_eq_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_eq_(vb.xx)_then_(.*)", ".*vb.[ax][ax].*_eq.*", null, "$2_eq_$1_then_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_eq_(vb.yy)_then_(.*)", ".*vb.[axy][axy].*_eq.*", null, "$2_eq_$1_then_$3", null, null)); + + // Use unsigned ASM to synthesize signed ASM ( ...vbs... -> ...vbu... ) + synths.add(new AsmFragmentTemplateSynthesisRule("(vbsz.|vbsc.|vbsaa|vbsxx|vbsyy)_(eq|neq)_(vbsz.|vbsc.|vbsaa|vbsxx|vbsyy)_then_(.*)", null, null, "$1_$2_$3_then_$4", null, mapSToU)); + synths.add(new AsmFragmentTemplateSynthesisRule("(vbsz.|vbsc.|vbsaa|vbsxx|vbsyy)=(vbsz.|vbsc.|vbsaa|vbsxx|vbsyy)", null, null, "$1=$2", null, mapSToU)); + synths.add(new AsmFragmentTemplateSynthesisRule("(vbsz.|vbsc.|vbsaa|vbsxx|vbsyy)=(vbsz.|vbsc.|vbsaa|vbsxx|vbsyy)_(plus|band|bxor|bor)_(vbsz.|csoby.|vbsaa|vbsxx|vbsyy)", null, null, "$1=$2_$3_$4", null, mapSToU)); + synths.add(new AsmFragmentTemplateSynthesisRule("(vbsz.|vbsc.|vbsaa|vbsxx|vbsyy)=_(inc|dec)_(vbsz.|vbsc.|vbsaa|vbsxx|vbsyy)", null, null, "$1=_$2_$3", null, mapSToU)); + synths.add(new AsmFragmentTemplateSynthesisRule("(vwsz.|vwsc.)_(eq|neq)_(vwsz.|vwsc.)_then_(.*)", null, null, "$1_$2_$3_then_$4", null, mapSToU)); + synths.add(new AsmFragmentTemplateSynthesisRule("(vwsz.)=(vwsz.|vwsc.)", null, null, "$1=$2", null, mapSToU)); + synths.add(new AsmFragmentTemplateSynthesisRule("(v.sz.)=(v.s..)_(band|bxor|bor)_(v.s..)", null, null, "$1=$2_$3_$4", null, mapSToU)); + synths.add(new AsmFragmentTemplateSynthesisRule("(vbuz.|vbuaa|vbuxx|vbuyy)=_(lo|hi)_vws(z.|c.)", null, null, "$1=_$2_vwu$3", null, mapSToU)); + + // Use constant word ASM to synthesize unsigned constant byte ASM ( ...vb.c... -> vw.c... ) + synths.add(new AsmFragmentTemplateSynthesisRule("(vwuz.)=(vwuz.)_(plus|minus|band|bxor|bor)_vb.c(.)", null, null, "$1=$2_$3_vwuc$4", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(vwuz.)=vb.c(.)_(plus|minus|band|bxor|bor)_(vwuz.)", null, null, "$1=vwuc$2_$3_$4", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(vwsz.)=(vwsz.)_(plus|minus|band|bxor|bor)_vb.c(.)", null, null, "$1=$2_$3_vwsc$4", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(vwsz.)=vb.c(.)_(plus|minus|band|bxor|bor)_(vwsz.)", null, null, "$1=vwsc$2_$3_$4", null, null)); + + // Move constant words to the end of the ASM signature for symmetric operators ( ...vw.c...vw.z... -> ...vw.z...vw.c... ) + synths.add(new AsmFragmentTemplateSynthesisRule("(vwuz.)=(vwuc.)_(plus|band|bxor|bor)_(vwuz.)", null, null, "$1=$4_$3_$2", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(vwsz.)=(vwsc.)_(plus|band|bxor|bor)_(vwsz.)", null, null, "$1=$4_$3_$2", null, null)); + + // Use Z1/Z2 ASM to synthesize Z1-only code ( ...z1...z1... -> ...z1...z2... ) + synths.add(new AsmFragmentTemplateSynthesisRule("(v..)z1=(v..)z1_(plus|minus|band|bxor|bor)_(.*)", ".*z2.*", null, "$1z1=$2z2_$3_$4", null, mapZ, false)); + synths.add(new AsmFragmentTemplateSynthesisRule("(v..)z1=(.*)_(plus|minus|band|bxor|bor)_(v..)z1", ".*z2.*", null, "$1z1=$2_$3_$4z2", null, mapZ, false)); + synths.add(new AsmFragmentTemplateSynthesisRule("(v..)z1=_(neg|lo|hi)_(v..)z1", ".*z2.*", null, "$1z1=_$2_$3z2", null, mapZ, false)); + + // Convert INC/DEC to +1/-1 ( ..._inc_xxx... -> ...xxx_plus_1_... / ..._dec_xxx... -> ...xxx_minus_1_... ) + synths.add(new AsmFragmentTemplateSynthesisRule("vb(.)aa=_inc_(.*)", null, null, "vb$1aa=$2_plus_1", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("vb(.)aa=_dec_(.*)", null, null, "vb$1aa=$2_minus_1", null, null)); + + // Synthesize XX/YY using AA + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vbuxx(.*)", ".*=.*aa.*|.*derefidx_vb.xx.*", "txa\n", "$1=$2vbuaa$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vbsxx(.*)", ".*=.*aa.*|.*derefidx_vb.xx.*", "txa\n", "$1=$2vbsaa$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vbuyy(.*)", ".*=.*aa.*|.*derefidx_vb.yy.*", "tya\n", "$1=$2vbuaa$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vbsyy(.*)", ".*=.*aa.*|.*derefidx_vb.yy.*", "tya\n", "$1=$2vbsaa$3", null, null)); + // Synthesize constants using AA + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vbuc1(.*)", ".*=.*aa.*|.*c1.*c1.*|.*c1_deref.*", "lda #{c1}\n", "$1=$2vbuaa$3", null, mapC)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vbsc1(.*)", ".*=.*aa.*|.*c1.*c1.*|.*c1_deref.*", "lda #{c1}\n", "$1=$2vbsaa$3", null, mapC)); + + // Synthesize some constant pointers as constant words + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_(lt|gt|le|ge|eq|neq)_p..([cz].)_then_(.*)", null, null, "$1_$2_vwu$3_then_$4", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("p..([cz].)_(lt|gt|le|ge|eq|neq)_(.*)", null, null, "vwu$1_$2_$3", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=p..([zc].)", null, null, "$1=vwu$2", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_(plus|minus|bor|bxor)_p..([cz].)", null, null, "$1=$2_$3_vwu$4", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=p..([cz].)_(plus|minus|bor|bxor)_(.*)", null, null, "$1=vwu$2_$3_$4", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("p..([cz].)=(.*)_(sethi|setlo|plus|minus)_(.*)", null, null, "vwu$1=$2_$3_$4", null, null)); + synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=p..([cz].)_(sethi|setlo|plus|minus)_(.*)", null, null, "$1=vwu$2_$3_$4", null, null)); + + return synths; + } + + /** + * The synthesis path describes the different signatures being attempted to synthesize a fragment. + * Used to avoid infinite loops during synthesis. + */ + static class AsmSynthesisPath { + + private ArrayDeque signatures; + + public AsmSynthesisPath() { + this.signatures = new ArrayDeque<>(); + } + + private AsmSynthesisPath(ArrayDeque signatures) { + this.signatures = signatures; + } + + AsmSynthesisPath add(String signature) { + ArrayDeque signatures = new ArrayDeque<>(this.signatures); + signatures.add(signature); + return new AsmSynthesisPath(signatures); + } + + boolean has(String signature) { + return signatures.contains(signature); + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + boolean first = true; + for(String signature : signatures) { + if(first) { + first = false; + } else { + str.append(" < "); + } + str.append(signature); + } + return str.toString(); + } + } + + /** + * Capable of creating fragments from signatures by loading them or synthesizing them from other smaller fragments. + *

+ * The synthesizer tries a lot of different combinations and keeps track of what has already been attempted. + */ + static class AsmFragmentTemplateSynthesizer { + + /** Signature of the fragment being synthesized. */ + private String creating; + + /** The log. */ + private CompileLog log; + + AsmFragmentTemplateSynthesizer(String creating, CompileLog log) { + this.creating = creating; + this.log = log; + } + + List loadOrSynthesizeFragment(String signature, AsmSynthesisPath path) { + if(path.has(signature)) { + // Synthesis loop - stop it here + if(log.isVerboseFragmentLog()) { + log.append("Finding fragment " + path.toString() + " - Stopping synthesis loop at " + signature); + } + return new ArrayList<>(); + } + // Add the current signature to the path + path = path.add(signature); + if(fragmentTemplateCache.get(signature) != null) { + if(log.isVerboseFragmentLog()) { + log.append("Finding fragment " + path.toString() + " - Using cached " + signature); + } + return fragmentTemplateCache.get(signature); + } + if(log.isVerboseFragmentLog()) { + log.append("Finding fragment " + path.toString() + " - Attempting " + signature); + } + List candidates = new ArrayList<>(); + // Synthesize the fragment from other fragments + List synths = getFragmentSyntheses(); + for(AsmFragmentTemplateSynthesisRule synth : synths) { + List synthesized = synth.synthesize(signature, path, this); + if(synthesized != null) { + if(log.isVerboseFragmentLog() && synthesized.size() > 0) { + log.append("Finding fragment " + path.toString() + " - Successfully synthesized " + synthesized.size() + " fragments "); + } + candidates.addAll(synthesized); + } + } + // Load the fragment from disk + CharStream fragmentCharStream = loadFragment(signature); + if(fragmentCharStream != null) { + try { + String body = fragmentCharStream.toString(); + candidates.add(new AsmFragmentTemplate(signature, body)); + + } catch(StringIndexOutOfBoundsException e) { + throw new RuntimeException("Problem reading fragment file " + signature, e); + } + if(log.isVerboseFragmentLog()) { + log.append("Finding fragment " + path.toString() + " - Successfully loaded " + signature + ".asm"); + } + } + if(candidates.size() == 0) { + if(log.isVerboseFragmentLog()) { + log.append("Finding fragment " + path.toString() + " - No synthesis/file found!"); + } + } + fragmentTemplateCache.put(signature, candidates); + return candidates; + } + + public String getCreating() { + return creating; + } + + public CompileLog getLog() { + return log; + } + } + + public static class UnknownFragmentException extends RuntimeException { + + private AsmFragmentInstanceSpec fragmentInstanceSpec; + + UnknownFragmentException(AsmFragmentInstanceSpec fragmentInstanceSpec) { + super("Fragment not found " + fragmentInstanceSpec.getSignature() ); + this.fragmentInstanceSpec = fragmentInstanceSpec; + } + + public String getFragmentSignature() { + return fragmentInstanceSpec.getSignature(); + } + + public String getFragmentDescription() { + return fragmentInstanceSpec.toString(); + } + + public AsmFragmentInstanceSpec getFragmentInstanceSpec() { + return fragmentInstanceSpec; + } + } + +} diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentSynthesis.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateSynthesisRule.java similarity index 88% rename from src/main/java/dk/camelot64/kickc/fragment/AsmFragmentSynthesis.java rename to src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateSynthesisRule.java index b4ed0ed36..66ae24214 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentSynthesis.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateSynthesisRule.java @@ -8,7 +8,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** AsmFragment synthesis mechanism based on matching fragment signature and reusing another fragment with added prefix/postfix and some bind-mappings */ -class AsmFragmentSynthesis { +class AsmFragmentTemplateSynthesisRule { private String sigMatch; private String sigAvoid; @@ -19,7 +19,7 @@ class AsmFragmentSynthesis { private boolean mapSignature; private String subSignature; - AsmFragmentSynthesis(String sigMatch, String sigAvoid, String asmPrefix, String sigReplace, String asmPostfix, Map bindMappings, boolean mapSignature) { + AsmFragmentTemplateSynthesisRule(String sigMatch, String sigAvoid, String asmPrefix, String sigReplace, String asmPostfix, Map bindMappings, boolean mapSignature) { this.sigMatch = sigMatch; this.sigAvoid = sigAvoid; this.asmPrefix = asmPrefix; @@ -29,7 +29,7 @@ class AsmFragmentSynthesis { this.mapSignature = mapSignature; } - public AsmFragmentSynthesis(String sigMatch, String sigAvoid, String asmPrefix, String sigReplace, String asmPostfix, Map bindMappings) { + public AsmFragmentTemplateSynthesisRule(String sigMatch, String sigAvoid, String asmPrefix, String sigReplace, String asmPostfix, Map bindMappings) { this(sigMatch, sigAvoid, asmPrefix, sigReplace, asmPostfix, bindMappings, true); } @@ -48,7 +48,7 @@ class AsmFragmentSynthesis { return sigMatch + (sigAvoid == null ? "" : ("/" + sigAvoid)); } - public List synthesize(String signature, AsmFragmentManager.AsmSynthesisPath path, AsmFragmentManager.AsmFragmentTemplateSynthesizer synthesizer) { + public List synthesize(String signature, AsmFragmentTemplateManager.AsmSynthesisPath path, AsmFragmentTemplateManager.AsmFragmentTemplateSynthesizer synthesizer) { ArrayList candidates = new ArrayList<>(); if(signature.matches(sigMatch)) { if(sigAvoid == null || !signature.matches(sigAvoid)) { diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentUsages.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateUsages.java similarity index 94% rename from src/main/java/dk/camelot64/kickc/fragment/AsmFragmentUsages.java rename to src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateUsages.java index 3d980dce4..349ee2c42 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentUsages.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateUsages.java @@ -5,8 +5,8 @@ import dk.camelot64.kickc.CompileLog; import java.io.File; import java.util.*; -/** Statistics for usage of the ASM fragments. Also contains a methos for identifying redundant/unused files. */ -public class AsmFragmentUsages { +/** Statistics for usage of the ASM fragments. Also contains a methods for identifying redundant/unused files. */ +public class AsmFragmentTemplateUsages { /** Usage Statistics for fragment templates. */ private static Map fragmentTemplateUsage = new HashMap<>(); @@ -35,10 +35,10 @@ public class AsmFragmentUsages { */ public static void logUsages(CompileLog log, boolean logRedundantFiles, boolean logUnusedFiles, boolean logFileDetails, boolean logAllDetails) { - Map> fragmentTemplateCache = AsmFragmentManager.getFragmentTemplateCache(); + Map> fragmentTemplateCache = AsmFragmentTemplateManager.getFragmentTemplateCache(); ArrayList signatures = new ArrayList<>(fragmentTemplateCache.keySet()); Collections.sort(signatures); - File[] files = AsmFragmentManager.allFragmentFiles(); + File[] files = AsmFragmentTemplateManager.allFragmentFiles(); if(logRedundantFiles) { // Find all file fragments that were bested by a synthesized fragment @@ -71,8 +71,8 @@ public class AsmFragmentUsages { String fileName = file.getName(); String signature = fileName.substring(0, fileName.length() - 4); // Try to synthesize the fragment - and check if the synthesis is as good as the file body - AsmFragmentManager.AsmFragmentTemplateSynthesizer synthesizer = new AsmFragmentManager.AsmFragmentTemplateSynthesizer(signature, log); - List templates = synthesizer.loadOrSynthesizeFragment(signature, new AsmFragmentManager.AsmSynthesisPath()); + AsmFragmentTemplateManager.AsmFragmentTemplateSynthesizer synthesizer = new AsmFragmentTemplateManager.AsmFragmentTemplateSynthesizer(signature, log); + List templates = synthesizer.loadOrSynthesizeFragment(signature, new AsmFragmentTemplateManager.AsmSynthesisPath()); AsmFragmentTemplate fileTemplate = null; for(AsmFragmentTemplate template : templates) { if(template.isFile()) { diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java index 20636df49..1e2e5e661 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java @@ -217,13 +217,13 @@ public class Pass4CodeGeneration { if(aluState.hasAluAssignment()) { StatementAssignment assignmentAlu = aluState.getAluAssignment(); if(!(statement instanceof StatementAssignment)) { - throw new AsmFragment.AluNotApplicableException(); + throw new AsmFragmentInstance.AluNotApplicableException(); } StatementAssignment assignment = (StatementAssignment) statement; - AsmFragmentSignature signature = new AsmFragmentSignature(assignment, assignmentAlu, program); - AsmFragment asmFragment = AsmFragmentManager.getFragment(signature, program.getLog()); - asm.getCurrentSegment().setFragment(asmFragment.getFragmentName()); - asmFragment.generate(asm); + AsmFragmentInstanceSpec signature = new AsmFragmentInstanceSpec(assignment, assignmentAlu, program); + AsmFragmentInstance asmFragmentInstance = AsmFragmentTemplateManager.getFragment(signature, program.getLog()); + asm.getCurrentSegment().setFragment(asmFragmentInstance.getFragmentName()); + asmFragmentInstance.generate(asm); aluState.clear(); return; } @@ -247,17 +247,17 @@ public class Pass4CodeGeneration { if(assignment.getOperator() == null && assignment.getrValue1() == null && isRegisterCopy(lValue, assignment.getrValue2())) { asm.addComment(lValue.toString(program) + " = " + assignment.getrValue2().toString(program) + " // register copy " + getRegister(lValue)); } else { - AsmFragmentSignature asmFragmentSignature = new AsmFragmentSignature(assignment, program); - AsmFragment asmFragment = AsmFragmentManager.getFragment(asmFragmentSignature, program.getLog()); - asm.getCurrentSegment().setFragment(asmFragment.getFragmentName()); - asmFragment.generate(asm); + AsmFragmentInstanceSpec asmFragmentInstanceSpec = new AsmFragmentInstanceSpec(assignment, program); + AsmFragmentInstance asmFragmentInstance = AsmFragmentTemplateManager.getFragment(asmFragmentInstanceSpec, program.getLog()); + asm.getCurrentSegment().setFragment(asmFragmentInstance.getFragmentName()); + asmFragmentInstance.generate(asm); } } } else if(statement instanceof StatementConditionalJump) { - AsmFragmentSignature asmSignature = new AsmFragmentSignature((StatementConditionalJump) statement, block, program, getGraph()); - AsmFragment asmFragment = AsmFragmentManager.getFragment(asmSignature, program.getLog()); - asm.getCurrentSegment().setFragment(asmFragment.getFragmentName()); - asmFragment.generate(asm); + AsmFragmentInstanceSpec asmSignature = new AsmFragmentInstanceSpec((StatementConditionalJump) statement, block, program, getGraph()); + AsmFragmentInstance asmFragmentInstance = AsmFragmentTemplateManager.getFragment(asmSignature, program.getLog()); + asm.getCurrentSegment().setFragment(asmFragmentInstance.getFragmentName()); + asmFragmentInstance.generate(asm); } else if(statement instanceof StatementCall) { StatementCall call = (StatementCall) statement; if(genCallPhiEntry) { @@ -276,8 +276,8 @@ public class Pass4CodeGeneration { } else if(statement instanceof StatementAsm) { StatementAsm statementAsm = (StatementAsm) statement; HashMap bindings = new HashMap<>(); - AsmFragment asmFragment = new AsmFragment(program, "inline", block.getScope(), new AsmFragmentTemplate(statementAsm.getAsmLines()), bindings); - asmFragment.generate(asm); + AsmFragmentInstance asmFragmentInstance = new AsmFragmentInstance(program, "inline", block.getScope(), new AsmFragmentTemplate(statementAsm.getAsmLines()), bindings); + asmFragmentInstance.generate(asm); } else { throw new RuntimeException("Statement not supported " + statement); } @@ -340,10 +340,10 @@ public class Pass4CodeGeneration { if(isRegisterCopy(lValue, rValue)) { asm.getCurrentSegment().setFragment("register_copy"); } else { - AsmFragmentSignature asmSignature = new AsmFragmentSignature(lValue, rValue, program, scope); - AsmFragment asmFragment = AsmFragmentManager.getFragment(asmSignature, program.getLog()); - asm.getCurrentSegment().setFragment(asmFragment.getFragmentName()); - asmFragment.generate(asm); + AsmFragmentInstanceSpec asmSignature = new AsmFragmentInstanceSpec(lValue, rValue, program, scope); + AsmFragmentInstance asmFragmentInstance = AsmFragmentTemplateManager.getFragment(asmSignature, program.getLog()); + asm.getCurrentSegment().setFragment(asmFragmentInstance.getFragmentName()); + asmFragmentInstance.generate(asm); } } transition.setGenerated(true); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftCombinations.java b/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftCombinations.java index d0a2ac57a..db9113441 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftCombinations.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftCombinations.java @@ -2,8 +2,9 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.asm.AsmProgram; import dk.camelot64.kickc.asm.AsmSegment; -import dk.camelot64.kickc.fragment.AsmFragment; -import dk.camelot64.kickc.fragment.AsmFragmentManager; +import dk.camelot64.kickc.fragment.AsmFragmentInstance; +import dk.camelot64.kickc.fragment.AsmFragmentInstanceSpec; +import dk.camelot64.kickc.fragment.AsmFragmentTemplateManager; import dk.camelot64.kickc.model.*; import java.util.*; @@ -27,7 +28,7 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base { */ static void chooseBestUpliftCombination( RegisterCombinationIterator combinationIterator, int maxCombinations, - Set unknownFragments, + Set unknownFragments, ScopeRef scope, Program program ) { @@ -85,7 +86,7 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base { public static boolean generateCombinationAsm( RegisterCombination combination, Program program, - Set unknownFragments, + Set unknownFragments, ScopeRef scope) { // Reset register allocation to original zero page allocation new Pass4RegistersFinalize(program).allocate(false); @@ -106,8 +107,8 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base { // Generate ASM try { new Pass4CodeGeneration(program, false).generate(); - } catch(AsmFragmentManager.UnknownFragmentException e) { - unknownFragments.add(e.getFragmentSignature()); + } catch(AsmFragmentTemplateManager.UnknownFragmentException e) { + unknownFragments.add(e.getFragmentInstanceSpec()); if(program.getLog().isVerboseUplift()) { StringBuilder msg = new StringBuilder(); msg.append("Uplift attempt [" + (scope == null ? "" : scope) + "] "); @@ -116,7 +117,7 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base { program.getLog().append(msg.toString()); } return false; - } catch(AsmFragment.AluNotApplicableException e) { + } catch(AsmFragmentInstance.AluNotApplicableException e) { if(program.getLog().isVerboseUplift()) { StringBuilder msg = new StringBuilder(); msg.append("Uplift attempt [" + (scope == null ? "" : scope) + "] "); @@ -234,7 +235,7 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base { public void performUplift(int maxCombinations) { // Test uplift combinations to find the best one. - Set unknownFragments = new LinkedHashSet<>(); + Set unknownFragments = new LinkedHashSet<>(); List registerUpliftScopes = getProgram().getRegisterUpliftProgram().getRegisterUpliftScopes(); for(RegisterUpliftScope upliftScope : registerUpliftScopes) { RegisterCombinationIterator combinationIterator = upliftScope.getCombinationIterator(getProgram().getRegisterPotentials()); @@ -248,8 +249,8 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base { if(unknownFragments.size() > 0) { getLog().append("MISSING FRAGMENTS"); - for(String unknownFragment : unknownFragments) { - getLog().append(" " + unknownFragment); + for(AsmFragmentInstanceSpec unknownFragment : unknownFragments) { + getLog().append(" " + unknownFragment.toString()); } } } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftPotentialRegisterAnalysis.java b/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftPotentialRegisterAnalysis.java index c4e2eb227..f075db339 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftPotentialRegisterAnalysis.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftPotentialRegisterAnalysis.java @@ -2,8 +2,8 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.asm.AsmClobber; import dk.camelot64.kickc.asm.AsmProgram; -import dk.camelot64.kickc.fragment.AsmFragment; -import dk.camelot64.kickc.fragment.AsmFragmentManager; +import dk.camelot64.kickc.fragment.AsmFragmentInstance; +import dk.camelot64.kickc.fragment.AsmFragmentTemplateManager; import dk.camelot64.kickc.model.*; import java.util.*; @@ -196,15 +196,15 @@ public class Pass4RegisterUpliftPotentialRegisterAnalysis extends Pass2Base { Pass4CodeGeneration.AsmCodegenAluState aluState = new Pass4CodeGeneration.AsmCodegenAluState(); try { (new Pass4CodeGeneration(getProgram(), false)).generateStatementAsm(asm, block, statement, aluState, false); - } catch(AsmFragmentManager.UnknownFragmentException e) { - unknownFragments.add(e.getFragmentSignature()); + } catch(AsmFragmentTemplateManager.UnknownFragmentException e) { + unknownFragments.add(e.getFragmentDescription()); StringBuilder msg = new StringBuilder(); msg.append("Potential register analysis " + statement); msg.append(" missing fragment " + e.getFragmentSignature()); msg.append(" allocation: ").append(combination.toString()); getLog().append(msg.toString()); continue; - } catch(AsmFragment.AluNotApplicableException e) { + } catch(AsmFragmentInstance.AluNotApplicableException e) { if(getProgram().getLog().isVerboseUplift()) { StringBuilder msg = new StringBuilder(); msg.append("Potential register analysis "); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftRemains.java b/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftRemains.java index e5cafb65c..718f80f74 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftRemains.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftRemains.java @@ -1,5 +1,6 @@ package dk.camelot64.kickc.passes; +import dk.camelot64.kickc.fragment.AsmFragmentInstanceSpec; import dk.camelot64.kickc.model.*; import java.util.*; @@ -23,7 +24,7 @@ public class Pass4RegisterUpliftRemains extends Pass2Base { } }); - Set unknownFragments = new LinkedHashSet<>(); + Set unknownFragments = new LinkedHashSet<>(); for(LiveRangeEquivalenceClass equivalenceClass : equivalenceClasses) { if(equivalenceClass.getRegister().getType().equals(Registers.RegisterType.ZP_BYTE)) { @@ -37,8 +38,8 @@ public class Pass4RegisterUpliftRemains extends Pass2Base { if(unknownFragments.size() > 0) { getLog().append("MISSING FRAGMENTS"); - for(String unknownFragment : unknownFragments) { - getLog().append(" " + unknownFragment); + for(AsmFragmentInstanceSpec unknownFragment : unknownFragments) { + getLog().append(" " + unknownFragment.toString()); } } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftStatic.java b/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftStatic.java index fffc542e6..3efebac74 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftStatic.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftStatic.java @@ -1,5 +1,6 @@ package dk.camelot64.kickc.passes; +import dk.camelot64.kickc.fragment.AsmFragmentInstanceSpec; import dk.camelot64.kickc.model.*; import java.util.HashSet; @@ -87,7 +88,7 @@ public class Pass4RegisterUpliftStatic extends Pass2Base { boolean success = Pass4RegisterUpliftCombinations.generateCombinationAsm( combination, getProgram(), - new HashSet(), + new HashSet<>(), null); if(success) { diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 7a6ebc1a7..e519b7504 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -2,7 +2,7 @@ package dk.camelot64.kickc.test; import dk.camelot64.kickc.CompileLog; import dk.camelot64.kickc.Compiler; -import dk.camelot64.kickc.fragment.AsmFragmentUsages; +import dk.camelot64.kickc.fragment.AsmFragmentTemplateUsages; import dk.camelot64.kickc.model.CompileError; import dk.camelot64.kickc.model.Program; import org.junit.AfterClass; @@ -32,7 +32,7 @@ public class TestPrograms { public static void tearDown() throws Exception { CompileLog log = new CompileLog(); log.setSysOut(true); - AsmFragmentUsages.logUsages(log, false, false, false, false); + AsmFragmentTemplateUsages.logUsages(log, false, false, false, false); } @Test diff --git a/src/test/java/dk/camelot64/kickc/test/ref/callconstparam.log b/src/test/java/dk/camelot64/kickc/test/ref/callconstparam.log index 984f6de78..0f40ea4db 100644 --- a/src/test/java/dk/camelot64/kickc/test/ref/callconstparam.log +++ b/src/test/java/dk/camelot64/kickc/test/ref/callconstparam.log @@ -500,8 +500,12 @@ Uplift Scope [main] Uplifting [line] best 426 combination reg byte x [ line::x#2 line::x#0 line::x#1 ] zp ZP_BYTE:2 [ line::x1#3 ] Uplifting [] best 426 combination zp ZP_WORD:4 [ screen#10 screen#14 screen#11 ] Uplifting [main] best 426 combination +MISSING FRAGMENTS + vbuxx_lt_vbuaa_then_la1(line:: vbuxx=(byte) line::x#1 vbuaa=(byte) line::x1#3 la1=(label) line::b1_from_b1 ) Attempting to uplift remaining variables inzp ZP_BYTE:2 [ line::x1#3 ] Uplifting [line] best 426 combination zp ZP_BYTE:2 [ line::x1#3 ] +MISSING FRAGMENTS + vbuxx_lt_vbuaa_then_la1(line:: vbuxx=(byte) line::x#1 vbuaa=(byte) line::x1#3 la1=(label) line::b1_from_b1 ) Allocated (was zp ZP_WORD:4) zp ZP_WORD:3 [ screen#10 screen#14 screen#11 ] ASSEMBLER BEFORE OPTIMIZATION diff --git a/src/test/java/dk/camelot64/kickc/test/ref/inline-word.log b/src/test/java/dk/camelot64/kickc/test/ref/inline-word.log index aaec9c226..50cf5d382 100644 --- a/src/test/java/dk/camelot64/kickc/test/ref/inline-word.log +++ b/src/test/java/dk/camelot64/kickc/test/ref/inline-word.log @@ -447,8 +447,8 @@ main: { } REGISTER UPLIFT POTENTIAL REGISTERS -Potential register analysis [7] main::w#0 ← *(main::his#0 + main::h#4) w= main::l#2 missing fragment vwuz1=pbuc1_derefidx_vbuaa_word_vbuxx(main:: vwuz1=(word) main::w#0 pbuc1=(const byte[]) main::his#0 vbuaa=(byte) main::h#4 vbuxx=(byte) main::l#2 ) allocation: reg byte a [ main::h#4 main::h#1 ] reg byte x [ main::l#2 main::l#1 ] zp ZP_WORD:4 [ main::w#0 ] -Potential register analysis [7] main::w#0 ← *(main::his#0 + main::h#4) w= main::l#2 missing fragment vwuz1=pbuc1_derefidx_vbuaa_word_vbuyy(main:: vwuz1=(word) main::w#0 pbuc1=(const byte[]) main::his#0 vbuaa=(byte) main::h#4 vbuyy=(byte) main::l#2 ) allocation: reg byte a [ main::h#4 main::h#1 ] reg byte y [ main::l#2 main::l#1 ] zp ZP_WORD:4 [ main::w#0 ] +Potential register analysis [7] main::w#0 ← *(main::his#0 + main::h#4) w= main::l#2 missing fragment vwuz1=pbuc1_derefidx_vbuaa_word_vbuxx allocation: reg byte a [ main::h#4 main::h#1 ] reg byte x [ main::l#2 main::l#1 ] zp ZP_WORD:4 [ main::w#0 ] +Potential register analysis [7] main::w#0 ← *(main::his#0 + main::h#4) w= main::l#2 missing fragment vwuz1=pbuc1_derefidx_vbuaa_word_vbuyy allocation: reg byte a [ main::h#4 main::h#1 ] reg byte y [ main::l#2 main::l#1 ] zp ZP_WORD:4 [ main::w#0 ] MISSING FRAGMENTS vwuz1=pbuc1_derefidx_vbuaa_word_vbuxx(main:: vwuz1=(word) main::w#0 pbuc1=(const byte[]) main::his#0 vbuaa=(byte) main::h#4 vbuxx=(byte) main::l#2 ) vwuz1=pbuc1_derefidx_vbuaa_word_vbuyy(main:: vwuz1=(word) main::w#0 pbuc1=(const byte[]) main::his#0 vbuaa=(byte) main::h#4 vbuyy=(byte) main::l#2 ) diff --git a/src/test/java/dk/camelot64/kickc/test/ref/scrollbig.log b/src/test/java/dk/camelot64/kickc/test/ref/scrollbig.log index 7ffc53afe..956adcbb9 100644 --- a/src/test/java/dk/camelot64/kickc/test/ref/scrollbig.log +++ b/src/test/java/dk/camelot64/kickc/test/ref/scrollbig.log @@ -3050,8 +3050,8 @@ Statement [7] if(*((const byte*) RASTER#0)!=(byte/word/signed word) 254) goto ma Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ scroll#18 scroll#10 scroll#3 ] Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ current_bit#29 current_bit#12 current_bit#21 current_bit#5 ] Statement [8] if(*((const byte*) RASTER#0)!=(byte/word/signed word) 255) goto main::@3 [ scroll#18 current_bit#29 nxt#31 current_chargen#27 ] ( main:2 [ scroll#18 current_bit#29 nxt#31 current_chargen#27 ] ) always clobbers reg byte a -Potential register analysis [27] scroll_bit::c#0 ← ((word)) scroll_bit::$3 missing fragment vwuz1=_word_vbuxx(scroll_bit:: vwuz1=(word) scroll_bit::c#0 vbuxx=(byte~) scroll_bit::$3 ) allocation: reg byte x [ scroll_bit::$3 ] zp ZP_WORD:18 [ scroll_bit::c#0 ] -Potential register analysis [27] scroll_bit::c#0 ← ((word)) scroll_bit::$3 missing fragment vwuz1=_word_vbuyy(scroll_bit:: vwuz1=(word) scroll_bit::c#0 vbuyy=(byte~) scroll_bit::$3 ) allocation: reg byte y [ scroll_bit::$3 ] zp ZP_WORD:18 [ scroll_bit::c#0 ] +Potential register analysis [27] scroll_bit::c#0 ← ((word)) scroll_bit::$3 missing fragment vwuz1=_word_vbuxx allocation: reg byte x [ scroll_bit::$3 ] zp ZP_WORD:18 [ scroll_bit::c#0 ] +Potential register analysis [27] scroll_bit::c#0 ← ((word)) scroll_bit::$3 missing fragment vwuz1=_word_vbuyy allocation: reg byte y [ scroll_bit::$3 ] zp ZP_WORD:18 [ scroll_bit::c#0 ] MISSING FRAGMENTS vwuz1=_word_vbuxx(scroll_bit:: vwuz1=(word) scroll_bit::c#0 vbuxx=(byte~) scroll_bit::$3 ) vwuz1=_word_vbuyy(scroll_bit:: vwuz1=(word) scroll_bit::c#0 vbuyy=(byte~) scroll_bit::$3 ) @@ -3081,8 +3081,8 @@ Statement [68] *((byte*) fillscreen::cursor#2) ← (const byte) fillscreen::fill Statement [70] if((byte*) fillscreen::cursor#1<(const byte*) SCREEN#0+(word/signed word) 1000) goto fillscreen::@1 [ fillscreen::cursor#1 ] ( main:2::fillscreen:5 [ fillscreen::cursor#1 ] ) always clobbers reg byte a Statement [7] if(*((const byte*) RASTER#0)!=(byte/word/signed word) 254) goto main::@2 [ scroll#18 current_bit#29 nxt#31 current_chargen#27 ] ( main:2 [ scroll#18 current_bit#29 nxt#31 current_chargen#27 ] ) always clobbers reg byte a Statement [8] if(*((const byte*) RASTER#0)!=(byte/word/signed word) 255) goto main::@3 [ scroll#18 current_bit#29 nxt#31 current_chargen#27 ] ( main:2 [ scroll#18 current_bit#29 nxt#31 current_chargen#27 ] ) always clobbers reg byte a -Potential register analysis [27] scroll_bit::c#0 ← ((word)) scroll_bit::$3 missing fragment vwuz1=_word_vbuxx(scroll_bit:: vwuz1=(word) scroll_bit::c#0 vbuxx=(byte~) scroll_bit::$3 ) allocation: reg byte x [ scroll_bit::$3 ] zp ZP_WORD:18 [ scroll_bit::c#0 ] -Potential register analysis [27] scroll_bit::c#0 ← ((word)) scroll_bit::$3 missing fragment vwuz1=_word_vbuyy(scroll_bit:: vwuz1=(word) scroll_bit::c#0 vbuyy=(byte~) scroll_bit::$3 ) allocation: reg byte y [ scroll_bit::$3 ] zp ZP_WORD:18 [ scroll_bit::c#0 ] +Potential register analysis [27] scroll_bit::c#0 ← ((word)) scroll_bit::$3 missing fragment vwuz1=_word_vbuxx allocation: reg byte x [ scroll_bit::$3 ] zp ZP_WORD:18 [ scroll_bit::c#0 ] +Potential register analysis [27] scroll_bit::c#0 ← ((word)) scroll_bit::$3 missing fragment vwuz1=_word_vbuyy allocation: reg byte y [ scroll_bit::$3 ] zp ZP_WORD:18 [ scroll_bit::c#0 ] MISSING FRAGMENTS vwuz1=_word_vbuxx(scroll_bit:: vwuz1=(word) scroll_bit::c#0 vbuxx=(byte~) scroll_bit::$3 ) vwuz1=_word_vbuyy(scroll_bit:: vwuz1=(word) scroll_bit::c#0 vbuyy=(byte~) scroll_bit::$3 ) diff --git a/src/test/java/dk/camelot64/kickc/test/ref/signed-bytes.log b/src/test/java/dk/camelot64/kickc/test/ref/signed-bytes.log index 8164b2577..14f594e7f 100644 --- a/src/test/java/dk/camelot64/kickc/test/ref/signed-bytes.log +++ b/src/test/java/dk/camelot64/kickc/test/ref/signed-bytes.log @@ -354,16 +354,16 @@ main: { } REGISTER UPLIFT POTENTIAL REGISTERS -Potential register analysis [6] if(main::i#2<127) goto main::@2 missing fragment vbsxx_lt_vbuc1_then_la1(main:: vbsxx=(signed byte) main::i#2 vbuc1=(byte/signed byte/word/signed word) 127 la1=(label) main::@2 ) allocation: reg byte x [ main::i#2 main::i#1 ] -Potential register analysis [6] if(main::i#2<127) goto main::@2 missing fragment vbsyy_lt_vbuc1_then_la1(main:: vbsyy=(signed byte) main::i#2 vbuc1=(byte/signed byte/word/signed word) 127 la1=(label) main::@2 ) allocation: reg byte y [ main::i#2 main::i#1 ] +Potential register analysis [6] if(main::i#2<127) goto main::@2 missing fragment vbsxx_lt_vbuc1_then_la1 allocation: reg byte x [ main::i#2 main::i#1 ] +Potential register analysis [6] if(main::i#2<127) goto main::@2 missing fragment vbsyy_lt_vbuc1_then_la1 allocation: reg byte y [ main::i#2 main::i#1 ] MISSING FRAGMENTS vbsxx_lt_vbuc1_then_la1(main:: vbsxx=(signed byte) main::i#2 vbuc1=(byte/signed byte/word/signed word) 127 la1=(label) main::@2 ) vbsyy_lt_vbuc1_then_la1(main:: vbsyy=(signed byte) main::i#2 vbuc1=(byte/signed byte/word/signed word) 127 la1=(label) main::@2 ) Statement [6] if((signed byte) main::i#2<(byte/signed byte/word/signed word) 127) goto main::@2 [ main::i#2 main::j#2 ] ( main:2 [ main::i#2 main::j#2 ] ) 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#2 main::j#1 ] -Potential register analysis [6] if(main::i#2<127) goto main::@2 missing fragment vbsxx_lt_vbuc1_then_la1(main:: vbsxx=(signed byte) main::i#2 vbuc1=(byte/signed byte/word/signed word) 127 la1=(label) main::@2 ) allocation: reg byte x [ main::i#2 main::i#1 ] -Potential register analysis [6] if(main::i#2<127) goto main::@2 missing fragment vbsyy_lt_vbuc1_then_la1(main:: vbsyy=(signed byte) main::i#2 vbuc1=(byte/signed byte/word/signed word) 127 la1=(label) main::@2 ) allocation: reg byte y [ main::i#2 main::i#1 ] +Potential register analysis [6] if(main::i#2<127) goto main::@2 missing fragment vbsxx_lt_vbuc1_then_la1 allocation: reg byte x [ main::i#2 main::i#1 ] +Potential register analysis [6] if(main::i#2<127) goto main::@2 missing fragment vbsyy_lt_vbuc1_then_la1 allocation: reg byte y [ main::i#2 main::i#1 ] MISSING FRAGMENTS vbsxx_lt_vbuc1_then_la1(main:: vbsxx=(signed byte) main::i#2 vbuc1=(byte/signed byte/word/signed word) 127 la1=(label) main::@2 ) vbsyy_lt_vbuc1_then_la1(main:: vbsyy=(signed byte) main::i#2 vbuc1=(byte/signed byte/word/signed word) 127 la1=(label) main::@2 ) diff --git a/src/test/java/dk/camelot64/kickc/test/ref/sinus-basic.log b/src/test/java/dk/camelot64/kickc/test/ref/sinus-basic.log index 3f9f8bca7..b7153ca29 100644 --- a/src/test/java/dk/camelot64/kickc/test/ref/sinus-basic.log +++ b/src/test/java/dk/camelot64/kickc/test/ref/sinus-basic.log @@ -3178,8 +3178,8 @@ divFACby10: { } REGISTER UPLIFT POTENTIAL REGISTERS -Potential register analysis [11] setFAC::w#1 ← ((word)) main::i#10 missing fragment vwuz1=_word_vbuxx(main:: vwuz1=(word) setFAC::w#1 vbuxx=(byte) main::i#10 ) allocation: reg byte x [ main::i#10 main::i#1 ] zp ZP_WORD:13 [ setFAC::w#3 setFAC::w#1 ] -Potential register analysis [11] setFAC::w#1 ← ((word)) main::i#10 missing fragment vwuz1=_word_vbuyy(main:: vwuz1=(word) setFAC::w#1 vbuyy=(byte) main::i#10 ) allocation: reg byte y [ main::i#10 main::i#1 ] zp ZP_WORD:13 [ setFAC::w#3 setFAC::w#1 ] +Potential register analysis [11] setFAC::w#1 ← ((word)) main::i#10 missing fragment vwuz1=_word_vbuxx allocation: reg byte x [ main::i#10 main::i#1 ] zp ZP_WORD:13 [ setFAC::w#3 setFAC::w#1 ] +Potential register analysis [11] setFAC::w#1 ← ((word)) main::i#10 missing fragment vwuz1=_word_vbuyy allocation: reg byte y [ main::i#10 main::i#1 ] zp ZP_WORD:13 [ setFAC::w#3 setFAC::w#1 ] MISSING FRAGMENTS vwuz1=_word_vbuxx(main:: vwuz1=(word) setFAC::w#1 vbuxx=(byte) main::i#10 ) vwuz1=_word_vbuyy(main:: vwuz1=(word) setFAC::w#1 vbuyy=(byte) main::i#10 ) diff --git a/src/test/java/dk/camelot64/kickc/test/ref/sinus-sprites.log b/src/test/java/dk/camelot64/kickc/test/ref/sinus-sprites.log index caf2a7d8b..f13cc316f 100644 --- a/src/test/java/dk/camelot64/kickc/test/ref/sinus-sprites.log +++ b/src/test/java/dk/camelot64/kickc/test/ref/sinus-sprites.log @@ -7643,8 +7643,8 @@ Removing always clobbered register reg byte a as potential for zp ZP_BYTE:9 [ in Statement [49] *((const byte*) COLS#0+(byte/signed byte/word/signed word) 40 + (byte) init::i#2) ← (byte/signed byte/word/signed word) 11 [ init::i#2 ] ( main:2::init:5 [ init::i#2 ] ) always clobbers reg byte a Statement [69] *((byte*) clear_screen::sc#2) ← (byte) ' ' [ clear_screen::sc#2 ] ( main:2::init:5::clear_screen:46 [ clear_screen::sc#2 ] main:2::init:5::clear_screen:65 [ clear_screen::sc#2 ] ) always clobbers reg byte a reg byte y Statement [71] if((byte*) clear_screen::sc#1<(const byte*) SCREEN#0+(word/signed word) 1000) goto clear_screen::@1 [ clear_screen::sc#1 ] ( main:2::init:5::clear_screen:46 [ clear_screen::sc#1 ] main:2::init:5::clear_screen:65 [ clear_screen::sc#1 ] ) always clobbers reg byte a -Potential register analysis [74] setFAC::w#0 ← ((word)) gen_sintab::max#2 missing fragment vwuz1=_word_vbuxx(gen_sintab:: vwuz1=(word) setFAC::w#0 vbuxx=(byte) gen_sintab::max#2 ) allocation: reg byte x [ gen_sintab::max#2 ] zp ZP_WORD:29 [ setFAC::w#5 setFAC::w#0 setFAC::w#3 setFAC::w#4 setFAC::w#1 ] -Potential register analysis [74] setFAC::w#0 ← ((word)) gen_sintab::max#2 missing fragment vwuz1=_word_vbuyy(gen_sintab:: vwuz1=(word) setFAC::w#0 vbuyy=(byte) gen_sintab::max#2 ) allocation: reg byte y [ gen_sintab::max#2 ] zp ZP_WORD:29 [ setFAC::w#5 setFAC::w#0 setFAC::w#3 setFAC::w#4 setFAC::w#1 ] +Potential register analysis [74] setFAC::w#0 ← ((word)) gen_sintab::max#2 missing fragment vwuz1=_word_vbuxx allocation: reg byte x [ gen_sintab::max#2 ] zp ZP_WORD:29 [ setFAC::w#5 setFAC::w#0 setFAC::w#3 setFAC::w#4 setFAC::w#1 ] +Potential register analysis [74] setFAC::w#0 ← ((word)) gen_sintab::max#2 missing fragment vwuz1=_word_vbuyy allocation: reg byte y [ gen_sintab::max#2 ] zp ZP_WORD:29 [ setFAC::w#5 setFAC::w#0 setFAC::w#3 setFAC::w#4 setFAC::w#1 ] MISSING FRAGMENTS vwuz1=_word_vbuxx(gen_sintab:: vwuz1=(word) setFAC::w#0 vbuxx=(byte) gen_sintab::max#2 ) vwuz1=_word_vbuyy(gen_sintab:: vwuz1=(word) setFAC::w#0 vbuyy=(byte) gen_sintab::max#2 ) @@ -7657,8 +7657,8 @@ Removing always clobbered register reg byte y as potential for zp ZP_BYTE:13 [ g Removing always clobbered register reg byte x as potential for zp ZP_BYTE:14 [ gen_sintab::length#10 ] Removing always clobbered register reg byte y as potential for zp ZP_BYTE:14 [ gen_sintab::length#10 ] Statement [79] (word) setFAC::w#1 ← ((word)) (byte) gen_sintab::min#2 [ gen_sintab::length#10 gen_sintab::sintab#12 setFAC::w#1 progress_init::line#2 ] ( main:2::init:5::gen_sintab:59 [ gen_sintab::length#10 gen_sintab::sintab#12 setFAC::w#1 progress_init::line#2 ] main:2::init:5::gen_sintab:63 [ gen_sintab::length#10 gen_sintab::sintab#12 setFAC::w#1 progress_init::line#2 ] ) always clobbers reg byte a -Potential register analysis [98] setFAC::w#3 ← ((word)) gen_sintab::i#10 missing fragment vwuz1=_word_vbuxx(gen_sintab:: vwuz1=(word) setFAC::w#3 vbuxx=(byte) gen_sintab::i#10 ) allocation: zp ZP_WORD:29 [ setFAC::w#5 setFAC::w#0 setFAC::w#3 setFAC::w#4 setFAC::w#1 ] reg byte x [ gen_sintab::i#10 gen_sintab::i#1 ] -Potential register analysis [98] setFAC::w#3 ← ((word)) gen_sintab::i#10 missing fragment vwuz1=_word_vbuyy(gen_sintab:: vwuz1=(word) setFAC::w#3 vbuyy=(byte) gen_sintab::i#10 ) allocation: zp ZP_WORD:29 [ setFAC::w#5 setFAC::w#0 setFAC::w#3 setFAC::w#4 setFAC::w#1 ] reg byte y [ gen_sintab::i#10 gen_sintab::i#1 ] +Potential register analysis [98] setFAC::w#3 ← ((word)) gen_sintab::i#10 missing fragment vwuz1=_word_vbuxx allocation: zp ZP_WORD:29 [ setFAC::w#5 setFAC::w#0 setFAC::w#3 setFAC::w#4 setFAC::w#1 ] reg byte x [ gen_sintab::i#10 gen_sintab::i#1 ] +Potential register analysis [98] setFAC::w#3 ← ((word)) gen_sintab::i#10 missing fragment vwuz1=_word_vbuyy allocation: zp ZP_WORD:29 [ setFAC::w#5 setFAC::w#0 setFAC::w#3 setFAC::w#4 setFAC::w#1 ] reg byte y [ gen_sintab::i#10 gen_sintab::i#1 ] MISSING FRAGMENTS vwuz1=_word_vbuxx(gen_sintab:: vwuz1=(word) setFAC::w#3 vbuxx=(byte) gen_sintab::i#10 ) vwuz1=_word_vbuyy(gen_sintab:: vwuz1=(word) setFAC::w#3 vbuyy=(byte) gen_sintab::i#10 ) @@ -7669,7 +7669,7 @@ Statement [104] (word) setFAC::w#4 ← ((word)) (byte) gen_sintab::length#10 [ g Statement [116] (word) getFAC::return#2 ← (word) getFAC::return#0 [ gen_sintab::length#10 gen_sintab::sintab#12 gen_sintab::i#10 progress_idx#34 progress_cursor#34 getFAC::return#2 ] ( main:2::init:5::gen_sintab:59 [ gen_sintab::length#10 gen_sintab::sintab#12 gen_sintab::i#10 progress_idx#34 progress_cursor#34 getFAC::return#2 ] main:2::init:5::gen_sintab:63 [ gen_sintab::length#10 gen_sintab::sintab#12 gen_sintab::i#10 progress_idx#34 progress_cursor#34 getFAC::return#2 ] ) always clobbers reg byte a Statement [117] (word~) gen_sintab::$23 ← (word) getFAC::return#2 [ gen_sintab::length#10 gen_sintab::sintab#12 gen_sintab::i#10 progress_idx#34 progress_cursor#34 gen_sintab::$23 ] ( main:2::init:5::gen_sintab:59 [ gen_sintab::length#10 gen_sintab::sintab#12 gen_sintab::i#10 progress_idx#34 progress_cursor#34 gen_sintab::$23 ] main:2::init:5::gen_sintab:63 [ gen_sintab::length#10 gen_sintab::sintab#12 gen_sintab::i#10 progress_idx#34 progress_cursor#34 gen_sintab::$23 ] ) always clobbers reg byte a Statement [118] (byte~) gen_sintab::$24 ← ((byte)) (word~) gen_sintab::$23 [ gen_sintab::length#10 gen_sintab::sintab#12 gen_sintab::i#10 progress_idx#34 progress_cursor#34 gen_sintab::$24 ] ( main:2::init:5::gen_sintab:59 [ gen_sintab::length#10 gen_sintab::sintab#12 gen_sintab::i#10 progress_idx#34 progress_cursor#34 gen_sintab::$24 ] main:2::init:5::gen_sintab:63 [ gen_sintab::length#10 gen_sintab::sintab#12 gen_sintab::i#10 progress_idx#34 progress_cursor#34 gen_sintab::$24 ] ) always clobbers reg byte a -Potential register analysis [119] *(gen_sintab::sintab#12 + gen_sintab::i#10) ← gen_sintab::$24 missing fragment pbuz1_derefidx_vbuxx=vbuyy(gen_sintab:: pbuz1=(byte*) gen_sintab::sintab#12 vbuxx=(byte) gen_sintab::i#10 vbuyy=(byte~) gen_sintab::$24 ) allocation: zp ZP_WORD:15 [ gen_sintab::sintab#12 ] reg byte y [ gen_sintab::$24 ] reg byte x [ gen_sintab::i#10 gen_sintab::i#1 ] +Potential register analysis [119] *(gen_sintab::sintab#12 + gen_sintab::i#10) ← gen_sintab::$24 missing fragment pbuz1_derefidx_vbuxx=vbuyy allocation: zp ZP_WORD:15 [ gen_sintab::sintab#12 ] reg byte y [ gen_sintab::$24 ] reg byte x [ gen_sintab::i#10 gen_sintab::i#1 ] MISSING FRAGMENTS pbuz1_derefidx_vbuxx=vbuyy(gen_sintab:: pbuz1=(byte*) gen_sintab::sintab#12 vbuxx=(byte) gen_sintab::i#10 vbuyy=(byte~) gen_sintab::$24 ) Statement [126] *((byte*) progress_cursor#34) ← *((const byte[]) progress_inc::progress_chars#0+(byte/signed byte/word/signed word) 8) [ progress_cursor#34 ] ( main:2::init:5::gen_sintab:59::progress_inc:120 [ gen_sintab::length#10 gen_sintab::sintab#12 gen_sintab::i#10 progress_cursor#34 ] main:2::init:5::gen_sintab:63::progress_inc:120 [ gen_sintab::length#10 gen_sintab::sintab#12 gen_sintab::i#10 progress_cursor#34 ] ) always clobbers reg byte a reg byte y @@ -7695,8 +7695,8 @@ Statement [176] (byte*) gen_chargen_sprite::sprite#0 ← (byte*) gen_sprites::sp Removing always clobbered register reg byte a as potential for zp ZP_BYTE:33 [ gen_sprites::i#2 gen_sprites::i#1 ] Removing always clobbered register reg byte a as potential for zp ZP_BYTE:64 [ gen_chargen_sprite::ch#0 ] Statement [178] (byte*) gen_sprites::spr#1 ← (byte*) gen_sprites::spr#2 + (byte/signed byte/word/signed word) 64 [ gen_sprites::i#2 gen_sprites::spr#1 ] ( main:2::init:5::gen_sprites:55 [ gen_sprites::i#2 gen_sprites::spr#1 ] ) always clobbers reg byte a -Potential register analysis [182] gen_chargen_sprite::$0 ← ((word)) gen_chargen_sprite::ch#0 missing fragment vwuz1=_word_vbuxx(gen_chargen_sprite:: vwuz1=(word~) gen_chargen_sprite::$0 vbuxx=(byte) gen_chargen_sprite::ch#0 ) allocation: reg byte x [ gen_chargen_sprite::ch#0 ] zp ZP_WORD:65 [ gen_chargen_sprite::$0 ] -Potential register analysis [182] gen_chargen_sprite::$0 ← ((word)) gen_chargen_sprite::ch#0 missing fragment vwuz1=_word_vbuyy(gen_chargen_sprite:: vwuz1=(word~) gen_chargen_sprite::$0 vbuyy=(byte) gen_chargen_sprite::ch#0 ) allocation: reg byte y [ gen_chargen_sprite::ch#0 ] zp ZP_WORD:65 [ gen_chargen_sprite::$0 ] +Potential register analysis [182] gen_chargen_sprite::$0 ← ((word)) gen_chargen_sprite::ch#0 missing fragment vwuz1=_word_vbuxx allocation: reg byte x [ gen_chargen_sprite::ch#0 ] zp ZP_WORD:65 [ gen_chargen_sprite::$0 ] +Potential register analysis [182] gen_chargen_sprite::$0 ← ((word)) gen_chargen_sprite::ch#0 missing fragment vwuz1=_word_vbuyy allocation: reg byte y [ gen_chargen_sprite::ch#0 ] zp ZP_WORD:65 [ gen_chargen_sprite::$0 ] MISSING FRAGMENTS vwuz1=_word_vbuxx(gen_chargen_sprite:: vwuz1=(word~) gen_chargen_sprite::$0 vbuxx=(byte) gen_chargen_sprite::ch#0 ) vwuz1=_word_vbuyy(gen_chargen_sprite:: vwuz1=(word~) gen_chargen_sprite::$0 vbuyy=(byte) gen_chargen_sprite::ch#0 ) @@ -7715,8 +7715,8 @@ Statement [195] (byte~) gen_chargen_sprite::$6 ← (byte) gen_chargen_sprite::s_ Removing always clobbered register reg byte a as potential for zp ZP_BYTE:39 [ gen_chargen_sprite::c#3 ] Removing always clobbered register reg byte a as potential for zp ZP_BYTE:42 [ gen_chargen_sprite::b#2 gen_chargen_sprite::b#1 ] Statement [196] (byte) gen_chargen_sprite::s_gen#1 ← (byte~) gen_chargen_sprite::$6 | (byte) gen_chargen_sprite::c#3 [ gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::x#6 gen_chargen_sprite::c#3 gen_chargen_sprite::s_gen_cnt#3 gen_chargen_sprite::b#2 gen_chargen_sprite::sprite#3 gen_chargen_sprite::s_gen#1 ] ( main:2::init:5::gen_sprites:55::gen_chargen_sprite:177 [ gen_sprites::i#2 gen_sprites::spr#2 gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::x#6 gen_chargen_sprite::c#3 gen_chargen_sprite::s_gen_cnt#3 gen_chargen_sprite::b#2 gen_chargen_sprite::sprite#3 gen_chargen_sprite::s_gen#1 ] ) always clobbers reg byte a -Potential register analysis [199] *(gen_chargen_sprite::sprite#3 + 0) ← gen_chargen_sprite::s_gen#1 missing fragment pbuz1_derefidx_vbuc1=vbuxx(gen_chargen_sprite:: pbuz1=(byte*) gen_chargen_sprite::sprite#3 vbuc1=(byte/signed byte/word/signed word) 0 vbuxx=(byte) gen_chargen_sprite::s_gen#1 ) allocation: zp ZP_WORD:43 [ gen_chargen_sprite::sprite#3 gen_chargen_sprite::sprite#10 gen_chargen_sprite::sprite#11 gen_chargen_sprite::sprite#0 gen_chargen_sprite::sprite#2 gen_chargen_sprite::sprite#4 gen_chargen_sprite::sprite#1 ] reg byte x [ gen_chargen_sprite::s_gen#3 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen#6 gen_chargen_sprite::s_gen#1 ] -Potential register analysis [199] *(gen_chargen_sprite::sprite#3 + 0) ← gen_chargen_sprite::s_gen#1 missing fragment pbuz1_derefidx_vbuc1=vbuyy(gen_chargen_sprite:: pbuz1=(byte*) gen_chargen_sprite::sprite#3 vbuc1=(byte/signed byte/word/signed word) 0 vbuyy=(byte) gen_chargen_sprite::s_gen#1 ) allocation: zp ZP_WORD:43 [ gen_chargen_sprite::sprite#3 gen_chargen_sprite::sprite#10 gen_chargen_sprite::sprite#11 gen_chargen_sprite::sprite#0 gen_chargen_sprite::sprite#2 gen_chargen_sprite::sprite#4 gen_chargen_sprite::sprite#1 ] reg byte y [ gen_chargen_sprite::s_gen#3 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen#6 gen_chargen_sprite::s_gen#1 ] +Potential register analysis [199] *(gen_chargen_sprite::sprite#3 + 0) ← gen_chargen_sprite::s_gen#1 missing fragment pbuz1_derefidx_vbuc1=vbuxx allocation: zp ZP_WORD:43 [ gen_chargen_sprite::sprite#3 gen_chargen_sprite::sprite#10 gen_chargen_sprite::sprite#11 gen_chargen_sprite::sprite#0 gen_chargen_sprite::sprite#2 gen_chargen_sprite::sprite#4 gen_chargen_sprite::sprite#1 ] reg byte x [ gen_chargen_sprite::s_gen#3 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen#6 gen_chargen_sprite::s_gen#1 ] +Potential register analysis [199] *(gen_chargen_sprite::sprite#3 + 0) ← gen_chargen_sprite::s_gen#1 missing fragment pbuz1_derefidx_vbuc1=vbuyy allocation: zp ZP_WORD:43 [ gen_chargen_sprite::sprite#3 gen_chargen_sprite::sprite#10 gen_chargen_sprite::sprite#11 gen_chargen_sprite::sprite#0 gen_chargen_sprite::sprite#2 gen_chargen_sprite::sprite#4 gen_chargen_sprite::sprite#1 ] reg byte y [ gen_chargen_sprite::s_gen#3 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen#6 gen_chargen_sprite::s_gen#1 ] MISSING FRAGMENTS pbuz1_derefidx_vbuc1=vbuxx(gen_chargen_sprite:: pbuz1=(byte*) gen_chargen_sprite::sprite#3 vbuc1=(byte/signed byte/word/signed word) 0 vbuxx=(byte) gen_chargen_sprite::s_gen#1 ) pbuz1_derefidx_vbuc1=vbuyy(gen_chargen_sprite:: pbuz1=(byte*) gen_chargen_sprite::sprite#3 vbuc1=(byte/signed byte/word/signed word) 0 vbuyy=(byte) gen_chargen_sprite::s_gen#1 ) @@ -7728,11 +7728,11 @@ Removing always clobbered register reg byte y as potential for zp ZP_BYTE:38 [ g Removing always clobbered register reg byte y as potential for zp ZP_BYTE:39 [ gen_chargen_sprite::c#3 ] Removing always clobbered register reg byte y as potential for zp ZP_BYTE:42 [ gen_chargen_sprite::b#2 gen_chargen_sprite::b#1 ] Removing always clobbered register reg byte y as potential for zp ZP_BYTE:40 [ gen_chargen_sprite::s_gen#3 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen#6 gen_chargen_sprite::s_gen#1 ] -Potential register analysis [200] *(gen_chargen_sprite::sprite#3 + 3) ← gen_chargen_sprite::s_gen#1 missing fragment pbuz1_derefidx_vbuc1=vbuxx(gen_chargen_sprite:: pbuz1=(byte*) gen_chargen_sprite::sprite#3 vbuc1=(byte/signed byte/word/signed word) 3 vbuxx=(byte) gen_chargen_sprite::s_gen#1 ) allocation: zp ZP_WORD:43 [ gen_chargen_sprite::sprite#3 gen_chargen_sprite::sprite#10 gen_chargen_sprite::sprite#11 gen_chargen_sprite::sprite#0 gen_chargen_sprite::sprite#2 gen_chargen_sprite::sprite#4 gen_chargen_sprite::sprite#1 ] reg byte x [ gen_chargen_sprite::s_gen#3 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen#6 gen_chargen_sprite::s_gen#1 ] +Potential register analysis [200] *(gen_chargen_sprite::sprite#3 + 3) ← gen_chargen_sprite::s_gen#1 missing fragment pbuz1_derefidx_vbuc1=vbuxx allocation: zp ZP_WORD:43 [ gen_chargen_sprite::sprite#3 gen_chargen_sprite::sprite#10 gen_chargen_sprite::sprite#11 gen_chargen_sprite::sprite#0 gen_chargen_sprite::sprite#2 gen_chargen_sprite::sprite#4 gen_chargen_sprite::sprite#1 ] reg byte x [ gen_chargen_sprite::s_gen#3 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen#6 gen_chargen_sprite::s_gen#1 ] MISSING FRAGMENTS pbuz1_derefidx_vbuc1=vbuxx(gen_chargen_sprite:: pbuz1=(byte*) gen_chargen_sprite::sprite#3 vbuc1=(byte/signed byte/word/signed word) 3 vbuxx=(byte) gen_chargen_sprite::s_gen#1 ) Statement [200] *((byte*) gen_chargen_sprite::sprite#3 + (byte/signed byte/word/signed word) 3) ← (byte) gen_chargen_sprite::s_gen#1 [ gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::x#6 gen_chargen_sprite::c#3 gen_chargen_sprite::b#2 gen_chargen_sprite::sprite#3 gen_chargen_sprite::s_gen#1 ] ( main:2::init:5::gen_sprites:55::gen_chargen_sprite:177 [ gen_sprites::i#2 gen_sprites::spr#2 gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::x#6 gen_chargen_sprite::c#3 gen_chargen_sprite::b#2 gen_chargen_sprite::sprite#3 gen_chargen_sprite::s_gen#1 ] ) always clobbers reg byte a reg byte y -Potential register analysis [201] *(gen_chargen_sprite::sprite#3 + 6) ← gen_chargen_sprite::s_gen#1 missing fragment pbuz1_derefidx_vbuc1=vbuxx(gen_chargen_sprite:: pbuz1=(byte*) gen_chargen_sprite::sprite#3 vbuc1=(byte/signed byte/word/signed word) 6 vbuxx=(byte) gen_chargen_sprite::s_gen#1 ) allocation: zp ZP_WORD:43 [ gen_chargen_sprite::sprite#3 gen_chargen_sprite::sprite#10 gen_chargen_sprite::sprite#11 gen_chargen_sprite::sprite#0 gen_chargen_sprite::sprite#2 gen_chargen_sprite::sprite#4 gen_chargen_sprite::sprite#1 ] reg byte x [ gen_chargen_sprite::s_gen#3 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen#6 gen_chargen_sprite::s_gen#1 ] +Potential register analysis [201] *(gen_chargen_sprite::sprite#3 + 6) ← gen_chargen_sprite::s_gen#1 missing fragment pbuz1_derefidx_vbuc1=vbuxx allocation: zp ZP_WORD:43 [ gen_chargen_sprite::sprite#3 gen_chargen_sprite::sprite#10 gen_chargen_sprite::sprite#11 gen_chargen_sprite::sprite#0 gen_chargen_sprite::sprite#2 gen_chargen_sprite::sprite#4 gen_chargen_sprite::sprite#1 ] reg byte x [ gen_chargen_sprite::s_gen#3 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen#6 gen_chargen_sprite::s_gen#1 ] MISSING FRAGMENTS pbuz1_derefidx_vbuc1=vbuxx(gen_chargen_sprite:: pbuz1=(byte*) gen_chargen_sprite::sprite#3 vbuc1=(byte/signed byte/word/signed word) 6 vbuxx=(byte) gen_chargen_sprite::s_gen#1 ) Statement [201] *((byte*) gen_chargen_sprite::sprite#3 + (byte/signed byte/word/signed word) 6) ← (byte) gen_chargen_sprite::s_gen#1 [ gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::x#6 gen_chargen_sprite::c#3 gen_chargen_sprite::b#2 gen_chargen_sprite::sprite#3 ] ( main:2::init:5::gen_sprites:55::gen_chargen_sprite:177 [ gen_sprites::i#2 gen_sprites::spr#2 gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::x#6 gen_chargen_sprite::c#3 gen_chargen_sprite::b#2 gen_chargen_sprite::sprite#3 ] ) always clobbers reg byte a reg byte y @@ -7764,8 +7764,8 @@ Statement [48] *((const byte*) COLS#0 + (byte) init::i#2) ← (byte/signed byte/ Statement [49] *((const byte*) COLS#0+(byte/signed byte/word/signed word) 40 + (byte) init::i#2) ← (byte/signed byte/word/signed word) 11 [ init::i#2 ] ( main:2::init:5 [ init::i#2 ] ) always clobbers reg byte a Statement [69] *((byte*) clear_screen::sc#2) ← (byte) ' ' [ clear_screen::sc#2 ] ( main:2::init:5::clear_screen:46 [ clear_screen::sc#2 ] main:2::init:5::clear_screen:65 [ clear_screen::sc#2 ] ) always clobbers reg byte a reg byte y Statement [71] if((byte*) clear_screen::sc#1<(const byte*) SCREEN#0+(word/signed word) 1000) goto clear_screen::@1 [ clear_screen::sc#1 ] ( main:2::init:5::clear_screen:46 [ clear_screen::sc#1 ] main:2::init:5::clear_screen:65 [ clear_screen::sc#1 ] ) always clobbers reg byte a -Potential register analysis [74] setFAC::w#0 ← ((word)) gen_sintab::max#2 missing fragment vwuz1=_word_vbuxx(gen_sintab:: vwuz1=(word) setFAC::w#0 vbuxx=(byte) gen_sintab::max#2 ) allocation: reg byte x [ gen_sintab::max#2 ] zp ZP_WORD:29 [ setFAC::w#5 setFAC::w#0 setFAC::w#3 setFAC::w#4 setFAC::w#1 ] -Potential register analysis [74] setFAC::w#0 ← ((word)) gen_sintab::max#2 missing fragment vwuz1=_word_vbuyy(gen_sintab:: vwuz1=(word) setFAC::w#0 vbuyy=(byte) gen_sintab::max#2 ) allocation: reg byte y [ gen_sintab::max#2 ] zp ZP_WORD:29 [ setFAC::w#5 setFAC::w#0 setFAC::w#3 setFAC::w#4 setFAC::w#1 ] +Potential register analysis [74] setFAC::w#0 ← ((word)) gen_sintab::max#2 missing fragment vwuz1=_word_vbuxx allocation: reg byte x [ gen_sintab::max#2 ] zp ZP_WORD:29 [ setFAC::w#5 setFAC::w#0 setFAC::w#3 setFAC::w#4 setFAC::w#1 ] +Potential register analysis [74] setFAC::w#0 ← ((word)) gen_sintab::max#2 missing fragment vwuz1=_word_vbuyy allocation: reg byte y [ gen_sintab::max#2 ] zp ZP_WORD:29 [ setFAC::w#5 setFAC::w#0 setFAC::w#3 setFAC::w#4 setFAC::w#1 ] MISSING FRAGMENTS vwuz1=_word_vbuxx(gen_sintab:: vwuz1=(word) setFAC::w#0 vbuxx=(byte) gen_sintab::max#2 ) vwuz1=_word_vbuyy(gen_sintab:: vwuz1=(word) setFAC::w#0 vbuyy=(byte) gen_sintab::max#2 ) @@ -7797,8 +7797,8 @@ Statement [163] (byte*) prepareMEM::mem#1 ← (byte*) setMEMtoFAC::mem#5 [ prepa Statement asm { ldx$fe ldy$ff jsr$bbd4 } always clobbers reg byte x reg byte y Statement [176] (byte*) gen_chargen_sprite::sprite#0 ← (byte*) gen_sprites::spr#2 [ gen_sprites::i#2 gen_sprites::spr#2 gen_chargen_sprite::ch#0 gen_chargen_sprite::sprite#0 ] ( main:2::init:5::gen_sprites:55 [ gen_sprites::i#2 gen_sprites::spr#2 gen_chargen_sprite::ch#0 gen_chargen_sprite::sprite#0 ] ) always clobbers reg byte a Statement [178] (byte*) gen_sprites::spr#1 ← (byte*) gen_sprites::spr#2 + (byte/signed byte/word/signed word) 64 [ gen_sprites::i#2 gen_sprites::spr#1 ] ( main:2::init:5::gen_sprites:55 [ gen_sprites::i#2 gen_sprites::spr#1 ] ) always clobbers reg byte a -Potential register analysis [182] gen_chargen_sprite::$0 ← ((word)) gen_chargen_sprite::ch#0 missing fragment vwuz1=_word_vbuxx(gen_chargen_sprite:: vwuz1=(word~) gen_chargen_sprite::$0 vbuxx=(byte) gen_chargen_sprite::ch#0 ) allocation: reg byte x [ gen_chargen_sprite::ch#0 ] zp ZP_WORD:65 [ gen_chargen_sprite::$0 ] -Potential register analysis [182] gen_chargen_sprite::$0 ← ((word)) gen_chargen_sprite::ch#0 missing fragment vwuz1=_word_vbuyy(gen_chargen_sprite:: vwuz1=(word~) gen_chargen_sprite::$0 vbuyy=(byte) gen_chargen_sprite::ch#0 ) allocation: reg byte y [ gen_chargen_sprite::ch#0 ] zp ZP_WORD:65 [ gen_chargen_sprite::$0 ] +Potential register analysis [182] gen_chargen_sprite::$0 ← ((word)) gen_chargen_sprite::ch#0 missing fragment vwuz1=_word_vbuxx allocation: reg byte x [ gen_chargen_sprite::ch#0 ] zp ZP_WORD:65 [ gen_chargen_sprite::$0 ] +Potential register analysis [182] gen_chargen_sprite::$0 ← ((word)) gen_chargen_sprite::ch#0 missing fragment vwuz1=_word_vbuyy allocation: reg byte y [ gen_chargen_sprite::ch#0 ] zp ZP_WORD:65 [ gen_chargen_sprite::$0 ] MISSING FRAGMENTS vwuz1=_word_vbuxx(gen_chargen_sprite:: vwuz1=(word~) gen_chargen_sprite::$0 vbuxx=(byte) gen_chargen_sprite::ch#0 ) vwuz1=_word_vbuyy(gen_chargen_sprite:: vwuz1=(word~) gen_chargen_sprite::$0 vbuyy=(byte) gen_chargen_sprite::ch#0 ) @@ -7810,15 +7810,15 @@ Statement [188] (byte) gen_chargen_sprite::bits#0 ← *((byte*) gen_chargen_spri Statement [190] (byte~) gen_chargen_sprite::$3 ← (byte) gen_chargen_sprite::bits#2 & (byte/word/signed word) 128 [ gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen_cnt#4 gen_chargen_sprite::sprite#10 gen_chargen_sprite::x#6 gen_chargen_sprite::$3 ] ( main:2::init:5::gen_sprites:55::gen_chargen_sprite:177 [ gen_sprites::i#2 gen_sprites::spr#2 gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen_cnt#4 gen_chargen_sprite::sprite#10 gen_chargen_sprite::x#6 gen_chargen_sprite::$3 ] ) always clobbers reg byte a Statement [195] (byte~) gen_chargen_sprite::$6 ← (byte) gen_chargen_sprite::s_gen#3 << (byte/signed byte/word/signed word) 1 [ gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::x#6 gen_chargen_sprite::c#3 gen_chargen_sprite::s_gen_cnt#3 gen_chargen_sprite::b#2 gen_chargen_sprite::sprite#3 gen_chargen_sprite::$6 ] ( main:2::init:5::gen_sprites:55::gen_chargen_sprite:177 [ gen_sprites::i#2 gen_sprites::spr#2 gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::x#6 gen_chargen_sprite::c#3 gen_chargen_sprite::s_gen_cnt#3 gen_chargen_sprite::b#2 gen_chargen_sprite::sprite#3 gen_chargen_sprite::$6 ] ) always clobbers reg byte a Statement [196] (byte) gen_chargen_sprite::s_gen#1 ← (byte~) gen_chargen_sprite::$6 | (byte) gen_chargen_sprite::c#3 [ gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::x#6 gen_chargen_sprite::c#3 gen_chargen_sprite::s_gen_cnt#3 gen_chargen_sprite::b#2 gen_chargen_sprite::sprite#3 gen_chargen_sprite::s_gen#1 ] ( main:2::init:5::gen_sprites:55::gen_chargen_sprite:177 [ gen_sprites::i#2 gen_sprites::spr#2 gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::x#6 gen_chargen_sprite::c#3 gen_chargen_sprite::s_gen_cnt#3 gen_chargen_sprite::b#2 gen_chargen_sprite::sprite#3 gen_chargen_sprite::s_gen#1 ] ) always clobbers reg byte a -Potential register analysis [199] *(gen_chargen_sprite::sprite#3 + 0) ← gen_chargen_sprite::s_gen#1 missing fragment pbuz1_derefidx_vbuc1=vbuxx(gen_chargen_sprite:: pbuz1=(byte*) gen_chargen_sprite::sprite#3 vbuc1=(byte/signed byte/word/signed word) 0 vbuxx=(byte) gen_chargen_sprite::s_gen#1 ) allocation: zp ZP_WORD:43 [ gen_chargen_sprite::sprite#3 gen_chargen_sprite::sprite#10 gen_chargen_sprite::sprite#11 gen_chargen_sprite::sprite#0 gen_chargen_sprite::sprite#2 gen_chargen_sprite::sprite#4 gen_chargen_sprite::sprite#1 ] reg byte x [ gen_chargen_sprite::s_gen#3 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen#6 gen_chargen_sprite::s_gen#1 ] +Potential register analysis [199] *(gen_chargen_sprite::sprite#3 + 0) ← gen_chargen_sprite::s_gen#1 missing fragment pbuz1_derefidx_vbuc1=vbuxx allocation: zp ZP_WORD:43 [ gen_chargen_sprite::sprite#3 gen_chargen_sprite::sprite#10 gen_chargen_sprite::sprite#11 gen_chargen_sprite::sprite#0 gen_chargen_sprite::sprite#2 gen_chargen_sprite::sprite#4 gen_chargen_sprite::sprite#1 ] reg byte x [ gen_chargen_sprite::s_gen#3 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen#6 gen_chargen_sprite::s_gen#1 ] MISSING FRAGMENTS pbuz1_derefidx_vbuc1=vbuxx(gen_chargen_sprite:: pbuz1=(byte*) gen_chargen_sprite::sprite#3 vbuc1=(byte/signed byte/word/signed word) 0 vbuxx=(byte) gen_chargen_sprite::s_gen#1 ) Statement [199] *((byte*) gen_chargen_sprite::sprite#3 + (byte/signed byte/word/signed word) 0) ← (byte) gen_chargen_sprite::s_gen#1 [ gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::x#6 gen_chargen_sprite::c#3 gen_chargen_sprite::b#2 gen_chargen_sprite::sprite#3 gen_chargen_sprite::s_gen#1 ] ( main:2::init:5::gen_sprites:55::gen_chargen_sprite:177 [ gen_sprites::i#2 gen_sprites::spr#2 gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::x#6 gen_chargen_sprite::c#3 gen_chargen_sprite::b#2 gen_chargen_sprite::sprite#3 gen_chargen_sprite::s_gen#1 ] ) always clobbers reg byte a reg byte y -Potential register analysis [200] *(gen_chargen_sprite::sprite#3 + 3) ← gen_chargen_sprite::s_gen#1 missing fragment pbuz1_derefidx_vbuc1=vbuxx(gen_chargen_sprite:: pbuz1=(byte*) gen_chargen_sprite::sprite#3 vbuc1=(byte/signed byte/word/signed word) 3 vbuxx=(byte) gen_chargen_sprite::s_gen#1 ) allocation: zp ZP_WORD:43 [ gen_chargen_sprite::sprite#3 gen_chargen_sprite::sprite#10 gen_chargen_sprite::sprite#11 gen_chargen_sprite::sprite#0 gen_chargen_sprite::sprite#2 gen_chargen_sprite::sprite#4 gen_chargen_sprite::sprite#1 ] reg byte x [ gen_chargen_sprite::s_gen#3 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen#6 gen_chargen_sprite::s_gen#1 ] +Potential register analysis [200] *(gen_chargen_sprite::sprite#3 + 3) ← gen_chargen_sprite::s_gen#1 missing fragment pbuz1_derefidx_vbuc1=vbuxx allocation: zp ZP_WORD:43 [ gen_chargen_sprite::sprite#3 gen_chargen_sprite::sprite#10 gen_chargen_sprite::sprite#11 gen_chargen_sprite::sprite#0 gen_chargen_sprite::sprite#2 gen_chargen_sprite::sprite#4 gen_chargen_sprite::sprite#1 ] reg byte x [ gen_chargen_sprite::s_gen#3 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen#6 gen_chargen_sprite::s_gen#1 ] MISSING FRAGMENTS pbuz1_derefidx_vbuc1=vbuxx(gen_chargen_sprite:: pbuz1=(byte*) gen_chargen_sprite::sprite#3 vbuc1=(byte/signed byte/word/signed word) 3 vbuxx=(byte) gen_chargen_sprite::s_gen#1 ) Statement [200] *((byte*) gen_chargen_sprite::sprite#3 + (byte/signed byte/word/signed word) 3) ← (byte) gen_chargen_sprite::s_gen#1 [ gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::x#6 gen_chargen_sprite::c#3 gen_chargen_sprite::b#2 gen_chargen_sprite::sprite#3 gen_chargen_sprite::s_gen#1 ] ( main:2::init:5::gen_sprites:55::gen_chargen_sprite:177 [ gen_sprites::i#2 gen_sprites::spr#2 gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::x#6 gen_chargen_sprite::c#3 gen_chargen_sprite::b#2 gen_chargen_sprite::sprite#3 gen_chargen_sprite::s_gen#1 ] ) always clobbers reg byte a reg byte y -Potential register analysis [201] *(gen_chargen_sprite::sprite#3 + 6) ← gen_chargen_sprite::s_gen#1 missing fragment pbuz1_derefidx_vbuc1=vbuxx(gen_chargen_sprite:: pbuz1=(byte*) gen_chargen_sprite::sprite#3 vbuc1=(byte/signed byte/word/signed word) 6 vbuxx=(byte) gen_chargen_sprite::s_gen#1 ) allocation: zp ZP_WORD:43 [ gen_chargen_sprite::sprite#3 gen_chargen_sprite::sprite#10 gen_chargen_sprite::sprite#11 gen_chargen_sprite::sprite#0 gen_chargen_sprite::sprite#2 gen_chargen_sprite::sprite#4 gen_chargen_sprite::sprite#1 ] reg byte x [ gen_chargen_sprite::s_gen#3 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen#6 gen_chargen_sprite::s_gen#1 ] +Potential register analysis [201] *(gen_chargen_sprite::sprite#3 + 6) ← gen_chargen_sprite::s_gen#1 missing fragment pbuz1_derefidx_vbuc1=vbuxx allocation: zp ZP_WORD:43 [ gen_chargen_sprite::sprite#3 gen_chargen_sprite::sprite#10 gen_chargen_sprite::sprite#11 gen_chargen_sprite::sprite#0 gen_chargen_sprite::sprite#2 gen_chargen_sprite::sprite#4 gen_chargen_sprite::sprite#1 ] reg byte x [ gen_chargen_sprite::s_gen#3 gen_chargen_sprite::s_gen#5 gen_chargen_sprite::s_gen#6 gen_chargen_sprite::s_gen#1 ] MISSING FRAGMENTS pbuz1_derefidx_vbuc1=vbuxx(gen_chargen_sprite:: pbuz1=(byte*) gen_chargen_sprite::sprite#3 vbuc1=(byte/signed byte/word/signed word) 6 vbuxx=(byte) gen_chargen_sprite::s_gen#1 ) Statement [201] *((byte*) gen_chargen_sprite::sprite#3 + (byte/signed byte/word/signed word) 6) ← (byte) gen_chargen_sprite::s_gen#1 [ gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::x#6 gen_chargen_sprite::c#3 gen_chargen_sprite::b#2 gen_chargen_sprite::sprite#3 ] ( main:2::init:5::gen_sprites:55::gen_chargen_sprite:177 [ gen_sprites::i#2 gen_sprites::spr#2 gen_chargen_sprite::chargen#0 gen_chargen_sprite::y#2 gen_chargen_sprite::bits#2 gen_chargen_sprite::x#6 gen_chargen_sprite::c#3 gen_chargen_sprite::b#2 gen_chargen_sprite::sprite#3 ] ) always clobbers reg byte a reg byte y diff --git a/src/test/java/dk/camelot64/kickc/test/ref/test-comparisons.log b/src/test/java/dk/camelot64/kickc/test/ref/test-comparisons.log index 86fbbdac5..b86a8f76f 100644 --- a/src/test/java/dk/camelot64/kickc/test/ref/test-comparisons.log +++ b/src/test/java/dk/camelot64/kickc/test/ref/test-comparisons.log @@ -8647,10 +8647,10 @@ Potential register analysis [21] if(main::a#10>=*(main::cs#0 + main::i#10)) goto Potential register analysis [21] if(main::a#10>=*(main::cs#0 + main::i#10)) goto main::@4 missing fragment vbuyy_ge_pbuc1_derefidx_vbuxx_then_la1 allocation: reg byte x [ main::i#10 main::i#1 ] reg byte y [ main::a#10 main::a#1 ] Potential register analysis [21] if(main::a#10>=*(main::cs#0 + main::i#10)) goto main::@4 missing fragment vbuyy_ge_pbuc1_derefidx_vbuyy_then_la1 allocation: reg byte y [ main::i#10 main::i#1 ] reg byte y [ main::a#10 main::a#1 ] MISSING FRAGMENTS - vbuz1_ge_pbuc1_derefidx_vbuxx_then_la1 - vbuyy_ge_pbuc1_derefidx_vbuz1_then_la1 - vbuyy_ge_pbuc1_derefidx_vbuxx_then_la1 - vbuyy_ge_pbuc1_derefidx_vbuyy_then_la1 + vbuz1_ge_pbuc1_derefidx_vbuxx_then_la1(main:: vbuz1=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuxx=(byte) main::i#10 la1=(label) main::b4_from_b47 ) + vbuyy_ge_pbuc1_derefidx_vbuz1_then_la1(main:: vbuyy=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuz1=(byte) main::i#10 la1=(label) main::b4_from_b47 ) + vbuyy_ge_pbuc1_derefidx_vbuxx_then_la1(main:: vbuyy=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuxx=(byte) main::i#10 la1=(label) main::b4_from_b47 ) + vbuyy_ge_pbuc1_derefidx_vbuyy_then_la1(main:: vbuyy=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 la1=(label) main::b4_from_b47 ) Statement [21] if((byte) main::a#10>=*((const byte[5]) main::cs#0 + (byte) main::i#10)) goto main::@4 [ main::a#10 main::i#10 line_cursor#21 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#21 main::b#0 char_cursor#52 ] ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp ZP_BYTE:39 [ main::b#0 ] Statement [28] if((byte) main::a#10>=(byte) main::a#10) goto main::@5 [ main::a#10 main::i#10 line_cursor#21 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#21 main::b#0 char_cursor#52 ] ) always clobbers reg byte a @@ -8663,28 +8663,28 @@ Potential register analysis [51] if(main::a#10<=*(main::cs#0 + main::i#10)) goto Potential register analysis [51] if(main::a#10<=*(main::cs#0 + main::i#10)) goto main::@8 missing fragment vbuyy_le_pbuc1_derefidx_vbuxx_then_la1 allocation: reg byte x [ main::i#10 main::i#1 ] reg byte y [ main::a#10 main::a#1 ] Potential register analysis [51] if(main::a#10<=*(main::cs#0 + main::i#10)) goto main::@8 missing fragment vbuyy_le_pbuc1_derefidx_vbuyy_then_la1 allocation: reg byte y [ main::i#10 main::i#1 ] reg byte y [ main::a#10 main::a#1 ] MISSING FRAGMENTS - vbuz1_le_pbuc1_derefidx_vbuxx_then_la1 - vbuyy_le_pbuc1_derefidx_vbuz1_then_la1 - vbuyy_le_pbuc1_derefidx_vbuxx_then_la1 - vbuyy_le_pbuc1_derefidx_vbuyy_then_la1 + vbuz1_le_pbuc1_derefidx_vbuxx_then_la1(main:: vbuz1=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuxx=(byte) main::i#10 la1=(label) main::b8_from_b52 ) + vbuyy_le_pbuc1_derefidx_vbuz1_then_la1(main:: vbuyy=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuz1=(byte) main::i#10 la1=(label) main::b8_from_b52 ) + vbuyy_le_pbuc1_derefidx_vbuxx_then_la1(main:: vbuyy=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuxx=(byte) main::i#10 la1=(label) main::b8_from_b52 ) + vbuyy_le_pbuc1_derefidx_vbuyy_then_la1(main:: vbuyy=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 la1=(label) main::b8_from_b52 ) Statement [51] if((byte) main::a#10<=*((const byte[5]) main::cs#0 + (byte) main::i#10)) goto main::@8 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ) always clobbers reg byte a Statement [58] if((byte) main::a#10<=(byte) main::a#10) goto main::@9 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ) always clobbers reg byte a Statement [73] (byte*~) char_cursor#138 ← (byte*) line_cursor#1 [ main::a#10 main::i#10 line_cursor#1 main::b#0 printu::a#8 printu::b#8 printu::res#8 char_cursor#138 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 printu::a#8 printu::b#8 printu::res#8 char_cursor#138 ] ) always clobbers reg byte a Potential register analysis [75] if(main::a#10>55) goto main::@11 missing fragment vbuxx_gt_vbuc1_then_la1 allocation: reg byte x [ main::a#10 main::a#1 ] Potential register analysis [75] if(main::a#10>55) goto main::@11 missing fragment vbuyy_gt_vbuc1_then_la1 allocation: reg byte y [ main::a#10 main::a#1 ] MISSING FRAGMENTS - vbuxx_gt_vbuc1_then_la1 - vbuyy_gt_vbuc1_then_la1 + vbuxx_gt_vbuc1_then_la1(main:: vbuxx=(byte) main::a#10 vbuc1=(byte/signed byte/word/signed word) 55 la1=(label) main::b11_from_b56 ) + vbuyy_gt_vbuc1_then_la1(main:: vbuyy=(byte) main::a#10 vbuc1=(byte/signed byte/word/signed word) 55 la1=(label) main::b11_from_b56 ) Statement [75] if((byte) main::a#10>(byte/signed byte/word/signed word) 55) goto main::@11 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ) always clobbers reg byte a Potential register analysis [81] if(main::a#10>*(main::cs#0 + main::i#10)) goto main::@12 missing fragment vbuz1_gt_pbuc1_derefidx_vbuxx_then_la1 allocation: reg byte x [ main::i#10 main::i#1 ] zp ZP_BYTE:2 [ main::a#10 main::a#1 ] Potential register analysis [81] if(main::a#10>*(main::cs#0 + main::i#10)) goto main::@12 missing fragment vbuyy_gt_pbuc1_derefidx_vbuz1_then_la1 allocation: zp ZP_BYTE:3 [ main::i#10 main::i#1 ] reg byte y [ main::a#10 main::a#1 ] Potential register analysis [81] if(main::a#10>*(main::cs#0 + main::i#10)) goto main::@12 missing fragment vbuyy_gt_pbuc1_derefidx_vbuxx_then_la1 allocation: reg byte x [ main::i#10 main::i#1 ] reg byte y [ main::a#10 main::a#1 ] Potential register analysis [81] if(main::a#10>*(main::cs#0 + main::i#10)) goto main::@12 missing fragment vbuyy_gt_pbuc1_derefidx_vbuyy_then_la1 allocation: reg byte y [ main::i#10 main::i#1 ] reg byte y [ main::a#10 main::a#1 ] MISSING FRAGMENTS - vbuz1_gt_pbuc1_derefidx_vbuxx_then_la1 - vbuyy_gt_pbuc1_derefidx_vbuz1_then_la1 - vbuyy_gt_pbuc1_derefidx_vbuxx_then_la1 - vbuyy_gt_pbuc1_derefidx_vbuyy_then_la1 + vbuz1_gt_pbuc1_derefidx_vbuxx_then_la1(main:: vbuz1=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuxx=(byte) main::i#10 la1=(label) main::b12_from_b57 ) + vbuyy_gt_pbuc1_derefidx_vbuz1_then_la1(main:: vbuyy=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuz1=(byte) main::i#10 la1=(label) main::b12_from_b57 ) + vbuyy_gt_pbuc1_derefidx_vbuxx_then_la1(main:: vbuyy=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuxx=(byte) main::i#10 la1=(label) main::b12_from_b57 ) + vbuyy_gt_pbuc1_derefidx_vbuyy_then_la1(main:: vbuyy=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 la1=(label) main::b12_from_b57 ) Statement [81] if((byte) main::a#10>*((const byte[5]) main::cs#0 + (byte) main::i#10)) goto main::@12 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ) always clobbers reg byte a Statement [88] if((byte) main::a#10>(byte) main::a#10) goto main::@13 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ) always clobbers reg byte a Statement [103] (byte*~) char_cursor#142 ← (byte*) line_cursor#1 [ main::a#10 main::i#10 line_cursor#1 main::b#0 printu::a#12 printu::b#12 printu::res#12 char_cursor#142 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 printu::a#12 printu::b#12 printu::res#12 char_cursor#142 ] ) always clobbers reg byte a @@ -8693,16 +8693,16 @@ Potential register analysis [111] if(main::a#10<*(main::cs#0 + main::i#10)) goto Potential register analysis [111] if(main::a#10<*(main::cs#0 + main::i#10)) goto main::@16 missing fragment vbuyy_lt_pbuc1_derefidx_vbuxx_then_la1 allocation: reg byte x [ main::i#10 main::i#1 ] reg byte y [ main::a#10 main::a#1 ] Potential register analysis [111] if(main::a#10<*(main::cs#0 + main::i#10)) goto main::@16 missing fragment vbuyy_lt_pbuc1_derefidx_vbuyy_then_la1 allocation: reg byte y [ main::i#10 main::i#1 ] reg byte y [ main::a#10 main::a#1 ] MISSING FRAGMENTS - vbuz1_lt_pbuc1_derefidx_vbuxx_then_la1 - vbuyy_lt_pbuc1_derefidx_vbuz1_then_la1 - vbuyy_lt_pbuc1_derefidx_vbuxx_then_la1 - vbuyy_lt_pbuc1_derefidx_vbuyy_then_la1 + vbuz1_lt_pbuc1_derefidx_vbuxx_then_la1(main:: vbuz1=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuxx=(byte) main::i#10 la1=(label) main::b16_from_b62 ) + vbuyy_lt_pbuc1_derefidx_vbuz1_then_la1(main:: vbuyy=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuz1=(byte) main::i#10 la1=(label) main::b16_from_b62 ) + vbuyy_lt_pbuc1_derefidx_vbuxx_then_la1(main:: vbuyy=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuxx=(byte) main::i#10 la1=(label) main::b16_from_b62 ) + vbuyy_lt_pbuc1_derefidx_vbuyy_then_la1(main:: vbuyy=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 la1=(label) main::b16_from_b62 ) Statement [111] if((byte) main::a#10<*((const byte[5]) main::cs#0 + (byte) main::i#10)) goto main::@16 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ) always clobbers reg byte a Potential register analysis [118] if(main::a#10=*(main::cs#0 + main::i#10)) goto main::@4 missing fragment vbuz1_ge_pbuc1_derefidx_vbuxx_then_la1 allocation: reg byte x [ main::i#10 main::i#1 ] zp ZP_BYTE:2 [ main::a#10 main::a#1 ] MISSING FRAGMENTS - vbuz1_ge_pbuc1_derefidx_vbuxx_then_la1 + vbuz1_ge_pbuc1_derefidx_vbuxx_then_la1(main:: vbuz1=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuxx=(byte) main::i#10 la1=(label) main::b4_from_b47 ) Statement [21] if((byte) main::a#10>=*((const byte[5]) main::cs#0 + (byte) main::i#10)) goto main::@4 [ main::a#10 main::i#10 line_cursor#21 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#21 main::b#0 char_cursor#52 ] ) always clobbers reg byte a reg byte y Statement [25] (byte) printu::b#2 ← *((const byte[5]) main::cs#0 + (byte) main::i#10) [ main::a#10 main::i#10 line_cursor#21 main::b#0 main::r#42 printu::a#2 printu::b#2 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#21 main::b#0 main::r#42 printu::a#2 printu::b#2 char_cursor#52 ] ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp ZP_BYTE:6 [ main::r#42 ] @@ -8748,7 +8748,7 @@ Statement [28] if((byte) main::a#10>=(byte) main::a#10) goto main::@5 [ main::a# Statement [43] (byte*~) char_cursor#154 ← (byte*) line_cursor#1 [ main::a#10 main::i#10 line_cursor#1 main::b#0 printu::a#4 printu::b#4 printu::res#4 char_cursor#154 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 printu::a#4 printu::b#4 printu::res#4 char_cursor#154 ] ) always clobbers reg byte a Potential register analysis [51] if(main::a#10<=*(main::cs#0 + main::i#10)) goto main::@8 missing fragment vbuz1_le_pbuc1_derefidx_vbuxx_then_la1 allocation: reg byte x [ main::i#10 main::i#1 ] zp ZP_BYTE:2 [ main::a#10 main::a#1 ] MISSING FRAGMENTS - vbuz1_le_pbuc1_derefidx_vbuxx_then_la1 + vbuz1_le_pbuc1_derefidx_vbuxx_then_la1(main:: vbuz1=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuxx=(byte) main::i#10 la1=(label) main::b8_from_b52 ) Statement [51] if((byte) main::a#10<=*((const byte[5]) main::cs#0 + (byte) main::i#10)) goto main::@8 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ) always clobbers reg byte a reg byte y Statement [55] (byte) printu::b#6 ← *((const byte[5]) main::cs#0 + (byte) main::i#10) [ main::a#10 main::i#10 line_cursor#1 main::b#0 main::r#46 printu::a#6 printu::b#6 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 main::r#46 printu::a#6 printu::b#6 char_cursor#52 ] ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp ZP_BYTE:10 [ main::r#46 ] @@ -8756,11 +8756,11 @@ Statement [58] if((byte) main::a#10<=(byte) main::a#10) goto main::@9 [ main::a# Statement [73] (byte*~) char_cursor#138 ← (byte*) line_cursor#1 [ main::a#10 main::i#10 line_cursor#1 main::b#0 printu::a#8 printu::b#8 printu::res#8 char_cursor#138 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 printu::a#8 printu::b#8 printu::res#8 char_cursor#138 ] ) always clobbers reg byte a Potential register analysis [75] if(main::a#10>55) goto main::@11 missing fragment vbuxx_gt_vbuc1_then_la1 allocation: reg byte x [ main::a#10 main::a#1 ] MISSING FRAGMENTS - vbuxx_gt_vbuc1_then_la1 + vbuxx_gt_vbuc1_then_la1(main:: vbuxx=(byte) main::a#10 vbuc1=(byte/signed byte/word/signed word) 55 la1=(label) main::b11_from_b56 ) Statement [75] if((byte) main::a#10>(byte/signed byte/word/signed word) 55) goto main::@11 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ) always clobbers reg byte a Potential register analysis [81] if(main::a#10>*(main::cs#0 + main::i#10)) goto main::@12 missing fragment vbuz1_gt_pbuc1_derefidx_vbuxx_then_la1 allocation: reg byte x [ main::i#10 main::i#1 ] zp ZP_BYTE:2 [ main::a#10 main::a#1 ] MISSING FRAGMENTS - vbuz1_gt_pbuc1_derefidx_vbuxx_then_la1 + vbuz1_gt_pbuc1_derefidx_vbuxx_then_la1(main:: vbuz1=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuxx=(byte) main::i#10 la1=(label) main::b12_from_b57 ) Statement [81] if((byte) main::a#10>*((const byte[5]) main::cs#0 + (byte) main::i#10)) goto main::@12 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ) always clobbers reg byte a reg byte y Statement [85] (byte) printu::b#10 ← *((const byte[5]) main::cs#0 + (byte) main::i#10) [ main::a#10 main::i#10 line_cursor#1 main::b#0 main::r#50 printu::a#10 printu::b#10 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 main::r#50 printu::a#10 printu::b#10 char_cursor#52 ] ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp ZP_BYTE:14 [ main::r#50 ] @@ -8768,18 +8768,18 @@ Statement [88] if((byte) main::a#10>(byte) main::a#10) goto main::@13 [ main::a# Statement [103] (byte*~) char_cursor#142 ← (byte*) line_cursor#1 [ main::a#10 main::i#10 line_cursor#1 main::b#0 printu::a#12 printu::b#12 printu::res#12 char_cursor#142 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 printu::a#12 printu::b#12 printu::res#12 char_cursor#142 ] ) always clobbers reg byte a Potential register analysis [111] if(main::a#10<*(main::cs#0 + main::i#10)) goto main::@16 missing fragment vbuz1_lt_pbuc1_derefidx_vbuxx_then_la1 allocation: reg byte x [ main::i#10 main::i#1 ] zp ZP_BYTE:2 [ main::a#10 main::a#1 ] MISSING FRAGMENTS - vbuz1_lt_pbuc1_derefidx_vbuxx_then_la1 + vbuz1_lt_pbuc1_derefidx_vbuxx_then_la1(main:: vbuz1=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuxx=(byte) main::i#10 la1=(label) main::b16_from_b62 ) Statement [111] if((byte) main::a#10<*((const byte[5]) main::cs#0 + (byte) main::i#10)) goto main::@16 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ) always clobbers reg byte a reg byte y Statement [115] (byte) printu::b#14 ← *((const byte[5]) main::cs#0 + (byte) main::i#10) [ main::a#10 main::i#10 line_cursor#1 main::b#0 main::r#54 printu::a#14 printu::b#14 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 main::r#54 printu::a#14 printu::b#14 char_cursor#52 ] ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp ZP_BYTE:18 [ main::r#54 ] Potential register analysis [118] if(main::a#10=*(main::cs#0 + main::i#10)) goto main::@4 missing fragment vbuz1_ge_pbuc1_derefidx_vbuxx_then_la1 allocation: reg byte x [ main::i#10 main::i#1 ] zp ZP_BYTE:2 [ main::a#10 main::a#1 ] MISSING FRAGMENTS - vbuz1_ge_pbuc1_derefidx_vbuxx_then_la1 + vbuz1_ge_pbuc1_derefidx_vbuxx_then_la1(main:: vbuz1=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuxx=(byte) main::i#10 la1=(label) main::b4_from_b47 ) Statement [21] if((byte) main::a#10>=*((const byte[5]) main::cs#0 + (byte) main::i#10)) goto main::@4 [ main::a#10 main::i#10 line_cursor#21 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#21 main::b#0 char_cursor#52 ] ) always clobbers reg byte a reg byte y Statement [25] (byte) printu::b#2 ← *((const byte[5]) main::cs#0 + (byte) main::i#10) [ main::a#10 main::i#10 line_cursor#21 main::b#0 main::r#42 printu::a#2 printu::b#2 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#21 main::b#0 main::r#42 printu::a#2 printu::b#2 char_cursor#52 ] ) always clobbers reg byte a Statement [28] if((byte) main::a#10>=(byte) main::a#10) goto main::@5 [ main::a#10 main::i#10 line_cursor#21 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#21 main::b#0 char_cursor#52 ] ) always clobbers reg byte a Statement [43] (byte*~) char_cursor#154 ← (byte*) line_cursor#1 [ main::a#10 main::i#10 line_cursor#1 main::b#0 printu::a#4 printu::b#4 printu::res#4 char_cursor#154 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 printu::a#4 printu::b#4 printu::res#4 char_cursor#154 ] ) always clobbers reg byte a Potential register analysis [51] if(main::a#10<=*(main::cs#0 + main::i#10)) goto main::@8 missing fragment vbuz1_le_pbuc1_derefidx_vbuxx_then_la1 allocation: reg byte x [ main::i#10 main::i#1 ] zp ZP_BYTE:2 [ main::a#10 main::a#1 ] MISSING FRAGMENTS - vbuz1_le_pbuc1_derefidx_vbuxx_then_la1 + vbuz1_le_pbuc1_derefidx_vbuxx_then_la1(main:: vbuz1=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuxx=(byte) main::i#10 la1=(label) main::b8_from_b52 ) Statement [51] if((byte) main::a#10<=*((const byte[5]) main::cs#0 + (byte) main::i#10)) goto main::@8 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ) always clobbers reg byte a reg byte y Statement [55] (byte) printu::b#6 ← *((const byte[5]) main::cs#0 + (byte) main::i#10) [ main::a#10 main::i#10 line_cursor#1 main::b#0 main::r#46 printu::a#6 printu::b#6 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 main::r#46 printu::a#6 printu::b#6 char_cursor#52 ] ) always clobbers reg byte a Statement [58] if((byte) main::a#10<=(byte) main::a#10) goto main::@9 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ) always clobbers reg byte a Statement [73] (byte*~) char_cursor#138 ← (byte*) line_cursor#1 [ main::a#10 main::i#10 line_cursor#1 main::b#0 printu::a#8 printu::b#8 printu::res#8 char_cursor#138 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 printu::a#8 printu::b#8 printu::res#8 char_cursor#138 ] ) always clobbers reg byte a Potential register analysis [75] if(main::a#10>55) goto main::@11 missing fragment vbuxx_gt_vbuc1_then_la1 allocation: reg byte x [ main::a#10 main::a#1 ] MISSING FRAGMENTS - vbuxx_gt_vbuc1_then_la1 + vbuxx_gt_vbuc1_then_la1(main:: vbuxx=(byte) main::a#10 vbuc1=(byte/signed byte/word/signed word) 55 la1=(label) main::b11_from_b56 ) Statement [75] if((byte) main::a#10>(byte/signed byte/word/signed word) 55) goto main::@11 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ) always clobbers reg byte a Potential register analysis [81] if(main::a#10>*(main::cs#0 + main::i#10)) goto main::@12 missing fragment vbuz1_gt_pbuc1_derefidx_vbuxx_then_la1 allocation: reg byte x [ main::i#10 main::i#1 ] zp ZP_BYTE:2 [ main::a#10 main::a#1 ] MISSING FRAGMENTS - vbuz1_gt_pbuc1_derefidx_vbuxx_then_la1 + vbuz1_gt_pbuc1_derefidx_vbuxx_then_la1(main:: vbuz1=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuxx=(byte) main::i#10 la1=(label) main::b12_from_b57 ) Statement [81] if((byte) main::a#10>*((const byte[5]) main::cs#0 + (byte) main::i#10)) goto main::@12 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ) always clobbers reg byte a reg byte y Statement [85] (byte) printu::b#10 ← *((const byte[5]) main::cs#0 + (byte) main::i#10) [ main::a#10 main::i#10 line_cursor#1 main::b#0 main::r#50 printu::a#10 printu::b#10 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 main::r#50 printu::a#10 printu::b#10 char_cursor#52 ] ) always clobbers reg byte a Statement [88] if((byte) main::a#10>(byte) main::a#10) goto main::@13 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ) always clobbers reg byte a Statement [103] (byte*~) char_cursor#142 ← (byte*) line_cursor#1 [ main::a#10 main::i#10 line_cursor#1 main::b#0 printu::a#12 printu::b#12 printu::res#12 char_cursor#142 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 printu::a#12 printu::b#12 printu::res#12 char_cursor#142 ] ) always clobbers reg byte a Potential register analysis [111] if(main::a#10<*(main::cs#0 + main::i#10)) goto main::@16 missing fragment vbuz1_lt_pbuc1_derefidx_vbuxx_then_la1 allocation: reg byte x [ main::i#10 main::i#1 ] zp ZP_BYTE:2 [ main::a#10 main::a#1 ] MISSING FRAGMENTS - vbuz1_lt_pbuc1_derefidx_vbuxx_then_la1 + vbuz1_lt_pbuc1_derefidx_vbuxx_then_la1(main:: vbuz1=(byte) main::a#10 pbuc1=(const byte[5]) main::cs#0 vbuxx=(byte) main::i#10 la1=(label) main::b16_from_b62 ) Statement [111] if((byte) main::a#10<*((const byte[5]) main::cs#0 + (byte) main::i#10)) goto main::@16 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 char_cursor#52 ] ) always clobbers reg byte a reg byte y Statement [115] (byte) printu::b#14 ← *((const byte[5]) main::cs#0 + (byte) main::i#10) [ main::a#10 main::i#10 line_cursor#1 main::b#0 main::r#54 printu::a#14 printu::b#14 char_cursor#52 ] ( main:2 [ main::a#10 main::i#10 line_cursor#1 main::b#0 main::r#54 printu::a#14 printu::b#14 char_cursor#52 ] ) always clobbers reg byte a Potential register analysis [118] if(main::a#10