1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-12-22 21:29:50 +00:00

Fixed exception "Block referenced, but not found in program" when encountering complex if(&&). Closes #676

This commit is contained in:
jespergravgaard 2021-07-07 08:47:44 +02:00
parent 72c5c7d537
commit 3dff5d04fb
15 changed files with 953 additions and 3 deletions

View File

@ -54,9 +54,9 @@ public class Procedure extends Scope {
PHI_CALL("__phicall"),
/** Parameters and return value over the stack. */
STACK_CALL("__stackcall"),
/** Parameters and return value handled through variables. */
/** Parameters and return value handled through shared variables. */
VAR_CALL("__varcall"),
/** Intrinsic calling. */
/** Intrinsic calling. Will be converted to intrinsic ASM late in the compile. */
INTRINSIC_CALL("__intrinsiccall");
private final String name;

View File

@ -126,7 +126,7 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
ControlFlowBlock destBlock = getGraph().getBlock(destLabel);
LinkedHashMap<LabelRef, LabelRef> replacements = new LinkedHashMap<>();
replacements.put(block.getLabel(), newBlockLabel.getRef());
replaceLabels(destBlock, replacements);
replaceLabels(destBlock.getPhiBlock(), replacements);
}

View File

@ -61,6 +61,16 @@ public abstract class Pass2SsaOptimization extends Pass1Base implements PassStep
visitor.visitBlock(block);
}
/**
* Replace all usages of a label in a statement with another label.
*
* @param replacements Variables that have alias values.
*/
public void replaceLabels(Statement statement, final Map<LabelRef, LabelRef> replacements) {
ControlFlowGraphBaseVisitor<Void> visitor = getLabelReplaceVisitor(replacements);
visitor.visitStatement(statement);
}
/** Creates a visitor that can replace labels. */
private ControlFlowGraphBaseVisitor<Void> getLabelReplaceVisitor(final Map<LabelRef, LabelRef> replacements) {
return new ControlFlowGraphBaseVisitor<Void>() {

View File

@ -9,6 +9,21 @@ import java.io.IOException;
*/
public class TestProgramsFast extends TestPrograms {
//@Test
//public void testShadowVariableError1() throws IOException {
// compileAndCompare("shadow-variable-error-1.c");
//}
@Test
public void testBlockError2() throws IOException {
compileAndCompare("block-error-2.c");
}
@Test
public void testBlockError1() throws IOException {
compileAndCompare("block-error-1.c");
}
@Test
public void testMakeLong42() throws IOException {
assertError("makelong4-2.c", "Wrong number of parameters in call. Expected 4.");

View File

@ -0,0 +1,15 @@
// Demonstrates error "Block referenced, but not found in program."
void main() {
for(char i=0;i!=8;i++) {
char move = 1;
char pos = 1;
char vacant = 1;
do {
pos += move;
if(pos) {
char vacant = 0;
}
} while(pos && vacant);
}
}

View File

@ -0,0 +1,12 @@
// Demonstrates error "Sequence does not contain all blocks from the program."
void main() {
char move = 1;
char pos = 1;
char vacant = 1;
do {
pos += move;
if(pos)
vacant = 0;
} while(pos && vacant);
}

View File

@ -0,0 +1,14 @@
// Demonstrates error "Variable used before being defined."
void main() {
for(char i=0;i!=8;i++) {
char move = 1;
char pos = 1;
char vacant = 1;
do {
pos += move;
if(pos)
char vacant = 0;
} while(pos && vacant);
}
}

View File

@ -0,0 +1,34 @@
// Demonstrates error "Block referenced, but not found in program."
// Commodore 64 PRG executable file
.file [name="block-error-1.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.segment Code
main: {
.const move = 1
ldx #0
__b1:
// for(char i=0;i!=8;i++)
cpx #8
bne __b4
// }
rts
__b4:
lda #1
__b2:
// pos += move
clc
adc #move
// if(pos)
cmp #0
// while(pos && vacant)
cmp #0
bne __b2
// for(char i=0;i!=8;i++)
inx
jmp __b1
}

View File

@ -0,0 +1,26 @@
void main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@5
[1] main::i#2 = phi( main/0, main::@5/main::i#1 )
[2] if(main::i#2!=8) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1 main::@3
[4] main::pos#2 = phi( main::@1/1, main::@3/main::pos#1 )
[5] main::pos#1 = main::pos#2 + main::move
[6] if(0==main::pos#1) goto main::@3
to:main::@4
main::@4: scope:[main] from main::@2
[7] phi()
to:main::@3
main::@3: scope:[main] from main::@2 main::@4
[8] if(0!=main::pos#1) goto main::@2
to:main::@5
main::@5: scope:[main] from main::@3
[9] main::i#1 = ++ main::i#2
to:main::@1

View File

@ -0,0 +1,389 @@
CONTROL FLOW GRAPH SSA
void main()
main: scope:[main] from __start
main::i#0 = 0
to:main::@1
main::@1: scope:[main] from main main::@6
main::i#2 = phi( main/main::i#0, main::@6/main::i#1 )
main::$0 = main::i#2 != 8
if(main::$0) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
main::i#7 = phi( main::@1/main::i#2 )
main::pos#0 = 1
to:main::@3
main::@3: scope:[main] from main::@2 main::@4
main::i#5 = phi( main::@2/main::i#7, main::@4/main::i#4 )
main::pos#2 = phi( main::@2/main::pos#0, main::@4/main::pos#3 )
main::pos#1 = main::pos#2 + main::move
main::$3 = 0 != main::pos#1
main::$1 = ! main::$3
if(main::$1) goto main::@4
to:main::@5
main::@4: scope:[main] from main::@3 main::@5
main::i#4 = phi( main::@3/main::i#5, main::@5/main::i#6 )
main::pos#3 = phi( main::@3/main::pos#1, main::@5/main::pos#4 )
main::$2 = main::pos#3 && main::vacant
if(main::$2) goto main::@3
to:main::@6
main::@5: scope:[main] from main::@3
main::i#6 = phi( main::@3/main::i#5 )
main::pos#4 = phi( main::@3/main::pos#1 )
to:main::@4
main::@6: scope:[main] from main::@4
main::i#3 = phi( main::@4/main::i#4 )
main::i#1 = ++ main::i#3
to:main::@1
main::@return: scope:[main] from main::@1
return
to:@return
void __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
void __start()
void main()
bool~ main::$0
bool~ main::$1
bool~ main::$2
bool~ main::$3
byte main::i
byte main::i#0
byte main::i#1
byte main::i#2
byte main::i#3
byte main::i#4
byte main::i#5
byte main::i#6
byte main::i#7
constant byte main::move = 1
byte main::pos
byte main::pos#0
byte main::pos#1
byte main::pos#2
byte main::pos#3
byte main::pos#4
constant byte main::vacant = 1
Adding number conversion cast (unumber) 8 in main::$0 = main::i#2 != 8
Adding number conversion cast (unumber) 0 in main::$3 = 0 != main::pos#1
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast 8
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 8
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inversing boolean not [9] main::$1 = 0 == main::pos#1 from [8] main::$3 = 0 != main::pos#1
Successful SSA optimization Pass2UnaryNotSimplification
Alias main::i#2 = main::i#7
Alias main::pos#1 = main::pos#4
Alias main::i#5 = main::i#6
Alias main::i#3 = main::i#4
Successful SSA optimization Pass2AliasElimination
Alias main::pos#1 = main::pos#3
Alias main::i#3 = main::i#5
Successful SSA optimization Pass2AliasElimination
Identical Phi Values main::i#3 main::i#2
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition main::$0 [3] if(main::i#2!=8) goto main::@2
Simple Condition main::$1 [8] if(0==main::pos#1) goto main::@4
Successful SSA optimization Pass2ConditionalJumpSimplification
Rewriting && if()-condition to two if()s [9] main::$2 = main::pos#1 && main::vacant
Successful SSA optimization Pass2ConditionalAndOrRewriting
Warning! Adding boolean cast to non-boolean condition main::pos#1
Warning! Adding boolean cast to non-boolean condition main::vacant
Constant right-side identified main::$5 = 0 != main::vacant
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant main::i#0 = 0
Constant main::pos#0 = 1
Constant main::$5 = 0!=main::vacant
Successful SSA optimization Pass2ConstantIdentification
if() condition always true - replacing block destination if(main::$5) goto main::@3
Successful SSA optimization Pass2ConstantIfs
Eliminating unused constant main::$5
Successful SSA optimization PassNEliminateUnusedVars
Eliminating unused constant main::vacant
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Adding number conversion cast (unumber) 0 in [5] main::$4 = 0 != main::pos#1
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Simple Condition main::$4 [6] if(0!=main::pos#1) goto main::@7
Successful SSA optimization Pass2ConditionalJumpSimplification
Inlining constant with var siblings main::i#0
Inlining constant with var siblings main::pos#0
Constant inlined main::i#0 = 0
Constant inlined main::pos#0 = 1
Successful SSA optimization Pass2ConstantInlining
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@2
Adding NOP phi() at start of main::@5
CALL GRAPH
Created 2 initial phi equivalence classes
Coalesced [11] main::i#8 = main::i#1
Coalesced [12] main::pos#5 = main::pos#1
Coalesced down to 2 phi equivalence classes
Culled Empty Block label main::@2
Culled Empty Block label main::@7
Renumbering block main::@3 to main::@2
Renumbering block main::@4 to main::@3
Renumbering block main::@5 to main::@4
Renumbering block main::@6 to main::@5
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@4
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@5
[1] main::i#2 = phi( main/0, main::@5/main::i#1 )
[2] if(main::i#2!=8) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1 main::@3
[4] main::pos#2 = phi( main::@1/1, main::@3/main::pos#1 )
[5] main::pos#1 = main::pos#2 + main::move
[6] if(0==main::pos#1) goto main::@3
to:main::@4
main::@4: scope:[main] from main::@2
[7] phi()
to:main::@3
main::@3: scope:[main] from main::@2 main::@4
[8] if(0!=main::pos#1) goto main::@2
to:main::@5
main::@5: scope:[main] from main::@3
[9] main::i#1 = ++ main::i#2
to:main::@1
VARIABLE REGISTER WEIGHTS
void main()
byte main::i
byte main::i#1 22.0
byte main::i#2 4.714285714285714
byte main::pos
byte main::pos#1 101.0
byte main::pos#2 202.0
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
[ main::pos#2 main::pos#1 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::pos#2 main::pos#1 ]
Allocated zp[1]:2 [ main::i#2 main::i#1 ]
Allocated zp[1]:3 [ main::pos#2 main::pos#1 ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [5] main::pos#1 = main::pos#2 + main::move [ main::i#2 main::pos#1 ] ( [ main::i#2 main::pos#1 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ]
Statement [5] main::pos#1 = main::pos#2 + main::move [ main::i#2 main::pos#1 ] ( [ main::i#2 main::pos#1 ] { } ) always clobbers reg byte a
Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 , reg byte x , reg byte y ,
Potential registers zp[1]:3 [ main::pos#2 main::pos#1 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 303: zp[1]:3 [ main::pos#2 main::pos#1 ] 26.71: zp[1]:2 [ main::i#2 main::i#1 ]
Uplift Scope []
Uplifting [main] best 2911 combination reg byte a [ main::pos#2 main::pos#1 ] reg byte x [ main::i#2 main::i#1 ]
Uplifting [] best 2911 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Demonstrates error "Block referenced, but not found in program."
// Upstart
// Commodore 64 PRG executable file
.file [name="block-error-1.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.segment Code
// main
main: {
.const move = 1
// [1] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [1] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
jmp __b1
// main::@1
__b1:
// [2] if(main::i#2!=8) goto main::@2 -- vbuxx_neq_vbuc1_then_la1
cpx #8
bne __b2_from___b1
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
// [4] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
__b2_from___b1:
// [4] phi main::pos#2 = 1 [phi:main::@1->main::@2#0] -- vbuaa=vbuc1
lda #1
jmp __b2
// [4] phi from main::@3 to main::@2 [phi:main::@3->main::@2]
__b2_from___b3:
// [4] phi main::pos#2 = main::pos#1 [phi:main::@3->main::@2#0] -- register_copy
jmp __b2
// main::@2
__b2:
// [5] main::pos#1 = main::pos#2 + main::move -- vbuaa=vbuaa_plus_vbuc1
clc
adc #move
// [6] if(0==main::pos#1) goto main::@3 -- 0_eq_vbuaa_then_la1
cmp #0
beq __b3
// [7] phi from main::@2 to main::@4 [phi:main::@2->main::@4]
__b4_from___b2:
jmp __b4
// main::@4
__b4:
jmp __b3
// main::@3
__b3:
// [8] if(0!=main::pos#1) goto main::@2 -- 0_neq_vbuaa_then_la1
cmp #0
bne __b2_from___b3
jmp __b5
// main::@5
__b5:
// [9] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx
inx
// [1] phi from main::@5 to main::@1 [phi:main::@5->main::@1]
__b1_from___b5:
// [1] phi main::i#2 = main::i#1 [phi:main::@5->main::@1#0] -- register_copy
jmp __b1
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __breturn
Removing instruction jmp __b2
Removing instruction jmp __b4
Removing instruction jmp __b3
Removing instruction jmp __b5
Succesful ASM optimization Pass5NextJumpElimination
Replacing label __b2_from___b3 with __b2
Removing instruction __b2_from___b3:
Removing instruction __b4_from___b2:
Removing instruction __b4:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __b1_from_main:
Removing instruction __breturn:
Removing instruction __b5:
Removing instruction __b1_from___b5:
Succesful ASM optimization Pass5UnusedLabelElimination
Relabelling long label __b2_from___b1 to __b4
Succesful ASM optimization Pass5RelabelLongLabels
Removing instruction jmp __b2
Removing instruction beq __b3
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __b3:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
void main()
byte main::i
byte main::i#1 reg byte x 22.0
byte main::i#2 reg byte x 4.714285714285714
constant byte main::move = 1
byte main::pos
byte main::pos#1 reg byte a 101.0
byte main::pos#2 reg byte a 202.0
reg byte x [ main::i#2 main::i#1 ]
reg byte a [ main::pos#2 main::pos#1 ]
FINAL ASSEMBLER
Score: 1371
// File Comments
// Demonstrates error "Block referenced, but not found in program."
// Upstart
// Commodore 64 PRG executable file
.file [name="block-error-1.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.segment Code
// main
main: {
.const move = 1
// [1] phi from main to main::@1 [phi:main->main::@1]
// [1] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
// main::@1
__b1:
// for(char i=0;i!=8;i++)
// [2] if(main::i#2!=8) goto main::@2 -- vbuxx_neq_vbuc1_then_la1
cpx #8
bne __b4
// main::@return
// }
// [3] return
rts
// [4] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
__b4:
// [4] phi main::pos#2 = 1 [phi:main::@1->main::@2#0] -- vbuaa=vbuc1
lda #1
// [4] phi from main::@3 to main::@2 [phi:main::@3->main::@2]
// [4] phi main::pos#2 = main::pos#1 [phi:main::@3->main::@2#0] -- register_copy
// main::@2
__b2:
// pos += move
// [5] main::pos#1 = main::pos#2 + main::move -- vbuaa=vbuaa_plus_vbuc1
clc
adc #move
// if(pos)
// [6] if(0==main::pos#1) goto main::@3 -- 0_eq_vbuaa_then_la1
cmp #0
// [7] phi from main::@2 to main::@4 [phi:main::@2->main::@4]
// main::@4
// main::@3
// while(pos && vacant)
// [8] if(0!=main::pos#1) goto main::@2 -- 0_neq_vbuaa_then_la1
cmp #0
bne __b2
// main::@5
// for(char i=0;i!=8;i++)
// [9] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx
inx
// [1] phi from main::@5 to main::@1 [phi:main::@5->main::@1]
// [1] phi main::i#2 = main::i#1 [phi:main::@5->main::@1#0] -- register_copy
jmp __b1
}
// File Data

View File

@ -0,0 +1,11 @@
void main()
byte main::i
byte main::i#1 reg byte x 22.0
byte main::i#2 reg byte x 4.714285714285714
constant byte main::move = 1
byte main::pos
byte main::pos#1 reg byte a 101.0
byte main::pos#2 reg byte a 202.0
reg byte x [ main::i#2 main::i#1 ]
reg byte a [ main::pos#2 main::pos#1 ]

View File

@ -0,0 +1,32 @@
// Demonstrates error "Sequence does not contain all blocks from the program."
// Commodore 64 PRG executable file
.file [name="block-error-2.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.segment Code
main: {
.const move = 1
ldx #1
txa
__b1:
// pos += move
clc
adc #move
// if(pos)
cmp #0
beq __b2
ldx #0
__b2:
// while(pos && vacant)
cmp #0
beq __breturn
cpx #0
bne __b1
__breturn:
// }
rts
}

View File

@ -0,0 +1,24 @@
void main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@3
[1] main::vacant#3 = phi( main/1, main::@3/main::vacant#2 )
[1] main::pos#2 = phi( main/1, main::@3/main::pos#1 )
[2] main::pos#1 = main::pos#2 + main::move
[3] if(0==main::pos#1) goto main::@4
to:main::@2
main::@4: scope:[main] from main::@1
[4] phi()
to:main::@2
main::@2: scope:[main] from main::@1 main::@4
[5] main::vacant#2 = phi( main::@4/main::vacant#3, main::@1/0 )
[6] if(0==main::pos#1) goto main::@return
to:main::@3
main::@3: scope:[main] from main::@2
[7] if(0!=main::vacant#2) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@2 main::@3
[8] return
to:@return

View File

@ -0,0 +1,357 @@
CONTROL FLOW GRAPH SSA
void main()
main: scope:[main] from __start
main::pos#0 = 1
main::vacant#0 = 1
to:main::@1
main::@1: scope:[main] from main main::@2
main::vacant#3 = phi( main/main::vacant#0, main::@2/main::vacant#2 )
main::pos#2 = phi( main/main::pos#0, main::@2/main::pos#3 )
main::pos#1 = main::pos#2 + main::move
main::$2 = 0 != main::pos#1
main::$0 = ! main::$2
if(main::$0) goto main::@2
to:main::@3
main::@2: scope:[main] from main::@1 main::@3
main::vacant#2 = phi( main::@1/main::vacant#3, main::@3/main::vacant#1 )
main::pos#3 = phi( main::@1/main::pos#1, main::@3/main::pos#4 )
main::$1 = main::pos#3 && main::vacant#2
if(main::$1) goto main::@1
to:main::@return
main::@3: scope:[main] from main::@1
main::pos#4 = phi( main::@1/main::pos#1 )
main::vacant#1 = 0
to:main::@2
main::@return: scope:[main] from main::@2
return
to:@return
void __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
void __start()
void main()
bool~ main::$0
bool~ main::$1
bool~ main::$2
constant byte main::move = 1
byte main::pos
byte main::pos#0
byte main::pos#1
byte main::pos#2
byte main::pos#3
byte main::pos#4
byte main::vacant
byte main::vacant#0
byte main::vacant#1
byte main::vacant#2
byte main::vacant#3
Adding number conversion cast (unumber) 0 in main::$2 = 0 != main::pos#1
Adding number conversion cast (unumber) 0 in main::vacant#1 = 0
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast main::vacant#1 = (unumber)0
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast 0
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inversing boolean not [5] main::$0 = 0 == main::pos#1 from [4] main::$2 = 0 != main::pos#1
Successful SSA optimization Pass2UnaryNotSimplification
Alias main::pos#1 = main::pos#4
Successful SSA optimization Pass2AliasElimination
Alias main::pos#1 = main::pos#3
Successful SSA optimization Pass2AliasElimination
Simple Condition main::$0 [5] if(0==main::pos#1) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Rewriting && if()-condition to two if()s [7] main::$1 = main::pos#1 && main::vacant#2
Successful SSA optimization Pass2ConditionalAndOrRewriting
Warning! Adding boolean cast to non-boolean condition main::pos#1
Warning! Adding boolean cast to non-boolean condition main::vacant#2
Constant main::pos#0 = 1
Constant main::vacant#0 = 1
Constant main::vacant#1 = 0
Successful SSA optimization Pass2ConstantIdentification
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Adding number conversion cast (unumber) 0 in [4] main::$3 = 0 != main::pos#1
Adding number conversion cast (unumber) 0 in [9] main::$4 = 0 != main::vacant#2
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast 0
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Simple Condition main::$3 [5] if(0!=main::pos#1) goto main::@4
Simple Condition main::$4 [8] if(0!=main::vacant#2) goto main::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Negating conditional jump and destination [5] if(0==main::pos#1) goto main::@return
Successful SSA optimization Pass2ConditionalJumpSequenceImprovement
Inlining constant with var siblings main::pos#0
Inlining constant with var siblings main::vacant#0
Inlining constant with var siblings main::vacant#1
Constant inlined main::vacant#0 = 1
Constant inlined main::vacant#1 = 0
Constant inlined main::pos#0 = 1
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting main::@5(between main::@4 and main::@1)
Added new block during phi lifting main::@6(between main::@1 and main::@2)
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@3
CALL GRAPH
Created 3 initial phi equivalence classes
Coalesced [9] main::pos#5 = main::pos#1
Coalesced [10] main::vacant#4 = main::vacant#2
Coalesced (already) [11] main::vacant#5 = main::vacant#3
Coalesced down to 2 phi equivalence classes
Culled Empty Block label main::@3
Culled Empty Block label main::@5
Renumbering block main::@4 to main::@3
Renumbering block main::@6 to main::@4
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@4
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@3
[1] main::vacant#3 = phi( main/1, main::@3/main::vacant#2 )
[1] main::pos#2 = phi( main/1, main::@3/main::pos#1 )
[2] main::pos#1 = main::pos#2 + main::move
[3] if(0==main::pos#1) goto main::@4
to:main::@2
main::@4: scope:[main] from main::@1
[4] phi()
to:main::@2
main::@2: scope:[main] from main::@1 main::@4
[5] main::vacant#2 = phi( main::@4/main::vacant#3, main::@1/0 )
[6] if(0==main::pos#1) goto main::@return
to:main::@3
main::@3: scope:[main] from main::@2
[7] if(0!=main::vacant#2) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@2 main::@3
[8] return
to:@return
VARIABLE REGISTER WEIGHTS
void main()
byte main::pos
byte main::pos#1 7.333333333333333
byte main::pos#2 22.0
byte main::vacant
byte main::vacant#2 11.0
byte main::vacant#3 5.5
Initial phi equivalence classes
[ main::pos#2 main::pos#1 ]
[ main::vacant#3 main::vacant#2 ]
Complete equivalence classes
[ main::pos#2 main::pos#1 ]
[ main::vacant#3 main::vacant#2 ]
Allocated zp[1]:2 [ main::pos#2 main::pos#1 ]
Allocated zp[1]:3 [ main::vacant#3 main::vacant#2 ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [2] main::pos#1 = main::pos#2 + main::move [ main::vacant#3 main::pos#1 ] ( [ main::vacant#3 main::pos#1 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:3 [ main::vacant#3 main::vacant#2 ]
Statement [2] main::pos#1 = main::pos#2 + main::move [ main::vacant#3 main::pos#1 ] ( [ main::vacant#3 main::pos#1 ] { } ) always clobbers reg byte a
Potential registers zp[1]:2 [ main::pos#2 main::pos#1 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:3 [ main::vacant#3 main::vacant#2 ] : zp[1]:3 , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 29.33: zp[1]:2 [ main::pos#2 main::pos#1 ] 16.5: zp[1]:3 [ main::vacant#3 main::vacant#2 ]
Uplift Scope []
Uplifting [main] best 451 combination reg byte a [ main::pos#2 main::pos#1 ] reg byte x [ main::vacant#3 main::vacant#2 ]
Uplifting [] best 451 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Demonstrates error "Sequence does not contain all blocks from the program."
// Upstart
// Commodore 64 PRG executable file
.file [name="block-error-2.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.segment Code
// main
main: {
.const move = 1
// [1] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [1] phi main::vacant#3 = 1 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #1
// [1] phi main::pos#2 = 1 [phi:main->main::@1#1] -- vbuaa=vbuc1
lda #1
jmp __b1
// [1] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
__b1_from___b3:
// [1] phi main::vacant#3 = main::vacant#2 [phi:main::@3->main::@1#0] -- register_copy
// [1] phi main::pos#2 = main::pos#1 [phi:main::@3->main::@1#1] -- register_copy
jmp __b1
// main::@1
__b1:
// [2] main::pos#1 = main::pos#2 + main::move -- vbuaa=vbuaa_plus_vbuc1
clc
adc #move
// [3] if(0==main::pos#1) goto main::@4 -- 0_eq_vbuaa_then_la1
cmp #0
beq __b4_from___b1
// [5] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
__b2_from___b1:
// [5] phi main::vacant#2 = 0 [phi:main::@1->main::@2#0] -- vbuxx=vbuc1
ldx #0
jmp __b2
// [4] phi from main::@1 to main::@4 [phi:main::@1->main::@4]
__b4_from___b1:
jmp __b4
// main::@4
__b4:
// [5] phi from main::@4 to main::@2 [phi:main::@4->main::@2]
__b2_from___b4:
// [5] phi main::vacant#2 = main::vacant#3 [phi:main::@4->main::@2#0] -- register_copy
jmp __b2
// main::@2
__b2:
// [6] if(0==main::pos#1) goto main::@return -- 0_eq_vbuaa_then_la1
cmp #0
beq __breturn
jmp __b3
// main::@3
__b3:
// [7] if(0!=main::vacant#2) goto main::@1 -- 0_neq_vbuxx_then_la1
cpx #0
bne __b1_from___b3
jmp __breturn
// main::@return
__breturn:
// [8] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __b4
Removing instruction jmp __b2
Removing instruction jmp __b3
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing instruction lda #1 with TXA
Replacing label __b4_from___b1 with __b2
Replacing label __b1_from___b3 with __b1
Removing instruction __b1_from___b3:
Removing instruction __b4_from___b1:
Removing instruction __b4:
Removing instruction __b2_from___b4:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __b1_from_main:
Removing instruction __b2_from___b1:
Removing instruction __b3:
Succesful ASM optimization Pass5UnusedLabelElimination
Removing instruction jmp __b1
Removing instruction jmp __b2
Succesful ASM optimization Pass5NextJumpElimination
FINAL SYMBOL TABLE
void main()
constant byte main::move = 1
byte main::pos
byte main::pos#1 reg byte a 7.333333333333333
byte main::pos#2 reg byte a 22.0
byte main::vacant
byte main::vacant#2 reg byte x 11.0
byte main::vacant#3 reg byte x 5.5
reg byte a [ main::pos#2 main::pos#1 ]
reg byte x [ main::vacant#3 main::vacant#2 ]
FINAL ASSEMBLER
Score: 241
// File Comments
// Demonstrates error "Sequence does not contain all blocks from the program."
// Upstart
// Commodore 64 PRG executable file
.file [name="block-error-2.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.segment Code
// main
main: {
.const move = 1
// [1] phi from main to main::@1 [phi:main->main::@1]
// [1] phi main::vacant#3 = 1 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #1
// [1] phi main::pos#2 = 1 [phi:main->main::@1#1] -- vbuaa=vbuc1
txa
// [1] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
// [1] phi main::vacant#3 = main::vacant#2 [phi:main::@3->main::@1#0] -- register_copy
// [1] phi main::pos#2 = main::pos#1 [phi:main::@3->main::@1#1] -- register_copy
// main::@1
__b1:
// pos += move
// [2] main::pos#1 = main::pos#2 + main::move -- vbuaa=vbuaa_plus_vbuc1
clc
adc #move
// if(pos)
// [3] if(0==main::pos#1) goto main::@4 -- 0_eq_vbuaa_then_la1
cmp #0
beq __b2
// [5] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
// [5] phi main::vacant#2 = 0 [phi:main::@1->main::@2#0] -- vbuxx=vbuc1
ldx #0
// [4] phi from main::@1 to main::@4 [phi:main::@1->main::@4]
// main::@4
// [5] phi from main::@4 to main::@2 [phi:main::@4->main::@2]
// [5] phi main::vacant#2 = main::vacant#3 [phi:main::@4->main::@2#0] -- register_copy
// main::@2
__b2:
// while(pos && vacant)
// [6] if(0==main::pos#1) goto main::@return -- 0_eq_vbuaa_then_la1
cmp #0
beq __breturn
// main::@3
// [7] if(0!=main::vacant#2) goto main::@1 -- 0_neq_vbuxx_then_la1
cpx #0
bne __b1
// main::@return
__breturn:
// }
// [8] return
rts
}
// File Data

View File

@ -0,0 +1,11 @@
void main()
constant byte main::move = 1
byte main::pos
byte main::pos#1 reg byte a 7.333333333333333
byte main::pos#2 reg byte a 22.0
byte main::vacant
byte main::vacant#2 reg byte x 11.0
byte main::vacant#3 reg byte x 5.5
reg byte a [ main::pos#2 main::pos#1 ]
reg byte x [ main::vacant#3 main::vacant#2 ]