1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-08-07 22:25:13 +00:00
Files
kickc/src/main/java/dk/camelot64/kickc/Compiler.java
2017-11-11 08:46:56 +01:00

312 lines
13 KiB
Java

package dk.camelot64.kickc;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.parser.KickCLexer;
import dk.camelot64.kickc.parser.KickCParser;
import dk.camelot64.kickc.passes.*;
import org.antlr.v4.runtime.*;
import java.util.ArrayList;
import java.util.List;
/**
* Perform KickC compilation and optimizations
*/
public class Compiler {
public Program compile(final CharStream input) {
CompileLog log = new CompileLog();
try {
KickCParser.FileContext file = pass0ParseInput(input, log);
Program program = pass1GenerateSSA(file, log);
pass2OptimizeSSA(program);
log.append("FINAL SYMBOL TABLE");
log.append(program.getScope().getSymbolTableContents(program));
pass3Analysis(program);
pass4RegisterAllocation(program);
pass5GenerateAndOptimizeAsm(program);
log.append("FINAL SYMBOL TABLE");
log.append(program.getScope().getSymbolTableContents(program));
log.append("FINAL CODE");
log.append(program.getAsm().toString());
return program;
} catch (Exception e) {
//System.out.println(log.getLog());
throw e;
}
}
public KickCParser.FileContext pass0ParseInput(final CharStream input, CompileLog log) {
log.append(input.toString());
KickCLexer lexer = new KickCLexer(input);
KickCParser parser = new KickCParser(new CommonTokenStream(lexer));
parser.setBuildParseTree(true);
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 file " + input.getSourceName() + "\n - Line: " + line + "\n - Message: " + msg);
}
});
return parser.file();
}
public Program pass1GenerateSSA(KickCParser.FileContext file, CompileLog log) {
Pass1GenerateStatementSequence pass1GenerateStatementSequence = new Pass1GenerateStatementSequence(log);
pass1GenerateStatementSequence.generate(file);
StatementSequence statementSequence = pass1GenerateStatementSequence.getSequence();
ProgramScope programScope = pass1GenerateStatementSequence.getProgramScope();
statementSequence = (new Pass1FixLvalueLoHi(statementSequence, programScope, log)).fix();
Pass1TypeInference pass1TypeInference = new Pass1TypeInference(programScope);
pass1TypeInference.inferTypes(statementSequence);
Program program = new Program(programScope, log);
log.append("PROGRAM");
log.append(statementSequence.toString(program));
log.append("SYMBOLS");
log.append(programScope.getSymbolTableContents(program));
Pass1GenerateControlFlowGraph pass1GenerateControlFlowGraph = new Pass1GenerateControlFlowGraph(programScope);
ControlFlowGraph controlFlowGraph = pass1GenerateControlFlowGraph.generate(statementSequence);
program.setGraph(controlFlowGraph);
log.append("INITIAL CONTROL FLOW GRAPH");
log.append(program.getGraph().toString(program));
Pass1EliminateEmptyBlocks pass1EliminateEmptyBlocks = new Pass1EliminateEmptyBlocks(program);
boolean blockEliminated = pass1EliminateEmptyBlocks.eliminate();
if (blockEliminated) {
log.append("CONTROL FLOW GRAPH");
log.append(program.getGraph().toString(program));
}
(new Pass1ModifiedVarsAnalysis(program)).findModifiedVars();
log.append("PROCEDURE MODIFY VARIABLE ANALYSIS");
log.append(program.getProcedureModifiedVars().toString(program));
Pass1ProcedureCallParameters pass1ProcedureCallParameters =
new Pass1ProcedureCallParameters(program);
pass1ProcedureCallParameters.generate();
log.append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL");
log.append(program.getGraph().toString(program));
Pass1GenerateSingleStaticAssignmentForm pass1GenerateSingleStaticAssignmentForm =
new Pass1GenerateSingleStaticAssignmentForm(log, program);
pass1GenerateSingleStaticAssignmentForm.generate();
log.append("CONTROL FLOW GRAPH SSA");
log.append(program.getGraph().toString(program));
Pass1ProcedureCallsReturnValue pass1ProcedureCallsReturnValue =
new Pass1ProcedureCallsReturnValue(program);
program.setGraph(pass1ProcedureCallsReturnValue.generate());
log.append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN");
log.append(program.getGraph().toString(program));
log.append("INITIAL SSA SYMBOL TABLE");
log.append(program.getScope().getSymbolTableContents(program));
return program;
}
public void pass2AssertSSA(Program program) {
List<Pass2SsaAssertion> assertions = new ArrayList<>();
assertions.add(new Pass2AssertSymbols(program));
assertions.add(new Pass2AssertBlocks(program));
assertions.add(new Pass2AssertNoCallParameters(program));
assertions.add(new Pass2AssertNoCallLvalues(program));
assertions.add(new Pass2AssertNoLvalueLoHi(program));
assertions.add(new Pass2AssertNoReturnValues(program));
assertions.add(new Pass2AssertNoProcs(program));
assertions.add(new Pass2AssertNoLabels(program));
for (Pass2SsaAssertion assertion : assertions) {
assertion.check();
}
}
public void pass2OptimizeSSA(Program program) {
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
optimizations.add(new Pass2CullEmptyBlocks(program));
optimizations.add(new Pass2UnaryNotSimplification(program));
optimizations.add(new Pass2AliasElimination(program));
optimizations.add(new Pass2SelfPhiElimination(program));
optimizations.add(new Pass2RedundantPhiElimination(program));
optimizations.add(new Pass2ConditionalJumpSimplification(program));
optimizations.add(new Pass2ConstantIdentification(program));
optimizations.add(new Pass2ConstantAdditionElimination(program));
pass2OptimizeSSA(program, optimizations);
// Constant inlining optimizations - as the last step to ensure that constant identification has been completed
List<Pass2SsaOptimization> constantOptimizations = new ArrayList<>();
constantOptimizations.add(new Pass2ConstantInlining(program));
pass2OptimizeSSA(program, constantOptimizations);
}
private void pass2OptimizeSSA(Program program, List<Pass2SsaOptimization> optimizations) {
boolean ssaOptimized = true;
while (ssaOptimized) {
pass2AssertSSA(program);
ssaOptimized = false;
for (Pass2SsaOptimization optimization : optimizations) {
boolean stepOptimized = true;
while (stepOptimized) {
stepOptimized = optimization.optimize();
if (stepOptimized) {
program.getLog().append("Succesful SSA optimization " + optimization.getClass().getSimpleName() + "");
ssaOptimized = true;
program.getLog().append("CONTROL FLOW GRAPH");
program.getLog().append(program.getGraph().toString(program));
}
}
}
}
}
private void pass3Analysis(Program program) {
new Pass3BlockSequencePlanner(program).plan();
// Phi lifting ensures that all variables in phi-blocks are in different live range equivalence classes
new Pass3PhiLifting(program).perform();
new Pass3BlockSequencePlanner(program).plan();
program.getLog().append("CONTROL FLOW GRAPH - PHI LIFTED");
program.getLog().append(program.getGraph().toString(program));
pass2AssertSSA(program);
new Pass3AddNopBeforeCallOns(program).generate();
new Pass3StatementIndices(program).generateStatementIndices();
new Pass3CallGraphAnalysis(program).findCallGraph();
program.getLog().append("CALL GRAPH");
program.getLog().append(program.getCallGraph().toString());
//program.getLog().setVerboseLiveRanges(true);
new Pass3StatementInfos(program).generateStatementInfos();
new Pass3VariableReferenceInfos(program).generateVariableReferenceInfos();
new Pass3LiveRangesAnalysis(program).findLiveRanges();
program.getLog().append("CONTROL FLOW GRAPH - LIVE RANGES FOUND");
program.getLog().append(program.getGraph().toString(program));
pass2AssertSSA(program);
//program.getLog().setVerboseLiveRanges(false);
// Phi mem coalesce removes as many variables introduced by phi lifting as possible - as long as their live ranges do not overlap
new Pass3PhiMemCoalesce(program).optimize();
new Pass2CullEmptyBlocks(program).optimize();
new Pass3BlockSequencePlanner(program).plan();
new Pass3AddNopBeforeCallOns(program).generate();
new Pass3StatementIndices(program).generateStatementIndices();
new Pass3CallGraphAnalysis(program).findCallGraph();
new Pass3StatementInfos(program).generateStatementInfos();
new Pass3VariableReferenceInfos(program).generateVariableReferenceInfos();
new Pass3LiveRangesAnalysis(program).findLiveRanges();
program.getLog().append("CONTROL FLOW GRAPH - BEFORE EFFECTIVE LIVE RANGES");
program.getLog().append(program.getGraph().toString(program));
new Pass3LiveRangesEffectiveAnalysis(program).findLiveRangesEffective();
program.getLog().append("CONTROL FLOW GRAPH - PHI MEM COALESCED");
program.getLog().append(program.getGraph().toString(program));
pass2AssertSSA(program);
new Pass3DominatorsAnalysis(program).findDominators();
program.getLog().append("DOMINATORS");
program.getLog().append(program.getDominators().toString());
new Pass3LoopAnalysis(program).findLoops();
program.getLog().append("NATURAL LOOPS");
program.getLog().append(program.getLoopSet().toString());
new Pass3LoopDepthAnalysis(program).findLoopDepths();
program.getLog().append("NATURAL LOOPS WITH DEPTH");
program.getLog().append(program.getLoopSet().toString());
new Pass3VariableRegisterWeightAnalysis(program).findWeights();
program.getLog().append("\nVARIABLE REGISTER WEIGHTS");
program.getLog().append(program.getScope().toString(program, Variable.class));
}
private void pass4RegisterAllocation(Program program) {
new Pass4LiveRangeEquivalenceClassesFinalize(program).allocate();
new Pass4RegistersFinalize(program).allocate(true);
// Initial Code generation
new Pass4CodeGeneration(program, true).generate();
new Pass4AssertNoCpuClobber(program).check();
program.getLog().append("INITIAL ASM");
program.getLog().append(program.getAsm().toString());
// Find potential registers for each live range equivalence class - based on clobbering of fragments
program.getLog().append("REGISTER UPLIFT POTENTIAL REGISTERS");
new Pass4RegisterUpliftPotentialInitialize(program).initPotentialRegisters();
new Pass4RegisterUpliftPotentialAluAnalysis(program).findPotentialAlu();
boolean change;
do {
change = new Pass4RegisterUpliftPotentialRegisterAnalysis(program).findPotentialRegisters();
} while (change);
program.getLog().append(program.getRegisterPotentials().toString());
// Find register uplift scopes
new Pass4RegisterUpliftScopeAnalysis(program).findScopes();
program.getLog().append("REGISTER UPLIFT SCOPES");
program.getLog().append(program.getRegisterUpliftProgram().toString((program.getVariableRegisterWeights())));
// Attempt uplifting registers through a lot of combinations
//program.getLog().setVerboseUplift(true);
new Pass4RegisterUpliftCombinations(program).performUplift(10_000);
//program.getLog().setVerboseUplift(true);
//new Pass4RegisterUpliftStatic(program).performUplift();
//program.getLog().setVerboseUplift(false);
// Attempt uplifting registers one at a time to catch remaining potential not realized by combination search
new Pass4RegisterUpliftRemains(program).performUplift(10_000);
// Final register coalesce and finalization
new Pass4ZeroPageCoalesce(program).allocate();
new Pass4RegistersFinalize(program).allocate(true);
}
public void pass5GenerateAndOptimizeAsm(Program program) {
// Final ASM code generation before optimization
new Pass4CodeGeneration(program, true).generate();
new Pass4AssertNoCpuClobber(program).check();
List<Pass5AsmOptimization> pass5Optimizations = new ArrayList<>();
pass5Optimizations.add(new Pass5NextJumpElimination(program));
pass5Optimizations.add(new Pass5UnnecesaryLoadElimination(program));
pass5Optimizations.add(new Pass5RedundantLabelElimination(program));
pass5Optimizations.add(new Pass5UnusedLabelElimination(program));
boolean asmOptimized = true;
CompileLog log = program.getLog();
while (asmOptimized) {
asmOptimized = false;
for (Pass5AsmOptimization optimization : pass5Optimizations) {
boolean stepOptimized = optimization.optimize();
if (stepOptimized) {
log.append("Succesful ASM optimization " + optimization.getClass().getSimpleName());
asmOptimized = true;
log.append("ASSEMBLER");
log.append(program.getAsm().toString());
}
}
}
}
}