mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-21 22:29:07 +00:00
Added static register value analysis - eliminating uncecasary loads.
This commit is contained in:
parent
b7fd96c4ee
commit
2a2d873e62
@ -2,6 +2,6 @@ lda {zpptrby1}
|
||||
clc
|
||||
adc #{coby1}
|
||||
sta {zpptrby1}
|
||||
bcs !+
|
||||
bcc !+
|
||||
inc {zpptrby1}+1
|
||||
!:
|
@ -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<AsmInstruction, AsmRegisterValues> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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<AsmLine> 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;
|
||||
}
|
||||
}
|
@ -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<Pass4AsmOptimization> 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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user