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

Optimized live range effective - vastly improving compile speed.

This commit is contained in:
jespergravgaard 2017-10-16 12:47:42 +02:00
parent d551f8c569
commit 520361f7b6
20 changed files with 1020 additions and 697 deletions

View File

@ -206,6 +206,7 @@ public class Compiler {
new Pass3StatementIndices(program).generateStatementIndices();
new Pass3CallGraphAnalysis(program).findCallGraph();
new Pass3LiveRangesAnalysis(program).findLiveRanges();
new Pass3LiveRangesEffectiveAnalysis(program).findLiveRangesEffective();
program.getLog().append("CONTROL FLOW GRAPH - PHI MEM COALESCED");
program.getLog().append(program.getGraph().toString(program));
pass2AssertSSA(program);

View File

@ -1,3 +1,4 @@
Known Problems
Features
- Move the main code into a main() function, and disallow code outside functions. The main function per default has no parameters and exits with RTS.
@ -21,16 +22,9 @@ Features
- Allow complex array expressions in lValues eg. (SCREEN+$100)[idx]
- Optimize loops by unrolling them somewhat
- Optimize loops with Strength reduction (https://en.wikipedia.org/wiki/Strength_reduction)
+ Create a proper main function for the compiler
+ Add ++/-- incrementing/decrementing operators.
+ Optimize if's without else if(expr) { stmt; } -> $1=!expr; if($1) goto @1; stmt; @1:
+ Add a for loop for(init;condition;increment) {stmt} -> { init; do { stmt; increment } while (condition) }
+ Add for loop for(byte i: 1..100) { } and for(byte i : 100..0) {} (plus maybe .+. and .-. to make the inc/dec unambiguous)
Assembler Improvements
- Make generated ASM human readable.
+ Use hex-numbers
+ add labels for constants and zp-variables.
- Relabel blocks eliminating long labels such as b3_from_b11
- Eliminate chained JMP's (replace by direct JMP) - example: loopsplit.asm
- Better ASM static value analysis
- Not just constants - but also other values (value of var, value of var1[var2], value of var+4 etc.)
@ -41,11 +35,6 @@ Assembler Improvements
- Eliminate LDA from STA $11, LDA $11 (using ASM static value analysis of A-register)
- Optimize by allowing resequencing of ASM (statements and phi assignments) in a final phase.
- ASM loop analysis: If all usages of a register has the same value move the assignment out of the loop (if the assignment is simple enough).
+ Eliminate unnecessary labels in ASM
Known Problems
+ Procedures that modify variables outside their scope does not work. Outer vars must be transfered in/out like parameters/return values to get it working.
+ Alive vars are propagated backward through procedures (correctly). However they are then propagated back through ALL calls to the procedure incorrectly. They should only be alive at calls where they are alive after the call. In summin.kc s1#0 is incirrectly backpropagated through the first call, where it is not alive.
Register Allocation
- Allow user to limit number of combinations tested
@ -58,6 +47,46 @@ Register Allocation
- Improve combination testing by finding live range overlaps and not creating combinations that would create an overlap conflict.
- Combinations should be created in a tree-structure instead of just doing all combinations
- Example: For equivalence classes a, b, c if a&c have overlapping live ranges they can never have the same register. Therefore the combination iterator should not create combinations where C has the same register as a.
Process/Code Structure Improvement
- Eliminate copy visitor
- Refactor Expression Operator Implementation & Evaluation into one class per operator
- Improve error messages to give better context
- Offer to compile resulting ASM with KickAssembler
+ Implemenent Assertions for the output of different phases (ensuring that the result of the phase is consistent)
+ Make each phase return a separate object graph (allowing for keeeping the history in memory & performing rollbacks)
Testing
- Implement ICL syntax (printer & parser). Drop the JSON.
- Test that the parse tree for specific KC syntax is as expected. Use a print function for the parse tree to generate output for comparison.
- Test the ICL result of a specific phase on a specific ICL input. Create an ICL syntax for parsing directly to ICL and a printer for the syntax.
- Emulate/Run the ASM for a specific KC program compiled. Compare the emulated ASM output to output calculated by executing directly on the KC tree.
- Add assert statements to the language. Create KC programs that test the compiler by compiling, running and testing assertions.
Usages
- Implement library for memory allocation in main memory
- Implement library for output on the screen (using basic functions)
Real Usage
- Implement library for fast multiply (mul.asm)
- Implement spline library (spline.asm)
- Implement polygon filler for complex polygons.
- Implement a true type font renderer.
Done
+ Test the ASM program output resulting from compiling specific KC program input.
+ Create a proper main function for the compiler
+ Add ++/-- incrementing/decrementing operators.
+ Optimize if's without else if(expr) { stmt; } -> $1=!expr; if($1) goto @1; stmt; @1:
+ Add a for loop for(init;condition;increment) {stmt} -> { init; do { stmt; increment } while (condition) }
+ Add for loop for(byte i: 1..100) { } and for(byte i : 100..0) {} (plus maybe .+. and .-. to make the inc/dec unambiguous)
+ Eliminate unnecessary labels in ASM
+ Make generated ASM human readable.
+ Use hex-numbers
+ add labels for constants and zp-variables.
+ Procedures that modify variables outside their scope does not work. Outer vars must be transfered in/out like parameters/return values to get it working.
+ Alive vars are propagated backward through procedures (correctly). However they are then propagated back through ALL calls to the procedure incorrectly. They should only be alive at calls where they are alive after the call. In summin.kc s1#0 is incirrectly backpropagated through the first call, where it is not alive.
+ Reuse phi-transitions that are identical
+ Optimize phi transitions by ensuring that identical phi-transitions with regards to register allocation are collected into a single transition.
+ Limit number of combinations tested
@ -72,33 +101,6 @@ Register Allocation
+ Register types: A, X, Y, ZP, (memory).
+ Implement a register allocation (coloring) algorithm using by liveness intervals, preferences, weights & clobbering information.
+ Optimize register allocation by combining with knowledge of ASM program cost (bytes/cycles) and different ASM fragments with different clobbering.
Process/Code Structure Improvement
- Eliminate copy visitor
- Refactor Expression Operator Implementation & Evaluation into one class per operator
- Improve error messages to give better context
- Offer to compile resulting ASM with KickAssembler
+ Implemenent Assertions for the output of different phases (ensuring that the result of the phase is consistent)
+ Make each phase return a separate object graph (allowing for keeeping the history in memory & performing rollbacks)
Testing
- Test that the parse tree for specific KC syntax is as expected. Use a print function for the parse tree to generate output for comparison.
- Test the ICL result of a specific phase on a specific ICL input. Create an ICL syntax for parsing directly to ICL and a printer for the syntax.
- Emulate/Run the ASM for a specific KC program compiled. Compare the emulated ASM output to output calculated by executing directly on the KC tree.
- Add assert statements to the language. Create KC programs that test the compiler by compiling, running and testing assertions.
+ Test the ASM program output resulting from compiling specific KC program input.
Usages
- Implement library for memory allocation in main memory
- Implement library for output on the screen (using basic functions)
Real Usage
- Implement library for fast multiply (mul.asm)
- Implement spline library (spline.asm)
- Implement polygon filler for complex polygons.
- Implement a true type font renderer.
New Constant Solution
+ Live range overlap analysis of register combinations inside methods must also look at registers alive at all calls.
+ Examine why temp-vars are used in flipper.
+ Examine why flipper is plotted in a wrong position on the screen.
@ -112,3 +114,4 @@ New Constant Solution
+ Fix by introducing "effective alive vars" which includes alive vars at all calls to containing methods and using that during clobber check.
+ In loopnest.asm x&y are used in both loops - the outer x&y are clobbered by the inner loop.
+ In voronoi.asm in render() x is clobbered during call to findcol().
+ Optimize getAliveEffective() to improve speed

View File

@ -68,40 +68,5 @@ public class LiveRangeVariables {
return liveRanges.get(variable);
}
/**
* Get all variables alive at a statement.
* If the statement is inside a method this also includes all variables alive at the exit of the calls.
* <p>
* This method requires a number of other analysis to be present and updated in the (global) program - especailly the Call Graph.
* </p>
* @param statement The statement to examine
* @return All variables alive at the statement
*/
public Collection<VariableRef> getAliveEffective(Statement statement) {
// Get variables alive from live range analysis
Collection<VariableRef> effectiveAlive = new LinkedHashSet<>();
effectiveAlive.addAll(getAlive(statement));
// If the statement is inside a method recurse back to all calls
// For each call add the variables alive after the call that are not referenced (used/defined) inside the method
ControlFlowBlock block = program.getGraph().getBlockFromStatementIdx(statement.getIndex());
ScopeRef scopeRef = block.getScope();
Scope scope = program.getScope().getScope(scopeRef);
if (scope instanceof Procedure) {
Procedure procedure = (Procedure) scope;
Collection<CallGraph.CallBlock.Call> callers =
program.getCallGraph().getCallers(procedure.getLabel().getRef());
VariableReferenceInfo referenceInfo = new VariableReferenceInfo(program);
Collection<VariableRef> referencedInProcedure = referenceInfo.getReferenced(procedure.getRef().getLabelRef());
for (CallGraph.CallBlock.Call caller : callers) {
StatementCall callStatement =
(StatementCall) program.getGraph().getStatementByIndex(caller.getCallStatementIdx());
Set<VariableRef> callAliveEffective = new LinkedHashSet<>(getAliveEffective(callStatement));
// Clear out any variables referenced in the method
callAliveEffective.removeAll(referencedInProcedure);
effectiveAlive.addAll(callAliveEffective);
}
}
return effectiveAlive;
}
}

View File

@ -0,0 +1,31 @@
package dk.camelot64.kickc.icl;
import java.util.*;
/** Effective variable live ranges for all statements. (Including variables alive in calling methods)
* Created by {@link dk.camelot64.kickc.passes.Pass3CallGraphAnalysis}
*/
public class LiveRangeVariablesEffective {
/** Effectively alive variables by statement index. */
Map<Integer, Collection<VariableRef>> effectiveLiveVariables;
public LiveRangeVariablesEffective(Map<Integer, Collection<VariableRef>> effectiveLiveVariables) {
this.effectiveLiveVariables = effectiveLiveVariables;
}
/**
* Get all variables alive at a statement.
* If the statement is inside a method this also includes all variables alive at the exit of the calls.
* <p>
* This method requires a number of other analysis to be present and updated in the (global) program - especailly the Call Graph.
* </p>
* @param statement The statement to examine
* @return All variables alive at the statement
*/
public Collection<VariableRef> getAliveEffective(Statement statement) {
return effectiveLiveVariables.get(statement.getIndex());
}
}

View File

@ -32,6 +32,8 @@ public class Program {
private LiveRangeVariables liveRangeVariables;
/** Live range equivalence classes containing variables that do not have overlapping live ranges. */
private LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet;
/** The effective live ranges of all variables. */
private LiveRangeVariablesEffective liveRangeVariablesEffective;
/** The register weight of all variables describing how much the variable would theoretically gain from being in a register */
private VariableRegisterWeights variableRegisterWeights;
/** Registers potentially usable as allocation for each live range equivalence class. */
@ -118,6 +120,14 @@ public class Program {
return liveRangeVariables;
}
public LiveRangeVariablesEffective getLiveRangeVariablesEffective() {
return liveRangeVariablesEffective;
}
public void setLiveRangeVariablesEffective(LiveRangeVariablesEffective liveRangeVariablesEffective) {
this.liveRangeVariablesEffective = liveRangeVariablesEffective;
}
public void setLiveRangeEquivalenceClassSet(LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet) {
this.liveRangeEquivalenceClassSet = liveRangeEquivalenceClassSet;
}

View File

@ -0,0 +1,72 @@
package dk.camelot64.kickc.passes;
/**
* Find effective alive intervals for all variables in all statements. Add the intervals to the Program.
*/
import dk.camelot64.kickc.icl.*;
import java.util.*;
public class Pass3LiveRangesEffectiveAnalysis extends Pass2Base {
public Pass3LiveRangesEffectiveAnalysis(Program program) {
super(program);
}
public void findLiveRangesEffective() {
LiveRangeVariablesEffective aliveEffective = findAliveEffective(getProgram());
getProgram().setLiveRangeVariablesEffective(aliveEffective);
//getLog().append("Calculated effective variable live ranges");
}
private LiveRangeVariablesEffective findAliveEffective(Program program) {
LiveRangeVariables liveRangeVariables = program.getLiveRangeVariables();
Map<Integer, Collection<VariableRef>> effectiveLiveVariables = new HashMap<>();
for (ControlFlowBlock block : program.getGraph().getAllBlocks()) {
for (Statement statement : block.getStatements()) {
Collection<VariableRef> aliveEffective = findAliveEffective( liveRangeVariables, statement);
effectiveLiveVariables.put(statement.getIndex(), aliveEffective);
}
}
return new LiveRangeVariablesEffective(effectiveLiveVariables);
}
/**
* Get all variables alive at a statement.
* If the statement is inside a method this also includes all variables alive at the exit of the calls.
* <p>
* This method requires a number of other analysis to be present and updated in the (global) program - especailly the Call Graph.
* </p>
* @param statement The statement to examine
* @return All variables alive at the statement
*/
private Collection<VariableRef> findAliveEffective(LiveRangeVariables liveRangeVariables, Statement statement) {
// Get variables alive from live range analysis
Collection<VariableRef> effectiveAlive = new LinkedHashSet<>();
effectiveAlive.addAll(liveRangeVariables.getAlive(statement));
// If the statement is inside a method recurse back to all calls
// For each call add the variables alive after the call that are not referenced (used/defined) inside the method
ControlFlowBlock block = getProgram().getGraph().getBlockFromStatementIdx(statement.getIndex());
ScopeRef scopeRef = block.getScope();
Scope scope = getProgram().getScope().getScope(scopeRef);
if (scope instanceof Procedure) {
Procedure procedure = (Procedure) scope;
Collection<CallGraph.CallBlock.Call> callers =
getProgram().getCallGraph().getCallers(procedure.getLabel().getRef());
VariableReferenceInfo referenceInfo = new VariableReferenceInfo(getProgram());
Collection<VariableRef> referencedInProcedure = referenceInfo.getReferenced(procedure.getRef().getLabelRef());
for (CallGraph.CallBlock.Call caller : callers) {
StatementCall callStatement =
(StatementCall) getProgram().getGraph().getStatementByIndex(caller.getCallStatementIdx());
Set<VariableRef> callAliveEffective = new LinkedHashSet<>(findAliveEffective(liveRangeVariables, callStatement));
// Clear out any variables referenced in the method
callAliveEffective.removeAll(referencedInProcedure);
effectiveAlive.addAll(callAliveEffective);
}
}
return effectiveAlive;
}
}

View File

@ -64,7 +64,7 @@ public class Pass4AssertNoCpuClobber extends Pass2Base {
}
// Find alive variables
List<VariableRef> aliveVars = new ArrayList<>(getProgram().getLiveRangeVariables().getAliveEffective(statement));
List<VariableRef> aliveVars = new ArrayList<>(getProgram().getLiveRangeVariablesEffective().getAliveEffective(statement));
// Non-assigned alive variables must not be clobbered
for (VariableRef aliveVar : aliveVars) {
Variable variable = getProgram().getScope().getVariable(aliveVar);

View File

@ -220,7 +220,7 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
Statement statement,
LinkedHashMap<Registers.Register, LiveRangeEquivalenceClass> usedRegisters) {
ProgramScope programScope = program.getScope();
Collection<VariableRef> alive = program.getLiveRangeVariables().getAliveEffective(statement);
Collection<VariableRef> alive = program.getLiveRangeVariablesEffective().getAliveEffective(statement);
for (VariableRef varRef : alive) {
Variable var = programScope.getVariable(varRef);
Registers.Register allocation = var.getAllocation();

View File

@ -90,7 +90,7 @@ public class Pass4RegisterUpliftPotentialRegisterAnalysis extends Pass2Base {
}
// For all non-assigned live variables: remove always clobbered registers from their potential allocation
Collection<VariableRef> aliveVars = getProgram().getLiveRangeVariables().getAliveEffective(statement);
Collection<VariableRef> aliveVars = getProgram().getLiveRangeVariablesEffective().getAliveEffective(statement);
for (VariableRef aliveVar : aliveVars) {
LiveRangeEquivalenceClass aliveClass = liveRangeEquivalenceClassSet.getEquivalenceClass(aliveVar);
if (assignedClasses.contains(aliveClass)) {

View File

@ -56,8 +56,8 @@ public class TestCompilationOutput extends TestCase {
compileAndCompare("bresenhamarr");
}
public void testMinus() throws IOException, URISyntaxException {
compileAndCompare("minus");
public void testIterArray() throws IOException, URISyntaxException {
compileAndCompare("iterarray");
}
public void testLoopMin() throws IOException, URISyntaxException {

View File

@ -0,0 +1,10 @@
main();
void main() {
byte[16] buf = $1100;
byte i = 5;
do {
buf[i] = 2+i+2;
i = i+1;
} while(i<10)
}

View File

@ -1,6 +0,0 @@
byte[16] p = $1100;
byte i = 5;
do {
p[i] = 2+i+2;
i = i+1;
} while(i<10)

View File

@ -0,0 +1,14 @@
jsr main
main: {
.const buf = $1100
ldx #5
b1:
txa
clc
adc #2+2
sta buf,x
inx
cpx #$a
bcc b1
rts
}

View File

@ -0,0 +1,17 @@
@begin: scope:[] from
[0] call main param-assignment [ ]
to:@end
@end: scope:[] from @begin
main: scope:[main] from @begin
[1] phi() [ ]
to:main::@1
main::@1: scope:[main] from main main::@1
[2] (byte) main::i#2 ← phi( main/(byte) 5 main::@1/(byte) main::i#1 ) [ main::i#2 ]
[3] (byte~) main::$1 ← (byte) main::i#2 + (byte) 2+(byte) 2 [ main::i#2 main::$1 ]
[4] *((const byte[16]) main::buf#0 + (byte) main::i#2) ← (byte~) main::$1 [ main::i#2 ]
[5] (byte) main::i#1 ← (byte) main::i#2 + (byte) 1 [ main::i#1 ]
[6] if((byte) main::i#1<(byte) 10) goto main::@1 [ main::i#1 ]
to:main::@return
main::@return: scope:[main] from main::@1
[7] return [ ]
to:@return

View File

@ -0,0 +1,803 @@
main();
void main() {
byte[16] buf = $1100;
byte i = 5;
do {
buf[i] = 2+i+2;
i = i+1;
} while(i<10)
}
PROGRAM
(void~) $0 ← call main
proc (void()) main()
(byte[16]) main::buf ← (word) 4352
(byte) main::i ← (byte) 5
main::@1:
(byte~) main::$0 ← (byte) 2 + (byte) main::i
(byte~) main::$1 ← (byte~) main::$0 + (byte) 2
*((byte[16]) main::buf + (byte) main::i) ← (byte~) main::$1
(byte~) main::$2 ← (byte) main::i + (byte) 1
(byte) main::i ← (byte~) main::$2
(boolean~) main::$3 ← (byte) main::i < (byte) 10
if((boolean~) main::$3) goto main::@1
main::@return:
return
endproc // main()
SYMBOLS
(void~) $0
(void()) main()
(byte~) main::$0
(byte~) main::$1
(byte~) main::$2
(boolean~) main::$3
(label) main::@1
(label) main::@return
(byte[16]) main::buf
(byte) main::i
INITIAL CONTROL FLOW GRAPH
@begin: scope:[] from
(void~) $0 ← call main
to:@1
main: scope:[main] from
(byte[16]) main::buf ← (word) 4352
(byte) main::i ← (byte) 5
to:main::@1
main::@1: scope:[main] from main main::@1
(byte~) main::$0 ← (byte) 2 + (byte) main::i
(byte~) main::$1 ← (byte~) main::$0 + (byte) 2
*((byte[16]) main::buf + (byte) main::i) ← (byte~) main::$1
(byte~) main::$2 ← (byte) main::i + (byte) 1
(byte) main::i ← (byte~) main::$2
(boolean~) main::$3 ← (byte) main::i < (byte) 10
if((boolean~) main::$3) goto main::@1
to:main::@2
main::@2: scope:[main] from main::@1
to:main::@return
main::@return: scope:[main] from main::@2
return
to:@return
@1: scope:[] from @begin
to:@end
@end: scope:[] from @1
Removing empty block main::@2
Removing empty block @1
CONTROL FLOW GRAPH
@begin: scope:[] from
(void~) $0 ← call main
to:@end
main: scope:[main] from
(byte[16]) main::buf ← (word) 4352
(byte) main::i ← (byte) 5
to:main::@1
main::@1: scope:[main] from main main::@1
(byte~) main::$0 ← (byte) 2 + (byte) main::i
(byte~) main::$1 ← (byte~) main::$0 + (byte) 2
*((byte[16]) main::buf + (byte) main::i) ← (byte~) main::$1
(byte~) main::$2 ← (byte) main::i + (byte) 1
(byte) main::i ← (byte~) main::$2
(boolean~) main::$3 ← (byte) main::i < (byte) 10
if((boolean~) main::$3) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
@end: scope:[] from @begin
PROCEDURE MODIFY VARIABLE ANALYSIS
CONTROL FLOW GRAPH WITH ASSIGNMENT CALL
@begin: scope:[] from
call main param-assignment
to:@2
@2: scope:[] from @begin
to:@end
main: scope:[main] from @begin
(byte[16]) main::buf ← (word) 4352
(byte) main::i ← (byte) 5
to:main::@1
main::@1: scope:[main] from main main::@1
(byte~) main::$0 ← (byte) 2 + (byte) main::i
(byte~) main::$1 ← (byte~) main::$0 + (byte) 2
*((byte[16]) main::buf + (byte) main::i) ← (byte~) main::$1
(byte~) main::$2 ← (byte) main::i + (byte) 1
(byte) main::i ← (byte~) main::$2
(boolean~) main::$3 ← (byte) main::i < (byte) 10
if((boolean~) main::$3) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
@end: scope:[] from @2
Completing Phi functions...
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
call main param-assignment
to:@2
@2: scope:[] from @begin
to:@end
main: scope:[main] from @begin
(byte[16]) main::buf#0 ← (word) 4352
(byte) main::i#0 ← (byte) 5
to:main::@1
main::@1: scope:[main] from main main::@1
(byte[16]) main::buf#1 ← phi( main/(byte[16]) main::buf#0 main::@1/(byte[16]) main::buf#1 )
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 )
(byte~) main::$0 ← (byte) 2 + (byte) main::i#2
(byte~) main::$1 ← (byte~) main::$0 + (byte) 2
*((byte[16]) main::buf#1 + (byte) main::i#2) ← (byte~) main::$1
(byte~) main::$2 ← (byte) main::i#2 + (byte) 1
(byte) main::i#1 ← (byte~) main::$2
(boolean~) main::$3 ← (byte) main::i#1 < (byte) 10
if((boolean~) main::$3) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
@end: scope:[] from @2
CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN
@begin: scope:[] from
call main param-assignment
to:@2
@2: scope:[] from @begin
to:@end
main: scope:[main] from @begin
(byte[16]) main::buf#0 ← (word) 4352
(byte) main::i#0 ← (byte) 5
to:main::@1
main::@1: scope:[main] from main main::@1
(byte[16]) main::buf#1 ← phi( main/(byte[16]) main::buf#0 main::@1/(byte[16]) main::buf#1 )
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 )
(byte~) main::$0 ← (byte) 2 + (byte) main::i#2
(byte~) main::$1 ← (byte~) main::$0 + (byte) 2
*((byte[16]) main::buf#1 + (byte) main::i#2) ← (byte~) main::$1
(byte~) main::$2 ← (byte) main::i#2 + (byte) 1
(byte) main::i#1 ← (byte~) main::$2
(boolean~) main::$3 ← (byte) main::i#1 < (byte) 10
if((boolean~) main::$3) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
@end: scope:[] from @2
INITIAL SSA SYMBOL TABLE
(label) @2
(label) @begin
(label) @end
(void()) main()
(byte~) main::$0
(byte~) main::$1
(byte~) main::$2
(boolean~) main::$3
(label) main::@1
(label) main::@return
(byte[16]) main::buf
(byte[16]) main::buf#0
(byte[16]) main::buf#1
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
Culled Empty Block (label) @2
Succesful SSA optimization Pass2CullEmptyBlocks
CONTROL FLOW GRAPH
@begin: scope:[] from
call main param-assignment
to:@end
main: scope:[main] from @begin
(byte[16]) main::buf#0 ← (word) 4352
(byte) main::i#0 ← (byte) 5
to:main::@1
main::@1: scope:[main] from main main::@1
(byte[16]) main::buf#1 ← phi( main/(byte[16]) main::buf#0 main::@1/(byte[16]) main::buf#1 )
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 )
(byte~) main::$0 ← (byte) 2 + (byte) main::i#2
(byte~) main::$1 ← (byte~) main::$0 + (byte) 2
*((byte[16]) main::buf#1 + (byte) main::i#2) ← (byte~) main::$1
(byte~) main::$2 ← (byte) main::i#2 + (byte) 1
(byte) main::i#1 ← (byte~) main::$2
(boolean~) main::$3 ← (byte) main::i#1 < (byte) 10
if((boolean~) main::$3) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
@end: scope:[] from @begin
Alias (byte) main::i#1 = (byte~) main::$2
Succesful SSA optimization Pass2AliasElimination
CONTROL FLOW GRAPH
@begin: scope:[] from
call main param-assignment
to:@end
main: scope:[main] from @begin
(byte[16]) main::buf#0 ← (word) 4352
(byte) main::i#0 ← (byte) 5
to:main::@1
main::@1: scope:[main] from main main::@1
(byte[16]) main::buf#1 ← phi( main/(byte[16]) main::buf#0 main::@1/(byte[16]) main::buf#1 )
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 )
(byte~) main::$0 ← (byte) 2 + (byte) main::i#2
(byte~) main::$1 ← (byte~) main::$0 + (byte) 2
*((byte[16]) main::buf#1 + (byte) main::i#2) ← (byte~) main::$1
(byte) main::i#1 ← (byte) main::i#2 + (byte) 1
(boolean~) main::$3 ← (byte) main::i#1 < (byte) 10
if((boolean~) main::$3) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
@end: scope:[] from @begin
Self Phi Eliminated (byte[16]) main::buf#1
Succesful SSA optimization Pass2SelfPhiElimination
CONTROL FLOW GRAPH
@begin: scope:[] from
call main param-assignment
to:@end
main: scope:[main] from @begin
(byte[16]) main::buf#0 ← (word) 4352
(byte) main::i#0 ← (byte) 5
to:main::@1
main::@1: scope:[main] from main main::@1
(byte[16]) main::buf#1 ← phi( main/(byte[16]) main::buf#0 )
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 )
(byte~) main::$0 ← (byte) 2 + (byte) main::i#2
(byte~) main::$1 ← (byte~) main::$0 + (byte) 2
*((byte[16]) main::buf#1 + (byte) main::i#2) ← (byte~) main::$1
(byte) main::i#1 ← (byte) main::i#2 + (byte) 1
(boolean~) main::$3 ← (byte) main::i#1 < (byte) 10
if((boolean~) main::$3) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
@end: scope:[] from @begin
Simple Condition (boolean~) main::$3 if((byte) main::i#1<(byte) 10) goto main::@1
Succesful SSA optimization Pass2ConditionalJumpSimplification
CONTROL FLOW GRAPH
@begin: scope:[] from
call main param-assignment
to:@end
main: scope:[main] from @begin
(byte[16]) main::buf#0 ← (word) 4352
(byte) main::i#0 ← (byte) 5
to:main::@1
main::@1: scope:[main] from main main::@1
(byte[16]) main::buf#1 ← phi( main/(byte[16]) main::buf#0 )
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 )
(byte~) main::$0 ← (byte) 2 + (byte) main::i#2
(byte~) main::$1 ← (byte~) main::$0 + (byte) 2
*((byte[16]) main::buf#1 + (byte) main::i#2) ← (byte~) main::$1
(byte) main::i#1 ← (byte) main::i#2 + (byte) 1
if((byte) main::i#1<(byte) 10) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
@end: scope:[] from @begin
Constant (const byte[16]) main::buf#0 = 4352
Constant (const byte) main::i#0 = 5
Succesful SSA optimization Pass2ConstantIdentification
CONTROL FLOW GRAPH
@begin: scope:[] from
call main param-assignment
to:@end
main: scope:[main] from @begin
to:main::@1
main::@1: scope:[main] from main main::@1
(byte[16]) main::buf#1 ← phi( main/(const byte[16]) main::buf#0 )
(byte) main::i#2 ← phi( main/(const byte) main::i#0 main::@1/(byte) main::i#1 )
(byte~) main::$0 ← (byte) 2 + (byte) main::i#2
(byte~) main::$1 ← (byte~) main::$0 + (byte) 2
*((byte[16]) main::buf#1 + (byte) main::i#2) ← (byte~) main::$1
(byte) main::i#1 ← (byte) main::i#2 + (byte) 1
if((byte) main::i#1<(byte) 10) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
@end: scope:[] from @begin
Constant (const byte[16]) main::buf#1 = main::buf#0
Succesful SSA optimization Pass2ConstantIdentification
CONTROL FLOW GRAPH
@begin: scope:[] from
call main param-assignment
to:@end
main: scope:[main] from @begin
to:main::@1
main::@1: scope:[main] from main main::@1
(byte) main::i#2 ← phi( main/(const byte) main::i#0 main::@1/(byte) main::i#1 )
(byte~) main::$0 ← (byte) 2 + (byte) main::i#2
(byte~) main::$1 ← (byte~) main::$0 + (byte) 2
*((const byte[16]) main::buf#1 + (byte) main::i#2) ← (byte~) main::$1
(byte) main::i#1 ← (byte) main::i#2 + (byte) 1
if((byte) main::i#1<(byte) 10) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
@end: scope:[] from @begin
Multiple usages for variable. Not optimizing sub-constant (byte) main::i#2
Consolidated constant in assignment main::$1
Multiple usages for variable. Not optimizing sub-constant (byte) main::i#2
Multiple usages for variable. Not optimizing sub-constant (byte) main::i#2
Succesful SSA optimization Pass2ConstantAdditionElimination
CONTROL FLOW GRAPH
@begin: scope:[] from
call main param-assignment
to:@end
main: scope:[main] from @begin
to:main::@1
main::@1: scope:[main] from main main::@1
(byte) main::i#2 ← phi( main/(const byte) main::i#0 main::@1/(byte) main::i#1 )
(byte~) main::$0 ← (byte) main::i#2
(byte~) main::$1 ← (byte~) main::$0 + (byte) 2+(byte) 2
*((const byte[16]) main::buf#1 + (byte) main::i#2) ← (byte~) main::$1
(byte) main::i#1 ← (byte) main::i#2 + (byte) 1
if((byte) main::i#1<(byte) 10) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
@end: scope:[] from @begin
Multiple usages for variable. Not optimizing sub-constant (byte) main::i#2
Multiple usages for variable. Not optimizing sub-constant (byte) main::i#2
Alias (byte) main::i#2 = (byte~) main::$0
Succesful SSA optimization Pass2AliasElimination
CONTROL FLOW GRAPH
@begin: scope:[] from
call main param-assignment
to:@end
main: scope:[main] from @begin
to:main::@1
main::@1: scope:[main] from main main::@1
(byte) main::i#2 ← phi( main/(const byte) main::i#0 main::@1/(byte) main::i#1 )
(byte~) main::$1 ← (byte) main::i#2 + (byte) 2+(byte) 2
*((const byte[16]) main::buf#1 + (byte) main::i#2) ← (byte~) main::$1
(byte) main::i#1 ← (byte) main::i#2 + (byte) 1
if((byte) main::i#1<(byte) 10) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
@end: scope:[] from @begin
Multiple usages for variable. Not optimizing sub-constant (byte) main::i#2
Multiple usages for variable. Not optimizing sub-constant (byte) main::i#2
Multiple usages for variable. Not optimizing sub-constant (byte) main::i#2
Multiple usages for variable. Not optimizing sub-constant (byte) main::i#2
Multiple usages for variable. Not optimizing sub-constant (byte) main::i#2
Multiple usages for variable. Not optimizing sub-constant (byte) main::i#2
Constant inlined main::buf#1 = (const byte[16]) main::buf#0
Constant inlined main::i#0 = (byte) 5
Succesful SSA optimization Pass2ConstantInlining
CONTROL FLOW GRAPH
@begin: scope:[] from
call main param-assignment
to:@end
main: scope:[main] from @begin
to:main::@1
main::@1: scope:[main] from main main::@1
(byte) main::i#2 ← phi( main/(byte) 5 main::@1/(byte) main::i#1 )
(byte~) main::$1 ← (byte) main::i#2 + (byte) 2+(byte) 2
*((const byte[16]) main::buf#0 + (byte) main::i#2) ← (byte~) main::$1
(byte) main::i#1 ← (byte) main::i#2 + (byte) 1
if((byte) main::i#1<(byte) 10) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
@end: scope:[] from @begin
FINAL SYMBOL TABLE
(label) @begin
(label) @end
(void()) main()
(byte~) main::$1
(label) main::@1
(label) main::@return
(byte[16]) main::buf
(const byte[16]) main::buf#0 = (word) 4352
(byte) main::i
(byte) main::i#1
(byte) main::i#2
Block Sequence Planned @begin @end main main::@1 main::@return
Added new block during phi lifting main::@3(between main::@1 and main::@1)
Block Sequence Planned @begin @end main main::@1 main::@return main::@3
CONTROL FLOW GRAPH - PHI LIFTED
@begin: scope:[] from
call main param-assignment
to:@end
@end: scope:[] from @begin
main: scope:[main] from @begin
to:main::@1
main::@1: scope:[main] from main main::@3
(byte) main::i#2 ← phi( main/(byte) 5 main::@3/(byte~) main::i#3 )
(byte~) main::$1 ← (byte) main::i#2 + (byte) 2+(byte) 2
*((const byte[16]) main::buf#0 + (byte) main::i#2) ← (byte~) main::$1
(byte) main::i#1 ← (byte) main::i#2 + (byte) 1
if((byte) main::i#1<(byte) 10) goto main::@3
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
main::@3: scope:[main] from main::@1
(byte~) main::i#3 ← (byte) main::i#1
to:main::@1
Adding NOP phi() at start of main
CALL GRAPH
Calls in [] to 0:main
Propagating live ranges...
Propagating live ranges...
CONTROL FLOW GRAPH - LIVE RANGES FOUND
@begin: scope:[] from
[0] call main param-assignment [ ]
to:@end
@end: scope:[] from @begin
main: scope:[main] from @begin
[1] phi() [ ]
to:main::@1
main::@1: scope:[main] from main main::@3
[2] (byte) main::i#2 ← phi( main/(byte) 5 main::@3/(byte~) main::i#3 ) [ main::i#2 ]
[3] (byte~) main::$1 ← (byte) main::i#2 + (byte) 2+(byte) 2 [ main::i#2 main::$1 ]
[4] *((const byte[16]) main::buf#0 + (byte) main::i#2) ← (byte~) main::$1 [ main::i#2 ]
[5] (byte) main::i#1 ← (byte) main::i#2 + (byte) 1 [ main::i#1 ]
[6] if((byte) main::i#1<(byte) 10) goto main::@3 [ main::i#1 ]
to:main::@return
main::@return: scope:[main] from main::@1
[7] return [ ]
to:@return
main::@3: scope:[main] from main::@1
[8] (byte~) main::i#3 ← (byte) main::i#1 [ main::i#3 ]
to:main::@1
Created 1 initial phi equivalence classes
Coalesced [8] main::i#3 ← main::i#1
Coalesced down to 1 phi equivalence classes
Culled Empty Block (label) main::@3
Block Sequence Planned @begin @end main main::@1 main::@return
Adding NOP phi() at start of main
Propagating live ranges...
Propagating live ranges...
CONTROL FLOW GRAPH - PHI MEM COALESCED
@begin: scope:[] from
[0] call main param-assignment [ ]
to:@end
@end: scope:[] from @begin
main: scope:[main] from @begin
[1] phi() [ ]
to:main::@1
main::@1: scope:[main] from main main::@1
[2] (byte) main::i#2 ← phi( main/(byte) 5 main::@1/(byte) main::i#1 ) [ main::i#2 ]
[3] (byte~) main::$1 ← (byte) main::i#2 + (byte) 2+(byte) 2 [ main::i#2 main::$1 ]
[4] *((const byte[16]) main::buf#0 + (byte) main::i#2) ← (byte~) main::$1 [ main::i#2 ]
[5] (byte) main::i#1 ← (byte) main::i#2 + (byte) 1 [ main::i#1 ]
[6] if((byte) main::i#1<(byte) 10) goto main::@1 [ main::i#1 ]
to:main::@return
main::@return: scope:[main] from main::@1
[7] return [ ]
to:@return
DOMINATORS
@begin dominated by @begin
@end dominated by @end @begin
main dominated by @begin main
main::@1 dominated by @begin main::@1 main
main::@return dominated by main::@return @begin main::@1 main
Found back edge: Loop head: main::@1 tails: main::@1 blocks: null
Populated: Loop head: main::@1 tails: main::@1 blocks: main::@1
NATURAL LOOPS
Loop head: main::@1 tails: main::@1 blocks: main::@1
Found 0 loops in scope []
Found 1 loops in scope [main]
Loop head: main::@1 tails: main::@1 blocks: main::@1
NATURAL LOOPS WITH DEPTH
Loop head: main::@1 tails: main::@1 blocks: main::@1 depth: 1
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte~) main::$1 22.0
(byte[16]) main::buf
(byte) main::i
(byte) main::i#1 16.5
(byte) main::i#2 14.666666666666666
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Added variable main::$1 to zero page equivalence class [ main::$1 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::$1 ]
Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Allocated zp ZP_BYTE:3 [ main::$1 ]
INITIAL ASM
//SEG0 Global Constants & labels
//SEG1 @begin
bbegin:
//SEG2 [0] call main param-assignment [ ]
//SEG3 [1] phi from @begin to main
main_from_bbegin:
jsr main
jmp bend
//SEG4 @end
bend:
//SEG5 main
main: {
.const buf = $1100
.label _1 = 3
.label i = 2
//SEG6 [2] phi from main to main::@1
b1_from_main:
//SEG7 [2] phi (byte) main::i#2 = (byte) 5 -- zpby1=coby1
lda #5
sta i
jmp b1
//SEG8 [2] phi from main::@1 to main::@1
b1_from_b1:
//SEG9 [2] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy
jmp b1
//SEG10 main::@1
b1:
//SEG11 [3] (byte~) main::$1 ← (byte) main::i#2 + (byte) 2+(byte) 2 [ main::i#2 main::$1 ] -- zpby1=zpby2_plus_coby1
lda i
clc
adc #2+2
sta _1
//SEG12 [4] *((const byte[16]) main::buf#0 + (byte) main::i#2) ← (byte~) main::$1 [ main::i#2 ] -- cowo1_staridx_zpby1=zpby2
lda _1
ldx i
sta buf,x
//SEG13 [5] (byte) main::i#1 ← (byte) main::i#2 + (byte) 1 [ main::i#1 ] -- zpby1=zpby1_plus_1
inc i
//SEG14 [6] if((byte) main::i#1<(byte) 10) goto main::@1 [ main::i#1 ] -- zpby1_lt_coby1_then_la1
lda i
cmp #$a
bcc b1_from_b1
jmp breturn
//SEG15 main::@return
breturn:
//SEG16 [7] return [ ]
rts
}
Statement [3] (byte~) main::$1 ← (byte) main::i#2 + (byte) 2+(byte) 2 [ main::i#2 main::$1 ] always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Statement [3] (byte~) main::$1 ← (byte) main::i#2 + (byte) 2+(byte) 2 [ main::i#2 main::$1 ] always clobbers reg byte a
REGISTER UPLIFT POTENTIAL REGISTERS
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:3 [ main::$1 ] : zp ZP_BYTE:3 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 31.17: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:3 [ main::$1 ]
Uplift Scope []
Uplifting [main] best 300 combination reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$1 ]
Uplifting [] best 300 combination
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
ASSEMBLER
//SEG0 Global Constants & labels
//SEG1 @begin
bbegin:
//SEG2 [0] call main param-assignment [ ]
//SEG3 [1] phi from @begin to main
main_from_bbegin:
jsr main
//SEG4 @end
bend:
//SEG5 main
main: {
.const buf = $1100
//SEG6 [2] phi from main to main::@1
b1_from_main:
//SEG7 [2] phi (byte) main::i#2 = (byte) 5 -- xby=coby1
ldx #5
jmp b1
//SEG8 [2] phi from main::@1 to main::@1
b1_from_b1:
//SEG9 [2] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy
//SEG10 main::@1
b1:
//SEG11 [3] (byte~) main::$1 ← (byte) main::i#2 + (byte) 2+(byte) 2 [ main::i#2 main::$1 ] -- aby=xby_plus_coby1
txa
clc
adc #2+2
//SEG12 [4] *((const byte[16]) main::buf#0 + (byte) main::i#2) ← (byte~) main::$1 [ main::i#2 ] -- cowo1_staridx_xby=aby
sta buf,x
//SEG13 [5] (byte) main::i#1 ← (byte) main::i#2 + (byte) 1 [ main::i#1 ] -- xby=xby_plus_1
inx
//SEG14 [6] if((byte) main::i#1<(byte) 10) goto main::@1 [ main::i#1 ] -- xby_lt_coby1_then_la1
cpx #$a
bcc b1_from_b1
//SEG15 main::@return
breturn:
//SEG16 [7] return [ ]
rts
}
Replacing label b1_from_b1 with b1
Removing instruction main_from_bbegin:
Removing instruction b1_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
ASSEMBLER
//SEG0 Global Constants & labels
//SEG1 @begin
bbegin:
//SEG2 [0] call main param-assignment [ ]
//SEG3 [1] phi from @begin to main
jsr main
//SEG4 @end
bend:
//SEG5 main
main: {
.const buf = $1100
//SEG6 [2] phi from main to main::@1
b1_from_main:
//SEG7 [2] phi (byte) main::i#2 = (byte) 5 -- xby=coby1
ldx #5
jmp b1
//SEG8 [2] phi from main::@1 to main::@1
//SEG9 [2] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy
//SEG10 main::@1
b1:
//SEG11 [3] (byte~) main::$1 ← (byte) main::i#2 + (byte) 2+(byte) 2 [ main::i#2 main::$1 ] -- aby=xby_plus_coby1
txa
clc
adc #2+2
//SEG12 [4] *((const byte[16]) main::buf#0 + (byte) main::i#2) ← (byte~) main::$1 [ main::i#2 ] -- cowo1_staridx_xby=aby
sta buf,x
//SEG13 [5] (byte) main::i#1 ← (byte) main::i#2 + (byte) 1 [ main::i#1 ] -- xby=xby_plus_1
inx
//SEG14 [6] if((byte) main::i#1<(byte) 10) goto main::@1 [ main::i#1 ] -- xby_lt_coby1_then_la1
cpx #$a
bcc b1
//SEG15 main::@return
breturn:
//SEG16 [7] return [ ]
rts
}
Removing instruction bbegin:
Removing instruction bend:
Removing instruction b1_from_main:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
ASSEMBLER
//SEG0 Global Constants & labels
//SEG1 @begin
//SEG2 [0] call main param-assignment [ ]
//SEG3 [1] phi from @begin to main
jsr main
//SEG4 @end
//SEG5 main
main: {
.const buf = $1100
//SEG6 [2] phi from main to main::@1
//SEG7 [2] phi (byte) main::i#2 = (byte) 5 -- xby=coby1
ldx #5
jmp b1
//SEG8 [2] phi from main::@1 to main::@1
//SEG9 [2] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy
//SEG10 main::@1
b1:
//SEG11 [3] (byte~) main::$1 ← (byte) main::i#2 + (byte) 2+(byte) 2 [ main::i#2 main::$1 ] -- aby=xby_plus_coby1
txa
clc
adc #2+2
//SEG12 [4] *((const byte[16]) main::buf#0 + (byte) main::i#2) ← (byte~) main::$1 [ main::i#2 ] -- cowo1_staridx_xby=aby
sta buf,x
//SEG13 [5] (byte) main::i#1 ← (byte) main::i#2 + (byte) 1 [ main::i#1 ] -- xby=xby_plus_1
inx
//SEG14 [6] if((byte) main::i#1<(byte) 10) goto main::@1 [ main::i#1 ] -- xby_lt_coby1_then_la1
cpx #$a
bcc b1
//SEG15 main::@return
//SEG16 [7] return [ ]
rts
}
Removing instruction jmp b1
Succesful ASM optimization Pass5NextJumpElimination
ASSEMBLER
//SEG0 Global Constants & labels
//SEG1 @begin
//SEG2 [0] call main param-assignment [ ]
//SEG3 [1] phi from @begin to main
jsr main
//SEG4 @end
//SEG5 main
main: {
.const buf = $1100
//SEG6 [2] phi from main to main::@1
//SEG7 [2] phi (byte) main::i#2 = (byte) 5 -- xby=coby1
ldx #5
//SEG8 [2] phi from main::@1 to main::@1
//SEG9 [2] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy
//SEG10 main::@1
b1:
//SEG11 [3] (byte~) main::$1 ← (byte) main::i#2 + (byte) 2+(byte) 2 [ main::i#2 main::$1 ] -- aby=xby_plus_coby1
txa
clc
adc #2+2
//SEG12 [4] *((const byte[16]) main::buf#0 + (byte) main::i#2) ← (byte~) main::$1 [ main::i#2 ] -- cowo1_staridx_xby=aby
sta buf,x
//SEG13 [5] (byte) main::i#1 ← (byte) main::i#2 + (byte) 1 [ main::i#1 ] -- xby=xby_plus_1
inx
//SEG14 [6] if((byte) main::i#1<(byte) 10) goto main::@1 [ main::i#1 ] -- xby_lt_coby1_then_la1
cpx #$a
bcc b1
//SEG15 main::@return
//SEG16 [7] return [ ]
rts
}
FINAL SYMBOL TABLE
(label) @begin
(label) @end
(void()) main()
(byte~) main::$1 reg byte a 22.0
(label) main::@1
(label) main::@return
(byte[16]) main::buf
(const byte[16]) main::buf#0 = (word) 4352
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#2 reg byte x 14.666666666666666
reg byte x [ main::i#2 main::i#1 ]
reg byte a [ main::$1 ]
FINAL CODE
//SEG0 Global Constants & labels
//SEG1 @begin
//SEG2 [0] call main param-assignment [ ]
//SEG3 [1] phi from @begin to main
jsr main
//SEG4 @end
//SEG5 main
main: {
.const buf = $1100
//SEG6 [2] phi from main to main::@1
//SEG7 [2] phi (byte) main::i#2 = (byte) 5 -- xby=coby1
ldx #5
//SEG8 [2] phi from main::@1 to main::@1
//SEG9 [2] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy
//SEG10 main::@1
b1:
//SEG11 [3] (byte~) main::$1 ← (byte) main::i#2 + (byte) 2+(byte) 2 [ main::i#2 main::$1 ] -- aby=xby_plus_coby1
txa
clc
adc #2+2
//SEG12 [4] *((const byte[16]) main::buf#0 + (byte) main::i#2) ← (byte~) main::$1 [ main::i#2 ] -- cowo1_staridx_xby=aby
sta buf,x
//SEG13 [5] (byte) main::i#1 ← (byte) main::i#2 + (byte) 1 [ main::i#1 ] -- xby=xby_plus_1
inx
//SEG14 [6] if((byte) main::i#1<(byte) 10) goto main::@1 [ main::i#1 ] -- xby_lt_coby1_then_la1
cpx #$a
bcc b1
//SEG15 main::@return
//SEG16 [7] return [ ]
rts
}

View File

@ -0,0 +1,14 @@
(label) @begin
(label) @end
(void()) main()
(byte~) main::$1 reg byte a 22.0
(label) main::@1
(label) main::@return
(byte[16]) main::buf
(const byte[16]) main::buf#0 = (word) 4352
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#2 reg byte x 14.666666666666666
reg byte x [ main::i#2 main::i#1 ]
reg byte a [ main::$1 ]

View File

@ -1,10 +0,0 @@
.const p = $1100
ldx #5
b1:
txa
clc
adc #2+2
sta p,x
inx
cpx #$a
bcc b1

View File

@ -1,10 +0,0 @@
@begin: scope:[] from
to:@1
@1: scope:[] from @1 @begin
[0] (byte) i#2 ← phi( @1/(byte) i#1 @begin/(byte) 5 ) [ i#2 ]
[1] (byte~) $1 ← (byte) i#2 + (byte) 2+(byte) 2 [ i#2 $1 ]
[2] *((const byte[16]) p#0 + (byte) i#2) ← (byte~) $1 [ i#2 ]
[3] (byte) i#1 ← (byte) i#2 + (byte) 1 [ i#1 ]
[4] if((byte) i#1<(byte) 10) goto @1 [ i#1 ]
to:@end
@end: scope:[] from @1

View File

@ -1,579 +0,0 @@
byte[16] p = $1100;
byte i = 5;
do {
p[i] = 2+i+2;
i = i+1;
} while(i<10)
PROGRAM
(byte[16]) p ← (word) 4352
(byte) i ← (byte) 5
@1:
(byte~) $0 ← (byte) 2 + (byte) i
(byte~) $1 ← (byte~) $0 + (byte) 2
*((byte[16]) p + (byte) i) ← (byte~) $1
(byte~) $2 ← (byte) i + (byte) 1
(byte) i ← (byte~) $2
(boolean~) $3 ← (byte) i < (byte) 10
if((boolean~) $3) goto @1
SYMBOLS
(byte~) $0
(byte~) $1
(byte~) $2
(boolean~) $3
(label) @1
(byte) i
(byte[16]) p
INITIAL CONTROL FLOW GRAPH
@begin: scope:[] from
(byte[16]) p ← (word) 4352
(byte) i ← (byte) 5
to:@1
@1: scope:[] from @1 @begin
(byte~) $0 ← (byte) 2 + (byte) i
(byte~) $1 ← (byte~) $0 + (byte) 2
*((byte[16]) p + (byte) i) ← (byte~) $1
(byte~) $2 ← (byte) i + (byte) 1
(byte) i ← (byte~) $2
(boolean~) $3 ← (byte) i < (byte) 10
if((boolean~) $3) goto @1
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
Removing empty block @2
CONTROL FLOW GRAPH
@begin: scope:[] from
(byte[16]) p ← (word) 4352
(byte) i ← (byte) 5
to:@1
@1: scope:[] from @1 @begin
(byte~) $0 ← (byte) 2 + (byte) i
(byte~) $1 ← (byte~) $0 + (byte) 2
*((byte[16]) p + (byte) i) ← (byte~) $1
(byte~) $2 ← (byte) i + (byte) 1
(byte) i ← (byte~) $2
(boolean~) $3 ← (byte) i < (byte) 10
if((boolean~) $3) goto @1
to:@end
@end: scope:[] from @1
PROCEDURE MODIFY VARIABLE ANALYSIS
CONTROL FLOW GRAPH WITH ASSIGNMENT CALL
@begin: scope:[] from
(byte[16]) p ← (word) 4352
(byte) i ← (byte) 5
to:@1
@1: scope:[] from @1 @begin
(byte~) $0 ← (byte) 2 + (byte) i
(byte~) $1 ← (byte~) $0 + (byte) 2
*((byte[16]) p + (byte) i) ← (byte~) $1
(byte~) $2 ← (byte) i + (byte) 1
(byte) i ← (byte~) $2
(boolean~) $3 ← (byte) i < (byte) 10
if((boolean~) $3) goto @1
to:@end
@end: scope:[] from @1
Completing Phi functions...
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte[16]) p#0 ← (word) 4352
(byte) i#0 ← (byte) 5
to:@1
@1: scope:[] from @1 @begin
(byte[16]) p#1 ← phi( @1/(byte[16]) p#1 @begin/(byte[16]) p#0 )
(byte) i#2 ← phi( @1/(byte) i#1 @begin/(byte) i#0 )
(byte~) $0 ← (byte) 2 + (byte) i#2
(byte~) $1 ← (byte~) $0 + (byte) 2
*((byte[16]) p#1 + (byte) i#2) ← (byte~) $1
(byte~) $2 ← (byte) i#2 + (byte) 1
(byte) i#1 ← (byte~) $2
(boolean~) $3 ← (byte) i#1 < (byte) 10
if((boolean~) $3) goto @1
to:@end
@end: scope:[] from @1
CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN
@begin: scope:[] from
(byte[16]) p#0 ← (word) 4352
(byte) i#0 ← (byte) 5
to:@1
@1: scope:[] from @1 @begin
(byte[16]) p#1 ← phi( @1/(byte[16]) p#1 @begin/(byte[16]) p#0 )
(byte) i#2 ← phi( @1/(byte) i#1 @begin/(byte) i#0 )
(byte~) $0 ← (byte) 2 + (byte) i#2
(byte~) $1 ← (byte~) $0 + (byte) 2
*((byte[16]) p#1 + (byte) i#2) ← (byte~) $1
(byte~) $2 ← (byte) i#2 + (byte) 1
(byte) i#1 ← (byte~) $2
(boolean~) $3 ← (byte) i#1 < (byte) 10
if((boolean~) $3) goto @1
to:@end
@end: scope:[] from @1
INITIAL SSA SYMBOL TABLE
(byte~) $0
(byte~) $1
(byte~) $2
(boolean~) $3
(label) @1
(label) @begin
(label) @end
(byte) i
(byte) i#0
(byte) i#1
(byte) i#2
(byte[16]) p
(byte[16]) p#0
(byte[16]) p#1
Alias (byte) i#1 = (byte~) $2
Succesful SSA optimization Pass2AliasElimination
CONTROL FLOW GRAPH
@begin: scope:[] from
(byte[16]) p#0 ← (word) 4352
(byte) i#0 ← (byte) 5
to:@1
@1: scope:[] from @1 @begin
(byte[16]) p#1 ← phi( @1/(byte[16]) p#1 @begin/(byte[16]) p#0 )
(byte) i#2 ← phi( @1/(byte) i#1 @begin/(byte) i#0 )
(byte~) $0 ← (byte) 2 + (byte) i#2
(byte~) $1 ← (byte~) $0 + (byte) 2
*((byte[16]) p#1 + (byte) i#2) ← (byte~) $1
(byte) i#1 ← (byte) i#2 + (byte) 1
(boolean~) $3 ← (byte) i#1 < (byte) 10
if((boolean~) $3) goto @1
to:@end
@end: scope:[] from @1
Self Phi Eliminated (byte[16]) p#1
Succesful SSA optimization Pass2SelfPhiElimination
CONTROL FLOW GRAPH
@begin: scope:[] from
(byte[16]) p#0 ← (word) 4352
(byte) i#0 ← (byte) 5
to:@1
@1: scope:[] from @1 @begin
(byte[16]) p#1 ← phi( @begin/(byte[16]) p#0 )
(byte) i#2 ← phi( @1/(byte) i#1 @begin/(byte) i#0 )
(byte~) $0 ← (byte) 2 + (byte) i#2
(byte~) $1 ← (byte~) $0 + (byte) 2
*((byte[16]) p#1 + (byte) i#2) ← (byte~) $1
(byte) i#1 ← (byte) i#2 + (byte) 1
(boolean~) $3 ← (byte) i#1 < (byte) 10
if((boolean~) $3) goto @1
to:@end
@end: scope:[] from @1
Simple Condition (boolean~) $3 if((byte) i#1<(byte) 10) goto @1
Succesful SSA optimization Pass2ConditionalJumpSimplification
CONTROL FLOW GRAPH
@begin: scope:[] from
(byte[16]) p#0 ← (word) 4352
(byte) i#0 ← (byte) 5
to:@1
@1: scope:[] from @1 @begin
(byte[16]) p#1 ← phi( @begin/(byte[16]) p#0 )
(byte) i#2 ← phi( @1/(byte) i#1 @begin/(byte) i#0 )
(byte~) $0 ← (byte) 2 + (byte) i#2
(byte~) $1 ← (byte~) $0 + (byte) 2
*((byte[16]) p#1 + (byte) i#2) ← (byte~) $1
(byte) i#1 ← (byte) i#2 + (byte) 1
if((byte) i#1<(byte) 10) goto @1
to:@end
@end: scope:[] from @1
Constant (const byte[16]) p#0 = 4352
Constant (const byte) i#0 = 5
Succesful SSA optimization Pass2ConstantIdentification
CONTROL FLOW GRAPH
@begin: scope:[] from
to:@1
@1: scope:[] from @1 @begin
(byte[16]) p#1 ← phi( @begin/(const byte[16]) p#0 )
(byte) i#2 ← phi( @1/(byte) i#1 @begin/(const byte) i#0 )
(byte~) $0 ← (byte) 2 + (byte) i#2
(byte~) $1 ← (byte~) $0 + (byte) 2
*((byte[16]) p#1 + (byte) i#2) ← (byte~) $1
(byte) i#1 ← (byte) i#2 + (byte) 1
if((byte) i#1<(byte) 10) goto @1
to:@end
@end: scope:[] from @1
Constant (const byte[16]) p#1 = p#0
Succesful SSA optimization Pass2ConstantIdentification
CONTROL FLOW GRAPH
@begin: scope:[] from
to:@1
@1: scope:[] from @1 @begin
(byte) i#2 ← phi( @1/(byte) i#1 @begin/(const byte) i#0 )
(byte~) $0 ← (byte) 2 + (byte) i#2
(byte~) $1 ← (byte~) $0 + (byte) 2
*((const byte[16]) p#1 + (byte) i#2) ← (byte~) $1
(byte) i#1 ← (byte) i#2 + (byte) 1
if((byte) i#1<(byte) 10) goto @1
to:@end
@end: scope:[] from @1
Multiple usages for variable. Not optimizing sub-constant (byte) i#2
Consolidated constant in assignment $1
Multiple usages for variable. Not optimizing sub-constant (byte) i#2
Multiple usages for variable. Not optimizing sub-constant (byte) i#2
Succesful SSA optimization Pass2ConstantAdditionElimination
CONTROL FLOW GRAPH
@begin: scope:[] from
to:@1
@1: scope:[] from @1 @begin
(byte) i#2 ← phi( @1/(byte) i#1 @begin/(const byte) i#0 )
(byte~) $0 ← (byte) i#2
(byte~) $1 ← (byte~) $0 + (byte) 2+(byte) 2
*((const byte[16]) p#1 + (byte) i#2) ← (byte~) $1
(byte) i#1 ← (byte) i#2 + (byte) 1
if((byte) i#1<(byte) 10) goto @1
to:@end
@end: scope:[] from @1
Multiple usages for variable. Not optimizing sub-constant (byte) i#2
Multiple usages for variable. Not optimizing sub-constant (byte) i#2
Alias (byte) i#2 = (byte~) $0
Succesful SSA optimization Pass2AliasElimination
CONTROL FLOW GRAPH
@begin: scope:[] from
to:@1
@1: scope:[] from @1 @begin
(byte) i#2 ← phi( @1/(byte) i#1 @begin/(const byte) i#0 )
(byte~) $1 ← (byte) i#2 + (byte) 2+(byte) 2
*((const byte[16]) p#1 + (byte) i#2) ← (byte~) $1
(byte) i#1 ← (byte) i#2 + (byte) 1
if((byte) i#1<(byte) 10) goto @1
to:@end
@end: scope:[] from @1
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
Multiple usages for variable. Not optimizing sub-constant (byte) i#2
Multiple usages for variable. Not optimizing sub-constant (byte) i#2
Constant inlined p#1 = (const byte[16]) p#0
Constant inlined i#0 = (byte) 5
Succesful SSA optimization Pass2ConstantInlining
CONTROL FLOW GRAPH
@begin: scope:[] from
to:@1
@1: scope:[] from @1 @begin
(byte) i#2 ← phi( @1/(byte) i#1 @begin/(byte) 5 )
(byte~) $1 ← (byte) i#2 + (byte) 2+(byte) 2
*((const byte[16]) p#0 + (byte) i#2) ← (byte~) $1
(byte) i#1 ← (byte) i#2 + (byte) 1
if((byte) i#1<(byte) 10) goto @1
to:@end
@end: scope:[] from @1
FINAL SYMBOL TABLE
(byte~) $1
(label) @1
(label) @begin
(label) @end
(byte) i
(byte) i#1
(byte) i#2
(byte[16]) p
(const byte[16]) p#0 = (word) 4352
Block Sequence Planned @begin @1 @end
Added new block during phi lifting @3(between @1 and @1)
Block Sequence Planned @begin @1 @end @3
CONTROL FLOW GRAPH - PHI LIFTED
@begin: scope:[] from
to:@1
@1: scope:[] from @3 @begin
(byte) i#2 ← phi( @3/(byte~) i#3 @begin/(byte) 5 )
(byte~) $1 ← (byte) i#2 + (byte) 2+(byte) 2
*((const byte[16]) p#0 + (byte) i#2) ← (byte~) $1
(byte) i#1 ← (byte) i#2 + (byte) 1
if((byte) i#1<(byte) 10) goto @3
to:@end
@end: scope:[] from @1
@3: scope:[] from @1
(byte~) i#3 ← (byte) i#1
to:@1
CALL GRAPH
Propagating live ranges...
Propagating live ranges...
CONTROL FLOW GRAPH - LIVE RANGES FOUND
@begin: scope:[] from
to:@1
@1: scope:[] from @3 @begin
[0] (byte) i#2 ← phi( @3/(byte~) i#3 @begin/(byte) 5 ) [ i#2 ]
[1] (byte~) $1 ← (byte) i#2 + (byte) 2+(byte) 2 [ i#2 $1 ]
[2] *((const byte[16]) p#0 + (byte) i#2) ← (byte~) $1 [ i#2 ]
[3] (byte) i#1 ← (byte) i#2 + (byte) 1 [ i#1 ]
[4] if((byte) i#1<(byte) 10) goto @3 [ i#1 ]
to:@end
@end: scope:[] from @1
@3: scope:[] from @1
[5] (byte~) i#3 ← (byte) i#1 [ i#3 ]
to:@1
Created 1 initial phi equivalence classes
Coalesced [5] i#3 ← i#1
Coalesced down to 1 phi equivalence classes
Culled Empty Block (label) @3
Block Sequence Planned @begin @1 @end
Propagating live ranges...
Propagating live ranges...
CONTROL FLOW GRAPH - PHI MEM COALESCED
@begin: scope:[] from
to:@1
@1: scope:[] from @1 @begin
[0] (byte) i#2 ← phi( @1/(byte) i#1 @begin/(byte) 5 ) [ i#2 ]
[1] (byte~) $1 ← (byte) i#2 + (byte) 2+(byte) 2 [ i#2 $1 ]
[2] *((const byte[16]) p#0 + (byte) i#2) ← (byte~) $1 [ i#2 ]
[3] (byte) i#1 ← (byte) i#2 + (byte) 1 [ i#1 ]
[4] if((byte) i#1<(byte) 10) goto @1 [ i#1 ]
to:@end
@end: scope:[] from @1
DOMINATORS
@begin dominated by @begin
@1 dominated by @1 @begin
@end dominated by @1 @end @begin
Found back edge: Loop head: @1 tails: @1 blocks: null
Populated: Loop head: @1 tails: @1 blocks: @1
NATURAL LOOPS
Loop head: @1 tails: @1 blocks: @1
Found 1 loops in scope []
Loop head: @1 tails: @1 blocks: @1
NATURAL LOOPS WITH DEPTH
Loop head: @1 tails: @1 blocks: @1 depth: 1
VARIABLE REGISTER WEIGHTS
(byte~) $1 22.0
(byte) i
(byte) i#1 16.5
(byte) i#2 14.666666666666666
(byte[16]) p
Initial phi equivalence classes
[ i#2 i#1 ]
Added variable $1 to zero page equivalence class [ $1 ]
Complete equivalence classes
[ i#2 i#1 ]
[ $1 ]
Allocated zp ZP_BYTE:2 [ i#2 i#1 ]
Allocated zp ZP_BYTE:3 [ $1 ]
INITIAL ASM
//SEG0 Global Constants & labels
.const p = $1100
.label _1 = 3
.label i = 2
//SEG1 @begin
bbegin:
//SEG2 [0] phi from @begin to @1
b1_from_bbegin:
//SEG3 [0] phi (byte) i#2 = (byte) 5 -- zpby1=coby1
lda #5
sta i
jmp b1
//SEG4 [0] phi from @1 to @1
b1_from_b1:
//SEG5 [0] phi (byte) i#2 = (byte) i#1 -- register_copy
jmp b1
//SEG6 @1
b1:
//SEG7 [1] (byte~) $1 ← (byte) i#2 + (byte) 2+(byte) 2 [ i#2 $1 ] -- zpby1=zpby2_plus_coby1
lda i
clc
adc #2+2
sta _1
//SEG8 [2] *((const byte[16]) p#0 + (byte) i#2) ← (byte~) $1 [ i#2 ] -- cowo1_staridx_zpby1=zpby2
lda _1
ldx i
sta p,x
//SEG9 [3] (byte) i#1 ← (byte) i#2 + (byte) 1 [ i#1 ] -- zpby1=zpby1_plus_1
inc i
//SEG10 [4] if((byte) i#1<(byte) 10) goto @1 [ i#1 ] -- zpby1_lt_coby1_then_la1
lda i
cmp #$a
bcc b1_from_b1
jmp bend
//SEG11 @end
bend:
Statement [1] (byte~) $1 ← (byte) i#2 + (byte) 2+(byte) 2 [ i#2 $1 ] always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ i#2 i#1 ]
Statement [1] (byte~) $1 ← (byte) i#2 + (byte) 2+(byte) 2 [ i#2 $1 ] always clobbers reg byte a
REGISTER UPLIFT POTENTIAL REGISTERS
Potential registers zp ZP_BYTE:2 [ i#2 i#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:3 [ $1 ] : zp ZP_BYTE:3 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [] 31.17: zp ZP_BYTE:2 [ i#2 i#1 ] 22: zp ZP_BYTE:3 [ $1 ]
Uplifting [] best 285 combination reg byte x [ i#2 i#1 ] reg byte a [ $1 ]
Removing instruction jmp b1
Removing instruction jmp bend
Succesful ASM optimization Pass5NextJumpElimination
ASSEMBLER
//SEG0 Global Constants & labels
.const p = $1100
//SEG1 @begin
bbegin:
//SEG2 [0] phi from @begin to @1
b1_from_bbegin:
//SEG3 [0] phi (byte) i#2 = (byte) 5 -- xby=coby1
ldx #5
jmp b1
//SEG4 [0] phi from @1 to @1
b1_from_b1:
//SEG5 [0] phi (byte) i#2 = (byte) i#1 -- register_copy
//SEG6 @1
b1:
//SEG7 [1] (byte~) $1 ← (byte) i#2 + (byte) 2+(byte) 2 [ i#2 $1 ] -- aby=xby_plus_coby1
txa
clc
adc #2+2
//SEG8 [2] *((const byte[16]) p#0 + (byte) i#2) ← (byte~) $1 [ i#2 ] -- cowo1_staridx_xby=aby
sta p,x
//SEG9 [3] (byte) i#1 ← (byte) i#2 + (byte) 1 [ i#1 ] -- xby=xby_plus_1
inx
//SEG10 [4] if((byte) i#1<(byte) 10) goto @1 [ i#1 ] -- xby_lt_coby1_then_la1
cpx #$a
bcc b1_from_b1
//SEG11 @end
bend:
Replacing label b1_from_b1 with b1
Removing instruction b1_from_bbegin:
Removing instruction b1_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
ASSEMBLER
//SEG0 Global Constants & labels
.const p = $1100
//SEG1 @begin
bbegin:
//SEG2 [0] phi from @begin to @1
//SEG3 [0] phi (byte) i#2 = (byte) 5 -- xby=coby1
ldx #5
jmp b1
//SEG4 [0] phi from @1 to @1
//SEG5 [0] phi (byte) i#2 = (byte) i#1 -- register_copy
//SEG6 @1
b1:
//SEG7 [1] (byte~) $1 ← (byte) i#2 + (byte) 2+(byte) 2 [ i#2 $1 ] -- aby=xby_plus_coby1
txa
clc
adc #2+2
//SEG8 [2] *((const byte[16]) p#0 + (byte) i#2) ← (byte~) $1 [ i#2 ] -- cowo1_staridx_xby=aby
sta p,x
//SEG9 [3] (byte) i#1 ← (byte) i#2 + (byte) 1 [ i#1 ] -- xby=xby_plus_1
inx
//SEG10 [4] if((byte) i#1<(byte) 10) goto @1 [ i#1 ] -- xby_lt_coby1_then_la1
cpx #$a
bcc b1
//SEG11 @end
bend:
Removing instruction bbegin:
Removing instruction bend:
Succesful ASM optimization Pass5UnusedLabelElimination
ASSEMBLER
//SEG0 Global Constants & labels
.const p = $1100
//SEG1 @begin
//SEG2 [0] phi from @begin to @1
//SEG3 [0] phi (byte) i#2 = (byte) 5 -- xby=coby1
ldx #5
jmp b1
//SEG4 [0] phi from @1 to @1
//SEG5 [0] phi (byte) i#2 = (byte) i#1 -- register_copy
//SEG6 @1
b1:
//SEG7 [1] (byte~) $1 ← (byte) i#2 + (byte) 2+(byte) 2 [ i#2 $1 ] -- aby=xby_plus_coby1
txa
clc
adc #2+2
//SEG8 [2] *((const byte[16]) p#0 + (byte) i#2) ← (byte~) $1 [ i#2 ] -- cowo1_staridx_xby=aby
sta p,x
//SEG9 [3] (byte) i#1 ← (byte) i#2 + (byte) 1 [ i#1 ] -- xby=xby_plus_1
inx
//SEG10 [4] if((byte) i#1<(byte) 10) goto @1 [ i#1 ] -- xby_lt_coby1_then_la1
cpx #$a
bcc b1
//SEG11 @end
Removing instruction jmp b1
Succesful ASM optimization Pass5NextJumpElimination
ASSEMBLER
//SEG0 Global Constants & labels
.const p = $1100
//SEG1 @begin
//SEG2 [0] phi from @begin to @1
//SEG3 [0] phi (byte) i#2 = (byte) 5 -- xby=coby1
ldx #5
//SEG4 [0] phi from @1 to @1
//SEG5 [0] phi (byte) i#2 = (byte) i#1 -- register_copy
//SEG6 @1
b1:
//SEG7 [1] (byte~) $1 ← (byte) i#2 + (byte) 2+(byte) 2 [ i#2 $1 ] -- aby=xby_plus_coby1
txa
clc
adc #2+2
//SEG8 [2] *((const byte[16]) p#0 + (byte) i#2) ← (byte~) $1 [ i#2 ] -- cowo1_staridx_xby=aby
sta p,x
//SEG9 [3] (byte) i#1 ← (byte) i#2 + (byte) 1 [ i#1 ] -- xby=xby_plus_1
inx
//SEG10 [4] if((byte) i#1<(byte) 10) goto @1 [ i#1 ] -- xby_lt_coby1_then_la1
cpx #$a
bcc b1
//SEG11 @end
FINAL SYMBOL TABLE
(byte~) $1 reg byte a 22.0
(label) @1
(label) @begin
(label) @end
(byte) i
(byte) i#1 reg byte x 16.5
(byte) i#2 reg byte x 14.666666666666666
(byte[16]) p
(const byte[16]) p#0 = (word) 4352
reg byte x [ i#2 i#1 ]
reg byte a [ $1 ]
FINAL CODE
//SEG0 Global Constants & labels
.const p = $1100
//SEG1 @begin
//SEG2 [0] phi from @begin to @1
//SEG3 [0] phi (byte) i#2 = (byte) 5 -- xby=coby1
ldx #5
//SEG4 [0] phi from @1 to @1
//SEG5 [0] phi (byte) i#2 = (byte) i#1 -- register_copy
//SEG6 @1
b1:
//SEG7 [1] (byte~) $1 ← (byte) i#2 + (byte) 2+(byte) 2 [ i#2 $1 ] -- aby=xby_plus_coby1
txa
clc
adc #2+2
//SEG8 [2] *((const byte[16]) p#0 + (byte) i#2) ← (byte~) $1 [ i#2 ] -- cowo1_staridx_xby=aby
sta p,x
//SEG9 [3] (byte) i#1 ← (byte) i#2 + (byte) 1 [ i#1 ] -- xby=xby_plus_1
inx
//SEG10 [4] if((byte) i#1<(byte) 10) goto @1 [ i#1 ] -- xby_lt_coby1_then_la1
cpx #$a
bcc b1
//SEG11 @end

View File

@ -1,12 +0,0 @@
(byte~) $1 reg byte a 22.0
(label) @1
(label) @begin
(label) @end
(byte) i
(byte) i#1 reg byte x 16.5
(byte) i#2 reg byte x 14.666666666666666
(byte[16]) p
(const byte[16]) p#0 = (word) 4352
reg byte x [ i#2 i#1 ]
reg byte a [ $1 ]