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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
package dk.camelot64.kickc.fragment; package dk.camelot64.kickc.fragment;
import dk.camelot64.kickc.CompileLog; import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import dk.camelot64.kickc.fragment.synthesis.*; import dk.camelot64.kickc.fragment.synthesis.*;
import java.io.File; 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) { 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(); synthesizer.getSynthesisGraph();
ArrayList<String> signatures = new ArrayList<>(synthesisGraph.keySet()); ArrayList<AsmFragmentSignature> signatures = new ArrayList<>(synthesisGraph.keySet());
Collections.sort(signatures); Collections.sort(signatures);
File[] files = synthesizer.allFragmentFiles(); File[] files = synthesizer.allFragmentFiles();
if(logRedundantFiles) { if(logRedundantFiles) {
log.append("\nREDUNDANT ASM FRAGMENT FILES ANALYSIS (if found consider removing them from disk)"); 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) { for(File file : files) {
String fileName = file.getName(); 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 // Synthesize the fragment - and check if the synthesis is as good as the file body
Collection<AsmFragmentSynthesisResult> templates = synthesizer.getBestTemplates(signature, log); Collection<AsmFragmentSynthesisResult> templates = synthesizer.getBestTemplates(signature, log);
boolean isFile = false; boolean isFile = false;
@ -110,7 +112,7 @@ public class AsmFragmentTemplateUsages {
log.append("\nUNUSED ASM FRAGMENT SYNTHESIS RULE ANALYSIS (if found consider removing them)"); log.append("\nUNUSED ASM FRAGMENT SYNTHESIS RULE ANALYSIS (if found consider removing them)");
final Collection<AsmFragmentTemplateSynthesisRule> allRules = AsmFragmentTemplateSynthesisRuleManager.getAllSynthesisRules(); final Collection<AsmFragmentTemplateSynthesisRule> allRules = AsmFragmentTemplateSynthesisRuleManager.getAllSynthesisRules();
for(String signature : signatures) { for(AsmFragmentSignature signature : signatures) {
LinkedList<AsmFragmentSynthesisResult> templates = new LinkedList<>(synthesizer.getBestTemplates(signature, log)); LinkedList<AsmFragmentSynthesisResult> templates = new LinkedList<>(synthesizer.getBestTemplates(signature, log));
while(!templates.isEmpty()) { while(!templates.isEmpty()) {
final AsmFragmentSynthesisResult template = templates.pop(); final AsmFragmentSynthesisResult template = templates.pop();
@ -128,7 +130,7 @@ public class AsmFragmentTemplateUsages {
log.append("\nDETAILED ASM FILE USAGES"); log.append("\nDETAILED ASM FILE USAGES");
// Find all file templates // Find all file templates
List<AsmFragmentSynthesisResult> fileTemplates = new ArrayList<>(); List<AsmFragmentSynthesisResult> fileTemplates = new ArrayList<>();
for(String signature : signatures) { for(AsmFragmentSignature signature : signatures) {
Collection<AsmFragmentSynthesisResult> templates = synthesisGraph.get(signature).getBestTemplates(); Collection<AsmFragmentSynthesisResult> templates = synthesisGraph.get(signature).getBestTemplates();
for(AsmFragmentSynthesisResult template : templates) { for(AsmFragmentSynthesisResult template : templates) {
if(template.isFile()) { if(template.isFile()) {
@ -143,7 +145,7 @@ public class AsmFragmentTemplateUsages {
if(logAllDetails) { if(logAllDetails) {
log.append("\nDETAILED ASM FRAGMENT USAGES"); log.append("\nDETAILED ASM FRAGMENT USAGES");
List<AsmFragmentSynthesisResult> allTemplates = new ArrayList<>(); List<AsmFragmentSynthesisResult> allTemplates = new ArrayList<>();
for(String signature : signatures) { for(AsmFragmentSignature signature : signatures) {
Collection<AsmFragmentSynthesisResult> templates = synthesisGraph.get(signature).getBestTemplates(); Collection<AsmFragmentSynthesisResult> templates = synthesisGraph.get(signature).getBestTemplates();
allTemplates.addAll(templates); allTemplates.addAll(templates);
} }
@ -155,14 +157,13 @@ public class AsmFragmentTemplateUsages {
private static void logTemplatesByUsage(AsmFragmentTemplateSynthesizer synthesizer, CompileLog log, List<AsmFragmentSynthesisResult> templates, boolean logBody) { private static void logTemplatesByUsage(AsmFragmentTemplateSynthesizer synthesizer, CompileLog log, List<AsmFragmentSynthesisResult> templates, boolean logBody) {
// Sort by usage // Sort by usage
Collections.sort(templates, (o1, o2) -> { templates.sort((o1, o2) -> {
Integer u1 = fragmentTemplateUsage.get(o1); Integer u1 = fragmentTemplateUsage.get(o1);
Integer u2 = fragmentTemplateUsage.get(o2); Integer u2 = fragmentTemplateUsage.get(o2);
if(u1 == null) u1 = 0; if (u1 == null) u1 = 0;
if(u2 == null) u2 = 0; if (u2 == null) u2 = 0;
return u2 - u1; return u2 - u1;
} });
);
// Output // Output
for(AsmFragmentSynthesisResult template : templates) { for(AsmFragmentSynthesisResult template : templates) {
Integer usage = fragmentTemplateUsage.get(template); 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.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.CommonTokenStream;
import java.util.Objects;
/** /**
* A signature of an ASM fragment. * A signature of an ASM fragment.
* The signature captures the operation performed by the fragment and the types of the parameters. * 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> * 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. * Parses a signature name to a typed signature.
*
* @param sigName The signature name (created by signature.getName()) * @param sigName The signature name (created by signature.getName())
* @return The signature * @return The signature
*/ */
@ -34,10 +37,36 @@ public interface AsmFragmentSignature {
return instantiator.visitSignature(sigCtx); 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>. * 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 lValue;
final private AsmFragmentSignatureExpr rValue; final private AsmFragmentSignatureExpr rValue;
@ -56,7 +85,7 @@ public interface AsmFragmentSignature {
/** /**
* ASM fragment signature for a conditional jump <code>if(A) goto B</code>. * 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; final private AsmFragmentSignatureExpr procedure;
@ -73,7 +102,7 @@ public interface AsmFragmentSignature {
/** /**
* ASM fragment signature for a conditional jump <code>if(A) goto B</code>. * 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 condition;
final private AsmFragmentSignatureExpr label; final private AsmFragmentSignatureExpr label;
@ -92,7 +121,7 @@ public interface AsmFragmentSignature {
/** /**
* ASM fragment signature for a stand-alone expression with a side-effect. * ASM fragment signature for a stand-alone expression with a side-effect.
*/ */
class ExprSideEffect implements AsmFragmentSignature { class ExprSideEffect extends AsmFragmentSignatureBase {
final private AsmFragmentSignatureExpr expr; 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; 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; package dk.camelot64.kickc.fragment.synthesis;
import dk.camelot64.kickc.fragment.AsmFragmentClobber; import dk.camelot64.kickc.fragment.AsmFragmentClobber;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import java.util.*; import java.util.*;
@ -14,7 +15,7 @@ public class AsmFragmentSynthesis {
/** /**
* The signature of the fragment template being synthesized. * 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 * 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 * @param signature The signature of the fragment template to load/synthesize
*/ */
AsmFragmentSynthesis(String signature) { AsmFragmentSynthesis(AsmFragmentSignature signature) {
this.signature = signature; this.signature = signature;
this.bestTemplates = new LinkedHashMap<>(); this.bestTemplates = new LinkedHashMap<>();
this.synthesisOptions = new LinkedHashSet<>(); this.synthesisOptions = new LinkedHashSet<>();
@ -163,7 +164,7 @@ public class AsmFragmentSynthesis {
return bestTemplates.values(); return bestTemplates.values();
} }
public String getSignature() { public AsmFragmentSignature getSignature() {
return signature; return signature;
} }
} }

View File

@ -1,5 +1,7 @@
package dk.camelot64.kickc.fragment.synthesis; package dk.camelot64.kickc.fragment.synthesis;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import java.util.List; import java.util.List;
import java.util.Objects; 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. * 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. * 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. * 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 signature the signature of the fragment template being synthesized.
* @param rule The synthesis rule capable of synthesizing this template from the sub-fragment. * @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.signature = signature;
this.rule = rule; this.rule = rule;
this.subSignatures = rule.getSubSignatures(signature); this.subSignatures = rule.getSubSignatures(signature);
} }
public String getSignature() { public AsmFragmentSignature getSignature() {
return signature; return signature;
} }
List<String> getSubSignatures() { List<AsmFragmentSignature> getSubSignatures() {
return subSignatures; 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.AsmFragmentClobber;
import dk.camelot64.kickc.fragment.AsmFragmentTemplate; import dk.camelot64.kickc.fragment.AsmFragmentTemplate;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import java.util.List; import java.util.List;
@ -18,20 +19,20 @@ public class AsmFragmentSynthesisResult {
/** /**
* true if the fragment was loaded from disk. * 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. * 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. * 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. * 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) { public AsmFragmentSynthesisResult(AsmFragmentTemplate fragment, boolean file, boolean cache, AsmFragmentTemplateSynthesisRule synthesis, List<AsmFragmentSynthesisResult> subFragments) {
this.fragment = fragment; this.fragment = fragment;
@ -92,7 +93,7 @@ public class AsmFragmentSynthesisResult {
return fragment.getBody(); return fragment.getBody();
} }
public String getSignature() { public AsmFragmentSignature getSignature() {
return fragment.getSignature(); return fragment.getSignature();
} }
} }

View File

@ -1,6 +1,7 @@
package dk.camelot64.kickc.fragment.synthesis; package dk.camelot64.kickc.fragment.synthesis;
import dk.camelot64.kickc.fragment.AsmFragmentTemplate; import dk.camelot64.kickc.fragment.AsmFragmentTemplate;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import java.util.List; import java.util.List;
@ -15,7 +16,7 @@ public interface AsmFragmentTemplateSynthesisRule {
* @param signature The fragment template signature * @param signature The fragment template signature
* @return true if the rule matches the 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 * 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 * @param signature The signature of the fragment to synthesize
* @return Signatures of the sub-templates that are needed to synthesize the fragment template. * @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. * Synthesize a fragment template from a sub fragment template.
@ -33,5 +34,5 @@ public interface AsmFragmentTemplateSynthesisRule {
* @return The synthesized ASM fragment template. * @return The synthesized ASM fragment template.
* Null if the fragment cannot be synthesized (for instance due to clobber constraints). * 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; package dk.camelot64.kickc.fragment.synthesis;
import dk.camelot64.kickc.fragment.AsmFragmentTemplate; import dk.camelot64.kickc.fragment.AsmFragmentTemplate;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import java.util.*; import java.util.*;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -71,39 +72,42 @@ class AsmFragmentTemplateSynthesisRuleRegex implements AsmFragmentTemplateSynthe
* @param signature The fragment template signature * @param signature The fragment template signature
* @return true if the rule matches the 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) if(sigMatchPattern == null)
sigMatchPattern = Pattern.compile(sigMatch); sigMatchPattern = Pattern.compile(sigMatch);
Matcher m = sigMatchPattern.matcher(signature); Matcher m = sigMatchPattern.matcher(signatureText);
if(m.matches()) { if(m.matches()) {
if(sigAvoid == null) if(sigAvoid == null)
return true; return true;
else { else {
if(sigAvoidPattern == null) if(sigAvoidPattern == null)
sigAvoidPattern = Pattern.compile(sigAvoid); sigAvoidPattern = Pattern.compile(sigAvoid);
Matcher ma = sigAvoidPattern.matcher(signature); Matcher ma = sigAvoidPattern.matcher(signatureText);
return !ma.matches(); return !ma.matches();
} }
} }
return false; return false;
} }
public List<String> getSubSignatures(String signature) { public List<AsmFragmentSignature> getSubSignatures(AsmFragmentSignature signature) {
if(matches(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) { if(mapSignature && bindMappings != null) {
// When mapping the signature we do the map replacement in the signature // When mapping the signature we do the map replacement in the signature
for(String bound : bindMappings.keySet()) { 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 { } else {
return null; return null;
} }
} }
public AsmFragmentTemplate synthesize(String signature, List<AsmFragmentTemplate> subTemplates) { public AsmFragmentTemplate synthesize(AsmFragmentSignature signature, List<AsmFragmentTemplate> subTemplates) {
final AsmFragmentTemplate subTemplate = subTemplates.get(0); final AsmFragmentTemplate subTemplate = subTemplates.get(0);
// if(!matches(signature)) { // if(!matches(signature)) {
// throw new RuntimeException("Synthesis error! Attempting to synthesize on non-matching signature signature:"+signature+" match:"+sigMatch+" avoid:"+sigAvoid); // 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.CompileLog;
import dk.camelot64.kickc.fragment.*; import dk.camelot64.kickc.fragment.*;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import dk.camelot64.kickc.model.TargetCpu; import dk.camelot64.kickc.model.TargetCpu;
import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams; 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 * 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. * 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. */ /** Finalize the fragment template synthesizer. */
void finalize(CompileLog log) { void finalize(CompileLog log) {
@ -73,7 +74,7 @@ public class AsmFragmentTemplateSynthesizer {
} }
public AsmFragmentInstance getFragmentInstance(AsmFragmentInstanceSpec instanceSpec, CompileLog log) { public AsmFragmentInstance getFragmentInstance(AsmFragmentInstanceSpec instanceSpec, CompileLog log) {
String signature = instanceSpec.getSignature(); AsmFragmentSignature signature = instanceSpec.getSignature();
AsmFragmentTemplate fragmentTemplate = getFragmentTemplate(signature, log); AsmFragmentTemplate fragmentTemplate = getFragmentTemplate(signature, log);
// Return the resulting fragment instance // Return the resulting fragment instance
return new AsmFragmentInstance( return new AsmFragmentInstance(
@ -91,14 +92,14 @@ public class AsmFragmentTemplateSynthesizer {
* @param log The log * @param log The log
* @return The best templates (with different clobber profiles) for the signature * @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 // Attempt to find in memory/disk cache
AsmFragmentTemplate bestTemplate = fragmentCache.get(signature); AsmFragmentTemplate bestTemplate = fragmentCache.get(signature);
if (bestTemplate == AsmFragmentTemplateCache.NO_SYNTHESIS) { if (bestTemplate == AsmFragmentTemplateCache.NO_SYNTHESIS) {
if (log.isVerboseFragmentLog()) { if (log.isVerboseFragmentLog()) {
log.append("Unknown fragment " + signature); log.append("Unknown fragment " + signature);
} }
throw new UnknownFragmentException(signature); throw new UnknownFragmentException(signature.getName());
} }
if (bestTemplate != null) { if (bestTemplate != null) {
AsmFragmentTemplateUsages.incUsage(new AsmFragmentSynthesisResult(bestTemplate, false, true, null, new ArrayList<>())); AsmFragmentTemplateUsages.incUsage(new AsmFragmentSynthesisResult(bestTemplate, false, true, null, new ArrayList<>()));
@ -144,7 +145,7 @@ public class AsmFragmentTemplateSynthesizer {
* @param log The compile log * @param log The compile log
* @return The best templates for the passed signature * @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); getOrCreateSynthesis(signature, log);
updateBestTemplates(log); updateBestTemplates(log);
AsmFragmentSynthesis synthesis = getSynthesis(signature); AsmFragmentSynthesis synthesis = getSynthesis(signature);
@ -159,7 +160,7 @@ public class AsmFragmentTemplateSynthesizer {
* *
* @return The entire synthesis graph * @return The entire synthesis graph
*/ */
public Map<String, AsmFragmentSynthesis> getSynthesisGraph() { public Map<AsmFragmentSignature, AsmFragmentSynthesis> getSynthesisGraph() {
return synthesisGraph; return synthesisGraph;
} }
@ -171,7 +172,7 @@ public class AsmFragmentTemplateSynthesizer {
* @return The synthesis used to synthesize the fragment template. * @return The synthesis used to synthesize the fragment template.
* null if the synthesis graph does not contain the synthesis. * null if the synthesis graph does not contain the synthesis.
*/ */
private AsmFragmentSynthesis getSynthesis(String signature) { private AsmFragmentSynthesis getSynthesis(AsmFragmentSignature signature) {
return synthesisGraph.get(signature); return synthesisGraph.get(signature);
} }
@ -184,7 +185,7 @@ public class AsmFragmentTemplateSynthesizer {
* @param log The compile log * @param log The compile log
* @return The synthesis that is used to load/synthesize the best template * @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); AsmFragmentSynthesis synthesis = getSynthesis(signature);
if (synthesis != null) { if (synthesis != null) {
return synthesis; return synthesis;
@ -210,13 +211,13 @@ public class AsmFragmentTemplateSynthesizer {
AsmFragmentSynthesisOption synthesisOption = new AsmFragmentSynthesisOption(signature, rule); AsmFragmentSynthesisOption synthesisOption = new AsmFragmentSynthesisOption(signature, rule);
synthesis.addSynthesisOption(synthesisOption); synthesis.addSynthesisOption(synthesisOption);
if (log.isVerboseFragmentLog()) { 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 // Ensure that all sub-synthesis exist (recursively) - and set their parent options
for (AsmFragmentSynthesisOption synthesisOption : synthesis.getSynthesisOptions()) { for (AsmFragmentSynthesisOption synthesisOption : synthesis.getSynthesisOptions()) {
for (String subSignature : synthesisOption.getSubSignatures()) { for (AsmFragmentSignature subSignature : synthesisOption.getSubSignatures()) {
AsmFragmentSynthesis subSynthesis = getOrCreateSynthesis(subSignature, log); AsmFragmentSynthesis subSynthesis = getOrCreateSynthesis(subSignature, log);
subSynthesis.addParentOption(synthesisOption); subSynthesis.addParentOption(synthesisOption);
} }
@ -256,7 +257,7 @@ public class AsmFragmentTemplateSynthesizer {
for (AsmFragmentSynthesisOption synthesisOption : synthesisOptions) { for (AsmFragmentSynthesisOption synthesisOption : synthesisOptions) {
// for each sub-signature find the best templates // for each sub-signature find the best templates
List<Collection<AsmFragmentSynthesisResult>> subSignatureTemplates = new ArrayList<>(); List<Collection<AsmFragmentSynthesisResult>> subSignatureTemplates = new ArrayList<>();
for (String subSignature : synthesisOption.getSubSignatures()) { for (AsmFragmentSignature subSignature : synthesisOption.getSubSignatures()) {
AsmFragmentSynthesis subSynthesis = getSynthesis(subSignature); AsmFragmentSynthesis subSynthesis = getSynthesis(subSignature);
if (subSynthesis == null) { if (subSynthesis == null) {
throw new RuntimeException("Synthesis Graph Error! Sub-synthesis not found in graph " + subSignature); 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); final AsmFragmentTemplate synthesize = rule.synthesize(synthesis.getSignature(), subFragments);
if (synthesize != null) { if (synthesize != null) {
if (log.isVerboseFragmentLog()) { 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); AsmFragmentSynthesisResult synthesisResult = new AsmFragmentSynthesisResult(synthesize, false, false, rule, subFragmentCombination);
modified |= synthesis.bestTemplateCandidate(synthesisResult); modified |= synthesis.bestTemplateCandidate(synthesisResult);
} else { } else {
if (log.isVerboseFragmentLog()) { 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) { if (modified) {
// The synthesis was modified - update all parents later // The synthesis was modified - update all parents later
for (AsmFragmentSynthesisOption parentOption : synthesis.getParentOptions()) { for (AsmFragmentSynthesisOption parentOption : synthesis.getParentOptions()) {
String parentSignature = parentOption.getSignature(); AsmFragmentSignature parentSignature = parentOption.getSignature();
AsmFragmentSynthesis parentSynthesis = getSynthesis(parentSignature); AsmFragmentSynthesis parentSynthesis = getSynthesis(parentSignature);
if (parentSynthesis == null) { if (parentSynthesis == null) {
throw new RuntimeException("Synthesis Graph Error! Parent synthesis not found in graph " + parentSignature); throw new RuntimeException("Synthesis Graph Error! Parent synthesis not found in graph " + parentSignature);
@ -341,7 +342,7 @@ public class AsmFragmentTemplateSynthesizer {
* @param signature The signature * @param signature The signature
* @return The fragment template from a file. null if the template is not found as a file. * @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<>(); ArrayList<AsmFragmentSynthesisResult> fileTemplates = new ArrayList<>();
List<TargetCpu.Feature> cpuFeatures = targetCpu.getFeatures(); List<TargetCpu.Feature> cpuFeatures = targetCpu.getFeatures();
for (TargetCpu.Feature cpuFeature : cpuFeatures) { for (TargetCpu.Feature cpuFeature : cpuFeatures) {
@ -359,9 +360,11 @@ public class AsmFragmentTemplateSynthesizer {
* @param fragmentFolder The folder to look in * @param fragmentFolder The folder to look in
* @return any fragment with the given signature found in the folder. null if not found. * @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 { try {
File fragmentFile = fragmentFolder.resolve(signature + ".asm").toFile(); File fragmentFile = fragmentFolder.resolve(signatureText + ".asm").toFile();
if (!fragmentFile.exists()) { if (!fragmentFile.exists()) {
return null; return null;
} }
@ -407,6 +410,10 @@ public class AsmFragmentTemplateSynthesizer {
private final String signature; private final String signature;
public UnknownFragmentException(AsmFragmentSignature signature) {
this(signature.getName());
}
public UnknownFragmentException(String signature) { public UnknownFragmentException(String signature) {
super("Fragment not found " + signature); super("Fragment not found " + signature);
this.signature = signature; this.signature = signature;

View File

@ -4,6 +4,7 @@ import dk.camelot64.cpufamily6502.CpuAddressingMode;
import dk.camelot64.cpufamily6502.CpuClobber; import dk.camelot64.cpufamily6502.CpuClobber;
import dk.camelot64.kickc.asm.*; import dk.camelot64.kickc.asm.*;
import dk.camelot64.kickc.fragment.*; import dk.camelot64.kickc.fragment.*;
import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature;
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentTemplateSynthesizer; import dk.camelot64.kickc.fragment.synthesis.AsmFragmentTemplateSynthesizer;
import dk.camelot64.kickc.model.InternalError; import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.*; import dk.camelot64.kickc.model.*;
@ -893,7 +894,13 @@ public class Pass4CodeGeneration {
} else if (statement instanceof StatementAsm) { } else if (statement instanceof StatementAsm) {
StatementAsm statementAsm = (StatementAsm) statement; StatementAsm statementAsm = (StatementAsm) statement;
HashMap<String, Value> bindings = new HashMap<>(); 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); asmFragmentInstance.generate(asm);
AsmChunk currentChunk = asm.getCurrentChunk(); 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 asm The assembler to generate code into
* @param procedure The interrupt procedure * @param procedure The interrupt procedure
@ -933,10 +940,10 @@ public class Pass4CodeGeneration {
String entryName; String entryName;
if (interruptType.contains("clobber")) { if (interruptType.contains("clobber")) {
entryFragment = AsmFragmentInstanceSpecBuilder.interruptEntry(interruptType.replace("clobber", "all"), program); entryFragment = AsmFragmentInstanceSpecBuilder.interruptEntry(interruptType.replace("clobber", "all"), program);
entryName = entryFragment.getSignature().replace("all", "clobber"); entryName = entryFragment.getSignature().getName().replace("all", "clobber");
} else { } else {
entryFragment = AsmFragmentInstanceSpecBuilder.interruptEntry(interruptType, program); entryFragment = AsmFragmentInstanceSpecBuilder.interruptEntry(interruptType, program);
entryName = entryFragment.getSignature(); entryName = entryFragment.getSignature().getName();
} }
try { try {
asm.startChunk(procedure.getRef(), null, "interrupt(" + entryName + ")"); asm.startChunk(procedure.getRef(), null, "interrupt(" + entryName + ")");
@ -958,10 +965,10 @@ public class Pass4CodeGeneration {
String entryName; String entryName;
if (interruptType.contains("clobber")) { if (interruptType.contains("clobber")) {
entryFragment = AsmFragmentInstanceSpecBuilder.interruptExit(interruptType.replace("clobber", "all"), program); entryFragment = AsmFragmentInstanceSpecBuilder.interruptExit(interruptType.replace("clobber", "all"), program);
entryName = entryFragment.getSignature().replace("all", "clobber"); entryName = entryFragment.getSignature().getName().replace("all", "clobber");
} else { } else {
entryFragment = AsmFragmentInstanceSpecBuilder.interruptExit(interruptType, program); entryFragment = AsmFragmentInstanceSpecBuilder.interruptExit(interruptType, program);
entryName = entryFragment.getSignature(); entryName = entryFragment.getSignature().getName();
} }
asm.startChunk(procedure.getRef(), null, "interrupt(" + entryName + ")"); asm.startChunk(procedure.getRef(), null, "interrupt(" + entryName + ")");
try { try {

View File

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