mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-01-26 15:30:28 +00:00
Added ifmin() for optimizing if() block sequence.
This commit is contained in:
parent
4741a2d22e
commit
7b30fa4f2c
@ -1,71 +0,0 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.icl.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/*** Uplift one variable into the A register - and check if the program still works */
|
||||
public class Pass3RegisterUpliftTest extends Pass2Base {
|
||||
|
||||
public Pass3RegisterUpliftTest(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
/** Uplift variables to registers */
|
||||
public void uplift() {
|
||||
VariableRegisterWeights variableRegisterWeights = getProgram().getVariableRegisterWeights();
|
||||
LiveRangeEquivalenceClassSet equivalenceClassSet = getProgram().getLiveRangeEquivalenceClassSet();
|
||||
|
||||
double maxWeight = 0.0;
|
||||
LiveRangeEquivalenceClass maxEquivalenceClass = null;
|
||||
|
||||
// Find the live range equivalence class with the highest total weight
|
||||
for (LiveRangeEquivalenceClass equivalenceClass : equivalenceClassSet.getEquivalenceClasses()) {
|
||||
double totalWeight = 0.0;
|
||||
List<VariableRef> vars = equivalenceClass.getVariables();
|
||||
for (VariableRef var : vars) {
|
||||
Double varWeight = variableRegisterWeights.getWeight(var);
|
||||
totalWeight += varWeight;
|
||||
}
|
||||
if (maxWeight < totalWeight) {
|
||||
maxEquivalenceClass = equivalenceClass;
|
||||
maxWeight = totalWeight;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxEquivalenceClass != null) {
|
||||
getLog().append("Uplifting max weight " + maxWeight + " live range equivalence class " + maxEquivalenceClass);
|
||||
// Try the A register first
|
||||
List<RegisterAllocation.Register> registers =
|
||||
Arrays.asList(
|
||||
RegisterAllocation.getRegisterA(),
|
||||
RegisterAllocation.getRegisterX(),
|
||||
RegisterAllocation.getRegisterY());
|
||||
for (RegisterAllocation.Register register : registers) {
|
||||
attemptUplift(maxEquivalenceClass, register);
|
||||
}
|
||||
}
|
||||
|
||||
RegisterAllocation allocation = getProgram().getLiveRangeEquivalenceClassSet().createRegisterAllocation();
|
||||
getProgram().setAllocation(allocation);
|
||||
|
||||
}
|
||||
|
||||
private void attemptUplift(LiveRangeEquivalenceClass equivalenceClass, RegisterAllocation.Register register) {
|
||||
RegisterAllocation allocation = getProgram().getLiveRangeEquivalenceClassSet().createRegisterAllocation();
|
||||
for (VariableRef var : equivalenceClass.getVariables()) {
|
||||
allocation.setRegister(var, register);
|
||||
}
|
||||
getProgram().setAllocation(allocation);
|
||||
new Pass4CodeGeneration(getProgram()).generate();
|
||||
Pass4AssertNoCpuClobber clobber = new Pass4AssertNoCpuClobber(getProgram());
|
||||
if (clobber.hasClobberProblem(false)) {
|
||||
getLog().append("Uplift to " + register + " resulted in clobber.");
|
||||
} else {
|
||||
getLog().append("Uplift to " + register + " succesfull.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -84,6 +84,10 @@ public class TestCompilationOutput extends TestCase {
|
||||
compileAndCompare("modglobalmin");
|
||||
}
|
||||
|
||||
public void testIfMin() throws IOException, URISyntaxException {
|
||||
compileAndCompare("ifmin");
|
||||
}
|
||||
|
||||
public void testUseUninitialized() throws IOException, URISyntaxException {
|
||||
String filename = "useuninitialized";
|
||||
compileAndCompare(filename);
|
||||
|
13
src/main/java/dk/camelot64/kickc/test/ifmin.kc
Normal file
13
src/main/java/dk/camelot64/kickc/test/ifmin.kc
Normal file
@ -0,0 +1,13 @@
|
||||
// Minimal if() test
|
||||
byte* SCREEN = $0400;
|
||||
|
||||
main();
|
||||
|
||||
void main() {
|
||||
byte i=0;
|
||||
do {
|
||||
if(i<50) {
|
||||
*SCREEN = i;
|
||||
}
|
||||
} while(++i<100)
|
||||
}
|
15
src/main/java/dk/camelot64/kickc/test/ref/ifmin.asm
Normal file
15
src/main/java/dk/camelot64/kickc/test/ref/ifmin.asm
Normal file
@ -0,0 +1,15 @@
|
||||
jsr main
|
||||
main: {
|
||||
ldx #$0
|
||||
b1:
|
||||
cpx #$32
|
||||
bcc b2
|
||||
b3:
|
||||
inx
|
||||
cpx #$64
|
||||
bcc b1
|
||||
rts
|
||||
b2:
|
||||
stx $400
|
||||
jmp b3
|
||||
}
|
20
src/main/java/dk/camelot64/kickc/test/ref/ifmin.cfg
Normal file
20
src/main/java/dk/camelot64/kickc/test/ref/ifmin.cfg
Normal file
@ -0,0 +1,20 @@
|
||||
@begin: scope:[] from
|
||||
[0] 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
|
||||
[1] (byte) main::i#2 ← phi( main/(byte) 0 main::@3/(byte) main::i#1 ) [ main::i#2 ]
|
||||
[2] if((byte) main::i#2<(byte) 50) goto main::@2 [ main::i#2 ]
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
[3] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 ]
|
||||
[4] if((byte) main::i#1<(byte) 100) goto main::@1 [ main::i#1 ]
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
[5] return [ ]
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[6] *((word) 1024) ← (byte) main::i#2 [ main::i#2 ]
|
||||
to:main::@3
|
798
src/main/java/dk/camelot64/kickc/test/ref/ifmin.log
Normal file
798
src/main/java/dk/camelot64/kickc/test/ref/ifmin.log
Normal file
@ -0,0 +1,798 @@
|
||||
// Minimal if() test
|
||||
byte* SCREEN = $0400;
|
||||
|
||||
main();
|
||||
|
||||
void main() {
|
||||
byte i=0;
|
||||
do {
|
||||
if(i<50) {
|
||||
*SCREEN = i;
|
||||
}
|
||||
} while(++i<100)
|
||||
}
|
||||
Adding pre/post-modifier (byte) main::i ← ++ (byte) main::i
|
||||
PROGRAM
|
||||
(byte*) SCREEN ← (word) 1024
|
||||
(void~) $0 ← call main
|
||||
proc (void()) main()
|
||||
(byte) main::i ← (byte) 0
|
||||
main::@1:
|
||||
(boolean~) main::$0 ← (byte) main::i < (byte) 50
|
||||
if((boolean~) main::$0) goto main::@2
|
||||
goto main::@3
|
||||
main::@2:
|
||||
*((byte*) SCREEN) ← (byte) main::i
|
||||
main::@3:
|
||||
(byte) main::i ← ++ (byte) main::i
|
||||
(boolean~) main::$1 ← (byte) main::i < (byte) 100
|
||||
if((boolean~) main::$1) goto main::@1
|
||||
main::@return:
|
||||
return
|
||||
endproc // main()
|
||||
|
||||
SYMBOLS
|
||||
(void~) $0
|
||||
(byte*) SCREEN
|
||||
(void()) main()
|
||||
(boolean~) main::$0
|
||||
(boolean~) main::$1
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@return
|
||||
(byte) main::i
|
||||
|
||||
INITIAL CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
(byte*) SCREEN ← (word) 1024
|
||||
(void~) $0 ← call main
|
||||
to:@1
|
||||
main: scope:[main] from
|
||||
(byte) main::i ← (byte) 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@3
|
||||
(boolean~) main::$0 ← (byte) main::i < (byte) 50
|
||||
if((boolean~) main::$0) goto main::@2
|
||||
to:main::@4
|
||||
main::@2: scope:[main] from main::@1 main::@5
|
||||
*((byte*) SCREEN) ← (byte) main::i
|
||||
to:main::@3
|
||||
main::@4: scope:[main] from main::@1
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@2 main::@4
|
||||
(byte) main::i ← ++ (byte) main::i
|
||||
(boolean~) main::$1 ← (byte) main::i < (byte) 100
|
||||
if((boolean~) main::$1) goto main::@1
|
||||
to:main::@6
|
||||
main::@5: scope:[main] from
|
||||
to:main::@2
|
||||
main::@6: scope:[main] from main::@3
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@6
|
||||
return
|
||||
to:@return
|
||||
@1: scope:[] from @begin
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
|
||||
Removing empty block main::@4
|
||||
Removing empty block main::@5
|
||||
Removing empty block main::@6
|
||||
Removing empty block @1
|
||||
CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
(byte*) SCREEN ← (word) 1024
|
||||
(void~) $0 ← call main
|
||||
to:@end
|
||||
main: scope:[main] from
|
||||
(byte) main::i ← (byte) 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@3
|
||||
(boolean~) main::$0 ← (byte) main::i < (byte) 50
|
||||
if((boolean~) main::$0) goto main::@2
|
||||
to:main::@3
|
||||
main::@2: scope:[main] from main::@1
|
||||
*((byte*) SCREEN) ← (byte) main::i
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
(byte) main::i ← ++ (byte) main::i
|
||||
(boolean~) main::$1 ← (byte) main::i < (byte) 100
|
||||
if((boolean~) main::$1) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
return
|
||||
to:@return
|
||||
@end: scope:[] from @begin
|
||||
|
||||
PROCEDURE MODIFY VARIABLE ANALYSIS
|
||||
|
||||
CONTROL FLOW GRAPH WITH ASSIGNMENT CALL
|
||||
@begin: scope:[] from
|
||||
(byte*) SCREEN ← (word) 1024
|
||||
call main param-assignment
|
||||
to:@2
|
||||
@2: scope:[] from @begin
|
||||
to:@end
|
||||
main: scope:[main] from @begin
|
||||
(byte) main::i ← (byte) 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@3
|
||||
(boolean~) main::$0 ← (byte) main::i < (byte) 50
|
||||
if((boolean~) main::$0) goto main::@2
|
||||
to:main::@3
|
||||
main::@2: scope:[main] from main::@1
|
||||
*((byte*) SCREEN) ← (byte) main::i
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
(byte) main::i ← ++ (byte) main::i
|
||||
(boolean~) main::$1 ← (byte) main::i < (byte) 100
|
||||
if((boolean~) main::$1) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
return
|
||||
to:@return
|
||||
@end: scope:[] from @2
|
||||
|
||||
Completing Phi functions...
|
||||
Completing Phi functions...
|
||||
Completing Phi functions...
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
(byte*) SCREEN#0 ← (word) 1024
|
||||
call main param-assignment
|
||||
to:@2
|
||||
@2: scope:[] from @begin
|
||||
to:@end
|
||||
main: scope:[main] from @begin
|
||||
(byte*) SCREEN#3 ← phi( @begin/(byte*) SCREEN#0 )
|
||||
(byte) main::i#0 ← (byte) 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@3
|
||||
(byte*) SCREEN#2 ← phi( main/(byte*) SCREEN#3 main::@3/(byte*) SCREEN#4 )
|
||||
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@3/(byte) main::i#1 )
|
||||
(boolean~) main::$0 ← (byte) main::i#2 < (byte) 50
|
||||
if((boolean~) main::$0) goto main::@2
|
||||
to:main::@3
|
||||
main::@2: scope:[main] from main::@1
|
||||
(byte*) SCREEN#1 ← phi( main::@1/(byte*) SCREEN#2 )
|
||||
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
|
||||
*((byte*) SCREEN#1) ← (byte) main::i#3
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
(byte*) SCREEN#4 ← phi( main::@1/(byte*) SCREEN#2 main::@2/(byte*) SCREEN#1 )
|
||||
(byte) main::i#4 ← phi( main::@1/(byte) main::i#2 main::@2/(byte) main::i#3 )
|
||||
(byte) main::i#1 ← ++ (byte) main::i#4
|
||||
(boolean~) main::$1 ← (byte) main::i#1 < (byte) 100
|
||||
if((boolean~) main::$1) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
return
|
||||
to:@return
|
||||
@end: scope:[] from @2
|
||||
|
||||
CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN
|
||||
@begin: scope:[] from
|
||||
(byte*) SCREEN#0 ← (word) 1024
|
||||
call main param-assignment
|
||||
to:@2
|
||||
@2: scope:[] from @begin
|
||||
to:@end
|
||||
main: scope:[main] from @begin
|
||||
(byte*) SCREEN#3 ← phi( @begin/(byte*) SCREEN#0 )
|
||||
(byte) main::i#0 ← (byte) 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@3
|
||||
(byte*) SCREEN#2 ← phi( main/(byte*) SCREEN#3 main::@3/(byte*) SCREEN#4 )
|
||||
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@3/(byte) main::i#1 )
|
||||
(boolean~) main::$0 ← (byte) main::i#2 < (byte) 50
|
||||
if((boolean~) main::$0) goto main::@2
|
||||
to:main::@3
|
||||
main::@2: scope:[main] from main::@1
|
||||
(byte*) SCREEN#1 ← phi( main::@1/(byte*) SCREEN#2 )
|
||||
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
|
||||
*((byte*) SCREEN#1) ← (byte) main::i#3
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
(byte*) SCREEN#4 ← phi( main::@1/(byte*) SCREEN#2 main::@2/(byte*) SCREEN#1 )
|
||||
(byte) main::i#4 ← phi( main::@1/(byte) main::i#2 main::@2/(byte) main::i#3 )
|
||||
(byte) main::i#1 ← ++ (byte) main::i#4
|
||||
(boolean~) main::$1 ← (byte) main::i#1 < (byte) 100
|
||||
if((boolean~) main::$1) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
return
|
||||
to:@return
|
||||
@end: scope:[] from @2
|
||||
|
||||
Culled Empty Block (label) @2
|
||||
Succesful SSA optimization Pass2CullEmptyBlocks
|
||||
CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
(byte*) SCREEN#0 ← (word) 1024
|
||||
call main param-assignment
|
||||
to:@end
|
||||
main: scope:[main] from @begin
|
||||
(byte*) SCREEN#3 ← phi( @begin/(byte*) SCREEN#0 )
|
||||
(byte) main::i#0 ← (byte) 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@3
|
||||
(byte*) SCREEN#2 ← phi( main/(byte*) SCREEN#3 main::@3/(byte*) SCREEN#4 )
|
||||
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@3/(byte) main::i#1 )
|
||||
(boolean~) main::$0 ← (byte) main::i#2 < (byte) 50
|
||||
if((boolean~) main::$0) goto main::@2
|
||||
to:main::@3
|
||||
main::@2: scope:[main] from main::@1
|
||||
(byte*) SCREEN#1 ← phi( main::@1/(byte*) SCREEN#2 )
|
||||
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
|
||||
*((byte*) SCREEN#1) ← (byte) main::i#3
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
(byte*) SCREEN#4 ← phi( main::@1/(byte*) SCREEN#2 main::@2/(byte*) SCREEN#1 )
|
||||
(byte) main::i#4 ← phi( main::@1/(byte) main::i#2 main::@2/(byte) main::i#3 )
|
||||
(byte) main::i#1 ← ++ (byte) main::i#4
|
||||
(boolean~) main::$1 ← (byte) main::i#1 < (byte) 100
|
||||
if((boolean~) main::$1) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
return
|
||||
to:@return
|
||||
@end: scope:[] from @begin
|
||||
|
||||
Constant (byte*) SCREEN#0 (word) 1024
|
||||
Constant (byte) main::i#0 (byte) 0
|
||||
Succesful SSA optimization Pass2ConstantPropagation
|
||||
CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
call main param-assignment
|
||||
to:@end
|
||||
main: scope:[main] from @begin
|
||||
(byte*) SCREEN#3 ← phi( @begin/(word) 1024 )
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@3
|
||||
(byte*) SCREEN#2 ← phi( main/(byte*) SCREEN#3 main::@3/(byte*) SCREEN#4 )
|
||||
(byte) main::i#2 ← phi( main/(byte) 0 main::@3/(byte) main::i#1 )
|
||||
(boolean~) main::$0 ← (byte) main::i#2 < (byte) 50
|
||||
if((boolean~) main::$0) goto main::@2
|
||||
to:main::@3
|
||||
main::@2: scope:[main] from main::@1
|
||||
(byte*) SCREEN#1 ← phi( main::@1/(byte*) SCREEN#2 )
|
||||
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
|
||||
*((byte*) SCREEN#1) ← (byte) main::i#3
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
(byte*) SCREEN#4 ← phi( main::@1/(byte*) SCREEN#2 main::@2/(byte*) SCREEN#1 )
|
||||
(byte) main::i#4 ← phi( main::@1/(byte) main::i#2 main::@2/(byte) main::i#3 )
|
||||
(byte) main::i#1 ← ++ (byte) main::i#4
|
||||
(boolean~) main::$1 ← (byte) main::i#1 < (byte) 100
|
||||
if((boolean~) main::$1) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
return
|
||||
to:@return
|
||||
@end: scope:[] from @begin
|
||||
|
||||
Alias (byte) main::i#2 = (byte) main::i#3
|
||||
Alias (byte*) SCREEN#1 = (byte*) SCREEN#2
|
||||
Succesful SSA optimization Pass2AliasElimination
|
||||
CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
call main param-assignment
|
||||
to:@end
|
||||
main: scope:[main] from @begin
|
||||
(byte*) SCREEN#3 ← phi( @begin/(word) 1024 )
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@3
|
||||
(byte*) SCREEN#1 ← phi( main/(byte*) SCREEN#3 main::@3/(byte*) SCREEN#4 )
|
||||
(byte) main::i#2 ← phi( main/(byte) 0 main::@3/(byte) main::i#1 )
|
||||
(boolean~) main::$0 ← (byte) main::i#2 < (byte) 50
|
||||
if((boolean~) main::$0) goto main::@2
|
||||
to:main::@3
|
||||
main::@2: scope:[main] from main::@1
|
||||
*((byte*) SCREEN#1) ← (byte) main::i#2
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
(byte*) SCREEN#4 ← phi( main::@1/(byte*) SCREEN#1 main::@2/(byte*) SCREEN#1 )
|
||||
(byte) main::i#4 ← phi( main::@1/(byte) main::i#2 main::@2/(byte) main::i#2 )
|
||||
(byte) main::i#1 ← ++ (byte) main::i#4
|
||||
(boolean~) main::$1 ← (byte) main::i#1 < (byte) 100
|
||||
if((boolean~) main::$1) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
return
|
||||
to:@return
|
||||
@end: scope:[] from @begin
|
||||
|
||||
Redundant Phi (byte*) SCREEN#3 (word) 1024
|
||||
Redundant Phi (byte) main::i#4 (byte) main::i#2
|
||||
Redundant Phi (byte*) SCREEN#4 (byte*) SCREEN#1
|
||||
Succesful SSA optimization Pass2RedundantPhiElimination
|
||||
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::@3
|
||||
(byte*) SCREEN#1 ← phi( main/(word) 1024 main::@3/(byte*) SCREEN#1 )
|
||||
(byte) main::i#2 ← phi( main/(byte) 0 main::@3/(byte) main::i#1 )
|
||||
(boolean~) main::$0 ← (byte) main::i#2 < (byte) 50
|
||||
if((boolean~) main::$0) goto main::@2
|
||||
to:main::@3
|
||||
main::@2: scope:[main] from main::@1
|
||||
*((byte*) SCREEN#1) ← (byte) main::i#2
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
(byte) main::i#1 ← ++ (byte) main::i#2
|
||||
(boolean~) main::$1 ← (byte) main::i#1 < (byte) 100
|
||||
if((boolean~) main::$1) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
return
|
||||
to:@return
|
||||
@end: scope:[] from @begin
|
||||
|
||||
Self Phi Eliminated (byte*) SCREEN#1
|
||||
Succesful SSA optimization Pass2SelfPhiElimination
|
||||
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::@3
|
||||
(byte*) SCREEN#1 ← phi( main/(word) 1024 )
|
||||
(byte) main::i#2 ← phi( main/(byte) 0 main::@3/(byte) main::i#1 )
|
||||
(boolean~) main::$0 ← (byte) main::i#2 < (byte) 50
|
||||
if((boolean~) main::$0) goto main::@2
|
||||
to:main::@3
|
||||
main::@2: scope:[main] from main::@1
|
||||
*((byte*) SCREEN#1) ← (byte) main::i#2
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
(byte) main::i#1 ← ++ (byte) main::i#2
|
||||
(boolean~) main::$1 ← (byte) main::i#1 < (byte) 100
|
||||
if((boolean~) main::$1) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
return
|
||||
to:@return
|
||||
@end: scope:[] from @begin
|
||||
|
||||
Simple Condition (boolean~) main::$0 if((byte) main::i#2<(byte) 50) goto main::@2
|
||||
Simple Condition (boolean~) main::$1 if((byte) main::i#1<(byte) 100) goto main::@1
|
||||
Succesful SSA optimization Pass2ConditionalJumpSimplification
|
||||
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::@3
|
||||
(byte*) SCREEN#1 ← phi( main/(word) 1024 )
|
||||
(byte) main::i#2 ← phi( main/(byte) 0 main::@3/(byte) main::i#1 )
|
||||
if((byte) main::i#2<(byte) 50) goto main::@2
|
||||
to:main::@3
|
||||
main::@2: scope:[main] from main::@1
|
||||
*((byte*) SCREEN#1) ← (byte) main::i#2
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
(byte) main::i#1 ← ++ (byte) main::i#2
|
||||
if((byte) main::i#1<(byte) 100) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
return
|
||||
to:@return
|
||||
@end: scope:[] from @begin
|
||||
|
||||
Constant (byte*) SCREEN#1 (word) 1024
|
||||
Succesful SSA optimization Pass2ConstantPropagation
|
||||
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::@3
|
||||
(byte) main::i#2 ← phi( main/(byte) 0 main::@3/(byte) main::i#1 )
|
||||
if((byte) main::i#2<(byte) 50) goto main::@2
|
||||
to:main::@3
|
||||
main::@2: scope:[main] from main::@1
|
||||
*((word) 1024) ← (byte) main::i#2
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
(byte) main::i#1 ← ++ (byte) main::i#2
|
||||
if((byte) main::i#1<(byte) 100) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
return
|
||||
to:@return
|
||||
@end: scope:[] from @begin
|
||||
|
||||
Block Sequence Planned @begin @end main main::@1 main::@3 main::@return main::@2
|
||||
Added new block during phi lifting main::@7(between main::@3 and main::@1)
|
||||
Block Sequence Planned @begin @end main main::@1 main::@3 main::@return main::@7 main::@2
|
||||
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::@7
|
||||
(byte) main::i#2 ← phi( main/(byte) 0 main::@7/(byte~) main::i#5 )
|
||||
if((byte) main::i#2<(byte) 50) goto main::@2
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
(byte) main::i#1 ← ++ (byte) main::i#2
|
||||
if((byte) main::i#1<(byte) 100) goto main::@7
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
return
|
||||
to:@return
|
||||
main::@7: scope:[main] from main::@3
|
||||
(byte~) main::i#5 ← (byte) main::i#1
|
||||
to:main::@1
|
||||
main::@2: scope:[main] from main::@1
|
||||
*((word) 1024) ← (byte) main::i#2
|
||||
to:main::@3
|
||||
|
||||
Propagating live ranges...
|
||||
CONTROL FLOW GRAPH - LIVE RANGES
|
||||
@begin: scope:[] from
|
||||
[0] 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::@7
|
||||
[1] (byte) main::i#2 ← phi( main/(byte) 0 main::@7/(byte~) main::i#5 ) [ main::i#2 ]
|
||||
[2] if((byte) main::i#2<(byte) 50) goto main::@2 [ main::i#2 ]
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
[3] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 ]
|
||||
[4] if((byte) main::i#1<(byte) 100) goto main::@7 [ main::i#1 ]
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
[5] return [ ]
|
||||
to:@return
|
||||
main::@7: scope:[main] from main::@3
|
||||
[6] (byte~) main::i#5 ← (byte) main::i#1 [ main::i#5 ]
|
||||
to:main::@1
|
||||
main::@2: scope:[main] from main::@1
|
||||
[7] *((word) 1024) ← (byte) main::i#2 [ main::i#2 ]
|
||||
to:main::@3
|
||||
|
||||
Created 1 initial phi equivalence classes
|
||||
Coalesced [6] main::i#5 ← main::i#1
|
||||
Coalesced down to 1 phi equivalence classes
|
||||
Culled Empty Block (label) main::@7
|
||||
Block Sequence Planned @begin @end main main::@1 main::@3 main::@return main::@2
|
||||
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
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@3
|
||||
[1] (byte) main::i#2 ← phi( main/(byte) 0 main::@3/(byte) main::i#1 ) [ main::i#2 ]
|
||||
[2] if((byte) main::i#2<(byte) 50) goto main::@2 [ main::i#2 ]
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@1 main::@2
|
||||
[3] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 ]
|
||||
[4] if((byte) main::i#1<(byte) 100) goto main::@1 [ main::i#1 ]
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
[5] return [ ]
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[6] *((word) 1024) ← (byte) main::i#2 [ main::i#2 ]
|
||||
to:main::@3
|
||||
|
||||
CALL GRAPH
|
||||
Calls in [] to 0:main
|
||||
|
||||
DOMINATORS
|
||||
@begin dominated by @begin
|
||||
@end dominated by @end @begin
|
||||
main dominated by @begin main
|
||||
main::@1 dominated by @begin main::@1 main
|
||||
main::@3 dominated by @begin main::@1 main::@3 main
|
||||
main::@return dominated by main::@return @begin main::@1 main::@3 main
|
||||
main::@2 dominated by @begin main::@2 main::@1 main
|
||||
|
||||
Found back edge: Loop head: main::@1 tails: main::@3 blocks: null
|
||||
Populated: Loop head: main::@1 tails: main::@3 blocks: main::@3 main::@1 main::@2
|
||||
NATURAL LOOPS
|
||||
Loop head: main::@1 tails: main::@3 blocks: main::@3 main::@1 main::@2
|
||||
|
||||
Found 0 loops in scope []
|
||||
Found 1 loops in scope [main]
|
||||
Loop head: main::@1 tails: main::@3 blocks: main::@3 main::@1 main::@2
|
||||
NATURAL LOOPS WITH DEPTH
|
||||
Loop head: main::@1 tails: main::@3 blocks: main::@3 main::@1 main::@2 depth: 1
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(byte*) SCREEN
|
||||
(void()) main()
|
||||
(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 ]
|
||||
Complete equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
Allocated zp byte:2 to zp byte:2 [ main::i#2 main::i#1 ]
|
||||
INITIAL ASM
|
||||
//SEG0 @begin
|
||||
bbegin:
|
||||
//SEG1 [0] call main param-assignment [ ]
|
||||
jsr main
|
||||
jmp bend
|
||||
//SEG2 @end
|
||||
bend:
|
||||
//SEG3 main
|
||||
main: {
|
||||
//SEG4 [1] phi from main to main::@1
|
||||
b1_from_main:
|
||||
//SEG5 [1] phi (byte) main::i#2 = (byte) 0 -- zpby1=coby1
|
||||
lda #$0
|
||||
sta $2
|
||||
jmp b1
|
||||
//SEG6 [1] phi from main::@3 to main::@1
|
||||
b1_from_b3:
|
||||
//SEG7 [1] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy
|
||||
jmp b1
|
||||
//SEG8 main::@1
|
||||
b1:
|
||||
//SEG9 [2] if((byte) main::i#2<(byte) 50) goto main::@2 [ main::i#2 ] -- zpby1_lt_coby1_then_la1
|
||||
lda $2
|
||||
cmp #$32
|
||||
bcc b2
|
||||
jmp b3
|
||||
//SEG10 main::@3
|
||||
b3:
|
||||
//SEG11 [3] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 ] -- zpby1=_inc_zpby1
|
||||
inc $2
|
||||
//SEG12 [4] if((byte) main::i#1<(byte) 100) goto main::@1 [ main::i#1 ] -- zpby1_lt_coby1_then_la1
|
||||
lda $2
|
||||
cmp #$64
|
||||
bcc b1_from_b3
|
||||
jmp breturn
|
||||
//SEG13 main::@return
|
||||
breturn:
|
||||
//SEG14 [5] return [ ]
|
||||
rts
|
||||
//SEG15 main::@2
|
||||
b2:
|
||||
//SEG16 [6] *((word) 1024) ← (byte) main::i#2 [ main::i#2 ] -- _star_cowo1=zpby1
|
||||
lda $2
|
||||
sta $400
|
||||
jmp b3
|
||||
}
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Potential registers zp byte:2 [ main::i#2 main::i#1 ] : zp byte:2 , reg byte a , reg byte x , reg byte y ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main] 31.17: zp byte:2 [ main::i#2 main::i#1 ]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 335 combination reg byte x [ main::i#2 main::i#1 ]
|
||||
Uplifting [] best 335 combination
|
||||
Removing instruction jmp bend
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp b3
|
||||
Removing instruction jmp breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
ASSEMBLER
|
||||
//SEG0 @begin
|
||||
bbegin:
|
||||
//SEG1 [0] call main param-assignment [ ]
|
||||
jsr main
|
||||
//SEG2 @end
|
||||
bend:
|
||||
//SEG3 main
|
||||
main: {
|
||||
//SEG4 [1] phi from main to main::@1
|
||||
b1_from_main:
|
||||
//SEG5 [1] phi (byte) main::i#2 = (byte) 0 -- xby=coby1
|
||||
ldx #$0
|
||||
jmp b1
|
||||
//SEG6 [1] phi from main::@3 to main::@1
|
||||
b1_from_b3:
|
||||
//SEG7 [1] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy
|
||||
//SEG8 main::@1
|
||||
b1:
|
||||
//SEG9 [2] if((byte) main::i#2<(byte) 50) goto main::@2 [ main::i#2 ] -- xby_lt_coby1_then_la1
|
||||
cpx #$32
|
||||
bcc b2
|
||||
//SEG10 main::@3
|
||||
b3:
|
||||
//SEG11 [3] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 ] -- xby=_inc_xby
|
||||
inx
|
||||
//SEG12 [4] if((byte) main::i#1<(byte) 100) goto main::@1 [ main::i#1 ] -- xby_lt_coby1_then_la1
|
||||
cpx #$64
|
||||
bcc b1_from_b3
|
||||
//SEG13 main::@return
|
||||
breturn:
|
||||
//SEG14 [5] return [ ]
|
||||
rts
|
||||
//SEG15 main::@2
|
||||
b2:
|
||||
//SEG16 [6] *((word) 1024) ← (byte) main::i#2 [ main::i#2 ] -- _star_cowo1=xby
|
||||
stx $400
|
||||
jmp b3
|
||||
}
|
||||
|
||||
Replacing label b1_from_b3 with b1
|
||||
Removing instruction b1_from_b3:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
ASSEMBLER
|
||||
//SEG0 @begin
|
||||
bbegin:
|
||||
//SEG1 [0] call main param-assignment [ ]
|
||||
jsr main
|
||||
//SEG2 @end
|
||||
bend:
|
||||
//SEG3 main
|
||||
main: {
|
||||
//SEG4 [1] phi from main to main::@1
|
||||
b1_from_main:
|
||||
//SEG5 [1] phi (byte) main::i#2 = (byte) 0 -- xby=coby1
|
||||
ldx #$0
|
||||
jmp b1
|
||||
//SEG6 [1] phi from main::@3 to main::@1
|
||||
//SEG7 [1] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy
|
||||
//SEG8 main::@1
|
||||
b1:
|
||||
//SEG9 [2] if((byte) main::i#2<(byte) 50) goto main::@2 [ main::i#2 ] -- xby_lt_coby1_then_la1
|
||||
cpx #$32
|
||||
bcc b2
|
||||
//SEG10 main::@3
|
||||
b3:
|
||||
//SEG11 [3] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 ] -- xby=_inc_xby
|
||||
inx
|
||||
//SEG12 [4] if((byte) main::i#1<(byte) 100) goto main::@1 [ main::i#1 ] -- xby_lt_coby1_then_la1
|
||||
cpx #$64
|
||||
bcc b1
|
||||
//SEG13 main::@return
|
||||
breturn:
|
||||
//SEG14 [5] return [ ]
|
||||
rts
|
||||
//SEG15 main::@2
|
||||
b2:
|
||||
//SEG16 [6] *((word) 1024) ← (byte) main::i#2 [ main::i#2 ] -- _star_cowo1=xby
|
||||
stx $400
|
||||
jmp b3
|
||||
}
|
||||
|
||||
Removing instruction bbegin:
|
||||
Removing instruction bend:
|
||||
Removing instruction b1_from_main:
|
||||
Removing instruction breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
ASSEMBLER
|
||||
//SEG0 @begin
|
||||
//SEG1 [0] call main param-assignment [ ]
|
||||
jsr main
|
||||
//SEG2 @end
|
||||
//SEG3 main
|
||||
main: {
|
||||
//SEG4 [1] phi from main to main::@1
|
||||
//SEG5 [1] phi (byte) main::i#2 = (byte) 0 -- xby=coby1
|
||||
ldx #$0
|
||||
jmp b1
|
||||
//SEG6 [1] phi from main::@3 to main::@1
|
||||
//SEG7 [1] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy
|
||||
//SEG8 main::@1
|
||||
b1:
|
||||
//SEG9 [2] if((byte) main::i#2<(byte) 50) goto main::@2 [ main::i#2 ] -- xby_lt_coby1_then_la1
|
||||
cpx #$32
|
||||
bcc b2
|
||||
//SEG10 main::@3
|
||||
b3:
|
||||
//SEG11 [3] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 ] -- xby=_inc_xby
|
||||
inx
|
||||
//SEG12 [4] if((byte) main::i#1<(byte) 100) goto main::@1 [ main::i#1 ] -- xby_lt_coby1_then_la1
|
||||
cpx #$64
|
||||
bcc b1
|
||||
//SEG13 main::@return
|
||||
//SEG14 [5] return [ ]
|
||||
rts
|
||||
//SEG15 main::@2
|
||||
b2:
|
||||
//SEG16 [6] *((word) 1024) ← (byte) main::i#2 [ main::i#2 ] -- _star_cowo1=xby
|
||||
stx $400
|
||||
jmp b3
|
||||
}
|
||||
|
||||
Removing instruction jmp b1
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
ASSEMBLER
|
||||
//SEG0 @begin
|
||||
//SEG1 [0] call main param-assignment [ ]
|
||||
jsr main
|
||||
//SEG2 @end
|
||||
//SEG3 main
|
||||
main: {
|
||||
//SEG4 [1] phi from main to main::@1
|
||||
//SEG5 [1] phi (byte) main::i#2 = (byte) 0 -- xby=coby1
|
||||
ldx #$0
|
||||
//SEG6 [1] phi from main::@3 to main::@1
|
||||
//SEG7 [1] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy
|
||||
//SEG8 main::@1
|
||||
b1:
|
||||
//SEG9 [2] if((byte) main::i#2<(byte) 50) goto main::@2 [ main::i#2 ] -- xby_lt_coby1_then_la1
|
||||
cpx #$32
|
||||
bcc b2
|
||||
//SEG10 main::@3
|
||||
b3:
|
||||
//SEG11 [3] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 ] -- xby=_inc_xby
|
||||
inx
|
||||
//SEG12 [4] if((byte) main::i#1<(byte) 100) goto main::@1 [ main::i#1 ] -- xby_lt_coby1_then_la1
|
||||
cpx #$64
|
||||
bcc b1
|
||||
//SEG13 main::@return
|
||||
//SEG14 [5] return [ ]
|
||||
rts
|
||||
//SEG15 main::@2
|
||||
b2:
|
||||
//SEG16 [6] *((word) 1024) ← (byte) main::i#2 [ main::i#2 ] -- _star_cowo1=xby
|
||||
stx $400
|
||||
jmp b3
|
||||
}
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(byte*) SCREEN
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@return
|
||||
(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 ]
|
||||
|
||||
FINAL CODE
|
||||
//SEG0 @begin
|
||||
//SEG1 [0] call main param-assignment [ ]
|
||||
jsr main
|
||||
//SEG2 @end
|
||||
//SEG3 main
|
||||
main: {
|
||||
//SEG4 [1] phi from main to main::@1
|
||||
//SEG5 [1] phi (byte) main::i#2 = (byte) 0 -- xby=coby1
|
||||
ldx #$0
|
||||
//SEG6 [1] phi from main::@3 to main::@1
|
||||
//SEG7 [1] phi (byte) main::i#2 = (byte) main::i#1 -- register_copy
|
||||
//SEG8 main::@1
|
||||
b1:
|
||||
//SEG9 [2] if((byte) main::i#2<(byte) 50) goto main::@2 [ main::i#2 ] -- xby_lt_coby1_then_la1
|
||||
cpx #$32
|
||||
bcc b2
|
||||
//SEG10 main::@3
|
||||
b3:
|
||||
//SEG11 [3] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 ] -- xby=_inc_xby
|
||||
inx
|
||||
//SEG12 [4] if((byte) main::i#1<(byte) 100) goto main::@1 [ main::i#1 ] -- xby_lt_coby1_then_la1
|
||||
cpx #$64
|
||||
bcc b1
|
||||
//SEG13 main::@return
|
||||
//SEG14 [5] return [ ]
|
||||
rts
|
||||
//SEG15 main::@2
|
||||
b2:
|
||||
//SEG16 [6] *((word) 1024) ← (byte) main::i#2 [ main::i#2 ] -- _star_cowo1=xby
|
||||
stx $400
|
||||
jmp b3
|
||||
}
|
||||
|
13
src/main/java/dk/camelot64/kickc/test/ref/ifmin.sym
Normal file
13
src/main/java/dk/camelot64/kickc/test/ref/ifmin.sym
Normal file
@ -0,0 +1,13 @@
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(byte*) SCREEN
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@return
|
||||
(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 ]
|
Loading…
x
Reference in New Issue
Block a user