mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-14 23:04:57 +00:00
Iplemented graph based synthesis. Working on the kinks - eg. issue #75
This commit is contained in:
parent
b29ed11a81
commit
e9965580a4
@ -35,7 +35,7 @@ public class CompileLog {
|
||||
/**
|
||||
* Should the log be output to System.out while being built
|
||||
*/
|
||||
private boolean sysOut = false;
|
||||
private boolean sysOut = true;
|
||||
|
||||
public CompileLog() {
|
||||
this.log = new StringBuilder();
|
||||
|
@ -0,0 +1,51 @@
|
||||
package dk.camelot64.kickc.fragment;
|
||||
|
||||
import dk.camelot64.kickc.asm.AsmClobber;
|
||||
|
||||
/** The clobber profile for a fragment template. Only distinguishes the 3 registers A/X/Y and not the flags. */
|
||||
public class AsmFragmentClobber {
|
||||
|
||||
private boolean clobberA;
|
||||
private boolean clobberX;
|
||||
private boolean clobberY;
|
||||
|
||||
public AsmFragmentClobber(boolean clobberA, boolean clobberX, boolean clobberY) {
|
||||
this.clobberA = clobberA;
|
||||
this.clobberX = clobberX;
|
||||
this.clobberY = clobberY;
|
||||
}
|
||||
|
||||
public AsmFragmentClobber(AsmClobber clobber) {
|
||||
this(clobber.isClobberA(), clobber.isClobberX(), clobber.isClobberY());
|
||||
}
|
||||
|
||||
public boolean isClobberA() {
|
||||
return clobberA;
|
||||
}
|
||||
|
||||
public boolean isClobberX() {
|
||||
return clobberX;
|
||||
}
|
||||
|
||||
public boolean isClobberY() {
|
||||
return clobberY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(this == o) return true;
|
||||
if(o == null || getClass() != o.getClass()) return false;
|
||||
AsmFragmentClobber that = (AsmFragmentClobber) o;
|
||||
if(clobberA != that.clobberA) return false;
|
||||
if(clobberX != that.clobberX) return false;
|
||||
return clobberY == that.clobberY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (clobberA ? 1 : 0);
|
||||
result = 31 * result + (clobberX ? 1 : 0);
|
||||
result = 31 * result + (clobberY ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,9 +1,14 @@
|
||||
package dk.camelot64.kickc.fragment;
|
||||
|
||||
import dk.camelot64.kickc.asm.AsmClobber;
|
||||
import dk.camelot64.kickc.asm.AsmProgram;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.parser.KickCLexer;
|
||||
import dk.camelot64.kickc.parser.KickCParser;
|
||||
import org.antlr.v4.runtime.*;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
/**
|
||||
* An ASM fragment template usable for generating KickAssembler code for different bindings.
|
||||
* The AsmFragmentTemplateSynthesizer can generate multiple different templates usable for a specific fragment signature.
|
||||
@ -16,14 +21,18 @@ public class AsmFragmentTemplate {
|
||||
private String signature;
|
||||
/** The fragment template body */
|
||||
private String body;
|
||||
/** 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 AsmFragmentTemplateSynthesisRule synthesis;
|
||||
|
||||
/** The sub fragment template that the synthesis modified to create this. null if the fragment template was loaded. */
|
||||
private AsmFragmentTemplate subFragment;
|
||||
|
||||
/** 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 ASM clobber of the fragment. */
|
||||
private AsmFragmentClobber clobber;
|
||||
/** The cycles consumed by the ASM of the fragment. */
|
||||
private Double cycles;
|
||||
|
||||
public AsmFragmentTemplate(String signature, String body) {
|
||||
this.signature = signature;
|
||||
this.body = body;
|
||||
@ -49,25 +58,50 @@ public class AsmFragmentTemplate {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an ASM fragment.
|
||||
* Initialize the fields that require parsing the ASM (bodyAsm, clobber, clobber).
|
||||
*
|
||||
* @param fragmentBody The stream containing the fragment syntax
|
||||
* @param fragmentFileName The filename (used in error messages)
|
||||
* @return The parsed fragment ready for generating
|
||||
*/
|
||||
private static KickCParser.AsmLinesContext parseBody(String fragmentBody, final String fragmentFileName) {
|
||||
CodePointCharStream fragmentCharStream = CharStreams.fromString(fragmentBody);
|
||||
private void initAsm() {
|
||||
// Parse the body ASM
|
||||
CodePointCharStream fragmentCharStream = CharStreams.fromString(body);
|
||||
KickCLexer kickCLexer = new KickCLexer(fragmentCharStream);
|
||||
KickCParser kickCParser = new KickCParser(new CommonTokenStream(kickCLexer));
|
||||
kickCParser.addErrorListener(new BaseErrorListener() {
|
||||
@Override
|
||||
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
|
||||
throw new RuntimeException("Error parsing fragment " + fragmentFileName + "\n - Line: " + line + "\n - Message: " + msg);
|
||||
throw new RuntimeException("Error parsing fragment " + signature + "\n - Line: " + line + "\n - Message: " + msg);
|
||||
}
|
||||
});
|
||||
kickCParser.setBuildParseTree(true);
|
||||
KickCParser.AsmFileContext asmFile = kickCParser.asmFile();
|
||||
return asmFile.asmLines();
|
||||
this.bodyAsm = kickCParser.asmFile().asmLines();
|
||||
// Generate a dummy instance to find clobber & cycles
|
||||
ProgramScope scope = new ProgramScope();
|
||||
LinkedHashMap<String, Value> bindings = new LinkedHashMap<>();
|
||||
VariableVersion v1 = new VariableVersion("$tmp1", SymbolType.BYTE, null);
|
||||
VariableVersion v2 = new VariableVersion("$tmp2", SymbolType.BYTE, null);
|
||||
VariableVersion v3 = new VariableVersion("$tmp3", SymbolType.BYTE, null);
|
||||
v1.setScope(scope);
|
||||
v2.setScope(scope);
|
||||
v3.setScope(scope);
|
||||
v1.setAllocation(new Registers.RegisterZpByte(2));
|
||||
v2.setAllocation(new Registers.RegisterZpByte(4));
|
||||
v3.setAllocation(new Registers.RegisterZpByte(6));
|
||||
if(signature.contains("z1")) bindings.put("z1", v1);
|
||||
if(signature.contains("z2")) bindings.put("z2", v2);
|
||||
if(signature.contains("z3")) bindings.put("z3", v3);
|
||||
if(signature.contains("c1")) bindings.put("c1", new ConstantInteger(10));
|
||||
if(signature.contains("c2")) bindings.put("c2", new ConstantInteger(20));
|
||||
if(signature.contains("c3")) bindings.put("c3", new ConstantInteger(30));
|
||||
if(signature.contains("la1")) bindings.put("la1", new Label("@1", scope, true));
|
||||
AsmFragmentInstance fragmentInstance =
|
||||
new AsmFragmentInstance(new Program(), signature, ScopeRef.ROOT, this, bindings);
|
||||
AsmProgram asm = new AsmProgram();
|
||||
asm.startSegment(null, signature);
|
||||
fragmentInstance.generate(asm);
|
||||
AsmClobber asmClobber = asm.getClobber();
|
||||
this.clobber = new AsmFragmentClobber(asmClobber);
|
||||
this.cycles = asm.getCycles();
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
@ -80,11 +114,25 @@ public class AsmFragmentTemplate {
|
||||
|
||||
public KickCParser.AsmLinesContext getBodyAsm() {
|
||||
if(bodyAsm == null) {
|
||||
bodyAsm = parseBody(body, signature);
|
||||
initAsm();
|
||||
}
|
||||
return bodyAsm;
|
||||
}
|
||||
|
||||
public AsmFragmentClobber getClobber() {
|
||||
if(clobber == null) {
|
||||
initAsm();
|
||||
}
|
||||
return clobber;
|
||||
}
|
||||
|
||||
public double getCycles() {
|
||||
if(cycles == null) {
|
||||
initAsm();
|
||||
}
|
||||
return cycles;
|
||||
}
|
||||
|
||||
public boolean isFile() {
|
||||
return file;
|
||||
}
|
||||
|
@ -1,570 +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.
|
||||
* <p>
|
||||
* 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<String, AsmFragmentTemplate> bestFragmentCache = new HashMap<>();
|
||||
|
||||
/** Caches all asm fragment templates for all encountered signatures. */
|
||||
private static Map<String, List<AsmFragmentTemplate>> 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<AsmFragmentTemplateSynthesisRule> fragmentSyntheses;
|
||||
|
||||
static Map<String, List<AsmFragmentTemplate>> 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<AsmFragmentTemplate> 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<AsmFragmentTemplateSynthesisRule> getFragmentSyntheses() {
|
||||
if(fragmentSyntheses == null) {
|
||||
fragmentSyntheses = initFragmentSyntheses();
|
||||
}
|
||||
return fragmentSyntheses;
|
||||
}
|
||||
|
||||
private static List<AsmFragmentTemplateSynthesisRule> initFragmentSyntheses() {
|
||||
Map<String, String> mapZ = new LinkedHashMap<>();
|
||||
mapZ.put("z2", "z1");
|
||||
mapZ.put("z3", "z2");
|
||||
Map<String, String> mapZ2 = new LinkedHashMap<>();
|
||||
mapZ2.put("z3", "z1");
|
||||
Map<String, String> mapZ3 = new LinkedHashMap<>();
|
||||
mapZ3.put("z3", "z2");
|
||||
Map<String, String> mapC = new LinkedHashMap<>();
|
||||
mapC.put("c2", "c1");
|
||||
mapC.put("c3", "c2");
|
||||
Map<String, String> mapC3 = new LinkedHashMap<>();
|
||||
mapC3.put("c3", "c2");
|
||||
Map<String, String> mapZC = new LinkedHashMap<>();
|
||||
mapZC.putAll(mapZ);
|
||||
mapZC.putAll(mapC);
|
||||
Map<String, String> 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<AsmFragmentTemplateSynthesisRule> 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<String> signatures;
|
||||
|
||||
public AsmSynthesisPath() {
|
||||
this.signatures = new ArrayDeque<>();
|
||||
}
|
||||
|
||||
private AsmSynthesisPath(ArrayDeque<String> signatures) {
|
||||
this.signatures = signatures;
|
||||
}
|
||||
|
||||
AsmSynthesisPath add(String signature) {
|
||||
ArrayDeque<String> 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.
|
||||
* <p>
|
||||
* 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<AsmFragmentTemplate> 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<AsmFragmentTemplate> candidates = new ArrayList<>();
|
||||
// Synthesize the fragment from other fragments
|
||||
List<AsmFragmentTemplateSynthesisRule> synths = getFragmentSyntheses();
|
||||
for(AsmFragmentTemplateSynthesisRule synth : synths) {
|
||||
List<AsmFragmentTemplate> 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,23 +1,21 @@
|
||||
package dk.camelot64.kickc.fragment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import dk.camelot64.kickc.CompileLog;
|
||||
|
||||
import java.util.*;
|
||||
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 AsmFragmentTemplateSynthesisRule {
|
||||
|
||||
private String sigMatch;
|
||||
private String sigAvoid;
|
||||
private String asmPrefix;
|
||||
private String sigReplace;
|
||||
private String asmPostfix;
|
||||
private Map<String, String> bindMappings;
|
||||
private boolean mapSignature;
|
||||
private String subSignature;
|
||||
final private String sigMatch;
|
||||
final private String sigAvoid;
|
||||
final private String asmPrefix;
|
||||
final private String sigReplace;
|
||||
final private String asmPostfix;
|
||||
final private Map<String, String> bindMappings;
|
||||
final private boolean mapSignature;
|
||||
|
||||
AsmFragmentTemplateSynthesisRule(String sigMatch, String sigAvoid, String asmPrefix, String sigReplace, String asmPostfix, Map<String, String> bindMappings, boolean mapSignature) {
|
||||
this.sigMatch = sigMatch;
|
||||
@ -29,44 +27,53 @@ class AsmFragmentTemplateSynthesisRule {
|
||||
this.mapSignature = mapSignature;
|
||||
}
|
||||
|
||||
public AsmFragmentTemplateSynthesisRule(String sigMatch, String sigAvoid, String asmPrefix, String sigReplace, String asmPostfix, Map<String, String> bindMappings) {
|
||||
AsmFragmentTemplateSynthesisRule(String sigMatch, String sigAvoid, String asmPrefix, String sigReplace, String asmPostfix, Map<String, String> bindMappings) {
|
||||
this(sigMatch, sigAvoid, asmPrefix, sigReplace, asmPostfix, bindMappings, true);
|
||||
}
|
||||
|
||||
static String regexpRewriteSignature(String signature, String match, String replace) {
|
||||
Pattern p = Pattern.compile(match);
|
||||
Matcher m = p.matcher(signature);
|
||||
String output = signature;
|
||||
if(m.find()) {
|
||||
// getReplacement first number with "number" and second number with the first
|
||||
output = m.replaceAll(replace);
|
||||
}
|
||||
return output;
|
||||
/**
|
||||
* Is the rule match usable for synthesizing a fragment template
|
||||
*
|
||||
* @param signature The fragment template signature
|
||||
* @return true if the rule matches the signature
|
||||
*/
|
||||
public boolean matches(String signature) {
|
||||
return signature.matches(sigMatch) && (sigAvoid == null || !signature.matches(sigAvoid));
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return sigMatch + (sigAvoid == null ? "" : ("/" + sigAvoid));
|
||||
}
|
||||
|
||||
public List<AsmFragmentTemplate> synthesize(String signature, AsmFragmentTemplateManager.AsmSynthesisPath path, AsmFragmentTemplateManager.AsmFragmentTemplateSynthesizer synthesizer) {
|
||||
ArrayList<AsmFragmentTemplate> candidates = new ArrayList<>();
|
||||
if(signature.matches(sigMatch)) {
|
||||
if(sigAvoid == null || !signature.matches(sigAvoid)) {
|
||||
subSignature = regexpRewriteSignature(signature, sigMatch, sigReplace);
|
||||
/**
|
||||
* The signature of the sub-template to synthesize the template from
|
||||
*
|
||||
* @param signature The signature to synthesize
|
||||
* @return Signature of the sub-template to synthesize the template from. null if the rule does not match the signature.
|
||||
*/
|
||||
public String getSubSignature(String signature) {
|
||||
if(matches(signature)) {
|
||||
String subSignature = regexpRewriteSignature(signature, sigMatch, sigReplace);
|
||||
if(mapSignature && bindMappings != null) {
|
||||
// When mapping the signature we do the map replacement in the signature
|
||||
for(String bound : bindMappings.keySet()) {
|
||||
subSignature = subSignature.replace(bound, bindMappings.get(bound));
|
||||
}
|
||||
}
|
||||
List<AsmFragmentTemplate> subFragmentTemplates = synthesizer.loadOrSynthesizeFragment(subSignature, path);
|
||||
for(AsmFragmentTemplate subFragmentTemplate : subFragmentTemplates) {
|
||||
if(subFragmentTemplate != null) {
|
||||
return subSignature;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public AsmFragmentTemplate synthesize(String signature, AsmFragmentTemplate subTemplate) {
|
||||
if(!matches(signature)) {
|
||||
throw new RuntimeException("Synthesis error! Attempting to synthesize on non-matching signature signature:"+signature+" match:"+sigMatch+" avoid:"+sigAvoid);
|
||||
}
|
||||
if(!subTemplate.getSignature().equals(getSubSignature(signature))) {
|
||||
throw new RuntimeException("Synthesis error! Attempting to synthesize on non-matching sub template sub-signature:"+subTemplate.getSignature()+" expecting:"+getSubSignature(signature));
|
||||
}
|
||||
StringBuilder newFragment = new StringBuilder();
|
||||
if(asmPrefix != null) {
|
||||
newFragment.append(asmPrefix).append("\n");
|
||||
}
|
||||
String subFragment = subFragmentTemplate.getBody();
|
||||
String subFragment = subTemplate.getBody();
|
||||
if(bindMappings != null) {
|
||||
if(mapSignature) {
|
||||
// When mapping the signature we do the reverse replacement in the ASM
|
||||
@ -87,17 +94,350 @@ class AsmFragmentTemplateSynthesisRule {
|
||||
newFragment.append("\n");
|
||||
newFragment.append(asmPostfix);
|
||||
}
|
||||
candidates.add(new AsmFragmentTemplate(signature, newFragment.toString(), this, subFragmentTemplate));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return candidates;
|
||||
return new AsmFragmentTemplate(signature, newFragment.toString(), this, subTemplate);
|
||||
}
|
||||
|
||||
public String getSubSignature() {
|
||||
return subSignature;
|
||||
static String regexpRewriteSignature(String signature, String match, String replace) {
|
||||
Pattern p = Pattern.compile(match);
|
||||
Matcher m = p.matcher(signature);
|
||||
String output = signature;
|
||||
if(m.find()) {
|
||||
output = m.replaceAll(replace);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(this == o) return true;
|
||||
if(o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
AsmFragmentTemplateSynthesisRule that = (AsmFragmentTemplateSynthesisRule) o;
|
||||
|
||||
if(mapSignature != that.mapSignature) return false;
|
||||
if(sigMatch != null ? !sigMatch.equals(that.sigMatch) : that.sigMatch != null) return false;
|
||||
if(sigAvoid != null ? !sigAvoid.equals(that.sigAvoid) : that.sigAvoid != null) return false;
|
||||
if(asmPrefix != null ? !asmPrefix.equals(that.asmPrefix) : that.asmPrefix != null) return false;
|
||||
if(sigReplace != null ? !sigReplace.equals(that.sigReplace) : that.sigReplace != null) return false;
|
||||
if(asmPostfix != null ? !asmPostfix.equals(that.asmPostfix) : that.asmPostfix != null) return false;
|
||||
return bindMappings != null ? bindMappings.equals(that.bindMappings) : that.bindMappings == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = sigMatch != null ? sigMatch.hashCode() : 0;
|
||||
result = 31 * result + (sigAvoid != null ? sigAvoid.hashCode() : 0);
|
||||
result = 31 * result + (asmPrefix != null ? asmPrefix.hashCode() : 0);
|
||||
result = 31 * result + (sigReplace != null ? sigReplace.hashCode() : 0);
|
||||
result = 31 * result + (asmPostfix != null ? asmPostfix.hashCode() : 0);
|
||||
result = 31 * result + (bindMappings != null ? bindMappings.hashCode() : 0);
|
||||
result = 31 * result + (mapSignature ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** All the synthesize rules available. */
|
||||
private static List<AsmFragmentTemplateSynthesisRule> fragmentSyntheses;
|
||||
|
||||
static List<AsmFragmentTemplateSynthesisRule> getSynthesisRules() {
|
||||
if(fragmentSyntheses == null) {
|
||||
fragmentSyntheses = initFragmentSyntheses();
|
||||
}
|
||||
return fragmentSyntheses;
|
||||
}
|
||||
|
||||
private static List<AsmFragmentTemplateSynthesisRule> initFragmentSyntheses() {
|
||||
Map<String, String> mapZ = new LinkedHashMap<>();
|
||||
mapZ.put("z2", "z1");
|
||||
mapZ.put("z3", "z2");
|
||||
Map<String, String> mapZ2 = new LinkedHashMap<>();
|
||||
mapZ2.put("z3", "z1");
|
||||
Map<String, String> mapZ3 = new LinkedHashMap<>();
|
||||
mapZ3.put("z3", "z2");
|
||||
Map<String, String> mapC = new LinkedHashMap<>();
|
||||
mapC.put("c2", "c1");
|
||||
mapC.put("c3", "c2");
|
||||
Map<String, String> mapC3 = new LinkedHashMap<>();
|
||||
mapC3.put("c3", "c2");
|
||||
Map<String, String> mapZC = new LinkedHashMap<>();
|
||||
mapZC.putAll(mapZ);
|
||||
mapZC.putAll(mapC);
|
||||
Map<String, String> 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<AsmFragmentTemplateSynthesisRule> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,471 @@
|
||||
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 fragment templates from their signature.
|
||||
* <p>
|
||||
* Fragment templates are created by either:
|
||||
* <ul>
|
||||
* <li>Loading a fragment file from the fragment-folder.</li>
|
||||
* <li>synthesising from another fragment using one of the {@link AsmFragmentTemplateSynthesisRule}s.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The actual creation is handled by a full-graph
|
||||
*/
|
||||
public class AsmFragmentTemplateSynthesizer {
|
||||
|
||||
/** Resource Folder containing the fragment files. */
|
||||
public static final String FRAGMENT_RESOURCE_FOLDER = "dk/camelot64/kickc/fragment/asm/";
|
||||
|
||||
/** The static instance. */
|
||||
static AsmFragmentTemplateSynthesizer SYNTHESIZER = new AsmFragmentTemplateSynthesizer();
|
||||
|
||||
/** Create synthesizer. */
|
||||
private AsmFragmentTemplateSynthesizer() {
|
||||
this.bestFragmentCache = new LinkedHashMap<>();
|
||||
this.synthesisGraph = new LinkedHashMap<>();
|
||||
this.bestTemplateUpdate = new ArrayDeque<>();
|
||||
}
|
||||
|
||||
/** Cache for the best fragment templates. Maps signature to the best fragment template for the signature. */
|
||||
private Map<String, AsmFragmentTemplate> bestFragmentCache;
|
||||
|
||||
/** Special singleton representing that the fragment can not be synthesized or loaded. */
|
||||
private AsmFragmentTemplate UNKNOWN = new AsmFragmentTemplate("UNKNOWN", null);
|
||||
|
||||
public static AsmFragmentInstance getFragmentInstance(AsmFragmentInstanceSpec instanceSpec, CompileLog log) {
|
||||
String signature = instanceSpec.getSignature();
|
||||
AsmFragmentTemplate fragmentTemplate = SYNTHESIZER.getFragmentTemplate(signature, log);
|
||||
// Return the resulting fragment instance
|
||||
return new AsmFragmentInstance(
|
||||
instanceSpec.getProgram(),
|
||||
signature,
|
||||
instanceSpec.getCodeScope(),
|
||||
fragmentTemplate,
|
||||
instanceSpec.getBindings());
|
||||
}
|
||||
|
||||
public AsmFragmentTemplate getFragmentTemplate(String signature, CompileLog log) {
|
||||
AsmFragmentTemplate bestTemplate = bestFragmentCache.get(signature);
|
||||
if(bestTemplate == UNKNOWN) {
|
||||
if(log.isVerboseFragmentLog()) {
|
||||
log.append("Unknown fragment " + signature);
|
||||
}
|
||||
throw new UnknownFragmentException(signature);
|
||||
}
|
||||
if(bestTemplate == null) {
|
||||
Collection<AsmFragmentTemplate> candidates = getBestTemplates(signature, log);
|
||||
if(candidates.size() == 0) {
|
||||
if(log.isVerboseFragmentLog()) {
|
||||
log.append("Unknown fragment " + signature);
|
||||
}
|
||||
bestFragmentCache.put(signature, UNKNOWN);
|
||||
throw new UnknownFragmentException(signature);
|
||||
}
|
||||
double minScore = Double.MAX_VALUE;
|
||||
for(AsmFragmentTemplate candidateTemplate : candidates) {
|
||||
double score = candidateTemplate.getCycles();
|
||||
if(candidateTemplate.getClobber().isClobberA()) score+=0.5;
|
||||
if(candidateTemplate.getClobber().isClobberY()) score+=1.0;
|
||||
if(candidateTemplate.getClobber().isClobberX()) score+=1.5;
|
||||
if(score < minScore) {
|
||||
minScore = score;
|
||||
bestTemplate = candidateTemplate;
|
||||
}
|
||||
}
|
||||
if(log.isVerboseFragmentLog()) {
|
||||
log.append("Found best fragment " + bestTemplate.getName() + " score: " + minScore);
|
||||
}
|
||||
bestFragmentCache.put(signature, bestTemplate);
|
||||
}
|
||||
// Count usages
|
||||
AsmFragmentTemplateUsages.incUsage(bestTemplate);
|
||||
return bestTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the best fragment templates for a signature.
|
||||
* The templates are either loaded or synthesized from other templates.
|
||||
*
|
||||
* @param signature The signature of the fragment template to get
|
||||
* @param log The compile log
|
||||
* @return The best templates for the passed signature
|
||||
*/
|
||||
private Collection<AsmFragmentTemplate> getBestTemplates(String signature, CompileLog log) {
|
||||
getOrCreateSynthesis(signature, log);
|
||||
updateBestTemplates(log);
|
||||
AsmFragmentSynthesis synthesis = getSynthesis(signature);
|
||||
if(synthesis == null) {
|
||||
throw new RuntimeException("Synthesis Graph Error! synthesis not found in graph " + signature);
|
||||
}
|
||||
return synthesis.getBestTemplates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains the synthesis for each fragment template signature.
|
||||
* The synthesis is capable of loading the fragment from disk or synthesizing it from other fragments using synthesis rules.
|
||||
* The synthesis caches the best fragments for each clobber profile (loaded or synthesized).
|
||||
* This map is effectively a full-graph where the nodes are synthesis for signatures and edges are the
|
||||
* synthesis rules capable of synthesizing one fragment temple from another.
|
||||
*/
|
||||
private Map<String, AsmFragmentSynthesis> synthesisGraph;
|
||||
|
||||
/**
|
||||
* The synthesis is capable of loading the fragment from disk or synthesizing it from other fragments using synthesis rules.
|
||||
* The synthesis caches the best fragments for each clobber profile (loaded or synthesized).
|
||||
* A node in the synthesis graph.
|
||||
*/
|
||||
public static class AsmFragmentSynthesis {
|
||||
|
||||
/** The signature of the fragment template being synthesized. */
|
||||
private String signature;
|
||||
|
||||
/** The best template loaded/synthesized so far for each clobber profile */
|
||||
private Map<AsmFragmentClobber, AsmFragmentTemplate> bestTemplates;
|
||||
|
||||
/** Options for synthesizing the template from sub-fragments using a specific synthesis rule. Forward edges in the synthesis graph. */
|
||||
private Set<AsmFragmentSynthesisOption> synthesisOptions;
|
||||
|
||||
/** Options for synthesizing the other templates from this template using a specific synthesis rule. Backward edges in the synthesis graph. */
|
||||
private Set<AsmFragmentSynthesisOption> parentOptions;
|
||||
|
||||
/** The template loaded from a file, if it exists. null if no file exists for the signature. */
|
||||
private AsmFragmentTemplate fileTemplate;
|
||||
|
||||
/**
|
||||
* Create a new synthesis
|
||||
*
|
||||
* @param signature The signature of the fragment template to load/synthesize
|
||||
*/
|
||||
public AsmFragmentSynthesis(String signature) {
|
||||
this.signature = signature;
|
||||
this.bestTemplates = new LinkedHashMap<>();
|
||||
this.synthesisOptions = new LinkedHashSet<>();
|
||||
this.parentOptions = new LinkedHashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a synthesis option to the template synthesis.
|
||||
* The synthesis options can be used for synthesizing the template from sub-fragments using a specific synthesis rule.
|
||||
*
|
||||
* @param synthesisOption The option to add
|
||||
*/
|
||||
public void addSynthesisOption(AsmFragmentSynthesisOption synthesisOption) {
|
||||
this.synthesisOptions.add(synthesisOption);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the options for synthesizing the template from sub-fragments using a specific synthesis rule. Forward edges in the synthesis graph.
|
||||
*
|
||||
* @return The options
|
||||
*/
|
||||
public Collection<AsmFragmentSynthesisOption> getSynthesisOptions() {
|
||||
return synthesisOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a parent. The parent is an option for synthesizing another fragment template from this one using a specific synthesis rule.
|
||||
*
|
||||
* @param synthesisOption Thew parent option to add
|
||||
*/
|
||||
public void addParentOption(AsmFragmentSynthesisOption synthesisOption) {
|
||||
this.parentOptions.add(synthesisOption);
|
||||
}
|
||||
|
||||
public void setFileTemplate(AsmFragmentTemplate fileTemplate) {
|
||||
this.fileTemplate = fileTemplate;
|
||||
}
|
||||
|
||||
public AsmFragmentTemplate getFileTemplate() {
|
||||
return fileTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a candidate for best template.
|
||||
* If the candidate is better than the current best for its clobber profile update the best template
|
||||
*
|
||||
* @param template The template candidate to examine
|
||||
* @return true if the best template was updated
|
||||
*/
|
||||
public boolean bestTemplateCandidate(AsmFragmentTemplate template) {
|
||||
AsmFragmentClobber clobber = template.getClobber();
|
||||
AsmFragmentTemplate bestTemplate = bestTemplates.get(clobber);
|
||||
if(bestTemplate == null || bestTemplate.getCycles() > template.getCycles()) {
|
||||
bestTemplates.put(clobber, template);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent options.
|
||||
* These are options for synthesizing other templates
|
||||
* from this template using a specific synthesis rule. Backward edges in the synthesis graph.
|
||||
*
|
||||
* @return The parent options.
|
||||
*/
|
||||
public Set<AsmFragmentSynthesisOption> getParentOptions() {
|
||||
return parentOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the best fragment templates of the synthesis.
|
||||
* Multiple templates are returned if templates with different clobber profiles exist.
|
||||
*
|
||||
* @return The best templates of the synthesis.
|
||||
*/
|
||||
public Collection<AsmFragmentTemplate> getBestTemplates() {
|
||||
return bestTemplates.values();
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
}
|
||||
|
||||
/** An option for synthesizing a fragment template from a sub-template using a specific synthesis rule. An edge in the synthesis graph. */
|
||||
public static class AsmFragmentSynthesisOption {
|
||||
|
||||
/** The signature of the fragment template being synthesized. The from-node in the graph. */
|
||||
private String signature;
|
||||
|
||||
/** The signature of the sub-fragment template to synthesize from. The to-node in the graph. */
|
||||
private String subSignature;
|
||||
|
||||
/** The synthesis rule capable of synthesizing this template from the sub-fragment. */
|
||||
private AsmFragmentTemplateSynthesisRule rule;
|
||||
|
||||
/**
|
||||
* Create a synthesis option
|
||||
*
|
||||
* @param signature he signature of the fragment template being synthesized.
|
||||
* @param rule The synthesis rule capable of synthesizing this template from the sub-fragment.
|
||||
*/
|
||||
public AsmFragmentSynthesisOption(String signature, AsmFragmentTemplateSynthesisRule rule) {
|
||||
this.signature = signature;
|
||||
this.rule = rule;
|
||||
this.subSignature = rule.getSubSignature(signature);
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public String getSubSignature() {
|
||||
return subSignature;
|
||||
}
|
||||
|
||||
public AsmFragmentTemplateSynthesisRule getRule() {
|
||||
return rule;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(this == o) return true;
|
||||
if(o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
AsmFragmentSynthesisOption that = (AsmFragmentSynthesisOption) o;
|
||||
|
||||
if(signature != null ? !signature.equals(that.signature) : that.signature != null) return false;
|
||||
if(subSignature != null ? !subSignature.equals(that.subSignature) : that.subSignature != null) return false;
|
||||
return rule != null ? rule.equals(that.rule) : that.rule == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = signature != null ? signature.hashCode() : 0;
|
||||
result = 31 * result + (subSignature != null ? subSignature.hashCode() : 0);
|
||||
result = 31 * result + (rule != null ? rule.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the entire synthesis graph. Called by the usage statistics.
|
||||
*
|
||||
* @return The entire synthesis graph
|
||||
*/
|
||||
Map<String, AsmFragmentSynthesis> getSynthesisGraph() {
|
||||
return synthesisGraph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the synthesis used to synthesize a fragment template.
|
||||
* If the synthesis does not exist null is returned.
|
||||
*
|
||||
* @param signature The signature of the template to synthesize
|
||||
* @return The synthesis used to synthesize the fragment template.
|
||||
* null if the synthesis graph does not contain the synthesis.
|
||||
*/
|
||||
private AsmFragmentSynthesis getSynthesis(String signature) {
|
||||
return synthesisGraph.get(signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get (or create) the synthesis used to synthesize a fragment template.
|
||||
* If the synthesis does not already exist in the synthesis graph it is created - along with any sub-synthesis recursively usable for creating it.
|
||||
* If any synthesis are created they are added to the {@link #bestTemplateUpdate} queue.
|
||||
*
|
||||
* @param signature The signature of the template to synthesize
|
||||
* @param log The compile log
|
||||
* @return The synthesis that is used to load/synthesize the best template
|
||||
*/
|
||||
AsmFragmentSynthesis getOrCreateSynthesis(String signature, CompileLog log) {
|
||||
AsmFragmentSynthesis synthesis = getSynthesis(signature);
|
||||
if(synthesis != null) {
|
||||
return synthesis;
|
||||
}
|
||||
// Synthesis not found - create it
|
||||
if(log.isVerboseFragmentLog()) {
|
||||
log.append("New fragment synthesis " + signature);
|
||||
}
|
||||
synthesis = new AsmFragmentSynthesis(signature);
|
||||
synthesisGraph.put(signature, synthesis);
|
||||
queueUpdateBestTemplate(synthesis);
|
||||
// Load the template from file - if it exists
|
||||
AsmFragmentTemplate fileTemplate = loadFragmentTemplate(signature, log);
|
||||
if(fileTemplate != null) {
|
||||
synthesis.setFileTemplate(fileTemplate);
|
||||
if(log.isVerboseFragmentLog()) {
|
||||
log.append("New fragment synthesis " + signature + " - Successfully loaded " + signature + ".asm");
|
||||
}
|
||||
}
|
||||
// Populate with synthesis options
|
||||
for(AsmFragmentTemplateSynthesisRule rule : AsmFragmentTemplateSynthesisRule.getSynthesisRules()) {
|
||||
if(rule.matches(signature)) {
|
||||
AsmFragmentSynthesisOption synthesisOption = new AsmFragmentSynthesisOption(signature, rule);
|
||||
synthesis.addSynthesisOption(synthesisOption);
|
||||
if(log.isVerboseFragmentLog()) {
|
||||
log.append("New fragment synthesis " + signature + " - sub-option " + synthesisOption.getSubSignature());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ensure that all sub-synthesis exist (recursively) - and set their parent options
|
||||
for(AsmFragmentSynthesisOption synthesisOption : synthesis.getSynthesisOptions()) {
|
||||
AsmFragmentSynthesis subSynthesis = getOrCreateSynthesis(synthesisOption.getSubSignature(), log);
|
||||
subSynthesis.addParentOption(synthesisOption);
|
||||
}
|
||||
return synthesis;
|
||||
}
|
||||
|
||||
/** Work queue with synthesis that need to be recalculated to find the best templates. */
|
||||
private Deque<AsmFragmentSynthesis> bestTemplateUpdate;
|
||||
|
||||
/**
|
||||
* Queue an update of the best templates for a synthesis to the work queue
|
||||
*
|
||||
* @param synthesis The synthesis to add to the work queue
|
||||
*/
|
||||
private void queueUpdateBestTemplate(AsmFragmentSynthesis synthesis) {
|
||||
if(!bestTemplateUpdate.contains(synthesis)) {
|
||||
bestTemplateUpdate.push(synthesis);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the best fragment template for all synthesis in the work queue {@link #bestTemplateUpdate} queue.
|
||||
* During the update more items can be added to the work queue.
|
||||
* Returns when the work queue is empty.
|
||||
*/
|
||||
void updateBestTemplates(CompileLog log) {
|
||||
while(!bestTemplateUpdate.isEmpty()) {
|
||||
AsmFragmentSynthesis synthesis = bestTemplateUpdate.pop();
|
||||
boolean modified = false;
|
||||
// Check if the file template is best in class
|
||||
AsmFragmentTemplate fileTemplate = synthesis.getFileTemplate();
|
||||
if(fileTemplate != null) {
|
||||
modified |= synthesis.bestTemplateCandidate(fileTemplate);
|
||||
}
|
||||
Collection<AsmFragmentSynthesisOption> synthesisOptions = synthesis.getSynthesisOptions();
|
||||
for(AsmFragmentSynthesisOption synthesisOption : synthesisOptions) {
|
||||
String subSignature = synthesisOption.getSubSignature();
|
||||
AsmFragmentTemplateSynthesisRule rule = synthesisOption.getRule();
|
||||
AsmFragmentSynthesis subSynthesis = getSynthesis(subSignature);
|
||||
if(subSynthesis == null) {
|
||||
throw new RuntimeException("Synthesis Graph Error! Sub-synthesis not found in graph " + subSignature);
|
||||
}
|
||||
Collection<AsmFragmentTemplate> subTemplates = subSynthesis.getBestTemplates();
|
||||
for(AsmFragmentTemplate subTemplate : subTemplates) {
|
||||
AsmFragmentTemplate synthesized = rule.synthesize(synthesis.getSignature(), subTemplate);
|
||||
if(log.isVerboseFragmentLog()) {
|
||||
log.append("Fragment synthesis " + synthesis.getSignature() + " - Successfully synthesized from " + subSignature);
|
||||
}
|
||||
modified |= synthesis.bestTemplateCandidate(synthesized);
|
||||
}
|
||||
}
|
||||
if(modified) {
|
||||
// The synthesis was modified - update all parents later
|
||||
for(AsmFragmentSynthesisOption parentOption : synthesis.getParentOptions()) {
|
||||
String parentSignature = parentOption.getSignature();
|
||||
AsmFragmentSynthesis parentSynthesis = getSynthesis(parentSignature);
|
||||
if(parentSynthesis == null) {
|
||||
throw new RuntimeException("Synthesis Graph Error! Parent synthesis not found in graph " + parentSignature);
|
||||
}
|
||||
queueUpdateBestTemplate(parentSynthesis);
|
||||
if(log.isVerboseFragmentLog()) {
|
||||
log.append("Fragment synthesis " + synthesis.getSignature() + " - New best, scheduling parent " + parentSignature);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(synthesis.getBestTemplates().isEmpty() && log.isVerboseFragmentLog()) {
|
||||
log.append("Fragment synthesis " + synthesis.getSignature() + " - No file or synthesis results!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to load a fragment template from disk.
|
||||
*
|
||||
* @param signature The signature
|
||||
* @param log The compile log
|
||||
* @return The fragment template from a file. null if the template is not found as a file.
|
||||
*/
|
||||
private AsmFragmentTemplate loadFragmentTemplate(String signature, CompileLog log) {
|
||||
try {
|
||||
ClassLoader classLoader = AsmFragmentTemplateSynthesizer.class.getClassLoader();
|
||||
URL fragmentUrl = classLoader.getResource(FRAGMENT_RESOURCE_FOLDER + signature + ".asm");
|
||||
if(fragmentUrl == null) return null;
|
||||
InputStream fragmentStream = fragmentUrl.openStream();
|
||||
CharStream fragmentCharStream = CharStreams.fromStream(fragmentStream);
|
||||
String body = fragmentCharStream.toString();
|
||||
return new AsmFragmentTemplate(signature, body);
|
||||
} catch(IOException e) {
|
||||
throw new RuntimeException("Error loading fragment file " + signature, e);
|
||||
} catch(StringIndexOutOfBoundsException e) {
|
||||
throw new RuntimeException("Problem reading fragment file " + signature, e);
|
||||
}
|
||||
}
|
||||
|
||||
File[] allFragmentFiles() {
|
||||
ClassLoader classLoader = AsmFragmentTemplateSynthesizer.class.getClassLoader();
|
||||
String path = classLoader.getResource("dk/camelot64/kickc/fragment/asm/").getPath();
|
||||
return new File(path).listFiles((dir, name) -> name.endsWith(".asm"));
|
||||
|
||||
}
|
||||
|
||||
public class UnknownFragmentException extends RuntimeException {
|
||||
|
||||
private String signature;
|
||||
|
||||
UnknownFragmentException(String signature) {
|
||||
super("Fragment not found " + signature);
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public String getFragmentSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -35,12 +35,14 @@ public class AsmFragmentTemplateUsages {
|
||||
*/
|
||||
public static void logUsages(CompileLog log, boolean logRedundantFiles, boolean logUnusedFiles, boolean logFileDetails, boolean logAllDetails) {
|
||||
|
||||
Map<String, List<AsmFragmentTemplate>> fragmentTemplateCache = AsmFragmentTemplateManager.getFragmentTemplateCache();
|
||||
ArrayList<String> signatures = new ArrayList<>(fragmentTemplateCache.keySet());
|
||||
Map<String, AsmFragmentTemplateSynthesizer.AsmFragmentSynthesis> synthesisGraph =
|
||||
AsmFragmentTemplateSynthesizer.SYNTHESIZER.getSynthesisGraph();
|
||||
ArrayList<String> signatures = new ArrayList<>(synthesisGraph.keySet());
|
||||
Collections.sort(signatures);
|
||||
File[] files = AsmFragmentTemplateManager.allFragmentFiles();
|
||||
File[] files = AsmFragmentTemplateSynthesizer.SYNTHESIZER.allFragmentFiles();
|
||||
|
||||
if(logRedundantFiles) {
|
||||
/*
|
||||
// Find all file fragments that were bested by a synthesized fragment
|
||||
log.append("\nREDUNDANT ASM FRAGMENT FILE ANALYSIS (if found remove them from disk)");
|
||||
for(String signature : signatures) {
|
||||
@ -65,22 +67,16 @@ public class AsmFragmentTemplateUsages {
|
||||
log.append("rm " + fileTemplate.getName() + ".asm #synthesized by " + maxTemplate.getName() + " - usages: " + maxUsage);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
Set<String> redundantSignatures = new LinkedHashSet<>();
|
||||
for(File file : files) {
|
||||
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
|
||||
AsmFragmentTemplateManager.AsmFragmentTemplateSynthesizer synthesizer = new AsmFragmentTemplateManager.AsmFragmentTemplateSynthesizer(signature, log);
|
||||
List<AsmFragmentTemplate> templates = synthesizer.loadOrSynthesizeFragment(signature, new AsmFragmentTemplateManager.AsmSynthesisPath());
|
||||
AsmFragmentTemplate fileTemplate = null;
|
||||
for(AsmFragmentTemplate template : templates) {
|
||||
if(template.isFile()) {
|
||||
fileTemplate = template;
|
||||
}
|
||||
}
|
||||
for(AsmFragmentTemplate template : templates) {
|
||||
if(!template.isFile() && template.getBody().equals(fileTemplate.getBody())) {
|
||||
// Synthesize the fragment - and check if the synthesis is as good as the file body
|
||||
AsmFragmentTemplate template =
|
||||
AsmFragmentTemplateSynthesizer.SYNTHESIZER.getFragmentTemplate(signature, log);
|
||||
if(!template.isFile()) {
|
||||
// Check if the synthesis uses a file marked as redundant
|
||||
AsmFragmentTemplate sourceFileTemplate = template;
|
||||
while(!sourceFileTemplate.isFile()) {
|
||||
@ -89,10 +85,8 @@ public class AsmFragmentTemplateUsages {
|
||||
if(redundantSignatures.contains(sourceFileTemplate.getSignature())) {
|
||||
throw new RuntimeException("Problem in redundancy analysis! " + sourceFileTemplate.getSignature() + ".asm seems redundant but is needed for synthesis of " + signature);
|
||||
}
|
||||
log.append("rm " + fileTemplate.getName() + ".asm #synthesized same ASM by " + template.getName());
|
||||
log.append("rm " + template.getName() + ".asm #synthesized better ASM by " + template.getName());
|
||||
redundantSignatures.add(signature);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -102,7 +96,8 @@ public class AsmFragmentTemplateUsages {
|
||||
for(File file : files) {
|
||||
String fileName = file.getName();
|
||||
String signature = fileName.substring(0, fileName.length() - 4);
|
||||
List<AsmFragmentTemplate> templates = fragmentTemplateCache.get(signature);
|
||||
AsmFragmentTemplateSynthesizer.AsmFragmentSynthesis asmFragmentSynthesis = synthesisGraph.get(signature);
|
||||
Collection<AsmFragmentTemplate> templates = asmFragmentSynthesis.getBestTemplates();
|
||||
if(templates != null && templates.size() > 0) {
|
||||
// The template has been loaded / synthesized - is the usage count zero?
|
||||
boolean allZero = true;
|
||||
@ -135,7 +130,7 @@ public class AsmFragmentTemplateUsages {
|
||||
// Find all file templates
|
||||
List<AsmFragmentTemplate> fileTemplates = new ArrayList<>();
|
||||
for(String signature : signatures) {
|
||||
List<AsmFragmentTemplate> templates = fragmentTemplateCache.get(signature);
|
||||
Collection<AsmFragmentTemplate> templates = synthesisGraph.get(signature).getBestTemplates();
|
||||
for(AsmFragmentTemplate template : templates) {
|
||||
if(template.isFile()) {
|
||||
fileTemplates.add(template);
|
||||
@ -150,10 +145,8 @@ public class AsmFragmentTemplateUsages {
|
||||
log.append("\nDETAILED ASM FRAGMENT USAGES");
|
||||
List<AsmFragmentTemplate> allTemplates = new ArrayList<>();
|
||||
for(String signature : signatures) {
|
||||
List<AsmFragmentTemplate> templates = fragmentTemplateCache.get(signature);
|
||||
for(AsmFragmentTemplate template : templates) {
|
||||
allTemplates.add(template);
|
||||
}
|
||||
Collection<AsmFragmentTemplate> templates = synthesisGraph.get(signature).getBestTemplates();
|
||||
allTemplates.addAll(templates);
|
||||
}
|
||||
logTemplatesByUsage(log, allTemplates);
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ public class Pass4CodeGeneration {
|
||||
}
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
AsmFragmentInstanceSpec asmFragmentInstanceSpec = new AsmFragmentInstanceSpec(assignment, assignmentAlu, program);
|
||||
AsmFragmentInstance asmFragmentInstance = AsmFragmentTemplateManager.getFragment(asmFragmentInstanceSpec, program.getLog());
|
||||
AsmFragmentInstance asmFragmentInstance = AsmFragmentTemplateSynthesizer.getFragmentInstance(asmFragmentInstanceSpec, program.getLog());
|
||||
asm.getCurrentSegment().setFragment(asmFragmentInstance.getFragmentName());
|
||||
asmFragmentInstance.generate(asm);
|
||||
aluState.clear();
|
||||
@ -248,14 +248,14 @@ public class Pass4CodeGeneration {
|
||||
asm.addComment(lValue.toString(program) + " = " + assignment.getrValue2().toString(program) + " // register copy " + getRegister(lValue));
|
||||
} else {
|
||||
AsmFragmentInstanceSpec asmFragmentInstanceSpec = new AsmFragmentInstanceSpec(assignment, program);
|
||||
AsmFragmentInstance asmFragmentInstance = AsmFragmentTemplateManager.getFragment(asmFragmentInstanceSpec, program.getLog());
|
||||
AsmFragmentInstance asmFragmentInstance = AsmFragmentTemplateSynthesizer.getFragmentInstance(asmFragmentInstanceSpec, program.getLog());
|
||||
asm.getCurrentSegment().setFragment(asmFragmentInstance.getFragmentName());
|
||||
asmFragmentInstance.generate(asm);
|
||||
}
|
||||
}
|
||||
} else if(statement instanceof StatementConditionalJump) {
|
||||
AsmFragmentInstanceSpec asmFragmentInstanceSpec = new AsmFragmentInstanceSpec((StatementConditionalJump) statement, block, program, getGraph());
|
||||
AsmFragmentInstance asmFragmentInstance = AsmFragmentTemplateManager.getFragment(asmFragmentInstanceSpec, program.getLog());
|
||||
AsmFragmentInstance asmFragmentInstance = AsmFragmentTemplateSynthesizer.getFragmentInstance(asmFragmentInstanceSpec, program.getLog());
|
||||
asm.getCurrentSegment().setFragment(asmFragmentInstance.getFragmentName());
|
||||
asmFragmentInstance.generate(asm);
|
||||
} else if(statement instanceof StatementCall) {
|
||||
@ -341,7 +341,7 @@ public class Pass4CodeGeneration {
|
||||
asm.getCurrentSegment().setFragment("register_copy");
|
||||
} else {
|
||||
AsmFragmentInstanceSpec asmFragmentInstanceSpec = new AsmFragmentInstanceSpec(lValue, rValue, program, scope);
|
||||
AsmFragmentInstance asmFragmentInstance = AsmFragmentTemplateManager.getFragment(asmFragmentInstanceSpec, program.getLog());
|
||||
AsmFragmentInstance asmFragmentInstance = AsmFragmentTemplateSynthesizer.getFragmentInstance(asmFragmentInstanceSpec, program.getLog());
|
||||
asm.getCurrentSegment().setFragment(asmFragmentInstance.getFragmentName());
|
||||
asmFragmentInstance.generate(asm);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import dk.camelot64.kickc.asm.AsmProgram;
|
||||
import dk.camelot64.kickc.asm.AsmSegment;
|
||||
import dk.camelot64.kickc.fragment.AsmFragmentInstance;
|
||||
import dk.camelot64.kickc.fragment.AsmFragmentInstanceSpec;
|
||||
import dk.camelot64.kickc.fragment.AsmFragmentTemplateManager;
|
||||
import dk.camelot64.kickc.fragment.AsmFragmentTemplateSynthesizer;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
|
||||
import java.util.*;
|
||||
@ -28,7 +28,7 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
||||
*/
|
||||
static void chooseBestUpliftCombination(
|
||||
RegisterCombinationIterator combinationIterator, int maxCombinations,
|
||||
Set<AsmFragmentInstanceSpec> unknownFragments,
|
||||
Set<String> unknownFragments,
|
||||
ScopeRef scope,
|
||||
Program program
|
||||
) {
|
||||
@ -86,7 +86,7 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
||||
public static boolean generateCombinationAsm(
|
||||
RegisterCombination combination,
|
||||
Program program,
|
||||
Set<AsmFragmentInstanceSpec> unknownFragments,
|
||||
Set<String> unknownFragments,
|
||||
ScopeRef scope) {
|
||||
// Reset register allocation to original zero page allocation
|
||||
new Pass4RegistersFinalize(program).allocate(false);
|
||||
@ -107,8 +107,8 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
||||
// Generate ASM
|
||||
try {
|
||||
new Pass4CodeGeneration(program, false).generate();
|
||||
} catch(AsmFragmentTemplateManager.UnknownFragmentException e) {
|
||||
unknownFragments.add(e.getFragmentInstanceSpec());
|
||||
} catch(AsmFragmentTemplateSynthesizer.UnknownFragmentException e) {
|
||||
unknownFragments.add(e.getFragmentSignature());
|
||||
if(program.getLog().isVerboseUplift()) {
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Uplift attempt [" + (scope == null ? "" : scope) + "] ");
|
||||
@ -235,7 +235,7 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
||||
|
||||
public void performUplift(int maxCombinations) {
|
||||
// Test uplift combinations to find the best one.
|
||||
Set<AsmFragmentInstanceSpec> unknownFragments = new LinkedHashSet<>();
|
||||
Set<String> unknownFragments = new LinkedHashSet<>();
|
||||
List<RegisterUpliftScope> registerUpliftScopes = getProgram().getRegisterUpliftProgram().getRegisterUpliftScopes();
|
||||
for(RegisterUpliftScope upliftScope : registerUpliftScopes) {
|
||||
RegisterCombinationIterator combinationIterator = upliftScope.getCombinationIterator(getProgram().getRegisterPotentials());
|
||||
@ -249,8 +249,8 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
||||
|
||||
if(unknownFragments.size() > 0) {
|
||||
getLog().append("MISSING FRAGMENTS");
|
||||
for(AsmFragmentInstanceSpec unknownFragment : unknownFragments) {
|
||||
getLog().append(" " + unknownFragment.toString());
|
||||
for(String unknownFragment : unknownFragments) {
|
||||
getLog().append(" " + unknownFragment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package dk.camelot64.kickc.passes;
|
||||
import dk.camelot64.kickc.asm.AsmClobber;
|
||||
import dk.camelot64.kickc.asm.AsmProgram;
|
||||
import dk.camelot64.kickc.fragment.AsmFragmentInstance;
|
||||
import dk.camelot64.kickc.fragment.AsmFragmentTemplateManager;
|
||||
import dk.camelot64.kickc.fragment.AsmFragmentTemplateSynthesizer;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
|
||||
import java.util.*;
|
||||
@ -196,8 +196,8 @@ public class Pass4RegisterUpliftPotentialRegisterAnalysis extends Pass2Base {
|
||||
Pass4CodeGeneration.AsmCodegenAluState aluState = new Pass4CodeGeneration.AsmCodegenAluState();
|
||||
try {
|
||||
(new Pass4CodeGeneration(getProgram(), false)).generateStatementAsm(asm, block, statement, aluState, false);
|
||||
} catch(AsmFragmentTemplateManager.UnknownFragmentException e) {
|
||||
unknownFragments.add(e.getFragmentDescription());
|
||||
} catch(AsmFragmentTemplateSynthesizer.UnknownFragmentException e) {
|
||||
unknownFragments.add(e.getFragmentSignature());
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Potential register analysis " + statement);
|
||||
msg.append(" missing fragment " + e.getFragmentSignature());
|
||||
|
@ -1,6 +1,5 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.fragment.AsmFragmentInstanceSpec;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
|
||||
import java.util.*;
|
||||
@ -24,7 +23,7 @@ public class Pass4RegisterUpliftRemains extends Pass2Base {
|
||||
}
|
||||
});
|
||||
|
||||
Set<AsmFragmentInstanceSpec> unknownFragments = new LinkedHashSet<>();
|
||||
Set<String> unknownFragments = new LinkedHashSet<>();
|
||||
|
||||
for(LiveRangeEquivalenceClass equivalenceClass : equivalenceClasses) {
|
||||
if(equivalenceClass.getRegister().getType().equals(Registers.RegisterType.ZP_BYTE)) {
|
||||
@ -38,8 +37,8 @@ public class Pass4RegisterUpliftRemains extends Pass2Base {
|
||||
|
||||
if(unknownFragments.size() > 0) {
|
||||
getLog().append("MISSING FRAGMENTS");
|
||||
for(AsmFragmentInstanceSpec unknownFragment : unknownFragments) {
|
||||
getLog().append(" " + unknownFragment.toString());
|
||||
for(String unknownFragment : unknownFragments) {
|
||||
getLog().append(" " + unknownFragment);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ public class TestPrograms {
|
||||
public static void tearDown() throws Exception {
|
||||
CompileLog log = new CompileLog();
|
||||
log.setSysOut(true);
|
||||
AsmFragmentTemplateUsages.logUsages(log, false, false, false, false);
|
||||
AsmFragmentTemplateUsages.logUsages(log, false, false, false, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
Reference in New Issue
Block a user