mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-10-11 12:23:45 +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
|
* Should the log be output to System.out while being built
|
||||||
*/
|
*/
|
||||||
private boolean sysOut = false;
|
private boolean sysOut = true;
|
||||||
|
|
||||||
public CompileLog() {
|
public CompileLog() {
|
||||||
this.log = new StringBuilder();
|
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;
|
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.KickCLexer;
|
||||||
import dk.camelot64.kickc.parser.KickCParser;
|
import dk.camelot64.kickc.parser.KickCParser;
|
||||||
import org.antlr.v4.runtime.*;
|
import org.antlr.v4.runtime.*;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An ASM fragment template usable for generating KickAssembler code for different bindings.
|
* 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.
|
* The AsmFragmentTemplateSynthesizer can generate multiple different templates usable for a specific fragment signature.
|
||||||
@ -16,14 +21,18 @@ public class AsmFragmentTemplate {
|
|||||||
private String signature;
|
private String signature;
|
||||||
/** The fragment template body */
|
/** The fragment template body */
|
||||||
private String 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. */
|
/** The synthesis that created the fragment. null if the fragment template was loaded. */
|
||||||
private AsmFragmentTemplateSynthesisRule synthesis;
|
private AsmFragmentTemplateSynthesisRule synthesis;
|
||||||
|
|
||||||
/** The sub fragment template that the synthesis modified to create this. null if the fragment template was loaded. */
|
/** The sub fragment template that the synthesis modified to create this. null if the fragment template was loaded. */
|
||||||
private AsmFragmentTemplate subFragment;
|
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) {
|
public AsmFragmentTemplate(String signature, String body) {
|
||||||
this.signature = signature;
|
this.signature = signature;
|
||||||
this.body = body;
|
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
|
* @return The parsed fragment ready for generating
|
||||||
*/
|
*/
|
||||||
private static KickCParser.AsmLinesContext parseBody(String fragmentBody, final String fragmentFileName) {
|
private void initAsm() {
|
||||||
CodePointCharStream fragmentCharStream = CharStreams.fromString(fragmentBody);
|
// Parse the body ASM
|
||||||
|
CodePointCharStream fragmentCharStream = CharStreams.fromString(body);
|
||||||
KickCLexer kickCLexer = new KickCLexer(fragmentCharStream);
|
KickCLexer kickCLexer = new KickCLexer(fragmentCharStream);
|
||||||
KickCParser kickCParser = new KickCParser(new CommonTokenStream(kickCLexer));
|
KickCParser kickCParser = new KickCParser(new CommonTokenStream(kickCLexer));
|
||||||
kickCParser.addErrorListener(new BaseErrorListener() {
|
kickCParser.addErrorListener(new BaseErrorListener() {
|
||||||
@Override
|
@Override
|
||||||
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
|
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.setBuildParseTree(true);
|
||||||
KickCParser.AsmFileContext asmFile = kickCParser.asmFile();
|
this.bodyAsm = kickCParser.asmFile().asmLines();
|
||||||
return 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() {
|
public String getSignature() {
|
||||||
@ -80,11 +114,25 @@ public class AsmFragmentTemplate {
|
|||||||
|
|
||||||
public KickCParser.AsmLinesContext getBodyAsm() {
|
public KickCParser.AsmLinesContext getBodyAsm() {
|
||||||
if(bodyAsm == null) {
|
if(bodyAsm == null) {
|
||||||
bodyAsm = parseBody(body, signature);
|
initAsm();
|
||||||
}
|
}
|
||||||
return bodyAsm;
|
return bodyAsm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AsmFragmentClobber getClobber() {
|
||||||
|
if(clobber == null) {
|
||||||
|
initAsm();
|
||||||
|
}
|
||||||
|
return clobber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getCycles() {
|
||||||
|
if(cycles == null) {
|
||||||
|
initAsm();
|
||||||
|
}
|
||||||
|
return cycles;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isFile() {
|
public boolean isFile() {
|
||||||
return file;
|
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;
|
package dk.camelot64.kickc.fragment;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import dk.camelot64.kickc.CompileLog;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
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 */
|
/** AsmFragment synthesis mechanism based on matching fragment signature and reusing another fragment with added prefix/postfix and some bind-mappings */
|
||||||
class AsmFragmentTemplateSynthesisRule {
|
class AsmFragmentTemplateSynthesisRule {
|
||||||
|
|
||||||
private String sigMatch;
|
final private String sigMatch;
|
||||||
private String sigAvoid;
|
final private String sigAvoid;
|
||||||
private String asmPrefix;
|
final private String asmPrefix;
|
||||||
private String sigReplace;
|
final private String sigReplace;
|
||||||
private String asmPostfix;
|
final private String asmPostfix;
|
||||||
private Map<String, String> bindMappings;
|
final private Map<String, String> bindMappings;
|
||||||
private boolean mapSignature;
|
final private boolean mapSignature;
|
||||||
private String subSignature;
|
|
||||||
|
|
||||||
AsmFragmentTemplateSynthesisRule(String sigMatch, String sigAvoid, String asmPrefix, String sigReplace, String asmPostfix, Map<String, String> bindMappings, boolean mapSignature) {
|
AsmFragmentTemplateSynthesisRule(String sigMatch, String sigAvoid, String asmPrefix, String sigReplace, String asmPostfix, Map<String, String> bindMappings, boolean mapSignature) {
|
||||||
this.sigMatch = sigMatch;
|
this.sigMatch = sigMatch;
|
||||||
@ -29,75 +27,417 @@ class AsmFragmentTemplateSynthesisRule {
|
|||||||
this.mapSignature = mapSignature;
|
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);
|
this(sigMatch, sigAvoid, asmPrefix, sigReplace, asmPostfix, bindMappings, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 = subTemplate.getBody();
|
||||||
|
if(bindMappings != null) {
|
||||||
|
if(mapSignature) {
|
||||||
|
// When mapping the signature we do the reverse replacement in the ASM
|
||||||
|
List<String> reverse = new ArrayList<>(bindMappings.keySet());
|
||||||
|
Collections.reverse(reverse);
|
||||||
|
for(String bound : reverse) {
|
||||||
|
subFragment = subFragment.replace("{" + bindMappings.get(bound) + "}", "{" + bound + "}");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// When not mapping the signature we do the replacement directly in the ASM
|
||||||
|
for(String bound : bindMappings.keySet()) {
|
||||||
|
subFragment = subFragment.replace("{" + bound + "}", "{" + bindMappings.get(bound) + "}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newFragment.append(subFragment);
|
||||||
|
if(asmPostfix != null) {
|
||||||
|
newFragment.append("\n");
|
||||||
|
newFragment.append(asmPostfix);
|
||||||
|
}
|
||||||
|
return new AsmFragmentTemplate(signature, newFragment.toString(), this, subTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
static String regexpRewriteSignature(String signature, String match, String replace) {
|
static String regexpRewriteSignature(String signature, String match, String replace) {
|
||||||
Pattern p = Pattern.compile(match);
|
Pattern p = Pattern.compile(match);
|
||||||
Matcher m = p.matcher(signature);
|
Matcher m = p.matcher(signature);
|
||||||
String output = signature;
|
String output = signature;
|
||||||
if(m.find()) {
|
if(m.find()) {
|
||||||
// getReplacement first number with "number" and second number with the first
|
|
||||||
output = m.replaceAll(replace);
|
output = m.replaceAll(replace);
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
@Override
|
||||||
return sigMatch + (sigAvoid == null ? "" : ("/" + sigAvoid));
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<AsmFragmentTemplate> synthesize(String signature, AsmFragmentTemplateManager.AsmSynthesisPath path, AsmFragmentTemplateManager.AsmFragmentTemplateSynthesizer synthesizer) {
|
@Override
|
||||||
ArrayList<AsmFragmentTemplate> candidates = new ArrayList<>();
|
public int hashCode() {
|
||||||
if(signature.matches(sigMatch)) {
|
int result = sigMatch != null ? sigMatch.hashCode() : 0;
|
||||||
if(sigAvoid == null || !signature.matches(sigAvoid)) {
|
result = 31 * result + (sigAvoid != null ? sigAvoid.hashCode() : 0);
|
||||||
subSignature = regexpRewriteSignature(signature, sigMatch, sigReplace);
|
result = 31 * result + (asmPrefix != null ? asmPrefix.hashCode() : 0);
|
||||||
if(mapSignature && bindMappings != null) {
|
result = 31 * result + (sigReplace != null ? sigReplace.hashCode() : 0);
|
||||||
// When mapping the signature we do the map replacement in the signature
|
result = 31 * result + (asmPostfix != null ? asmPostfix.hashCode() : 0);
|
||||||
for(String bound : bindMappings.keySet()) {
|
result = 31 * result + (bindMappings != null ? bindMappings.hashCode() : 0);
|
||||||
subSignature = subSignature.replace(bound, bindMappings.get(bound));
|
result = 31 * result + (mapSignature ? 1 : 0);
|
||||||
}
|
return result;
|
||||||
}
|
}
|
||||||
List<AsmFragmentTemplate> subFragmentTemplates = synthesizer.loadOrSynthesizeFragment(subSignature, path);
|
|
||||||
for(AsmFragmentTemplate subFragmentTemplate : subFragmentTemplates) {
|
/** All the synthesize rules available. */
|
||||||
if(subFragmentTemplate != null) {
|
private static List<AsmFragmentTemplateSynthesisRule> fragmentSyntheses;
|
||||||
StringBuilder newFragment = new StringBuilder();
|
|
||||||
if(asmPrefix != null) {
|
static List<AsmFragmentTemplateSynthesisRule> getSynthesisRules() {
|
||||||
newFragment.append(asmPrefix).append("\n");
|
if(fragmentSyntheses == null) {
|
||||||
}
|
fragmentSyntheses = initFragmentSyntheses();
|
||||||
String subFragment = subFragmentTemplate.getBody();
|
|
||||||
if(bindMappings != null) {
|
|
||||||
if(mapSignature) {
|
|
||||||
// When mapping the signature we do the reverse replacement in the ASM
|
|
||||||
List<String> reverse = new ArrayList<>(bindMappings.keySet());
|
|
||||||
Collections.reverse(reverse);
|
|
||||||
for(String bound : reverse) {
|
|
||||||
subFragment = subFragment.replace("{" + bindMappings.get(bound) + "}", "{" + bound + "}");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// When not mapping the signature we do the replacement directly in the ASM
|
|
||||||
for(String bound : bindMappings.keySet()) {
|
|
||||||
subFragment = subFragment.replace("{" + bound + "}", "{" + bindMappings.get(bound) + "}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newFragment.append(subFragment);
|
|
||||||
if(asmPostfix != null) {
|
|
||||||
newFragment.append("\n");
|
|
||||||
newFragment.append(asmPostfix);
|
|
||||||
}
|
|
||||||
candidates.add(new AsmFragmentTemplate(signature, newFragment.toString(), this, subFragmentTemplate));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return candidates;
|
return fragmentSyntheses;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSubSignature() {
|
private static List<AsmFragmentTemplateSynthesisRule> initFragmentSyntheses() {
|
||||||
return subSignature;
|
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) {
|
public static void logUsages(CompileLog log, boolean logRedundantFiles, boolean logUnusedFiles, boolean logFileDetails, boolean logAllDetails) {
|
||||||
|
|
||||||
Map<String, List<AsmFragmentTemplate>> fragmentTemplateCache = AsmFragmentTemplateManager.getFragmentTemplateCache();
|
Map<String, AsmFragmentTemplateSynthesizer.AsmFragmentSynthesis> synthesisGraph =
|
||||||
ArrayList<String> signatures = new ArrayList<>(fragmentTemplateCache.keySet());
|
AsmFragmentTemplateSynthesizer.SYNTHESIZER.getSynthesisGraph();
|
||||||
|
ArrayList<String> signatures = new ArrayList<>(synthesisGraph.keySet());
|
||||||
Collections.sort(signatures);
|
Collections.sort(signatures);
|
||||||
File[] files = AsmFragmentTemplateManager.allFragmentFiles();
|
File[] files = AsmFragmentTemplateSynthesizer.SYNTHESIZER.allFragmentFiles();
|
||||||
|
|
||||||
if(logRedundantFiles) {
|
if(logRedundantFiles) {
|
||||||
|
/*
|
||||||
// Find all file fragments that were bested by a synthesized fragment
|
// Find all file fragments that were bested by a synthesized fragment
|
||||||
log.append("\nREDUNDANT ASM FRAGMENT FILE ANALYSIS (if found remove them from disk)");
|
log.append("\nREDUNDANT ASM FRAGMENT FILE ANALYSIS (if found remove them from disk)");
|
||||||
for(String signature : signatures) {
|
for(String signature : signatures) {
|
||||||
@ -65,34 +67,26 @@ public class AsmFragmentTemplateUsages {
|
|||||||
log.append("rm " + fileTemplate.getName() + ".asm #synthesized by " + maxTemplate.getName() + " - usages: " + maxUsage);
|
log.append("rm " + fileTemplate.getName() + ".asm #synthesized by " + maxTemplate.getName() + " - usages: " + maxUsage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
Set<String> redundantSignatures = new LinkedHashSet<>();
|
Set<String> redundantSignatures = new LinkedHashSet<>();
|
||||||
for(File file : files) {
|
for(File file : files) {
|
||||||
String fileName = file.getName();
|
String fileName = file.getName();
|
||||||
String signature = fileName.substring(0, fileName.length() - 4);
|
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
|
// Synthesize the fragment - and check if the synthesis is as good as the file body
|
||||||
AsmFragmentTemplateManager.AsmFragmentTemplateSynthesizer synthesizer = new AsmFragmentTemplateManager.AsmFragmentTemplateSynthesizer(signature, log);
|
AsmFragmentTemplate template =
|
||||||
List<AsmFragmentTemplate> templates = synthesizer.loadOrSynthesizeFragment(signature, new AsmFragmentTemplateManager.AsmSynthesisPath());
|
AsmFragmentTemplateSynthesizer.SYNTHESIZER.getFragmentTemplate(signature, log);
|
||||||
AsmFragmentTemplate fileTemplate = null;
|
if(!template.isFile()) {
|
||||||
for(AsmFragmentTemplate template : templates) {
|
// Check if the synthesis uses a file marked as redundant
|
||||||
if(template.isFile()) {
|
AsmFragmentTemplate sourceFileTemplate = template;
|
||||||
fileTemplate = template;
|
while(!sourceFileTemplate.isFile()) {
|
||||||
|
sourceFileTemplate = sourceFileTemplate.getSubFragment();
|
||||||
}
|
}
|
||||||
}
|
if(redundantSignatures.contains(sourceFileTemplate.getSignature())) {
|
||||||
for(AsmFragmentTemplate template : templates) {
|
throw new RuntimeException("Problem in redundancy analysis! " + sourceFileTemplate.getSignature() + ".asm seems redundant but is needed for synthesis of " + signature);
|
||||||
if(!template.isFile() && template.getBody().equals(fileTemplate.getBody())) {
|
|
||||||
// Check if the synthesis uses a file marked as redundant
|
|
||||||
AsmFragmentTemplate sourceFileTemplate = template;
|
|
||||||
while(!sourceFileTemplate.isFile()) {
|
|
||||||
sourceFileTemplate = sourceFileTemplate.getSubFragment();
|
|
||||||
}
|
|
||||||
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());
|
|
||||||
redundantSignatures.add(signature);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
log.append("rm " + template.getName() + ".asm #synthesized better ASM by " + template.getName());
|
||||||
|
redundantSignatures.add(signature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,7 +96,8 @@ public class AsmFragmentTemplateUsages {
|
|||||||
for(File file : files) {
|
for(File file : files) {
|
||||||
String fileName = file.getName();
|
String fileName = file.getName();
|
||||||
String signature = fileName.substring(0, fileName.length() - 4);
|
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) {
|
if(templates != null && templates.size() > 0) {
|
||||||
// The template has been loaded / synthesized - is the usage count zero?
|
// The template has been loaded / synthesized - is the usage count zero?
|
||||||
boolean allZero = true;
|
boolean allZero = true;
|
||||||
@ -135,7 +130,7 @@ public class AsmFragmentTemplateUsages {
|
|||||||
// Find all file templates
|
// Find all file templates
|
||||||
List<AsmFragmentTemplate> fileTemplates = new ArrayList<>();
|
List<AsmFragmentTemplate> fileTemplates = new ArrayList<>();
|
||||||
for(String signature : signatures) {
|
for(String signature : signatures) {
|
||||||
List<AsmFragmentTemplate> templates = fragmentTemplateCache.get(signature);
|
Collection<AsmFragmentTemplate> templates = synthesisGraph.get(signature).getBestTemplates();
|
||||||
for(AsmFragmentTemplate template : templates) {
|
for(AsmFragmentTemplate template : templates) {
|
||||||
if(template.isFile()) {
|
if(template.isFile()) {
|
||||||
fileTemplates.add(template);
|
fileTemplates.add(template);
|
||||||
@ -150,10 +145,8 @@ public class AsmFragmentTemplateUsages {
|
|||||||
log.append("\nDETAILED ASM FRAGMENT USAGES");
|
log.append("\nDETAILED ASM FRAGMENT USAGES");
|
||||||
List<AsmFragmentTemplate> allTemplates = new ArrayList<>();
|
List<AsmFragmentTemplate> allTemplates = new ArrayList<>();
|
||||||
for(String signature : signatures) {
|
for(String signature : signatures) {
|
||||||
List<AsmFragmentTemplate> templates = fragmentTemplateCache.get(signature);
|
Collection<AsmFragmentTemplate> templates = synthesisGraph.get(signature).getBestTemplates();
|
||||||
for(AsmFragmentTemplate template : templates) {
|
allTemplates.addAll(templates);
|
||||||
allTemplates.add(template);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
logTemplatesByUsage(log, allTemplates);
|
logTemplatesByUsage(log, allTemplates);
|
||||||
}
|
}
|
||||||
|
@ -221,7 +221,7 @@ public class Pass4CodeGeneration {
|
|||||||
}
|
}
|
||||||
StatementAssignment assignment = (StatementAssignment) statement;
|
StatementAssignment assignment = (StatementAssignment) statement;
|
||||||
AsmFragmentInstanceSpec asmFragmentInstanceSpec = new AsmFragmentInstanceSpec(assignment, assignmentAlu, program);
|
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());
|
asm.getCurrentSegment().setFragment(asmFragmentInstance.getFragmentName());
|
||||||
asmFragmentInstance.generate(asm);
|
asmFragmentInstance.generate(asm);
|
||||||
aluState.clear();
|
aluState.clear();
|
||||||
@ -248,14 +248,14 @@ public class Pass4CodeGeneration {
|
|||||||
asm.addComment(lValue.toString(program) + " = " + assignment.getrValue2().toString(program) + " // register copy " + getRegister(lValue));
|
asm.addComment(lValue.toString(program) + " = " + assignment.getrValue2().toString(program) + " // register copy " + getRegister(lValue));
|
||||||
} else {
|
} else {
|
||||||
AsmFragmentInstanceSpec asmFragmentInstanceSpec = new AsmFragmentInstanceSpec(assignment, program);
|
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());
|
asm.getCurrentSegment().setFragment(asmFragmentInstance.getFragmentName());
|
||||||
asmFragmentInstance.generate(asm);
|
asmFragmentInstance.generate(asm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(statement instanceof StatementConditionalJump) {
|
} else if(statement instanceof StatementConditionalJump) {
|
||||||
AsmFragmentInstanceSpec asmFragmentInstanceSpec = new AsmFragmentInstanceSpec((StatementConditionalJump) statement, block, program, getGraph());
|
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());
|
asm.getCurrentSegment().setFragment(asmFragmentInstance.getFragmentName());
|
||||||
asmFragmentInstance.generate(asm);
|
asmFragmentInstance.generate(asm);
|
||||||
} else if(statement instanceof StatementCall) {
|
} else if(statement instanceof StatementCall) {
|
||||||
@ -341,7 +341,7 @@ public class Pass4CodeGeneration {
|
|||||||
asm.getCurrentSegment().setFragment("register_copy");
|
asm.getCurrentSegment().setFragment("register_copy");
|
||||||
} else {
|
} else {
|
||||||
AsmFragmentInstanceSpec asmFragmentInstanceSpec = new AsmFragmentInstanceSpec(lValue, rValue, program, scope);
|
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());
|
asm.getCurrentSegment().setFragment(asmFragmentInstance.getFragmentName());
|
||||||
asmFragmentInstance.generate(asm);
|
asmFragmentInstance.generate(asm);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import dk.camelot64.kickc.asm.AsmProgram;
|
|||||||
import dk.camelot64.kickc.asm.AsmSegment;
|
import dk.camelot64.kickc.asm.AsmSegment;
|
||||||
import dk.camelot64.kickc.fragment.AsmFragmentInstance;
|
import dk.camelot64.kickc.fragment.AsmFragmentInstance;
|
||||||
import dk.camelot64.kickc.fragment.AsmFragmentInstanceSpec;
|
import dk.camelot64.kickc.fragment.AsmFragmentInstanceSpec;
|
||||||
import dk.camelot64.kickc.fragment.AsmFragmentTemplateManager;
|
import dk.camelot64.kickc.fragment.AsmFragmentTemplateSynthesizer;
|
||||||
import dk.camelot64.kickc.model.*;
|
import dk.camelot64.kickc.model.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -28,7 +28,7 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
|||||||
*/
|
*/
|
||||||
static void chooseBestUpliftCombination(
|
static void chooseBestUpliftCombination(
|
||||||
RegisterCombinationIterator combinationIterator, int maxCombinations,
|
RegisterCombinationIterator combinationIterator, int maxCombinations,
|
||||||
Set<AsmFragmentInstanceSpec> unknownFragments,
|
Set<String> unknownFragments,
|
||||||
ScopeRef scope,
|
ScopeRef scope,
|
||||||
Program program
|
Program program
|
||||||
) {
|
) {
|
||||||
@ -86,7 +86,7 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
|||||||
public static boolean generateCombinationAsm(
|
public static boolean generateCombinationAsm(
|
||||||
RegisterCombination combination,
|
RegisterCombination combination,
|
||||||
Program program,
|
Program program,
|
||||||
Set<AsmFragmentInstanceSpec> unknownFragments,
|
Set<String> unknownFragments,
|
||||||
ScopeRef scope) {
|
ScopeRef scope) {
|
||||||
// Reset register allocation to original zero page allocation
|
// Reset register allocation to original zero page allocation
|
||||||
new Pass4RegistersFinalize(program).allocate(false);
|
new Pass4RegistersFinalize(program).allocate(false);
|
||||||
@ -107,8 +107,8 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
|||||||
// Generate ASM
|
// Generate ASM
|
||||||
try {
|
try {
|
||||||
new Pass4CodeGeneration(program, false).generate();
|
new Pass4CodeGeneration(program, false).generate();
|
||||||
} catch(AsmFragmentTemplateManager.UnknownFragmentException e) {
|
} catch(AsmFragmentTemplateSynthesizer.UnknownFragmentException e) {
|
||||||
unknownFragments.add(e.getFragmentInstanceSpec());
|
unknownFragments.add(e.getFragmentSignature());
|
||||||
if(program.getLog().isVerboseUplift()) {
|
if(program.getLog().isVerboseUplift()) {
|
||||||
StringBuilder msg = new StringBuilder();
|
StringBuilder msg = new StringBuilder();
|
||||||
msg.append("Uplift attempt [" + (scope == null ? "" : scope) + "] ");
|
msg.append("Uplift attempt [" + (scope == null ? "" : scope) + "] ");
|
||||||
@ -235,7 +235,7 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
|||||||
|
|
||||||
public void performUplift(int maxCombinations) {
|
public void performUplift(int maxCombinations) {
|
||||||
// Test uplift combinations to find the best one.
|
// Test uplift combinations to find the best one.
|
||||||
Set<AsmFragmentInstanceSpec> unknownFragments = new LinkedHashSet<>();
|
Set<String> unknownFragments = new LinkedHashSet<>();
|
||||||
List<RegisterUpliftScope> registerUpliftScopes = getProgram().getRegisterUpliftProgram().getRegisterUpliftScopes();
|
List<RegisterUpliftScope> registerUpliftScopes = getProgram().getRegisterUpliftProgram().getRegisterUpliftScopes();
|
||||||
for(RegisterUpliftScope upliftScope : registerUpliftScopes) {
|
for(RegisterUpliftScope upliftScope : registerUpliftScopes) {
|
||||||
RegisterCombinationIterator combinationIterator = upliftScope.getCombinationIterator(getProgram().getRegisterPotentials());
|
RegisterCombinationIterator combinationIterator = upliftScope.getCombinationIterator(getProgram().getRegisterPotentials());
|
||||||
@ -249,8 +249,8 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
|
|||||||
|
|
||||||
if(unknownFragments.size() > 0) {
|
if(unknownFragments.size() > 0) {
|
||||||
getLog().append("MISSING FRAGMENTS");
|
getLog().append("MISSING FRAGMENTS");
|
||||||
for(AsmFragmentInstanceSpec unknownFragment : unknownFragments) {
|
for(String unknownFragment : unknownFragments) {
|
||||||
getLog().append(" " + unknownFragment.toString());
|
getLog().append(" " + unknownFragment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package dk.camelot64.kickc.passes;
|
|||||||
import dk.camelot64.kickc.asm.AsmClobber;
|
import dk.camelot64.kickc.asm.AsmClobber;
|
||||||
import dk.camelot64.kickc.asm.AsmProgram;
|
import dk.camelot64.kickc.asm.AsmProgram;
|
||||||
import dk.camelot64.kickc.fragment.AsmFragmentInstance;
|
import dk.camelot64.kickc.fragment.AsmFragmentInstance;
|
||||||
import dk.camelot64.kickc.fragment.AsmFragmentTemplateManager;
|
import dk.camelot64.kickc.fragment.AsmFragmentTemplateSynthesizer;
|
||||||
import dk.camelot64.kickc.model.*;
|
import dk.camelot64.kickc.model.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -196,8 +196,8 @@ public class Pass4RegisterUpliftPotentialRegisterAnalysis extends Pass2Base {
|
|||||||
Pass4CodeGeneration.AsmCodegenAluState aluState = new Pass4CodeGeneration.AsmCodegenAluState();
|
Pass4CodeGeneration.AsmCodegenAluState aluState = new Pass4CodeGeneration.AsmCodegenAluState();
|
||||||
try {
|
try {
|
||||||
(new Pass4CodeGeneration(getProgram(), false)).generateStatementAsm(asm, block, statement, aluState, false);
|
(new Pass4CodeGeneration(getProgram(), false)).generateStatementAsm(asm, block, statement, aluState, false);
|
||||||
} catch(AsmFragmentTemplateManager.UnknownFragmentException e) {
|
} catch(AsmFragmentTemplateSynthesizer.UnknownFragmentException e) {
|
||||||
unknownFragments.add(e.getFragmentDescription());
|
unknownFragments.add(e.getFragmentSignature());
|
||||||
StringBuilder msg = new StringBuilder();
|
StringBuilder msg = new StringBuilder();
|
||||||
msg.append("Potential register analysis " + statement);
|
msg.append("Potential register analysis " + statement);
|
||||||
msg.append(" missing fragment " + e.getFragmentSignature());
|
msg.append(" missing fragment " + e.getFragmentSignature());
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package dk.camelot64.kickc.passes;
|
package dk.camelot64.kickc.passes;
|
||||||
|
|
||||||
import dk.camelot64.kickc.fragment.AsmFragmentInstanceSpec;
|
|
||||||
import dk.camelot64.kickc.model.*;
|
import dk.camelot64.kickc.model.*;
|
||||||
|
|
||||||
import java.util.*;
|
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) {
|
for(LiveRangeEquivalenceClass equivalenceClass : equivalenceClasses) {
|
||||||
if(equivalenceClass.getRegister().getType().equals(Registers.RegisterType.ZP_BYTE)) {
|
if(equivalenceClass.getRegister().getType().equals(Registers.RegisterType.ZP_BYTE)) {
|
||||||
@ -38,8 +37,8 @@ public class Pass4RegisterUpliftRemains extends Pass2Base {
|
|||||||
|
|
||||||
if(unknownFragments.size() > 0) {
|
if(unknownFragments.size() > 0) {
|
||||||
getLog().append("MISSING FRAGMENTS");
|
getLog().append("MISSING FRAGMENTS");
|
||||||
for(AsmFragmentInstanceSpec unknownFragment : unknownFragments) {
|
for(String unknownFragment : unknownFragments) {
|
||||||
getLog().append(" " + unknownFragment.toString());
|
getLog().append(" " + unknownFragment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ public class TestPrograms {
|
|||||||
public static void tearDown() throws Exception {
|
public static void tearDown() throws Exception {
|
||||||
CompileLog log = new CompileLog();
|
CompileLog log = new CompileLog();
|
||||||
log.setSysOut(true);
|
log.setSysOut(true);
|
||||||
AsmFragmentTemplateUsages.logUsages(log, false, false, false, false);
|
AsmFragmentTemplateUsages.logUsages(log, false, false, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
Reference in New Issue
Block a user