1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-10-11 12:23:45 +00:00

Implemented variable live range identification

This commit is contained in:
jespergravgaard 2017-07-26 00:26:50 +02:00
parent 69cbee294d
commit c43ab3acef
37 changed files with 1855 additions and 534 deletions

View File

@ -49,6 +49,7 @@ public class Compiler {
KickCParser.FileContext file = pass0ParseInput(input, log);
Program program = pass1GenerateSSA(file, log);
pass2OptimizeSSA(program, log);
pass3IntervalAnalysis(program, log);
AsmProgram asmProgram = pass4GenerateAsm(program, log);
pass5OptimizeAsm(asmProgram, log);
@ -84,8 +85,6 @@ public class Compiler {
}
public AsmProgram pass4GenerateAsm(Program program, CompileLog log) {
Pass4BlockSequencePlanner pass4BlockSequencePlanner = new Pass4BlockSequencePlanner(program);
pass4BlockSequencePlanner.plan();
Pass4RegisterAllocation pass4RegisterAllocation = new Pass4RegisterAllocation(program);
pass4RegisterAllocation.allocate();
Pass4CodeGeneration pass4CodeGeneration = new Pass4CodeGeneration(program);
@ -96,6 +95,28 @@ public class Compiler {
return asmProgram;
}
private void pass3IntervalAnalysis(Program program, CompileLog log) {
Pass3BlockSequencePlanner pass3BlockSequencePlanner = new Pass3BlockSequencePlanner(program, log);
pass3BlockSequencePlanner.plan();
//Pass3PhiLifting pass3PhiLifting = new Pass3PhiLifting(program, log);
//pass3PhiLifting.perform();
log.append("CONTROL FLOW GRAPH - PHI LIFTED");
log.append(program.getGraph().toString(program.getScope()));
Pass3IdentifyAliveRanges pass3IdentifyAliveRanges = new Pass3IdentifyAliveRanges(program, log);
pass3IdentifyAliveRanges.findLiveRanges();
log.append("CONTROL FLOW GRAPH - LIVE RANGES");
log.append(program.getGraph().toString(program.getScope()));
log.append("SYMBOLS - LIVE RANGES");
log.append(program.getScope().getSymbolTableContents());
}
public void pass2OptimizeSSA(Program program, CompileLog log) {
List<Pass2SsaOptimization> optimizations = new ArrayList<>();
optimizations.add(new Pass2CullEmptyBlocks(program, log));

View File

@ -120,19 +120,19 @@ public class AsmFragment {
private String conditionalJumpSignature(StatementConditionalJump conditionalJump, ControlFlowBlock block, ControlFlowGraph graph) {
StringBuilder signature = new StringBuilder();
if (conditionalJump.getRValue1() != null) {
signature.append(bind(conditionalJump.getRValue1()));
if (conditionalJump.getrValue1() != null) {
signature.append(bind(conditionalJump.getrValue1()));
}
if (conditionalJump.getOperator() != null) {
signature.append(getOperatorFragmentName(conditionalJump.getOperator()));
}
if (conditionalJump.getRValue2() instanceof ConstantInteger && ((ConstantInteger) conditionalJump.getRValue2()).getNumber() == 0) {
if (conditionalJump.getrValue2() instanceof ConstantInteger && ((ConstantInteger) conditionalJump.getrValue2()).getNumber() == 0) {
signature.append("0");
} else if (conditionalJump.getRValue2() instanceof ConstantBool) {
ConstantBool boolValue = (ConstantBool) conditionalJump.getRValue2();
} else if (conditionalJump.getrValue2() instanceof ConstantBool) {
ConstantBool boolValue = (ConstantBool) conditionalJump.getrValue2();
signature.append(boolValue.toString());
} else{
signature.append(bind(conditionalJump.getRValue2()));
signature.append(bind(conditionalJump.getrValue2()));
}
signature.append("_then_");
LabelRef destination = conditionalJump.getDestination();

View File

@ -40,7 +40,15 @@ public class ControlFlowGraph {
@JsonIgnore
public Collection<ControlFlowBlock> getAllBlocks() {
return blocks.values();
if(sequence!=null) {
ArrayList<ControlFlowBlock> blocks = new ArrayList<>();
for (LabelRef labelRef : sequence) {
blocks.add(getBlock(labelRef));
}
return blocks;
} else {
return blocks.values();
}
}
public void remove(LabelRef label) {
@ -137,7 +145,7 @@ public class ControlFlowGraph {
public String toString(ProgramScope scope) {
StringBuffer out = new StringBuffer();
for (ControlFlowBlock block : blocks.values()) {
for (ControlFlowBlock block : getAllBlocks()) {
out.append(block.toString(this, scope));
}
return out.toString();

View File

@ -137,9 +137,9 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor<Obj
@Override
public StatementConditionalJump visitConditionalJump(StatementConditionalJump origConditionalJump) {
RValue rValue1 = origConditionalJump.getRValue1();
RValue rValue1 = origConditionalJump.getrValue1();
Operator operator = origConditionalJump.getOperator();
RValue rValue2 = origConditionalJump.getRValue2();
RValue rValue2 = origConditionalJump.getrValue2();
LabelRef destination = origConditionalJump.getDestination();
return new StatementConditionalJump(rValue1, operator, rValue2, destination);
}

View File

@ -0,0 +1,140 @@
package dk.camelot64.kickc.icl;
import java.util.ArrayList;
import java.util.List;
/**
* The range, where a variable or set of variables are alive. The live ranges require all statements of the program graph to be indexed as it is stored using statement indices.
* <p>
* The definition of a variable being alive during a statement is that it is used after the statement by some later instruction in the flow.
* Note especially that a variable is not alive in the very last instruction that uses it. (Ie. in the statement x := y the variable y is not alive if it is not used again later. However in the preceding statement it is alive.)
*/
public class LiveRange {
/**
* Sorted non-overlapping intervals.
*/
private List<LiveInterval> intervals;
public static class LiveInterval {
/**
* The statement index of the first statement where the variable is assigned.
*/
private int firstStatementIdx;
/**
* The statement index of the las statement where the variable alive when the statement ends.
* <ul><li>
* If the statement is in the middle of a block:
* The variable is always used in the following statement for assignment or calculation - but never after.
* </li><li>
* If the statement is the last in a block:
* The variable is available for use in the first statement of following blocks. There the interval may "continue" as another interval - or it may end if the variable is used in the phi-block, and then no more.
* </li></ul>
*/
private int lastStatementIdx;
public LiveInterval(int firstStatementIdx, int lastStatementIdx) {
this.firstStatementIdx = firstStatementIdx;
this.lastStatementIdx = lastStatementIdx;
}
public int getFirstStatementIdx() {
return firstStatementIdx;
}
public int getLastStatementIdx() {
return lastStatementIdx;
}
}
public LiveRange() {
this.intervals = new ArrayList<>();
}
/**
* Add a statement to the live range
*
* @param statement The statement to add
* @return true if the live range was modified by the addition. false otherwise
*/
public boolean add(Statement statement) {
return add(getIndex(statement));
}
private Integer getIndex(Statement statement) {
Integer index = statement.getIndex();
if (index == null) {
throw new RuntimeException("Statement index not defined! Live Ranges only work after defining statement indexes (Pass3IdentifyAliveRanges.generateStatementIndexes).");
}
return index;
}
/**
* Add an index to the live range
* @param index The index to add
* @return true if the live range was modified. false otherwise
*/
public boolean add(int index) {
for (int i = 0; i < intervals.size(); i++) {
LiveInterval interval = intervals.get(i);
if (index < interval.firstStatementIdx - 1) {
// Add new interval before the current interval
intervals.add(i, new LiveInterval(index, index));
return true;
} else if(index == interval.firstStatementIdx - 1) {
// Extend the current interval downward
interval.firstStatementIdx = index;
return true;
} else if(index <= interval.lastStatementIdx) {
// Already inside the interval
return false;
} else if(index == interval.lastStatementIdx+1) {
// Extend current interval upward - and check if next interval should be merged
interval.lastStatementIdx = index;
if(i<intervals.size()-1) {
LiveInterval nextInterval = intervals.get(i + 1);
if(nextInterval.firstStatementIdx==index+1) {
// Merge intervals
interval.lastStatementIdx = nextInterval.lastStatementIdx;
intervals.remove(i+1);
}
}
return true;
}
}
// Not added yet - add a new interval at the end
intervals.add(new LiveInterval(index, index));
return true;
}
/**
* Determines if the live range contains a statement
* @param statement The statement to examine
* @return true if the live range contains the statement
*/
public boolean contains(Statement statement) {
return contains(getIndex(statement));
}
/**
* Determines if the live range contains an index
* @param index
* @return true if the live range contains the index
*/
private boolean contains(int index) {
for (LiveInterval interval : intervals) {
if(interval.lastStatementIdx>=index) {
if(interval.firstStatementIdx<=index) {
return true;
} else {
return false;
}
}
}
return false;
}
}

View File

@ -11,6 +11,8 @@ public class ProgramScope extends Scope {
private RegisterAllocation allocation;
private VariableLiveRanges liveRanges;
public ProgramScope() {
super("", null);
}
@ -48,6 +50,14 @@ public class ProgramScope extends Scope {
return allocation;
}
public void setLiveRanges(VariableLiveRanges liveRanges) {
this.liveRanges = liveRanges;
}
public VariableLiveRanges getLiveRanges() {
return liveRanges;
}
@Override
public boolean equals(Object o) {
if (this == o) {

View File

@ -23,4 +23,9 @@ public interface Statement {
String toString(ProgramScope scope);
/** Set the index of the statement. Indexes are used during live range analysis. */
void setIndex(Integer idx);
/** Get the index of the statement. Indexes are used during live range analysis. */
Integer getIndex();
}

View File

@ -13,7 +13,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
* <i> lValue := rValue1 &lt;operator&gt; rValue2 </i>
*/
@JsonPropertyOrder({"lValue", "rValue1", "operator", "rValue2"})
public class StatementAssignment implements StatementLValue {
public class StatementAssignment extends StatementBase implements StatementLValue {
/** The variable being assigned a value by the statement. */
private LValue lValue;
@ -22,10 +22,15 @@ public class StatementAssignment implements StatementLValue {
private RValue rValue2;
public StatementAssignment(LValue lValue, RValue rValue2) {
this.lValue = lValue;
this.rValue1 = null;
this.operator = null;
this.rValue2 = rValue2;
this(lValue, null, null, rValue2, null);
}
public StatementAssignment(LValue lValue, Operator operator, RValue rValue2) {
this(lValue, null, operator, rValue2, null);
}
public StatementAssignment(LValue lValue, RValue rValue1, Operator operator, RValue rValue2) {
this(lValue, rValue1, operator, rValue2, null);
}
public StatementAssignment(Variable lValue, Variable rValue2) {
@ -41,19 +46,15 @@ public class StatementAssignment implements StatementLValue {
@JsonProperty("lValue1") LValue lValue,
@JsonProperty("rValue1") RValue rValue1,
@JsonProperty("operator") Operator operator,
@JsonProperty("rValue2") RValue rValue2) {
@JsonProperty("rValue2") RValue rValue2,
@JsonProperty("index") Integer index) {
super(index);
this.lValue = lValue;
this.rValue1 = rValue1;
this.operator = operator;
this.rValue2 = rValue2;
}
public StatementAssignment(LValue lValue, Operator operator, RValue rValue2) {
this.lValue = lValue;
this.rValue1 = null;
this.operator = operator;
this.rValue2 = rValue2;
}
public LValue getlValue() {
return lValue;
@ -95,16 +96,19 @@ public class StatementAssignment implements StatementLValue {
@Override
public String toString(ProgramScope scope) {
return
super.idxString() +
lValue.toString(scope) + "" +
(rValue1==null?"":rValue1.toString(scope)+" ") +
(operator==null?"":operator+" ") +
rValue2.toString(scope);
rValue2.toString(scope) +
super.aliveString(scope);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
StatementAssignment that = (StatementAssignment) o;
@ -116,7 +120,8 @@ public class StatementAssignment implements StatementLValue {
@Override
public int hashCode() {
int result = lValue.hashCode();
int result = super.hashCode();
result = 31 * result + lValue.hashCode();
result = 31 * result + (rValue1 != null ? rValue1.hashCode() : 0);
result = 31 * result + (operator != null ? operator.hashCode() : 0);
result = 31 * result + (rValue2 != null ? rValue2.hashCode() : 0);

View File

@ -0,0 +1,63 @@
package dk.camelot64.kickc.icl;
import java.util.List;
/** Statement base class implementing shared properties and logic */
public abstract class StatementBase implements Statement {
private Integer index;
public StatementBase(Integer index) {
this.index = index;
}
@Override
public Integer getIndex() {
return index;
}
@Override
public void setIndex(Integer index) {
this.index = index;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StatementBase that = (StatementBase) o;
return index != null ? index.equals(that.index) : that.index == null;
}
@Override
public int hashCode() {
return index != null ? index.hashCode() : 0;
}
public String idxString() {
return index==null?"":("["+index+"] ");
}
@Override
public String toString() {
return toString(null);
}
public String aliveString(ProgramScope scope) {
if(scope==null || scope.getLiveRanges()==null) {
return "";
}
VariableLiveRanges liveRanges = scope.getLiveRanges();
List<VariableRef> alive = liveRanges.getAlive(this);
StringBuilder str = new StringBuilder();
str.append(" [ ");
for (VariableRef variableRef : alive) {
str.append(variableRef.getFullName());
str.append(" ");
}
str.append("]");
return str.toString();
}
}

View File

@ -11,17 +11,19 @@ import java.util.List;
* <br>
* <i> X<sub>i</sub> := call label param1 param2 param3 ... </i>
*/
public class StatementCall implements StatementLValue {
public class StatementCall extends StatementBase implements StatementLValue {
/** The variable being assigned a value by the call. Can be null. */
/**
* The variable being assigned a value by the call. Can be null.
*/
private LValue lValue;
private String procedureName;
private ProcedureRef procedure;
private List<RValue> parameters;
private boolean parametersByAssignment;
public StatementCall(
LValue lValue, String procedureName, List<RValue> parameters) {
public StatementCall(LValue lValue, String procedureName, List<RValue> parameters) {
super(null);
this.lValue = lValue;
this.procedureName = procedureName;
this.parameters = parameters;
@ -34,7 +36,9 @@ public class StatementCall implements StatementLValue {
@JsonProperty("procedureName") String procedureName,
@JsonProperty("procedure") ProcedureRef procedure,
@JsonProperty("parameters") List<RValue> parameters,
@JsonProperty("parametersByAssignment") boolean parametersByAssignment) {
@JsonProperty("parametersByAssignment") boolean parametersByAssignment,
@JsonProperty("index") Integer index) {
super(index);
this.lValue = lValue;
this.procedureName = procedureName;
this.procedure = procedure;
@ -92,32 +96,29 @@ public class StatementCall implements StatementLValue {
this.parametersByAssignment = true;
}
@Override
public String toString() {
return toString(null);
}
@Override
public String toString(ProgramScope scope) {
StringBuilder res = new StringBuilder();
if(lValue!=null) {
res.append(super.idxString());
if (lValue != null) {
res.append(lValue.toString(scope));
res.append("");
}
res.append("call ");
if(procedure!=null) {
res.append(procedure.getFullName()+ " ");
} else {
if (procedure != null) {
res.append(procedure.getFullName() + " ");
} else {
res.append(procedureName + " ");
}
if(parameters!=null) {
if (parameters != null) {
for (RValue parameter : parameters) {
res.append(parameter.toString(scope) + " ");
}
}
if(parametersByAssignment) {
if (parametersByAssignment) {
res.append("param-assignment");
}
res.append(super.aliveString(scope));
return res.toString();
}
@ -125,6 +126,7 @@ public class StatementCall implements StatementLValue {
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
StatementCall that = (StatementCall) o;
@ -137,7 +139,8 @@ public class StatementCall implements StatementLValue {
@Override
public int hashCode() {
int result = lValue != null ? lValue.hashCode() : 0;
int result = super.hashCode();
result = 31 * result + (lValue != null ? lValue.hashCode() : 0);
result = 31 * result + procedureName.hashCode();
result = 31 * result + (procedure != null ? procedure.hashCode() : 0);
result = 31 * result + (parameters != null ? parameters.hashCode() : 0);

View File

@ -12,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* The condition may be a single boolean variable, or a comparison between two variables (==, &lt;&gt;, &lt;, &gt;, &lt;=, &gt;= )
*
*/
public class StatementConditionalJump implements Statement {
public class StatementConditionalJump extends StatementBase {
private RValue rValue1;
private Operator operator;
@ -20,25 +20,36 @@ public class StatementConditionalJump implements Statement {
private LabelRef destination;
public StatementConditionalJump(RValue condition, LabelRef destination) {
super(null);
this.rValue1 = null;
this.operator = null;
this.rValue2 = condition;
this.destination = destination;
}
public StatementConditionalJump(
RValue rValue1,
Operator operator,
RValue rValue2,
LabelRef destination) {
this(rValue1, operator, rValue2, destination, null);
}
@JsonCreator
public StatementConditionalJump(
@JsonProperty("rValue1") RValue rValue1,
@JsonProperty("operator") Operator operator,
@JsonProperty("rValue2") RValue rValue2,
@JsonProperty("destination") LabelRef destination) {
@JsonProperty("destination") LabelRef destination,
@JsonProperty("index") Integer index) {
super(index);
this.rValue1 = rValue1;
this.operator = operator;
this.rValue2 = rValue2;
this.destination = destination;
}
public RValue getRValue1() {
public RValue getrValue1() {
return rValue1;
}
@ -46,7 +57,7 @@ public class StatementConditionalJump implements Statement {
return operator;
}
public RValue getRValue2() {
public RValue getrValue2() {
return rValue2;
}
@ -54,7 +65,7 @@ public class StatementConditionalJump implements Statement {
return destination;
}
public void setRValue1(RValue rValue1) {
public void setrValue1(RValue rValue1) {
this.rValue1 = rValue1;
}
@ -62,7 +73,7 @@ public class StatementConditionalJump implements Statement {
this.operator = operator;
}
public void setRValue2(RValue rValue2) {
public void setrValue2(RValue rValue2) {
this.rValue2 = rValue2;
}
@ -70,14 +81,10 @@ public class StatementConditionalJump implements Statement {
this.destination = destination;
}
@Override
public String toString() {
return toString(null);
}
@Override
public String toString(ProgramScope scope) {
StringBuilder out = new StringBuilder();
out.append(super.idxString());
out.append("if(");
if(rValue1!=null) {
out.append(rValue1.toString(scope));
@ -86,6 +93,7 @@ public class StatementConditionalJump implements Statement {
out.append(rValue2.toString(scope));
out.append(") goto ");
out.append(destination.getFullName());
out.append(super.aliveString(scope));
return out.toString();
}
@ -93,6 +101,7 @@ public class StatementConditionalJump implements Statement {
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
StatementConditionalJump that = (StatementConditionalJump) o;
@ -104,7 +113,8 @@ public class StatementConditionalJump implements Statement {
@Override
public int hashCode() {
int result = rValue1 != null ? rValue1.hashCode() : 0;
int result = super.hashCode();
result = 31 * result + (rValue1 != null ? rValue1.hashCode() : 0);
result = 31 * result + (operator != null ? operator.hashCode() : 0);
result = 31 * result + (rValue2 != null ? rValue2.hashCode() : 0);
result = 31 * result + destination.hashCode();

View File

@ -6,11 +6,12 @@ package dk.camelot64.kickc.icl;
* <br>
* <i> goto XX </i>
*/
public class StatementJump implements Statement {
public class StatementJump extends StatementBase {
private LabelRef destination;
public StatementJump(LabelRef destination) {
super(null);
this.destination = destination;
}
@ -22,14 +23,9 @@ public class StatementJump implements Statement {
this.destination = destination;
}
@Override
public String toString() {
return toString(null);
}
@Override
public String toString(ProgramScope scope) {
return "goto "+destination.getFullName();
return super.idxString() + "goto " + destination.getFullName()+ super.aliveString(scope);
}
}

View File

@ -3,11 +3,12 @@ package dk.camelot64.kickc.icl;
/**
* Single Static Assignment Form Statement Jump target.
*/
public class StatementLabel implements Statement {
public class StatementLabel extends StatementBase {
private LabelRef label;
public StatementLabel(LabelRef label) {
super(null);
this.label = label;
}
@ -15,14 +16,9 @@ public class StatementLabel implements Statement {
return label;
}
@Override
public String toString() {
return toString(null);
}
@Override
public String toString(ProgramScope scope) {
return label.getFullName() + ":";
return super.idxString() + label.getFullName() + ":"+super.aliveString(scope);
}
}

View File

@ -10,7 +10,7 @@ import java.util.*;
* The Phi Block initializing the necessary SSA-variables of a predecessor.
* The phi predecessor initializes a number of variables with different values depending on which predecessor control flow enters from.
*/
public class StatementPhiBlock implements Statement {
public class StatementPhiBlock extends StatementBase {
/**
* Maps each phi-varible of the predecessor to a map from a predecessor predecessor to the rvalue of the variable.
@ -19,24 +19,17 @@ public class StatementPhiBlock implements Statement {
@JsonCreator
public StatementPhiBlock(
@JsonProperty("phiVariables") List<PhiVariable> phiVariables) {
@JsonProperty("phiVariables") List<PhiVariable> phiVariables,
@JsonProperty("index") Integer index) {
super(index);
this.phiVariables = phiVariables;
}
public StatementPhiBlock() {
super(null);
this.phiVariables = new ArrayList<>();
}
/**
* Get the ordered predecessor blocks where control can enter the predecessor.
*
* @return the predecessor blocks
*/
//public List<LabelRef> getPredecessors() {
// return predecessors;
//}
/**
* Get the variables defined by the phi predecessor.
*
@ -75,6 +68,7 @@ public class StatementPhiBlock implements Statement {
List<PhiVariable> variables = new ArrayList<>(phiVariables);
Collections.reverse(variables);
for (PhiVariable phiVariable : variables) {
s.append(super.idxString());
s.append(phiVariable.getVariable().toString(scope));
s.append(" ← phi(");
for (PhiRValue phiRValue : phiVariable.getValues()) {
@ -84,7 +78,9 @@ public class StatementPhiBlock implements Statement {
RValue rValue = phiRValue.getrValue();
s.append(rValue==null?"null":rValue.toString(scope));
}
s.append(" )\n ");
s.append(" )");
s.append(super.aliveString(scope));
s.append("\n ");
}
if(s.length()>0) {
return s.toString().substring(0, s.length() - 3);
@ -108,15 +104,18 @@ public class StatementPhiBlock implements Statement {
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
StatementPhiBlock phiBlock = (StatementPhiBlock) o;
return phiVariables != null ? phiVariables.equals(phiBlock.phiVariables) : phiBlock.phiVariables == null;
return phiVariables.equals(phiBlock.phiVariables);
}
@Override
public int hashCode() {
return phiVariables != null ? phiVariables.hashCode() : 0;
int result = super.hashCode();
result = 31 * result + phiVariables.hashCode();
return result;
}
/**

View File

@ -1,7 +1,7 @@
package dk.camelot64.kickc.icl;
/** Procedure declaration in SSA */
public class StatementProcedureBegin implements Statement {
public class StatementProcedureBegin extends StatementBase {
private ProcedureRef procedure;
@ -13,6 +13,7 @@ public class StatementProcedureBegin implements Statement {
}
public StatementProcedureBegin(ProcedureRef procedure) {
super(null);
this.procedure = procedure;
}
@ -28,14 +29,9 @@ public class StatementProcedureBegin implements Statement {
this.strategy = strategy;
}
@Override
public String toString() {
return toString(null);
}
@Override
public String toString(ProgramScope scope) {
return "proc " + procedure.toString(scope);
return super.idxString() + "proc " + procedure.toString(scope) + super.aliveString(scope);
}
}

View File

@ -1,11 +1,14 @@
package dk.camelot64.kickc.icl;
/** Procedure declaration in SSA */
public class StatementProcedureEnd implements Statement {
/**
* Procedure declaration in SSA
*/
public class StatementProcedureEnd extends StatementBase {
private ProcedureRef procedure;
public StatementProcedureEnd(ProcedureRef procedure) {
super(null);
this.procedure = procedure;
}
@ -13,13 +16,8 @@ public class StatementProcedureEnd implements Statement {
return procedure;
}
@Override
public String toString() {
return toString(null);
}
@Override
public String toString(ProgramScope scope) {
return "endproc // "+procedure.getFullName()+"()";
return super.idxString() + "endproc // " + procedure.getFullName() + "()"+super.aliveString(scope);
}
}

View File

@ -6,13 +6,23 @@ import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Return Statement inside procedure in Single Static Assignment Form.
*/
public class StatementReturn implements Statement {
public class StatementReturn extends StatementBase {
/** Return value. May be null if not returning a value. */
/**
* Return value. May be null if not returning a value.
*/
private RValue value;
public StatementReturn(RValue value) {
super(null);
this.value = value;
}
@JsonCreator
public StatementReturn( @JsonProperty("value") RValue value) {
StatementReturn(
@JsonProperty("value") RValue value,
@JsonProperty("index") Integer index) {
super(index);
this.value = value;
}
@ -24,20 +34,16 @@ public class StatementReturn implements Statement {
this.value = value;
}
@Override
public String toString() {
return toString(null);
}
@Override
public String toString(ProgramScope scope) {
return "return " + (value == null ? "" : value.toString(scope));
return super.idxString() + "return " + (value == null ? "" : value.toString(scope)) + super.aliveString(scope);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
StatementReturn that = (StatementReturn) o;
@ -46,6 +52,8 @@ public class StatementReturn implements Statement {
@Override
public int hashCode() {
return value != null ? value.hashCode() : 0;
int result = super.hashCode();
result = 31 * result + (value != null ? value.hashCode() : 0);
return result;
}
}

View File

@ -0,0 +1,47 @@
package dk.camelot64.kickc.icl;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
/** Live ranges for all variables. */
public class VariableLiveRanges {
private LinkedHashMap<VariableRef, LiveRange> liveRanges;
public VariableLiveRanges() {
this.liveRanges = new LinkedHashMap<>();
}
/** Add a single statement to the live range of a variable.
*
* @param variable The variable
* @param statement The statement to add
* @return true if a live range was modified by the addition
*/
public boolean addAlive(VariableRef variable, Statement statement) {
LiveRange liveRange = liveRanges.get(variable);
if (liveRange == null) {
liveRange = new LiveRange();
liveRanges.put(variable, liveRange);
}
return liveRange.add(statement);
}
/**
* Get all variables alive at a specific statement
* @param statement The statement
* @return List of all live variables.
*/
public List<VariableRef> getAlive(Statement statement) {
ArrayList<VariableRef> aliveVars = new ArrayList<>();
for (VariableRef variable : liveRanges.keySet()) {
LiveRange liveRange = liveRanges.get(variable);
if(liveRange.contains(statement)) {
aliveVars.add(variable);
}
}
return aliveVars;
}
}

View File

@ -114,8 +114,8 @@ public class Pass2AssertSymbols extends Pass2SsaAssertion {
@Override
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
addSymbol(conditionalJump.getRValue1());
addSymbol(conditionalJump.getRValue2());
addSymbol(conditionalJump.getrValue1());
addSymbol(conditionalJump.getrValue2());
addSymbol(conditionalJump.getDestination());
return super.visitConditionalJump(conditionalJump);
}

View File

@ -36,8 +36,8 @@ public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization {
ControlFlowGraphBaseVisitor<Void> visitor = new ControlFlowGraphBaseVisitor<Void>() {
@Override
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
if(conditionalJump.getRValue1()==null && conditionalJump.getOperator()==null) {
RValue conditionRValue = conditionalJump.getRValue2();
if(conditionalJump.getrValue1()==null && conditionalJump.getOperator()==null) {
RValue conditionRValue = conditionalJump.getrValue2();
if(conditionRValue instanceof VariableRef && usages.get(conditionRValue).size()==1) {
VariableRef conditionVar = (VariableRef) conditionRValue;
StatementAssignment conditionAssignment = assignments.get(conditionVar);
@ -52,9 +52,9 @@ public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization {
case "=<":
case ">=":
case "=>":
conditionalJump.setRValue1(conditionAssignment.getrValue1());
conditionalJump.setrValue1(conditionAssignment.getrValue1());
conditionalJump.setOperator(conditionAssignment.getOperator());
conditionalJump.setRValue2(conditionAssignment.getrValue2());
conditionalJump.setrValue2(conditionAssignment.getrValue2());
simpleConditionVars.add(conditionVar);
log.append("Simple Condition " + conditionVar.toString(getSymbols()) + " " + conditionalJump.toString(getSymbols()));
break;

View File

@ -107,11 +107,11 @@ public abstract class Pass2SsaOptimization {
@Override
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
if (getAlias(aliases, conditionalJump.getRValue1()) != null) {
conditionalJump.setRValue1(getAlias(aliases, conditionalJump.getRValue1()));
if (getAlias(aliases, conditionalJump.getrValue1()) != null) {
conditionalJump.setrValue1(getAlias(aliases, conditionalJump.getrValue1()));
}
if (getAlias(aliases, conditionalJump.getRValue2()) != null) {
conditionalJump.setRValue2(getAlias(aliases, conditionalJump.getRValue2()));
if (getAlias(aliases, conditionalJump.getrValue2()) != null) {
conditionalJump.setrValue2(getAlias(aliases, conditionalJump.getrValue2()));
}
return null;
}
@ -319,8 +319,8 @@ public abstract class Pass2SsaOptimization {
@Override
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
addUsage(conditionalJump.getRValue1(), conditionalJump);
addUsage(conditionalJump.getRValue2(), conditionalJump);
addUsage(conditionalJump.getrValue1(), conditionalJump);
addUsage(conditionalJump.getrValue2(), conditionalJump);
return null;
}

View File

@ -1,5 +1,6 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.icl.*;
import java.util.ArrayList;
@ -7,14 +8,16 @@ import java.util.List;
import java.util.Stack;
/** Plan the optimal sequence for the blocks of the control flow graph */
public class Pass4BlockSequencePlanner {
public class Pass3BlockSequencePlanner {
private ControlFlowGraph graph;
private ProgramScope scope;
private CompileLog log;
public Pass4BlockSequencePlanner(Program program) {
public Pass3BlockSequencePlanner(Program program, CompileLog log) {
this.graph = program.getGraph();
this.scope = program.getScope();
this.log = log;
}
public void plan() {
@ -46,5 +49,14 @@ public class Pass4BlockSequencePlanner {
}
}
graph.setSequence(sequence);
StringBuilder entry = new StringBuilder();
entry.append("Block Sequence Planned ");
for (LabelRef labelRef : sequence) {
entry.append(labelRef.getFullName() + " ");
}
log.append(entry.toString());
}
}

View File

@ -0,0 +1,368 @@
package dk.camelot64.kickc.passes;
/**
* Identify the alive intervals for all variables. Add the intervals to the ProgramScope.
*/
import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.icl.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Pass3IdentifyAliveRanges {
private final Program program;
private final CompileLog log;
public Pass3IdentifyAliveRanges(Program program, CompileLog log) {
this.program = program;
this.log = log;
}
public void findLiveRanges() {
generateStatementIndexes();
VariableLiveRanges liveRanges = initializeLiveRanges();
program.getScope().setLiveRanges(liveRanges);
//log.append("CONTROL FLOW GRAPH - LIVE RANGES");
//log.append(program.getGraph().toString(program.getScope()));
boolean propagating;
do {
propagating = propagateLiveRanges(liveRanges);
program.getScope().setLiveRanges(liveRanges);
log.append("Propagating live ranges...");
//log.append("CONTROL FLOW GRAPH - LIVE RANGES");
//log.append(program.getGraph().toString(program.getScope()));
} while (propagating);
program.getScope().setLiveRanges(liveRanges);
}
/**
* Create index numbers for all statements in the control flow graph.
*/
private void generateStatementIndexes() {
int currentIdx = 0;
for (ControlFlowBlock block : program.getGraph().getAllBlocks()) {
for (Statement statement : block.getStatements()) {
statement.setIndex(currentIdx++);
}
}
}
/**
* Create initial live ranges for all variables used in the program.
* The initial live ranges include only the statements preceding a usage of a variable. The live ranges will be extended iteratively afterwards.
*
* @return The initial live ranges.
*/
private VariableLiveRanges initializeLiveRanges() {
LiveRangeInitializer liveRangeInitializer = new LiveRangeInitializer(program);
return liveRangeInitializer.initialize();
}
private static class LiveRangeInitializer extends ControlFlowGraphBaseVisitor<Void> {
private final Program program;
private VariableLiveRanges liveRanges;
/**
* Contains the previous statement through the iteration of each block. null if this statement is the first in the block.
*/
private Statement previousStatement;
/**
* Contains the current block through the iteration. Used to find previous statement(s) when at the start of a block.
*/
private ControlFlowBlock currentBlock;
public LiveRangeInitializer(Program program) {
this.program = program;
this.liveRanges = new VariableLiveRanges();
}
public VariableLiveRanges initialize() {
this.visitGraph(program.getGraph());
return liveRanges;
}
@Override
public Void visitBlock(ControlFlowBlock block) {
this.currentBlock = block;
this.previousStatement = null;
return super.visitBlock(block);
}
@Override
public Void visitStatement(Statement statement) {
super.visitStatement(statement);
this.previousStatement = statement;
return null;
}
private void addInitialLiveRange(RValue rValue) {
if (rValue == null) {
return;
} else if (rValue instanceof Constant) {
return;
} else if (rValue instanceof PointerDereferenceSimple) {
addInitialLiveRange(((PointerDereferenceSimple) rValue).getPointer());
} else if (rValue instanceof PointerDereferenceIndexed) {
addInitialLiveRange(((PointerDereferenceIndexed) rValue).getPointer());
addInitialLiveRange(((PointerDereferenceIndexed) rValue).getIndex());
} else if (rValue instanceof VariableRef) {
if (previousStatement != null) {
// Inside a block - add live range to previous statement
liveRanges.addAlive((VariableRef) rValue, previousStatement);
} else {
// At start of block without a phi block - add live range at end of all previous blocks
List<ControlFlowBlock> predecessors = program.getGraph().getPredecessors(currentBlock);
for (ControlFlowBlock predecessor : predecessors) {
List<Statement> predecessorStatements = predecessor.getStatements();
Statement predecessorLastStatement = predecessorStatements.get(predecessorStatements.size() - 1);
liveRanges.addAlive((VariableRef) rValue, predecessorLastStatement);
}
}
} else {
throw new RuntimeException("Unhandled RValue type " + rValue);
}
}
@Override
public Void visitPhiBlock(StatementPhiBlock phi) {
for (StatementPhiBlock.PhiVariable phiVariable : phi.getPhiVariables()) {
for (StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
if (phiRValue.getrValue() instanceof Constant) {
continue;
} else {
LabelRef predecessorRef = phiRValue.getPredecessor();
ControlFlowBlock predecessor = program.getGraph().getBlock(predecessorRef);
List<Statement> predecessorStatements = predecessor.getStatements();
Statement predecessorLastStatement = predecessorStatements.get(predecessorStatements.size() - 1);
liveRanges.addAlive((VariableRef) phiRValue.getrValue(), predecessorLastStatement);
}
}
}
return null;
}
@Override
public Void visitCall(StatementCall callLValue) {
if (callLValue.getlValue() instanceof PointerDereferenceIndexed) {
addInitialLiveRange(((PointerDereferenceIndexed) callLValue.getlValue()).getPointer());
addInitialLiveRange(((PointerDereferenceIndexed) callLValue.getlValue()).getIndex());
} else if (callLValue.getlValue() instanceof PointerDereferenceSimple) {
addInitialLiveRange(((PointerDereferenceSimple) callLValue.getlValue()).getPointer());
}
if (callLValue.getParameters() != null) {
for (RValue parameter : callLValue.getParameters()) {
addInitialLiveRange(parameter);
}
}
return null;
}
@Override
public Void visitReturn(StatementReturn aReturn) {
addInitialLiveRange(aReturn.getValue());
return null;
}
@Override
public Void visitAssignment(StatementAssignment assignment) {
if (assignment.getlValue() instanceof PointerDereferenceIndexed) {
addInitialLiveRange(((PointerDereferenceIndexed) assignment.getlValue()).getPointer());
addInitialLiveRange(((PointerDereferenceIndexed) assignment.getlValue()).getIndex());
} else if (assignment.getlValue() instanceof PointerDereferenceSimple) {
addInitialLiveRange(((PointerDereferenceSimple) assignment.getlValue()).getPointer());
}
addInitialLiveRange(assignment.getrValue1());
addInitialLiveRange(assignment.getrValue2());
return null;
}
@Override
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
addInitialLiveRange(conditionalJump.getrValue1());
addInitialLiveRange(conditionalJump.getrValue2());
return null;
}
}
/**
* Propagate live ranges to previous statements until reaching the definition of the variable.
*
* @return true if any propagation was done. (and more propagation is necessary to complete the live ranges)
*/
private boolean propagateLiveRanges(VariableLiveRanges liveRanges) {
LiveRangePropagator liveRangePropagator = new LiveRangePropagator(program, liveRanges);
return liveRangePropagator.propagate();
}
private static class LiveRangePropagator extends ControlFlowGraphBaseVisitor<Void> {
/**
* The program.
*/
private Program program;
/**
* The variable live ranges being propagated.
*/
private VariableLiveRanges liveRanges;
/**
* Has anything been modified.
*/
private boolean modified;
/**
* Contains the previous statement through the iteration of each block. null if this statement is the first in the block.
*/
private Statement previousStatement;
/**
* Contains the current block through the iteration. Used to find previous statement(s) when at the start of a block.
*/
private ControlFlowBlock currentBlock;
public LiveRangePropagator(Program program, VariableLiveRanges liveRanges) {
this.program = program;
this.liveRanges = liveRanges;
this.modified = false;
}
public boolean propagate() {
this.visitGraph(program.getGraph());
return modified;
}
@Override
public Void visitBlock(ControlFlowBlock block) {
this.currentBlock = block;
this.previousStatement = null;
return super.visitBlock(block);
}
@Override
public Void visitStatement(Statement statement) {
super.visitStatement(statement);
this.previousStatement = statement;
return null;
}
/**
* Propagate variable live ranges backward from a statement to a previous statement
*
* @param statement The current statement
* @param previous The previous statement
* @param defined The lValues assigned in the current statement (will not be propagated)
*/
private void propagate(Statement statement, List<Statement> previous, List<? extends LValue> defined) {
List<VariableRef> alive = liveRanges.getAlive(statement);
if (defined != null) {
for (LValue lValue : defined) {
if (lValue instanceof VariableRef) {
// Remove the defined variable
alive.remove(lValue);
}
}
}
// Add all non-defined alive vars to all previous statement
for (VariableRef var : alive) {
for (Statement prev : previous) {
modified |= liveRanges.addAlive(var, prev);
}
}
}
private List<Statement> getPreviousStatements() {
if (previousStatement != null) {
// Inside a block
return Arrays.asList(previousStatement);
} else {
// At start of block - add last statement of all previous blocks
return getPreviousStatements(this.currentBlock);
}
}
private ArrayList<Statement> getPreviousStatements(ControlFlowBlock block) {
ArrayList<Statement> statements = new ArrayList<>();
List<ControlFlowBlock> predecessors = program.getGraph().getPredecessors(block);
for (ControlFlowBlock predecessor : predecessors) {
List<Statement> predecessorStatements = predecessor.getStatements();
if (predecessorStatements.size() == 0) {
// Predecessor has no statements - go further back!
statements.addAll(getPreviousStatements(predecessor));
} else {
// Add last statement from predecessor
Statement predecessorLastStatement = predecessorStatements.get(predecessorStatements.size() - 1);
statements.add(predecessorLastStatement);
}
}
return statements;
}
@Override
public Void visitPhiBlock(StatementPhiBlock phi) {
List<VariableRef> defined = new ArrayList<>();
for (StatementPhiBlock.PhiVariable phiVariable : phi.getPhiVariables()) {
defined.add(phiVariable.getVariable());
}
propagate(phi, getPreviousStatements(), defined);
return null;
}
@Override
public Void visitCall(StatementCall callLValue) {
if (callLValue.getlValue() != null) {
propagate(callLValue, getPreviousStatements(), Arrays.asList(callLValue.getlValue()));
}
return null;
}
@Override
public Void visitAssignment(StatementAssignment assignment) {
if (assignment.getlValue() != null) {
propagate(assignment, getPreviousStatements(), Arrays.asList(assignment.getlValue()));
}
return null;
}
@Override
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
propagate(conditionalJump, getPreviousStatements(), new ArrayList<LValue>());
return null;
}
@Override
public Void visitJump(StatementJump jump) {
propagate(jump, getPreviousStatements(), new ArrayList<LValue>());
return null;
}
@Override
public Void visitReturn(StatementReturn aReturn) {
propagate(aReturn, getPreviousStatements(), new ArrayList<LValue>());
return null;
}
@Override
public Void visitProcedureBegin(StatementProcedureBegin statement) {
throw new RuntimeException("Statement not supported during live range propagation. Should be eliminated in earlier phase. " + statement);
}
@Override
public Void visitProcedureEnd(StatementProcedureEnd statement) {
throw new RuntimeException("Statement not supported during live range propagation. Should be eliminated in earlier phase. " + statement);
}
@Override
public Void visitJumpTarget(StatementLabel jumpTarget) {
throw new RuntimeException("Statement not supported during live range propagation. Should be eliminated in earlier phase. " + jumpTarget);
}
}
}

View File

@ -0,0 +1,60 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.icl.*;
import java.util.Collection;
import java.util.List;
/**
* Perform PhiLifting to greatly reduce overlapping of alive intervals for variables.
* PhiLifting introduces a large number of new virtual variables (one for each rvalue in phi-functions).
* Most of these are eliminated again by the PhiMemCoalesce pass.
* <p>
* See http://compilers.cs.ucla.edu/fernando/projects/soc/reports/short_tech.pdf
*/
public class Pass3PhiLifting {
private final Program program;
private final CompileLog log;
public Pass3PhiLifting(Program program, CompileLog log) {
this.program = program;
this.log = log;
}
public void perform() {
ControlFlowGraph graph = program.getGraph();
ProgramScope programScope = program.getScope();
Collection<ControlFlowBlock> blocks = graph.getAllBlocks();
for (ControlFlowBlock block : blocks) {
if (block.hasPhiBlock()) {
StatementPhiBlock phiBlock = block.getPhiBlock();
for (StatementPhiBlock.PhiVariable phiVariable : phiBlock.getPhiVariables()) {
for (StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
if (!(phiRValue.getrValue() instanceof Constant)) {
LabelRef predecessorRef = phiRValue.getPredecessor();
ControlFlowBlock predecessorBlock = graph.getBlock(predecessorRef);
Symbol predecessorSymbol = programScope.getSymbol(predecessorRef);
VariableIntermediate newVar = predecessorSymbol.getScope().addVariableIntermediate();
Symbol phiLValue = programScope.getSymbol(phiVariable.getVariable());
newVar.setType(phiLValue.getType());
newVar.setInferredType(true);
List<Statement> predecessorStatements = predecessorBlock.getStatements();
Statement lastPredecessorStatement = predecessorStatements.get(predecessorStatements.size() - 1);
StatementAssignment newAssignment = new StatementAssignment(newVar, phiRValue.getrValue());
if (lastPredecessorStatement instanceof StatementConditionalJump || lastPredecessorStatement instanceof StatementCall) {
predecessorStatements.add(predecessorStatements.size() - 1, newAssignment);
} else {
predecessorBlock.addStatement(newAssignment);
}
phiRValue.setrValue(newVar.getRef());
}
}
}
}
}
}
}

View File

@ -0,0 +1,96 @@
package dk.camelot64.kickc.test;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
/** Helper for handling reference files and output files in tests. */
public class ReferenceHelper {
private static Path tempDir;
static {
try {
tempDir = Files.createTempDirectory("kickc-output");
} catch (IOException e) {
e.printStackTrace();
}
}
private String refPath;
public ReferenceHelper(String refPath) {
this.refPath = refPath;
}
public boolean testOutput(
String fileName,
String extension,
String outputString) throws IOException, URISyntaxException {
// Read reference file
List<String> refLines = null;
try {
refLines = loadReferenceLines(fileName, extension);
} catch (Exception e) {
writeOutputFile(fileName, extension, outputString);
System.out.println("Reference file not found "+refPath+fileName+extension);
return false;
}
// Split output into outLines
List<String> outLines = getOutLines(outputString);
for (int i = 0; i < outLines.size(); i++) {
String outLine = outLines.get(i);
if(refLines.size()>i) {
String refLine = refLines.get(i);
if(!outLine.equals(refLine)) {
writeOutputFile(fileName, extension, outputString);
System.out.println(
"Output does not match reference on line "+i+"\n"+
"Reference: "+refLine+"\n"+
"Output: "+outLine
);
return false;
}
}
}
return true;
}
private List<String> getOutLines(String outputString) throws IOException {
BufferedReader rdr = new BufferedReader(new StringReader(outputString));
List<String> outLines = new ArrayList<>();
for (String line = rdr.readLine(); line != null; line = rdr.readLine()) {
outLines.add(line);
}
rdr.close();
return outLines;
}
private List<String> loadReferenceLines(String fileName, String extension) throws URISyntaxException, IOException {
String refFile = refPath+fileName+extension;
ClassLoader classLoader = this.getClass().getClassLoader();
URL refResource = classLoader.getResource(refFile);
URI refURI = refResource.toURI();
return Files.readAllLines(Paths.get(refURI), Charset.defaultCharset());
}
private void writeOutputFile(String fileName, String extension, String outputString) throws IOException {
// Write output file
File file = new File(tempDir.toFile(), fileName + extension);
FileOutputStream outputStream = new FileOutputStream(file);
OutputStreamWriter writer = new OutputStreamWriter(outputStream);
writer.write(outputString);
writer.close();
outputStream.close();
System.out.println("Output written to " + file.getAbsolutePath());
}
}

View File

@ -16,17 +16,19 @@ import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
/** Compile a number of source files and compare the resulting assembler with expected output*/
/**
* Compile a number of source files and compare the resulting assembler with expected output
*/
public class TestCompilationOutput extends TestCase {
private Path tempDir;
private String testPath;
private String refPath;
ReferenceHelper helper;
String testPath;
public TestCompilationOutput() throws IOException {
testPath = "src/dk/camelot64/kickc/test/";
refPath = "dk/camelot64/kickc/test/ref/";
tempDir = Files.createTempDirectory("kickc-output");
helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/");
}
public void testFlipper() throws IOException, URISyntaxException {
@ -56,80 +58,19 @@ public class TestCompilationOutput extends TestCase {
private void testFile(String fileName) throws IOException, URISyntaxException {
String inputPath = testPath + fileName + ".kc";
System.out.println("Testing output for "+inputPath);
System.out.println("Testing output for " + inputPath);
CharStream input = CharStreams.fromFileName(inputPath);
Compiler compiler = new Compiler();
Compiler.CompilationResult output = compiler.compile(input);
boolean success = true;
success &= testOutput(fileName, ".asm", output.getAsmProgram().toString(false));
success &= testOutput(fileName, ".sym", output.getSymbols().getSymbolTableContents());
success &= testOutput(fileName, ".cfg", output.getGraph().toString(output.getSymbols()));
success &= testOutput(fileName, ".log", output.getLog().toString());
if(!success) {
success &= helper.testOutput(fileName, ".asm", output.getAsmProgram().toString(false));
success &= helper.testOutput(fileName, ".sym", output.getSymbols().getSymbolTableContents());
success &= helper.testOutput(fileName, ".cfg", output.getGraph().toString(output.getSymbols()));
success &= helper.testOutput(fileName, ".log", output.getLog().toString());
if (!success) {
fail("Output does not match reference!");
}
}
private boolean testOutput(
String fileName,
String extension,
String outputString) throws IOException, URISyntaxException {
// Read reference file
List<String> refLines = null;
try {
refLines = loadReferenceLines(fileName, extension);
} catch (Exception e) {
writeOutputFile(fileName, extension, outputString);
System.out.println("Reference file not found "+refPath+fileName+extension);
return false;
}
// Split output into outLines
List<String> outLines = getOutLines(outputString);
for (int i = 0; i < outLines.size(); i++) {
String outLine = outLines.get(i);
if(refLines.size()>i) {
String refLine = refLines.get(i);
if(!outLine.equals(refLine)) {
writeOutputFile(fileName, extension, outputString);
System.out.println(
"Output does not match reference on line "+i+"\n"+
"Reference: "+refLine+"\n"+
"Output: "+outLine
);
return false;
}
}
}
return true;
}
private List<String> getOutLines(String outputString) throws IOException {
BufferedReader rdr = new BufferedReader(new StringReader(outputString));
List<String> outLines = new ArrayList<>();
for (String line = rdr.readLine(); line != null; line = rdr.readLine()) {
outLines.add(line);
}
rdr.close();
return outLines;
}
private List<String> loadReferenceLines(String fileName, String extension) throws URISyntaxException, IOException {
String refFile = refPath+fileName+extension;
ClassLoader classLoader = this.getClass().getClassLoader();
URL refResource = classLoader.getResource(refFile);
URI refURI = refResource.toURI();
return Files.readAllLines(Paths.get(refURI), Charset.defaultCharset());
}
private void writeOutputFile(String fileName, String extension, String outputString) throws IOException {
// Write output file
File file = new File(tempDir.toFile(), fileName + extension);
FileOutputStream outputStream = new FileOutputStream(file);
OutputStreamWriter writer = new OutputStreamWriter(outputStream);
writer.write(outputString);
writer.close();
outputStream.close();
System.out.println("Output written to " + file.getAbsolutePath());
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,25 +1,25 @@
@BEGIN: from
to:@1
@1: from @3 @BEGIN
(byte) y#2 ← phi( @3/(byte) y#4 @BEGIN/(byte) 0 )
(byte) e#3 ← phi( @3/(byte) e#5 @BEGIN/(byte) 12 )
(byte) x#2 ← phi( @3/(byte) x#1 @BEGIN/(byte) 0 )
(byte*) cursor#3 ← phi( @3/(byte*) cursor#5 @BEGIN/(word) 1024 )
*((byte*) cursor#3) ← (byte) 81
(byte) x#1 ← (byte) x#2 + (byte) 1
(byte*) cursor#1 ← (byte*) cursor#3 + (byte) 1
(byte) e#1 ← (byte) e#3 + (byte) 24
if((byte) 39<(byte) e#1) goto @2
to:@3
@2: from @1
(byte) y#1 ← (byte) y#2 + (byte) 1
(byte*) cursor#2 ← (byte*) cursor#1 + (byte) 40
(byte) e#2 ← (byte) e#1 - (byte) 39
[0] (byte) y#2 ← phi( @3/(byte) y#4 @BEGIN/(byte) 0 ) [ cursor#3 x#2 e#3 y#2 ]
[0] (byte) e#3 ← phi( @3/(byte) e#5 @BEGIN/(byte) 12 ) [ cursor#3 x#2 e#3 y#2 ]
[0] (byte) x#2 ← phi( @3/(byte) x#1 @BEGIN/(byte) 0 ) [ cursor#3 x#2 e#3 y#2 ]
[0] (byte*) cursor#3 ← phi( @3/(byte*) cursor#5 @BEGIN/(word) 1024 ) [ cursor#3 x#2 e#3 y#2 ]
[1] *((byte*) cursor#3) ← (byte) 81 [ cursor#3 x#2 e#3 y#2 ]
[2] (byte) x#1 ← (byte) x#2 + (byte) 1 [ x#1 cursor#3 e#3 y#2 ]
[3] (byte*) cursor#1 ← (byte*) cursor#3 + (byte) 1 [ x#1 e#3 cursor#1 y#2 ]
[4] (byte) e#1 ← (byte) e#3 + (byte) 24 [ x#1 e#1 cursor#1 y#2 ]
[5] if((byte) 39<(byte) e#1) goto @2 [ x#1 e#1 cursor#1 y#2 ]
to:@3
@3: from @1 @2
(byte) y#4 ← phi( @1/(byte) y#2 @2/(byte) y#1 )
(byte) e#5 ← phi( @1/(byte) e#1 @2/(byte) e#2 )
(byte*) cursor#5 ← phi( @1/(byte*) cursor#1 @2/(byte*) cursor#2 )
if((byte) x#1<(byte) 40) goto @1
[6] (byte) y#4 ← phi( @1/(byte) y#2 @2/(byte) y#1 ) [ cursor#5 x#1 e#5 y#4 ]
[6] (byte) e#5 ← phi( @1/(byte) e#1 @2/(byte) e#2 ) [ cursor#5 x#1 e#5 y#4 ]
[6] (byte*) cursor#5 ← phi( @1/(byte*) cursor#1 @2/(byte*) cursor#2 ) [ cursor#5 x#1 e#5 y#4 ]
[7] if((byte) x#1<(byte) 40) goto @1 [ cursor#5 x#1 e#5 y#4 ]
to:@END
@END: from @3
@2: from @1
[8] (byte) y#1 ← (byte) y#2 + (byte) 1 [ x#1 e#1 cursor#1 y#1 ]
[9] (byte*) cursor#2 ← (byte*) cursor#1 + (byte) 40 [ x#1 e#1 cursor#2 y#1 ]
[10] (byte) e#2 ← (byte) e#1 - (byte) 39 [ x#1 cursor#2 e#2 y#1 ]
to:@3

View File

@ -843,6 +843,99 @@ Multiple usages for variable. Not optimizing sub-constant (byte) y#2
Multiple usages for variable. Not optimizing sub-constant (byte*) cursor#1
Multiple usages for variable. Not optimizing sub-constant (byte) y#2
Multiple usages for variable. Not optimizing sub-constant (byte*) cursor#1
Block Sequence Planned @BEGIN @1 @3 @END @2
CONTROL FLOW GRAPH - PHI LIFTED
@BEGIN: from
to:@1
@1: from @3 @BEGIN
(byte) y#2 ← phi( @3/(byte) y#4 @BEGIN/(byte) 0 )
(byte) e#3 ← phi( @3/(byte) e#5 @BEGIN/(byte) 12 )
(byte) x#2 ← phi( @3/(byte) x#1 @BEGIN/(byte) 0 )
(byte*) cursor#3 ← phi( @3/(byte*) cursor#5 @BEGIN/(word) 1024 )
*((byte*) cursor#3) ← (byte) 81
(byte) x#1 ← (byte) x#2 + (byte) 1
(byte*) cursor#1 ← (byte*) cursor#3 + (byte) 1
(byte) e#1 ← (byte) e#3 + (byte) 24
if((byte) 39<(byte) e#1) goto @2
to:@3
@3: from @1 @2
(byte) y#4 ← phi( @1/(byte) y#2 @2/(byte) y#1 )
(byte) e#5 ← phi( @1/(byte) e#1 @2/(byte) e#2 )
(byte*) cursor#5 ← phi( @1/(byte*) cursor#1 @2/(byte*) cursor#2 )
if((byte) x#1<(byte) 40) goto @1
to:@END
@END: from @3
@2: from @1
(byte) y#1 ← (byte) y#2 + (byte) 1
(byte*) cursor#2 ← (byte*) cursor#1 + (byte) 40
(byte) e#2 ← (byte) e#1 - (byte) 39
to:@3
Propagating live ranges...
Propagating live ranges...
Propagating live ranges...
Propagating live ranges...
Propagating live ranges...
Propagating live ranges...
CONTROL FLOW GRAPH - LIVE RANGES
@BEGIN: from
to:@1
@1: from @3 @BEGIN
[0] (byte) y#2 ← phi( @3/(byte) y#4 @BEGIN/(byte) 0 ) [ cursor#3 x#2 e#3 y#2 ]
[0] (byte) e#3 ← phi( @3/(byte) e#5 @BEGIN/(byte) 12 ) [ cursor#3 x#2 e#3 y#2 ]
[0] (byte) x#2 ← phi( @3/(byte) x#1 @BEGIN/(byte) 0 ) [ cursor#3 x#2 e#3 y#2 ]
[0] (byte*) cursor#3 ← phi( @3/(byte*) cursor#5 @BEGIN/(word) 1024 ) [ cursor#3 x#2 e#3 y#2 ]
[1] *((byte*) cursor#3) ← (byte) 81 [ cursor#3 x#2 e#3 y#2 ]
[2] (byte) x#1 ← (byte) x#2 + (byte) 1 [ x#1 cursor#3 e#3 y#2 ]
[3] (byte*) cursor#1 ← (byte*) cursor#3 + (byte) 1 [ x#1 e#3 cursor#1 y#2 ]
[4] (byte) e#1 ← (byte) e#3 + (byte) 24 [ x#1 e#1 cursor#1 y#2 ]
[5] if((byte) 39<(byte) e#1) goto @2 [ x#1 e#1 cursor#1 y#2 ]
to:@3
@3: from @1 @2
[6] (byte) y#4 ← phi( @1/(byte) y#2 @2/(byte) y#1 ) [ cursor#5 x#1 e#5 y#4 ]
[6] (byte) e#5 ← phi( @1/(byte) e#1 @2/(byte) e#2 ) [ cursor#5 x#1 e#5 y#4 ]
[6] (byte*) cursor#5 ← phi( @1/(byte*) cursor#1 @2/(byte*) cursor#2 ) [ cursor#5 x#1 e#5 y#4 ]
[7] if((byte) x#1<(byte) 40) goto @1 [ cursor#5 x#1 e#5 y#4 ]
to:@END
@END: from @3
@2: from @1
[8] (byte) y#1 ← (byte) y#2 + (byte) 1 [ x#1 e#1 cursor#1 y#1 ]
[9] (byte*) cursor#2 ← (byte*) cursor#1 + (byte) 40 [ x#1 e#1 cursor#2 y#1 ]
[10] (byte) e#2 ← (byte) e#1 - (byte) 39 [ x#1 cursor#2 e#2 y#1 ]
to:@3
SYMBOLS - LIVE RANGES
(label) @1
(label) @2
(label) @3
(label) @BEGIN
(label) @END
(byte[1000]) SCREEN
(byte) STAR
(byte*) cursor
(byte*) cursor#1
(byte*) cursor#2
(byte*) cursor#3
(byte*) cursor#5
(byte) e
(byte) e#1
(byte) e#2
(byte) e#3
(byte) e#5
(byte) x
(byte) x#1
(byte) x#2
(byte) x0
(byte) x1
(byte) xd
(byte) y
(byte) y#1
(byte) y#2
(byte) y#4
(byte) y0
(byte) y1
(byte) yd
INITIAL ASM
BBEGIN:
B1_from_BBEGIN:
@ -878,16 +971,16 @@ B1_from_B3:
sta 10+1
jmp B1
B1:
// *((byte*) cursor#3) ← (byte) 81 // zpiby1=coby1
// [1] *((byte*) cursor#3) ← (byte) 81 [ cursor#3 x#2 e#3 y#2 ] // zpiby1=coby1
ldy #0
lda #81
sta (10),y
// (byte) x#1 ← (byte) x#2 + (byte) 1 // zpby1=zpby2_plus_1
// [2] (byte) x#1 ← (byte) x#2 + (byte) 1 [ x#1 cursor#3 e#3 y#2 ] // zpby1=zpby2_plus_1
lda 12
clc
adc #1
sta 2
// (byte*) cursor#1 ← (byte*) cursor#3 + (byte) 1 // zpptrby1=zpptrby2_plus_1
// [3] (byte*) cursor#1 ← (byte*) cursor#3 + (byte) 1 [ x#1 e#3 cursor#1 y#2 ] // zpptrby1=zpptrby2_plus_1
lda 10
clc
adc #1
@ -895,12 +988,12 @@ B1:
lda 10+1
adc #0
sta 3+1
// (byte) e#1 ← (byte) e#3 + (byte) 24 // zpby1=zpby2_plus_coby1
// [4] (byte) e#1 ← (byte) e#3 + (byte) 24 [ x#1 e#1 cursor#1 y#2 ] // zpby1=zpby2_plus_coby1
lda 13
clc
adc #24
sta 5
// if((byte) 39<(byte) e#1) goto @2 // coby1_lt_zpby1_then_la1
// [5] if((byte) 39<(byte) e#1) goto @2 [ x#1 e#1 cursor#1 y#2 ] // coby1_lt_zpby1_then_la1
lda #39
cmp 5
bcc B2
@ -918,19 +1011,19 @@ B3_from_B1:
sta 15+1
jmp B3
B3:
// if((byte) x#1<(byte) 40) goto @1 // zpby1_lt_coby1_then_la1
// [7] if((byte) x#1<(byte) 40) goto @1 [ cursor#5 x#1 e#5 y#4 ] // zpby1_lt_coby1_then_la1
lda 2
cmp #40
bcc B1_from_B3
jmp BEND
BEND:
B2:
// (byte) y#1 ← (byte) y#2 + (byte) 1 // zpby1=zpby2_plus_1
// [8] (byte) y#1 ← (byte) y#2 + (byte) 1 [ x#1 e#1 cursor#1 y#1 ] // zpby1=zpby2_plus_1
lda 14
clc
adc #1
sta 6
// (byte*) cursor#2 ← (byte*) cursor#1 + (byte) 40 // zpptrby1=zpptrby2_plus_coby1
// [9] (byte*) cursor#2 ← (byte*) cursor#1 + (byte) 40 [ x#1 e#1 cursor#2 y#1 ] // zpptrby1=zpptrby2_plus_coby1
lda #40
clc
adc 3
@ -938,7 +1031,7 @@ B2:
lda #0
adc 3+1
sta 7+1
// (byte) e#2 ← (byte) e#1 - (byte) 39 // zpby1=zpby2_minus_coby1
// [10] (byte) e#2 ← (byte) e#1 - (byte) 39 [ x#1 cursor#2 e#2 y#1 ] // zpby1=zpby2_minus_coby1
lda 5
sec
sbc #39
@ -960,7 +1053,7 @@ B3_from_B2:
Removing instruction jmp B1
Removing instruction jmp B3
Removing instruction jmp BEND
Succesful ASM optimization Pass4NextJumpElimination
Succesful ASM optimization Pass5NextJumpElimination
ASSEMBLER
BBEGIN:
B1_from_BBEGIN:
@ -995,16 +1088,16 @@ B1_from_B3:
lda 15+1
sta 10+1
B1:
// *((byte*) cursor#3) ← (byte) 81 // zpiby1=coby1
// [1] *((byte*) cursor#3) ← (byte) 81 [ cursor#3 x#2 e#3 y#2 ] // zpiby1=coby1
ldy #0
lda #81
sta (10),y
// (byte) x#1 ← (byte) x#2 + (byte) 1 // zpby1=zpby2_plus_1
// [2] (byte) x#1 ← (byte) x#2 + (byte) 1 [ x#1 cursor#3 e#3 y#2 ] // zpby1=zpby2_plus_1
lda 12
clc
adc #1
sta 2
// (byte*) cursor#1 ← (byte*) cursor#3 + (byte) 1 // zpptrby1=zpptrby2_plus_1
// [3] (byte*) cursor#1 ← (byte*) cursor#3 + (byte) 1 [ x#1 e#3 cursor#1 y#2 ] // zpptrby1=zpptrby2_plus_1
lda 10
clc
adc #1
@ -1012,12 +1105,12 @@ B1:
lda 10+1
adc #0
sta 3+1
// (byte) e#1 ← (byte) e#3 + (byte) 24 // zpby1=zpby2_plus_coby1
// [4] (byte) e#1 ← (byte) e#3 + (byte) 24 [ x#1 e#1 cursor#1 y#2 ] // zpby1=zpby2_plus_coby1
lda 13
clc
adc #24
sta 5
// if((byte) 39<(byte) e#1) goto @2 // coby1_lt_zpby1_then_la1
// [5] if((byte) 39<(byte) e#1) goto @2 [ x#1 e#1 cursor#1 y#2 ] // coby1_lt_zpby1_then_la1
lda #39
cmp 5
bcc B2
@ -1034,18 +1127,18 @@ B3_from_B1:
lda 3+1
sta 15+1
B3:
// if((byte) x#1<(byte) 40) goto @1 // zpby1_lt_coby1_then_la1
// [7] if((byte) x#1<(byte) 40) goto @1 [ cursor#5 x#1 e#5 y#4 ] // zpby1_lt_coby1_then_la1
lda 2
cmp #40
bcc B1_from_B3
BEND:
B2:
// (byte) y#1 ← (byte) y#2 + (byte) 1 // zpby1=zpby2_plus_1
// [8] (byte) y#1 ← (byte) y#2 + (byte) 1 [ x#1 e#1 cursor#1 y#1 ] // zpby1=zpby2_plus_1
lda 14
clc
adc #1
sta 6
// (byte*) cursor#2 ← (byte*) cursor#1 + (byte) 40 // zpptrby1=zpptrby2_plus_coby1
// [9] (byte*) cursor#2 ← (byte*) cursor#1 + (byte) 40 [ x#1 e#1 cursor#2 y#1 ] // zpptrby1=zpptrby2_plus_coby1
lda #40
clc
adc 3
@ -1053,7 +1146,7 @@ B2:
lda #0
adc 3+1
sta 7+1
// (byte) e#2 ← (byte) e#1 - (byte) 39 // zpby1=zpby2_minus_coby1
// [10] (byte) e#2 ← (byte) e#1 - (byte) 39 [ x#1 cursor#2 e#2 y#1 ] // zpby1=zpby2_minus_coby1
lda 5
sec
sbc #39
@ -1138,16 +1231,16 @@ B1_from_B3:
lda 15+1
sta 10+1
B1:
// *((byte*) cursor#3) ← (byte) 81 // zpiby1=coby1
// [1] *((byte*) cursor#3) ← (byte) 81 [ cursor#3 x#2 e#3 y#2 ] // zpiby1=coby1
ldy #0
lda #81
sta (10),y
// (byte) x#1 ← (byte) x#2 + (byte) 1 // zpby1=zpby2_plus_1
// [2] (byte) x#1 ← (byte) x#2 + (byte) 1 [ x#1 cursor#3 e#3 y#2 ] // zpby1=zpby2_plus_1
lda 12
clc
adc #1
sta 2
// (byte*) cursor#1 ← (byte*) cursor#3 + (byte) 1 // zpptrby1=zpptrby2_plus_1
// [3] (byte*) cursor#1 ← (byte*) cursor#3 + (byte) 1 [ x#1 e#3 cursor#1 y#2 ] // zpptrby1=zpptrby2_plus_1
lda 10
clc
adc #1
@ -1155,12 +1248,12 @@ B1:
lda 10+1
adc #0
sta 3+1
// (byte) e#1 ← (byte) e#3 + (byte) 24 // zpby1=zpby2_plus_coby1
// [4] (byte) e#1 ← (byte) e#3 + (byte) 24 [ x#1 e#1 cursor#1 y#2 ] // zpby1=zpby2_plus_coby1
lda 13
clc
adc #24
sta 5
// if((byte) 39<(byte) e#1) goto @2 // coby1_lt_zpby1_then_la1
// [5] if((byte) 39<(byte) e#1) goto @2 [ x#1 e#1 cursor#1 y#2 ] // coby1_lt_zpby1_then_la1
lda #39
cmp 5
bcc B2
@ -1177,18 +1270,18 @@ B3_from_B1:
lda 3+1
sta 15+1
B3:
// if((byte) x#1<(byte) 40) goto @1 // zpby1_lt_coby1_then_la1
// [7] if((byte) x#1<(byte) 40) goto @1 [ cursor#5 x#1 e#5 y#4 ] // zpby1_lt_coby1_then_la1
lda 2
cmp #40
bcc B1_from_B3
BEND:
B2:
// (byte) y#1 ← (byte) y#2 + (byte) 1 // zpby1=zpby2_plus_1
// [8] (byte) y#1 ← (byte) y#2 + (byte) 1 [ x#1 e#1 cursor#1 y#1 ] // zpby1=zpby2_plus_1
lda 14
clc
adc #1
sta 6
// (byte*) cursor#2 ← (byte*) cursor#1 + (byte) 40 // zpptrby1=zpptrby2_plus_coby1
// [9] (byte*) cursor#2 ← (byte*) cursor#1 + (byte) 40 [ x#1 e#1 cursor#2 y#1 ] // zpptrby1=zpptrby2_plus_coby1
lda #40
clc
adc 3
@ -1196,7 +1289,7 @@ B2:
lda #0
adc 3+1
sta 7+1
// (byte) e#2 ← (byte) e#1 - (byte) 39 // zpby1=zpby2_minus_coby1
// [10] (byte) e#2 ← (byte) e#1 - (byte) 39 [ x#1 cursor#2 e#2 y#1 ] // zpby1=zpby2_minus_coby1
lda 5
sec
sbc #39

View File

@ -1,100 +1,100 @@
@BEGIN: from
call main param-assignment
[0] call main param-assignment [ ]
to:@END
@END: from @BEGIN
main: from @BEGIN
call prepare param-assignment
[1] call prepare param-assignment [ ]
to:main::@3
main::@3: from main main::@11 main::@3 main::@6
(byte) main::c#2 ← phi( main/(byte) 25 main::@11/(byte) 25 main::@6/(byte) main::c#1 )
(byte~) main::$1 ← * (word) 53266
if((byte~) main::$1!=(byte) 254) goto main::@3
[2] (byte) main::c#2 ← phi( main/(byte) 25 main::@11/(byte) 25 main::@6/(byte) main::c#1 ) [ main::c#2 ]
[3] (byte~) main::$1 ← * (word) 53266 [ main::$1 main::c#2 ]
[4] if((byte~) main::$1!=(byte) 254) goto main::@3 [ main::c#2 ]
to:main::@4
main::@4: from main::@3 main::@4
(byte~) main::$3 ← * (word) 53266
if((byte~) main::$3!=(byte) 255) goto main::@4
[5] (byte~) main::$3 ← * (word) 53266 [ main::$3 main::c#2 ]
[6] if((byte~) main::$3!=(byte) 255) goto main::@4 [ main::c#2 ]
to:main::@6
main::@6: from main::@4
(byte) main::c#1 ← -- (byte) main::c#2
if((byte) main::c#1!=(byte) 0) goto main::@3
[7] (byte) main::c#1 ← -- (byte) main::c#2 [ main::c#1 ]
[8] if((byte) main::c#1!=(byte) 0) goto main::@3 [ main::c#1 ]
to:main::@7
main::@7: from main::@6
call flip param-assignment
[9] call flip param-assignment [ ]
to:main::@10
main::@10: from main::@7
call plot param-assignment
[10] call plot param-assignment [ ]
to:main::@11
main::@11: from main::@10
if(true) goto main::@3
[11] if(true) goto main::@3 [ ]
to:main::@return
main::@return: from main::@11
return
to:@RETURN
prepare: from main
to:prepare::@1
prepare::@1: from prepare prepare::@1
(byte) prepare::i#2 ← phi( prepare/(byte) 0 prepare::@1/(byte) prepare::i#1 )
*((word) 4096 + (byte) prepare::i#2) ← (byte) prepare::i#2
(byte) prepare::i#1 ← ++ (byte) prepare::i#2
if((byte) prepare::i#1!=(byte) 0) goto prepare::@1
to:prepare::@return
prepare::@return: from prepare::@1
return
to:@RETURN
flip: from main::@7
to:flip::@1
flip::@1: from flip flip::@4
(byte) flip::r#2 ← phi( flip/(byte) 16 flip::@4/(byte) flip::r#1 )
(byte) flip::dstIdx#5 ← phi( flip/(byte) 15 flip::@4/(byte) flip::dstIdx#2 )
(byte) flip::srcIdx#3 ← phi( flip/(byte) 0 flip::@4/(byte) flip::srcIdx#1 )
to:flip::@2
flip::@2: from flip::@1 flip::@2
(byte) flip::c#2 ← phi( flip::@1/(byte) 16 flip::@2/(byte) flip::c#1 )
(byte) flip::dstIdx#3 ← phi( flip::@1/(byte) flip::dstIdx#5 flip::@2/(byte) flip::dstIdx#1 )
(byte) flip::srcIdx#2 ← phi( flip::@1/(byte) flip::srcIdx#3 flip::@2/(byte) flip::srcIdx#1 )
(byte~) flip::$0 ← (word) 4096 *idx (byte) flip::srcIdx#2
*((word) 4352 + (byte) flip::dstIdx#3) ← (byte~) flip::$0
(byte) flip::srcIdx#1 ← ++ (byte) flip::srcIdx#2
(byte) flip::dstIdx#1 ← (byte) flip::dstIdx#3 + (byte) 16
(byte) flip::c#1 ← -- (byte) flip::c#2
if((byte) flip::c#1!=(byte) 0) goto flip::@2
to:flip::@4
flip::@4: from flip::@2
(byte) flip::dstIdx#2 ← -- (byte) flip::dstIdx#1
(byte) flip::r#1 ← -- (byte) flip::r#2
if((byte) flip::r#1!=(byte) 0) goto flip::@1
to:flip::@3
flip::@3: from flip::@3 flip::@4
(byte) flip::i#2 ← phi( flip::@3/(byte) flip::i#1 flip::@4/(byte) 0 )
(byte~) flip::$4 ← (word) 4352 *idx (byte) flip::i#2
*((word) 4096 + (byte) flip::i#2) ← (byte~) flip::$4
(byte) flip::i#1 ← ++ (byte) flip::i#2
if((byte) flip::i#1!=(byte) 0) goto flip::@3
to:flip::@return
flip::@return: from flip::@3
return
[12] return [ ]
to:@RETURN
plot: from main::@10
to:plot::@1
plot::@1: from plot plot::@3
(byte) plot::y#2 ← phi( plot/(byte) 16 plot::@3/(byte) plot::y#1 )
(byte*) plot::line#2 ← phi( plot/(word) 1236 plot::@3/(byte*) plot::line#1 )
(byte) plot::i#3 ← phi( plot/(byte) 0 plot::@3/(byte) plot::i#1 )
[13] (byte) plot::y#2 ← phi( plot/(byte) 16 plot::@3/(byte) plot::y#1 ) [ plot::i#3 plot::line#2 plot::y#2 ]
[13] (byte*) plot::line#2 ← phi( plot/(word) 1236 plot::@3/(byte*) plot::line#1 ) [ plot::i#3 plot::line#2 plot::y#2 ]
[13] (byte) plot::i#3 ← phi( plot/(byte) 0 plot::@3/(byte) plot::i#1 ) [ plot::i#3 plot::line#2 plot::y#2 ]
to:plot::@2
plot::@2: from plot::@1 plot::@2
(byte) plot::x#2 ← phi( plot::@1/(byte) 0 plot::@2/(byte) plot::x#1 )
(byte) plot::i#2 ← phi( plot::@1/(byte) plot::i#3 plot::@2/(byte) plot::i#1 )
(byte~) plot::$3 ← (word) 4096 *idx (byte) plot::i#2
*((byte*) plot::line#2 + (byte) plot::x#2) ← (byte~) plot::$3
(byte) plot::i#1 ← ++ (byte) plot::i#2
(byte) plot::x#1 ← ++ (byte) plot::x#2
if((byte) plot::x#1<(byte) 16) goto plot::@2
[14] (byte) plot::x#2 ← phi( plot::@1/(byte) 0 plot::@2/(byte) plot::x#1 ) [ plot::i#2 plot::line#2 plot::x#2 plot::y#2 ]
[14] (byte) plot::i#2 ← phi( plot::@1/(byte) plot::i#3 plot::@2/(byte) plot::i#1 ) [ plot::i#2 plot::line#2 plot::x#2 plot::y#2 ]
[15] (byte~) plot::$3 ← (word) 4096 *idx (byte) plot::i#2 [ plot::i#2 plot::line#2 plot::x#2 plot::$3 plot::y#2 ]
[16] *((byte*) plot::line#2 + (byte) plot::x#2) ← (byte~) plot::$3 [ plot::i#2 plot::line#2 plot::x#2 plot::y#2 ]
[17] (byte) plot::i#1 ← ++ (byte) plot::i#2 [ plot::i#1 plot::line#2 plot::x#2 plot::y#2 ]
[18] (byte) plot::x#1 ← ++ (byte) plot::x#2 [ plot::i#1 plot::x#1 plot::line#2 plot::y#2 ]
[19] if((byte) plot::x#1<(byte) 16) goto plot::@2 [ plot::i#1 plot::x#1 plot::line#2 plot::y#2 ]
to:plot::@3
plot::@3: from plot::@2
(byte*) plot::line#1 ← (byte*) plot::line#2 + (byte) 40
(byte) plot::y#1 ← -- (byte) plot::y#2
if((byte) plot::y#1!=(byte) 0) goto plot::@1
[20] (byte*) plot::line#1 ← (byte*) plot::line#2 + (byte) 40 [ plot::i#1 plot::line#1 plot::y#2 ]
[21] (byte) plot::y#1 ← -- (byte) plot::y#2 [ plot::i#1 plot::line#1 plot::y#1 ]
[22] if((byte) plot::y#1!=(byte) 0) goto plot::@1 [ plot::i#1 plot::line#1 plot::y#1 ]
to:plot::@return
plot::@return: from plot::@3
return
[23] return [ ]
to:@RETURN
flip: from main::@7
to:flip::@1
flip::@1: from flip flip::@4
[24] (byte) flip::r#2 ← phi( flip/(byte) 16 flip::@4/(byte) flip::r#1 ) [ flip::srcIdx#3 flip::dstIdx#5 flip::r#2 ]
[24] (byte) flip::dstIdx#5 ← phi( flip/(byte) 15 flip::@4/(byte) flip::dstIdx#2 ) [ flip::srcIdx#3 flip::dstIdx#5 flip::r#2 ]
[24] (byte) flip::srcIdx#3 ← phi( flip/(byte) 0 flip::@4/(byte) flip::srcIdx#1 ) [ flip::srcIdx#3 flip::dstIdx#5 flip::r#2 ]
to:flip::@2
flip::@2: from flip::@1 flip::@2
[25] (byte) flip::c#2 ← phi( flip::@1/(byte) 16 flip::@2/(byte) flip::c#1 ) [ flip::srcIdx#2 flip::dstIdx#3 flip::c#2 flip::r#2 ]
[25] (byte) flip::dstIdx#3 ← phi( flip::@1/(byte) flip::dstIdx#5 flip::@2/(byte) flip::dstIdx#1 ) [ flip::srcIdx#2 flip::dstIdx#3 flip::c#2 flip::r#2 ]
[25] (byte) flip::srcIdx#2 ← phi( flip::@1/(byte) flip::srcIdx#3 flip::@2/(byte) flip::srcIdx#1 ) [ flip::srcIdx#2 flip::dstIdx#3 flip::c#2 flip::r#2 ]
[26] (byte~) flip::$0 ← (word) 4096 *idx (byte) flip::srcIdx#2 [ flip::srcIdx#2 flip::dstIdx#3 flip::$0 flip::c#2 flip::r#2 ]
[27] *((word) 4352 + (byte) flip::dstIdx#3) ← (byte~) flip::$0 [ flip::srcIdx#2 flip::dstIdx#3 flip::c#2 flip::r#2 ]
[28] (byte) flip::srcIdx#1 ← ++ (byte) flip::srcIdx#2 [ flip::srcIdx#1 flip::dstIdx#3 flip::c#2 flip::r#2 ]
[29] (byte) flip::dstIdx#1 ← (byte) flip::dstIdx#3 + (byte) 16 [ flip::srcIdx#1 flip::dstIdx#1 flip::c#2 flip::r#2 ]
[30] (byte) flip::c#1 ← -- (byte) flip::c#2 [ flip::srcIdx#1 flip::dstIdx#1 flip::c#1 flip::r#2 ]
[31] if((byte) flip::c#1!=(byte) 0) goto flip::@2 [ flip::srcIdx#1 flip::dstIdx#1 flip::c#1 flip::r#2 ]
to:flip::@4
flip::@4: from flip::@2
[32] (byte) flip::dstIdx#2 ← -- (byte) flip::dstIdx#1 [ flip::srcIdx#1 flip::dstIdx#2 flip::r#2 ]
[33] (byte) flip::r#1 ← -- (byte) flip::r#2 [ flip::srcIdx#1 flip::dstIdx#2 flip::r#1 ]
[34] if((byte) flip::r#1!=(byte) 0) goto flip::@1 [ flip::srcIdx#1 flip::dstIdx#2 flip::r#1 ]
to:flip::@3
flip::@3: from flip::@3 flip::@4
[35] (byte) flip::i#2 ← phi( flip::@3/(byte) flip::i#1 flip::@4/(byte) 0 ) [ flip::i#2 ]
[36] (byte~) flip::$4 ← (word) 4352 *idx (byte) flip::i#2 [ flip::i#2 flip::$4 ]
[37] *((word) 4096 + (byte) flip::i#2) ← (byte~) flip::$4 [ flip::i#2 ]
[38] (byte) flip::i#1 ← ++ (byte) flip::i#2 [ flip::i#1 ]
[39] if((byte) flip::i#1!=(byte) 0) goto flip::@3 [ flip::i#1 ]
to:flip::@return
flip::@return: from flip::@3
[40] return [ ]
to:@RETURN
prepare: from main
to:prepare::@1
prepare::@1: from prepare prepare::@1
[41] (byte) prepare::i#2 ← phi( prepare/(byte) 0 prepare::@1/(byte) prepare::i#1 ) [ prepare::i#2 ]
[42] *((word) 4096 + (byte) prepare::i#2) ← (byte) prepare::i#2 [ prepare::i#2 ]
[43] (byte) prepare::i#1 ← ++ (byte) prepare::i#2 [ prepare::i#1 ]
[44] if((byte) prepare::i#1!=(byte) 0) goto prepare::@1 [ prepare::i#1 ]
to:prepare::@return
prepare::@return: from prepare::@1
[45] return [ ]
to:@RETURN
@END: from @BEGIN

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,16 @@
@BEGIN: from
to:@1
@1: from @3 @BEGIN
(byte) s#2 ← phi( @3/(byte) s#4 @BEGIN/(byte) 0 )
(byte) i#2 ← phi( @3/(byte) i#1 @BEGIN/(byte) 10 )
if((byte) i#2>(byte) 5) goto @2
to:@3
@2: from @1
(byte) s#1 ← (byte) s#2 + (byte) i#2
[0] (byte) s#2 ← phi( @3/(byte) s#4 @BEGIN/(byte) 0 ) [ i#2 s#2 ]
[0] (byte) i#2 ← phi( @3/(byte) i#1 @BEGIN/(byte) 10 ) [ i#2 s#2 ]
[1] if((byte) i#2>(byte) 5) goto @2 [ i#2 s#2 ]
to:@3
@3: from @1 @2
(byte) s#4 ← phi( @1/(byte) s#2 @2/(byte) s#1 )
(byte) i#1 ← -- (byte) i#2
if((byte) i#1>(byte) 0) goto @1
[2] (byte) s#4 ← phi( @1/(byte) s#2 @2/(byte) s#1 ) [ s#4 i#2 ]
[3] (byte) i#1 ← -- (byte) i#2 [ i#1 s#4 ]
[4] if((byte) i#1>(byte) 0) goto @1 [ i#1 s#4 ]
to:@END
@END: from @3
@2: from @1
[5] (byte) s#1 ← (byte) s#2 + (byte) i#2 [ i#2 s#1 ]
to:@3

View File

@ -251,6 +251,60 @@ CONTROL FLOW GRAPH
to:@END
@END: from @3
Block Sequence Planned @BEGIN @1 @3 @END @2
CONTROL FLOW GRAPH - PHI LIFTED
@BEGIN: from
to:@1
@1: from @3 @BEGIN
(byte) s#2 ← phi( @3/(byte) s#4 @BEGIN/(byte) 0 )
(byte) i#2 ← phi( @3/(byte) i#1 @BEGIN/(byte) 10 )
if((byte) i#2>(byte) 5) goto @2
to:@3
@3: from @1 @2
(byte) s#4 ← phi( @1/(byte) s#2 @2/(byte) s#1 )
(byte) i#1 ← -- (byte) i#2
if((byte) i#1>(byte) 0) goto @1
to:@END
@END: from @3
@2: from @1
(byte) s#1 ← (byte) s#2 + (byte) i#2
to:@3
Propagating live ranges...
Propagating live ranges...
Propagating live ranges...
CONTROL FLOW GRAPH - LIVE RANGES
@BEGIN: from
to:@1
@1: from @3 @BEGIN
[0] (byte) s#2 ← phi( @3/(byte) s#4 @BEGIN/(byte) 0 ) [ i#2 s#2 ]
[0] (byte) i#2 ← phi( @3/(byte) i#1 @BEGIN/(byte) 10 ) [ i#2 s#2 ]
[1] if((byte) i#2>(byte) 5) goto @2 [ i#2 s#2 ]
to:@3
@3: from @1 @2
[2] (byte) s#4 ← phi( @1/(byte) s#2 @2/(byte) s#1 ) [ s#4 i#2 ]
[3] (byte) i#1 ← -- (byte) i#2 [ i#1 s#4 ]
[4] if((byte) i#1>(byte) 0) goto @1 [ i#1 s#4 ]
to:@END
@END: from @3
@2: from @1
[5] (byte) s#1 ← (byte) s#2 + (byte) i#2 [ i#2 s#1 ]
to:@3
SYMBOLS - LIVE RANGES
(label) @1
(label) @2
(label) @3
(label) @BEGIN
(label) @END
(byte) i
(byte) i#1
(byte) i#2
(byte) s
(byte) s#1
(byte) s#2
(byte) s#4
INITIAL ASM
BBEGIN:
B1_from_BBEGIN:
@ -270,7 +324,7 @@ B1_from_B3:
sta 4
jmp B1
B1:
// if((byte) i#2>(byte) 5) goto @2 // zpby1_gt_coby1_then_la1
// [1] if((byte) i#2>(byte) 5) goto @2 [ i#2 s#2 ] // zpby1_gt_coby1_then_la1
lda 4
cmp #5
beq !+
@ -282,17 +336,17 @@ B3_from_B1:
sta 6
jmp B3
B3:
// (byte) i#1 ← -- (byte) i#2 // zpby1=_dec_zpby2
// [3] (byte) i#1 ← -- (byte) i#2 [ i#1 s#4 ] // zpby1=_dec_zpby2
lda 4
sta 3
dec 3
// if((byte) i#1>(byte) 0) goto @1 // zpby1_gt_0_then_la1
// [4] if((byte) i#1>(byte) 0) goto @1 [ i#1 s#4 ] // zpby1_gt_0_then_la1
lda 3
bne B1_from_B3
jmp BEND
BEND:
B2:
// (byte) s#1 ← (byte) s#2 + (byte) i#2 // zpby1=zpby2_plus_zpby3
// [5] (byte) s#1 ← (byte) s#2 + (byte) i#2 [ i#2 s#1 ] // zpby1=zpby2_plus_zpby3
lda 5
clc
adc 4
@ -306,7 +360,7 @@ B3_from_B2:
Removing instruction jmp B1
Removing instruction jmp B3
Removing instruction jmp BEND
Succesful ASM optimization Pass4NextJumpElimination
Succesful ASM optimization Pass5NextJumpElimination
ASSEMBLER
BBEGIN:
B1_from_BBEGIN:
@ -325,7 +379,7 @@ B1_from_B3:
lda 3
sta 4
B1:
// if((byte) i#2>(byte) 5) goto @2 // zpby1_gt_coby1_then_la1
// [1] if((byte) i#2>(byte) 5) goto @2 [ i#2 s#2 ] // zpby1_gt_coby1_then_la1
lda 4
cmp #5
beq !+
@ -336,16 +390,16 @@ B3_from_B1:
lda 5
sta 6
B3:
// (byte) i#1 ← -- (byte) i#2 // zpby1=_dec_zpby2
// [3] (byte) i#1 ← -- (byte) i#2 [ i#1 s#4 ] // zpby1=_dec_zpby2
lda 4
sta 3
dec 3
// if((byte) i#1>(byte) 0) goto @1 // zpby1_gt_0_then_la1
// [4] if((byte) i#1>(byte) 0) goto @1 [ i#1 s#4 ] // zpby1_gt_0_then_la1
lda 3
bne B1_from_B3
BEND:
B2:
// (byte) s#1 ← (byte) s#2 + (byte) i#2 // zpby1=zpby2_plus_zpby3
// [5] (byte) s#1 ← (byte) s#2 + (byte) i#2 [ i#2 s#1 ] // zpby1=zpby2_plus_zpby3
lda 5
clc
adc 4
@ -388,7 +442,7 @@ B1_from_B3:
lda 3
sta 4
B1:
// if((byte) i#2>(byte) 5) goto @2 // zpby1_gt_coby1_then_la1
// [1] if((byte) i#2>(byte) 5) goto @2 [ i#2 s#2 ] // zpby1_gt_coby1_then_la1
lda 4
cmp #5
beq !+
@ -399,16 +453,16 @@ B3_from_B1:
lda 5
sta 6
B3:
// (byte) i#1 ← -- (byte) i#2 // zpby1=_dec_zpby2
// [3] (byte) i#1 ← -- (byte) i#2 [ i#1 s#4 ] // zpby1=_dec_zpby2
lda 4
sta 3
dec 3
// if((byte) i#1>(byte) 0) goto @1 // zpby1_gt_0_then_la1
// [4] if((byte) i#1>(byte) 0) goto @1 [ i#1 s#4 ] // zpby1_gt_0_then_la1
lda 3
bne B1_from_B3
BEND:
B2:
// (byte) s#1 ← (byte) s#2 + (byte) i#2 // zpby1=zpby2_plus_zpby3
// [5] (byte) s#1 ← (byte) s#2 + (byte) i#2 [ i#2 s#1 ] // zpby1=zpby2_plus_zpby3
lda 5
clc
adc 4

View File

@ -1,11 +1,11 @@
@BEGIN: from
to:@1
@1: from @1 @BEGIN
(byte) i#2 ← phi( @1/(byte) i#1 @BEGIN/(byte) 5 )
(byte~) $0 ← (byte) 2 + (byte) i#2
(byte~) $1 ← (byte~) $0 + (byte) 2
*((word) 4352 + (byte) i#2) ← (byte~) $1
(byte) i#1 ← (byte) i#2 + (byte) 1
if((byte) i#1<(byte) 10) goto @1
[0] (byte) i#2 ← phi( @1/(byte) i#1 @BEGIN/(byte) 5 ) [ i#2 ]
[1] (byte~) $0 ← (byte) 2 + (byte) i#2 [ i#2 $0 ]
[2] (byte~) $1 ← (byte~) $0 + (byte) 2 [ i#2 $1 ]
[3] *((word) 4352 + (byte) i#2) ← (byte~) $1 [ i#2 ]
[4] (byte) i#1 ← (byte) i#2 + (byte) 1 [ i#1 ]
[5] if((byte) i#1<(byte) 10) goto @1 [ i#1 ]
to:@END
@END: from @1

View File

@ -206,6 +206,46 @@ Multiple usages for variable. Not optimizing sub-constant (byte) i#2
Multiple usages for variable. Not optimizing sub-constant (byte) i#2
Multiple usages for variable. Not optimizing sub-constant (byte) i#2
Multiple usages for variable. Not optimizing sub-constant (byte) i#2
Block Sequence Planned @BEGIN @1 @END
CONTROL FLOW GRAPH - PHI LIFTED
@BEGIN: from
to:@1
@1: from @1 @BEGIN
(byte) i#2 ← phi( @1/(byte) i#1 @BEGIN/(byte) 5 )
(byte~) $0 ← (byte) 2 + (byte) i#2
(byte~) $1 ← (byte~) $0 + (byte) 2
*((word) 4352 + (byte) i#2) ← (byte~) $1
(byte) i#1 ← (byte) i#2 + (byte) 1
if((byte) i#1<(byte) 10) goto @1
to:@END
@END: from @1
Propagating live ranges...
Propagating live ranges...
CONTROL FLOW GRAPH - LIVE RANGES
@BEGIN: from
to:@1
@1: from @1 @BEGIN
[0] (byte) i#2 ← phi( @1/(byte) i#1 @BEGIN/(byte) 5 ) [ i#2 ]
[1] (byte~) $0 ← (byte) 2 + (byte) i#2 [ i#2 $0 ]
[2] (byte~) $1 ← (byte~) $0 + (byte) 2 [ i#2 $1 ]
[3] *((word) 4352 + (byte) i#2) ← (byte~) $1 [ i#2 ]
[4] (byte) i#1 ← (byte) i#2 + (byte) 1 [ i#1 ]
[5] if((byte) i#1<(byte) 10) goto @1 [ i#1 ]
to:@END
@END: from @1
SYMBOLS - LIVE RANGES
(byte~) $0
(byte~) $1
(label) @1
(label) @BEGIN
(label) @END
(byte) i
(byte) i#1
(byte) i#2
(byte[16]) p
INITIAL ASM
BBEGIN:
B1_from_BBEGIN:
@ -219,26 +259,26 @@ B1_from_B1:
sta 5
jmp B1
B1:
// (byte~) $0 ← (byte) 2 + (byte) i#2 // zpby1=coby1_plus_zpby2
// [1] (byte~) $0 ← (byte) 2 + (byte) i#2 [ i#2 $0 ] // zpby1=coby1_plus_zpby2
lda #2
clc
adc 5
sta 2
// (byte~) $1 ← (byte~) $0 + (byte) 2 // zpby1=zpby2_plus_coby1
// [2] (byte~) $1 ← (byte~) $0 + (byte) 2 [ i#2 $1 ] // zpby1=zpby2_plus_coby1
lda 2
clc
adc #2
sta 3
// *((word) 4352 + (byte) i#2) ← (byte~) $1 // ptr_cowo1_zpby1=zpby2
// [3] *((word) 4352 + (byte) i#2) ← (byte~) $1 [ i#2 ] // ptr_cowo1_zpby1=zpby2
lda 3
ldy 5
sta 4352,y
// (byte) i#1 ← (byte) i#2 + (byte) 1 // zpby1=zpby2_plus_1
// [4] (byte) i#1 ← (byte) i#2 + (byte) 1 [ i#1 ] // zpby1=zpby2_plus_1
lda 5
clc
adc #1
sta 4
// if((byte) i#1<(byte) 10) goto @1 // zpby1_lt_coby1_then_la1
// [5] if((byte) i#1<(byte) 10) goto @1 [ i#1 ] // zpby1_lt_coby1_then_la1
lda 4
cmp #10
bcc B1_from_B1
@ -247,7 +287,7 @@ BEND:
Removing instruction jmp B1
Removing instruction jmp BEND
Succesful ASM optimization Pass4NextJumpElimination
Succesful ASM optimization Pass5NextJumpElimination
ASSEMBLER
BBEGIN:
B1_from_BBEGIN:
@ -260,26 +300,26 @@ B1_from_B1:
lda 4
sta 5
B1:
// (byte~) $0 ← (byte) 2 + (byte) i#2 // zpby1=coby1_plus_zpby2
// [1] (byte~) $0 ← (byte) 2 + (byte) i#2 [ i#2 $0 ] // zpby1=coby1_plus_zpby2
lda #2
clc
adc 5
sta 2
// (byte~) $1 ← (byte~) $0 + (byte) 2 // zpby1=zpby2_plus_coby1
// [2] (byte~) $1 ← (byte~) $0 + (byte) 2 [ i#2 $1 ] // zpby1=zpby2_plus_coby1
lda 2
clc
adc #2
sta 3
// *((word) 4352 + (byte) i#2) ← (byte~) $1 // ptr_cowo1_zpby1=zpby2
// [3] *((word) 4352 + (byte) i#2) ← (byte~) $1 [ i#2 ] // ptr_cowo1_zpby1=zpby2
lda 3
ldy 5
sta 4352,y
// (byte) i#1 ← (byte) i#2 + (byte) 1 // zpby1=zpby2_plus_1
// [4] (byte) i#1 ← (byte) i#2 + (byte) 1 [ i#1 ] // zpby1=zpby2_plus_1
lda 5
clc
adc #1
sta 4
// if((byte) i#1<(byte) 10) goto @1 // zpby1_lt_coby1_then_la1
// [5] if((byte) i#1<(byte) 10) goto @1 [ i#1 ] // zpby1_lt_coby1_then_la1
lda 4
cmp #10
bcc B1_from_B1
@ -308,26 +348,26 @@ B1_from_B1:
lda 4
sta 5
B1:
// (byte~) $0 ← (byte) 2 + (byte) i#2 // zpby1=coby1_plus_zpby2
// [1] (byte~) $0 ← (byte) 2 + (byte) i#2 [ i#2 $0 ] // zpby1=coby1_plus_zpby2
lda #2
clc
adc 5
sta 2
// (byte~) $1 ← (byte~) $0 + (byte) 2 // zpby1=zpby2_plus_coby1
// [2] (byte~) $1 ← (byte~) $0 + (byte) 2 [ i#2 $1 ] // zpby1=zpby2_plus_coby1
lda 2
clc
adc #2
sta 3
// *((word) 4352 + (byte) i#2) ← (byte~) $1 // ptr_cowo1_zpby1=zpby2
// [3] *((word) 4352 + (byte) i#2) ← (byte~) $1 [ i#2 ] // ptr_cowo1_zpby1=zpby2
lda 3
ldy 5
sta 4352,y
// (byte) i#1 ← (byte) i#2 + (byte) 1 // zpby1=zpby2_plus_1
// [4] (byte) i#1 ← (byte) i#2 + (byte) 1 [ i#1 ] // zpby1=zpby2_plus_1
lda 5
clc
adc #1
sta 4
// if((byte) i#1<(byte) 10) goto @1 // zpby1_lt_coby1_then_la1
// [5] if((byte) i#1<(byte) 10) goto @1 [ i#1 ] // zpby1_lt_coby1_then_la1
lda 4
cmp #10
bcc B1_from_B1

View File

@ -1,15 +1,15 @@
@BEGIN: from
call sum param-assignment
[0] call sum param-assignment [ ]
to:@2
@2: from @BEGIN
call sum param-assignment
[1] call sum param-assignment [ ]
to:@END
@END: from @2
sum: from @2 @BEGIN
(byte) sum::b#2 ← phi( @2/(byte) 13 @BEGIN/(byte) 2 )
(byte) sum::a#2 ← phi( @2/(byte) 9 @BEGIN/(byte) 1 )
(byte) s1#0 ← (byte) sum::a#2 + (byte) sum::b#2
[2] (byte) sum::b#2 ← phi( @2/(byte) 13 @BEGIN/(byte) 2 ) [ sum::a#2 sum::b#2 ]
[2] (byte) sum::a#2 ← phi( @2/(byte) 9 @BEGIN/(byte) 1 ) [ sum::a#2 sum::b#2 ]
[3] (byte) s1#0 ← (byte) sum::a#2 + (byte) sum::b#2 [ s1#0 ]
to:sum::@return
sum::@return: from sum
return (byte) s1#0
[4] return (byte) s1#0 [ ]
to:@RETURN
@END: from @2

View File

@ -240,6 +240,58 @@ sum::@return: from sum
to:@RETURN
@END: from @2
Block Sequence Planned @BEGIN @2 @END sum sum::@return
CONTROL FLOW GRAPH - PHI LIFTED
@BEGIN: from
call sum param-assignment
to:@2
@2: from @BEGIN
call sum param-assignment
to:@END
@END: from @2
sum: from @2 @BEGIN
(byte) sum::b#2 ← phi( @2/(byte) 13 @BEGIN/(byte) 2 )
(byte) sum::a#2 ← phi( @2/(byte) 9 @BEGIN/(byte) 1 )
(byte) s1#0 ← (byte) sum::a#2 + (byte) sum::b#2
to:sum::@return
sum::@return: from sum
return (byte) s1#0
to:@RETURN
Propagating live ranges...
CONTROL FLOW GRAPH - LIVE RANGES
@BEGIN: from
[0] call sum param-assignment [ ]
to:@2
@2: from @BEGIN
[1] call sum param-assignment [ ]
to:@END
@END: from @2
sum: from @2 @BEGIN
[2] (byte) sum::b#2 ← phi( @2/(byte) 13 @BEGIN/(byte) 2 ) [ sum::a#2 sum::b#2 ]
[2] (byte) sum::a#2 ← phi( @2/(byte) 9 @BEGIN/(byte) 1 ) [ sum::a#2 sum::b#2 ]
[3] (byte) s1#0 ← (byte) sum::a#2 + (byte) sum::b#2 [ s1#0 ]
to:sum::@return
sum::@return: from sum
[4] return (byte) s1#0 [ ]
to:@RETURN
SYMBOLS - LIVE RANGES
(label) @2
(label) @BEGIN
(label) @END
(byte) s1
(byte) s1#0
(byte) s2
(byte()) sum((byte) sum::a , (byte) sum::b)
(label) sum::@return
(byte) sum::a
(byte) sum::a#2
(byte) sum::b
(byte) sum::b#2
(byte) sum::return
INITIAL ASM
BBEGIN:
sum_from_BBEGIN:
@ -263,7 +315,7 @@ sum_from_B2:
jmp BEND
BEND:
sum:
// (byte) s1#0 ← (byte) sum::a#2 + (byte) sum::b#2 // zpby1=zpby2_plus_zpby3
// [3] (byte) s1#0 ← (byte) sum::a#2 + (byte) sum::b#2 [ s1#0 ] // zpby1=zpby2_plus_zpby3
lda 2
clc
adc 3
@ -275,7 +327,7 @@ sum__Breturn:
Removing instruction jmp B2
Removing instruction jmp BEND
Removing instruction jmp sum__Breturn
Succesful ASM optimization Pass4NextJumpElimination
Succesful ASM optimization Pass5NextJumpElimination
ASSEMBLER
BBEGIN:
sum_from_BBEGIN:
@ -297,7 +349,7 @@ sum_from_B2:
jsr sum
BEND:
sum:
// (byte) s1#0 ← (byte) sum::a#2 + (byte) sum::b#2 // zpby1=zpby2_plus_zpby3
// [3] (byte) s1#0 ← (byte) sum::a#2 + (byte) sum::b#2 [ s1#0 ] // zpby1=zpby2_plus_zpby3
lda 2
clc
adc 3
@ -342,7 +394,7 @@ sum_from_B2:
jsr sum
BEND:
sum:
// (byte) s1#0 ← (byte) sum::a#2 + (byte) sum::b#2 // zpby1=zpby2_plus_zpby3
// [3] (byte) s1#0 ← (byte) sum::a#2 + (byte) sum::b#2 [ s1#0 ] // zpby1=zpby2_plus_zpby3
lda 2
clc
adc 3