1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-08 17:54:40 +00:00

Added pass 1 base class. Added test for unused vars.

This commit is contained in:
jespergravgaard 2017-11-30 21:51:13 +01:00
parent 42840f8f77
commit deb1304ba6
16 changed files with 1622 additions and 111 deletions

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View 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

File diff suppressed because it is too large Load Diff

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

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

View File

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