mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-20 23:30:43 +00:00
Implemented variable live range identification
This commit is contained in:
parent
69cbee294d
commit
c43ab3acef
@ -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));
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
140
src/dk/camelot64/kickc/icl/LiveRange.java
Normal file
140
src/dk/camelot64/kickc/icl/LiveRange.java
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
* <i> lValue := rValue1 <operator> 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);
|
||||
|
63
src/dk/camelot64/kickc/icl/StatementBase.java
Normal file
63
src/dk/camelot64/kickc/icl/StatementBase.java
Normal 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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -12,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
* The condition may be a single boolean variable, or a comparison between two variables (==, <>, <, >, <=, >= )
|
||||
*
|
||||
*/
|
||||
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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
47
src/dk/camelot64/kickc/icl/VariableLiveRanges.java
Normal file
47
src/dk/camelot64/kickc/icl/VariableLiveRanges.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
||||
}
|
||||
}
|
368
src/dk/camelot64/kickc/passes/Pass3IdentifyAliveRanges.java
Normal file
368
src/dk/camelot64/kickc/passes/Pass3IdentifyAliveRanges.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
60
src/dk/camelot64/kickc/passes/Pass3PhiLifting.java
Normal file
60
src/dk/camelot64/kickc/passes/Pass3PhiLifting.java
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
96
src/dk/camelot64/kickc/test/ReferenceHelper.java
Normal file
96
src/dk/camelot64/kickc/test/ReferenceHelper.java
Normal 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());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user