diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmFragment.java b/src/main/java/dk/camelot64/kickc/asm/AsmFragment.java index d555d8874..056bde5fd 100644 --- a/src/main/java/dk/camelot64/kickc/asm/AsmFragment.java +++ b/src/main/java/dk/camelot64/kickc/asm/AsmFragment.java @@ -10,6 +10,7 @@ import org.antlr.v4.runtime.*; import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; @@ -344,6 +345,9 @@ public class AsmFragment { return bound; } + /** Cache for fragment files. Maps signature to the parsed file. */ + private static Map<String, Asm6502Parser.FileContext> fragmentFileCache = new HashMap<>(); + /** * Generate assembler code for the assembler fragment. * @@ -351,48 +355,50 @@ public class AsmFragment { */ public void generate(AsmProgram asm) { String signature = this.getSignature(); - ClassLoader classLoader = this.getClass().getClassLoader(); - final URL fragmentResource = classLoader.getResource("dk/camelot64/kickc/asm/fragment/" + signature + ".asm"); - if (fragmentResource == null) { - throw new UnknownFragmentException(signature); + Asm6502Parser.FileContext fragmentFile = fragmentFileCache.get(signature); + if(fragmentFile==null) { + ClassLoader classLoader = this.getClass().getClassLoader(); + final URL fragmentResource = classLoader.getResource("dk/camelot64/kickc/asm/fragment/" + signature + ".asm"); + if (fragmentResource == null) { + throw new UnknownFragmentException(signature); + } + + try { + InputStream fragmentStream = fragmentResource.openStream(); + Asm6502Lexer lexer = new Asm6502Lexer(CharStreams.fromStream(fragmentStream)); + Asm6502Parser parser = new Asm6502Parser(new CommonTokenStream(lexer)); + parser.addErrorListener(new BaseErrorListener() { + @Override + public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { + throw new RuntimeException("Error parsing fragment fragmentFile " + fragmentResource + "\n - Line: " + line + "\n - Message: " + msg); + } + }); + parser.setBuildParseTree(true); + fragmentFile = parser.file(); + fragmentStream.close(); + fragmentFileCache.put(signature, fragmentFile); + } catch (IOException e) { + throw new RuntimeException("Error reading code fragment " + fragmentResource); + } } - try { - InputStream fragmentStream = fragmentResource.openStream(); - Asm6502Lexer lexer = new Asm6502Lexer(CharStreams.fromStream(fragmentStream)); - Asm6502Parser parser = new Asm6502Parser(new CommonTokenStream(lexer)); - parser.addErrorListener(new BaseErrorListener() { - @Override - public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { - throw new RuntimeException("Error parsing fragment file " + fragmentResource + "\n - Line: " + line + "\n - Message: " + msg); - } - }); - parser.setBuildParseTree(true); - Asm6502Parser.FileContext file = parser.file(); - AsmSequenceGenerator asmSequenceGenerator = new AsmSequenceGenerator(fragmentResource, asm); - asmSequenceGenerator.generate(file); - fragmentStream.close(); - } catch (IOException e) { - throw new RuntimeException("Error reading code fragment " + fragmentResource); - } + AsmSequenceGenerator asmSequenceGenerator = new AsmSequenceGenerator(signature, this, asm); + asmSequenceGenerator.generate(fragmentFile); } - private class AsmSequenceGenerator extends Asm6502BaseVisitor { + private static class AsmSequenceGenerator extends Asm6502BaseVisitor { - private URL fragmentResource; + private String signature; private AsmProgram program; + private AsmFragment bindings; - public AsmSequenceGenerator(URL fragmentResource, AsmProgram program) { - this.fragmentResource = fragmentResource; + public AsmSequenceGenerator(String signature, AsmFragment bindings, AsmProgram program) { + this.signature = signature; + this.bindings = bindings; this.program = program; } - public AsmSequenceGenerator(URL fragmentResource) { - this.fragmentResource = fragmentResource; - this.program = new AsmProgram(); - } - public AsmProgram getProgram() { return program; } @@ -427,7 +433,7 @@ public class AsmFragment { if (instruction != null) { program.addLine(instruction); } else { - throw new RuntimeException("Error parsing ASM fragment line in " + fragmentResource.toString() + "\n - Line: " + ctx.getText()); + throw new RuntimeException("Error parsing ASM fragment line in dk/camelot64/kickc/asm/fragment/" + signature + ".asm\n - Line: " + ctx.getText()); } return null; } @@ -505,7 +511,7 @@ public class AsmFragment { @Override public Object visitExprReplace(Asm6502Parser.ExprReplaceContext ctx) { String replaceName = ctx.NAME().getSymbol().getText(); - return AsmFragment.this.getBoundValue(replaceName); + return bindings.getBoundValue(replaceName); } } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass3RegisterUpliftPotentialRegisterAnalysis.java b/src/main/java/dk/camelot64/kickc/passes/Pass3RegisterUpliftPotentialRegisterAnalysis.java index 956a9aefc..7ceda386d 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass3RegisterUpliftPotentialRegisterAnalysis.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass3RegisterUpliftPotentialRegisterAnalysis.java @@ -116,7 +116,7 @@ public class Pass3RegisterUpliftPotentialRegisterAnalysis extends Pass2Base { * @return A set with registers that are clobbered by all different register assignments in the combination */ private Set<RegisterAllocation.Register> findAlwaysClobberedRegisters(ControlFlowBlock block, Statement statement, RegisterCombinationIterator combinations) { - Set<RegisterAllocation.Register> alwaysClobbered = new HashSet<>(); + Set<RegisterAllocation.Register> alwaysClobbered = new LinkedHashSet<>(); alwaysClobbered.add(RegisterAllocation.getRegisterA()); alwaysClobbered.add(RegisterAllocation.getRegisterX()); alwaysClobbered.add(RegisterAllocation.getRegisterY()); diff --git a/src/main/java/dk/camelot64/kickc/test/ref/bresenham.log b/src/main/java/dk/camelot64/kickc/test/ref/bresenham.log index e42d66534..fb064b3ee 100644 --- a/src/main/java/dk/camelot64/kickc/test/ref/bresenham.log +++ b/src/main/java/dk/camelot64/kickc/test/ref/bresenham.log @@ -1171,13 +1171,13 @@ B3_from_B2: //SEG31 [6] phi (byte*) cursor#5 = (byte*) cursor#2 -- register_copy jmp B3 -Statement [1] *((byte*) cursor#3) ← (byte) 81 [ cursor#3 x#2 e#3 y#2 ] always clobbers reg byte y reg byte a -Removing always clobbered register reg byte y as potential for zp byte:4 [ x#2 x#1 ] +Statement [1] *((byte*) cursor#3) ← (byte) 81 [ cursor#3 x#2 e#3 y#2 ] always clobbers reg byte a reg byte y Removing always clobbered register reg byte a as potential for zp byte:4 [ x#2 x#1 ] -Removing always clobbered register reg byte y as potential for zp byte:5 [ e#3 e#5 e#1 e#2 ] +Removing always clobbered register reg byte y as potential for zp byte:4 [ x#2 x#1 ] Removing always clobbered register reg byte a as potential for zp byte:5 [ e#3 e#5 e#1 e#2 ] -Removing always clobbered register reg byte y as potential for zp byte:6 [ y#2 y#4 y#1 ] +Removing always clobbered register reg byte y as potential for zp byte:5 [ e#3 e#5 e#1 e#2 ] Removing always clobbered register reg byte a as potential for zp byte:6 [ y#2 y#4 y#1 ] +Removing always clobbered register reg byte y as potential for zp byte:6 [ y#2 y#4 y#1 ] Statement [4] (byte) e#1 ← (byte) e#3 + (byte) 24 [ x#1 e#1 cursor#1 y#2 ] always clobbers reg byte a Statement [9] (byte*) cursor#2 ← (byte*) cursor#1 + (byte) 40 [ x#1 e#1 cursor#2 y#1 ] always clobbers reg byte a Statement [10] (byte) e#2 ← (byte) e#1 - (byte) 39 [ x#1 cursor#2 e#2 y#1 ] always clobbers reg byte a diff --git a/src/main/java/dk/camelot64/kickc/test/ref/ptrtest.log b/src/main/java/dk/camelot64/kickc/test/ref/ptrtest.log index 6229f55ba..79baf5b71 100644 --- a/src/main/java/dk/camelot64/kickc/test/ref/ptrtest.log +++ b/src/main/java/dk/camelot64/kickc/test/ref/ptrtest.log @@ -2066,9 +2066,9 @@ lvalue__B1_from_B2: //SEG70 [27] phi (byte) lvalue::i#2 = (byte) lvalue::i#1 -- register_copy jmp lvalue__B1 -Statement [9] *((byte*) lvaluevar::screen#2) ← (byte) 4 [ lvaluevar::i#2 lvaluevar::screen#2 ] always clobbers reg byte y reg byte a -Removing always clobbered register reg byte y as potential for zp byte:2 [ lvaluevar::i#2 lvaluevar::i#1 ] +Statement [9] *((byte*) lvaluevar::screen#2) ← (byte) 4 [ lvaluevar::i#2 lvaluevar::screen#2 ] always clobbers reg byte a reg byte y Removing always clobbered register reg byte a as potential for zp byte:2 [ lvaluevar::i#2 lvaluevar::i#1 ] +Removing always clobbered register reg byte y as potential for zp byte:2 [ lvaluevar::i#2 lvaluevar::i#1 ] Statement [15] (byte) rvaluevar::b#0 ← * (byte*) rvaluevar::screen#2 [ rvaluevar::i#2 rvaluevar::screen#2 ] always clobbers reg byte a reg byte y Removing always clobbered register reg byte a as potential for zp byte:5 [ rvaluevar::i#2 rvaluevar::i#1 ] Removing always clobbered register reg byte y as potential for zp byte:5 [ rvaluevar::i#2 rvaluevar::i#1 ]