1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-01-18 07:30:22 +00:00

separated synthesis from fragment tempaltes.

This commit is contained in:
jespergravgaard 2021-12-28 20:39:51 +01:00
parent 36936efe80
commit 24049a12c1
10 changed files with 738 additions and 660 deletions

View File

@ -1,10 +1,10 @@
package dk.camelot64.kickc; package dk.camelot64.kickc;
import dk.camelot64.kickc.asm.AsmProgram; import dk.camelot64.kickc.asm.AsmProgram;
import dk.camelot64.kickc.fragment.AsmFragmentTemplate; import dk.camelot64.kickc.fragment.AsmFragmentTemplateUsages;
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;
import dk.camelot64.kickc.fragment.AsmFragmentTemplateUsages;
import dk.camelot64.kickc.model.*; import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.statements.StatementSource; import dk.camelot64.kickc.model.statements.StatementSource;
import dk.camelot64.kickc.model.symbols.Procedure; import dk.camelot64.kickc.model.symbols.Procedure;
@ -275,8 +275,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<AsmFragmentTemplate> fragmentTemplates = cpuSynthesizer.getBestTemplates(fragment, compiler.getLog()); Collection<AsmFragmentSynthesisResult> fragmentTemplates = cpuSynthesizer.getBestTemplates(fragment, compiler.getLog());
for(AsmFragmentTemplate fragmentTemplate : fragmentTemplates) { for(AsmFragmentSynthesisResult fragmentTemplate : fragmentTemplates) {
AsmFragmentTemplateUsages.logTemplate(compiler.getLog(), fragmentTemplate, ""); AsmFragmentTemplateUsages.logTemplate(compiler.getLog(), fragmentTemplate, "");
} }
if(fragmentTemplates.size() == 0) { if(fragmentTemplates.size() == 0) {
@ -359,7 +359,7 @@ public class KickC implements Callable<Integer> {
} }
StringBuilder CFileNames = new StringBuilder(); StringBuilder CFileNames = new StringBuilder();
cFiles.stream().forEach(path -> CFileNames.append(path.toString()).append(" ")); cFiles.forEach(path -> CFileNames.append(path.toString()).append(" "));
Map<String, String> effectiveDefines = new LinkedHashMap<>(); Map<String, String> effectiveDefines = new LinkedHashMap<>();
effectiveDefines.put("__KICKC__", "1"); effectiveDefines.put("__KICKC__", "1");

View File

@ -2,7 +2,6 @@ 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.synthesis.AsmFragmentTemplateSynthesisRule;
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;
@ -19,6 +18,7 @@ import dk.camelot64.kickc.parser.AsmParser;
import dk.camelot64.kickc.parser.KickCParser; import dk.camelot64.kickc.parser.KickCParser;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Objects;
/** /**
* An ASM fragment template usable for generating KickAssembler code for different bindings. * An ASM fragment template usable for generating KickAssembler code for different bindings.
@ -26,43 +26,24 @@ import java.util.LinkedHashMap;
*/ */
public class AsmFragmentTemplate { public class AsmFragmentTemplate {
/** true if the fragment was loaded from disk. */
private boolean file;
/** true if the fragment was loaded from the disk cache. */
private boolean cache;
/** The fragment template signature name. */ /** The fragment template signature name. */
private final String signature; private final String signature;
/** The fragment template body */
private String body;
/** The synthesis that created the fragment. null if the fragment template was loaded. */
private AsmFragmentTemplateSynthesisRule synthesis;
/** The sub fragment template that the synthesis modified to create this. null if the fragment template was loaded. */
private AsmFragmentTemplate subFragment;
/** The target CPU. */ /** The target CPU. */
private final TargetCpu targetCpu; private final TargetCpu targetCpu;
/** The parsed ASM lines. Initially null. Will be non-null, is the template is ever used to generate ASM code. */ /** The fragment template body */
private String body;
/** The parsed ASM lines. Initially null. Non-null after the template is used to generate ASM code. */
private KickCParser.AsmLinesContext bodyAsm; private KickCParser.AsmLinesContext bodyAsm;
/** The ASM clobber of the fragment. */ /** The ASM clobber of the fragment. Initially null. Non-null after the template is used to generate ASM code.*/
private AsmFragmentClobber clobber; private AsmFragmentClobber clobber;
/** The cycles consumed by the ASM of the fragment. */ /** 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, boolean cache) { public AsmFragmentTemplate(String signature, String body, TargetCpu targetCpu) {
this.signature = signature; this.signature = signature;
this.body = body; this.body = body;
this.targetCpu = targetCpu; this.targetCpu = targetCpu;
this.file = true;
this.cache = cache;
}
public AsmFragmentTemplate(String signature, String body, AsmFragmentTemplateSynthesisRule synthesis, AsmFragmentTemplate subFragment) {
this.signature = signature;
this.body = body;
this.synthesis = synthesis;
this.subFragment = subFragment;
this.targetCpu = subFragment.targetCpu;
this.file = false;
this.cache = false;
} }
/** /**
@ -173,7 +154,7 @@ public class AsmFragmentTemplate {
this.cycles = asm.getCycles(); this.cycles = asm.getCycles();
} }
String getSignature() { public String getSignature() {
return signature; return signature;
} }
@ -206,43 +187,16 @@ public class AsmFragmentTemplate {
return cycles; return cycles;
} }
public boolean isFile() {
return file;
}
public boolean isCache() {
return cache;
}
AsmFragmentTemplateSynthesisRule getSynthesis() {
return synthesis;
}
AsmFragmentTemplate getSubFragment() {
return subFragment;
}
public String getName() {
StringBuilder name = new StringBuilder();
name.append(signature);
if(synthesis != null) {
name.append(" < ");
name.append(subFragment.getName());
}
return name.toString();
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
AsmFragmentTemplate that = (AsmFragmentTemplate) o; AsmFragmentTemplate that = (AsmFragmentTemplate) o;
return getName().equals(that.getName()); return Objects.equals(signature, that.signature) && targetCpu == that.targetCpu && Objects.equals(body, that.body);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return getName().hashCode(); return Objects.hash(signature, targetCpu, body);
} }
} }

View File

@ -48,7 +48,7 @@ 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, false); public static AsmFragmentTemplate NO_SYNTHESIS = new AsmFragmentTemplate("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 ";
@ -189,7 +189,7 @@ public class AsmFragmentTemplateCache {
cache.put(signature, NO_SYNTHESIS); cache.put(signature, NO_SYNTHESIS);
} else { } else {
CharStream fragmentCharStream = CharStreams.fromString(bodyString); CharStream fragmentCharStream = CharStreams.fromString(bodyString);
AsmFragmentTemplate template = new AsmFragmentTemplate(signature, AsmFragmentTemplateSynthesizer.fixNewlines(fragmentCharStream.toString()), targetCpu, true); AsmFragmentTemplate template = new AsmFragmentTemplate(signature, AsmFragmentTemplateSynthesizer.fixNewlines(fragmentCharStream.toString()), targetCpu);
cache.put(signature, template); cache.put(signature, template);
} }
} }

View File

@ -1,9 +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.synthesis.AsmFragmentTemplateSynthesisRule; import dk.camelot64.kickc.fragment.synthesis.*;
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentTemplateSynthesisRuleManager;
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentTemplateSynthesizer;
import java.io.File; import java.io.File;
import java.util.*; import java.util.*;
@ -12,24 +10,25 @@ import java.util.*;
public class AsmFragmentTemplateUsages { public class AsmFragmentTemplateUsages {
/** Usage Statistics for fragment templates. */ /** Usage Statistics for fragment templates. */
private static Map<AsmFragmentTemplate, Integer> fragmentTemplateUsage = new HashMap<>(); private static Map<AsmFragmentSynthesisResult, Integer> fragmentTemplateUsage = new HashMap<>();
/** /**
* Count one usage of ASM fragment templates - directly or through synthesis * Count one usage of ASM fragment templates - directly or through synthesis
* *
* @param fragmentTemplate The template to increment usage of * @param fragmentTemplate The template to increment usage of
*/ */
public static void incUsage(AsmFragmentTemplate fragmentTemplate) { public static void incUsage(AsmFragmentSynthesisResult fragmentTemplate) {
Integer usage = fragmentTemplateUsage.get(fragmentTemplate); Integer usage = fragmentTemplateUsage.get(fragmentTemplate);
if(usage == null) { if(usage == null) {
usage = 0; usage = 0;
} }
fragmentTemplateUsage.put(fragmentTemplate, usage + 1); fragmentTemplateUsage.put(fragmentTemplate, usage + 1);
AsmFragmentTemplate subFragment = fragmentTemplate.getSubFragment(); for (AsmFragmentSynthesisResult subFragment : fragmentTemplate.getSubFragments()) {
if (subFragment != null) { if (subFragment != null) {
incUsage(subFragment); incUsage(subFragment);
} }
} }
}
/** /**
* Log the usage of all template fragemnts (both loaded and synthesized). * Log the usage of all template fragemnts (both loaded and synthesized).
@ -38,7 +37,7 @@ 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, AsmFragmentTemplateSynthesizer.AsmFragmentSynthesis> synthesisGraph = Map<String, AsmFragmentSynthesis> synthesisGraph =
synthesizer.getSynthesisGraph(); synthesizer.getSynthesisGraph();
ArrayList<String> signatures = new ArrayList<>(synthesisGraph.keySet()); ArrayList<String> signatures = new ArrayList<>(synthesisGraph.keySet());
Collections.sort(signatures); Collections.sort(signatures);
@ -51,29 +50,21 @@ public class AsmFragmentTemplateUsages {
String fileName = file.getName(); String fileName = file.getName();
String signature = fileName.substring(0, fileName.length() - 4); String signature = fileName.substring(0, fileName.length() - 4);
// 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<AsmFragmentTemplate> templates = synthesizer.getBestTemplates(signature, log); Collection<AsmFragmentSynthesisResult> templates = synthesizer.getBestTemplates(signature, log);
boolean isFile = false; boolean isFile = false;
for(AsmFragmentTemplate template : templates) { for(AsmFragmentSynthesisResult template : templates) {
isFile |= template.isFile(); isFile |= template.isFile();
} }
if(!isFile) { if(!isFile) {
StringBuilder templateNames = new StringBuilder(); StringBuilder templateNames = new StringBuilder();
boolean first = true; boolean first = true;
for(AsmFragmentTemplate template : templates) { for(AsmFragmentSynthesisResult template : templates) {
templateNames.append(template.getName()); templateNames.append(template.getName());
if(first) { if(first) {
first = false; first = false;
} else { } else {
templateNames.append(" / "); templateNames.append(" / ");
} }
// Check if the synthesis uses a file marked as redundant
AsmFragmentTemplate sourceFileTemplate = template;
while(!sourceFileTemplate.isFile()) {
sourceFileTemplate = sourceFileTemplate.getSubFragment();
}
if(redundantSignatures.contains(sourceFileTemplate.getSignature())) {
throw new RuntimeException("Problem in redundancy analysis! " + sourceFileTemplate.getSignature() + ".asm seems redundant but is needed for synthesis of " + signature);
}
} }
log.append("rm " + signature + ".asm #synthesized better ASM by " + templateNames); log.append("rm " + signature + ".asm #synthesized better ASM by " + templateNames);
redundantSignatures.add(signature); redundantSignatures.add(signature);
@ -86,13 +77,13 @@ public class AsmFragmentTemplateUsages {
for(File file : files) { for(File file : files) {
String fileName = file.getName(); String fileName = file.getName();
String signature = fileName.substring(0, fileName.length() - 4); String signature = fileName.substring(0, fileName.length() - 4);
AsmFragmentTemplateSynthesizer.AsmFragmentSynthesis asmFragmentSynthesis = synthesisGraph.get(signature); AsmFragmentSynthesis asmFragmentSynthesis = synthesisGraph.get(signature);
Collection<AsmFragmentTemplate> templates = asmFragmentSynthesis.getBestTemplates(); Collection<AsmFragmentSynthesisResult> templates = asmFragmentSynthesis.getBestTemplates();
if(templates != null && templates.size() > 0) { if(templates != null && templates.size() > 0) {
// The template has been loaded / synthesized - is the usage count zero? // The template has been loaded / synthesized - is the usage count zero?
boolean allZero = true; boolean allZero = true;
Integer fileUsage = null; Integer fileUsage = null;
for(AsmFragmentTemplate template : templates) { for(AsmFragmentSynthesisResult template : templates) {
Integer usage = fragmentTemplateUsage.get(template); Integer usage = fragmentTemplateUsage.get(template);
if(usage == null) usage = 0; if(usage == null) usage = 0;
if(usage > 0) { if(usage > 0) {
@ -118,16 +109,16 @@ public class AsmFragmentTemplateUsages {
if(logUnusedRules) { if(logUnusedRules) {
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(String signature : signatures) {
Collection<AsmFragmentTemplate> templates = LinkedList<AsmFragmentSynthesisResult> templates = new LinkedList<>(synthesizer.getBestTemplates(signature, log));
synthesizer.getBestTemplates(signature, log); while(!templates.isEmpty()) {
for(AsmFragmentTemplate template : templates) { final AsmFragmentSynthesisResult template = templates.pop();
while(template.getSynthesis()!=null) {
allRules.remove(template.getSynthesis()); allRules.remove(template.getSynthesis());
template = template.getSubFragment(); templates.addAll(template.getSubFragments());
}
} }
} }
for(AsmFragmentTemplateSynthesisRule rule : allRules) { for(AsmFragmentTemplateSynthesisRule rule : allRules) {
log.append("Synthesis Rule Unused: - "+rule.toString()); log.append("Synthesis Rule Unused: - "+rule.toString());
} }
@ -136,10 +127,10 @@ public class AsmFragmentTemplateUsages {
if(logFileDetails) { if(logFileDetails) {
log.append("\nDETAILED ASM FILE USAGES"); log.append("\nDETAILED ASM FILE USAGES");
// Find all file templates // Find all file templates
List<AsmFragmentTemplate> fileTemplates = new ArrayList<>(); List<AsmFragmentSynthesisResult> fileTemplates = new ArrayList<>();
for(String signature : signatures) { for(String signature : signatures) {
Collection<AsmFragmentTemplate> templates = synthesisGraph.get(signature).getBestTemplates(); Collection<AsmFragmentSynthesisResult> templates = synthesisGraph.get(signature).getBestTemplates();
for(AsmFragmentTemplate template : templates) { for(AsmFragmentSynthesisResult template : templates) {
if(template.isFile()) { if(template.isFile()) {
fileTemplates.add(template); fileTemplates.add(template);
} }
@ -151,9 +142,9 @@ public class AsmFragmentTemplateUsages {
if(logAllDetails) { if(logAllDetails) {
log.append("\nDETAILED ASM FRAGMENT USAGES"); log.append("\nDETAILED ASM FRAGMENT USAGES");
List<AsmFragmentTemplate> allTemplates = new ArrayList<>(); List<AsmFragmentSynthesisResult> allTemplates = new ArrayList<>();
for(String signature : signatures) { for(String signature : signatures) {
Collection<AsmFragmentTemplate> templates = synthesisGraph.get(signature).getBestTemplates(); Collection<AsmFragmentSynthesisResult> templates = synthesisGraph.get(signature).getBestTemplates();
allTemplates.addAll(templates); allTemplates.addAll(templates);
} }
logTemplatesByUsage(synthesizer, log, allTemplates, logDetailsBody); logTemplatesByUsage(synthesizer, log, allTemplates, logDetailsBody);
@ -162,7 +153,7 @@ public class AsmFragmentTemplateUsages {
} }
private static void logTemplatesByUsage(AsmFragmentTemplateSynthesizer synthesizer, CompileLog log, List<AsmFragmentTemplate> 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) -> { Collections.sort(templates, (o1, o2) -> {
Integer u1 = fragmentTemplateUsage.get(o1); Integer u1 = fragmentTemplateUsage.get(o1);
@ -173,14 +164,14 @@ public class AsmFragmentTemplateUsages {
} }
); );
// Output // Output
for(AsmFragmentTemplate template : templates) { for(AsmFragmentSynthesisResult template : templates) {
Integer usage = fragmentTemplateUsage.get(template); Integer usage = fragmentTemplateUsage.get(template);
if(usage == null) usage = 0; if(usage == null) usage = 0;
AsmFragmentTemplateSynthesizer.AsmFragmentSynthesis synthesis = synthesizer.getOrCreateSynthesis(template.getSignature(), log); AsmFragmentSynthesis synthesis = synthesizer.getOrCreateSynthesis(template.getSignature(), log);
Collection<AsmFragmentTemplate> bestTemplates = synthesis.getBestTemplates(); Collection<AsmFragmentSynthesisResult> bestTemplates = synthesis.getBestTemplates();
log.append(String.format("%8d", usage) + " " + template.getSignature()+" - templates: " + bestTemplates.size()); log.append(String.format("%8d", usage) + " " + template.getSignature()+" - templates: " + bestTemplates.size());
if(logBody) { if(logBody) {
for(AsmFragmentTemplate bestTemplate : bestTemplates) { for(AsmFragmentSynthesisResult bestTemplate : bestTemplates) {
logTemplate(log, bestTemplate, " "); logTemplate(log, bestTemplate, " ");
} }
@ -188,7 +179,7 @@ public class AsmFragmentTemplateUsages {
} }
} }
public static void logTemplate(CompileLog log, AsmFragmentTemplate template, String indent) { public static void logTemplate(CompileLog log, AsmFragmentSynthesisResult template, String indent) {
String prefix; String prefix;
if(template.isCache()) { if(template.isCache()) {
prefix = "cached "; prefix = "cached ";

View File

@ -0,0 +1,169 @@
package dk.camelot64.kickc.fragment.synthesis;
import dk.camelot64.kickc.fragment.AsmFragmentClobber;
import java.util.*;
/**
* The synthesis is capable of loading the fragment from disk or synthesizing it from other fragments using synthesis rules.
* The synthesis caches the best fragments for each clobber profile (loaded or synthesized).
* A node in the synthesis graph.
*/
public class AsmFragmentSynthesis {
/**
* The signature of the fragment template being synthesized.
*/
private final String signature;
/**
* The best template loaded/synthesized so far for each clobber profile
*/
private final Map<AsmFragmentClobber, AsmFragmentSynthesisResult> bestTemplates;
/**
* Options for synthesizing the template from sub-fragments using a specific synthesis rule. Forward edges in the synthesis graph.
*/
private final Set<AsmFragmentSynthesisOption> synthesisOptions;
/**
* Options for synthesizing the other templates from this template using a specific synthesis rule. Backward edges in the synthesis graph.
*/
private final Set<AsmFragmentSynthesisOption> parentOptions;
/**
* The templates loaded from a file. Empty if no file exists for the signature.
*/
private final List<AsmFragmentSynthesisResult> fileTemplates;
/**
* Create a new synthesis
*
* @param signature The signature of the fragment template to load/synthesize
*/
AsmFragmentSynthesis(String signature) {
this.signature = signature;
this.bestTemplates = new LinkedHashMap<>();
this.synthesisOptions = new LinkedHashSet<>();
this.parentOptions = new LinkedHashSet<>();
this.fileTemplates = new ArrayList<>();
}
/**
* Add a synthesis option to the template synthesis.
* The synthesis options can be used for synthesizing the template from sub-fragments using a specific synthesis rule.
*
* @param synthesisOption The option to add
*/
void addSynthesisOption(AsmFragmentSynthesisOption synthesisOption) {
this.synthesisOptions.add(synthesisOption);
}
/**
* Get the options for synthesizing the template from sub-fragments using a specific synthesis rule. Forward edges in the synthesis graph.
*
* @return The options
*/
Collection<AsmFragmentSynthesisOption> getSynthesisOptions() {
return synthesisOptions;
}
/**
* Add a parent. The parent is an option for synthesizing another fragment template from this one using a specific synthesis rule.
*
* @param synthesisOption Thew parent option to add
*/
void addParentOption(AsmFragmentSynthesisOption synthesisOption) {
this.parentOptions.add(synthesisOption);
}
void addFileTemplate(AsmFragmentSynthesisResult fileTemplate) {
this.fileTemplates.add(fileTemplate);
}
List<AsmFragmentSynthesisResult> getFileTemplates() {
return fileTemplates;
}
/**
* Handle a candidate for best template.
* If the candidate is better than the current best for its clobber profile update the best template
*
* @param candidate The template candidate to examine
* @return true if the best template was updated
*/
boolean bestTemplateCandidate(AsmFragmentSynthesisResult candidate) {
AsmFragmentClobber candidateClobber = candidate.getClobber();
double candidateCycles = candidate.getCycles();
// Check if any current best templates are better
Set<AsmFragmentClobber> bestClobbers = new LinkedHashSet<>(bestTemplates.keySet());
for (AsmFragmentClobber bestClobber : bestClobbers) {
AsmFragmentSynthesisResult bestTemplate = bestTemplates.get(bestClobber);
double bestCycles = bestTemplate.getCycles();
if (bestClobber.isTrueSubset(candidateClobber) && bestCycles <= candidateCycles) {
// A better template already found - don't update
return false;
}
if (bestClobber.isSubset(candidateClobber) && bestCycles < candidateCycles) {
// A better template already found - don't update
return false;
}
if (bestClobber.equals(candidateClobber) && bestCycles == candidateCycles && bestTemplate.getBody().compareTo(candidate.getBody()) <= 0) {
// A better template already found - don't update
return false;
}
}
// The candidate is better than some of the current best!
// Remove any current templates that are worse
for (AsmFragmentClobber bestClobber : bestClobbers) {
AsmFragmentSynthesisResult bestTemplate = bestTemplates.get(bestClobber);
double bestCycles = bestTemplate.getCycles();
if (candidateClobber.isTrueSubset(bestClobber) && candidateCycles <= bestCycles) {
// The candidate is better - remove the current template
bestTemplates.remove(bestClobber);
}
if (candidateClobber.isSubset(bestClobber) && candidateCycles < bestCycles) {
// The candidate is better - remove the current template
bestTemplates.remove(bestClobber);
}
if (candidateClobber.equals(bestClobber) && candidateCycles == bestCycles && candidate.getBody().compareTo(bestTemplate.getBody()) <= 0) {
// The candidate is better - remove the current template
bestTemplates.remove(bestClobber);
}
}
// Update the current best
bestTemplates.put(candidateClobber, candidate);
return true;
}
/**
* Get the parent options.
* These are options for synthesizing other templates
* from this template using a specific synthesis rule. Backward edges in the synthesis graph.
*
* @return The parent options.
*/
Set<AsmFragmentSynthesisOption> getParentOptions() {
return parentOptions;
}
/**
* Get the best fragment templates of the synthesis.
* Multiple templates are returned if templates with different clobber profiles exist.
*
* @return The best templates of the synthesis.
*/
public Collection<AsmFragmentSynthesisResult> getBestTemplates() {
return bestTemplates.values();
}
public String getSignature() {
return signature;
}
}

View File

@ -0,0 +1,64 @@
package dk.camelot64.kickc.fragment.synthesis;
import java.util.List;
import java.util.Objects;
/**
* An option for synthesizing a fragment template from a sub-template using a specific synthesis rule. An edge in the synthesis graph.
*/
public class AsmFragmentSynthesisOption {
/**
* The signature of the fragment template being synthesized. The from-node in the graph.
*/
private final String signature;
/**
* The signatures of the sub-fragment templates to synthesize from. The to-nodes in the graph.
*/
private final List<String> subSignatures;
/**
* The synthesis rule capable of synthesizing this template from the sub-fragments.
*/
private final AsmFragmentTemplateSynthesisRule rule;
/**
* Create a synthesis option
*
* @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) {
this.signature = signature;
this.rule = rule;
this.subSignatures = rule.getSubSignatures(signature);
}
public String getSignature() {
return signature;
}
List<String> getSubSignatures() {
return subSignatures;
}
AsmFragmentTemplateSynthesisRule getRule() {
return rule;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AsmFragmentSynthesisOption that = (AsmFragmentSynthesisOption) o;
return Objects.equals(signature, that.signature) &&
Objects.equals(subSignatures, that.subSignatures) &&
Objects.equals(rule, that.rule);
}
@Override
public int hashCode() {
return Objects.hash(signature, subSignatures, rule);
}
}

View File

@ -0,0 +1,98 @@
package dk.camelot64.kickc.fragment.synthesis;
import dk.camelot64.kickc.fragment.AsmFragmentClobber;
import dk.camelot64.kickc.fragment.AsmFragmentTemplate;
import java.util.List;
/**
* A successfully synthesized or loaded fragment.
*/
public class AsmFragmentSynthesisResult {
/**
* The ASM fragment template.
*/
final AsmFragmentTemplate fragment;
/**
* true if the fragment was loaded from disk.
*/
private boolean file;
/**
* true if the fragment was loaded from the disk cache.
*/
private boolean cache;
/**
* The synthesis that created the fragment. null if the fragment template was loaded.
*/
private AsmFragmentTemplateSynthesisRule synthesis;
/**
* The sub fragment template that the synthesis used to create this.
*/
private List<AsmFragmentSynthesisResult> subFragments;
public AsmFragmentSynthesisResult(AsmFragmentTemplate fragment, boolean file, boolean cache, AsmFragmentTemplateSynthesisRule synthesis, List<AsmFragmentSynthesisResult> subFragments) {
this.fragment = fragment;
this.file = file;
this.cache = cache;
this.synthesis = synthesis;
this.subFragments = subFragments;
}
public boolean isFile() {
return file;
}
public boolean isCache() {
return cache;
}
public AsmFragmentTemplateSynthesisRule getSynthesis() {
return synthesis;
}
public AsmFragmentTemplate getFragment() {
return fragment;
}
public List<AsmFragmentSynthesisResult> getSubFragments() {
return subFragments;
}
public String getName() {
StringBuilder name = new StringBuilder();
name.append(fragment.getSignature());
if (synthesis != null) {
name.append(" < ");
if (subFragments.size() == 1) {
name.append(subFragments.get(0).getName());
} else {
for (AsmFragmentSynthesisResult subFragment : subFragments) {
name.append("(");
name.append(subFragment.getName());
name.append(")");
}
}
}
return name.toString();
}
public AsmFragmentClobber getClobber() {
return fragment.getClobber();
}
public double getCycles() {
return fragment.getCycles();
}
public String getBody() {
return fragment.getBody();
}
public String getSignature() {
return fragment.getSignature();
}
}

View File

@ -97,7 +97,7 @@ class AsmFragmentTemplateSynthesisRuleRegex implements AsmFragmentTemplateSynthe
subSignature = subSignature.replace(bound, bindMappings.get(bound)); subSignature = subSignature.replace(bound, bindMappings.get(bound));
} }
} }
return Arrays.asList(subSignature); return Collections.singletonList(subSignature);
} else { } else {
return null; return null;
} }
@ -148,7 +148,7 @@ class AsmFragmentTemplateSynthesisRuleRegex implements AsmFragmentTemplateSynthe
if(newFragment.length() > 0 && newFragment.charAt(newFragment.length() - 1) == '\n') { if(newFragment.length() > 0 && newFragment.charAt(newFragment.length() - 1) == '\n') {
newFragment = new StringBuilder(newFragment.substring(0, newFragment.length() - 1)); newFragment = new StringBuilder(newFragment.substring(0, newFragment.length() - 1));
} }
return new AsmFragmentTemplate(signature, newFragment.toString(), this, subTemplate); return new AsmFragmentTemplate(signature, newFragment.toString(), subTemplate.getTargetCpu());
} }
static String regexpRewriteSignature(String signature, String match, String replace) { static String regexpRewriteSignature(String signature, String match, String replace) {

View File

@ -12,6 +12,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
/** /**
* Provides fragment templates from their signature. * Provides fragment templates from their signature.
@ -99,9 +100,14 @@ public class AsmFragmentTemplateSynthesizer {
} }
throw new UnknownFragmentException(signature); throw new UnknownFragmentException(signature);
} }
if(bestTemplate == null) { if (bestTemplate != null) {
AsmFragmentTemplateUsages.incUsage(new AsmFragmentSynthesisResult(bestTemplate, false, true, null, new ArrayList<>()));
return bestTemplate;
}
AsmFragmentSynthesisResult bestResult = null;
// Attempt to synthesize or load in main fragment folder // Attempt to synthesize or load in main fragment folder
Collection<AsmFragmentTemplate> candidates = getBestTemplates(signature, log); Collection<AsmFragmentSynthesisResult> candidates = getBestTemplates(signature, log);
if (candidates.size() == 0) { if (candidates.size() == 0) {
if (log.isVerboseFragmentLog()) { if (log.isVerboseFragmentLog()) {
log.append("Unknown fragment " + signature); log.append("Unknown fragment " + signature);
@ -110,7 +116,7 @@ public class AsmFragmentTemplateSynthesizer {
throw new UnknownFragmentException(signature); throw new UnknownFragmentException(signature);
} }
double minScore = Double.MAX_VALUE; double minScore = Double.MAX_VALUE;
for(AsmFragmentTemplate candidateTemplate : candidates) { for (AsmFragmentSynthesisResult candidateTemplate : candidates) {
double score = candidateTemplate.getCycles(); double score = candidateTemplate.getCycles();
if (candidateTemplate.getClobber().isClobberZ()) score += 0.25; if (candidateTemplate.getClobber().isClobberZ()) score += 0.25;
if (candidateTemplate.getClobber().isClobberA()) score += 0.5; if (candidateTemplate.getClobber().isClobberA()) score += 0.5;
@ -118,17 +124,15 @@ public class AsmFragmentTemplateSynthesizer {
if (candidateTemplate.getClobber().isClobberX()) score += 1.5; if (candidateTemplate.getClobber().isClobberX()) score += 1.5;
if (score < minScore) { if (score < minScore) {
minScore = score; minScore = score;
bestTemplate = candidateTemplate; bestResult = candidateTemplate;
} }
} }
if (log.isVerboseFragmentLog()) { if (log.isVerboseFragmentLog()) {
log.append("Found best fragment " + bestTemplate.getName() + " score: " + minScore); log.append("Found best fragment " + bestResult.getName() + " score: " + minScore);
} }
fragmentCache.put(signature, bestTemplate); fragmentCache.put(signature, bestResult.getFragment());
} AsmFragmentTemplateUsages.incUsage(bestResult);
// Count usages return bestResult.getFragment();
AsmFragmentTemplateUsages.incUsage(bestTemplate);
return bestTemplate;
} }
@ -140,7 +144,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<AsmFragmentTemplate> getBestTemplates(String signature, CompileLog log) { public Collection<AsmFragmentSynthesisResult> getBestTemplates(String signature, CompileLog log) {
getOrCreateSynthesis(signature, log); getOrCreateSynthesis(signature, log);
updateBestTemplates(log); updateBestTemplates(log);
AsmFragmentSynthesis synthesis = getSynthesis(signature); AsmFragmentSynthesis synthesis = getSynthesis(signature);
@ -150,212 +154,6 @@ public class AsmFragmentTemplateSynthesizer {
return synthesis.getBestTemplates(); return synthesis.getBestTemplates();
} }
/**
* The synthesis is capable of loading the fragment from disk or synthesizing it from other fragments using synthesis rules.
* The synthesis caches the best fragments for each clobber profile (loaded or synthesized).
* A node in the synthesis graph.
*/
public static class AsmFragmentSynthesis {
/** The signature of the fragment template being synthesized. */
private final String signature;
/** The best template loaded/synthesized so far for each clobber profile */
private final Map<AsmFragmentClobber, AsmFragmentTemplate> bestTemplates;
/** Options for synthesizing the template from sub-fragments using a specific synthesis rule. Forward edges in the synthesis graph. */
private final Set<AsmFragmentSynthesisOption> synthesisOptions;
/** Options for synthesizing the other templates from this template using a specific synthesis rule. Backward edges in the synthesis graph. */
private final Set<AsmFragmentSynthesisOption> parentOptions;
/** The templates loaded from a file. Empty if no file exists for the signature. */
private final List<AsmFragmentTemplate> fileTemplates;
/**
* Create a new synthesis
*
* @param signature The signature of the fragment template to load/synthesize
*/
AsmFragmentSynthesis(String signature) {
this.signature = signature;
this.bestTemplates = new LinkedHashMap<>();
this.synthesisOptions = new LinkedHashSet<>();
this.parentOptions = new LinkedHashSet<>();
this.fileTemplates = new ArrayList<>();
}
/**
* Add a synthesis option to the template synthesis.
* The synthesis options can be used for synthesizing the template from sub-fragments using a specific synthesis rule.
*
* @param synthesisOption The option to add
*/
void addSynthesisOption(AsmFragmentSynthesisOption synthesisOption) {
this.synthesisOptions.add(synthesisOption);
}
/**
* Get the options for synthesizing the template from sub-fragments using a specific synthesis rule. Forward edges in the synthesis graph.
*
* @return The options
*/
Collection<AsmFragmentSynthesisOption> getSynthesisOptions() {
return synthesisOptions;
}
/**
* Add a parent. The parent is an option for synthesizing another fragment template from this one using a specific synthesis rule.
*
* @param synthesisOption Thew parent option to add
*/
void addParentOption(AsmFragmentSynthesisOption synthesisOption) {
this.parentOptions.add(synthesisOption);
}
void addFileTemplate(AsmFragmentTemplate fileTemplate) {
this.fileTemplates.add(fileTemplate);
}
List<AsmFragmentTemplate> getFileTemplates() {
return fileTemplates;
}
/**
* Handle a candidate for best template.
* If the candidate is better than the current best for its clobber profile update the best template
*
* @param candidate The template candidate to examine
* @return true if the best template was updated
*/
boolean bestTemplateCandidate(AsmFragmentTemplate candidate) {
AsmFragmentClobber candidateClobber = candidate.getClobber();
double candidateCycles = candidate.getCycles();
// Check if any current best templates are better
Set<AsmFragmentClobber> bestClobbers = new LinkedHashSet<>(bestTemplates.keySet());
for(AsmFragmentClobber bestClobber : bestClobbers) {
AsmFragmentTemplate bestTemplate = bestTemplates.get(bestClobber);
double bestCycles = bestTemplate.getCycles();
if(bestClobber.isTrueSubset(candidateClobber) && bestCycles <= candidateCycles) {
// A better template already found - don't update
return false;
}
if(bestClobber.isSubset(candidateClobber) && bestCycles < candidateCycles) {
// A better template already found - don't update
return false;
}
if(bestClobber.equals(candidateClobber) && bestCycles == candidateCycles && bestTemplate.getBody().compareTo(candidate.getBody()) <= 0) {
// A better template already found - don't update
return false;
}
}
// The candidate is better than some of the current best!
// Remove any current templates that are worse
for(AsmFragmentClobber bestClobber : bestClobbers) {
AsmFragmentTemplate bestTemplate = bestTemplates.get(bestClobber);
double bestCycles = bestTemplate.getCycles();
if(candidateClobber.isTrueSubset(bestClobber) && candidateCycles <= bestCycles) {
// The candidate is better - remove the current template
bestTemplates.remove(bestClobber);
}
if(candidateClobber.isSubset(bestClobber) && candidateCycles < bestCycles) {
// The candidate is better - remove the current template
bestTemplates.remove(bestClobber);
}
if(candidateClobber.equals(bestClobber) && candidateCycles == bestCycles && candidate.getBody().compareTo(bestTemplate.getBody()) < 0) {
// The candidate is better - remove the current template
bestTemplates.remove(bestClobber);
}
}
// Update the current best
bestTemplates.put(candidateClobber, candidate);
return true;
}
/**
* Get the parent options.
* These are options for synthesizing other templates
* from this template using a specific synthesis rule. Backward edges in the synthesis graph.
*
* @return The parent options.
*/
Set<AsmFragmentSynthesisOption> getParentOptions() {
return parentOptions;
}
/**
* Get the best fragment templates of the synthesis.
* Multiple templates are returned if templates with different clobber profiles exist.
*
* @return The best templates of the synthesis.
*/
public Collection<AsmFragmentTemplate> getBestTemplates() {
return bestTemplates.values();
}
public String getSignature() {
return signature;
}
}
/** An option for synthesizing a fragment template from a sub-template using a specific synthesis rule. An edge in the synthesis graph. */
public static class AsmFragmentSynthesisOption {
/** The signature of the fragment template being synthesized. The from-node in the graph. */
private final String signature;
/** The signatures of the sub-fragment templates to synthesize from. The to-nodes in the graph. */
private final List<String> subSignatures;
/** The synthesis rule capable of synthesizing this template from the sub-fragments. */
private final AsmFragmentTemplateSynthesisRule rule;
/**
* Create a synthesis option
*
* @param signature he signature of the fragment template being synthesized.
* @param rule The synthesis rule capable of synthesizing this template from the sub-fragment.
*/
AsmFragmentSynthesisOption(String signature, AsmFragmentTemplateSynthesisRule rule) {
this.signature = signature;
this.rule = rule;
this.subSignatures = rule.getSubSignatures(signature);
}
public String getSignature() {
return signature;
}
List<String> getSubSignatures() {
return subSignatures;
}
AsmFragmentTemplateSynthesisRule getRule() {
return rule;
}
@Override
public boolean equals(Object o) {
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
AsmFragmentSynthesisOption that = (AsmFragmentSynthesisOption) o;
return Objects.equals(signature, that.signature) &&
Objects.equals(subSignatures, that.subSignatures) &&
Objects.equals(rule, that.rule);
}
@Override
public int hashCode() {
return Objects.hash(signature, subSignatures, rule);
}
}
/** /**
* Get the entire synthesis graph. Called by the usage statistics. * Get the entire synthesis graph. Called by the usage statistics.
* *
@ -399,8 +197,8 @@ public class AsmFragmentTemplateSynthesizer {
synthesisGraph.put(signature, synthesis); synthesisGraph.put(signature, synthesis);
queueUpdateBestTemplate(synthesis); queueUpdateBestTemplate(synthesis);
// Load the template from file - if it exists // Load the template from file - if it exists
List<AsmFragmentTemplate> fileTemplates = loadFragmentTemplates(signature); List<AsmFragmentSynthesisResult> fileTemplates = loadFragmentTemplates(signature);
for(AsmFragmentTemplate fileTemplate : fileTemplates) { for (AsmFragmentSynthesisResult fileTemplate : fileTemplates) {
synthesis.addFileTemplate(fileTemplate); synthesis.addFileTemplate(fileTemplate);
if (log.isVerboseFragmentLog()) { if (log.isVerboseFragmentLog()) {
log.append("New fragment synthesis " + signature + " - Successfully loaded " + signature + ".asm"); log.append("New fragment synthesis " + signature + " - Successfully loaded " + signature + ".asm");
@ -450,35 +248,37 @@ public class AsmFragmentTemplateSynthesizer {
AsmFragmentSynthesis synthesis = bestTemplateUpdate.pop(); AsmFragmentSynthesis synthesis = bestTemplateUpdate.pop();
boolean modified = false; boolean modified = false;
// Check if the file template is best in class // Check if the file template is best in class
List<AsmFragmentTemplate> fileTemplates = synthesis.getFileTemplates(); List<AsmFragmentSynthesisResult> fileTemplates = synthesis.getFileTemplates();
for(AsmFragmentTemplate fileTemplate : fileTemplates) { for (AsmFragmentSynthesisResult fileTemplate : fileTemplates) {
modified |= synthesis.bestTemplateCandidate(fileTemplate); modified |= synthesis.bestTemplateCandidate(fileTemplate);
} }
Collection<AsmFragmentSynthesisOption> synthesisOptions = synthesis.getSynthesisOptions(); Collection<AsmFragmentSynthesisOption> synthesisOptions = synthesis.getSynthesisOptions();
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<AsmFragmentTemplate>> subSignatureTemplates = new ArrayList<>(); List<Collection<AsmFragmentSynthesisResult>> subSignatureTemplates = new ArrayList<>();
for (String subSignature : synthesisOption.getSubSignatures()) { for (String 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);
} }
Collection<AsmFragmentTemplate> subTemplates = subSynthesis.getBestTemplates(); Collection<AsmFragmentSynthesisResult> subTemplates = subSynthesis.getBestTemplates();
subSignatureTemplates.add(subTemplates); subSignatureTemplates.add(subTemplates);
} }
AsmFragmentTemplateSynthesisRule rule = synthesisOption.getRule(); AsmFragmentTemplateSynthesisRule rule = synthesisOption.getRule();
// Create all combinations of the best sub-templates // Create all combinations of the best sub-templates
List<List<AsmFragmentTemplate>> combinations = combinations(subSignatureTemplates); List<List<AsmFragmentSynthesisResult>> combinations = combinations(subSignatureTemplates);
for (List<AsmFragmentTemplate> subTemplateCombination : combinations) { for (List<AsmFragmentSynthesisResult> subFragmentCombination : combinations) {
AsmFragmentTemplate synthesized = rule.synthesize(synthesis.getSignature(), subTemplateCombination); final List<AsmFragmentTemplate> subFragments = subFragmentCombination.stream().map(AsmFragmentSynthesisResult::getFragment).collect(Collectors.toList());
if (synthesized != null) { final AsmFragmentTemplate synthesize = rule.synthesize(synthesis.getSignature(), subFragments);
if (synthesize != null) {
if (log.isVerboseFragmentLog()) { if (log.isVerboseFragmentLog()) {
log.append("Fragment synthesis " + synthesis.getSignature() + " - Successfully synthesized from " + String.join(",", synthesisOption.subSignatures)); log.append("Fragment synthesis " + synthesis.getSignature() + " - Successfully synthesized from " + String.join(",", synthesisOption.getSubSignatures()));
} }
modified |= synthesis.bestTemplateCandidate(synthesized); AsmFragmentSynthesisResult synthesisResult = new AsmFragmentSynthesisResult(synthesize, false, false, rule, subFragmentCombination);
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.subSignatures)); log.append("Fragment synthesis " + synthesis.getSignature() + " - Sub clobber prevents synthesis from " + String.join(",", synthesisOption.getSubSignatures()));
} }
} }
} }
@ -506,6 +306,7 @@ public class AsmFragmentTemplateSynthesizer {
/** /**
* Generate all possible combinations of a number of options. * Generate all possible combinations of a number of options.
*
* @param options A list of the options for each position. * @param options A list of the options for each position.
* @param <T> The top of an option * @param <T> The top of an option
* @return A list with all combinations of the passed options on each position. * @return A list with all combinations of the passed options on each position.
@ -540,11 +341,11 @@ 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<AsmFragmentTemplate> loadFragmentTemplates(String signature) { private List<AsmFragmentSynthesisResult> loadFragmentTemplates(String signature) {
ArrayList<AsmFragmentTemplate> 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) {
AsmFragmentTemplate fileFragment = loadFragmentTemplate(signature, baseFragmentFolder.resolve(cpuFeature.getName())); AsmFragmentSynthesisResult fileFragment = loadFragmentTemplate(signature, baseFragmentFolder.resolve(cpuFeature.getName()));
if (fileFragment != null) if (fileFragment != null)
fileTemplates.add(fileFragment); fileTemplates.add(fileFragment);
} }
@ -556,9 +357,9 @@ public class AsmFragmentTemplateSynthesizer {
* *
* @param signature The signature to search for * @param signature The signature to search for
* @param fragmentFolder The folder to look in * @param fragmentFolder The folder to look in
* @return any fragment with the gicen 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 AsmFragmentTemplate loadFragmentTemplate(String signature, Path fragmentFolder) { private AsmFragmentSynthesisResult loadFragmentTemplate(String signature, Path fragmentFolder) {
try { try {
File fragmentFile = fragmentFolder.resolve(signature + ".asm").toFile(); File fragmentFile = fragmentFolder.resolve(signature + ".asm").toFile();
if (!fragmentFile.exists()) { if (!fragmentFile.exists()) {
@ -572,7 +373,8 @@ public class AsmFragmentTemplateSynthesizer {
CharStream fragmentCharStream = CharStreams.fromStream(fragmentStream); CharStream fragmentCharStream = CharStreams.fromStream(fragmentStream);
body = fixNewlines(fragmentCharStream.toString()); body = fixNewlines(fragmentCharStream.toString());
} }
return new AsmFragmentTemplate(signature, body, targetCpu, false); final AsmFragmentTemplate fragment = new AsmFragmentTemplate(signature, body, targetCpu);
return new AsmFragmentSynthesisResult(fragment, true, false, null, new ArrayList<>());
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Error loading fragment file " + signature, e); throw new RuntimeException("Error loading fragment file " + signature, e);
} catch (StringIndexOutOfBoundsException e) { } catch (StringIndexOutOfBoundsException e) {

View File

@ -1,9 +1,9 @@
package dk.camelot64.kickc.test; package dk.camelot64.kickc.test;
import dk.camelot64.kickc.CompileLog; import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.fragment.AsmFragmentTemplate;
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentTemplateSynthesizer;
import dk.camelot64.kickc.fragment.AsmFragmentTemplateUsages; import dk.camelot64.kickc.fragment.AsmFragmentTemplateUsages;
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentSynthesisResult;
import dk.camelot64.kickc.fragment.synthesis.AsmFragmentTemplateSynthesizer;
import dk.camelot64.kickc.model.TargetCpu; import dk.camelot64.kickc.model.TargetCpu;
import dk.camelot64.kickc.model.operators.Operators; import dk.camelot64.kickc.model.operators.Operators;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
@ -196,11 +196,11 @@ public class TestFragments {
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);
//log.setVerboseFragmentLog(true); //log.setVerboseFragmentLog(true);
List<AsmFragmentTemplate> templates = List<AsmFragmentSynthesisResult> templates =
new ArrayList<>(asmFragmentTemplateSynthesizer.getBestTemplates(signature, log)); new ArrayList<>(asmFragmentTemplateSynthesizer.getBestTemplates(signature, log));
if(templates.size() > 0) { if(templates.size() > 0) {
log.append(""); log.append("");
for(AsmFragmentTemplate template : templates) { for(AsmFragmentSynthesisResult template : templates) {
AsmFragmentTemplateUsages.logTemplate(log, template, ""); AsmFragmentTemplateUsages.logTemplate(log, template, "");
} }
log.append(""); log.append("");
@ -227,14 +227,14 @@ public class TestFragments {
String signature = sigs.get(testIdx); String signature = sigs.get(testIdx);
List<AsmFragmentTemplate> templates = List<AsmFragmentSynthesisResult> templates =
new ArrayList<>(asmFragmentTemplateSynthesizer.getBestTemplates(signature, log)); new ArrayList<>(asmFragmentTemplateSynthesizer.getBestTemplates(signature, log));
Collections.sort(templates, Comparator.comparing(AsmFragmentTemplate::getClobber)); Collections.sort(templates, Comparator.comparing(AsmFragmentSynthesisResult::getClobber));
if(templates.size() == 0) { if(templates.size() == 0) {
log.append("CANNOT SYNTHESIZE " + signature); log.append("CANNOT SYNTHESIZE " + signature);
} }
for(AsmFragmentTemplate template : templates) { for(AsmFragmentSynthesisResult template : templates) {
String prefix = ""; String prefix = "";
if(template.isCache()) { if(template.isCache()) {
prefix = "cached "; prefix = "cached ";