mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-03 12:07:26 +00:00
Implemented program snapshot and better PASS separation. Preparing for optimizations that require experimentation (snapshot/restore state).
This commit is contained in:
parent
764e0c1069
commit
bc1dd78bd8
@ -244,6 +244,8 @@ public class Compiler {
|
||||
getLog().append("SYMBOL TABLE SSA");
|
||||
getLog().append(program.getScope().toString(program, null));
|
||||
|
||||
program.endPass1();
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
@ -533,9 +535,6 @@ public class Compiler {
|
||||
}
|
||||
new Pass4RegistersFinalize(program).allocate(true);
|
||||
new Pass4AssertZeropageAllocation(program).check();
|
||||
}
|
||||
|
||||
private void pass5GenerateAndOptimizeAsm() {
|
||||
|
||||
// Final ASM code generation before optimization
|
||||
new Pass4PhiTransitions(program).generate();
|
||||
@ -545,6 +544,12 @@ public class Compiler {
|
||||
// Remove unnecessary register savings from interrupts {@link InterruptType#HARDWARE_NOCLOBBER}
|
||||
new Pass4InterruptClobberFix(program).fix();
|
||||
|
||||
program.endPass4();
|
||||
|
||||
}
|
||||
|
||||
private void pass5GenerateAndOptimizeAsm() {
|
||||
|
||||
getLog().append("\nASSEMBLER BEFORE OPTIMIZATION");
|
||||
getLog().append(program.getAsm().toString(new AsmProgram.AsmPrintState(true), program));
|
||||
|
||||
|
@ -16,67 +16,73 @@ import java.util.Map;
|
||||
/** A KickC Intermediate Compiler Language (ICL) Program */
|
||||
public class Program {
|
||||
|
||||
/** The name of the file being compiled. */
|
||||
private String fileName;
|
||||
/** Paths used for importing files. */
|
||||
private List<String> importPaths;
|
||||
/** Imported files. */
|
||||
private List<String> imported;
|
||||
/** The initial statement sequence generated by the parser. */
|
||||
private StatementSequence statementSequence;
|
||||
/** The main scope. */
|
||||
private ProgramScope scope;
|
||||
/** The control flow graph. */
|
||||
private ControlFlowGraph graph;
|
||||
/** The 6502 ASM program. */
|
||||
private AsmProgram asm;
|
||||
/** Resource files that should be copied to the output folder to be compiled with the generated ASM. */
|
||||
private List<Path> asmResourceFiles;
|
||||
/** Comments for the (main) file. */
|
||||
private List<Comment> fileComments;
|
||||
|
||||
/** The log containing information about the compilation process. */
|
||||
private CompileLog log;
|
||||
|
||||
/** Variables modified inside procedures. */
|
||||
private ProcedureModifiedVars procedureModifiedVars;
|
||||
/** Information about calls. */
|
||||
private CallGraph callGraph;
|
||||
/** Information about dominators of all blocks */
|
||||
private DominatorsGraph dominators;
|
||||
/** Information about loops. */
|
||||
private NaturalLoopSet loopSet;
|
||||
/** The name of the file being compiled. PASS 0-5 (STATIC) */
|
||||
private String fileName;
|
||||
/** Paths used for importing files. PASS 0 (STATIC) */
|
||||
private List<String> importPaths;
|
||||
/** Imported files. PASS 0 (STATIC) */
|
||||
private List<String> imported;
|
||||
|
||||
/** Which block is each statement a part of. */
|
||||
private StatementInfos statementInfos;
|
||||
/** Cached information about symbols. Contains a symbol table cache for fast access. */
|
||||
private SymbolInfos symbolInfos;
|
||||
/** The variables referenced by blocks/statements. */
|
||||
private VariableReferenceInfos variableReferenceInfos;
|
||||
/** The live ranges of all variables. */
|
||||
private LiveRangeVariables liveRangeVariables;
|
||||
/** Live range equivalence classes containing variables that do not have overlapping live ranges. */
|
||||
private LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet;
|
||||
/** The effective live ranges of all variables. */
|
||||
private LiveRangeVariablesEffective liveRangeVariablesEffective;
|
||||
/** The register weight of all variables describing how much the variable would theoretically gain from being in a register */
|
||||
private VariableRegisterWeights variableRegisterWeights;
|
||||
/** Registers potentially usable as allocation for each live range equivalence class. */
|
||||
private RegisterPotentials registerPotentials;
|
||||
/** Separation of live range equivalence classes into scopes - used for register uplift */
|
||||
private RegisterUpliftProgram registerUpliftProgram;
|
||||
/** Constants identified during pass 1. */
|
||||
private Collection<VariableRef> earlyIdentifiedConstants;
|
||||
/** Reserved ZP addresses that the compiler cannot use. */
|
||||
private List<Number> reservedZps;
|
||||
/** Absolute start address of the code. Null to start ad 0x080d. */
|
||||
private Number programPc;
|
||||
/** Cached phi transitions into each block. */
|
||||
private Map<LabelRef, PhiTransitions> phiTransitions;
|
||||
/** Struct values unwound to individual variables. */
|
||||
private StructUnwinding structUnwinding;
|
||||
/** The target platform that the program is being build for. */
|
||||
/** The target platform that the program is being build for. PASS 0-5 (STATIC) */
|
||||
private TargetPlatform targetPlatform = TargetPlatform.DEFAULT;
|
||||
/** Absolute start address of the code. Null to start ad 0x080d. PASS 0-5 (STATIC) */
|
||||
private Number programPc;
|
||||
/** Reserved ZP addresses that the compiler cannot use. PASS 0-5 (STATIC) */
|
||||
private List<Number> reservedZps;
|
||||
/** Resource files that should be copied to the output folder to be compiled with the generated ASM. PASS 0-5 (STATIC) */
|
||||
private List<Path> asmResourceFiles;
|
||||
/** Comments for the (main) file. PASS 0-4 (STATIC) */
|
||||
private List<Comment> fileComments;
|
||||
|
||||
/** The initial statement sequence generated by the parser. PASS 1 (STATIC) */
|
||||
private StatementSequence statementSequence;
|
||||
/** Constants identified during pass 1. PASS 1 (STATIC) */
|
||||
private Collection<VariableRef> earlyIdentifiedConstants;
|
||||
/** Variables modified inside procedures. PASS 1 (STATIC) */
|
||||
private ProcedureModifiedVars procedureModifiedVars;
|
||||
/** Struct values unwound to individual variables. PASS 1 (STATIC) */
|
||||
private StructUnwinding structUnwinding;
|
||||
|
||||
/** The main scope. PASS 0-5 (DYNAMIC) */
|
||||
private ProgramScope scope;
|
||||
/** The control flow graph. PASS 1-5 (DYNAMIC) */
|
||||
private ControlFlowGraph graph;
|
||||
/** Live range equivalence classes containing variables that do not have overlapping live ranges. PASS 3-5 (DYNAMIC) */
|
||||
private LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet;
|
||||
/** The 6502 ASM program. PASS 4-5 (DYNAMIC) */
|
||||
private AsmProgram asm;
|
||||
|
||||
/** A saved program snapshot that can be rolled back. Used to store the (DYNAMIC) state of the program while trying out a potential optimization. PASS 2 (DYNAMIC)*/
|
||||
private ProgramSnapshot snapshot;
|
||||
|
||||
/** Cached information about calls. PASS 1-4 (CACHED) */
|
||||
private CallGraph callGraph;
|
||||
/** Cached information about the variables referenced by blocks/statements. PASS 1-4 (CACHED) */
|
||||
private VariableReferenceInfos variableReferenceInfos;
|
||||
/** Information about dominators of all blocks. PASS 2U-4 (CACHED) */
|
||||
private DominatorsGraph dominators;
|
||||
/** Cached information about symbols. Contains a symbol table cache for fast access. PASS 3-4 (CACHED) */
|
||||
private SymbolInfos symbolInfos;
|
||||
/** Cached phi transitions into each block. PASS 4 (CACHED) */
|
||||
private Map<LabelRef, PhiTransitions> phiTransitions;
|
||||
/** The live ranges of all variables. PASS 3-4 (CACHED) */
|
||||
private LiveRangeVariables liveRangeVariables;
|
||||
/** The effective live ranges of all variables. PASS 3-4 (CACHED) */
|
||||
private LiveRangeVariablesEffective liveRangeVariablesEffective;
|
||||
/** Registers potentially usable as allocation for each live range equivalence class. PASS 4 (CACHED) */
|
||||
private RegisterPotentials registerPotentials;
|
||||
/** Separation of live range equivalence classes into scopes - used for register uplift. PASS 4 (CACHED) */
|
||||
private RegisterUpliftProgram registerUpliftProgram;
|
||||
|
||||
/** Cached information about which block is each statement a part of. PASS 2U-5 (CACHED) */
|
||||
private StatementInfos statementInfos;
|
||||
/** Information about loops. PASS 2U-5 (CACHED) */
|
||||
private NaturalLoopSet loopSet;
|
||||
/** The register weight of all variables describing how much the variable would theoretically gain from being in a register. PASS 3-5 (CACHED) */
|
||||
private VariableRegisterWeights variableRegisterWeights;
|
||||
|
||||
public Program() {
|
||||
this.scope = new ProgramScope();
|
||||
@ -87,6 +93,64 @@ public class Program {
|
||||
this.reservedZps = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all data that is only used in PASS 1
|
||||
*/
|
||||
public void endPass1() {
|
||||
this.importPaths = null;
|
||||
this.imported = null;
|
||||
this.statementSequence = null;
|
||||
this.earlyIdentifiedConstants = null;
|
||||
this.procedureModifiedVars = null;
|
||||
this.structUnwinding = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all data that is only used in PASS 2-4
|
||||
*/
|
||||
public void endPass4() {
|
||||
this.snapshot = null;
|
||||
this.fileComments = null;
|
||||
this.callGraph = null;
|
||||
this.variableReferenceInfos = null;
|
||||
this.dominators = null;
|
||||
this.symbolInfos = null;
|
||||
this.phiTransitions = null;
|
||||
this.liveRangeVariables = null;
|
||||
this.liveRangeVariablesEffective = null;
|
||||
this.registerPotentials = null;
|
||||
this.registerUpliftProgram = null;
|
||||
}
|
||||
|
||||
/** Save a snapshot of the dynamic parts of the program. */
|
||||
public void saveSnapshot() {
|
||||
if(this.snapshot!=null)
|
||||
throw new InternalError("Snapshot already saved!");
|
||||
if(this.liveRangeEquivalenceClassSet!=null)
|
||||
throw new InternalError("Compiler Program Snapshot does not support liveRangeEquivalenceClassSet!");
|
||||
this.snapshot = new ProgramSnapshot(scope, graph);
|
||||
}
|
||||
|
||||
/** Restore the snapshot of the dynamic parts of the program. Clear all cached data and the snapshot. */
|
||||
public void restoreSnapshot() {
|
||||
this.scope = snapshot.getScope();
|
||||
this.graph = snapshot.getGraph();
|
||||
this.snapshot = null;
|
||||
this.callGraph = null;
|
||||
this.variableReferenceInfos = null;
|
||||
this.dominators = null;
|
||||
this.loopSet = null;
|
||||
this.statementInfos = null;
|
||||
this.symbolInfos = null;
|
||||
this.phiTransitions = null;
|
||||
this.liveRangeVariables = null;
|
||||
this.liveRangeVariablesEffective = null;
|
||||
this.variableRegisterWeights = null;
|
||||
this.registerPotentials = null;
|
||||
this.registerUpliftProgram = null;
|
||||
this.asm = null;
|
||||
}
|
||||
|
||||
public TargetPlatform getTargetPlatform() {
|
||||
return targetPlatform;
|
||||
}
|
||||
@ -279,34 +343,6 @@ public class Program {
|
||||
this.earlyIdentifiedConstants = earlyIdentifiedConstants;
|
||||
}
|
||||
|
||||
public CompileLog getLog() {
|
||||
return log;
|
||||
}
|
||||
|
||||
public void setLog(CompileLog log) {
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(this == o) return true;
|
||||
if(o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Program program = (Program) o;
|
||||
|
||||
if(scope != null ? !scope.equals(program.scope) : program.scope != null) return false;
|
||||
if(graph != null ? !graph.equals(program.graph) : program.graph != null) return false;
|
||||
return asm != null ? asm.equals(program.asm) : program.asm == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = scope != null ? scope.hashCode() : 0;
|
||||
result = 31 * result + (graph != null ? graph.hashCode() : 0);
|
||||
result = 31 * result + (asm != null ? asm.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
@ -343,4 +379,14 @@ public class Program {
|
||||
public Number getProgramPc() {
|
||||
return programPc;
|
||||
}
|
||||
|
||||
public CompileLog getLog() {
|
||||
return log;
|
||||
}
|
||||
|
||||
public void setLog(CompileLog log) {
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
57
src/main/java/dk/camelot64/kickc/model/ProgramSnapshot.java
Normal file
57
src/main/java/dk/camelot64/kickc/model/ProgramSnapshot.java
Normal file
@ -0,0 +1,57 @@
|
||||
package dk.camelot64.kickc.model;
|
||||
|
||||
import dk.camelot64.kickc.model.symbols.ProgramScope;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* A snapshot of all dynamic data in a {@link Program}.
|
||||
* Used whenever the compiler need to run an experiment where it may need to roll back to a previous state.
|
||||
*/
|
||||
public class ProgramSnapshot {
|
||||
|
||||
/** The main scope. PASS 0-5 (DYNAMIC) */
|
||||
private ProgramScope scope;
|
||||
/** The control flow graph. PASS 1-5 (DYNAMIC) */
|
||||
private ControlFlowGraph graph;
|
||||
|
||||
public ProgramSnapshot(ProgramScope scope, ControlFlowGraph graph) {
|
||||
this.scope = snapshot(scope);
|
||||
this.graph = snapshot(graph);
|
||||
}
|
||||
|
||||
public ProgramScope getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public ControlFlowGraph getGraph() {
|
||||
return graph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a deep copy of an object (by using serialization)
|
||||
* @param orig The object tot copy
|
||||
* @return the copy with zero references to the original
|
||||
*/
|
||||
private static <T extends Object> T snapshot(T orig) {
|
||||
if(orig==null) return null;
|
||||
T obj = null;
|
||||
try {
|
||||
// Write the object out to a byte array
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream out = new ObjectOutputStream(bos);
|
||||
out.writeObject(orig);
|
||||
out.flush();
|
||||
out.close();
|
||||
// Make an input stream from the byte array and read a copy of the object back in.
|
||||
ObjectInputStream in = new ObjectInputStream(
|
||||
new ByteArrayInputStream(bos.toByteArray()));
|
||||
obj = (T) in.readObject();
|
||||
}
|
||||
catch(IOException | ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
}
|
@ -2,7 +2,6 @@ package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.StructUnwinding;
|
||||
import dk.camelot64.kickc.model.VariableReferenceInfos;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
import dk.camelot64.kickc.model.symbols.ConstantVar;
|
||||
@ -11,6 +10,7 @@ import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
|
||||
import dk.camelot64.kickc.model.values.LValue;
|
||||
import dk.camelot64.kickc.model.values.StructUnwoundPlaceholder;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
|
||||
import java.util.Collection;
|
||||
@ -51,9 +51,7 @@ public class PassNEliminateUnusedVars extends Pass2SsaOptimization {
|
||||
// Not volatile
|
||||
eliminate = true;
|
||||
} else if(variable.isVolatile() && variable.getType() instanceof SymbolTypeStruct) {
|
||||
// If an unwound volatile struct - eliminate it
|
||||
StructUnwinding.VariableUnwinding variableUnwinding = getProgram().getStructUnwinding().getVariableUnwinding(variable.getRef());
|
||||
if(variableUnwinding != null) {
|
||||
if(assignment.getOperator()==null && assignment.getrValue2() instanceof StructUnwoundPlaceholder) {
|
||||
eliminate = true;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user