From 2a2d873e62a9f495e9f7b06a3b66622d35b79094 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Tue, 30 May 2017 11:09:39 +0200 Subject: [PATCH] Added static register value analysis - eliminating uncecasary loads. --- .../fragment/zpptrby1=zpptrby1_plus_coby1.asm | 2 +- .../AsmProgramStaticRegisterValues.java | 182 ++++++++++++++++++ .../kickc/icl/Pass4AsmOptimization.java | 9 +- .../icl/Pass4UnnecesaryLoadElimination.java | 75 ++++++++ src/dk/camelot64/kickc/test/Main.java | 22 ++- 5 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 src/dk/camelot64/kickc/asm/parser/AsmProgramStaticRegisterValues.java create mode 100644 src/dk/camelot64/kickc/icl/Pass4UnnecesaryLoadElimination.java diff --git a/src/dk/camelot64/kickc/asm/fragment/zpptrby1=zpptrby1_plus_coby1.asm b/src/dk/camelot64/kickc/asm/fragment/zpptrby1=zpptrby1_plus_coby1.asm index 8d5784ff0..fc34dd6b6 100644 --- a/src/dk/camelot64/kickc/asm/fragment/zpptrby1=zpptrby1_plus_coby1.asm +++ b/src/dk/camelot64/kickc/asm/fragment/zpptrby1=zpptrby1_plus_coby1.asm @@ -2,6 +2,6 @@ lda {zpptrby1} clc adc #{coby1} sta {zpptrby1} -bcs !+ +bcc !+ inc {zpptrby1}+1 !: \ No newline at end of file diff --git a/src/dk/camelot64/kickc/asm/parser/AsmProgramStaticRegisterValues.java b/src/dk/camelot64/kickc/asm/parser/AsmProgramStaticRegisterValues.java new file mode 100644 index 000000000..0a5991350 --- /dev/null +++ b/src/dk/camelot64/kickc/asm/parser/AsmProgramStaticRegisterValues.java @@ -0,0 +1,182 @@ +package dk.camelot64.kickc.asm.parser; + +import dk.camelot64.kickc.asm.*; + +import java.util.HashMap; +import java.util.Map; + +/** + * Perform static analysis of an ASM program infering information about the values of registers entering each instruction + */ +public class AsmProgramStaticRegisterValues { + + private AsmProgram program; + + private Map values; + + public AsmProgramStaticRegisterValues(AsmProgram program) { + this.program = program; + this.values = new HashMap<>(); + initValues(); + } + + public AsmRegisterValues getValues(AsmInstruction instruction) { + return values.get(instruction); + } + + private void initValues() { + AsmRegisterValues current = new AsmRegisterValues(); + for (AsmLine line : program.getLines()) { + if (line instanceof AsmLabel) { + current = new AsmRegisterValues(); + } else if (line instanceof AsmInstruction) { + AsmInstruction instruction = (AsmInstruction) line; + values.put(instruction, current); + current = new AsmRegisterValues(current); + AsmInstructionType instructionType = instruction.getType(); + AsmClobber clobber = instructionType.getClobber(); + if (clobber.isClobberA()) { + current.setA(null); + } + if (clobber.isClobberX()) { + current.setX(null); + } + if (clobber.isClobberY()) { + current.setY(null); + } + if (clobber.isClobberC()) { + current.setC(null); + } + if (clobber.isClobberN()) { + current.setN(null); + } + if (clobber.isClobberV()) { + current.setV(null); + } + if (clobber.isClobberZ()) { + current.setZ(null); + } + if (instructionType.getMnemnonic().equals("lda") && instructionType.getAddressingMode().equals(AsmAddressingMode.IMM)) { + try { + int immValue = Integer.parseInt(instruction.getParameter()); + current.setZ(immValue == 0); + current.setN(immValue > 127); + current.setA(immValue); + } catch (NumberFormatException e) { + // ignore + } + } + if (instructionType.getMnemnonic().equals("ldx") && instructionType.getAddressingMode().equals(AsmAddressingMode.IMM)) { + try { + int immValue = Integer.parseInt(instruction.getParameter()); + current.setZ(immValue == 0); + current.setN(immValue > 127); + current.setX(immValue); + } catch (NumberFormatException e) { + // ignore + } + } + if (instructionType.getMnemnonic().equals("ldy") && instructionType.getAddressingMode().equals(AsmAddressingMode.IMM)) { + try { + int immValue = Integer.parseInt(instruction.getParameter()); + current.setZ(immValue == 0); + current.setN(immValue > 127); + current.setY(immValue); + } catch (NumberFormatException e) { + // ignore + } + } + if (instructionType.getMnemnonic().equals("sec")) { + current.setC(Boolean.TRUE); + } + if (instructionType.getMnemnonic().equals("clc")) { + current.setC(Boolean.FALSE); + } + } + } + } + + /** + * Known values of registers/flags at an instruction. null where value is unknown. + */ + public static class AsmRegisterValues { + private Integer a; + private Integer x; + private Integer y; + private Boolean c; + private Boolean v; + private Boolean n; + private Boolean z; + + public AsmRegisterValues() { + } + + public AsmRegisterValues(AsmRegisterValues original) { + this.a = original.getA(); + this.x = original.getX(); + this.y = original.getY(); + this.c = original.getC(); + this.v = original.getV(); + this.n = original.getN(); + this.z = original.getZ(); + } + + public Integer getA() { + return a; + } + + public Integer getX() { + return x; + } + + public Integer getY() { + return y; + } + + public Boolean getC() { + return c; + } + + public Boolean getV() { + return v; + } + + public Boolean getN() { + return n; + } + + public Boolean getZ() { + return z; + } + + public void setA(Integer a) { + this.a = a; + } + + public void setX(Integer x) { + this.x = x; + } + + public void setY(Integer y) { + this.y = y; + } + + public void setC(Boolean c) { + this.c = c; + } + + public void setV(Boolean v) { + this.v = v; + } + + public void setN(Boolean n) { + this.n = n; + } + + public void setZ(Boolean z) { + this.z = z; + } + + } + +} diff --git a/src/dk/camelot64/kickc/icl/Pass4AsmOptimization.java b/src/dk/camelot64/kickc/icl/Pass4AsmOptimization.java index 86c1a9d99..f282d209c 100644 --- a/src/dk/camelot64/kickc/icl/Pass4AsmOptimization.java +++ b/src/dk/camelot64/kickc/icl/Pass4AsmOptimization.java @@ -9,7 +9,7 @@ import java.util.List; /** Optimization performed on Assembler Code (Asm Code). * Optimizations are performed repeatedly until none of them yield any result **/ -public class Pass4AsmOptimization { +public abstract class Pass4AsmOptimization { private AsmProgram program; @@ -17,6 +17,13 @@ public class Pass4AsmOptimization { this.program = program; } + /** + * Attempt to perform optimization. + * + * @return true if an optimization was performed. false if no optimization was possible. + */ + public abstract boolean optimize(); + public AsmProgram getProgram() { return program; } diff --git a/src/dk/camelot64/kickc/icl/Pass4UnnecesaryLoadElimination.java b/src/dk/camelot64/kickc/icl/Pass4UnnecesaryLoadElimination.java new file mode 100644 index 000000000..84399289d --- /dev/null +++ b/src/dk/camelot64/kickc/icl/Pass4UnnecesaryLoadElimination.java @@ -0,0 +1,75 @@ +package dk.camelot64.kickc.icl; + +import dk.camelot64.kickc.asm.*; +import dk.camelot64.kickc.asm.parser.AsmProgramStaticRegisterValues; + +import java.util.ArrayList; +import java.util.List; + +/** Maps out register values entering all instructions. Removes unnecessary loads / clears / sets */ +public class Pass4UnnecesaryLoadElimination extends Pass4AsmOptimization { + + public Pass4UnnecesaryLoadElimination(AsmProgram program) { + super(program); + } + + @Override + public boolean optimize() { + AsmProgramStaticRegisterValues staticValues = new AsmProgramStaticRegisterValues(getProgram()); + List removes = new ArrayList<>(); + for (AsmLine line : getProgram().getLines()) { + if(line instanceof AsmInstruction) { + AsmInstruction instruction = (AsmInstruction) line; + AsmInstructionType instructionType = instruction.getType(); + if(instructionType.getMnemnonic().equals("lda") && instructionType.getAddressingMode().equals(AsmAddressingMode.IMM)) { + try { + int immValue = Integer.parseInt(instruction.getParameter()); + AsmProgramStaticRegisterValues.AsmRegisterValues instructionValues = staticValues.getValues(instruction); + if (instructionValues.getA() != null && instructionValues.getA().equals(immValue)) { + removes.add(instruction); + } + } catch (NumberFormatException e) { + // ignore + } + } + if(instructionType.getMnemnonic().equals("ldx") && instructionType.getAddressingMode().equals(AsmAddressingMode.IMM)) { + try { + int immValue = Integer.parseInt(instruction.getParameter()); + AsmProgramStaticRegisterValues.AsmRegisterValues instructionValues = staticValues.getValues(instruction); + if(instructionValues.getX()!=null && instructionValues.getX().equals(immValue)) { + removes.add(instruction); + } + } catch (NumberFormatException e) { + // ignore + } + + } + if(instructionType.getMnemnonic().equals("ldy") && instructionType.getAddressingMode().equals(AsmAddressingMode.IMM)) { + try { + int immValue = Integer.parseInt(instruction.getParameter()); + AsmProgramStaticRegisterValues.AsmRegisterValues instructionValues = staticValues.getValues(instruction); + if(instructionValues.getY()!=null && instructionValues.getY().equals(immValue)) { + removes.add(instruction); + } + } catch (NumberFormatException e) { + // ignore + } + } + if(instructionType.getMnemnonic().equals("clc")) { + AsmProgramStaticRegisterValues.AsmRegisterValues instructionValues = staticValues.getValues(instruction); + if(Boolean.FALSE.equals(instructionValues.getC())) { + removes.add(instruction); + } + } + if(instructionType.getMnemnonic().equals("sec")) { + AsmProgramStaticRegisterValues.AsmRegisterValues instructionValues = staticValues.getValues(instruction); + if(Boolean.TRUE.equals(instructionValues.getC())) { + removes.add(instruction); + } + } + } + } + remove(removes); + return removes.size()>0; + } +} diff --git a/src/dk/camelot64/kickc/test/Main.java b/src/dk/camelot64/kickc/test/Main.java index 5dc75617e..2379fe8be 100644 --- a/src/dk/camelot64/kickc/test/Main.java +++ b/src/dk/camelot64/kickc/test/Main.java @@ -13,7 +13,7 @@ import java.util.List; /** Test my KickC Grammar */ public class Main { public static void main(String[] args) throws IOException { - final String fileName = "src/dk/camelot64/kickc/test/bresenhamarr.kc"; + final String fileName = "src/dk/camelot64/kickc/test/bresenham.kc"; final CharStream input = CharStreams.fromFileName(fileName); System.out.println(input.toString()); KickCLexer lexer = new KickCLexer(input); @@ -59,7 +59,7 @@ public class Main { for (Pass2SsaOptimization optimization : optimizations) { boolean stepOptimized = optimization.optimize(); if (stepOptimized) { - System.out.println("Succesful optimization "+optimization); + System.out.println("Succesful SSA optimization "+optimization); ssaOptimized = true; System.out.println("CONTROL FLOW GRAPH"); System.out.println(controlFlowGraph.toString()); @@ -72,10 +72,24 @@ public class Main { Pass3CodeGeneration pass3CodeGeneration = new Pass3CodeGeneration(controlFlowGraph, symbolTable); AsmProgram asmProgram = pass3CodeGeneration.generate(); - Pass4NextJumpElimination pass5NextJumpElimination = new Pass4NextJumpElimination(asmProgram); + System.out.println("INITIAL ASM"); + System.out.println(asmProgram.toString()); + + List pass4Optimizations = new ArrayList<>(); + pass4Optimizations.add(new Pass4NextJumpElimination(asmProgram)); + pass4Optimizations.add(new Pass4UnnecesaryLoadElimination(asmProgram)); boolean asmOptimized = true; while(asmOptimized) { - asmOptimized = pass5NextJumpElimination.optimize(); + asmOptimized = false; + for (Pass4AsmOptimization optimization : pass4Optimizations) { + boolean stepOtimized = optimization.optimize(); + if(stepOtimized) { + System.out.println("Succesful ASM optimization "+optimization); + asmOptimized = true; + System.out.println("ASSEMBLER"); + System.out.println(asmProgram.toString()); + } + } } System.out.println("SYMBOLS");