From 03150c83c37d16e079cce7fe80f5a7b01d7073c2 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sat, 2 Apr 2022 08:27:34 +0200 Subject: [PATCH] Working on ASM fragment template interface and implementation. Currently synthesizing even simple fragments uses up all memory. --- .../kickc/fragment/AsmFragmentTemplate.java | 10 +- .../fragment/AsmFragmentTemplateCache.java | 12 +- .../fragment/AsmFragmentTemplateImpl.java | 13 +- .../fragment/AsmFragmentTemplateParser.java | 6 +- .../fragment/AsmTemplateBodyPrinter.java | 4 +- .../synthesis/AsmFragmentSynthesis.java | 302 ++++++++++-------- .../synthesis/AsmFragmentSynthesisResult.java | 7 +- ...AsmFragmentTemplateSynthesisRuleRegex.java | 3 +- .../camelot64/kickc/test/TestFragments.java | 2 +- .../kickc/test/TestProgramsFast.java | 2 +- 10 files changed, 190 insertions(+), 171 deletions(-) diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplate.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplate.java index 6a96eb14c..d8f8531ed 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplate.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplate.java @@ -23,15 +23,7 @@ public interface AsmFragmentTemplate { * @return The target CPU */ TargetCpu getTargetCpu(); - - /** - * Get the ASM body as a string. - * The ASM body contains parameter placeholders where bindings will be used to place actual values. - * - * @return The ASM body - */ - String getBody(); - + /** * Get the ASM body as parsed ASM. * The ASM body contains parameter placeholders where bindings will be used to place actual values. diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateCache.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateCache.java index d9884a762..087cd4d45 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateCache.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateCache.java @@ -47,7 +47,7 @@ public class AsmFragmentTemplateCache { /** Special singleton representing that the fragment can not be synthesized or loaded. */ public static AsmFragmentTemplate NO_SYNTHESIS = - new AsmFragmentTemplateImpl(new AsmFragmentSignature.Singleton("NO_SYNTHESIS"), "NO_SYNTHESIS", null, null, null, null); + new AsmFragmentTemplateImpl(new AsmFragmentSignature.Singleton("NO_SYNTHESIS"), null, null, null, null); /** Prefix for the fragment hash file header. */ public static final String HASH_HEADER = "//KICKC FRAGMENT CACHE "; @@ -184,7 +184,7 @@ public class AsmFragmentTemplateCache { private static void addFragment(LinkedHashMap cache, String signatureText, StringBuilder body, TargetCpu targetCpu) { AsmFragmentSignature signature = AsmFragmentSignature.parse(signatureText); final String bodyString = body.toString(); - if(bodyString.startsWith(NO_SYNTHESIS.getBody())) { + if(bodyString.startsWith("NO_SYNTHESIS")) { cache.put(signature, NO_SYNTHESIS); } else { AsmFragmentTemplate template = AsmFragmentTemplateParser.parse(signature, AsmFragmentTemplateParser.fixNewlines(bodyString), targetCpu); @@ -215,10 +215,12 @@ public class AsmFragmentTemplateCache { AsmFragmentTemplate fragmentTemplate = this.cache.get(signature); fragmentFilePrint.println(FRAGMENT_HEADER + signature); if(fragmentTemplate == NO_SYNTHESIS) { - fragmentFilePrint.println(NO_SYNTHESIS.getBody()); + fragmentFilePrint.println("NO_SYNTHESIS"); } else { - if(fragmentTemplate.getBody() != null) - fragmentFilePrint.println(fragmentTemplate.getBody()); + if(fragmentTemplate.getBodyAsm() != null) { + final String bodyString = AsmTemplateBodyPrinter.print(fragmentTemplate.getBodyAsm()); + fragmentFilePrint.println(bodyString); + } } } fragmentFilePrint.close(); diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateImpl.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateImpl.java index c5a6a8954..dd9960933 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateImpl.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateImpl.java @@ -16,8 +16,6 @@ public class AsmFragmentTemplateImpl implements AsmFragmentTemplate { private final AsmFragmentSignature signature; /** The target CPU. */ private final TargetCpu targetCpu; - /** The fragment template body */ - private final String body; /** The parsed ASM lines. Initially null. Non-null after the template is used to generate ASM code. */ private final KickCParser.AsmLinesContext bodyAsm; @@ -26,9 +24,8 @@ public class AsmFragmentTemplateImpl implements AsmFragmentTemplate { /** The cycles consumed by the ASM of the fragment. Initially null. Non-null after the template is used to generate ASM code. */ private final Double cycles; - AsmFragmentTemplateImpl(AsmFragmentSignature signature, String body, TargetCpu targetCpu, KickCParser.AsmLinesContext bodyAsm, AsmFragmentClobber clobber, Double cycles) { + AsmFragmentTemplateImpl(AsmFragmentSignature signature, TargetCpu targetCpu, KickCParser.AsmLinesContext bodyAsm, AsmFragmentClobber clobber, Double cycles) { this.signature = signature; - this.body = body; this.targetCpu = targetCpu; this.bodyAsm = bodyAsm; this.clobber = clobber; @@ -39,10 +36,6 @@ public class AsmFragmentTemplateImpl implements AsmFragmentTemplate { return signature; } - public String getBody() { - return body; - } - @Override public KickCParser.AsmLinesContext getBodyAsm() { return bodyAsm; @@ -65,11 +58,11 @@ public class AsmFragmentTemplateImpl implements AsmFragmentTemplate { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AsmFragmentTemplateImpl that = (AsmFragmentTemplateImpl) o; - return Objects.equals(signature, that.signature) && targetCpu == that.targetCpu && Objects.equals(body, that.body); + return signature.equals(that.signature) && targetCpu == that.targetCpu && Objects.equals(bodyAsm, that.bodyAsm); } @Override public int hashCode() { - return Objects.hash(signature, targetCpu, body); + return Objects.hash(signature, targetCpu, bodyAsm); } } diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateParser.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateParser.java index 4b8a58526..2babbc630 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateParser.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateParser.java @@ -37,7 +37,7 @@ public class AsmFragmentTemplateParser { */ public static AsmFragmentTemplate parse(AsmFragmentSignature signature, String body, TargetCpu targetCpu) { final ParsedAsmBody parsedAsmBody = parseAsm(signature, targetCpu, body); - final AsmFragmentTemplateImpl asmFragmentTemplate = new AsmFragmentTemplateImpl(signature, body, targetCpu, parsedAsmBody.bodyAsm, parsedAsmBody.clobber, parsedAsmBody.cycles); + final AsmFragmentTemplateImpl asmFragmentTemplate = new AsmFragmentTemplateImpl(signature, targetCpu, parsedAsmBody.bodyAsm, parsedAsmBody.clobber, parsedAsmBody.cycles); // assertBodyPrint(signature, body, parsedAsmBody.bodyAsm); return asmFragmentTemplate; } @@ -90,7 +90,7 @@ public class AsmFragmentTemplateParser { * @return The ASM fragment template */ public static AsmFragmentTemplate inline(AsmFragmentSignature signature, KickCParser.AsmLinesContext asmBody, TargetCpu targetCpu) { - return new AsmFragmentTemplateImpl(signature, null, targetCpu, asmBody, null, null); + return new AsmFragmentTemplateImpl(signature, targetCpu, asmBody, null, null); } /** @@ -207,7 +207,7 @@ public class AsmFragmentTemplateParser { if (signatureName.contains("c6")) bindings.put("c6", new ConstantInteger(360L)); if (signatureName.contains("la1")) bindings.put("la1", new Label("@1", scope, true)); if (signatureName.startsWith("call_")) bindings.put("la1", new Label("@1", scope, true)); - final AsmFragmentTemplateImpl fragmentTemplate = new AsmFragmentTemplateImpl(signature, body, targetCpu, bodyAsm, null, null); + final AsmFragmentTemplateImpl fragmentTemplate = new AsmFragmentTemplateImpl(signature, targetCpu, bodyAsm, null, null); AsmFragmentInstance fragmentInstance = new AsmFragmentInstance(new Program(), signature, ScopeRef.ROOT, fragmentTemplate, bindings); AsmProgram asm = new AsmProgram(targetCpu); diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmTemplateBodyPrinter.java b/src/main/java/dk/camelot64/kickc/fragment/AsmTemplateBodyPrinter.java index bbbee9939..ef5037c7d 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmTemplateBodyPrinter.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmTemplateBodyPrinter.java @@ -11,7 +11,7 @@ import java.util.List; */ public class AsmTemplateBodyPrinter extends KickCParserBaseVisitor { - private StringBuffer out; + private final StringBuffer out; private AsmTemplateBodyPrinter(StringBuffer out) { this.out = out; @@ -25,7 +25,7 @@ public class AsmTemplateBodyPrinter extends KickCParserBaseVisitor { } private void printTags(List tags) { - tags.stream().forEach(tag -> out.append(" ").append(tag)); + tags.forEach(tag -> out.append(" ").append(tag)); } @Override diff --git a/src/main/java/dk/camelot64/kickc/fragment/synthesis/AsmFragmentSynthesis.java b/src/main/java/dk/camelot64/kickc/fragment/synthesis/AsmFragmentSynthesis.java index ac472eda7..af08914b2 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/synthesis/AsmFragmentSynthesis.java +++ b/src/main/java/dk/camelot64/kickc/fragment/synthesis/AsmFragmentSynthesis.java @@ -2,6 +2,8 @@ package dk.camelot64.kickc.fragment.synthesis; import dk.camelot64.kickc.fragment.AsmFragmentClobber; import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.tree.ParseTree; import java.util.*; @@ -12,159 +14,187 @@ import java.util.*; */ public class AsmFragmentSynthesis { - /** - * The signature of the fragment template being synthesized. - */ - private final AsmFragmentSignature signature; + /** + * The signature of the fragment template being synthesized. + */ + private final AsmFragmentSignature signature; - /** - * The best template loaded/synthesized so far for each clobber profile - */ - private final Map bestTemplates; + /** + * The best template loaded/synthesized so far for each clobber profile + */ + private final Map bestTemplates; - /** - * Options for synthesizing the template from sub-fragments using a specific synthesis rule. Forward edges in the synthesis graph. - */ - private final List synthesisOptions; + /** + * Options for synthesizing the template from sub-fragments using a specific synthesis rule. Forward edges in the synthesis graph. + */ + private final List synthesisOptions; - /** - * Options for synthesizing the other templates from this template using a specific synthesis rule. Backward edges in the synthesis graph. - */ - private final List parentOptions; + /** + * Options for synthesizing the other templates from this template using a specific synthesis rule. Backward edges in the synthesis graph. + */ + private final List parentOptions; - /** - * The templates loaded from a file. Empty if no file exists for the signature. - */ - private final List fileTemplates; + /** + * The templates loaded from a file. Empty if no file exists for the signature. + */ + private final List fileTemplates; - /** - * Create a new synthesis - * - * @param signature The signature of the fragment template to load/synthesize - */ - AsmFragmentSynthesis(AsmFragmentSignature signature) { - this.signature = signature; - this.bestTemplates = new LinkedHashMap<>(); - this.synthesisOptions = new ArrayList<>(); - this.parentOptions = new ArrayList<>(); - this.fileTemplates = new ArrayList<>(); - } + /** + * Create a new synthesis + * + * @param signature The signature of the fragment template to load/synthesize + */ + AsmFragmentSynthesis(AsmFragmentSignature signature) { + this.signature = signature; + this.bestTemplates = new LinkedHashMap<>(); + this.synthesisOptions = new ArrayList<>(); + this.parentOptions = new ArrayList<>(); + 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); - } + /** + * 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 getSynthesisOptions() { - return synthesisOptions; - } + /** + * 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 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); - } + /** + * 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); - } + void addFileTemplate(AsmFragmentSynthesisResult fileTemplate) { + this.fileTemplates.add(fileTemplate); + } - List getFileTemplates() { - return fileTemplates; - } + List 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(); + /** + * 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) { - // Check if any current best templates are better - Set 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; - } + // Check if any current best templates are better + Set bestClobbers = new LinkedHashSet<>(bestTemplates.keySet()); + for(AsmFragmentClobber bestClobber : bestClobbers) { + AsmFragmentSynthesisResult bestTemplate = bestTemplates.get(bestClobber); + if(isBetter(bestTemplate, candidate)) return false; + } - } + // The candidate is better than some current best! - // 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(isBetter(candidate, bestTemplate)) { + // The candidate is better - remove the current template + bestTemplates.remove(bestClobber); + } + } + // Update the current best + bestTemplates.put(candidate.getClobber(), candidate); + return true; + } - // Remove any current templates that are worse - for (AsmFragmentClobber bestClobber : bestClobbers) { - AsmFragmentSynthesisResult bestTemplate = bestTemplates.get(bestClobber); - double bestCycles = bestTemplate.getCycles(); + /** + * Determines if a candidate ASM fragment template is better than another template. + *

+ * The candidate is better if either + *

    + *
  • The clobber of the candidate is a true subset of the other and the number of cycles spent is smaller
  • + *
  • The clobber of the candidate is the same as the other and the number of cycles spent is smaller
  • + *
  • The clobber and number of cycles spent is the same but the body is shorter
  • + *
+ * + * @param candidate The candidate template + * @param other The other template + * @return true if the candidate is better + */ + private boolean isBetter(AsmFragmentSynthesisResult candidate, AsmFragmentSynthesisResult other) { + final AsmFragmentClobber candidateClobber = candidate.getClobber(); + final double candidateCycles = candidate.getCycles(); + final double otherCycles = other.getCycles(); + final AsmFragmentClobber otherClobber = other.getClobber(); + if(candidateClobber.isTrueSubset(otherClobber) && candidateCycles <= otherCycles) { + // The candidate template is better + return true; + } + if(candidateClobber.isSubset(otherClobber) && candidateCycles < otherCycles) { + // The candidate template is better + return false; + } + if(candidateClobber.equals(otherClobber) && candidateCycles == otherCycles && asmSize(candidate.fragment.getBodyAsm()) < asmSize(other.getFragment().getBodyAsm())) { + // The candidate template is better + return false; + } + return true; + } - 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); - } + /** + * Find the size of some ASM + * + * @param asm The ASM + * @return The size of the ASM represented as the number of "nodes" in the ASM body + */ + private static int asmSize(ParseTree asm) { + int size = 1; + if(asm instanceof ParserRuleContext) { + ParserRuleContext parent = (ParserRuleContext) asm; + if(parent.children != null) { + for(ParseTree child : parent.children) { + size += asmSize(child); + } + } + } + return size; + } - } - // 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. + */ + List getParentOptions() { + return parentOptions; + } - /** - * 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. - */ - List 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 getBestTemplates() { + return bestTemplates.values(); + } - /** - * 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 getBestTemplates() { - return bestTemplates.values(); - } - - public AsmFragmentSignature getSignature() { - return signature; - } + public AsmFragmentSignature getSignature() { + return signature; + } } diff --git a/src/main/java/dk/camelot64/kickc/fragment/synthesis/AsmFragmentSynthesisResult.java b/src/main/java/dk/camelot64/kickc/fragment/synthesis/AsmFragmentSynthesisResult.java index 05072dabe..0ebfbe1e6 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/synthesis/AsmFragmentSynthesisResult.java +++ b/src/main/java/dk/camelot64/kickc/fragment/synthesis/AsmFragmentSynthesisResult.java @@ -3,6 +3,7 @@ package dk.camelot64.kickc.fragment.synthesis; import dk.camelot64.kickc.CompileLog; import dk.camelot64.kickc.fragment.AsmFragmentClobber; import dk.camelot64.kickc.fragment.AsmFragmentTemplate; +import dk.camelot64.kickc.fragment.AsmTemplateBodyPrinter; import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature; import java.util.List; @@ -91,7 +92,7 @@ public class AsmFragmentSynthesisResult { prefix = "synthesized "; } log.append(indent + prefix + this.getSynthesisDescription() + " - clobber:" + fragment.getClobber().toString() + " cycles:" + fragment.getCycles()); - log.append(indent + " " + fragment.getBody().replace("\n", "\n" + indent + " ")); + log.append(indent + " " + getBodyString().replace("\n", "\n" + indent + " ")); } public AsmFragmentClobber getClobber() { @@ -102,8 +103,8 @@ public class AsmFragmentSynthesisResult { return fragment.getCycles(); } - public String getBody() { - return fragment.getBody(); + public String getBodyString() { + return AsmTemplateBodyPrinter.print(fragment.getBodyAsm()); } public AsmFragmentSignature getSignature() { diff --git a/src/main/java/dk/camelot64/kickc/fragment/synthesis/AsmFragmentTemplateSynthesisRuleRegex.java b/src/main/java/dk/camelot64/kickc/fragment/synthesis/AsmFragmentTemplateSynthesisRuleRegex.java index a22be95e2..9f4793cc0 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/synthesis/AsmFragmentTemplateSynthesisRuleRegex.java +++ b/src/main/java/dk/camelot64/kickc/fragment/synthesis/AsmFragmentTemplateSynthesisRuleRegex.java @@ -2,6 +2,7 @@ package dk.camelot64.kickc.fragment.synthesis; import dk.camelot64.kickc.fragment.AsmFragmentTemplate; import dk.camelot64.kickc.fragment.AsmFragmentTemplateParser; +import dk.camelot64.kickc.fragment.AsmTemplateBodyPrinter; import dk.camelot64.kickc.fragment.signature.AsmFragmentSignature; import java.util.*; @@ -127,7 +128,7 @@ class AsmFragmentTemplateSynthesisRuleRegex implements AsmFragmentTemplateSynthe if(asmPrefix != null) { newFragment.append(asmPrefix).append("\n"); } - String subFragment = subTemplate.getBody(); + String subFragment = AsmTemplateBodyPrinter.print(subTemplate.getBodyAsm()); if(bindMappings != null) { if(mapSignature) { // When mapping the signature we do the reverse replacement in the ASM diff --git a/src/test/java/dk/camelot64/kickc/test/TestFragments.java b/src/test/java/dk/camelot64/kickc/test/TestFragments.java index 5444d83f1..6abcf88b4 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestFragments.java +++ b/src/test/java/dk/camelot64/kickc/test/TestFragments.java @@ -251,7 +251,7 @@ public class TestFragments { } log.append(prefix + template.getSynthesisDescription() + " - clobber:" + template.getClobber().toString() + " cycles:" + template.getCycles()); - log.append(" " + template.getBody().replace("\n", "\n ")); + log.append(" " + template.getBodyString().replace("\n", "\n ")); } } // Print some information about the testing to stdout diff --git a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java index d8c075657..5466d7c4e 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java +++ b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java @@ -3131,7 +3131,7 @@ public class TestProgramsFast extends TestPrograms { @Test public void testSimpleLoop() throws IOException { - compileAndCompare("simple-loop.c"); + compileAndCompare("simple-loop.c", log()); } @Test