1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-01-12 11:31:11 +00:00

#742 Working on typed ASM fragment signature in synthesis.

This commit is contained in:
jespergravgaard 2021-12-30 13:01:32 +01:00
parent 9652931592
commit 7c77be79bd
16 changed files with 227 additions and 145 deletions

View File

@ -2,6 +2,7 @@ package dk.camelot64.kickc;
import dk.camelot64.kickc.asm.AsmProgram;
import dk.camelot64.kickc.fragment.AsmFragmentTemplateUsages;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentSynthesisResult;
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentTemplateMasterSynthesizer;
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentTemplateSynthesizer;
@ -275,7 +276,8 @@ public class KickC implements Callable<Integer> {
try {
final AsmFragmentTemplateMasterSynthesizer masterSynthesizer = compiler.getAsmFragmentMasterSynthesizer();
final AsmFragmentTemplateSynthesizer cpuSynthesizer = masterSynthesizer.getSynthesizer(program.getTargetCpu());
Collection<AsmFragmentSynthesisResult> fragmentTemplates = cpuSynthesizer.getBestTemplates(fragment, compiler.getLog());
final AsmFragmentSignature signature = AsmFragmentSignature.parse(fragment);
Collection<AsmFragmentSynthesisResult> fragmentTemplates = cpuSynthesizer.getBestTemplates(signature, compiler.getLog());
for(AsmFragmentSynthesisResult fragmentTemplate : fragmentTemplates) {
AsmFragmentTemplateUsages.logTemplate(compiler.getLog(), fragmentTemplate, "");
}

View File

@ -1,6 +1,7 @@
package dk.camelot64.kickc.fragment;
import dk.camelot64.kickc.asm.AsmProgram;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentTemplateSynthesizer;
import dk.camelot64.kickc.model.Program;
@ -15,7 +16,7 @@ public class AsmFragmentCodeGenerator {
*/
public static void generateAsm(AsmProgram asm, AsmFragmentInstanceSpec fragmentInstanceSpec, Program program) {
AsmEncodingHelper.ensureEncoding(asm, fragmentInstanceSpec);
String initialSignature = fragmentInstanceSpec.getSignature();
AsmFragmentSignature initialSignature = fragmentInstanceSpec.getSignature();
AsmFragmentInstance fragmentInstance = null;
StringBuilder fragmentVariationsTried = new StringBuilder();
while(fragmentInstance == null) {
@ -24,7 +25,7 @@ public class AsmFragmentCodeGenerator {
fragmentInstance = cpuSynthesizer.getFragmentInstance(fragmentInstanceSpec, program.getLog());
} catch(AsmFragmentTemplateSynthesizer.UnknownFragmentException e) {
// Unknown fragment - keep looking through alternative ASM fragment instance specs until we have tried them all
String signature = fragmentInstanceSpec.getSignature();
AsmFragmentSignature signature = fragmentInstanceSpec.getSignature();
fragmentVariationsTried.append(signature).append(" ");
if(fragmentInstanceSpec.hasNextVariation()) {
fragmentInstanceSpec.nextVariation();
@ -37,7 +38,7 @@ public class AsmFragmentCodeGenerator {
}
}
}
asm.getCurrentChunk().setFragment(fragmentInstance.getFragmentName());
asm.getCurrentChunk().setFragment(fragmentInstance.getFragmentSignature().getName());
fragmentInstance.generate(asm);
}

View File

@ -4,6 +4,7 @@ import dk.camelot64.cpufamily6502.CpuAddressingMode;
import dk.camelot64.cpufamily6502.CpuOpcode;
import dk.camelot64.kickc.NumberParser;
import dk.camelot64.kickc.asm.*;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.symbols.Label;
@ -25,7 +26,7 @@ public class AsmFragmentInstance {
private final Program program;
/** The name of the fragment used in error messages. */
private final String name;
private final AsmFragmentSignature signature;
/** The fragment template for the ASM code. */
private final AsmFragmentTemplate fragmentTemplate;
@ -38,12 +39,12 @@ public class AsmFragmentInstance {
public AsmFragmentInstance(
Program program,
String name,
AsmFragmentSignature signature,
ScopeRef codeScopeRef,
AsmFragmentTemplate fragmentTemplate,
Map<String, Value> bindings) {
this.program = program;
this.name = name;
this.signature = signature;
this.fragmentTemplate = fragmentTemplate;
this.bindings = bindings;
this.codeScopeRef = codeScopeRef;
@ -75,7 +76,7 @@ public class AsmFragmentInstance {
}
if(boundValue == null) {
throw new RuntimeException("Binding '" + name + "' not found in fragment " + this.name);
throw new RuntimeException("Binding '" + name + "' not found in fragment " + this.signature);
}
if(boundValue instanceof Variable && ((Variable) boundValue).isVariable()) {
Variable boundVar = (Variable) boundValue;
@ -151,8 +152,8 @@ public class AsmFragmentInstance {
return false;
}
public String getFragmentName() {
return name;
public AsmFragmentSignature getFragmentSignature() {
return signature;
}
/**
@ -161,7 +162,7 @@ public class AsmFragmentInstance {
* @param asm The assembler sequence to generate into.
*/
public void generate(AsmProgram asm) {
AsmSequenceGenerator asmSequenceGenerator = new AsmSequenceGenerator(name, this, asm);
AsmSequenceGenerator asmSequenceGenerator = new AsmSequenceGenerator(signature.getName(), this, asm);
asmSequenceGenerator.generate(fragmentTemplate.getBodyAsm());
}

View File

@ -24,7 +24,7 @@ public class AsmFragmentInstanceSpec {
/**
* The string signature/name of the fragment template.
*/
private String signature;
private AsmFragmentSignature signature;
/**
* Binding of named values in the fragment to values (constants, variables, ...) .
@ -46,13 +46,13 @@ public class AsmFragmentInstanceSpec {
*/
public AsmFragmentInstanceSpec(Program program, AsmFragmentSignature signature, AsmFragmentBindings bindings, ScopeRef codeScopeRef) {
this.program = program;
this.signature = signature.getName();
this.signature = signature;
this.bindings = bindings.variables;
this.codeScopeRef = codeScopeRef;
}
public String getSignature() {
public AsmFragmentSignature getSignature() {
return signature;
}
@ -148,7 +148,6 @@ public class AsmFragmentInstanceSpec {
return potentialTypes;
}
/**
* Updates the ASM fragment instance specification to the next available variation.
* If no more variations exist the ASM fragment instance specification will become unusable.
@ -164,11 +163,11 @@ public class AsmFragmentInstanceSpec {
bindings.remove(variationCurrentName);
bindings.put(variationNextName, constValue);
// Update signature
this.signature = signature.replace(variationCurrentName, variationNextName);
this.signature = AsmFragmentSignature.parse(signature.getName().replace(variationCurrentName, variationNextName));
variationCurrentName = variationNextName;
variationCurrentValue = nextVariationValue;
} else {
this.signature = "no-more-variations";
this.signature = new AsmFragmentSignature.Singleton("NO_MORE_VARIATIONS");
this.bindings = new LinkedHashMap<>();
}
}

View File

@ -2,6 +2,8 @@ package dk.camelot64.kickc.fragment;
import dk.camelot64.cpufamily6502.CpuClobber;
import dk.camelot64.kickc.asm.AsmProgram;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignatureExpr;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.Registers;
import dk.camelot64.kickc.model.TargetCpu;
@ -27,7 +29,7 @@ import java.util.Objects;
public class AsmFragmentTemplate {
/** The fragment template signature name. */
private final String signature;
private final AsmFragmentSignature signature;
/** The target CPU. */
private final TargetCpu targetCpu;
/** The fragment template body */
@ -40,7 +42,7 @@ public class AsmFragmentTemplate {
/** The cycles consumed by the ASM of the fragment. Initially null. Non-null after the template is used to generate ASM code.*/
private Double cycles;
public AsmFragmentTemplate(String signature, String body, TargetCpu targetCpu) {
public AsmFragmentTemplate(AsmFragmentSignature signature, String body, TargetCpu targetCpu) {
this.signature = signature;
this.body = body;
this.targetCpu = targetCpu;
@ -52,7 +54,7 @@ public class AsmFragmentTemplate {
* @param bodyLines Parsed ASM body
*/
public AsmFragmentTemplate(KickCParser.AsmLinesContext bodyLines, TargetCpu targetCpu) {
this.signature = "--inline--";
this.signature = new AsmFragmentSignature.Singleton("INLINE");
this.bodyAsm = bodyLines;
this.targetCpu = targetCpu;
}
@ -89,6 +91,8 @@ public class AsmFragmentTemplate {
* Initialize the fields that require parsing the ASM (bodyAsm, clobber, cycles).
*/
private void initAsm() {
String signatureName = signature.getName();
// Parse the body ASM
this.bodyAsm = AsmParser.parseAsm(this.body, new StatementSource(signature + ".asm", 1, 1, this.body, -1, -1));
// Generate a dummy instance to find clobber & cycles
@ -108,12 +112,12 @@ public class AsmFragmentTemplate {
v4.setAllocation(new Registers.RegisterZpMem(8, 1));
v5.setAllocation(new Registers.RegisterZpMem(9, 1));
v6.setAllocation(new Registers.RegisterZpMem(10, 1));
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("z4")) bindings.put("z4", v4);
if(signature.contains("z5")) bindings.put("z5", v5);
if(signature.contains("z6")) bindings.put("z6", v6);
if(signatureName.contains("z1")) bindings.put("z1", v1);
if(signatureName.contains("z2")) bindings.put("z2", v2);
if(signatureName.contains("z3")) bindings.put("z3", v3);
if(signatureName.contains("z4")) bindings.put("z4", v4);
if(signatureName.contains("z5")) bindings.put("z5", v5);
if(signatureName.contains("z6")) bindings.put("z6", v6);
}
{
Variable v1 = createLoadStore("m1", SymbolType.BYTE, scope, Variable.MemoryArea.MAIN_MEMORY, null);
@ -128,25 +132,25 @@ public class AsmFragmentTemplate {
v4.setAllocation(new Registers.RegisterMainMem(v4.getVariableRef(), 1, null, false));
v5.setAllocation(new Registers.RegisterMainMem(v5.getVariableRef(), 1, null, false));
v6.setAllocation(new Registers.RegisterMainMem(v6.getVariableRef(), 1, null, false));
if(signature.contains("m1")) bindings.put("m1", v1);
if(signature.contains("m2")) bindings.put("m2", v2);
if(signature.contains("m3")) bindings.put("m3", v3);
if(signature.contains("m4")) bindings.put("m4", v4);
if(signature.contains("m5")) bindings.put("m5", v5);
if(signature.contains("m6")) bindings.put("m6", v6);
if(signatureName.contains("m1")) bindings.put("m1", v1);
if(signatureName.contains("m2")) bindings.put("m2", v2);
if(signatureName.contains("m3")) bindings.put("m3", v3);
if(signatureName.contains("m4")) bindings.put("m4", v4);
if(signatureName.contains("m5")) bindings.put("m5", v5);
if(signatureName.contains("m6")) bindings.put("m6", v6);
}
if(signature.contains("c1")) bindings.put("c1", new ConstantInteger(310L));
if(signature.contains("c2")) bindings.put("c2", new ConstantInteger(320L));
if(signature.contains("c3")) bindings.put("c3", new ConstantInteger(330L));
if(signature.contains("c4")) bindings.put("c4", new ConstantInteger(340L));
if(signature.contains("c5")) bindings.put("c5", new ConstantInteger(350L));
if(signature.contains("c6")) bindings.put("c6", new ConstantInteger(360L));
if(signature.contains("la1")) bindings.put("la1", new Label("@1", scope, true));
if(signature.startsWith("call_")) bindings.put("la1", new Label("@1", scope, true));
if(signatureName.contains("c1")) bindings.put("c1", new ConstantInteger(310L));
if(signatureName.contains("c2")) bindings.put("c2", new ConstantInteger(320L));
if(signatureName.contains("c3")) bindings.put("c3", new ConstantInteger(330L));
if(signatureName.contains("c4")) bindings.put("c4", new ConstantInteger(340L));
if(signatureName.contains("c5")) bindings.put("c5", new ConstantInteger(350L));
if(signatureName.contains("c6")) bindings.put("c6", new ConstantInteger(360L));
if(signatureName.contains("la1")) bindings.put("la1", new Label("@1", scope, true));
if(signatureName.startsWith("call_")) bindings.put("la1", new Label("@1", scope, true));
AsmFragmentInstance fragmentInstance =
new AsmFragmentInstance(new Program(), signature, ScopeRef.ROOT, this, bindings);
AsmProgram asm = new AsmProgram(targetCpu);
asm.startChunk(ScopeRef.ROOT, null, signature);
asm.startChunk(ScopeRef.ROOT, null, signature.getName());
fragmentInstance.generate(asm);
CpuClobber cpuClobber = asm.getClobber();
this.clobber = new AsmFragmentClobber(cpuClobber);
@ -154,7 +158,7 @@ public class AsmFragmentTemplate {
this.cycles = asm.getCycles();
}
public String getSignature() {
public AsmFragmentSignature getSignature() {
return signature;
}

View File

@ -1,6 +1,7 @@
package dk.camelot64.kickc.fragment;
import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentTemplateSynthesizer;
import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.TargetCpu;
@ -29,7 +30,7 @@ public class AsmFragmentTemplateCache {
private TargetCpu cpu;
/** Cache for the best fragment templates. Maps signature to the best fragment template for the signature. Maps to NO_SYNTHESIS if synthesis was unsuccessful. */
private Map<String, AsmFragmentTemplate> cache;
private Map<AsmFragmentSignature, AsmFragmentTemplate> cache;
/** Detects any modification of the cache. */
private boolean modified;
@ -39,7 +40,7 @@ public class AsmFragmentTemplateCache {
*
* @param cpu The target CPU
*/
private AsmFragmentTemplateCache(Path cacheFolder, TargetCpu cpu, AsmFragmentSystemHash fragmentSystemHash, Map<String, AsmFragmentTemplate> cache) {
private AsmFragmentTemplateCache(Path cacheFolder, TargetCpu cpu, AsmFragmentSystemHash fragmentSystemHash, Map<AsmFragmentSignature, AsmFragmentTemplate> cache) {
this.cacheFolder = cacheFolder;
this.cpu = cpu;
this.fragmentSystemHash = fragmentSystemHash;
@ -48,7 +49,8 @@ public class AsmFragmentTemplateCache {
}
/** Special singleton representing that the fragment can not be synthesized or loaded. */
public static AsmFragmentTemplate NO_SYNTHESIS = new AsmFragmentTemplate("NO_SYNTHESIS", "NO_SYNTHESIS", null);
public static AsmFragmentTemplate NO_SYNTHESIS =
new AsmFragmentTemplate(new AsmFragmentSignature.Singleton("NO_SYNTHESIS"), "NO_SYNTHESIS", null);
/** Prefix for the fragment hash file header. */
public static final String HASH_HEADER = "//KICKC FRAGMENT CACHE ";
@ -62,7 +64,7 @@ public class AsmFragmentTemplateCache {
* @param signature The signature
* @return The cached ASM fragment template. null if not in the cache. NO_SYNTHESIS if synthesis was unsuccessful.
*/
public AsmFragmentTemplate get(String signature) {
public AsmFragmentTemplate get(AsmFragmentSignature signature) {
return cache.get(signature);
}
@ -72,7 +74,7 @@ public class AsmFragmentTemplateCache {
* @param signature The signature
* @param asmFragmentTemplate The ASM fragment template. NO_SYNTHESIS if synthesis was unsuccessful.
*/
public void put(String signature, AsmFragmentTemplate asmFragmentTemplate) {
public void put(AsmFragmentSignature signature, AsmFragmentTemplate asmFragmentTemplate) {
this.cache.put(signature, asmFragmentTemplate);
this.modified = true;
}
@ -101,7 +103,7 @@ public class AsmFragmentTemplateCache {
* @param cpu The CPU to make a cache for
* @return The new empty cache
*/
public static AsmFragmentTemplateCache diskCache(Path cacheFolder, TargetCpu cpu, AsmFragmentSystemHash fragmentSystemHash, Map<String, AsmFragmentTemplate> cache) {
public static AsmFragmentTemplateCache diskCache(Path cacheFolder, TargetCpu cpu, AsmFragmentSystemHash fragmentSystemHash, Map<AsmFragmentSignature, AsmFragmentTemplate> cache) {
return new AsmFragmentTemplateCache(cacheFolder, cpu, fragmentSystemHash, cache);
}
@ -118,7 +120,7 @@ public class AsmFragmentTemplateCache {
final Date before = new Date();
if(!cacheFolder.toFile().exists()) {
if(log.isVerboseFragmentLog())
log.append("Creating fragment cache folder " + cacheFolder.toAbsolutePath().toString());
log.append("Creating fragment cache folder " + cacheFolder.toAbsolutePath());
cacheFolder.toFile().mkdir();
return diskCache(cacheFolder, cpu, fragmentSystemHash, new LinkedHashMap<>());
}
@ -133,7 +135,7 @@ public class AsmFragmentTemplateCache {
cacheFile.delete();
return diskCache(cacheFolder, cpu, fragmentSystemHash, new LinkedHashMap<>());
}
LinkedHashMap<String, AsmFragmentTemplate> cache = new LinkedHashMap<>();
LinkedHashMap<AsmFragmentSignature, AsmFragmentTemplate> cache = new LinkedHashMap<>();
BufferedReader fragmentCacheReader = new BufferedReader(new FileReader(cacheFile));
String hashLine = fragmentCacheReader.readLine();
final String hashPayload = hashLine.substring(HASH_HEADER.length());
@ -152,16 +154,16 @@ public class AsmFragmentTemplateCache {
// Read the first "real" line
String cacheLine = fragmentCacheReader.readLine();
StringBuilder body = null;
String signature = null;
String signatureText = null;
while(cacheLine != null) {
// Determine if the line is a new fragment or the continuation of the current fragment body
if(cacheLine.startsWith(FRAGMENT_HEADER)) {
// New fragment - first put the current one into the cache
if(signature != null)
addFragment(cache, signature, body, cpu);
if(signatureText != null)
addFragment(cache, signatureText, body, cpu);
// Clear body and initialize signature
body = new StringBuilder();
signature = cacheLine.substring(FRAGMENT_HEADER.length());
signatureText = cacheLine.substring(FRAGMENT_HEADER.length());
} else {
// Continuation of body
body.append(cacheLine).append("\n");
@ -169,8 +171,8 @@ public class AsmFragmentTemplateCache {
cacheLine = fragmentCacheReader.readLine();
}
// Put the last fragment into the cache
if(signature != null)
addFragment(cache, signature, body, cpu);
if(signatureText != null)
addFragment(cache, signatureText, body, cpu);
final Date after = new Date();
final long millis = after.getTime() - before.getTime();
if(log.isVerboseFragmentLog())
@ -183,7 +185,8 @@ public class AsmFragmentTemplateCache {
}
}
private static void addFragment(LinkedHashMap<String, AsmFragmentTemplate> cache, String signature, StringBuilder body, TargetCpu targetCpu) {
private static void addFragment(LinkedHashMap<AsmFragmentSignature, AsmFragmentTemplate> cache, String signatureText, StringBuilder body, TargetCpu targetCpu) {
AsmFragmentSignature signature = AsmFragmentSignature.parse(signatureText);
final String bodyString = body.toString();
if(bodyString.startsWith(NO_SYNTHESIS.getBody())) {
cache.put(signature, NO_SYNTHESIS);
@ -213,7 +216,7 @@ public class AsmFragmentTemplateCache {
if(newFragmentSystemHash.getHashStringLF() == null || newFragmentSystemHash.getHashStringCRLF() == null)
throw new InternalError("Error saving ASM fragment cache file. Not calculated for all systems!");
fragmentFilePrint.println(HASH_HEADER + newFragmentSystemHash.getHashStringLF() + " " + newFragmentSystemHash.getHashStringCRLF());
for(String signature : this.cache.keySet()) {
for(AsmFragmentSignature signature : this.cache.keySet()) {
AsmFragmentTemplate fragmentTemplate = this.cache.get(signature);
fragmentFilePrint.println(FRAGMENT_HEADER + signature);
if(fragmentTemplate == NO_SYNTHESIS) {

View File

@ -1,6 +1,7 @@
package dk.camelot64.kickc.fragment;
import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import dk.camelot64.kickc.fragment.synthesis.*;
import java.io.File;
@ -37,18 +38,19 @@ public class AsmFragmentTemplateUsages {
*/
public static void logUsages(AsmFragmentTemplateSynthesizer synthesizer, CompileLog log, boolean logRedundantFiles, boolean logUnusedFiles, boolean logUnusedRules, boolean logFileDetails, boolean logAllDetails, boolean logDetailsBody) {
Map<String, AsmFragmentSynthesis> synthesisGraph =
Map<AsmFragmentSignature, AsmFragmentSynthesis> synthesisGraph =
synthesizer.getSynthesisGraph();
ArrayList<String> signatures = new ArrayList<>(synthesisGraph.keySet());
ArrayList<AsmFragmentSignature> signatures = new ArrayList<>(synthesisGraph.keySet());
Collections.sort(signatures);
File[] files = synthesizer.allFragmentFiles();
if(logRedundantFiles) {
log.append("\nREDUNDANT ASM FRAGMENT FILES ANALYSIS (if found consider removing them from disk)");
Set<String> redundantSignatures = new LinkedHashSet<>();
Set<AsmFragmentSignature> redundantSignatures = new LinkedHashSet<>();
for(File file : files) {
String fileName = file.getName();
String signature = fileName.substring(0, fileName.length() - 4);
String signatureText = fileName.substring(0, fileName.length() - 4);
AsmFragmentSignature signature = AsmFragmentSignature.parse(signatureText);
// Synthesize the fragment - and check if the synthesis is as good as the file body
Collection<AsmFragmentSynthesisResult> templates = synthesizer.getBestTemplates(signature, log);
boolean isFile = false;
@ -110,7 +112,7 @@ public class AsmFragmentTemplateUsages {
log.append("\nUNUSED ASM FRAGMENT SYNTHESIS RULE ANALYSIS (if found consider removing them)");
final Collection<AsmFragmentTemplateSynthesisRule> allRules = AsmFragmentTemplateSynthesisRuleManager.getAllSynthesisRules();
for(String signature : signatures) {
for(AsmFragmentSignature signature : signatures) {
LinkedList<AsmFragmentSynthesisResult> templates = new LinkedList<>(synthesizer.getBestTemplates(signature, log));
while(!templates.isEmpty()) {
final AsmFragmentSynthesisResult template = templates.pop();
@ -128,7 +130,7 @@ public class AsmFragmentTemplateUsages {
log.append("\nDETAILED ASM FILE USAGES");
// Find all file templates
List<AsmFragmentSynthesisResult> fileTemplates = new ArrayList<>();
for(String signature : signatures) {
for(AsmFragmentSignature signature : signatures) {
Collection<AsmFragmentSynthesisResult> templates = synthesisGraph.get(signature).getBestTemplates();
for(AsmFragmentSynthesisResult template : templates) {
if(template.isFile()) {
@ -143,7 +145,7 @@ public class AsmFragmentTemplateUsages {
if(logAllDetails) {
log.append("\nDETAILED ASM FRAGMENT USAGES");
List<AsmFragmentSynthesisResult> allTemplates = new ArrayList<>();
for(String signature : signatures) {
for(AsmFragmentSignature signature : signatures) {
Collection<AsmFragmentSynthesisResult> templates = synthesisGraph.get(signature).getBestTemplates();
allTemplates.addAll(templates);
}
@ -155,14 +157,13 @@ public class AsmFragmentTemplateUsages {
private static void logTemplatesByUsage(AsmFragmentTemplateSynthesizer synthesizer, CompileLog log, List<AsmFragmentSynthesisResult> templates, boolean logBody) {
// Sort by usage
Collections.sort(templates, (o1, o2) -> {
Integer u1 = fragmentTemplateUsage.get(o1);
Integer u2 = fragmentTemplateUsage.get(o2);
if(u1 == null) u1 = 0;
if(u2 == null) u2 = 0;
return u2 - u1;
}
);
templates.sort((o1, o2) -> {
Integer u1 = fragmentTemplateUsage.get(o1);
Integer u2 = fragmentTemplateUsage.get(o2);
if (u1 == null) u1 = 0;
if (u2 == null) u2 = 0;
return u2 - u1;
});
// Output
for(AsmFragmentSynthesisResult template : templates) {
Integer usage = fragmentTemplateUsage.get(template);

View File

@ -6,11 +6,13 @@ import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import java.util.Objects;
/**
* A signature of an ASM fragment.
* The signature captures the operation performed by the fragment and the types of the parameters.
*/
public interface AsmFragmentSignature {
public interface AsmFragmentSignature extends Comparable<AsmFragmentSignature> {
/**
* Get the signature name. Eg. <code>vbum1=pbum2_derefidx_vbuyy</code>
@ -22,6 +24,7 @@ public interface AsmFragmentSignature {
/**
* Parses a signature name to a typed signature.
*
* @param sigName The signature name (created by signature.getName())
* @return The signature
*/
@ -34,10 +37,36 @@ public interface AsmFragmentSignature {
return instantiator.visitSignature(sigCtx);
}
abstract class AsmFragmentSignatureBase implements AsmFragmentSignature {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AsmFragmentSignatureBase other = (AsmFragmentSignatureBase) o;
return Objects.equals(getName(), other.getName());
}
@Override
public int hashCode() {
return Objects.hash(getName());
}
@Override
public int compareTo(AsmFragmentSignature other) {
return getName().compareTo(other.getName());
}
@Override
public String toString() {
return getName();
}
}
/**
* ASM fragment signature for an assignment <code>A=B</code>.
*/
class Assignment implements AsmFragmentSignature {
class Assignment extends AsmFragmentSignatureBase {
final private AsmFragmentSignatureExpr lValue;
final private AsmFragmentSignatureExpr rValue;
@ -56,7 +85,7 @@ public interface AsmFragmentSignature {
/**
* ASM fragment signature for a conditional jump <code>if(A) goto B</code>.
*/
class Call implements AsmFragmentSignature {
class Call extends AsmFragmentSignatureBase {
final private AsmFragmentSignatureExpr procedure;
@ -73,7 +102,7 @@ public interface AsmFragmentSignature {
/**
* ASM fragment signature for a conditional jump <code>if(A) goto B</code>.
*/
class ConditionalJump implements AsmFragmentSignature {
class ConditionalJump extends AsmFragmentSignatureBase {
final private AsmFragmentSignatureExpr condition;
final private AsmFragmentSignatureExpr label;
@ -92,7 +121,7 @@ public interface AsmFragmentSignature {
/**
* ASM fragment signature for a stand-alone expression with a side-effect.
*/
class ExprSideEffect implements AsmFragmentSignature {
class ExprSideEffect extends AsmFragmentSignatureBase {
final private AsmFragmentSignatureExpr expr;
@ -106,8 +135,10 @@ public interface AsmFragmentSignature {
}
}
/** Interrupt Service Routine Code. */
class Isr implements AsmFragmentSignature {
/**
* Interrupt Service Routine Code.
*/
class Isr extends AsmFragmentSignatureBase {
final private String interruptType;
@ -129,4 +160,22 @@ public interface AsmFragmentSignature {
}
}
/** Signature used for singletons. */
class Singleton extends AsmFragmentSignatureBase {
/** The singleton name. */
private final String name;
public Singleton(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
}

View File

@ -1,6 +1,7 @@
package dk.camelot64.kickc.fragment.synthesis;
import dk.camelot64.kickc.fragment.AsmFragmentClobber;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import java.util.*;
@ -14,7 +15,7 @@ public class AsmFragmentSynthesis {
/**
* The signature of the fragment template being synthesized.
*/
private final String signature;
private final AsmFragmentSignature signature;
/**
* The best template loaded/synthesized so far for each clobber profile
@ -41,7 +42,7 @@ public class AsmFragmentSynthesis {
*
* @param signature The signature of the fragment template to load/synthesize
*/
AsmFragmentSynthesis(String signature) {
AsmFragmentSynthesis(AsmFragmentSignature signature) {
this.signature = signature;
this.bestTemplates = new LinkedHashMap<>();
this.synthesisOptions = new LinkedHashSet<>();
@ -163,7 +164,7 @@ public class AsmFragmentSynthesis {
return bestTemplates.values();
}
public String getSignature() {
public AsmFragmentSignature getSignature() {
return signature;
}
}

View File

@ -1,5 +1,7 @@
package dk.camelot64.kickc.fragment.synthesis;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import java.util.List;
import java.util.Objects;
@ -11,12 +13,12 @@ public class AsmFragmentSynthesisOption {
/**
* The signature of the fragment template being synthesized. The from-node in the graph.
*/
private final String signature;
private final AsmFragmentSignature signature;
/**
* The signatures of the sub-fragment templates to synthesize from. The to-nodes in the graph.
*/
private final List<String> subSignatures;
private final List<AsmFragmentSignature> subSignatures;
/**
* The synthesis rule capable of synthesizing this template from the sub-fragments.
@ -29,17 +31,17 @@ public class AsmFragmentSynthesisOption {
* @param signature the signature of the fragment template being synthesized.
* @param rule The synthesis rule capable of synthesizing this template from the sub-fragment.
*/
AsmFragmentSynthesisOption(String signature, AsmFragmentTemplateSynthesisRule rule) {
AsmFragmentSynthesisOption(AsmFragmentSignature signature, AsmFragmentTemplateSynthesisRule rule) {
this.signature = signature;
this.rule = rule;
this.subSignatures = rule.getSubSignatures(signature);
}
public String getSignature() {
public AsmFragmentSignature getSignature() {
return signature;
}
List<String> getSubSignatures() {
List<AsmFragmentSignature> getSubSignatures() {
return subSignatures;
}

View File

@ -2,6 +2,7 @@ package dk.camelot64.kickc.fragment.synthesis;
import dk.camelot64.kickc.fragment.AsmFragmentClobber;
import dk.camelot64.kickc.fragment.AsmFragmentTemplate;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import java.util.List;
@ -18,20 +19,20 @@ public class AsmFragmentSynthesisResult {
/**
* true if the fragment was loaded from disk.
*/
private boolean file;
private final boolean file;
/**
* true if the fragment was loaded from the disk cache.
*/
private boolean cache;
private final boolean cache;
/**
* The synthesis that created the fragment. null if the fragment template was loaded.
*/
private AsmFragmentTemplateSynthesisRule synthesis;
private final AsmFragmentTemplateSynthesisRule synthesis;
/**
* The sub fragment template that the synthesis used to create this.
*/
private List<AsmFragmentSynthesisResult> subFragments;
private final List<AsmFragmentSynthesisResult> subFragments;
public AsmFragmentSynthesisResult(AsmFragmentTemplate fragment, boolean file, boolean cache, AsmFragmentTemplateSynthesisRule synthesis, List<AsmFragmentSynthesisResult> subFragments) {
this.fragment = fragment;
@ -92,7 +93,7 @@ public class AsmFragmentSynthesisResult {
return fragment.getBody();
}
public String getSignature() {
public AsmFragmentSignature getSignature() {
return fragment.getSignature();
}
}

View File

@ -1,6 +1,7 @@
package dk.camelot64.kickc.fragment.synthesis;
import dk.camelot64.kickc.fragment.AsmFragmentTemplate;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import java.util.List;
@ -15,7 +16,7 @@ public interface AsmFragmentTemplateSynthesisRule {
* @param signature The fragment template signature
* @return true if the rule matches the signature
*/
boolean matches(String signature);
boolean matches(AsmFragmentSignature signature);
/**
* The signatures of the sub-templates that are needed to generate an ASM fragment template
@ -23,7 +24,7 @@ public interface AsmFragmentTemplateSynthesisRule {
* @param signature The signature of the fragment to synthesize
* @return Signatures of the sub-templates that are needed to synthesize the fragment template.
*/
List<String> getSubSignatures(String signature);
List<AsmFragmentSignature> getSubSignatures(AsmFragmentSignature signature);
/**
* Synthesize a fragment template from a sub fragment template.
@ -33,5 +34,5 @@ public interface AsmFragmentTemplateSynthesisRule {
* @return The synthesized ASM fragment template.
* Null if the fragment cannot be synthesized (for instance due to clobber constraints).
*/
AsmFragmentTemplate synthesize(String signature, List<AsmFragmentTemplate> subTemplates);
AsmFragmentTemplate synthesize(AsmFragmentSignature signature, List<AsmFragmentTemplate> subTemplates);
}

View File

@ -1,6 +1,7 @@
package dk.camelot64.kickc.fragment.synthesis;
import dk.camelot64.kickc.fragment.AsmFragmentTemplate;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import java.util.*;
import java.util.regex.Matcher;
@ -71,39 +72,42 @@ class AsmFragmentTemplateSynthesisRuleRegex implements AsmFragmentTemplateSynthe
* @param signature The fragment template signature
* @return true if the rule matches the signature
*/
public boolean matches(String signature) {
public boolean matches(AsmFragmentSignature signature) {
final String signatureText = signature.getName();
if(sigMatchPattern == null)
sigMatchPattern = Pattern.compile(sigMatch);
Matcher m = sigMatchPattern.matcher(signature);
Matcher m = sigMatchPattern.matcher(signatureText);
if(m.matches()) {
if(sigAvoid == null)
return true;
else {
if(sigAvoidPattern == null)
sigAvoidPattern = Pattern.compile(sigAvoid);
Matcher ma = sigAvoidPattern.matcher(signature);
Matcher ma = sigAvoidPattern.matcher(signatureText);
return !ma.matches();
}
}
return false;
}
public List<String> getSubSignatures(String signature) {
public List<AsmFragmentSignature> getSubSignatures(AsmFragmentSignature signature) {
if(matches(signature)) {
String subSignature = regexpRewriteSignature(signature, sigMatch, sigReplace);
final String signatureText = signature.getName();
String subSignatureText = regexpRewriteSignature(signatureText, 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));
subSignatureText = subSignatureText.replace(bound, bindMappings.get(bound));
}
}
return Collections.singletonList(subSignature);
return Collections.singletonList(AsmFragmentSignature.parse(subSignatureText));
} else {
return null;
}
}
public AsmFragmentTemplate synthesize(String signature, List<AsmFragmentTemplate> subTemplates) {
public AsmFragmentTemplate synthesize(AsmFragmentSignature signature, List<AsmFragmentTemplate> subTemplates) {
final AsmFragmentTemplate subTemplate = subTemplates.get(0);
// if(!matches(signature)) {
// throw new RuntimeException("Synthesis error! Attempting to synthesize on non-matching signature signature:"+signature+" match:"+sigMatch+" avoid:"+sigAvoid);

View File

@ -2,6 +2,7 @@ package dk.camelot64.kickc.fragment.synthesis;
import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.fragment.*;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import dk.camelot64.kickc.model.TargetCpu;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
@ -55,7 +56,7 @@ public class AsmFragmentTemplateSynthesizer {
* 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 final Map<String, AsmFragmentSynthesis> synthesisGraph;
private final Map<AsmFragmentSignature, AsmFragmentSynthesis> synthesisGraph;
/** Finalize the fragment template synthesizer. */
void finalize(CompileLog log) {
@ -73,7 +74,7 @@ public class AsmFragmentTemplateSynthesizer {
}
public AsmFragmentInstance getFragmentInstance(AsmFragmentInstanceSpec instanceSpec, CompileLog log) {
String signature = instanceSpec.getSignature();
AsmFragmentSignature signature = instanceSpec.getSignature();
AsmFragmentTemplate fragmentTemplate = getFragmentTemplate(signature, log);
// Return the resulting fragment instance
return new AsmFragmentInstance(
@ -91,14 +92,14 @@ public class AsmFragmentTemplateSynthesizer {
* @param log The log
* @return The best templates (with different clobber profiles) for the signature
*/
private AsmFragmentTemplate getFragmentTemplate(String signature, CompileLog log) {
private AsmFragmentTemplate getFragmentTemplate(AsmFragmentSignature signature, CompileLog log) {
// Attempt to find in memory/disk cache
AsmFragmentTemplate bestTemplate = fragmentCache.get(signature);
if (bestTemplate == AsmFragmentTemplateCache.NO_SYNTHESIS) {
if (log.isVerboseFragmentLog()) {
log.append("Unknown fragment " + signature);
}
throw new UnknownFragmentException(signature);
throw new UnknownFragmentException(signature.getName());
}
if (bestTemplate != null) {
AsmFragmentTemplateUsages.incUsage(new AsmFragmentSynthesisResult(bestTemplate, false, true, null, new ArrayList<>()));
@ -144,7 +145,7 @@ public class AsmFragmentTemplateSynthesizer {
* @param log The compile log
* @return The best templates for the passed signature
*/
public Collection<AsmFragmentSynthesisResult> getBestTemplates(String signature, CompileLog log) {
public Collection<AsmFragmentSynthesisResult> getBestTemplates(AsmFragmentSignature signature, CompileLog log) {
getOrCreateSynthesis(signature, log);
updateBestTemplates(log);
AsmFragmentSynthesis synthesis = getSynthesis(signature);
@ -159,7 +160,7 @@ public class AsmFragmentTemplateSynthesizer {
*
* @return The entire synthesis graph
*/
public Map<String, AsmFragmentSynthesis> getSynthesisGraph() {
public Map<AsmFragmentSignature, AsmFragmentSynthesis> getSynthesisGraph() {
return synthesisGraph;
}
@ -171,7 +172,7 @@ public class AsmFragmentTemplateSynthesizer {
* @return The synthesis used to synthesize the fragment template.
* null if the synthesis graph does not contain the synthesis.
*/
private AsmFragmentSynthesis getSynthesis(String signature) {
private AsmFragmentSynthesis getSynthesis(AsmFragmentSignature signature) {
return synthesisGraph.get(signature);
}
@ -184,7 +185,7 @@ public class AsmFragmentTemplateSynthesizer {
* @param log The compile log
* @return The synthesis that is used to load/synthesize the best template
*/
public AsmFragmentSynthesis getOrCreateSynthesis(String signature, CompileLog log) {
public AsmFragmentSynthesis getOrCreateSynthesis(AsmFragmentSignature signature, CompileLog log) {
AsmFragmentSynthesis synthesis = getSynthesis(signature);
if (synthesis != null) {
return synthesis;
@ -210,13 +211,13 @@ public class AsmFragmentTemplateSynthesizer {
AsmFragmentSynthesisOption synthesisOption = new AsmFragmentSynthesisOption(signature, rule);
synthesis.addSynthesisOption(synthesisOption);
if (log.isVerboseFragmentLog()) {
log.append("New fragment synthesis " + signature + " - sub-option " + String.join(",", synthesisOption.getSubSignatures()));
log.append("New fragment synthesis " + signature + " - sub-option " + synthesisOption.getSubSignatures().stream().map(AsmFragmentSignature::getName).collect(Collectors.joining(",")));
}
}
}
// Ensure that all sub-synthesis exist (recursively) - and set their parent options
for (AsmFragmentSynthesisOption synthesisOption : synthesis.getSynthesisOptions()) {
for (String subSignature : synthesisOption.getSubSignatures()) {
for (AsmFragmentSignature subSignature : synthesisOption.getSubSignatures()) {
AsmFragmentSynthesis subSynthesis = getOrCreateSynthesis(subSignature, log);
subSynthesis.addParentOption(synthesisOption);
}
@ -256,7 +257,7 @@ public class AsmFragmentTemplateSynthesizer {
for (AsmFragmentSynthesisOption synthesisOption : synthesisOptions) {
// for each sub-signature find the best templates
List<Collection<AsmFragmentSynthesisResult>> subSignatureTemplates = new ArrayList<>();
for (String subSignature : synthesisOption.getSubSignatures()) {
for (AsmFragmentSignature subSignature : synthesisOption.getSubSignatures()) {
AsmFragmentSynthesis subSynthesis = getSynthesis(subSignature);
if (subSynthesis == null) {
throw new RuntimeException("Synthesis Graph Error! Sub-synthesis not found in graph " + subSignature);
@ -272,13 +273,13 @@ public class AsmFragmentTemplateSynthesizer {
final AsmFragmentTemplate synthesize = rule.synthesize(synthesis.getSignature(), subFragments);
if (synthesize != null) {
if (log.isVerboseFragmentLog()) {
log.append("Fragment synthesis " + synthesis.getSignature() + " - Successfully synthesized from " + String.join(",", synthesisOption.getSubSignatures()));
log.append("Fragment synthesis " + synthesis.getSignature() + " - Successfully synthesized from " + synthesisOption.getSubSignatures().stream().map(AsmFragmentSignature::getName).collect(Collectors.joining(",")));
}
AsmFragmentSynthesisResult synthesisResult = new AsmFragmentSynthesisResult(synthesize, false, false, rule, subFragmentCombination);
modified |= synthesis.bestTemplateCandidate(synthesisResult);
} else {
if (log.isVerboseFragmentLog()) {
log.append("Fragment synthesis " + synthesis.getSignature() + " - Sub clobber prevents synthesis from " + String.join(",", synthesisOption.getSubSignatures()));
log.append("Fragment synthesis " + synthesis.getSignature() + " - Sub clobber prevents synthesis from " + synthesisOption.getSubSignatures().stream().map(AsmFragmentSignature::getName).collect(Collectors.joining(",")));
}
}
}
@ -287,7 +288,7 @@ public class AsmFragmentTemplateSynthesizer {
if (modified) {
// The synthesis was modified - update all parents later
for (AsmFragmentSynthesisOption parentOption : synthesis.getParentOptions()) {
String parentSignature = parentOption.getSignature();
AsmFragmentSignature parentSignature = parentOption.getSignature();
AsmFragmentSynthesis parentSynthesis = getSynthesis(parentSignature);
if (parentSynthesis == null) {
throw new RuntimeException("Synthesis Graph Error! Parent synthesis not found in graph " + parentSignature);
@ -341,7 +342,7 @@ public class AsmFragmentTemplateSynthesizer {
* @param signature The signature
* @return The fragment template from a file. null if the template is not found as a file.
*/
private List<AsmFragmentSynthesisResult> loadFragmentTemplates(String signature) {
private List<AsmFragmentSynthesisResult> loadFragmentTemplates(AsmFragmentSignature signature) {
ArrayList<AsmFragmentSynthesisResult> fileTemplates = new ArrayList<>();
List<TargetCpu.Feature> cpuFeatures = targetCpu.getFeatures();
for (TargetCpu.Feature cpuFeature : cpuFeatures) {
@ -359,9 +360,11 @@ public class AsmFragmentTemplateSynthesizer {
* @param fragmentFolder The folder to look in
* @return any fragment with the given signature found in the folder. null if not found.
*/
private AsmFragmentSynthesisResult loadFragmentTemplate(String signature, Path fragmentFolder) {
private AsmFragmentSynthesisResult loadFragmentTemplate(AsmFragmentSignature signature, Path fragmentFolder) {
final String signatureText = signature.getName();
try {
File fragmentFile = fragmentFolder.resolve(signature + ".asm").toFile();
File fragmentFile = fragmentFolder.resolve(signatureText + ".asm").toFile();
if (!fragmentFile.exists()) {
return null;
}
@ -407,6 +410,10 @@ public class AsmFragmentTemplateSynthesizer {
private final String signature;
public UnknownFragmentException(AsmFragmentSignature signature) {
this(signature.getName());
}
public UnknownFragmentException(String signature) {
super("Fragment not found " + signature);
this.signature = signature;

View File

@ -4,6 +4,7 @@ import dk.camelot64.cpufamily6502.CpuAddressingMode;
import dk.camelot64.cpufamily6502.CpuClobber;
import dk.camelot64.kickc.asm.*;
import dk.camelot64.kickc.fragment.*;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentTemplateSynthesizer;
import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.*;
@ -893,7 +894,13 @@ public class Pass4CodeGeneration {
} else if (statement instanceof StatementAsm) {
StatementAsm statementAsm = (StatementAsm) statement;
HashMap<String, Value> bindings = new HashMap<>();
AsmFragmentInstance asmFragmentInstance = new AsmFragmentInstance(program, "inline", block.getScope(), new AsmFragmentTemplate(statementAsm.getAsmLines(), program.getTargetCpu()), bindings);
AsmFragmentInstance asmFragmentInstance =
new AsmFragmentInstance(
program,
new AsmFragmentSignature.Singleton("INLINE"),
block.getScope(),
new AsmFragmentTemplate(statementAsm.getAsmLines(), program.getTargetCpu()),
bindings);
asmFragmentInstance.generate(asm);
AsmChunk currentChunk = asm.getCurrentChunk();
@ -922,7 +929,7 @@ public class Pass4CodeGeneration {
}
/**
* Generate exit-code for entering an interrupt procedure based on the interrupt type
* Generate entry-code for entering an interrupt procedure based on the interrupt type
*
* @param asm The assembler to generate code into
* @param procedure The interrupt procedure
@ -933,10 +940,10 @@ public class Pass4CodeGeneration {
String entryName;
if (interruptType.contains("clobber")) {
entryFragment = AsmFragmentInstanceSpecBuilder.interruptEntry(interruptType.replace("clobber", "all"), program);
entryName = entryFragment.getSignature().replace("all", "clobber");
entryName = entryFragment.getSignature().getName().replace("all", "clobber");
} else {
entryFragment = AsmFragmentInstanceSpecBuilder.interruptEntry(interruptType, program);
entryName = entryFragment.getSignature();
entryName = entryFragment.getSignature().getName();
}
try {
asm.startChunk(procedure.getRef(), null, "interrupt(" + entryName + ")");
@ -958,10 +965,10 @@ public class Pass4CodeGeneration {
String entryName;
if (interruptType.contains("clobber")) {
entryFragment = AsmFragmentInstanceSpecBuilder.interruptExit(interruptType.replace("clobber", "all"), program);
entryName = entryFragment.getSignature().replace("all", "clobber");
entryName = entryFragment.getSignature().getName().replace("all", "clobber");
} else {
entryFragment = AsmFragmentInstanceSpecBuilder.interruptExit(interruptType, program);
entryName = entryFragment.getSignature();
entryName = entryFragment.getSignature().getName();
}
asm.startChunk(procedure.getRef(), null, "interrupt(" + entryName + ")");
try {

View File

@ -2,6 +2,7 @@ package dk.camelot64.kickc.test;
import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.fragment.AsmFragmentTemplateUsages;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentSynthesisResult;
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentTemplateSynthesizer;
import dk.camelot64.kickc.model.TargetCpu;
@ -35,7 +36,7 @@ public class TestFragments {
}
@Test
public void testSynthesis() throws IOException {
public void testSynthesis() {
testFragmentExists("pbuz1=pbuz2_plus_pwuc1_derefidx_vbuxx");
}
@ -189,9 +190,10 @@ public class TestFragments {
/**
* Test that a specific fragment can be succesfully loaded/synthesized
*
* @param signature The fragment signature
* @param signatureText The fragment signature
*/
private void testFragmentExists(String signature) {
private void testFragmentExists(String signatureText) {
AsmFragmentSignature signature = AsmFragmentSignature.parse(signatureText);
CompileLog log = new CompileLog();
asmFragmentTemplateSynthesizer = new AsmFragmentTemplateSynthesizer(TargetCpu.MOS6502X, new File("src/main/fragment/").toPath(), false, new CompileLog());
log.setSysOut(true);
@ -225,17 +227,18 @@ public class TestFragments {
if((testStep % 100) == 0)
System.out.println("Testing " + testIdx + "/" + sigs.size());
String signature = sigs.get(testIdx);
String signatureText = sigs.get(testIdx);
AsmFragmentSignature signature = AsmFragmentSignature.parse(signatureText);
List<AsmFragmentSynthesisResult> templates =
new ArrayList<>(asmFragmentTemplateSynthesizer.getBestTemplates(signature, log));
Collections.sort(templates, Comparator.comparing(AsmFragmentSynthesisResult::getClobber));
templates.sort(Comparator.comparing(AsmFragmentSynthesisResult::getClobber));
if(templates.size() == 0) {
log.append("CANNOT SYNTHESIZE " + signature);
}
for(AsmFragmentSynthesisResult template : templates) {
String prefix = "";
String prefix;
if(template.isCache()) {
prefix = "cached ";
} else if(template.isFile()) {
@ -328,8 +331,7 @@ public class TestFragments {
private Collection<Value> lValuesBu(Collection<Value> usedValues) {
ArrayList<Value> values = new ArrayList<>();
values.addAll(lValuesVbu(usedValues));
ArrayList<Value> values = new ArrayList<>(lValuesVbu(usedValues));
Collection<Value> pbus = rValuesPbu(usedValues);
for(Value pbu : pbus) {
values.add(new Value("_deref_" + pbu.getSignature(), pbu));
@ -347,8 +349,7 @@ public class TestFragments {
}
private Collection<Value> rValuesBu(Collection<Value> usedValues) {
ArrayList<Value> values = new ArrayList<>();
values.addAll(lValuesBu(usedValues));
ArrayList<Value> values = new ArrayList<>(lValuesBu(usedValues));
values.add(new Value("vbuc1"));
if(contains(usedValues, "c1")) {
values.add(new Value("vbuc2"));
@ -393,8 +394,7 @@ public class TestFragments {
}
private Collection<Value> rValuesVbu(Collection<Value> usedValues) {
ArrayList<Value> values = new ArrayList<>();
values.addAll(lValuesVbu(usedValues));
ArrayList<Value> values = new ArrayList<>(lValuesVbu(usedValues));
values.add(new Value("vbuc1"));
if(contains(usedValues, "c1")) {
values.add(new Value("vbuc2"));
@ -437,8 +437,7 @@ public class TestFragments {
}
private Collection<Value> rValuesPbu(Collection<Value> usedValues) {
ArrayList<Value> values = new ArrayList<>();
values.addAll(lValuesPbu(usedValues));
ArrayList<Value> values = new ArrayList<>(lValuesPbu(usedValues));
values.add(new Value("pbuc1"));
if(contains(usedValues, "c1")) {
values.add(new Value("pbuc2"));
@ -470,12 +469,12 @@ public class TestFragments {
/** A signature that is part of a fragment signature. The signature may have sub-values (eg. if. it is a _derefidx_ signature */
public static class Value {
private String signature;
private final String signature;
private Collection<Value> subValues;
private final Collection<Value> subValues;
public Value(String signature) {
this(signature, new ArrayList<Value>());
this(signature, new ArrayList<>());
}
public Value(String signature, Collection<Value> subValues) {
@ -484,7 +483,7 @@ public class TestFragments {
}
public Value(String signature, Value subVal) {
this(signature, Arrays.asList(subVal));
this(signature, Collections.singletonList(subVal));
}