mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-01-12 11:31:11 +00:00
Added pass 1 base class. Added test for unused vars.
This commit is contained in:
parent
42840f8f77
commit
deb1304ba6
@ -78,40 +78,33 @@ public class Compiler {
|
||||
|
||||
Pass1GenerateControlFlowGraph pass1GenerateControlFlowGraph = new Pass1GenerateControlFlowGraph(programScope);
|
||||
ControlFlowGraph controlFlowGraph = pass1GenerateControlFlowGraph.generate(statementSequence);
|
||||
|
||||
program.setGraph(controlFlowGraph);
|
||||
|
||||
new Pass1AddTypePromotions(program).addPromotions();
|
||||
new Pass1AddTypePromotions(program).execute();
|
||||
|
||||
log.append("INITIAL CONTROL FLOW GRAPH");
|
||||
log.append(program.getGraph().toString(program));
|
||||
|
||||
new Pass1ExtractInlineStrings(program).extract();
|
||||
new Pass1EliminateUncalledProcedures(program).eliminate();
|
||||
new Pass1EliminateEmptyBlocks(program).eliminate();
|
||||
new Pass1ExtractInlineStrings(program).execute();
|
||||
new Pass1EliminateUncalledProcedures(program).execute();
|
||||
new Pass1EliminateEmptyBlocks(program).execute();
|
||||
log.append("CONTROL FLOW GRAPH");
|
||||
log.append(program.getGraph().toString(program));
|
||||
|
||||
new Pass1ModifiedVarsAnalysis(program).findModifiedVars();
|
||||
new Pass1ModifiedVarsAnalysis(program).execute();
|
||||
log.append("PROCEDURE MODIFY VARIABLE ANALYSIS");
|
||||
log.append(program.getProcedureModifiedVars().toString(program));
|
||||
|
||||
Pass1ProcedureCallParameters pass1ProcedureCallParameters =
|
||||
new Pass1ProcedureCallParameters(program);
|
||||
pass1ProcedureCallParameters.generate();
|
||||
new Pass1ProcedureCallParameters(program).generate();
|
||||
log.append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL");
|
||||
log.append(program.getGraph().toString(program));
|
||||
|
||||
Pass1GenerateSingleStaticAssignmentForm pass1GenerateSingleStaticAssignmentForm =
|
||||
new Pass1GenerateSingleStaticAssignmentForm(log, program);
|
||||
pass1GenerateSingleStaticAssignmentForm.generate();
|
||||
new Pass1GenerateSingleStaticAssignmentForm(program).execute();
|
||||
|
||||
log.append("CONTROL FLOW GRAPH SSA");
|
||||
log.append(program.getGraph().toString(program));
|
||||
|
||||
Pass1ProcedureCallsReturnValue pass1ProcedureCallsReturnValue =
|
||||
new Pass1ProcedureCallsReturnValue(program);
|
||||
program.setGraph(pass1ProcedureCallsReturnValue.generate());
|
||||
program.setGraph(new Pass1ProcedureCallsReturnValue(program).generate());
|
||||
log.append("CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN");
|
||||
log.append(program.getGraph().toString(program));
|
||||
|
||||
|
@ -8,23 +8,15 @@ import java.util.ListIterator;
|
||||
/**
|
||||
* Add casts in all assignments where types are not equal, but the rValue type can be promoted to the lValue type.
|
||||
*/
|
||||
public class Pass1AddTypePromotions {
|
||||
|
||||
private Program program;
|
||||
public class Pass1AddTypePromotions extends Pass1Base {
|
||||
|
||||
public Pass1AddTypePromotions(Program program) {
|
||||
this.program = program;
|
||||
super(program);
|
||||
}
|
||||
|
||||
public Program getProgram() {
|
||||
return program;
|
||||
}
|
||||
|
||||
public ProgramScope getSymbols() {
|
||||
return program.getScope();
|
||||
}
|
||||
|
||||
public void addPromotions() {
|
||||
@Override
|
||||
public boolean executeStep() {
|
||||
for (ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) {
|
||||
List<Statement> statements = block.getStatements();
|
||||
ListIterator<Statement> stmtIt = statements.listIterator();
|
||||
@ -36,7 +28,7 @@ public class Pass1AddTypePromotions {
|
||||
// TODO: Implement promotion for calls
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,8 +42,8 @@ public class Pass1AddTypePromotions {
|
||||
*/
|
||||
private void getPromotionAssignment(StatementAssignment assignment, ListIterator<Statement> stmtIt) {
|
||||
LValue lValue = assignment.getlValue();
|
||||
SymbolType lValueType = SymbolTypeInference.inferType(getSymbols(), lValue);
|
||||
SymbolType rValueType = SymbolTypeInference.inferTypeRValue(getSymbols(), assignment);
|
||||
SymbolType lValueType = SymbolTypeInference.inferType(getScope(), lValue);
|
||||
SymbolType rValueType = SymbolTypeInference.inferTypeRValue(getScope(), assignment);
|
||||
if (SymbolTypeInference.typeMatch(lValueType, rValueType)) {
|
||||
return;
|
||||
}
|
||||
|
54
src/main/java/dk/camelot64/kickc/passes/Pass1Base.java
Normal file
54
src/main/java/dk/camelot64/kickc/passes/Pass1Base.java
Normal file
@ -0,0 +1,54 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.CompileLog;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
/**
|
||||
* Pass 1 (before SSA optimizations) base class
|
||||
*/
|
||||
public abstract class Pass1Base {
|
||||
|
||||
private Program program;
|
||||
|
||||
public Pass1Base(Program program) {
|
||||
this.program = program;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the pass 1 step repeatedly until it is done.
|
||||
*/
|
||||
public void execute() {
|
||||
boolean again = true;
|
||||
while (again) {
|
||||
again = executeStep();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the pass 1 step.
|
||||
*
|
||||
* @return boolean indicating whether the step should be repeated.
|
||||
*/
|
||||
abstract boolean executeStep();
|
||||
|
||||
public Program getProgram() {
|
||||
return program;
|
||||
}
|
||||
|
||||
public ProgramScope getScope() {
|
||||
return program.getScope();
|
||||
}
|
||||
|
||||
public CompileLog getLog() {
|
||||
return program.getLog();
|
||||
}
|
||||
|
||||
public ControlFlowGraph getGraph() {
|
||||
return program.getGraph();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -10,17 +10,16 @@ import java.util.List;
|
||||
/**
|
||||
* Eliminate empty blocks in pass 1 (before creating SSA)
|
||||
*/
|
||||
public class Pass1EliminateEmptyBlocks {
|
||||
|
||||
private Program program;
|
||||
public class Pass1EliminateEmptyBlocks extends Pass1Base {
|
||||
|
||||
public Pass1EliminateEmptyBlocks(Program program) {
|
||||
this.program = program;
|
||||
super(program);
|
||||
}
|
||||
|
||||
public boolean eliminate() {
|
||||
CompileLog log = program.getLog();
|
||||
ControlFlowGraph graph = program.getGraph();
|
||||
@Override
|
||||
boolean executeStep() {
|
||||
CompileLog log = getLog();
|
||||
ControlFlowGraph graph = getProgram().getGraph();
|
||||
Collection<ControlFlowBlock> blocks = graph.getAllBlocks();
|
||||
List<LabelRef> removeList = new ArrayList<>();
|
||||
for (ControlFlowBlock block : blocks) {
|
||||
@ -44,16 +43,18 @@ public class Pass1EliminateEmptyBlocks {
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean modified = false;
|
||||
for (LabelRef labelRef : removeList) {
|
||||
Symbol removeSymbol = program.getScope().getSymbol(labelRef);
|
||||
Symbol removeSymbol = getScope().getSymbol(labelRef);
|
||||
if(removeSymbol instanceof Label) {
|
||||
Label label = (Label) removeSymbol;
|
||||
graph.remove(labelRef);
|
||||
label.getScope().remove(label);
|
||||
log.append("Removing empty block "+labelRef);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
return removeList.size()>0;
|
||||
return modified;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,17 +8,16 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/** Eliminate uncalled methods */
|
||||
public class Pass1EliminateUncalledProcedures {
|
||||
|
||||
private Program program;
|
||||
public class Pass1EliminateUncalledProcedures extends Pass1Base {
|
||||
|
||||
public Pass1EliminateUncalledProcedures(Program program) {
|
||||
this.program = program;
|
||||
super(program);
|
||||
}
|
||||
|
||||
public void eliminate() {
|
||||
@Override
|
||||
boolean executeStep() {
|
||||
Set<ProcedureRef> calledProcedures = new LinkedHashSet<>();
|
||||
for (ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
for (ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) {
|
||||
for (Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementCall) {
|
||||
StatementCall call = (StatementCall) statement;
|
||||
@ -29,7 +28,7 @@ public class Pass1EliminateUncalledProcedures {
|
||||
}
|
||||
|
||||
Set<ProcedureRef> unusedProcedures = new LinkedHashSet<>();
|
||||
Collection<Procedure> allProcedures = program.getScope().getAllProcedures(true);
|
||||
Collection<Procedure> allProcedures = getProgram().getScope().getAllProcedures(true);
|
||||
for (Procedure procedure : allProcedures) {
|
||||
if(!calledProcedures.contains(procedure.getRef())) {
|
||||
// The procedure is not used - mark for removal!
|
||||
@ -38,16 +37,16 @@ public class Pass1EliminateUncalledProcedures {
|
||||
}
|
||||
|
||||
for (ProcedureRef unusedProcedure : unusedProcedures) {
|
||||
program.getLog().append("Removing unused procedure "+unusedProcedure);
|
||||
Procedure procedure = program.getScope().getProcedure(unusedProcedure);
|
||||
List<ControlFlowBlock> procedureBlocks = program.getGraph().getScopeBlocks(unusedProcedure);
|
||||
getLog().append("Removing unused procedure "+unusedProcedure);
|
||||
Procedure procedure = getProgram().getScope().getProcedure(unusedProcedure);
|
||||
List<ControlFlowBlock> procedureBlocks = getProgram().getGraph().getScopeBlocks(unusedProcedure);
|
||||
for (ControlFlowBlock procedureBlock : procedureBlocks) {
|
||||
program.getGraph().remove(procedureBlock.getLabel());
|
||||
getProgram().getGraph().remove(procedureBlock.getLabel());
|
||||
}
|
||||
procedure.getScope().remove(procedure);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,18 +7,17 @@ import java.util.*;
|
||||
/**
|
||||
* Eliminate uncalled methods
|
||||
*/
|
||||
public class Pass1ExtractInlineStrings {
|
||||
|
||||
private Program program;
|
||||
public class Pass1ExtractInlineStrings extends Pass1Base {
|
||||
|
||||
public Pass1ExtractInlineStrings(Program program) {
|
||||
this.program = program;
|
||||
super(program);
|
||||
}
|
||||
|
||||
public void extract() {
|
||||
for (ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
@Override
|
||||
boolean executeStep() {
|
||||
for (ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) {
|
||||
ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
Scope blockScope = program.getScope().getScope(block.getScope());
|
||||
Scope blockScope = getProgram().getScope().getScope(block.getScope());
|
||||
while (stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
if (statement instanceof StatementCall) {
|
||||
@ -28,7 +27,7 @@ public class Pass1ExtractInlineStrings {
|
||||
while (parIt.hasNext()) {
|
||||
RValue parameter = parIt.next();
|
||||
if (parameter instanceof ConstantString) {
|
||||
Procedure procedure = program.getScope().getProcedure(call.getProcedure());
|
||||
Procedure procedure = getProgram().getScope().getProcedure(call.getProcedure());
|
||||
String parameterName = procedure.getParameterNames().get(parNum);
|
||||
ConstantVar strConst = createStringConstantVar(blockScope, (ConstantString) parameter, parameterName);
|
||||
parIt.set(strConst.getRef());
|
||||
@ -57,7 +56,7 @@ public class Pass1ExtractInlineStrings {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private ConstantVar createStringConstantVar(Scope blockScope, ConstantString constantString, String nameHint) {
|
||||
@ -73,7 +72,7 @@ public class Pass1ExtractInlineStrings {
|
||||
}
|
||||
ConstantVar strConst = new ConstantVar(name, blockScope, new SymbolTypeArray(SymbolType.BYTE), constantString);
|
||||
blockScope.add(strConst);
|
||||
program.getLog().append("Creating constant string variable for inline " + strConst.toString(program) + " \"" + constantString.getValue() + "\"");
|
||||
getLog().append("Creating constant string variable for inline " + strConst.toString(getProgram()) + " \"" + constantString.getValue() + "\"");
|
||||
return strConst;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.CompileLog;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
@ -11,41 +10,37 @@ import java.util.Map;
|
||||
* <p>First versions all variable assignments, then versions all variable usages and introduces necessary Phi-functions,
|
||||
* <p>See https://en.wikipedia.org/wiki/Static_single_assignment_form
|
||||
*/
|
||||
public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
||||
|
||||
private CompileLog log;
|
||||
private ProgramScope symbols;
|
||||
private ControlFlowGraph controlFlowGraph;
|
||||
|
||||
public Pass1GenerateSingleStaticAssignmentForm(CompileLog log, Program program) {
|
||||
this.log = log;
|
||||
this.symbols = program.getScope();
|
||||
this.controlFlowGraph = program.getGraph();
|
||||
public Pass1GenerateSingleStaticAssignmentForm(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
public void generate() {
|
||||
@Override
|
||||
boolean executeStep() {
|
||||
versionAllAssignments();
|
||||
versionAllUses();
|
||||
boolean done;
|
||||
do {
|
||||
log.append("Completing Phi functions...");
|
||||
getLog().append("Completing Phi functions...");
|
||||
done = completePhiFunctions();
|
||||
//log.append(this.controlFlowGraph.toString(symbols));
|
||||
} while (!done);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Version all non-versioned non-intermediary being assigned a value.
|
||||
*/
|
||||
private void versionAllAssignments() {
|
||||
for (ControlFlowBlock block : controlFlowGraph.getAllBlocks()) {
|
||||
for (ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for (Statement statement : block.getStatements()) {
|
||||
if (statement instanceof StatementLValue) {
|
||||
StatementLValue statementLValue = (StatementLValue) statement;
|
||||
LValue lValue = statementLValue.getlValue();
|
||||
if (lValue instanceof VariableRef) {
|
||||
VariableRef lValueRef = (VariableRef) lValue;
|
||||
Variable assignedVar = symbols.getVariable(lValueRef);
|
||||
Variable assignedVar = getScope().getVariable(lValueRef);
|
||||
if (assignedVar instanceof VariableUnversioned) {
|
||||
// Assignment to a non-versioned non-intermediary variable
|
||||
VariableUnversioned assignedSymbol = (VariableUnversioned) assignedVar;
|
||||
@ -62,7 +57,7 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
* Version all uses of non-versioned non-intermediary variables
|
||||
*/
|
||||
private void versionAllUses() {
|
||||
for (ControlFlowBlock block : controlFlowGraph.getAllBlocks()) {
|
||||
for (ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
// Newest version of variables in the block.
|
||||
Map<VariableUnversioned, VariableVersion> blockVersions = new LinkedHashMap<>();
|
||||
// New phi functions introduced in the block to create versions of variables.
|
||||
@ -116,7 +111,7 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
LValue lValue = assignment.getlValue();
|
||||
if (lValue instanceof VariableRef) {
|
||||
VariableRef lValueRef = (VariableRef) lValue;
|
||||
Variable variable = symbols.getVariable(lValueRef);
|
||||
Variable variable = getScope().getVariable(lValueRef);
|
||||
if (variable instanceof VariableVersion) {
|
||||
VariableVersion versioned = (VariableVersion) variable;
|
||||
blockVersions.put(versioned.getVersionOf(), versioned);
|
||||
@ -165,7 +160,7 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
Map<VariableUnversioned, VariableVersion> blockNewPhis) {
|
||||
VariableVersion version = null;
|
||||
if (rValue instanceof VariableRef) {
|
||||
Variable rValueVar = symbols.getVariable((VariableRef) rValue);
|
||||
Variable rValueVar = getScope().getVariable((VariableRef) rValue);
|
||||
if (rValueVar instanceof VariableUnversioned) {
|
||||
// rValue needs versioning - look for version in statements
|
||||
VariableUnversioned rSymbol = (VariableUnversioned) rValueVar;
|
||||
@ -193,7 +188,7 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
private boolean completePhiFunctions() {
|
||||
Map<LabelRef, Map<VariableUnversioned, VariableVersion>> newPhis = new LinkedHashMap<>();
|
||||
Map<LabelRef, Map<VariableUnversioned, VariableVersion>> symbolMap = buildSymbolMap();
|
||||
for (ControlFlowBlock block : this.controlFlowGraph.getAllBlocks()) {
|
||||
for (ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for (Statement statement : block.getStatements()) {
|
||||
|
||||
if (statement instanceof StatementPhiBlock) {
|
||||
@ -201,9 +196,9 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
for (StatementPhiBlock.PhiVariable phiVariable : phiBlock.getPhiVariables()) {
|
||||
if (phiVariable.isEmpty()) {
|
||||
VariableRef phiLValVarRef = phiVariable.getVariable();
|
||||
VariableVersion versioned = (VariableVersion) symbols.getVariable(phiLValVarRef);
|
||||
VariableVersion versioned = (VariableVersion) getScope().getVariable(phiLValVarRef);
|
||||
VariableUnversioned unversioned = versioned.getVersionOf();
|
||||
for (ControlFlowBlock predecessor : controlFlowGraph.getPredecessors(block)) {
|
||||
for (ControlFlowBlock predecessor : getGraph().getPredecessors(block)) {
|
||||
LabelRef predecessorLabel = predecessor.getLabel();
|
||||
Map<VariableUnversioned, VariableVersion> predecessorMap = symbolMap.get(predecessorLabel);
|
||||
VariableVersion previousSymbol = null;
|
||||
@ -232,7 +227,7 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
}
|
||||
}
|
||||
// Ads new phi functions to blocks
|
||||
for (ControlFlowBlock block : controlFlowGraph.getAllBlocks()) {
|
||||
for (ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
Map<VariableUnversioned, VariableVersion> blockNewPhis = newPhis.get(block.getLabel());
|
||||
if (blockNewPhis != null) {
|
||||
for (VariableUnversioned symbol : blockNewPhis.keySet()) {
|
||||
@ -250,7 +245,7 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
*/
|
||||
private Map<LabelRef, Map<VariableUnversioned, VariableVersion>> buildSymbolMap() {
|
||||
Map<LabelRef, Map<VariableUnversioned, VariableVersion>> symbolMap = new LinkedHashMap<>();
|
||||
for (ControlFlowBlock block : this.controlFlowGraph.getAllBlocks()) {
|
||||
for (ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for (Statement statement : block.getStatements()) {
|
||||
if (statement instanceof StatementLValue) {
|
||||
StatementLValue assignment = (StatementLValue) statement;
|
||||
@ -268,7 +263,7 @@ public class Pass1GenerateSingleStaticAssignmentForm {
|
||||
|
||||
private void addSymbolToMap(Map<LabelRef, Map<VariableUnversioned, VariableVersion>> symbolMap, ControlFlowBlock block, LValue lValue) {
|
||||
if (lValue instanceof VariableRef) {
|
||||
Variable lValueVar = symbols.getVariable((VariableRef) lValue);
|
||||
Variable lValueVar = getScope().getVariable((VariableRef) lValue);
|
||||
if (lValueVar instanceof VariableVersion) {
|
||||
VariableVersion versioned = (VariableVersion) lValueVar;
|
||||
LabelRef label = block.getLabel();
|
||||
|
@ -5,22 +5,22 @@ import dk.camelot64.kickc.model.*;
|
||||
import java.util.*;
|
||||
|
||||
/** Find all variables from an outer scope modified in an inner scope (ie. a procedure) */
|
||||
public class Pass1ModifiedVarsAnalysis {
|
||||
|
||||
private Program program;
|
||||
public class Pass1ModifiedVarsAnalysis extends Pass1Base {
|
||||
|
||||
public Pass1ModifiedVarsAnalysis(Program program) {
|
||||
this.program = program;
|
||||
super(program);
|
||||
}
|
||||
|
||||
public void findModifiedVars() {
|
||||
@Override
|
||||
boolean executeStep() {
|
||||
Map<ProcedureRef, Set<VariableRef>> modified = new LinkedHashMap<>();
|
||||
Collection<Procedure> allProcedures = program.getScope().getAllProcedures(true);
|
||||
Collection<Procedure> allProcedures = getScope().getAllProcedures(true);
|
||||
for (Procedure procedure : allProcedures) {
|
||||
Set<VariableRef> modifiedVars = getModifiedVars(procedure);
|
||||
modified.put(procedure.getRef(), modifiedVars);
|
||||
}
|
||||
program.setProcedureModifiedVars(new ProcedureModifiedVars(modified));
|
||||
getProgram().setProcedureModifiedVars(new ProcedureModifiedVars(modified));
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Get all outside variables modified by a procedure (or any sub-procedure called by the procedure).
|
||||
@ -31,7 +31,7 @@ public class Pass1ModifiedVarsAnalysis {
|
||||
public Set<VariableRef> getModifiedVars(Procedure procedure) {
|
||||
Set<VariableRef> modified = new LinkedHashSet<>();
|
||||
ScopeRef procScope = procedure.getRef();
|
||||
List<ControlFlowBlock> procBlocks = program.getGraph().getScopeBlocks(procScope);
|
||||
List<ControlFlowBlock> procBlocks = getProgram().getGraph().getScopeBlocks(procScope);
|
||||
for (ControlFlowBlock block : procBlocks) {
|
||||
for (Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementLValue) {
|
||||
@ -44,7 +44,7 @@ public class Pass1ModifiedVarsAnalysis {
|
||||
}
|
||||
if(statement instanceof StatementCall) {
|
||||
ProcedureRef called = ((StatementCall) statement).getProcedure();
|
||||
Procedure calledProc = program.getScope().getProcedure(called);
|
||||
Procedure calledProc = getScope().getProcedure(called);
|
||||
modified.addAll(getModifiedVars(calledProc));
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,14 @@ public class TestPrograms extends TestCase {
|
||||
helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/");
|
||||
}
|
||||
|
||||
public void testUnusedVars() throws IOException, URISyntaxException {
|
||||
compileAndCompare("unused-vars");
|
||||
}
|
||||
|
||||
public void testFillscreen() throws IOException, URISyntaxException {
|
||||
compileAndCompare("fillscreen");
|
||||
}
|
||||
|
||||
public void testLiverangeCallProblem() throws IOException, URISyntaxException {
|
||||
compileAndCompare("liverange-call-problem");
|
||||
}
|
||||
|
19
src/main/java/dk/camelot64/kickc/test/fillscreen.kc
Normal file
19
src/main/java/dk/camelot64/kickc/test/fillscreen.kc
Normal file
@ -0,0 +1,19 @@
|
||||
byte *SCREEN = $0400;
|
||||
|
||||
void main() {
|
||||
byte c = (*SCREEN);
|
||||
fillscreen(c);
|
||||
}
|
||||
|
||||
void fillscreen(byte c) {
|
||||
for(byte j : 0..255) {
|
||||
byte* SCREEN2 = SCREEN+$100;
|
||||
byte* SCREEN3 = SCREEN+$200;
|
||||
byte* SCREEN4 = SCREEN+$3e8;
|
||||
SCREEN[j] = c;
|
||||
SCREEN2[j] = c;
|
||||
SCREEN3[j] = c;
|
||||
SCREEN4[j] = c;
|
||||
}
|
||||
}
|
||||
|
25
src/main/java/dk/camelot64/kickc/test/ref/fillscreen.asm
Normal file
25
src/main/java/dk/camelot64/kickc/test/ref/fillscreen.asm
Normal file
@ -0,0 +1,25 @@
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.const SCREEN = $400
|
||||
jsr main
|
||||
main: {
|
||||
lda SCREEN
|
||||
jsr fillscreen
|
||||
rts
|
||||
}
|
||||
fillscreen: {
|
||||
.const SCREEN2 = SCREEN+$100
|
||||
.const SCREEN3 = SCREEN+$200
|
||||
.const SCREEN4 = SCREEN+$3e8
|
||||
ldx #0
|
||||
b1:
|
||||
sta SCREEN,x
|
||||
sta SCREEN2,x
|
||||
sta SCREEN3,x
|
||||
sta SCREEN4,x
|
||||
inx
|
||||
cpx #0
|
||||
bne b1
|
||||
rts
|
||||
}
|
32
src/main/java/dk/camelot64/kickc/test/ref/fillscreen.cfg
Normal file
32
src/main/java/dk/camelot64/kickc/test/ref/fillscreen.cfg
Normal file
@ -0,0 +1,32 @@
|
||||
@begin: scope:[] from
|
||||
[0] phi() [ ] ( )
|
||||
to:@2
|
||||
@2: scope:[] from @begin
|
||||
[1] phi() [ ] ( )
|
||||
[2] call main param-assignment [ ] ( )
|
||||
to:@end
|
||||
@end: scope:[] from @2
|
||||
[3] phi() [ ] ( )
|
||||
main: scope:[main] from @2
|
||||
[4] (byte) main::c#0 ← *((const byte*) SCREEN#0) [ main::c#0 ] ( main:2 [ main::c#0 ] )
|
||||
[5] (byte) fillscreen::c#0 ← (byte) main::c#0 [ fillscreen::c#0 ] ( main:2 [ fillscreen::c#0 ] )
|
||||
[6] call fillscreen param-assignment [ ] ( main:2 [ ] )
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[7] return [ ] ( main:2 [ ] )
|
||||
to:@return
|
||||
fillscreen: scope:[fillscreen] from main
|
||||
[8] phi() [ fillscreen::c#0 ] ( main:2::fillscreen:6 [ fillscreen::c#0 ] )
|
||||
to:fillscreen::@1
|
||||
fillscreen::@1: scope:[fillscreen] from fillscreen fillscreen::@1
|
||||
[9] (byte) fillscreen::j#2 ← phi( fillscreen/(byte/signed byte/word/signed word) 0 fillscreen::@1/(byte) fillscreen::j#1 ) [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] )
|
||||
[10] *((const byte*) SCREEN#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] )
|
||||
[11] *((const byte*) fillscreen::SCREEN2#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] )
|
||||
[12] *((const byte*) fillscreen::SCREEN3#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] )
|
||||
[13] *((const byte*) fillscreen::SCREEN4#0 + (byte) fillscreen::j#2) ← (byte) fillscreen::c#0 [ fillscreen::c#0 fillscreen::j#2 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#2 ] )
|
||||
[14] (byte) fillscreen::j#1 ← ++ (byte) fillscreen::j#2 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] )
|
||||
[15] if((byte) fillscreen::j#1!=(byte/signed byte/word/signed word) 0) goto fillscreen::@1 [ fillscreen::c#0 fillscreen::j#1 ] ( main:2::fillscreen:6 [ fillscreen::c#0 fillscreen::j#1 ] )
|
||||
to:fillscreen::@return
|
||||
fillscreen::@return: scope:[fillscreen] from fillscreen::@1
|
||||
[16] return [ ] ( main:2::fillscreen:6 [ ] )
|
||||
to:@return
|
1356
src/main/java/dk/camelot64/kickc/test/ref/fillscreen.log
Normal file
1356
src/main/java/dk/camelot64/kickc/test/ref/fillscreen.log
Normal file
File diff suppressed because it is too large
Load Diff
27
src/main/java/dk/camelot64/kickc/test/ref/fillscreen.sym
Normal file
27
src/main/java/dk/camelot64/kickc/test/ref/fillscreen.sym
Normal file
@ -0,0 +1,27 @@
|
||||
(label) @2
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(byte*) SCREEN
|
||||
(const byte*) SCREEN#0 SCREEN = ((byte*))(word/signed word) 1024
|
||||
(void()) fillscreen((byte) fillscreen::c)
|
||||
(label) fillscreen::@1
|
||||
(label) fillscreen::@return
|
||||
(byte*) fillscreen::SCREEN2
|
||||
(const byte*) fillscreen::SCREEN2#0 SCREEN2 = (const byte*) SCREEN#0+(word/signed word) 256
|
||||
(byte*) fillscreen::SCREEN3
|
||||
(const byte*) fillscreen::SCREEN3#0 SCREEN3 = (const byte*) SCREEN#0+(word/signed word) 512
|
||||
(byte*) fillscreen::SCREEN4
|
||||
(const byte*) fillscreen::SCREEN4#0 SCREEN4 = (const byte*) SCREEN#0+(word/signed word) 1000
|
||||
(byte) fillscreen::c
|
||||
(byte) fillscreen::c#0 reg byte a 5.111111111111112
|
||||
(byte) fillscreen::j
|
||||
(byte) fillscreen::j#1 reg byte x 16.5
|
||||
(byte) fillscreen::j#2 reg byte x 13.2
|
||||
(void()) main()
|
||||
(label) main::@return
|
||||
(byte) main::c
|
||||
(byte) main::c#0 reg byte a 4.0
|
||||
|
||||
reg byte x [ fillscreen::j#2 fillscreen::j#1 ]
|
||||
reg byte a [ main::c#0 ]
|
||||
reg byte a [ fillscreen::c#0 ]
|
29
src/main/java/dk/camelot64/kickc/test/unused-vars.kc
Normal file
29
src/main/java/dk/camelot64/kickc/test/unused-vars.kc
Normal file
@ -0,0 +1,29 @@
|
||||
// used vars
|
||||
const byte* SCREEN = $0400;
|
||||
byte b=0;
|
||||
|
||||
// unused vars
|
||||
const byte* BGCOL = $d021;
|
||||
byte[] msg = "hello world@";
|
||||
byte[] arr = { 7, 8, 9};
|
||||
byte c=1;
|
||||
word d=1000;
|
||||
|
||||
void main() {
|
||||
// used vars
|
||||
byte col=2;
|
||||
byte* COLS=$d800;
|
||||
// unused vars
|
||||
byte e=3+3+3;
|
||||
word f=2000+2000+d;
|
||||
byte[] g = {4, 5, 6};
|
||||
byte[] h = "goodbye sky ";
|
||||
|
||||
for(byte i : 0..100) {
|
||||
// the last unused var
|
||||
signed byte x = -13;
|
||||
COLS[i] = col;
|
||||
SCREEN[i] = b;
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
byte *SCREEN = $0400;
|
||||
|
||||
byte c = (*SCREEN);
|
||||
fillscreen(c);
|
||||
|
||||
void fillscreen(byte c) {
|
||||
byte j=0;
|
||||
do {
|
||||
byte* SCREEN2 = SCREEN+$100;
|
||||
byte* SCREEN3 = SCREEN+$200;
|
||||
byte* SCREEN4 = SCREEN+$3e8;
|
||||
SCREEN[j] = c;
|
||||
SCREEN2[j] = c;
|
||||
SCREEN3[j] = c;
|
||||
SCREEN4[j] = c;
|
||||
} while(++j!=0)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user