1
0
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:
jespergravgaard 2017-12-02 16:35:13 +01:00
parent 78dd8bc149
commit 41fd3bc436
17 changed files with 1221 additions and 566 deletions

View File

@ -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());
}
}
}

View File

@ -7,5 +7,7 @@ public class CompileError extends RuntimeException {
super(message);
}
public CompileError(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -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;
}

View File

@ -10,7 +10,7 @@ asmFile
;
importSeq
: importDecl+
: importDecl*
;
importDecl

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,6 @@ public class Pass1AddTypePromotions extends Pass1Base {
super(program);
}
@Override
public boolean executeStep() {
for (ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) {

View File

@ -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>&lt;plotter = x &amp; 8 </code>
* <br>Becomes: <code> $1 =x &amp; 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;
}
}

View File

@ -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) {

View File

@ -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;
}
}

View File

@ -83,7 +83,7 @@ public class Pass3LoopAnalysis extends Pass2Base {
}
}
getProgram().setLoops(loopSet);
getProgram().setLoopSet(loopSet);
}

View File

@ -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);

View File

@ -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));

View File

@ -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));

View 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
}

View 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

View 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
}

View 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