mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-06-10 10:29:36 +00:00
525 lines
21 KiB
Java
525 lines
21 KiB
Java
package dk.camelot64.kickc;
|
|
|
|
import dk.camelot64.kickc.model.Comment;
|
|
import dk.camelot64.kickc.model.CompileError;
|
|
import dk.camelot64.kickc.model.Program;
|
|
import dk.camelot64.kickc.model.StatementSequence;
|
|
import dk.camelot64.kickc.model.statements.StatementCall;
|
|
import dk.camelot64.kickc.model.statements.StatementSource;
|
|
import dk.camelot64.kickc.model.symbols.Variable;
|
|
import dk.camelot64.kickc.model.values.SymbolRef;
|
|
import dk.camelot64.kickc.parser.KickCLexer;
|
|
import dk.camelot64.kickc.parser.KickCParser;
|
|
import dk.camelot64.kickc.passes.*;
|
|
import org.antlr.v4.runtime.*;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.nio.file.Path;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Perform KickC compilation and optimizations
|
|
*/
|
|
public class Compiler {
|
|
|
|
private Program program;
|
|
|
|
/** The number of combinations to test when uplifting variables into registers. */
|
|
private int upliftCombinations = 100;
|
|
|
|
public Compiler() {
|
|
this.program = new Program();
|
|
}
|
|
|
|
public void setUpliftCombinations(int upliftCombinations) {
|
|
this.upliftCombinations = upliftCombinations;
|
|
}
|
|
|
|
public void setLog(CompileLog compileLog) {
|
|
program.setLog(compileLog);
|
|
}
|
|
|
|
public static void loadAndParseFile(String fileName, Program program, Path currentPath) {
|
|
try {
|
|
if(!fileName.endsWith(".kc")) {
|
|
fileName += ".kc";
|
|
}
|
|
File file = loadFile(fileName, currentPath, program);
|
|
List<String> imported = program.getImported();
|
|
if(imported.contains(file.getAbsolutePath())) {
|
|
return;
|
|
}
|
|
final CharStream fileStream = CharStreams.fromPath(file.toPath());
|
|
imported.add(file.getAbsolutePath());
|
|
if(program.getLog().isVerboseParse()) {
|
|
program.getLog().append("PARSING " + file.getPath().replace("\\", "/"));
|
|
program.getLog().append(fileStream.toString());
|
|
}
|
|
KickCLexer lexer = new KickCLexer(fileStream);
|
|
lexer.addErrorListener(new BaseErrorListener() {
|
|
@Override
|
|
public void syntaxError(
|
|
Recognizer<?, ?> recognizer,
|
|
Object offendingSymbol,
|
|
int line,
|
|
int charPositionInLine,
|
|
String msg,
|
|
RecognitionException e) {
|
|
throw new CompileError("Error parsing file " + fileStream.getSourceName() + "\n - Line: " + line + "\n - Message: " + msg);
|
|
}
|
|
});
|
|
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
|
KickCParser parser = new KickCParser(tokenStream);
|
|
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 CompileError("Error parsing file " + fileStream.getSourceName() + "\n - Line: " + line + "\n - Message: " + msg);
|
|
}
|
|
});
|
|
Pass0GenerateStatementSequence pass0GenerateStatementSequence = new Pass0GenerateStatementSequence(file, tokenStream, parser.file(), program);
|
|
pass0GenerateStatementSequence.generate();
|
|
} catch(IOException e) {
|
|
throw new CompileError("Error loading file " + fileName, e);
|
|
}
|
|
}
|
|
|
|
public static File loadFile(String fileName, Path currentPath, Program program) {
|
|
List<String> searchPaths = new ArrayList<>();
|
|
searchPaths.add(currentPath.toString());
|
|
searchPaths.addAll(program.getImportPaths());
|
|
for(String importPath : searchPaths) {
|
|
if(!importPath.endsWith("/")) {
|
|
importPath += "/";
|
|
}
|
|
String filePath = importPath + fileName;
|
|
//System.out.println("Looking for file "+filePath);
|
|
File file = new File(filePath);
|
|
if(file.exists()) {
|
|
//System.out.println("Found file "+file.getAbsolutePath()+" in import path "+importPath);
|
|
return file;
|
|
}
|
|
}
|
|
throw new CompileError("File not found " + fileName);
|
|
}
|
|
|
|
public CompileLog getLog() {
|
|
return program.getLog();
|
|
}
|
|
|
|
public void addImportPath(String path) {
|
|
program.getImportPaths().add(path);
|
|
}
|
|
|
|
public Program compile(String fileName) {
|
|
program.setFileName(fileName);
|
|
program.setStatementSequence(new StatementSequence());
|
|
try {
|
|
File currentPath = new File(".");
|
|
loadAndParseFile(fileName, program, currentPath.toPath());
|
|
|
|
StatementSequence sequence = program.getStatementSequence();
|
|
sequence.addStatement(new StatementCall(null, SymbolRef.MAIN_PROC_NAME, new ArrayList<>(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
|
|
program.setStatementSequence(sequence);
|
|
|
|
pass1GenerateSSA();
|
|
pass2Optimize();
|
|
pass2UnrollLoops();
|
|
pass2InlineConstants();
|
|
pass3Analysis();
|
|
pass4RegisterAllocation();
|
|
pass5GenerateAndOptimizeAsm();
|
|
return program;
|
|
} catch(Exception e) {
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
private Program pass1GenerateSSA() {
|
|
|
|
if(getLog().isVerboseStatementSequence()) {
|
|
getLog().append("\nSTATEMENTS");
|
|
getLog().append(program.getStatementSequence().toString(program));
|
|
}
|
|
|
|
new Pass1GenerateControlFlowGraph(program).execute();
|
|
new Pass1ResolveForwardReferences(program).execute();
|
|
new Pass1UnwindBlockScopes(program).execute();
|
|
new Pass1TypeInference(program).execute();
|
|
|
|
if(getLog().isVerbosePass1CreateSsa()) {
|
|
getLog().append("SYMBOLS");
|
|
getLog().append(program.getScope().getSymbolTableContents(program));
|
|
}
|
|
|
|
new Pass1FixLValuesLoHi(program).execute();
|
|
new Pass1AssertNoLValueIntermediate(program).execute();
|
|
new Pass1PointerSizeofFix(program).execute();
|
|
new Pass1AddTypePromotions(program).execute();
|
|
new Pass1EarlyConstantIdentification(program).execute();
|
|
new PassNStatementIndices(program).step();
|
|
new PassNCallGraphAnalysis(program).step();
|
|
new Pass1AssertNoRecursion(program).execute();
|
|
new Pass1AssertInterrupts(program).execute();
|
|
|
|
if(getLog().isVerbosePass1CreateSsa()) {
|
|
getLog().append("INITIAL CONTROL FLOW GRAPH");
|
|
getLog().append(program.getGraph().toString(program));
|
|
}
|
|
|
|
new Pass1AssertReturn(program).execute();
|
|
new Pass1AssertUsedVars(program).execute();
|
|
new Pass1ProcedureInline(program).execute();
|
|
new Pass1EliminateUncalledProcedures(program).execute();
|
|
new PassNEliminateUnusedVars(program, false).execute();
|
|
new Pass1ExtractInlineStrings(program).execute();
|
|
new Pass1EliminateEmptyBlocks(program).execute();
|
|
|
|
new Pass1ModifiedVarsAnalysis(program).execute();
|
|
if(getLog().isVerbosePass1CreateSsa()) {
|
|
getLog().append("PROCEDURE MODIFY VARIABLE ANALYSIS");
|
|
getLog().append(program.getProcedureModifiedVars().toString(program));
|
|
}
|
|
|
|
new Pass1ProcedureCallParameters(program).generate();
|
|
//getLog().append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL");
|
|
//getLog().append(program.getGraph().toString(program));
|
|
|
|
new Pass1GenerateSingleStaticAssignmentForm(program).execute();
|
|
|
|
//getLog().append("CONTROL FLOW GRAPH SSA");
|
|
//getLog().append(program.getGraph().toString(program));
|
|
|
|
program.setGraph(new Pass1ProcedureCallsReturnValue(program).generate());
|
|
|
|
getLog().append("\nCONTROL FLOW GRAPH SSA");
|
|
getLog().append(program.getGraph().toString(program));
|
|
|
|
getLog().append("SYMBOL TABLE SSA");
|
|
getLog().append(program.getScope().getSymbolTableContents(program));
|
|
|
|
return program;
|
|
}
|
|
|
|
private void pass2AssertSSA() {
|
|
List<Pass2SsaAssertion> assertions = new ArrayList<>();
|
|
assertions.add(new Pass2AssertTypeMatch(program));
|
|
assertions.add(new Pass2AssertSymbols(program));
|
|
assertions.add(new Pass2AssertBlocks(program));
|
|
assertions.add(new Pass2AssertNoCallParameters(program));
|
|
assertions.add(new Pass2AssertNoCallLvalues(program));
|
|
assertions.add(new Pass2AssertNoReturnValues(program));
|
|
assertions.add(new Pass2AssertNoProcs(program));
|
|
assertions.add(new Pass2AssertNoLabels(program));
|
|
assertions.add(new Pass2AssertSingleAssignment(program));
|
|
assertions.add(new Pass2AssertRValues(program));
|
|
for(Pass2SsaAssertion assertion : assertions) {
|
|
assertion.check();
|
|
}
|
|
}
|
|
|
|
private void pass2Optimize() {
|
|
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
|
|
optimizations.add(new Pass2CullEmptyBlocks(program));
|
|
optimizations.add(new PassNStatementIndices(program));
|
|
optimizations.add(new PassNVariableReferenceInfos(program));
|
|
optimizations.add(new Pass2UnaryNotSimplification(program));
|
|
optimizations.add(new Pass2AliasElimination(program));
|
|
optimizations.add(new Pass2SelfPhiElimination(program));
|
|
optimizations.add(new Pass2RedundantPhiElimination(program));
|
|
optimizations.add(new Pass2IdenticalPhiElimination(program));
|
|
optimizations.add(new Pass2ConditionalJumpSimplification(program));
|
|
optimizations.add(new Pass2ConditionalAndOrRewriting(program));
|
|
optimizations.add(new Pass2ConstantIdentification(program));
|
|
optimizations.add(new PassNStatementIndices(program));
|
|
optimizations.add(new PassNVariableReferenceInfos(program));
|
|
optimizations.add(new Pass2ConstantAdditionElimination(program));
|
|
optimizations.add(new Pass2ConstantIfs(program));
|
|
optimizations.add(new Pass2ConstantStringConsolidation(program));
|
|
optimizations.add(new Pass2FixInlineConstructors(program));
|
|
optimizations.add(new Pass2TypeInference(program));
|
|
optimizations.add(new PassNEliminateUnusedVars(program, true));
|
|
optimizations.add(new Pass2EliminateRedundantCasts(program));
|
|
optimizations.add(new Pass2NopCastElimination(program));
|
|
optimizations.add(new Pass2EliminateUnusedBlocks(program));
|
|
optimizations.add(new Pass2RangeResolving(program));
|
|
optimizations.add(new Pass2ComparisonOptimization(program));
|
|
optimizations.add(new Pass2ConstantCallPointerIdentification(program));
|
|
optimizations.add(new Pass2MultiplyToShiftRewriting(program));
|
|
optimizations.add(new Pass2SizeOfSimplification(program));
|
|
optimizations.add(new Pass2InlineDerefIdx(program));
|
|
pass2Execute(optimizations);
|
|
}
|
|
|
|
private void pass2UnrollLoops() {
|
|
List<Pass2SsaOptimization> loopUnrolling = new ArrayList<>();
|
|
loopUnrolling.add(new PassNStatementIndices(program));
|
|
loopUnrolling.add(new PassNVariableReferenceInfos(program));
|
|
loopUnrolling.add(new PassNStatementInfos(program));
|
|
loopUnrolling.add(new PassNDominatorsAnalysis(program));
|
|
loopUnrolling.add(new PassNLoopAnalysis(program));
|
|
loopUnrolling.add(new Pass2LoopUnrollPhiPrepare(program));
|
|
loopUnrolling.add(new Pass2LoopUnroll(program));
|
|
|
|
boolean unrolled;
|
|
do {
|
|
unrolled = pass2ExecuteOnce(loopUnrolling);
|
|
if(unrolled) {
|
|
if(getLog().isVerboseLoopUnroll()) {
|
|
getLog().append("UNROLLED CONTROL FLOW GRAPH");
|
|
getLog().append(program.getGraph().toString(program));
|
|
}
|
|
pass2Optimize();
|
|
new Pass2LoopUnrollAssertComplete(program).step();
|
|
new PassNBlockSequencePlanner(program).step();
|
|
}
|
|
} while(unrolled);
|
|
|
|
}
|
|
|
|
private void pass2InlineConstants() {
|
|
// 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));
|
|
constantOptimizations.add(new Pass2ConstantStringConsolidation(program));
|
|
constantOptimizations.add(new Pass2IdenticalPhiElimination(program));
|
|
constantOptimizations.add(new Pass2ConstantIdentification(program));
|
|
constantOptimizations.add(new Pass2ConstantAdditionElimination(program));
|
|
constantOptimizations.add(new Pass2ConstantSimplification(program));
|
|
constantOptimizations.add(new Pass2ConstantIfs(program));
|
|
pass2Execute(constantOptimizations);
|
|
|
|
}
|
|
|
|
/**
|
|
* Execute optimization steps repeatedly until none of them performs an optimization anymore
|
|
*
|
|
* @param optimizations The optimizations to repeat
|
|
*/
|
|
private void pass2Execute(List<Pass2SsaOptimization> optimizations) {
|
|
boolean ssaOptimized = true;
|
|
while(ssaOptimized) {
|
|
pass2AssertSSA();
|
|
ssaOptimized = false;
|
|
for(Pass2SsaOptimization optimization : optimizations) {
|
|
boolean stepOptimized = true;
|
|
while(stepOptimized) {
|
|
stepOptimized = optimization.step();
|
|
ssaOptimized = pass2LogOptimization(ssaOptimized, optimization, stepOptimized);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Repeat a set of optimizations steps once each.
|
|
*
|
|
* @param optimizations The optimizations
|
|
* @return true if any step performed an optimization
|
|
*/
|
|
private boolean pass2ExecuteOnce(List<Pass2SsaOptimization> optimizations) {
|
|
boolean ssaOptimized = false;
|
|
for(Pass2SsaOptimization optimization : optimizations) {
|
|
pass2AssertSSA();
|
|
boolean stepOptimized = optimization.step();
|
|
ssaOptimized = pass2LogOptimization(ssaOptimized, optimization, stepOptimized);
|
|
}
|
|
return ssaOptimized;
|
|
}
|
|
|
|
private boolean pass2LogOptimization(boolean ssaOptimized, Pass2SsaOptimization optimization, boolean stepOptimized) {
|
|
if(stepOptimized) {
|
|
getLog().append("Successful SSA optimization " + optimization.getClass().getSimpleName() + "");
|
|
ssaOptimized = true;
|
|
if(getLog().isVerboseSSAOptimize()) {
|
|
getLog().append("CONTROL FLOW GRAPH");
|
|
getLog().append(program.getGraph().toString(program));
|
|
}
|
|
}
|
|
return ssaOptimized;
|
|
}
|
|
|
|
private void pass3Analysis() {
|
|
new Pass3AssertRValues(program).check();
|
|
new Pass3AssertConstants(program).check();
|
|
new Pass3AssertArrayLengths(program).check();
|
|
new Pass3AssertNoMulDivMod(program).check();
|
|
new PassNBlockSequencePlanner(program).step();
|
|
// Phi lifting ensures that all variables in phi-blocks are in different live range equivalence classes
|
|
new Pass3PhiLifting(program).perform();
|
|
new PassNBlockSequencePlanner(program).step();
|
|
//getLog().append("CONTROL FLOW GRAPH - PHI LIFTED");
|
|
//getLog().append(program.getGraph().toString(program));
|
|
pass2AssertSSA();
|
|
new Pass3AddNopBeforeCallOns(program).generate();
|
|
new PassNStatementIndices(program).execute();
|
|
|
|
getLog().append("CALL GRAPH");
|
|
new PassNCallGraphAnalysis(program).step();
|
|
getLog().append(program.getCallGraph().toString());
|
|
|
|
//getLog().setVerboseLiveRanges(true);
|
|
|
|
new PassNStatementInfos(program).execute();
|
|
new PassNVariableReferenceInfos(program).execute();
|
|
new Pass3LiveRangesAnalysis(program).findLiveRanges();
|
|
//getLog().append("CONTROL FLOW GRAPH - LIVE RANGES FOUND");
|
|
//getLog().append(program.getGraph().toString(program));
|
|
pass2AssertSSA();
|
|
|
|
//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).step();
|
|
new Pass2CullEmptyBlocks(program).step();
|
|
new PassNRenumberLabels(program).execute();
|
|
new PassNBlockSequencePlanner(program).step();
|
|
new Pass3AddNopBeforeCallOns(program).generate();
|
|
new PassNStatementIndices(program).execute();
|
|
new PassNCallGraphAnalysis(program).step();
|
|
new PassNStatementInfos(program).execute();
|
|
new PassNVariableReferenceInfos(program).execute();
|
|
new Pass3SymbolInfos(program).generateSymbolInfos();
|
|
new Pass3LiveRangesAnalysis(program).findLiveRanges();
|
|
new Pass3LiveRangesEffectiveAnalysis(program).findLiveRangesEffective();
|
|
pass2AssertSSA();
|
|
|
|
getLog().append("\nFINAL CONTROL FLOW GRAPH");
|
|
getLog().append(program.getGraph().toString(program));
|
|
|
|
}
|
|
|
|
private void pass4RegisterAllocation() {
|
|
|
|
if(getLog().isVerboseLoopAnalysis()) {
|
|
getLog().append("DOMINATORS");
|
|
}
|
|
new PassNDominatorsAnalysis(program).step();
|
|
if(getLog().isVerboseLoopAnalysis()) {
|
|
getLog().append(program.getDominators().toString());
|
|
}
|
|
|
|
if(getLog().isVerboseLoopAnalysis()) {
|
|
getLog().append("NATURAL LOOPS");
|
|
}
|
|
new PassNLoopAnalysis(program).step();
|
|
if(getLog().isVerboseLoopAnalysis()) {
|
|
getLog().append(program.getLoopSet().toString());
|
|
}
|
|
|
|
if(getLog().isVerboseLoopAnalysis()) {
|
|
getLog().append("NATURAL LOOPS WITH DEPTH");
|
|
}
|
|
new Pass3LoopDepthAnalysis(program).findLoopDepths();
|
|
if(getLog().isVerboseLoopAnalysis()) {
|
|
getLog().append(program.getLoopSet().toString());
|
|
}
|
|
|
|
getLog().append("\nVARIABLE REGISTER WEIGHTS");
|
|
new Pass3VariableRegisterWeightAnalysis(program).findWeights();
|
|
getLog().append(program.getScope().toString(program, Variable.class));
|
|
|
|
new Pass4LiveRangeEquivalenceClassesFinalize(program).allocate();
|
|
new Pass4RegistersFinalize(program).allocate(true);
|
|
|
|
// Initial Code generation
|
|
new Pass4CodeGeneration(program, false).generate();
|
|
new Pass4AssertNoCpuClobber(program).check();
|
|
getLog().append("\nINITIAL ASM");
|
|
getLog().append(program.getAsm().toString());
|
|
|
|
// Find potential registers for each live range equivalence class - based on clobbering of fragments
|
|
getLog().append("REGISTER UPLIFT POTENTIAL REGISTERS");
|
|
new Pass4RegisterUpliftPotentialInitialize(program).initPotentialRegisters();
|
|
new Pass4RegisterUpliftPotentialAluAnalysis(program).findPotentialAlu();
|
|
boolean change;
|
|
do {
|
|
change = new Pass4RegisterUpliftPotentialRegisterAnalysis(program).findPotentialRegisters();
|
|
} while(change);
|
|
getLog().append(program.getRegisterPotentials().toString());
|
|
|
|
// Find register uplift scopes
|
|
getLog().append("REGISTER UPLIFT SCOPES");
|
|
new Pass4RegisterUpliftScopeAnalysis(program).findScopes();
|
|
getLog().append(program.getRegisterUpliftProgram().toString((program.getVariableRegisterWeights())));
|
|
|
|
// Attempt uplifting registers through a lot of combinations
|
|
//getLog().setVerboseUplift(true);
|
|
new Pass4RegisterUpliftCombinations(program).performUplift(upliftCombinations);
|
|
|
|
//getLog().setVerboseUplift(true);
|
|
//new Pass4RegisterUpliftStatic(program).performUplift();
|
|
//getLog().setVerboseUplift(false);
|
|
|
|
// Attempt uplifting registers one at a time to catch remaining potential not realized by combination search
|
|
new Pass4RegisterUpliftRemains(program).performUplift(upliftCombinations);
|
|
|
|
// Final register coalesce and finalization
|
|
new Pass4ZeroPageCoalesceAssignment(program).coalesce();
|
|
new Pass4ZeroPageCoalesce(program).coalesce();
|
|
new Pass4RegistersFinalize(program).allocate(true);
|
|
|
|
}
|
|
|
|
private void pass5GenerateAndOptimizeAsm() {
|
|
|
|
// Final ASM code generation before optimization
|
|
new Pass4CodeGeneration(program, false).generate();
|
|
new Pass4AssertNoCpuClobber(program).check();
|
|
|
|
// Remove unnecessary register savings from interrupts {@link InterruptType#HARDWARE_NOCLOBBER}
|
|
new Pass4InterruptClobberFix(program).fix();
|
|
|
|
getLog().append("\nASSEMBLER BEFORE OPTIMIZATION");
|
|
getLog().append(program.getAsm().toString());
|
|
|
|
getLog().append("ASSEMBLER OPTIMIZATIONS");
|
|
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));
|
|
pass5Optimizations.add(new Pass5SkipBegin(program));
|
|
pass5Optimizations.add(new Pass5DoubleJumpElimination(program));
|
|
pass5Optimizations.add(new Pass5UnreachableCodeElimination(program));
|
|
pass5Optimizations.add(new Pass5RelabelLongLabels(program));
|
|
pass5Optimizations.add(new Pass5SkipBegin(program));
|
|
pass5Optimizations.add(new Pass5AddMainRts(program));
|
|
boolean asmOptimized = true;
|
|
while(asmOptimized) {
|
|
asmOptimized = false;
|
|
for(Pass5AsmOptimization optimization : pass5Optimizations) {
|
|
boolean stepOptimized = optimization.optimize();
|
|
if(stepOptimized) {
|
|
getLog().append("Succesful ASM optimization " + optimization.getClass().getSimpleName());
|
|
asmOptimized = true;
|
|
if(getLog().isVerboseAsmOptimize()) {
|
|
getLog().append("ASSEMBLER");
|
|
getLog().append(program.getAsm().toString());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
new Pass5ReindexAsmLines(program).optimize();
|
|
new Pass5FixLongBranches(program).optimize();
|
|
|
|
getLog().append("\nFINAL SYMBOL TABLE");
|
|
getLog().append(program.getScope().getSymbolTableContents(program));
|
|
|
|
getLog().append("\nFINAL ASSEMBLER");
|
|
getLog().append("Score: " + Pass4RegisterUpliftCombinations.getAsmScore(program) + "\n");
|
|
getLog().append(program.getAsm().toString());
|
|
|
|
}
|
|
|
|
}
|