1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-04-07 06:37:31 +00:00

Added a few fragments - and some tests illustrating certain problems.

This commit is contained in:
jespergravgaard 2019-08-18 20:59:57 +02:00
parent 3c12acbb43
commit 55b7dfdf91
25 changed files with 2242 additions and 0 deletions

View File

@ -0,0 +1,9 @@
lda {c2}
sta $fe
lda {c2}+1
sta $ff
lda ($fe),y
sta {c1},y
iny
lda ($fe),y
sta {c1},y

View File

@ -0,0 +1,5 @@
lda {c1}
sta !+ +1
lda {c1}+1
sta !+ +2
!: lda {c1},x

View File

@ -0,0 +1,5 @@
lda {c1}
sta !+ +1
lda {c1}+1
sta !+ +2
!: lda {c1},y

View File

@ -36,6 +36,11 @@ public class TestPrograms {
public TestPrograms() {
}
@Test
public void testCodeAfterReturn() throws IOException, URISyntaxException {
compileAndCompare("code-after-return",log());
}
@Test
public void testStringEscapesErr1() throws IOException, URISyntaxException {
assertError("string-escapes-err-1", "Illegal string escape sequence");
@ -416,6 +421,12 @@ public class TestPrograms {
compileAndCompare("enum-0");
}
// TODO: Fix https://gitlab.com/camelot/kickc/issues/269
//@Test
//public void testTypedef2() throws IOException, URISyntaxException {
// compileAndCompare("typedef-2");
//}
@Test
public void testTypedef1() throws IOException, URISyntaxException {
compileAndCompare("typedef-1");
@ -481,6 +492,16 @@ public class TestPrograms {
}
*/
@Test
public void testStructPtr21() throws IOException, URISyntaxException {
compileAndCompare("struct-ptr-21");
}
@Test
public void testStructPtr20() throws IOException, URISyntaxException {
compileAndCompare("struct-ptr-20");
}
@Test
public void testStructPtr19() throws IOException, URISyntaxException {
compileAndCompare("struct-ptr-19");
@ -1351,6 +1372,11 @@ public class TestPrograms {
compileAndCompare("loop-break-continue");
}
@Test
public void testLoopForEmptyBody() throws IOException, URISyntaxException {
compileAndCompare("loop-for-empty-body");
}
@Test
public void testLoopForContinue() throws IOException, URISyntaxException {
compileAndCompare("loop-for-continue");

View File

@ -0,0 +1,9 @@
// Test code after return in main()
const char* SCREEN = 0x0400;
void main() {
SCREEN[0] = 'a';
return;
SCREEN[1] = 'a';
}

View File

@ -0,0 +1,10 @@
// Test a for-loop with an empty body
const char[] str = "Hello!";
const char* SCREEN = 0x0400;
void main() {
char b = 0;
for (; str[b] != 0; ++b) {} // Empty body
SCREEN[0] = '0'+b;
}

View File

@ -0,0 +1,25 @@
// Demonstrates problem with conditions using negated struct references
const char* SCREEN = 0x0400;
struct Setting {
char off;
char id;
};
const struct Setting[] settings = {
{ 0, 'a' },
{ 1, 'b' },
{ 0, 'c' }
};
void main() {
char idx = 0;
char len = sizeof(settings)/sizeof(struct Setting);
for(struct Setting* setting = settings; setting<settings+len; setting++) {
if (! setting->off) {
SCREEN[idx++] = setting->id;
}
}
}

View File

@ -0,0 +1,22 @@
// Demonstrates problem with conditions using negated struct references
const unsigned int* SCREEN = 0x0400;
struct Setting {
char len;
unsigned int* buf;
};
unsigned int[] seq = { 1, 2, 3 };
struct Setting[] settings = { { 3, &seq[0] } };
void main() {
struct Setting *setting = &settings[0];
char idx = 0;
for( char i=0;i<setting->len;i++) {
SCREEN[i] = setting->buf[i];
}
}

12
src/test/kc/typedef-2.kc Normal file
View File

@ -0,0 +1,12 @@
typedef unsigned int WORD;
const char* SCREEN = 0x0400;
char* ptr = 0x1000;
void main() {
WORD w = (WORD)&ptr;
w += 50;
SCREEN[0] = <w;
}

View File

@ -0,0 +1,10 @@
// Test code after return in main()
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label SCREEN = $400
main: {
lda #'a'
sta SCREEN
rts
}

View File

@ -0,0 +1,15 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] *((const byte*) SCREEN#0) ← (byte) 'a'
to:main::@return
main::@return: scope:[main] from main
[5] return
to:@return

View File

@ -0,0 +1,231 @@
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte*) SCREEN#0 ← ((byte*)) (number) $400
to:@1
main: scope:[main] from @1
*((byte*) SCREEN#0 + (number) 0) ← (byte) 'a'
to:main::@return
main::@return: scope:[main] from main main::@1
return
to:@return
main::@1: scope:[main] from
*((byte*) SCREEN#0 + (number) 1) ← (byte) 'a'
to:main::@return
@1: scope:[] from @begin
call main
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @begin
(label) @end
(byte*) SCREEN
(byte*) SCREEN#0
(void()) main()
(label) main::@1
(label) main::@return
Adding number conversion cast (unumber) 0 in *((byte*) SCREEN#0 + (number) 0) ← (byte) 'a'
Adding number conversion cast (unumber) 1 in *((byte*) SCREEN#0 + (number) 1) ← (byte) 'a'
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400
Successful SSA optimization Pass2InlineCast
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Simplifying constant integer cast 1
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 1
Successful SSA optimization PassNFinalizeNumberTypeConversions
Constant (const byte*) SCREEN#0 = (byte*) 1024
Successful SSA optimization Pass2ConstantIdentification
Simplifying expression containing zero SCREEN#0 in [1] *((const byte*) SCREEN#0 + (byte) 0) ← (byte) 'a'
Successful SSA optimization PassNSimplifyExpressionWithZero
Removing unused block main::@1
Successful SSA optimization Pass2EliminateUnusedBlocks
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
CALL GRAPH
Calls in [] to main:2
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
Culled Empty Block (label) @2
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] *((const byte*) SCREEN#0) ← (byte) 'a'
to:main::@return
main::@return: scope:[main] from main
[5] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte*) SCREEN
(void()) main()
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
Target platform is c64basic
// File Comments
// Test code after return in main()
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
// [4] *((const byte*) SCREEN#0) ← (byte) 'a' -- _deref_pbuc1=vbuc2
lda #'a'
sta SCREEN
jmp breturn
// main::@return
breturn:
// [5] return
rts
}
// File Data
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] *((const byte*) SCREEN#0) ← (byte) 'a' [ ] ( main:2 [ ] ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [main]
Uplift Scope []
Uplifting [main] best 27 combination
Uplifting [] best 27 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test code after return in main()
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
// [4] *((const byte*) SCREEN#0) ← (byte) 'a' -- _deref_pbuc1=vbuc2
lda #'a'
sta SCREEN
jmp breturn
// main::@return
breturn:
// [5] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction bend_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(void()) main()
(label) main::@return
FINAL ASSEMBLER
Score: 12
// File Comments
// Test code after return in main()
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
// SCREEN[0] = 'a'
// [4] *((const byte*) SCREEN#0) ← (byte) 'a' -- _deref_pbuc1=vbuc2
lda #'a'
sta SCREEN
// main::@return
// }
// [5] return
rts
}
// File Data

View File

@ -0,0 +1,8 @@
(label) @1
(label) @begin
(label) @end
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(void()) main()
(label) main::@return

View File

@ -0,0 +1,22 @@
// Test a for-loop with an empty body
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label SCREEN = $400
main: {
ldx #0
b1:
lda str,x
cmp #0
bne b2
txa
axs #-['0']
// Empty body
stx SCREEN
rts
b2:
inx
jmp b1
}
str: .text "Hello!"
.byte 0

View File

@ -0,0 +1,26 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[5] (byte) main::b#2 ← phi( main/(byte) 0 main::@2/(byte) main::b#1 )
[6] if(*((const byte[]) str#0 + (byte) main::b#2)!=(byte) 0) goto main::@2
to:main::@3
main::@3: scope:[main] from main::@1
[7] (byte~) main::$0 ← (byte) '0' + (byte) main::b#2
[8] *((const byte*) SCREEN#0) ← (byte~) main::$0
to:main::@return
main::@return: scope:[main] from main::@3
[9] return
to:@return
main::@2: scope:[main] from main::@1
[10] (byte) main::b#1 ← ++ (byte) main::b#2
to:main::@1

View File

@ -0,0 +1,409 @@
Culled Empty Block (label) main::@4
Culled Empty Block (label) main::@5
Culled Empty Block (label) main::@6
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte[]) str#0 ← (const string) $0
(byte*) SCREEN#0 ← ((byte*)) (number) $400
to:@1
main: scope:[main] from @1
(byte) main::b#0 ← (number) 0
to:main::@1
main::@1: scope:[main] from main main::@2
(byte) main::b#2 ← phi( main/(byte) main::b#0 main::@2/(byte) main::b#1 )
(bool~) main::$1 ← *((byte[]) str#0 + (byte) main::b#2) != (number) 0
if((bool~) main::$1) goto main::@2
to:main::@3
main::@2: scope:[main] from main::@1
(byte) main::b#3 ← phi( main::@1/(byte) main::b#2 )
(byte) main::b#1 ← ++ (byte) main::b#3
to:main::@1
main::@3: scope:[main] from main::@1
(byte) main::b#4 ← phi( main::@1/(byte) main::b#2 )
(byte~) main::$0 ← (byte) '0' + (byte) main::b#4
*((byte*) SCREEN#0 + (number) 0) ← (byte~) main::$0
to:main::@return
main::@return: scope:[main] from main::@3
return
to:@return
@1: scope:[] from @begin
call main
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(const string) $0 = (string) "Hello!"
(label) @1
(label) @2
(label) @begin
(label) @end
(byte*) SCREEN
(byte*) SCREEN#0
(void()) main()
(byte~) main::$0
(bool~) main::$1
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@return
(byte) main::b
(byte) main::b#0
(byte) main::b#1
(byte) main::b#2
(byte) main::b#3
(byte) main::b#4
(byte[]) str
(byte[]) str#0
Adding number conversion cast (unumber) 0 in (byte) main::b#0 ← (number) 0
Adding number conversion cast (unumber) 0 in (bool~) main::$1 ← *((byte[]) str#0 + (byte) main::b#2) != (number) 0
Adding number conversion cast (unumber) 0 in *((byte*) SCREEN#0 + (number) 0) ← (byte~) main::$0
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400
Inlining cast (byte) main::b#0 ← (unumber)(number) 0
Successful SSA optimization Pass2InlineCast
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
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
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias (byte) main::b#2 = (byte) main::b#3 (byte) main::b#4
Successful SSA optimization Pass2AliasElimination
Simple Condition (bool~) main::$1 [5] if(*((byte[]) str#0 + (byte) main::b#2)!=(byte) 0) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte[]) str#0 = $0
Constant (const byte*) SCREEN#0 = (byte*) 1024
Constant (const byte) main::b#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Simplifying expression containing zero SCREEN#0 in [10] *((const byte*) SCREEN#0 + (byte) 0) ← (byte~) main::$0
Successful SSA optimization PassNSimplifyExpressionWithZero
Inlining constant with var siblings (const byte) main::b#0
Constant inlined $0 = (const byte[]) str#0
Constant inlined main::b#0 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
CALL GRAPH
Calls in [] to main:2
Created 1 initial phi equivalence classes
Coalesced [12] main::b#5 ← main::b#1
Coalesced down to 1 phi equivalence classes
Culled Empty Block (label) @2
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[5] (byte) main::b#2 ← phi( main/(byte) 0 main::@2/(byte) main::b#1 )
[6] if(*((const byte[]) str#0 + (byte) main::b#2)!=(byte) 0) goto main::@2
to:main::@3
main::@3: scope:[main] from main::@1
[7] (byte~) main::$0 ← (byte) '0' + (byte) main::b#2
[8] *((const byte*) SCREEN#0) ← (byte~) main::$0
to:main::@return
main::@return: scope:[main] from main::@3
[9] return
to:@return
main::@2: scope:[main] from main::@1
[10] (byte) main::b#1 ← ++ (byte) main::b#2
to:main::@1
VARIABLE REGISTER WEIGHTS
(byte*) SCREEN
(void()) main()
(byte~) main::$0 4.0
(byte) main::b
(byte) main::b#1 22.0
(byte) main::b#2 17.5
(byte[]) str
Initial phi equivalence classes
[ main::b#2 main::b#1 ]
Added variable main::$0 to zero page equivalence class [ main::$0 ]
Complete equivalence classes
[ main::b#2 main::b#1 ]
[ main::$0 ]
Allocated zp ZP_BYTE:2 [ main::b#2 main::b#1 ]
Allocated zp ZP_BYTE:3 [ main::$0 ]
INITIAL ASM
Target platform is c64basic
// File Comments
// Test a for-loop with an empty body
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
.label _0 = 3
.label b = 2
// [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
// [5] phi (byte) main::b#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z b
jmp b1
// main::@1
b1:
// [6] if(*((const byte[]) str#0 + (byte) main::b#2)!=(byte) 0) goto main::@2 -- pbuc1_derefidx_vbuz1_neq_0_then_la1
ldy.z b
lda str,y
cmp #0
bne b2
jmp b3
// main::@3
b3:
// [7] (byte~) main::$0 ← (byte) '0' + (byte) main::b#2 -- vbuz1=vbuc1_plus_vbuz2
lax.z b
axs #-['0']
stx.z _0
// [8] *((const byte*) SCREEN#0) ← (byte~) main::$0 -- _deref_pbuc1=vbuz1
// Empty body
lda.z _0
sta SCREEN
jmp breturn
// main::@return
breturn:
// [9] return
rts
// main::@2
b2:
// [10] (byte) main::b#1 ← ++ (byte) main::b#2 -- vbuz1=_inc_vbuz1
inc.z b
// [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
b1_from_b2:
// [5] phi (byte) main::b#2 = (byte) main::b#1 [phi:main::@2->main::@1#0] -- register_copy
jmp b1
}
// File Data
str: .text "Hello!"
.byte 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [6] if(*((const byte[]) str#0 + (byte) main::b#2)!=(byte) 0) goto main::@2 [ main::b#2 ] ( main:2 [ main::b#2 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::b#2 main::b#1 ]
Statement [7] (byte~) main::$0 ← (byte) '0' + (byte) main::b#2 [ main::$0 ] ( main:2 [ main::$0 ] ) always clobbers reg byte a
Statement [6] if(*((const byte[]) str#0 + (byte) main::b#2)!=(byte) 0) goto main::@2 [ main::b#2 ] ( main:2 [ main::b#2 ] ) always clobbers reg byte a
Statement [7] (byte~) main::$0 ← (byte) '0' + (byte) main::b#2 [ main::$0 ] ( main:2 [ main::$0 ] ) always clobbers reg byte a
Potential registers zp ZP_BYTE:2 [ main::b#2 main::b#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:3 [ main::$0 ] : zp ZP_BYTE:3 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 39.5: zp ZP_BYTE:2 [ main::b#2 main::b#1 ] 4: zp ZP_BYTE:3 [ main::$0 ]
Uplift Scope []
Uplifting [main] best 249 combination reg byte x [ main::b#2 main::b#1 ] reg byte x [ main::$0 ]
Uplifting [] best 249 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test a for-loop with an empty body
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
// [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
// [5] phi (byte) main::b#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
jmp b1
// main::@1
b1:
// [6] if(*((const byte[]) str#0 + (byte) main::b#2)!=(byte) 0) goto main::@2 -- pbuc1_derefidx_vbuxx_neq_0_then_la1
lda str,x
cmp #0
bne b2
jmp b3
// main::@3
b3:
// [7] (byte~) main::$0 ← (byte) '0' + (byte) main::b#2 -- vbuxx=vbuc1_plus_vbuxx
txa
axs #-['0']
// [8] *((const byte*) SCREEN#0) ← (byte~) main::$0 -- _deref_pbuc1=vbuxx
// Empty body
stx SCREEN
jmp breturn
// main::@return
breturn:
// [9] return
rts
// main::@2
b2:
// [10] (byte) main::b#1 ← ++ (byte) main::b#2 -- vbuxx=_inc_vbuxx
inx
// [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
b1_from_b2:
// [5] phi (byte) main::b#2 = (byte) main::b#1 [phi:main::@2->main::@1#0] -- register_copy
jmp b1
}
// File Data
str: .text "Hello!"
.byte 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp b3
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction b1_from_main:
Removing instruction b3:
Removing instruction breturn:
Removing instruction b1_from_b2:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(void()) main()
(byte~) main::$0 reg byte x 4.0
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@return
(byte) main::b
(byte) main::b#1 reg byte x 22.0
(byte) main::b#2 reg byte x 17.5
(byte[]) str
(const byte[]) str#0 str = (string) "Hello!"
reg byte x [ main::b#2 main::b#1 ]
reg byte x [ main::$0 ]
FINAL ASSEMBLER
Score: 174
// File Comments
// Test a for-loop with an empty body
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
// [5] phi from main to main::@1 [phi:main->main::@1]
// [5] phi (byte) main::b#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
// main::@1
b1:
// for (; str[b] != 0; ++b)
// [6] if(*((const byte[]) str#0 + (byte) main::b#2)!=(byte) 0) goto main::@2 -- pbuc1_derefidx_vbuxx_neq_0_then_la1
lda str,x
cmp #0
bne b2
// main::@3
// '0'+b
// [7] (byte~) main::$0 ← (byte) '0' + (byte) main::b#2 -- vbuxx=vbuc1_plus_vbuxx
txa
axs #-['0']
// SCREEN[0] = '0'+b
// [8] *((const byte*) SCREEN#0) ← (byte~) main::$0 -- _deref_pbuc1=vbuxx
// Empty body
stx SCREEN
// main::@return
// }
// [9] return
rts
// main::@2
b2:
// for (; str[b] != 0; ++b)
// [10] (byte) main::b#1 ← ++ (byte) main::b#2 -- vbuxx=_inc_vbuxx
inx
// [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
// [5] phi (byte) main::b#2 = (byte) main::b#1 [phi:main::@2->main::@1#0] -- register_copy
jmp b1
}
// File Data
str: .text "Hello!"
.byte 0

View File

@ -0,0 +1,19 @@
(label) @1
(label) @begin
(label) @end
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(void()) main()
(byte~) main::$0 reg byte x 4.0
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@return
(byte) main::b
(byte) main::b#1 reg byte x 22.0
(byte) main::b#2 reg byte x 17.5
(byte[]) str
(const byte[]) str#0 str = (string) "Hello!"
reg byte x [ main::b#2 main::b#1 ]
reg byte x [ main::$0 ]

View File

@ -0,0 +1,48 @@
// Demonstrates problem with conditions using negated struct references
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const SIZEOF_STRUCT_SETTING = 2
.const OFFSET_STRUCT_SETTING_ID = 1
.label SCREEN = $400
main: {
.const len = 3*SIZEOF_STRUCT_SETTING/SIZEOF_STRUCT_SETTING
.label setting = 2
ldx #0
lda #<settings
sta.z setting
lda #>settings
sta.z setting+1
b1:
lda.z setting+1
cmp #>settings+len*SIZEOF_STRUCT_SETTING
bcc b2
bne !+
lda.z setting
cmp #<settings+len*SIZEOF_STRUCT_SETTING
bcc b2
!:
rts
b2:
ldy #0
lda (setting),y
cmp #0
bne b3
ldy #OFFSET_STRUCT_SETTING_ID
lda (setting),y
sta SCREEN,x
inx
b3:
lda #SIZEOF_STRUCT_SETTING
clc
adc.z setting
sta.z setting
bcc !+
inc.z setting+1
!:
jmp b1
}
settings:
.byte 0, 'a'
.byte 1, 'b'
.byte 0, 'c'

View File

@ -0,0 +1,31 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@3
[5] (byte) main::idx#2 ← phi( main/(byte) 0 main::@3/(byte) main::idx#5 )
[5] (struct Setting*) main::setting#2 ← phi( main/(const struct Setting[]) settings#0 main::@3/(struct Setting*) main::setting#1 )
[6] if((struct Setting*) main::setting#2<(const struct Setting[]) settings#0+(const byte) main::len#0*(const byte) SIZEOF_STRUCT_SETTING) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[7] return
to:@return
main::@2: scope:[main] from main::@1
[8] if((byte) 0!=*((byte*)(struct Setting*) main::setting#2)) goto main::@3
to:main::@4
main::@4: scope:[main] from main::@2
[9] *((const byte*) SCREEN#0 + (byte) main::idx#2) ← *((byte*)(struct Setting*) main::setting#2 + (const byte) OFFSET_STRUCT_SETTING_ID)
[10] (byte) main::idx#1 ← ++ (byte) main::idx#2
to:main::@3
main::@3: scope:[main] from main::@2 main::@4
[11] (byte) main::idx#5 ← phi( main::@2/(byte) main::idx#2 main::@4/(byte) main::idx#1 )
[12] (struct Setting*) main::setting#1 ← (struct Setting*) main::setting#2 + (const byte) SIZEOF_STRUCT_SETTING
to:main::@1

View File

@ -0,0 +1,662 @@
Fixing pointer addition (struct Setting*~) main::$2 ← (struct Setting[]) settings + (byte) main::len
Fixing pointer increment (struct Setting*) main::setting ← ++ (struct Setting*) main::setting
Rewriting struct pointer member access *((struct Setting*) main::setting).off
Rewriting struct pointer member access *((struct Setting*) main::setting).id
Warning! Adding boolean cast to non-boolean sub-expression *((byte*) main::$7)
Culled Empty Block (label) main::@5
Culled Empty Block (label) main::@3
Culled Empty Block (label) main::@6
Culled Empty Block (label) main::@8
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte*) SCREEN#0 ← ((byte*)) (number) $400
(struct Setting[]) settings#0 ← { { (number) 0, (byte) 'a' }, { (number) 1, (byte) 'b' }, { (number) 0, (byte) 'c' } }
to:@1
main: scope:[main] from @1
(byte) main::idx#0 ← (number) 0
(byte~) main::$0 ← sizeof (struct Setting[]) settings#0
(byte~) main::$1 ← (byte~) main::$0 / (const byte) SIZEOF_STRUCT_SETTING
(byte) main::len#0 ← (byte~) main::$1
(struct Setting*) main::setting#0 ← (struct Setting[]) settings#0
to:main::@1
main::@1: scope:[main] from main main::@4
(byte) main::idx#4 ← phi( main/(byte) main::idx#0 main::@4/(byte) main::idx#5 )
(struct Setting*) main::setting#2 ← phi( main/(struct Setting*) main::setting#0 main::@4/(struct Setting*) main::setting#1 )
(byte) main::len#1 ← phi( main/(byte) main::len#0 main::@4/(byte) main::len#2 )
(byte~) main::$6 ← (byte) main::len#1 * (const byte) SIZEOF_STRUCT_SETTING
(struct Setting*~) main::$2 ← (struct Setting[]) settings#0 + (byte~) main::$6
(bool~) main::$3 ← (struct Setting*) main::setting#2 < (struct Setting*~) main::$2
if((bool~) main::$3) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
(byte) main::len#3 ← phi( main::@1/(byte) main::len#1 )
(byte) main::idx#3 ← phi( main::@1/(byte) main::idx#4 )
(struct Setting*) main::setting#3 ← phi( main::@1/(struct Setting*) main::setting#2 )
(byte*) main::$7 ← (byte*)(struct Setting*) main::setting#3 + (const byte) OFFSET_STRUCT_SETTING_OFF
(bool~) main::$9 ← (number) 0 != *((byte*) main::$7)
(bool~) main::$4 ← ! (bool~) main::$9
(bool~) main::$5 ← ! (bool~) main::$4
if((bool~) main::$5) goto main::@4
to:main::@7
main::@4: scope:[main] from main::@2 main::@7
(byte) main::idx#5 ← phi( main::@2/(byte) main::idx#3 main::@7/(byte) main::idx#1 )
(byte) main::len#2 ← phi( main::@2/(byte) main::len#3 main::@7/(byte) main::len#4 )
(struct Setting*) main::setting#4 ← phi( main::@2/(struct Setting*) main::setting#3 main::@7/(struct Setting*) main::setting#5 )
(struct Setting*) main::setting#1 ← (struct Setting*) main::setting#4 + (const byte) SIZEOF_STRUCT_SETTING
to:main::@1
main::@7: scope:[main] from main::@2
(byte) main::len#4 ← phi( main::@2/(byte) main::len#3 )
(byte) main::idx#2 ← phi( main::@2/(byte) main::idx#3 )
(struct Setting*) main::setting#5 ← phi( main::@2/(struct Setting*) main::setting#3 )
(byte*) main::$8 ← (byte*)(struct Setting*) main::setting#5 + (const byte) OFFSET_STRUCT_SETTING_ID
*((byte*) SCREEN#0 + (byte) main::idx#2) ← *((byte*) main::$8)
(byte) main::idx#1 ← ++ (byte) main::idx#2
to:main::@4
main::@return: scope:[main] from main::@1
return
to:@return
@1: scope:[] from @begin
call main
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_SETTING_ID = (byte) 1
(const byte) OFFSET_STRUCT_SETTING_OFF = (byte) 0
(byte*) SCREEN
(byte*) SCREEN#0
(const byte) SIZEOF_STRUCT_SETTING = (byte) 2
(byte) Setting::id
(byte) Setting::off
(void()) main()
(byte~) main::$0
(byte~) main::$1
(struct Setting*~) main::$2
(bool~) main::$3
(bool~) main::$4
(bool~) main::$5
(byte~) main::$6
(byte*) main::$7
(byte*) main::$8
(bool~) main::$9
(label) main::@1
(label) main::@2
(label) main::@4
(label) main::@7
(label) main::@return
(byte) main::idx
(byte) main::idx#0
(byte) main::idx#1
(byte) main::idx#2
(byte) main::idx#3
(byte) main::idx#4
(byte) main::idx#5
(byte) main::len
(byte) main::len#0
(byte) main::len#1
(byte) main::len#2
(byte) main::len#3
(byte) main::len#4
(struct Setting*) main::setting
(struct Setting*) main::setting#0
(struct Setting*) main::setting#1
(struct Setting*) main::setting#2
(struct Setting*) main::setting#3
(struct Setting*) main::setting#4
(struct Setting*) main::setting#5
(struct Setting[]) settings
(struct Setting[]) settings#0
Adding number conversion cast (unumber) 0 in (byte) main::idx#0 ← (number) 0
Adding number conversion cast (unumber) 0 in (bool~) main::$9 ← (number) 0 != *((byte*) main::$7)
Successful SSA optimization PassNAddNumberTypeConversions
Added casts to value list in (struct Setting[]) settings#0 ← (struct Setting[]){ (struct Setting){ (byte)(number) 0, (byte) 'a' }, (struct Setting){ (byte)(number) 1, (byte) 'b' }, (struct Setting){ (byte)(number) 0, (byte) 'c' } }
Successful SSA optimization PassNAddInitializerValueListTypeCasts
Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400
Inlining cast (byte) main::idx#0 ← (unumber)(number) 0
Successful SSA optimization Pass2InlineCast
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Simplifying constant integer cast 1
Simplifying constant integer cast 0
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 [15] (bool~) main::$4 ← (byte) 0 == *((byte*) main::$7) from [14] (bool~) main::$9 ← (byte) 0 != *((byte*) main::$7)
Inversing boolean not [16] (bool~) main::$5 ← (byte) 0 != *((byte*) main::$7) from [15] (bool~) main::$4 ← (byte) 0 == *((byte*) main::$7)
Successful SSA optimization Pass2UnaryNotSimplification
Alias (byte) main::len#0 = (byte~) main::$1
Alias (struct Setting*) main::setting#2 = (struct Setting*) main::setting#3 (struct Setting*) main::setting#5
Alias (byte) main::idx#2 = (byte) main::idx#3 (byte) main::idx#4
Alias (byte) main::len#1 = (byte) main::len#3 (byte) main::len#4
Successful SSA optimization Pass2AliasElimination
Alias (struct Setting*) main::setting#2 = (struct Setting*) main::setting#4
Alias (byte) main::len#1 = (byte) main::len#2
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (byte) main::len#1 (byte) main::len#0
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition (bool~) main::$3 [11] if((struct Setting*) main::setting#2<(struct Setting*~) main::$2) goto main::@2
Simple Condition (bool~) main::$5 [17] if((byte) 0!=*((byte*) main::$7)) goto main::@4
Successful SSA optimization Pass2ConditionalJumpSimplification
Identified constant from value list (struct Setting) { off: (byte) 0, id: (byte) 'a' }
Identified constant from value list (struct Setting) { off: (byte) 1, id: (byte) 'b' }
Identified constant from value list (struct Setting) { off: (byte) 0, id: (byte) 'c' }
Successful SSA optimization Pass2ConstantInitializerValueLists
Identified constant from value list (struct Setting[]) { { off: (byte) 0, id: (byte) 'a' }, { off: (byte) 1, id: (byte) 'b' }, { off: (byte) 0, id: (byte) 'c' } }
Successful SSA optimization Pass2ConstantInitializerValueLists
Constant (const byte*) SCREEN#0 = (byte*) 1024
Constant (const struct Setting[]) settings#0 = { { off: 0, id: 'a' }, { off: 1, id: 'b' }, { off: 0, id: 'c' } }
Constant (const byte) main::idx#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Constant (const struct Setting*) main::setting#0 = settings#0
Successful SSA optimization Pass2ConstantIdentification
Converting *(pointer+n) to pointer[n] [17] if((byte) 0!=*((byte*) main::$7)) goto main::@4 -- *((byte*)main::setting#2 + OFFSET_STRUCT_SETTING_OFF)
Converting *(pointer+n) to pointer[n] [22] *((const byte*) SCREEN#0 + (byte) main::idx#2) ← *((byte*) main::$8) -- *((byte*)main::setting#2 + OFFSET_STRUCT_SETTING_ID)
Successful SSA optimization Pass2InlineDerefIdx
Simplifying expression containing zero (byte*)main::setting#2 in [13] (byte*) main::$7 ← (byte*)(struct Setting*) main::setting#2 + (const byte) OFFSET_STRUCT_SETTING_OFF
Simplifying expression containing zero (byte*)main::setting#2 in [17] if((byte) 0!=*((byte*)(struct Setting*) main::setting#2 + (const byte) OFFSET_STRUCT_SETTING_OFF)) goto main::@4
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable (byte*) main::$7 and assignment [6] (byte*) main::$7 ← (byte*)(struct Setting*) main::setting#2
Eliminating unused variable (byte*) main::$8 and assignment [10] (byte*) main::$8 ← (byte*)(struct Setting*) main::setting#2 + (const byte) OFFSET_STRUCT_SETTING_ID
Eliminating unused constant (const byte) OFFSET_STRUCT_SETTING_OFF
Successful SSA optimization PassNEliminateUnusedVars
Constant right-side identified [0] (byte~) main::$0 ← sizeof (const struct Setting[]) settings#0
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte) main::$0 = sizeof settings#0
Successful SSA optimization Pass2ConstantIdentification
Resolving array sizeof() sizeof (const struct Setting[]) settings#0
Successful SSA optimization PassNSizeOfSimplification
Constant right-side identified [0] (byte) main::len#0 ← (const byte) main::$0 / (const byte) SIZEOF_STRUCT_SETTING
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte) main::len#0 = main::$0/SIZEOF_STRUCT_SETTING
Successful SSA optimization Pass2ConstantIdentification
Adding number conversion cast (unumber) 3 in
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast 3
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 3
Successful SSA optimization PassNFinalizeNumberTypeConversions
Constant right-side identified [1] (byte~) main::$6 ← (const byte) main::len#0 * (const byte) SIZEOF_STRUCT_SETTING
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte) main::$6 = main::len#0*SIZEOF_STRUCT_SETTING
Successful SSA optimization Pass2ConstantIdentification
Constant right-side identified [1] (struct Setting*~) main::$2 ← (const struct Setting[]) settings#0 + (const byte) main::$6
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const struct Setting*) main::$2 = settings#0+main::$6
Successful SSA optimization Pass2ConstantIdentification
Inlining constant with var siblings (const byte) main::idx#0
Inlining constant with var siblings (const struct Setting*) main::setting#0
Constant inlined main::$6 = (const byte) main::len#0*(const byte) SIZEOF_STRUCT_SETTING
Constant inlined main::idx#0 = (byte) 0
Constant inlined main::setting#0 = (const struct Setting[]) settings#0
Constant inlined main::$2 = (const struct Setting[]) settings#0+(const byte) main::len#0*(const byte) SIZEOF_STRUCT_SETTING
Constant inlined main::$0 = (byte) 3*(const byte) SIZEOF_STRUCT_SETTING
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting main::@9(between main::@2 and main::@4)
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
CALL GRAPH
Calls in [] to main:2
Created 3 initial phi equivalence classes
Coalesced [12] main::idx#8 ← main::idx#1
Coalesced [15] main::setting#6 ← main::setting#1
Coalesced [16] main::idx#6 ← main::idx#5
Coalesced (already) [17] main::idx#7 ← main::idx#2
Coalesced down to 2 phi equivalence classes
Culled Empty Block (label) @2
Culled Empty Block (label) main::@9
Renumbering block main::@4 to main::@3
Renumbering block main::@7 to main::@4
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@3
[5] (byte) main::idx#2 ← phi( main/(byte) 0 main::@3/(byte) main::idx#5 )
[5] (struct Setting*) main::setting#2 ← phi( main/(const struct Setting[]) settings#0 main::@3/(struct Setting*) main::setting#1 )
[6] if((struct Setting*) main::setting#2<(const struct Setting[]) settings#0+(const byte) main::len#0*(const byte) SIZEOF_STRUCT_SETTING) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[7] return
to:@return
main::@2: scope:[main] from main::@1
[8] if((byte) 0!=*((byte*)(struct Setting*) main::setting#2)) goto main::@3
to:main::@4
main::@4: scope:[main] from main::@2
[9] *((const byte*) SCREEN#0 + (byte) main::idx#2) ← *((byte*)(struct Setting*) main::setting#2 + (const byte) OFFSET_STRUCT_SETTING_ID)
[10] (byte) main::idx#1 ← ++ (byte) main::idx#2
to:main::@3
main::@3: scope:[main] from main::@2 main::@4
[11] (byte) main::idx#5 ← phi( main::@2/(byte) main::idx#2 main::@4/(byte) main::idx#1 )
[12] (struct Setting*) main::setting#1 ← (struct Setting*) main::setting#2 + (const byte) SIZEOF_STRUCT_SETTING
to:main::@1
VARIABLE REGISTER WEIGHTS
(byte*) SCREEN
(byte) Setting::id
(byte) Setting::off
(void()) main()
(byte) main::idx
(byte) main::idx#1 22.0
(byte) main::idx#2 11.0
(byte) main::idx#5 16.5
(byte) main::len
(struct Setting*) main::setting
(struct Setting*) main::setting#1 22.0
(struct Setting*) main::setting#2 5.5
(struct Setting[]) settings
Initial phi equivalence classes
[ main::setting#2 main::setting#1 ]
[ main::idx#2 main::idx#5 main::idx#1 ]
Complete equivalence classes
[ main::setting#2 main::setting#1 ]
[ main::idx#2 main::idx#5 main::idx#1 ]
Allocated zp ZP_WORD:2 [ main::setting#2 main::setting#1 ]
Allocated zp ZP_BYTE:4 [ main::idx#2 main::idx#5 main::idx#1 ]
INITIAL ASM
Target platform is c64basic
// File Comments
// Demonstrates problem with conditions using negated struct references
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_SETTING = 2
.const OFFSET_STRUCT_SETTING_ID = 1
.label SCREEN = $400
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
.const len = 3*SIZEOF_STRUCT_SETTING/SIZEOF_STRUCT_SETTING
.label setting = 2
.label idx = 4
// [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
// [5] phi (byte) main::idx#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z idx
// [5] phi (struct Setting*) main::setting#2 = (const struct Setting[]) settings#0 [phi:main->main::@1#1] -- pssz1=pssc1
lda #<settings
sta.z setting
lda #>settings
sta.z setting+1
jmp b1
// main::@1
b1:
// [6] if((struct Setting*) main::setting#2<(const struct Setting[]) settings#0+(const byte) main::len#0*(const byte) SIZEOF_STRUCT_SETTING) goto main::@2 -- pssz1_lt_pssc1_then_la1
lda.z setting+1
cmp #>settings+len*SIZEOF_STRUCT_SETTING
bcc b2
bne !+
lda.z setting
cmp #<settings+len*SIZEOF_STRUCT_SETTING
bcc b2
!:
jmp breturn
// main::@return
breturn:
// [7] return
rts
// main::@2
b2:
// [8] if((byte) 0!=*((byte*)(struct Setting*) main::setting#2)) goto main::@3 -- vbuc1_neq__deref_pbuz1_then_la1
ldy #0
lda (setting),y
cmp #0
bne b3_from_b2
jmp b4
// main::@4
b4:
// [9] *((const byte*) SCREEN#0 + (byte) main::idx#2) ← *((byte*)(struct Setting*) main::setting#2 + (const byte) OFFSET_STRUCT_SETTING_ID) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuc2
ldx.z idx
ldy #OFFSET_STRUCT_SETTING_ID
lda (setting),y
sta SCREEN,x
// [10] (byte) main::idx#1 ← ++ (byte) main::idx#2 -- vbuz1=_inc_vbuz1
inc.z idx
// [11] phi from main::@2 main::@4 to main::@3 [phi:main::@2/main::@4->main::@3]
b3_from_b2:
b3_from_b4:
// [11] phi (byte) main::idx#5 = (byte) main::idx#2 [phi:main::@2/main::@4->main::@3#0] -- register_copy
jmp b3
// main::@3
b3:
// [12] (struct Setting*) main::setting#1 ← (struct Setting*) main::setting#2 + (const byte) SIZEOF_STRUCT_SETTING -- pssz1=pssz1_plus_vbuc1
lda #SIZEOF_STRUCT_SETTING
clc
adc.z setting
sta.z setting
bcc !+
inc.z setting+1
!:
// [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
b1_from_b3:
// [5] phi (byte) main::idx#2 = (byte) main::idx#5 [phi:main::@3->main::@1#0] -- register_copy
// [5] phi (struct Setting*) main::setting#2 = (struct Setting*) main::setting#1 [phi:main::@3->main::@1#1] -- register_copy
jmp b1
}
// File Data
settings:
.byte 0, 'a'
.byte 1, 'b'
.byte 0, 'c'
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [6] if((struct Setting*) main::setting#2<(const struct Setting[]) settings#0+(const byte) main::len#0*(const byte) SIZEOF_STRUCT_SETTING) goto main::@2 [ main::setting#2 main::idx#2 ] ( main:2 [ main::setting#2 main::idx#2 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::idx#2 main::idx#5 main::idx#1 ]
Statement [8] if((byte) 0!=*((byte*)(struct Setting*) main::setting#2)) goto main::@3 [ main::setting#2 main::idx#2 ] ( main:2 [ main::setting#2 main::idx#2 ] ) always clobbers reg byte a reg byte y
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:4 [ main::idx#2 main::idx#5 main::idx#1 ]
Statement [9] *((const byte*) SCREEN#0 + (byte) main::idx#2) ← *((byte*)(struct Setting*) main::setting#2 + (const byte) OFFSET_STRUCT_SETTING_ID) [ main::setting#2 main::idx#2 ] ( main:2 [ main::setting#2 main::idx#2 ] ) always clobbers reg byte a reg byte y
Statement [12] (struct Setting*) main::setting#1 ← (struct Setting*) main::setting#2 + (const byte) SIZEOF_STRUCT_SETTING [ main::setting#1 main::idx#5 ] ( main:2 [ main::setting#1 main::idx#5 ] ) always clobbers reg byte a
Statement [6] if((struct Setting*) main::setting#2<(const struct Setting[]) settings#0+(const byte) main::len#0*(const byte) SIZEOF_STRUCT_SETTING) goto main::@2 [ main::setting#2 main::idx#2 ] ( main:2 [ main::setting#2 main::idx#2 ] ) always clobbers reg byte a
Statement [8] if((byte) 0!=*((byte*)(struct Setting*) main::setting#2)) goto main::@3 [ main::setting#2 main::idx#2 ] ( main:2 [ main::setting#2 main::idx#2 ] ) always clobbers reg byte a reg byte y
Statement [9] *((const byte*) SCREEN#0 + (byte) main::idx#2) ← *((byte*)(struct Setting*) main::setting#2 + (const byte) OFFSET_STRUCT_SETTING_ID) [ main::setting#2 main::idx#2 ] ( main:2 [ main::setting#2 main::idx#2 ] ) always clobbers reg byte a reg byte y
Statement [12] (struct Setting*) main::setting#1 ← (struct Setting*) main::setting#2 + (const byte) SIZEOF_STRUCT_SETTING [ main::setting#1 main::idx#5 ] ( main:2 [ main::setting#1 main::idx#5 ] ) always clobbers reg byte a
Potential registers zp ZP_WORD:2 [ main::setting#2 main::setting#1 ] : zp ZP_WORD:2 ,
Potential registers zp ZP_BYTE:4 [ main::idx#2 main::idx#5 main::idx#1 ] : zp ZP_BYTE:4 , reg byte x ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 49.5: zp ZP_BYTE:4 [ main::idx#2 main::idx#5 main::idx#1 ] 27.5: zp ZP_WORD:2 [ main::setting#2 main::setting#1 ]
Uplift Scope [Setting]
Uplift Scope []
Uplifting [main] best 903 combination reg byte x [ main::idx#2 main::idx#5 main::idx#1 ] zp ZP_WORD:2 [ main::setting#2 main::setting#1 ]
Uplifting [Setting] best 903 combination
Uplifting [] best 903 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Demonstrates problem with conditions using negated struct references
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_SETTING = 2
.const OFFSET_STRUCT_SETTING_ID = 1
.label SCREEN = $400
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
.const len = 3*SIZEOF_STRUCT_SETTING/SIZEOF_STRUCT_SETTING
.label setting = 2
// [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
// [5] phi (byte) main::idx#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
// [5] phi (struct Setting*) main::setting#2 = (const struct Setting[]) settings#0 [phi:main->main::@1#1] -- pssz1=pssc1
lda #<settings
sta.z setting
lda #>settings
sta.z setting+1
jmp b1
// main::@1
b1:
// [6] if((struct Setting*) main::setting#2<(const struct Setting[]) settings#0+(const byte) main::len#0*(const byte) SIZEOF_STRUCT_SETTING) goto main::@2 -- pssz1_lt_pssc1_then_la1
lda.z setting+1
cmp #>settings+len*SIZEOF_STRUCT_SETTING
bcc b2
bne !+
lda.z setting
cmp #<settings+len*SIZEOF_STRUCT_SETTING
bcc b2
!:
jmp breturn
// main::@return
breturn:
// [7] return
rts
// main::@2
b2:
// [8] if((byte) 0!=*((byte*)(struct Setting*) main::setting#2)) goto main::@3 -- vbuc1_neq__deref_pbuz1_then_la1
ldy #0
lda (setting),y
cmp #0
bne b3_from_b2
jmp b4
// main::@4
b4:
// [9] *((const byte*) SCREEN#0 + (byte) main::idx#2) ← *((byte*)(struct Setting*) main::setting#2 + (const byte) OFFSET_STRUCT_SETTING_ID) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_SETTING_ID
lda (setting),y
sta SCREEN,x
// [10] (byte) main::idx#1 ← ++ (byte) main::idx#2 -- vbuxx=_inc_vbuxx
inx
// [11] phi from main::@2 main::@4 to main::@3 [phi:main::@2/main::@4->main::@3]
b3_from_b2:
b3_from_b4:
// [11] phi (byte) main::idx#5 = (byte) main::idx#2 [phi:main::@2/main::@4->main::@3#0] -- register_copy
jmp b3
// main::@3
b3:
// [12] (struct Setting*) main::setting#1 ← (struct Setting*) main::setting#2 + (const byte) SIZEOF_STRUCT_SETTING -- pssz1=pssz1_plus_vbuc1
lda #SIZEOF_STRUCT_SETTING
clc
adc.z setting
sta.z setting
bcc !+
inc.z setting+1
!:
// [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
b1_from_b3:
// [5] phi (byte) main::idx#2 = (byte) main::idx#5 [phi:main::@3->main::@1#0] -- register_copy
// [5] phi (struct Setting*) main::setting#2 = (struct Setting*) main::setting#1 [phi:main::@3->main::@1#1] -- register_copy
jmp b1
}
// File Data
settings:
.byte 0, 'a'
.byte 1, 'b'
.byte 0, 'c'
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp breturn
Removing instruction jmp b4
Removing instruction jmp b3
Succesful ASM optimization Pass5NextJumpElimination
Replacing label b3_from_b2 with b3
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Removing instruction b3_from_b2:
Removing instruction b3_from_b4:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction b1_from_main:
Removing instruction breturn:
Removing instruction b4:
Removing instruction b1_from_b3:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_SETTING_ID OFFSET_STRUCT_SETTING_ID = (byte) 1
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(const byte) SIZEOF_STRUCT_SETTING SIZEOF_STRUCT_SETTING = (byte) 2
(byte) Setting::id
(byte) Setting::off
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@4
(label) main::@return
(byte) main::idx
(byte) main::idx#1 reg byte x 22.0
(byte) main::idx#2 reg byte x 11.0
(byte) main::idx#5 reg byte x 16.5
(byte) main::len
(const byte) main::len#0 len = (byte) 3*(const byte) SIZEOF_STRUCT_SETTING/(const byte) SIZEOF_STRUCT_SETTING
(struct Setting*) main::setting
(struct Setting*) main::setting#1 setting zp ZP_WORD:2 22.0
(struct Setting*) main::setting#2 setting zp ZP_WORD:2 5.5
(struct Setting[]) settings
(const struct Setting[]) settings#0 settings = { { off: (byte) 0, id: (byte) 'a' }, { off: (byte) 1, id: (byte) 'b' }, { off: (byte) 0, id: (byte) 'c' } }
zp ZP_WORD:2 [ main::setting#2 main::setting#1 ]
reg byte x [ main::idx#2 main::idx#5 main::idx#1 ]
FINAL ASSEMBLER
Score: 771
// File Comments
// Demonstrates problem with conditions using negated struct references
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_SETTING = 2
.const OFFSET_STRUCT_SETTING_ID = 1
.label SCREEN = $400
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
.const len = 3*SIZEOF_STRUCT_SETTING/SIZEOF_STRUCT_SETTING
.label setting = 2
// [5] phi from main to main::@1 [phi:main->main::@1]
// [5] phi (byte) main::idx#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
// [5] phi (struct Setting*) main::setting#2 = (const struct Setting[]) settings#0 [phi:main->main::@1#1] -- pssz1=pssc1
lda #<settings
sta.z setting
lda #>settings
sta.z setting+1
// main::@1
b1:
// for(struct Setting* setting = settings; setting<settings+len; setting++)
// [6] if((struct Setting*) main::setting#2<(const struct Setting[]) settings#0+(const byte) main::len#0*(const byte) SIZEOF_STRUCT_SETTING) goto main::@2 -- pssz1_lt_pssc1_then_la1
lda.z setting+1
cmp #>settings+len*SIZEOF_STRUCT_SETTING
bcc b2
bne !+
lda.z setting
cmp #<settings+len*SIZEOF_STRUCT_SETTING
bcc b2
!:
// main::@return
// }
// [7] return
rts
// main::@2
b2:
// if (! setting->off)
// [8] if((byte) 0!=*((byte*)(struct Setting*) main::setting#2)) goto main::@3 -- vbuc1_neq__deref_pbuz1_then_la1
ldy #0
lda (setting),y
cmp #0
bne b3
// main::@4
// SCREEN[idx++] = setting->id
// [9] *((const byte*) SCREEN#0 + (byte) main::idx#2) ← *((byte*)(struct Setting*) main::setting#2 + (const byte) OFFSET_STRUCT_SETTING_ID) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_SETTING_ID
lda (setting),y
sta SCREEN,x
// SCREEN[idx++] = setting->id;
// [10] (byte) main::idx#1 ← ++ (byte) main::idx#2 -- vbuxx=_inc_vbuxx
inx
// [11] phi from main::@2 main::@4 to main::@3 [phi:main::@2/main::@4->main::@3]
// [11] phi (byte) main::idx#5 = (byte) main::idx#2 [phi:main::@2/main::@4->main::@3#0] -- register_copy
// main::@3
b3:
// for(struct Setting* setting = settings; setting<settings+len; setting++)
// [12] (struct Setting*) main::setting#1 ← (struct Setting*) main::setting#2 + (const byte) SIZEOF_STRUCT_SETTING -- pssz1=pssz1_plus_vbuc1
lda #SIZEOF_STRUCT_SETTING
clc
adc.z setting
sta.z setting
bcc !+
inc.z setting+1
!:
// [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
// [5] phi (byte) main::idx#2 = (byte) main::idx#5 [phi:main::@3->main::@1#0] -- register_copy
// [5] phi (struct Setting*) main::setting#2 = (struct Setting*) main::setting#1 [phi:main::@3->main::@1#1] -- register_copy
jmp b1
}
// File Data
settings:
.byte 0, 'a'
.byte 1, 'b'
.byte 0, 'c'

View File

@ -0,0 +1,29 @@
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_SETTING_ID OFFSET_STRUCT_SETTING_ID = (byte) 1
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(const byte) SIZEOF_STRUCT_SETTING SIZEOF_STRUCT_SETTING = (byte) 2
(byte) Setting::id
(byte) Setting::off
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@4
(label) main::@return
(byte) main::idx
(byte) main::idx#1 reg byte x 22.0
(byte) main::idx#2 reg byte x 11.0
(byte) main::idx#5 reg byte x 16.5
(byte) main::len
(const byte) main::len#0 len = (byte) 3*(const byte) SIZEOF_STRUCT_SETTING/(const byte) SIZEOF_STRUCT_SETTING
(struct Setting*) main::setting
(struct Setting*) main::setting#1 setting zp ZP_WORD:2 22.0
(struct Setting*) main::setting#2 setting zp ZP_WORD:2 5.5
(struct Setting[]) settings
(const struct Setting[]) settings#0 settings = { { off: (byte) 0, id: (byte) 'a' }, { off: (byte) 1, id: (byte) 'b' }, { off: (byte) 0, id: (byte) 'c' } }
zp ZP_WORD:2 [ main::setting#2 main::setting#1 ]
reg byte x [ main::idx#2 main::idx#5 main::idx#1 ]

View File

@ -0,0 +1,32 @@
// Demonstrates problem with conditions using negated struct references
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const OFFSET_STRUCT_SETTING_BUF = 1
.label SCREEN = $400
main: {
ldx #0
b1:
cpx settings
bcc b2
rts
b2:
txa
asl
tay
lda settings+OFFSET_STRUCT_SETTING_BUF
sta.z $fe
lda settings+OFFSET_STRUCT_SETTING_BUF+1
sta.z $ff
lda ($fe),y
sta SCREEN,y
iny
lda ($fe),y
sta SCREEN,y
inx
jmp b1
}
seq: .word 1, 2, 3
settings:
.byte 3
.word seq

View File

@ -0,0 +1,24 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[6] if((byte) main::i#2<*((byte*)(const struct Setting[]) settings#0)) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[7] return
to:@return
main::@2: scope:[main] from main::@1
[8] (byte~) main::$3 ← (byte) main::i#2 << (byte) 1
[9] *((const word*) SCREEN#0 + (byte~) main::$3) ← *(*((word**)(const struct Setting[]) settings#0+(const byte) OFFSET_STRUCT_SETTING_BUF) + (byte~) main::$3)
[10] (byte) main::i#1 ← ++ (byte) main::i#2
to:main::@1

View File

@ -0,0 +1,529 @@
Fixing pointer array-indexing *((word[]) seq + (number) 0)
Fixing pointer array-indexing *((struct Setting[]) settings + (number) 0)
Fixing pointer array-indexing *(*((struct Setting*) main::setting).buf + (byte) main::i)
Fixing pointer array-indexing *((word*) SCREEN + (byte) main::i)
Rewriting struct pointer member access *((struct Setting*) main::setting).len
Rewriting struct pointer member access *((struct Setting*) main::setting).buf
Identified constant variable (byte) main::idx
Culled Empty Block (label) main::@4
Culled Empty Block (label) main::@3
Culled Empty Block (label) main::@5
Culled Empty Block (label) main::@6
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(word*) SCREEN#0 ← ((word*)) (number) $400
(word[]) seq#0 ← { (number) 1, (number) 2, (number) 3 }
(number~) $1 ← (number) 0 * (const byte) SIZEOF_WORD
(word*~) $0 ← & *((word[]) seq#0 + (number~) $1)
(struct Setting[]) settings#0 ← { { (number) 3, (word*~) $0 } }
to:@1
main: scope:[main] from @1
(number~) main::$2 ← (number) 0 * (const byte) SIZEOF_STRUCT_SETTING
(struct Setting*~) main::$0 ← & *((struct Setting[]) settings#0 + (number~) main::$2)
(struct Setting*) main::setting#0 ← (struct Setting*~) main::$0
(byte) main::i#0 ← (number) 0
to:main::@1
main::@1: scope:[main] from main main::@2
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 )
(struct Setting*) main::setting#1 ← phi( main/(struct Setting*) main::setting#0 main::@2/(struct Setting*) main::setting#2 )
(byte*) main::$4 ← (byte*)(struct Setting*) main::setting#1 + (const byte) OFFSET_STRUCT_SETTING_LEN
(bool~) main::$1 ← (byte) main::i#2 < *((byte*) main::$4)
if((bool~) main::$1) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
(struct Setting*) main::setting#2 ← phi( main::@1/(struct Setting*) main::setting#1 )
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
(byte~) main::$3 ← (byte) main::i#3 * (const byte) SIZEOF_WORD
(word**) main::$5 ← (word**)(struct Setting*) main::setting#2 + (const byte) OFFSET_STRUCT_SETTING_BUF
*((word*) SCREEN#0 + (byte~) main::$3) ← *(*((word**) main::$5) + (byte~) main::$3)
(byte) main::i#1 ← ++ (byte) main::i#3
to:main::@1
main::@return: scope:[main] from main::@1
return
to:@return
@1: scope:[] from @begin
call main
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(word*~) $0
(number~) $1
(label) @1
(label) @2
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_SETTING_BUF = (byte) 1
(const byte) OFFSET_STRUCT_SETTING_LEN = (byte) 0
(word*) SCREEN
(word*) SCREEN#0
(const byte) SIZEOF_STRUCT_SETTING = (byte) 3
(const byte) SIZEOF_WORD = (byte) 2
(word*) Setting::buf
(byte) Setting::len
(void()) main()
(struct Setting*~) main::$0
(bool~) main::$1
(number~) main::$2
(byte~) main::$3
(byte*) main::$4
(word**) main::$5
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte) main::i#3
(struct Setting*) main::setting
(struct Setting*) main::setting#0
(struct Setting*) main::setting#1
(struct Setting*) main::setting#2
(word[]) seq
(word[]) seq#0
(struct Setting[]) settings
(struct Setting[]) settings#0
Adding number conversion cast (unumber) 0 in (number~) $1 ← (number) 0 * (const byte) SIZEOF_WORD
Adding number conversion cast (unumber) $1 in (number~) $1 ← (unumber)(number) 0 * (const byte) SIZEOF_WORD
Adding number conversion cast (unumber) 0 in (number~) main::$2 ← (number) 0 * (const byte) SIZEOF_STRUCT_SETTING
Adding number conversion cast (unumber) main::$2 in (number~) main::$2 ← (unumber)(number) 0 * (const byte) SIZEOF_STRUCT_SETTING
Adding number conversion cast (unumber) 0 in (byte) main::i#0 ← (number) 0
Successful SSA optimization PassNAddNumberTypeConversions
Added casts to value list in (word[]) seq#0 ← (word[]){ (word)(number) 1, (word)(number) 2, (word)(number) 3 }
Added casts to value list in (struct Setting[]) settings#0 ← (struct Setting[]){ (struct Setting){ (byte)(number) 3, (word*~) $0 } }
Successful SSA optimization PassNAddInitializerValueListTypeCasts
Inlining cast (word*) SCREEN#0 ← (word*)(number) $400
Inlining cast (byte) main::i#0 ← (unumber)(number) 0
Successful SSA optimization Pass2InlineCast
Simplifying constant pointer cast (word*) 1024
Simplifying constant integer cast 1
Simplifying constant integer cast 2
Simplifying constant integer cast 3
Simplifying constant integer cast 0
Simplifying constant integer cast 3
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
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inferred type updated to byte in (unumber~) $1 ← (byte) 0 * (const byte) SIZEOF_WORD
Inferred type updated to byte in (unumber~) main::$2 ← (byte) 0 * (const byte) SIZEOF_STRUCT_SETTING
Alias (struct Setting*) main::setting#0 = (struct Setting*~) main::$0
Alias (byte) main::i#2 = (byte) main::i#3
Alias (struct Setting*) main::setting#1 = (struct Setting*) main::setting#2
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (struct Setting*) main::setting#1 (struct Setting*) main::setting#0
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition (bool~) main::$1 [12] if((byte) main::i#2<*((byte*) main::$4)) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Rewriting array member address-of to pointer addition [3] (word*~) $0 ← (word[]) seq#0 + (byte~) $1
Rewriting array member address-of to pointer addition [6] (struct Setting*) main::setting#0 ← (struct Setting[]) settings#0 + (byte~) main::$2
Successful SSA optimization PassNArrayElementAddressOfRewriting
Constant right-side identified [2] (byte~) $1 ← (byte) 0 * (const byte) SIZEOF_WORD
Constant right-side identified [5] (byte~) main::$2 ← (byte) 0 * (const byte) SIZEOF_STRUCT_SETTING
Successful SSA optimization Pass2ConstantRValueConsolidation
Identified constant from value list (word[]) { (word) 1, (word) 2, (word) 3 }
Successful SSA optimization Pass2ConstantInitializerValueLists
Constant (const word*) SCREEN#0 = (word*) 1024
Constant (const word[]) seq#0 = { 1, 2, 3 }
Constant (const byte) $1 = 0*SIZEOF_WORD
Constant (const byte) main::$2 = 0*SIZEOF_STRUCT_SETTING
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Converting *(pointer+n) to pointer[n] [12] if((byte) main::i#2<*((byte*) main::$4)) goto main::@2 -- *((byte*)main::setting#0 + OFFSET_STRUCT_SETTING_LEN)
Converting *(pointer+n) to pointer[n] [16] *((const word*) SCREEN#0 + (byte~) main::$3) ← *(*((word**) main::$5) + (byte~) main::$3) -- *((word**)main::setting#0 + OFFSET_STRUCT_SETTING_BUF)
Successful SSA optimization Pass2InlineDerefIdx
Simplifying constant evaluating to zero (byte) 0*(const byte) SIZEOF_STRUCT_SETTING in
Simplifying constant evaluating to zero (byte) 0*(const byte) SIZEOF_WORD in
Successful SSA optimization PassNSimplifyConstantZero
Simplifying expression containing zero seq#0 in [3] (word*~) $0 ← (const word[]) seq#0 + (const byte) $1
Simplifying expression containing zero settings#0 in [6] (struct Setting*) main::setting#0 ← (struct Setting[]) settings#0 + (const byte) main::$2
Simplifying expression containing zero (byte*)main::setting#0 in [10] (byte*) main::$4 ← (byte*)(struct Setting*) main::setting#0 + (const byte) OFFSET_STRUCT_SETTING_LEN
Simplifying expression containing zero (byte*)main::setting#0 in [12] if((byte) main::i#2<*((byte*)(struct Setting*) main::setting#0 + (const byte) OFFSET_STRUCT_SETTING_LEN)) goto main::@2
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable (byte*) main::$4 and assignment [4] (byte*) main::$4 ← (byte*)(struct Setting*) main::setting#0
Eliminating unused variable (word**) main::$5 and assignment [7] (word**) main::$5 ← (word**)(struct Setting*) main::setting#0 + (const byte) OFFSET_STRUCT_SETTING_BUF
Eliminating unused constant (const byte) main::$2
Eliminating unused constant (const byte) SIZEOF_STRUCT_SETTING
Eliminating unused constant (const byte) OFFSET_STRUCT_SETTING_LEN
Eliminating unused constant (const byte) $1
Successful SSA optimization PassNEliminateUnusedVars
Constant (const word*) $0 = seq#0
Successful SSA optimization Pass2ConstantIdentification
Identified constant from value list (struct Setting) { len: (byte) 3, buf: (const word*) $0 }
Successful SSA optimization Pass2ConstantInitializerValueLists
Identified constant from value list (struct Setting[]) { { len: (byte) 3, buf: (const word*) $0 } }
Successful SSA optimization Pass2ConstantInitializerValueLists
Constant (const struct Setting[]) settings#0 = { { len: 3, buf: $0 } }
Successful SSA optimization Pass2ConstantIdentification
Constant (const struct Setting*) main::setting#0 = settings#0
Successful SSA optimization Pass2ConstantIdentification
Constant value identified (byte*)main::setting#0 in [3] if((byte) main::i#2<*((byte*)(const struct Setting*) main::setting#0)) goto main::@2
Constant value identified (word**)main::setting#0 in [5] *((const word*) SCREEN#0 + (byte~) main::$3) ← *(*((word**)(const struct Setting*) main::setting#0 + (const byte) OFFSET_STRUCT_SETTING_BUF) + (byte~) main::$3)
Successful SSA optimization Pass2ConstantValues
Rewriting multiplication to use shift [2] (byte~) main::$3 ← (byte) main::i#2 * (const byte) SIZEOF_WORD
Successful SSA optimization Pass2MultiplyToShiftRewriting
Inlining constant with var siblings (const byte) main::i#0
Constant inlined $0 = (const word[]) seq#0
Constant inlined main::i#0 = (byte) 0
Constant inlined main::setting#0 = (const struct Setting[]) settings#0
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *((word**)settings#0+OFFSET_STRUCT_SETTING_BUF)
Successful SSA optimization Pass2ConstantAdditionElimination
Eliminating unused constant (const byte) SIZEOF_WORD
Successful SSA optimization PassNEliminateUnusedVars
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
CALL GRAPH
Calls in [] to main:2
Created 1 initial phi equivalence classes
Coalesced [12] main::i#4 ← main::i#1
Coalesced down to 1 phi equivalence classes
Culled Empty Block (label) @2
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[6] if((byte) main::i#2<*((byte*)(const struct Setting[]) settings#0)) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[7] return
to:@return
main::@2: scope:[main] from main::@1
[8] (byte~) main::$3 ← (byte) main::i#2 << (byte) 1
[9] *((const word*) SCREEN#0 + (byte~) main::$3) ← *(*((word**)(const struct Setting[]) settings#0+(const byte) OFFSET_STRUCT_SETTING_BUF) + (byte~) main::$3)
[10] (byte) main::i#1 ← ++ (byte) main::i#2
to:main::@1
VARIABLE REGISTER WEIGHTS
(word*) SCREEN
(word*) Setting::buf
(byte) Setting::len
(void()) main()
(byte~) main::$3 33.0
(byte) main::i
(byte) main::i#1 22.0
(byte) main::i#2 11.0
(struct Setting*) main::setting
(word[]) seq
(struct Setting[]) settings
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Added variable main::$3 to zero page equivalence class [ main::$3 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::$3 ]
Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Allocated zp ZP_BYTE:3 [ main::$3 ]
INITIAL ASM
Target platform is c64basic
// File Comments
// Demonstrates problem with conditions using negated struct references
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_SETTING_BUF = 1
.label SCREEN = $400
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
.label _3 = 3
.label i = 2
// [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z i
jmp b1
// main::@1
b1:
// [6] if((byte) main::i#2<*((byte*)(const struct Setting[]) settings#0)) goto main::@2 -- vbuz1_lt__deref_pbuc1_then_la1
lda.z i
cmp settings
bcc b2
jmp breturn
// main::@return
breturn:
// [7] return
rts
// main::@2
b2:
// [8] (byte~) main::$3 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuz2_rol_1
lda.z i
asl
sta.z _3
// [9] *((const word*) SCREEN#0 + (byte~) main::$3) ← *(*((word**)(const struct Setting[]) settings#0+(const byte) OFFSET_STRUCT_SETTING_BUF) + (byte~) main::$3) -- pwuc1_derefidx_vbuz1=_deref_pptc2_derefidx_vbuz1
ldy.z _3
lda settings+OFFSET_STRUCT_SETTING_BUF
sta.z $fe
lda settings+OFFSET_STRUCT_SETTING_BUF+1
sta.z $ff
lda ($fe),y
sta SCREEN,y
iny
lda ($fe),y
sta SCREEN,y
// [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
b1_from_b2:
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp b1
}
// File Data
seq: .word 1, 2, 3
settings:
.byte 3
.word seq
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [8] (byte~) main::$3 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$3 ] ( main:2 [ main::i#2 main::$3 ] ) 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 [9] *((const word*) SCREEN#0 + (byte~) main::$3) ← *(*((word**)(const struct Setting[]) settings#0+(const byte) OFFSET_STRUCT_SETTING_BUF) + (byte~) main::$3) [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a reg byte y
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Statement [8] (byte~) main::$3 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$3 ] ( main:2 [ main::i#2 main::$3 ] ) always clobbers reg byte a
Statement [9] *((const word*) SCREEN#0 + (byte~) main::$3) ← *(*((word**)(const struct Setting[]) settings#0+(const byte) OFFSET_STRUCT_SETTING_BUF) + (byte~) main::$3) [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a reg byte y
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x ,
Potential registers zp ZP_BYTE:3 [ main::$3 ] : zp ZP_BYTE:3 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 33: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 33: zp ZP_BYTE:3 [ main::$3 ]
Uplift Scope [Setting]
Uplift Scope []
Uplifting [main] best 643 combination reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$3 ]
Uplifting [Setting] best 643 combination
Uplifting [] best 643 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Demonstrates problem with conditions using negated struct references
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_SETTING_BUF = 1
.label SCREEN = $400
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
// [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
jmp b1
// main::@1
b1:
// [6] if((byte) main::i#2<*((byte*)(const struct Setting[]) settings#0)) goto main::@2 -- vbuxx_lt__deref_pbuc1_then_la1
cpx settings
bcc b2
jmp breturn
// main::@return
breturn:
// [7] return
rts
// main::@2
b2:
// [8] (byte~) main::$3 ← (byte) main::i#2 << (byte) 1 -- vbuaa=vbuxx_rol_1
txa
asl
// [9] *((const word*) SCREEN#0 + (byte~) main::$3) ← *(*((word**)(const struct Setting[]) settings#0+(const byte) OFFSET_STRUCT_SETTING_BUF) + (byte~) main::$3) -- pwuc1_derefidx_vbuaa=_deref_pptc2_derefidx_vbuaa
tay
lda settings+OFFSET_STRUCT_SETTING_BUF
sta.z $fe
lda settings+OFFSET_STRUCT_SETTING_BUF+1
sta.z $ff
lda ($fe),y
sta SCREEN,y
iny
lda ($fe),y
sta SCREEN,y
// [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
b1_from_b2:
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp b1
}
// File Data
seq: .word 1, 2, 3
settings:
.byte 3
.word seq
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction b1_from_main:
Removing instruction breturn:
Removing instruction b1_from_b2:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_SETTING_BUF OFFSET_STRUCT_SETTING_BUF = (byte) 1
(word*) SCREEN
(const word*) SCREEN#0 SCREEN = (word*) 1024
(word*) Setting::buf
(byte) Setting::len
(void()) main()
(byte~) main::$3 reg byte a 33.0
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 22.0
(byte) main::i#2 reg byte x 11.0
(struct Setting*) main::setting
(word[]) seq
(const word[]) seq#0 seq = { (word) 1, (word) 2, (word) 3 }
(struct Setting[]) settings
(const struct Setting[]) settings#0 settings = { { len: (byte) 3, buf: (const word[]) seq#0 } }
reg byte x [ main::i#2 main::i#1 ]
reg byte a [ main::$3 ]
FINAL ASSEMBLER
Score: 571
// File Comments
// Demonstrates problem with conditions using negated struct references
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_SETTING_BUF = 1
.label SCREEN = $400
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
// [5] phi from main to main::@1 [phi:main->main::@1]
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
// main::@1
b1:
// for( char i=0;i<setting->len;i++)
// [6] if((byte) main::i#2<*((byte*)(const struct Setting[]) settings#0)) goto main::@2 -- vbuxx_lt__deref_pbuc1_then_la1
cpx settings
bcc b2
// main::@return
// }
// [7] return
rts
// main::@2
b2:
// SCREEN[i] = setting->buf[i]
// [8] (byte~) main::$3 ← (byte) main::i#2 << (byte) 1 -- vbuaa=vbuxx_rol_1
txa
asl
// [9] *((const word*) SCREEN#0 + (byte~) main::$3) ← *(*((word**)(const struct Setting[]) settings#0+(const byte) OFFSET_STRUCT_SETTING_BUF) + (byte~) main::$3) -- pwuc1_derefidx_vbuaa=_deref_pptc2_derefidx_vbuaa
tay
lda settings+OFFSET_STRUCT_SETTING_BUF
sta.z $fe
lda settings+OFFSET_STRUCT_SETTING_BUF+1
sta.z $ff
lda ($fe),y
sta SCREEN,y
iny
lda ($fe),y
sta SCREEN,y
// for( char i=0;i<setting->len;i++)
// [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp b1
}
// File Data
seq: .word 1, 2, 3
settings:
.byte 3
.word seq

View File

@ -0,0 +1,24 @@
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_SETTING_BUF OFFSET_STRUCT_SETTING_BUF = (byte) 1
(word*) SCREEN
(const word*) SCREEN#0 SCREEN = (word*) 1024
(word*) Setting::buf
(byte) Setting::len
(void()) main()
(byte~) main::$3 reg byte a 33.0
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 22.0
(byte) main::i#2 reg byte x 11.0
(struct Setting*) main::setting
(word[]) seq
(const word[]) seq#0 seq = { (word) 1, (word) 2, (word) 3 }
(struct Setting[]) settings
(const struct Setting[]) settings#0 settings = { { len: (byte) 3, buf: (const word[]) seq#0 } }
reg byte x [ main::i#2 main::i#1 ]
reg byte a [ main::$3 ]