mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-01-26 15:30:28 +00:00
Implemented import functionality. Added import test. Closes #32.
This commit is contained in:
parent
78dd8bc149
commit
41fd3bc436
@ -6,6 +6,8 @@ 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.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -14,23 +16,39 @@ import java.util.List;
|
||||
*/
|
||||
public class Compiler {
|
||||
|
||||
public Program compile(final CharStream input) {
|
||||
CompileLog log = new CompileLog();
|
||||
private Program program;
|
||||
|
||||
public Compiler() {
|
||||
this.program = new Program(new ProgramScope(), new CompileLog());
|
||||
this.program.setImportPaths(new ArrayList<>());
|
||||
}
|
||||
|
||||
public CompileLog getLog() {
|
||||
return program.getLog();
|
||||
}
|
||||
|
||||
public void addImportPath(String path) {
|
||||
program.getImportPaths().add(path);
|
||||
}
|
||||
|
||||
public Program compile(String fileName) throws IOException {
|
||||
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());
|
||||
|
||||
StatementSequenceGenerator statementSequenceGenerator = new StatementSequenceGenerator(program);
|
||||
loadAndParseFile(fileName, program, statementSequenceGenerator);
|
||||
StatementSequence sequence = statementSequenceGenerator.getSequence();
|
||||
sequence.addStatement(new StatementCall(null, "main", new ArrayList<>()));
|
||||
program.setStatementSequence(sequence);
|
||||
pass1GenerateSSA();
|
||||
pass2OptimizeSSA();
|
||||
getLog().append("FINAL SYMBOL TABLE");
|
||||
getLog().append(program.getScope().getSymbolTableContents(program));
|
||||
pass3Analysis();
|
||||
pass4RegisterAllocation();
|
||||
pass5GenerateAndOptimizeAsm();
|
||||
getLog().append("FINAL SYMBOL TABLE");
|
||||
getLog().append(program.getScope().getSymbolTableContents(program));
|
||||
getLog().append("FINAL CODE");
|
||||
getLog().append(program.getAsm().toString());
|
||||
return program;
|
||||
} catch (Exception e) {
|
||||
//System.out.println(log.getLog());
|
||||
@ -38,9 +56,10 @@ public class Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
public KickCParser.FileContext pass0ParseInput(final CharStream input, CompileLog log) {
|
||||
log.append(input.toString());
|
||||
KickCLexer lexer = new KickCLexer(input);
|
||||
public static void loadAndParseFile(String fileName, Program program, StatementSequenceGenerator statementSequenceGenerator) {
|
||||
CharStream fileStream = loadFile(fileName, program);
|
||||
program.getLog().append(fileStream.toString());
|
||||
KickCLexer lexer = new KickCLexer(fileStream);
|
||||
KickCParser parser = new KickCParser(new CommonTokenStream(lexer));
|
||||
parser.setBuildParseTree(true);
|
||||
parser.addErrorListener(new BaseErrorListener() {
|
||||
@ -52,64 +71,80 @@ public class Compiler {
|
||||
int charPositionInLine,
|
||||
String msg,
|
||||
RecognitionException e) {
|
||||
throw new CompileError("Error parsing file " + input.getSourceName() + "\n - Line: " + line + "\n - Message: " + msg);
|
||||
throw new CompileError("Error parsing file " + fileStream.getSourceName() + "\n - Line: " + line + "\n - Message: " + msg);
|
||||
}
|
||||
});
|
||||
return parser.file();
|
||||
statementSequenceGenerator.generate(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);
|
||||
private static CharStream loadFile(String fileName, Program program) {
|
||||
if(!fileName.endsWith(".kc")) {
|
||||
fileName += ".kc";
|
||||
}
|
||||
try {
|
||||
List<String> importPaths = program.getImportPaths();
|
||||
for (String importPath : importPaths) {
|
||||
if(!importPath.endsWith("/")) {
|
||||
importPath += "/";
|
||||
}
|
||||
String filePath = importPath + fileName;
|
||||
File file = new File(filePath);
|
||||
if(file.exists()) {
|
||||
return CharStreams.fromPath(file.toPath());
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new CompileError("Error loading file " + fileName, e);
|
||||
}
|
||||
throw new CompileError("File not found " + fileName);
|
||||
}
|
||||
|
||||
Program program = new Program(programScope, log);
|
||||
log.append("PROGRAM");
|
||||
log.append(statementSequence.toString(program));
|
||||
log.append("SYMBOLS");
|
||||
log.append(programScope.getSymbolTableContents(program));
|
||||
program.setGraph(new Pass1GenerateControlFlowGraph(programScope).generate(statementSequence));
|
||||
private Program pass1GenerateSSA() {
|
||||
new Pass1FixLvalueLoHi(program).execute();
|
||||
new Pass1TypeInference(program).execute();
|
||||
|
||||
getLog().append("PROGRAM");
|
||||
getLog().append(program.getStatementSequence().toString(program));
|
||||
getLog().append("SYMBOLS");
|
||||
getLog().append(program.getScope().getSymbolTableContents(program));
|
||||
new Pass1GenerateControlFlowGraph(program).execute();
|
||||
|
||||
new Pass1AddTypePromotions(program).execute();
|
||||
log.append("INITIAL CONTROL FLOW GRAPH");
|
||||
log.append(program.getGraph().toString(program));
|
||||
getLog().append("INITIAL CONTROL FLOW GRAPH");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
|
||||
new Pass1ExtractInlineStrings(program).execute();
|
||||
new Pass1EliminateUncalledProcedures(program).execute();
|
||||
new Pass1EliminateUnusedVars(program).execute();
|
||||
|
||||
new Pass1EliminateEmptyBlocks(program).execute();
|
||||
log.append("CONTROL FLOW GRAPH");
|
||||
log.append(program.getGraph().toString(program));
|
||||
getLog().append("CONTROL FLOW GRAPH");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
|
||||
new Pass1ModifiedVarsAnalysis(program).execute();
|
||||
log.append("PROCEDURE MODIFY VARIABLE ANALYSIS");
|
||||
log.append(program.getProcedureModifiedVars().toString(program));
|
||||
getLog().append("PROCEDURE MODIFY VARIABLE ANALYSIS");
|
||||
getLog().append(program.getProcedureModifiedVars().toString(program));
|
||||
|
||||
new Pass1ProcedureCallParameters(program).generate();
|
||||
log.append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL");
|
||||
log.append(program.getGraph().toString(program));
|
||||
getLog().append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
|
||||
new Pass1GenerateSingleStaticAssignmentForm(program).execute();
|
||||
|
||||
log.append("CONTROL FLOW GRAPH SSA");
|
||||
log.append(program.getGraph().toString(program));
|
||||
getLog().append("CONTROL FLOW GRAPH SSA");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
|
||||
program.setGraph(new Pass1ProcedureCallsReturnValue(program).generate());
|
||||
log.append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN");
|
||||
log.append(program.getGraph().toString(program));
|
||||
getLog().append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
|
||||
log.append("INITIAL SSA SYMBOL TABLE");
|
||||
log.append(program.getScope().getSymbolTableContents(program));
|
||||
getLog().append("INITIAL SSA SYMBOL TABLE");
|
||||
getLog().append(program.getScope().getSymbolTableContents(program));
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
public void pass2AssertSSA(Program program) {
|
||||
private void pass2AssertSSA() {
|
||||
List<Pass2SsaAssertion> assertions = new ArrayList<>();
|
||||
assertions.add(new Pass2AssertTypeMatch(program));
|
||||
assertions.add(new Pass2AssertSymbols(program));
|
||||
@ -126,7 +161,7 @@ public class Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
public void pass2OptimizeSSA(Program program) {
|
||||
private void pass2OptimizeSSA() {
|
||||
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
|
||||
optimizations.add(new Pass2CullEmptyBlocks(program));
|
||||
optimizations.add(new Pass2UnaryNotSimplification(program));
|
||||
@ -136,29 +171,29 @@ public class Compiler {
|
||||
optimizations.add(new Pass2ConditionalJumpSimplification(program));
|
||||
optimizations.add(new Pass2ConstantIdentification(program));
|
||||
optimizations.add(new Pass2ConstantAdditionElimination(program));
|
||||
pass2OptimizeSSA(program, optimizations);
|
||||
pass2OptimizeSSA(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);
|
||||
pass2OptimizeSSA(constantOptimizations);
|
||||
|
||||
}
|
||||
|
||||
private void pass2OptimizeSSA(Program program, List<Pass2SsaOptimization> optimizations) {
|
||||
private void pass2OptimizeSSA(List<Pass2SsaOptimization> optimizations) {
|
||||
boolean ssaOptimized = true;
|
||||
while (ssaOptimized) {
|
||||
pass2AssertSSA(program);
|
||||
pass2AssertSSA();
|
||||
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() + "");
|
||||
getLog().append("Succesful SSA optimization " + optimization.getClass().getSimpleName() + "");
|
||||
ssaOptimized = true;
|
||||
program.getLog().append("CONTROL FLOW GRAPH");
|
||||
program.getLog().append(program.getGraph().toString(program));
|
||||
getLog().append("CONTROL FLOW GRAPH");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
//pass2AssertSSA(program);
|
||||
}
|
||||
}
|
||||
@ -166,34 +201,34 @@ public class Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
private void pass3Analysis(Program program) {
|
||||
private void pass3Analysis() {
|
||||
|
||||
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);
|
||||
getLog().append("CONTROL FLOW GRAPH - PHI LIFTED");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
pass2AssertSSA();
|
||||
|
||||
new Pass3AddNopBeforeCallOns(program).generate();
|
||||
new Pass3StatementIndices(program).generateStatementIndices();
|
||||
|
||||
new Pass3CallGraphAnalysis(program).findCallGraph();
|
||||
program.getLog().append("CALL GRAPH");
|
||||
program.getLog().append(program.getCallGraph().toString());
|
||||
getLog().append("CALL GRAPH");
|
||||
getLog().append(program.getCallGraph().toString());
|
||||
|
||||
//program.getLog().setVerboseLiveRanges(true);
|
||||
//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);
|
||||
getLog().append("CONTROL FLOW GRAPH - LIVE RANGES FOUND");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
pass2AssertSSA();
|
||||
|
||||
//program.getLog().setVerboseLiveRanges(false);
|
||||
//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();
|
||||
@ -206,32 +241,32 @@ public class Compiler {
|
||||
new Pass3VariableReferenceInfos(program).generateVariableReferenceInfos();
|
||||
new Pass3SymbolInfos(program).generateSymbolInfos();
|
||||
new Pass3LiveRangesAnalysis(program).findLiveRanges();
|
||||
program.getLog().append("CONTROL FLOW GRAPH - BEFORE EFFECTIVE LIVE RANGES");
|
||||
program.getLog().append(program.getGraph().toString(program));
|
||||
getLog().append("CONTROL FLOW GRAPH - BEFORE EFFECTIVE LIVE RANGES");
|
||||
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);
|
||||
getLog().append("CONTROL FLOW GRAPH - PHI MEM COALESCED");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
pass2AssertSSA();
|
||||
|
||||
new Pass3DominatorsAnalysis(program).findDominators();
|
||||
program.getLog().append("DOMINATORS");
|
||||
program.getLog().append(program.getDominators().toString());
|
||||
getLog().append("DOMINATORS");
|
||||
getLog().append(program.getDominators().toString());
|
||||
|
||||
new Pass3LoopAnalysis(program).findLoops();
|
||||
program.getLog().append("NATURAL LOOPS");
|
||||
program.getLog().append(program.getLoopSet().toString());
|
||||
getLog().append("NATURAL LOOPS");
|
||||
getLog().append(program.getLoopSet().toString());
|
||||
|
||||
new Pass3LoopDepthAnalysis(program).findLoopDepths();
|
||||
program.getLog().append("NATURAL LOOPS WITH DEPTH");
|
||||
program.getLog().append(program.getLoopSet().toString());
|
||||
getLog().append("NATURAL LOOPS WITH DEPTH");
|
||||
getLog().append(program.getLoopSet().toString());
|
||||
|
||||
new Pass3VariableRegisterWeightAnalysis(program).findWeights();
|
||||
program.getLog().append("\nVARIABLE REGISTER WEIGHTS");
|
||||
program.getLog().append(program.getScope().toString(program, Variable.class));
|
||||
getLog().append("\nVARIABLE REGISTER WEIGHTS");
|
||||
getLog().append(program.getScope().toString(program, Variable.class));
|
||||
|
||||
}
|
||||
|
||||
private void pass4RegisterAllocation(Program program) {
|
||||
private void pass4RegisterAllocation() {
|
||||
|
||||
new Pass4LiveRangeEquivalenceClassesFinalize(program).allocate();
|
||||
new Pass4RegistersFinalize(program).allocate(true);
|
||||
@ -239,31 +274,31 @@ public class Compiler {
|
||||
// Initial Code generation
|
||||
new Pass4CodeGeneration(program, true).generate();
|
||||
new Pass4AssertNoCpuClobber(program).check();
|
||||
program.getLog().append("INITIAL ASM");
|
||||
program.getLog().append(program.getAsm().toString());
|
||||
getLog().append("INITIAL ASM");
|
||||
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");
|
||||
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());
|
||||
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())));
|
||||
getLog().append("REGISTER UPLIFT SCOPES");
|
||||
getLog().append(program.getRegisterUpliftProgram().toString((program.getVariableRegisterWeights())));
|
||||
|
||||
// Attempt uplifting registers through a lot of combinations
|
||||
//program.getLog().setVerboseUplift(true);
|
||||
//getLog().setVerboseUplift(true);
|
||||
new Pass4RegisterUpliftCombinations(program).performUplift(10_000);
|
||||
|
||||
//program.getLog().setVerboseUplift(true);
|
||||
//getLog().setVerboseUplift(true);
|
||||
//new Pass4RegisterUpliftStatic(program).performUplift();
|
||||
//program.getLog().setVerboseUplift(false);
|
||||
//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);
|
||||
@ -274,7 +309,7 @@ public class Compiler {
|
||||
|
||||
}
|
||||
|
||||
public void pass5GenerateAndOptimizeAsm(Program program) {
|
||||
private void pass5GenerateAndOptimizeAsm() {
|
||||
|
||||
// Final ASM code generation before optimization
|
||||
new Pass4CodeGeneration(program, true).generate();
|
||||
@ -288,16 +323,15 @@ public class Compiler {
|
||||
pass5Optimizations.add(new Pass5DoubleJumpElimination(program));
|
||||
pass5Optimizations.add(new Pass5UnreachableCodeElimination(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());
|
||||
getLog().append("Succesful ASM optimization " + optimization.getClass().getSimpleName());
|
||||
asmOptimized = true;
|
||||
log.append("ASSEMBLER");
|
||||
log.append(program.getAsm().toString());
|
||||
getLog().append("ASSEMBLER");
|
||||
getLog().append(program.getAsm().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,5 +7,7 @@ public class CompileError extends RuntimeException {
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
public CompileError(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,15 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import dk.camelot64.kickc.CompileLog;
|
||||
import dk.camelot64.kickc.asm.AsmProgram;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** A KickC Intermediate Compiler Language (ICL) Program */
|
||||
public class Program {
|
||||
|
||||
/** Paths used for importing files. */
|
||||
private List<String> importPaths;
|
||||
/** The initial statement sequence generated byt the parser. */
|
||||
private StatementSequence statementSequence;
|
||||
/** The main scope. */
|
||||
private ProgramScope scope;
|
||||
/** The control flow graph. */
|
||||
@ -29,7 +35,9 @@ public class Program {
|
||||
|
||||
/** Which block is each statement a part of. */
|
||||
private StatementInfos statementInfos;
|
||||
/** The variables freferenced by blocks/statements. */
|
||||
/** 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;
|
||||
@ -43,7 +51,6 @@ public class Program {
|
||||
private RegisterPotentials registerPotentials;
|
||||
/** Separation of live range equivalence classes into scopes - used for register uplift */
|
||||
private RegisterUpliftProgram registerUpliftProgram;
|
||||
private SymbolInfos symbolInfos;
|
||||
|
||||
@JsonCreator
|
||||
public Program(
|
||||
@ -60,6 +67,22 @@ public class Program {
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
public List<String> getImportPaths() {
|
||||
return importPaths;
|
||||
}
|
||||
|
||||
public void setImportPaths(List<String> importPaths) {
|
||||
this.importPaths = importPaths;
|
||||
}
|
||||
|
||||
public StatementSequence getStatementSequence() {
|
||||
return statementSequence;
|
||||
}
|
||||
|
||||
public void setStatementSequence(StatementSequence statementSequence) {
|
||||
this.statementSequence = statementSequence;
|
||||
}
|
||||
|
||||
public ProgramScope getScope() {
|
||||
return scope;
|
||||
}
|
||||
@ -108,7 +131,7 @@ public class Program {
|
||||
return dominators;
|
||||
}
|
||||
|
||||
public void setLoops(NaturalLoopSet loopSet) {
|
||||
public void setLoopSet(NaturalLoopSet loopSet) {
|
||||
this.loopSet = loopSet;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ asmFile
|
||||
;
|
||||
|
||||
importSeq
|
||||
: importDecl+
|
||||
: importDecl*
|
||||
;
|
||||
|
||||
importDecl
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -14,7 +14,6 @@ public class Pass1AddTypePromotions extends Pass1Base {
|
||||
super(program);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean executeStep() {
|
||||
for (ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.CompileLog;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
|
||||
import java.util.Stack;
|
||||
@ -10,24 +9,18 @@ import java.util.Stack;
|
||||
* <br>Example: <code><plotter = x & 8 </code>
|
||||
* <br>Becomes: <code> $1 =x & 8 , plotter = plotter lo= $1 </code>
|
||||
*/
|
||||
public class Pass1FixLvalueLoHi {
|
||||
public class Pass1FixLvalueLoHi extends Pass1Base {
|
||||
|
||||
private final StatementSequence statementSequence;
|
||||
private final ProgramScope programScope;
|
||||
private CompileLog log;
|
||||
|
||||
|
||||
public Pass1FixLvalueLoHi(StatementSequence statementSequence, ProgramScope programScope, CompileLog log) {
|
||||
this.statementSequence = statementSequence;
|
||||
this.programScope = programScope;
|
||||
this.log = log;
|
||||
public Pass1FixLvalueLoHi(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
public StatementSequence fix() {
|
||||
@Override
|
||||
boolean executeStep() {
|
||||
Stack<Scope> scopeStack = new Stack<>();
|
||||
scopeStack.push(programScope);
|
||||
scopeStack.push(getScope());
|
||||
StatementSequence fixedSequence = new StatementSequence();
|
||||
for (Statement statement : statementSequence.getStatements()) {
|
||||
for (Statement statement : getProgram().getStatementSequence().getStatements()) {
|
||||
if (statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
if (assignment.getlValue() instanceof LvalueLoHiByte) {
|
||||
@ -40,11 +33,11 @@ public class Pass1FixLvalueLoHi {
|
||||
fixedSequence.addStatement(tmpAssignment);
|
||||
Statement setLoHiAssignment = new StatementAssignment(loHiByte.getVariable(), loHiByte.getVariable(), loHiByte.getOperator(), tmpVarRef);
|
||||
fixedSequence.addStatement(setLoHiAssignment);
|
||||
log.append("Fixing lo/hi-lvalue with new tmpVar " + tmpVarRef + " " + assignment.toString());
|
||||
getLog().append("Fixing lo/hi-lvalue with new tmpVar " + tmpVarRef + " " + assignment.toString());
|
||||
} else {
|
||||
Statement setLoHiAssignment = new StatementAssignment(loHiByte.getVariable(), loHiByte.getVariable(), loHiByte.getOperator(), assignment.getrValue2());
|
||||
fixedSequence.addStatement(setLoHiAssignment);
|
||||
log.append("Fixing lo/hi-lvalue " + assignment.toString());
|
||||
getLog().append("Fixing lo/hi-lvalue " + assignment.toString());
|
||||
}
|
||||
} else {
|
||||
fixedSequence.addStatement(statement);
|
||||
@ -54,13 +47,14 @@ public class Pass1FixLvalueLoHi {
|
||||
}
|
||||
if (statement instanceof StatementProcedureBegin) {
|
||||
ProcedureRef procedureRef = ((StatementProcedureBegin) statement).getProcedure();
|
||||
Procedure procedure = programScope.getProcedure(procedureRef);
|
||||
Procedure procedure = getScope().getProcedure(procedureRef);
|
||||
scopeStack.push(procedure);
|
||||
} else if (statement instanceof StatementProcedureEnd) {
|
||||
scopeStack.pop();
|
||||
}
|
||||
}
|
||||
return fixedSequence;
|
||||
getProgram().setStatementSequence(fixedSequence);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,19 +7,20 @@ import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
/** Pass that generates a control flow graph for the program */
|
||||
public class Pass1GenerateControlFlowGraph {
|
||||
public class Pass1GenerateControlFlowGraph extends Pass1Base {
|
||||
|
||||
private ProgramScope scope;
|
||||
private Map<LabelRef, ControlFlowBlock> blocks;
|
||||
private ControlFlowBlock firstBlock;
|
||||
|
||||
public Pass1GenerateControlFlowGraph(ProgramScope scope) {
|
||||
this.scope = scope;
|
||||
this.blocks = new LinkedHashMap<>();
|
||||
public Pass1GenerateControlFlowGraph(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
public ControlFlowGraph generate(StatementSequence sequence) {
|
||||
this.firstBlock = getOrCreateBlock(scope.addLabel(SymbolRef.BEGIN_BLOCK_NAME).getRef(), ScopeRef.ROOT);
|
||||
private Map<LabelRef, ControlFlowBlock> blocks;
|
||||
|
||||
@Override
|
||||
boolean executeStep() {
|
||||
this.blocks = new LinkedHashMap<>();
|
||||
ProgramScope scope = getScope();
|
||||
StatementSequence sequence = getProgram().getStatementSequence();
|
||||
ControlFlowBlock firstBlock = getOrCreateBlock(scope.addLabel(SymbolRef.BEGIN_BLOCK_NAME).getRef(), ScopeRef.ROOT);
|
||||
Stack<ControlFlowBlock> blockStack = new Stack<>();
|
||||
blockStack.push(firstBlock);
|
||||
sequence.addStatement(new StatementLabel(scope.addLabel(SymbolRef.END_BLOCK_NAME).getRef()));
|
||||
@ -79,8 +80,9 @@ public class Pass1GenerateControlFlowGraph {
|
||||
currentBlock.addStatement(statement);
|
||||
}
|
||||
}
|
||||
|
||||
return new ControlFlowGraph(blocks, firstBlock.getLabel());
|
||||
ControlFlowGraph controlFlowGraph = new ControlFlowGraph(blocks, firstBlock.getLabel());
|
||||
getProgram().setGraph(controlFlowGraph);
|
||||
return false;
|
||||
}
|
||||
|
||||
private ControlFlowBlock getOrCreateBlock(LabelRef label, ScopeRef scope) {
|
||||
|
@ -8,22 +8,18 @@ import java.util.Stack;
|
||||
* Pass through the generated statements inferring types of unresolved variables.
|
||||
* Also updates procedure calls to point to the actual procedure called.
|
||||
*/
|
||||
public class Pass1TypeInference {
|
||||
public class Pass1TypeInference extends Pass1Base {
|
||||
|
||||
private ProgramScope programScope;
|
||||
|
||||
public Pass1TypeInference(ProgramScope programScope) {
|
||||
this.programScope = programScope;
|
||||
public Pass1TypeInference(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
public ProgramScope getProgramScope() {
|
||||
return programScope;
|
||||
}
|
||||
|
||||
public void inferTypes(StatementSequence sequence) {
|
||||
@Override
|
||||
boolean executeStep() {
|
||||
Stack<Scope> scopes = new Stack<>();
|
||||
ProgramScope programScope = getScope();
|
||||
scopes.add(programScope);
|
||||
for (Statement statement : sequence.getStatements()) {
|
||||
for (Statement statement : getProgram().getStatementSequence().getStatements()) {
|
||||
if(statement instanceof StatementProcedureBegin) {
|
||||
StatementProcedureBegin procedureBegin = (StatementProcedureBegin) statement;
|
||||
ProcedureRef procedureRef = procedureBegin.getProcedure();
|
||||
@ -66,6 +62,7 @@ public class Pass1TypeInference {
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ public class Pass3LoopAnalysis extends Pass2Base {
|
||||
}
|
||||
}
|
||||
|
||||
getProgram().setLoops(loopSet);
|
||||
getProgram().setLoopSet(loopSet);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.CompileLog;
|
||||
import dk.camelot64.kickc.Compiler;
|
||||
import dk.camelot64.kickc.NumberParser;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.parser.KickCBaseVisitor;
|
||||
@ -15,23 +15,19 @@ import java.util.Stack;
|
||||
/**
|
||||
* Generates program SSA form by visiting the ANTLR4 parse tree
|
||||
*/
|
||||
public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
public class StatementSequenceGenerator extends KickCBaseVisitor<Object> {
|
||||
|
||||
private Program program;
|
||||
private Stack<Scope> scopeStack;
|
||||
private StatementSequence sequence;
|
||||
|
||||
public Pass1GenerateStatementSequence(CompileLog log) {
|
||||
this.program = new Program(new ProgramScope(), log);
|
||||
public StatementSequenceGenerator(Program program) {
|
||||
this.program = program;
|
||||
this.scopeStack = new Stack<>();
|
||||
scopeStack.push(program.getScope());
|
||||
this.sequence = new StatementSequence();
|
||||
}
|
||||
|
||||
public ProgramScope getProgramScope() {
|
||||
return program.getScope();
|
||||
}
|
||||
|
||||
private Scope getCurrentSymbols() {
|
||||
return scopeStack.peek();
|
||||
}
|
||||
@ -47,7 +43,6 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
|
||||
public void generate(KickCParser.FileContext file) {
|
||||
this.visit(file);
|
||||
sequence.addStatement(new StatementCall(null, "main", new ArrayList<RValue>()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -68,9 +63,10 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
@Override
|
||||
public Object visitImportDecl(KickCParser.ImportDeclContext ctx) {
|
||||
String importName = ctx.STRING().getText();
|
||||
program.getLog().append("Importing "+importName.substring(1, importName.length() - 1));
|
||||
throw new RuntimeException("TODO: Implement importing!");
|
||||
//return null;
|
||||
String importFileName = importName.substring(1, importName.length() - 1);
|
||||
program.getLog().append("Importing "+ importFileName);
|
||||
Compiler.loadAndParseFile(importFileName, program, this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -638,9 +634,9 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
|
||||
private List<PrePostModifier> postMods;
|
||||
private List<PrePostModifier> preMods;
|
||||
private Pass1GenerateStatementSequence mainParser;
|
||||
private StatementSequenceGenerator mainParser;
|
||||
|
||||
public PrePostModifierHandler(Pass1GenerateStatementSequence mainParser) {
|
||||
public PrePostModifierHandler(StatementSequenceGenerator mainParser) {
|
||||
this.mainParser = mainParser;
|
||||
preMods = new ArrayList<>();
|
||||
postMods = new ArrayList<>();
|
||||
@ -654,14 +650,14 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
return postMods;
|
||||
}
|
||||
|
||||
public static void addPostModifiers(Pass1GenerateStatementSequence parser, ParserRuleContext ctx) {
|
||||
public static void addPostModifiers(StatementSequenceGenerator parser, ParserRuleContext ctx) {
|
||||
PrePostModifierHandler prePostModifierHandler = new PrePostModifierHandler(parser);
|
||||
prePostModifierHandler.visit(ctx);
|
||||
List<PrePostModifier> modifiers = prePostModifierHandler.getPostMods();
|
||||
addModifierStatements(parser, modifiers);
|
||||
}
|
||||
|
||||
public static void addPreModifiers(Pass1GenerateStatementSequence parser, ParserRuleContext ctx) {
|
||||
public static void addPreModifiers(StatementSequenceGenerator parser, ParserRuleContext ctx) {
|
||||
PrePostModifierHandler modifierHandler = new PrePostModifierHandler(parser);
|
||||
modifierHandler.visit(ctx);
|
||||
List<PrePostModifier> modifiers = modifierHandler.getPreMods();
|
||||
@ -669,7 +665,7 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
}
|
||||
|
||||
private static void addModifierStatements(
|
||||
Pass1GenerateStatementSequence parser,
|
||||
StatementSequenceGenerator parser,
|
||||
List<PrePostModifier> modifiers) {
|
||||
for (PrePostModifier mod : modifiers) {
|
||||
Statement stmt = new StatementAssignment((LValue) mod.child, mod.operator, mod.child);
|
@ -53,11 +53,10 @@ public class TestErrors extends TestCase {
|
||||
}
|
||||
|
||||
private void testFile(String fileName) throws IOException, URISyntaxException {
|
||||
String inputPath = testPath + fileName + ".kc";
|
||||
System.out.println("Testing output for " + inputPath);
|
||||
CharStream input = CharStreams.fromFileName(inputPath);
|
||||
System.out.println("Testing output for " + fileName);
|
||||
Compiler compiler = new Compiler();
|
||||
Program program = compiler.compile(input);
|
||||
compiler.addImportPath(testPath);
|
||||
Program program = compiler.compile(fileName);
|
||||
boolean success = true;
|
||||
success &= helper.testOutput(fileName, ".asm", program.getAsm().toString(false));
|
||||
success &= helper.testOutput(fileName, ".sym", program.getScope().getSymbolTableContents(program));
|
||||
|
@ -282,11 +282,10 @@ public class TestPrograms extends TestCase {
|
||||
}
|
||||
|
||||
private void testFile(String fileName) throws IOException, URISyntaxException {
|
||||
String inputPath = testPath + fileName + ".kc";
|
||||
System.out.println("Testing output for " + inputPath);
|
||||
CharStream input = CharStreams.fromFileName(inputPath);
|
||||
System.out.println("Testing output for " + fileName);
|
||||
Compiler compiler = new Compiler();
|
||||
Program program = compiler.compile(input);
|
||||
compiler.addImportPath(testPath);
|
||||
Program program = compiler.compile(fileName);
|
||||
boolean success = true;
|
||||
success &= helper.testOutput(fileName, ".asm", program.getAsm().toString(false));
|
||||
success &= helper.testOutput(fileName, ".sym", program.getScope().getSymbolTableContents(program));
|
||||
|
14
src/main/java/dk/camelot64/kickc/test/ref/importing.asm
Normal file
14
src/main/java/dk/camelot64/kickc/test/ref/importing.asm
Normal file
@ -0,0 +1,14 @@
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.const BGCOL = $d021
|
||||
.const RED = 2
|
||||
jsr main
|
||||
main: {
|
||||
.const screen = $400
|
||||
lda #1
|
||||
sta screen
|
||||
lda #RED
|
||||
sta BGCOL
|
||||
rts
|
||||
}
|
16
src/main/java/dk/camelot64/kickc/test/ref/importing.cfg
Normal file
16
src/main/java/dk/camelot64/kickc/test/ref/importing.cfg
Normal file
@ -0,0 +1,16 @@
|
||||
@begin: scope:[] from
|
||||
[0] phi() [ ] ( )
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi() [ ] ( )
|
||||
[2] call main param-assignment [ ] ( )
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
[3] phi() [ ] ( )
|
||||
main: scope:[main] from @1
|
||||
[4] *((const byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1 [ ] ( main:2 [ ] )
|
||||
[5] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] )
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[6] return [ ] ( main:2 [ ] )
|
||||
to:@return
|
568
src/main/java/dk/camelot64/kickc/test/ref/importing.log
Normal file
568
src/main/java/dk/camelot64/kickc/test/ref/importing.log
Normal file
@ -0,0 +1,568 @@
|
||||
import "imported.kc"
|
||||
|
||||
void main() {
|
||||
byte* screen = $0400;
|
||||
*screen = 1;
|
||||
*BGCOL = RED;
|
||||
}
|
||||
Importing imported.kc
|
||||
const byte *BGCOL = $d021;
|
||||
const byte RED = 2;
|
||||
|
||||
PROGRAM
|
||||
(byte*) BGCOL ← (word) 53281
|
||||
(byte) RED ← (byte/signed byte/word/signed word) 2
|
||||
proc (void()) main()
|
||||
(byte*) main::screen ← (word/signed word) 1024
|
||||
*((byte*) main::screen) ← (byte/signed byte/word/signed word) 1
|
||||
*((byte*) BGCOL) ← (byte) RED
|
||||
main::@return:
|
||||
return
|
||||
endproc // main()
|
||||
call main
|
||||
|
||||
SYMBOLS
|
||||
(byte*) BGCOL
|
||||
(byte) RED
|
||||
(void()) main()
|
||||
(label) main::@return
|
||||
(byte*) main::screen
|
||||
|
||||
Promoting word to byte* in BGCOL ← ((byte*)) 53281
|
||||
Promoting word/signed word to byte* in main::screen ← ((byte*)) 1024
|
||||
INITIAL CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
(byte*) BGCOL ← ((byte*)) (word) 53281
|
||||
(byte) RED ← (byte/signed byte/word/signed word) 2
|
||||
to:@1
|
||||
main: scope:[main] from
|
||||
(byte*) main::screen ← ((byte*)) (word/signed word) 1024
|
||||
*((byte*) main::screen) ← (byte/signed byte/word/signed word) 1
|
||||
*((byte*) BGCOL) ← (byte) RED
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
@1: scope:[] from @begin
|
||||
call main
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
|
||||
CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
(byte*) BGCOL ← ((byte*)) (word) 53281
|
||||
(byte) RED ← (byte/signed byte/word/signed word) 2
|
||||
to:@1
|
||||
main: scope:[main] from
|
||||
(byte*) main::screen ← ((byte*)) (word/signed word) 1024
|
||||
*((byte*) main::screen) ← (byte/signed byte/word/signed word) 1
|
||||
*((byte*) BGCOL) ← (byte) RED
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
@1: scope:[] from @begin
|
||||
call main
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
|
||||
PROCEDURE MODIFY VARIABLE ANALYSIS
|
||||
|
||||
CONTROL FLOW GRAPH WITH ASSIGNMENT CALL
|
||||
@begin: scope:[] from
|
||||
(byte*) BGCOL ← ((byte*)) (word) 53281
|
||||
(byte) RED ← (byte/signed byte/word/signed word) 2
|
||||
to:@1
|
||||
main: scope:[main] from @1
|
||||
(byte*) main::screen ← ((byte*)) (word/signed word) 1024
|
||||
*((byte*) main::screen) ← (byte/signed byte/word/signed word) 1
|
||||
*((byte*) BGCOL) ← (byte) RED
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
@1: scope:[] from @begin
|
||||
call main param-assignment
|
||||
to:@2
|
||||
@2: scope:[] from @1
|
||||
to:@end
|
||||
@end: scope:[] from @2
|
||||
|
||||
Completing Phi functions...
|
||||
Completing Phi functions...
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
(byte*) BGCOL#0 ← ((byte*)) (word) 53281
|
||||
(byte) RED#0 ← (byte/signed byte/word/signed word) 2
|
||||
to:@1
|
||||
main: scope:[main] from @1
|
||||
(byte*) BGCOL#1 ← phi( @1/(byte*) BGCOL#2 )
|
||||
(byte) RED#1 ← phi( @1/(byte) RED#2 )
|
||||
(byte*) main::screen#0 ← ((byte*)) (word/signed word) 1024
|
||||
*((byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1
|
||||
*((byte*) BGCOL#1) ← (byte) RED#1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
@1: scope:[] from @begin
|
||||
(byte*) BGCOL#2 ← phi( @begin/(byte*) BGCOL#0 )
|
||||
(byte) RED#2 ← phi( @begin/(byte) RED#0 )
|
||||
call main param-assignment
|
||||
to:@2
|
||||
@2: scope:[] from @1
|
||||
to:@end
|
||||
@end: scope:[] from @2
|
||||
|
||||
CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN
|
||||
@begin: scope:[] from
|
||||
(byte*) BGCOL#0 ← ((byte*)) (word) 53281
|
||||
(byte) RED#0 ← (byte/signed byte/word/signed word) 2
|
||||
to:@1
|
||||
main: scope:[main] from @1
|
||||
(byte*) BGCOL#1 ← phi( @1/(byte*) BGCOL#2 )
|
||||
(byte) RED#1 ← phi( @1/(byte) RED#2 )
|
||||
(byte*) main::screen#0 ← ((byte*)) (word/signed word) 1024
|
||||
*((byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1
|
||||
*((byte*) BGCOL#1) ← (byte) RED#1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
@1: scope:[] from @begin
|
||||
(byte*) BGCOL#2 ← phi( @begin/(byte*) BGCOL#0 )
|
||||
(byte) RED#2 ← phi( @begin/(byte) RED#0 )
|
||||
call main param-assignment
|
||||
to:@2
|
||||
@2: scope:[] from @1
|
||||
to:@end
|
||||
@end: scope:[] from @2
|
||||
|
||||
INITIAL SSA SYMBOL TABLE
|
||||
(label) @1
|
||||
(label) @2
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(byte*) BGCOL
|
||||
(byte*) BGCOL#0
|
||||
(byte*) BGCOL#1
|
||||
(byte*) BGCOL#2
|
||||
(byte) RED
|
||||
(byte) RED#0
|
||||
(byte) RED#1
|
||||
(byte) RED#2
|
||||
(void()) main()
|
||||
(label) main::@return
|
||||
(byte*) main::screen
|
||||
(byte*) main::screen#0
|
||||
|
||||
Culled Empty Block (label) @2
|
||||
Succesful SSA optimization Pass2CullEmptyBlocks
|
||||
CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
(byte*) BGCOL#0 ← ((byte*)) (word) 53281
|
||||
(byte) RED#0 ← (byte/signed byte/word/signed word) 2
|
||||
to:@1
|
||||
main: scope:[main] from @1
|
||||
(byte*) BGCOL#1 ← phi( @1/(byte*) BGCOL#2 )
|
||||
(byte) RED#1 ← phi( @1/(byte) RED#2 )
|
||||
(byte*) main::screen#0 ← ((byte*)) (word/signed word) 1024
|
||||
*((byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1
|
||||
*((byte*) BGCOL#1) ← (byte) RED#1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
@1: scope:[] from @begin
|
||||
(byte*) BGCOL#2 ← phi( @begin/(byte*) BGCOL#0 )
|
||||
(byte) RED#2 ← phi( @begin/(byte) RED#0 )
|
||||
call main param-assignment
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
|
||||
Not aliassing across scopes: RED#1 RED#2
|
||||
Not aliassing across scopes: BGCOL#1 BGCOL#2
|
||||
Alias (byte) RED#0 = (byte) RED#2
|
||||
Alias (byte*) BGCOL#0 = (byte*) BGCOL#2
|
||||
Succesful SSA optimization Pass2AliasElimination
|
||||
CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
(byte*) BGCOL#0 ← ((byte*)) (word) 53281
|
||||
(byte) RED#0 ← (byte/signed byte/word/signed word) 2
|
||||
to:@1
|
||||
main: scope:[main] from @1
|
||||
(byte*) BGCOL#1 ← phi( @1/(byte*) BGCOL#0 )
|
||||
(byte) RED#1 ← phi( @1/(byte) RED#0 )
|
||||
(byte*) main::screen#0 ← ((byte*)) (word/signed word) 1024
|
||||
*((byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1
|
||||
*((byte*) BGCOL#1) ← (byte) RED#1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
@1: scope:[] from @begin
|
||||
call main param-assignment
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
|
||||
Not aliassing across scopes: RED#1 RED#0
|
||||
Not aliassing across scopes: BGCOL#1 BGCOL#0
|
||||
Redundant Phi (byte) RED#1 (byte) RED#0
|
||||
Redundant Phi (byte*) BGCOL#1 (byte*) BGCOL#0
|
||||
Succesful SSA optimization Pass2RedundantPhiElimination
|
||||
CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
(byte*) BGCOL#0 ← ((byte*)) (word) 53281
|
||||
(byte) RED#0 ← (byte/signed byte/word/signed word) 2
|
||||
to:@1
|
||||
main: scope:[main] from @1
|
||||
(byte*) main::screen#0 ← ((byte*)) (word/signed word) 1024
|
||||
*((byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1
|
||||
*((byte*) BGCOL#0) ← (byte) RED#0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
@1: scope:[] from @begin
|
||||
call main param-assignment
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
|
||||
Constant (const byte*) BGCOL#0 = ((byte*))53281
|
||||
Constant (const byte) RED#0 = 2
|
||||
Constant (const byte*) main::screen#0 = ((byte*))1024
|
||||
Succesful SSA optimization Pass2ConstantIdentification
|
||||
CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
to:@1
|
||||
main: scope:[main] from @1
|
||||
*((const byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1
|
||||
*((const byte*) BGCOL#0) ← (const byte) RED#0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
@1: scope:[] from @begin
|
||||
call main param-assignment
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(byte*) BGCOL
|
||||
(const byte*) BGCOL#0 = ((byte*))(word) 53281
|
||||
(byte) RED
|
||||
(const byte) RED#0 = (byte/signed byte/word/signed word) 2
|
||||
(void()) main()
|
||||
(label) main::@return
|
||||
(byte*) main::screen
|
||||
(const byte*) main::screen#0 = ((byte*))(word/signed word) 1024
|
||||
|
||||
Block Sequence Planned @begin @1 @end main main::@return
|
||||
Block Sequence Planned @begin @1 @end main main::@return
|
||||
CONTROL FLOW GRAPH - PHI LIFTED
|
||||
@begin: scope:[] from
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
call main param-assignment
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
main: scope:[main] from @1
|
||||
*((const byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1
|
||||
*((const byte*) BGCOL#0) ← (const byte) RED#0
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @1
|
||||
Adding NOP phi() at start of @end
|
||||
CALL GRAPH
|
||||
Calls in [] to main:2
|
||||
|
||||
Propagating live ranges...
|
||||
CONTROL FLOW GRAPH - LIVE RANGES FOUND
|
||||
@begin: scope:[] from
|
||||
[0] phi() [ ]
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi() [ ]
|
||||
[2] call main param-assignment [ ]
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
[3] phi() [ ]
|
||||
main: scope:[main] from @1
|
||||
[4] *((const byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1 [ ]
|
||||
[5] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ]
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[6] return [ ]
|
||||
to:@return
|
||||
|
||||
Created 0 initial phi equivalence classes
|
||||
Coalesced down to 0 phi equivalence classes
|
||||
Block Sequence Planned @begin @1 @end main main::@return
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @1
|
||||
Adding NOP phi() at start of @end
|
||||
Propagating live ranges...
|
||||
CONTROL FLOW GRAPH - BEFORE EFFECTIVE LIVE RANGES
|
||||
@begin: scope:[] from
|
||||
[0] phi() [ ]
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi() [ ]
|
||||
[2] call main param-assignment [ ]
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
[3] phi() [ ]
|
||||
main: scope:[main] from @1
|
||||
[4] *((const byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1 [ ]
|
||||
[5] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ]
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[6] return [ ]
|
||||
to:@return
|
||||
|
||||
CONTROL FLOW GRAPH - PHI MEM COALESCED
|
||||
@begin: scope:[] from
|
||||
[0] phi() [ ] ( )
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi() [ ] ( )
|
||||
[2] call main param-assignment [ ] ( )
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
[3] phi() [ ] ( )
|
||||
main: scope:[main] from @1
|
||||
[4] *((const byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1 [ ] ( main:2 [ ] )
|
||||
[5] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] )
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[6] return [ ] ( main:2 [ ] )
|
||||
to:@return
|
||||
|
||||
DOMINATORS
|
||||
@begin dominated by @begin
|
||||
@1 dominated by @1 @begin
|
||||
@end dominated by @1 @begin @end
|
||||
main dominated by @1 @begin main
|
||||
main::@return dominated by main::@return @1 @begin main
|
||||
|
||||
NATURAL LOOPS
|
||||
|
||||
Found 0 loops in scope []
|
||||
Found 0 loops in scope [main]
|
||||
NATURAL LOOPS WITH DEPTH
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(byte*) BGCOL
|
||||
(byte) RED
|
||||
(void()) main()
|
||||
(byte*) main::screen
|
||||
|
||||
Initial phi equivalence classes
|
||||
Complete equivalence classes
|
||||
INITIAL ASM
|
||||
//SEG0 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG1 Global Constants & labels
|
||||
.const BGCOL = $d021
|
||||
.const RED = 2
|
||||
//SEG2 @begin
|
||||
bbegin:
|
||||
//SEG3 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
b1_from_bbegin:
|
||||
jmp b1
|
||||
//SEG4 @1
|
||||
b1:
|
||||
//SEG5 [2] call main param-assignment [ ] ( )
|
||||
jsr main
|
||||
//SEG6 [3] phi from @1 to @end [phi:@1->@end]
|
||||
bend_from_b1:
|
||||
jmp bend
|
||||
//SEG7 @end
|
||||
bend:
|
||||
//SEG8 main
|
||||
main: {
|
||||
.const screen = $400
|
||||
//SEG9 [4] *((const byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2
|
||||
lda #1
|
||||
sta screen
|
||||
//SEG10 [5] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2
|
||||
lda #RED
|
||||
sta BGCOL
|
||||
jmp breturn
|
||||
//SEG11 main::@return
|
||||
breturn:
|
||||
//SEG12 [6] return [ ] ( main:2 [ ] )
|
||||
rts
|
||||
}
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [4] *((const byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [5] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 33 combination
|
||||
Uplifting [] best 33 combination
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp bend
|
||||
Removing instruction jmp breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
ASSEMBLER
|
||||
//SEG0 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG1 Global Constants & labels
|
||||
.const BGCOL = $d021
|
||||
.const RED = 2
|
||||
//SEG2 @begin
|
||||
bbegin:
|
||||
//SEG3 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
b1_from_bbegin:
|
||||
//SEG4 @1
|
||||
b1:
|
||||
//SEG5 [2] call main param-assignment [ ] ( )
|
||||
jsr main
|
||||
//SEG6 [3] phi from @1 to @end [phi:@1->@end]
|
||||
bend_from_b1:
|
||||
//SEG7 @end
|
||||
bend:
|
||||
//SEG8 main
|
||||
main: {
|
||||
.const screen = $400
|
||||
//SEG9 [4] *((const byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2
|
||||
lda #1
|
||||
sta screen
|
||||
//SEG10 [5] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2
|
||||
lda #RED
|
||||
sta BGCOL
|
||||
//SEG11 main::@return
|
||||
breturn:
|
||||
//SEG12 [6] return [ ] ( main:2 [ ] )
|
||||
rts
|
||||
}
|
||||
|
||||
Removing instruction bbegin:
|
||||
Removing instruction b1_from_bbegin:
|
||||
Removing instruction bend_from_b1:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
ASSEMBLER
|
||||
//SEG0 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG1 Global Constants & labels
|
||||
.const BGCOL = $d021
|
||||
.const RED = 2
|
||||
//SEG2 @begin
|
||||
//SEG3 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
//SEG4 @1
|
||||
b1:
|
||||
//SEG5 [2] call main param-assignment [ ] ( )
|
||||
jsr main
|
||||
//SEG6 [3] phi from @1 to @end [phi:@1->@end]
|
||||
//SEG7 @end
|
||||
bend:
|
||||
//SEG8 main
|
||||
main: {
|
||||
.const screen = $400
|
||||
//SEG9 [4] *((const byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2
|
||||
lda #1
|
||||
sta screen
|
||||
//SEG10 [5] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2
|
||||
lda #RED
|
||||
sta BGCOL
|
||||
//SEG11 main::@return
|
||||
breturn:
|
||||
//SEG12 [6] return [ ] ( main:2 [ ] )
|
||||
rts
|
||||
}
|
||||
|
||||
Removing instruction b1:
|
||||
Removing instruction bend:
|
||||
Removing instruction breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
ASSEMBLER
|
||||
//SEG0 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG1 Global Constants & labels
|
||||
.const BGCOL = $d021
|
||||
.const RED = 2
|
||||
//SEG2 @begin
|
||||
//SEG3 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
//SEG4 @1
|
||||
//SEG5 [2] call main param-assignment [ ] ( )
|
||||
jsr main
|
||||
//SEG6 [3] phi from @1 to @end [phi:@1->@end]
|
||||
//SEG7 @end
|
||||
//SEG8 main
|
||||
main: {
|
||||
.const screen = $400
|
||||
//SEG9 [4] *((const byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2
|
||||
lda #1
|
||||
sta screen
|
||||
//SEG10 [5] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2
|
||||
lda #RED
|
||||
sta BGCOL
|
||||
//SEG11 main::@return
|
||||
//SEG12 [6] return [ ] ( main:2 [ ] )
|
||||
rts
|
||||
}
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(byte*) BGCOL
|
||||
(const byte*) BGCOL#0 BGCOL = ((byte*))(word) 53281
|
||||
(byte) RED
|
||||
(const byte) RED#0 RED = (byte/signed byte/word/signed word) 2
|
||||
(void()) main()
|
||||
(label) main::@return
|
||||
(byte*) main::screen
|
||||
(const byte*) main::screen#0 screen = ((byte*))(word/signed word) 1024
|
||||
|
||||
|
||||
FINAL CODE
|
||||
//SEG0 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG1 Global Constants & labels
|
||||
.const BGCOL = $d021
|
||||
.const RED = 2
|
||||
//SEG2 @begin
|
||||
//SEG3 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
//SEG4 @1
|
||||
//SEG5 [2] call main param-assignment [ ] ( )
|
||||
jsr main
|
||||
//SEG6 [3] phi from @1 to @end [phi:@1->@end]
|
||||
//SEG7 @end
|
||||
//SEG8 main
|
||||
main: {
|
||||
.const screen = $400
|
||||
//SEG9 [4] *((const byte*) main::screen#0) ← (byte/signed byte/word/signed word) 1 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2
|
||||
lda #1
|
||||
sta screen
|
||||
//SEG10 [5] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2
|
||||
lda #RED
|
||||
sta BGCOL
|
||||
//SEG11 main::@return
|
||||
//SEG12 [6] return [ ] ( main:2 [ ] )
|
||||
rts
|
||||
}
|
||||
|
12
src/main/java/dk/camelot64/kickc/test/ref/importing.sym
Normal file
12
src/main/java/dk/camelot64/kickc/test/ref/importing.sym
Normal file
@ -0,0 +1,12 @@
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(byte*) BGCOL
|
||||
(const byte*) BGCOL#0 BGCOL = ((byte*))(word) 53281
|
||||
(byte) RED
|
||||
(const byte) RED#0 RED = (byte/signed byte/word/signed word) 2
|
||||
(void()) main()
|
||||
(label) main::@return
|
||||
(byte*) main::screen
|
||||
(const byte*) main::screen#0 screen = ((byte*))(word/signed word) 1024
|
||||
|
Loading…
x
Reference in New Issue
Block a user