From f8af7172d41e7eafd6de41879b4326c473cabc16 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sat, 2 May 2020 12:07:12 +0200 Subject: [PATCH] Added test reference files. --- src/test/ref/multiply-1.asm | 15 ++ src/test/ref/multiply-1.cfg | 17 ++ src/test/ref/multiply-1.log | 281 +++++++++++++++++++++ src/test/ref/multiply-1.sym | 11 + src/test/ref/multiply-2.asm | 34 +++ src/test/ref/multiply-2.cfg | 31 +++ src/test/ref/multiply-2.log | 488 ++++++++++++++++++++++++++++++++++++ src/test/ref/multiply-2.sym | 26 ++ 8 files changed, 903 insertions(+) create mode 100644 src/test/ref/multiply-1.asm create mode 100644 src/test/ref/multiply-1.cfg create mode 100644 src/test/ref/multiply-1.log create mode 100644 src/test/ref/multiply-1.sym create mode 100644 src/test/ref/multiply-2.asm create mode 100644 src/test/ref/multiply-2.cfg create mode 100644 src/test/ref/multiply-2.log create mode 100644 src/test/ref/multiply-2.sym diff --git a/src/test/ref/multiply-1.asm b/src/test/ref/multiply-1.asm new file mode 100644 index 000000000..c667911c5 --- /dev/null +++ b/src/test/ref/multiply-1.asm @@ -0,0 +1,15 @@ +// Test compile-time and run-time multiplication +// Compile-time multiplication +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label SCREEN = $400 +main: { + .const c1 = 4 + .const c3 = c1*(c1*2+1) + // SCREEN[0] = c3 + lda #c3 + sta SCREEN + // } + rts +} diff --git a/src/test/ref/multiply-1.cfg b/src/test/ref/multiply-1.cfg new file mode 100644 index 000000000..ea29eb0b3 --- /dev/null +++ b/src/test/ref/multiply-1.cfg @@ -0,0 +1,17 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() + +(void()) main() +main: scope:[main] from @1 + [4] *((const nomodify byte*) SCREEN) ← (const byte) main::c3#0 + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return diff --git a/src/test/ref/multiply-1.log b/src/test/ref/multiply-1.log new file mode 100644 index 000000000..aba1a4e43 --- /dev/null +++ b/src/test/ref/multiply-1.log @@ -0,0 +1,281 @@ + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 + +(void()) main() +main: scope:[main] from @1 + (number~) main::$0 ← (const byte) main::c1 * (number) 2 + (byte) main::c2#0 ← (number~) main::$0 + (byte) main::c2#1 ← ++ (byte) main::c2#0 + (byte~) main::$1 ← (const byte) main::c1 * (byte) main::c2#1 + (byte) main::c3#0 ← (byte~) main::$1 + *((const nomodify byte*) SCREEN + (number) 0) ← (byte) main::c3#0 + to:main::@return +main::@return: scope:[main] from main + 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 nomodify byte*) SCREEN = (byte*)(number) $400 +(void()) main() +(number~) main::$0 +(byte~) main::$1 +(label) main::@return +(const byte) main::c1 = (byte) 4 +(byte) main::c2 +(byte) main::c2#0 +(byte) main::c2#1 +(byte) main::c3 +(byte) main::c3#0 + +Adding number conversion cast (unumber) 2 in (number~) main::$0 ← (const byte) main::c1 * (number) 2 +Adding number conversion cast (unumber) main::$0 in (number~) main::$0 ← (const byte) main::c1 * (unumber)(number) 2 +Adding number conversion cast (unumber) 0 in *((const nomodify byte*) SCREEN + (number) 0) ← (byte) main::c3#0 +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast 2 +Simplifying constant integer cast 0 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 2 +Finalized unsigned number type (byte) 0 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Inferred type updated to byte in (unumber~) main::$0 ← (const byte) main::c1 * (byte) 2 +Alias main::c2#0 = main::$0 +Alias main::c3#0 = main::$1 +Successful SSA optimization Pass2AliasElimination +Constant right-side identified [0] (byte) main::c2#0 ← (const byte) main::c1 * (byte) 2 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte) main::c2#0 = main::c1*2 +Successful SSA optimization Pass2ConstantIdentification +Simplifying expression containing zero SCREEN in [3] *((const nomodify byte*) SCREEN + (byte) 0) ← (byte) main::c3#0 +Successful SSA optimization PassNSimplifyExpressionWithZero +Constant right-side identified [0] (byte) main::c2#1 ← ++ (const byte) main::c2#0 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte) main::c2#1 = ++main::c2#0 +Successful SSA optimization Pass2ConstantIdentification +Constant right-side identified [0] (byte) main::c3#0 ← (const byte) main::c1 * (const byte) main::c2#1 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte) main::c3#0 = main::c1*main::c2#1 +Successful SSA optimization Pass2ConstantIdentification +Inlining constant with different constant siblings (const byte) main::c2#0 +Inlining constant with different constant siblings (const byte) main::c2#1 +Constant inlined main::c2#0 = (const byte) main::c1*(byte) 2 +Constant inlined main::c2#1 = ++(const byte) main::c1*(byte) 2 +Successful SSA optimization Pass2ConstantInlining +Simplifying constant integer increment ++main::c1*2 +Successful SSA optimization Pass2ConstantSimplification +Adding number conversion cast (unumber) main::c1*2+1 in +Adding number conversion cast (unumber) 1 in +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant integer cast (const byte) main::c1*(byte) 2+(unumber)(number) 1 +Simplifying constant integer cast 1 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 1 +Successful SSA optimization PassNFinalizeNumberTypeConversions +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() + +(void()) main() +main: scope:[main] from @1 + [4] *((const nomodify byte*) SCREEN) ← (const byte) main::c3#0 + to:main::@return +main::@return: scope:[main] from main + [5] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte) main::c2 +(byte) main::c3 + +Initial phi equivalence classes +Complete equivalence classes + +INITIAL ASM +Target platform is c64basic / MOS6502X + // File Comments +// Test compile-time and run-time multiplication +// Compile-time multiplication + // 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: { + .const c1 = 4 + .const c3 = c1*(c1*2+1) + // [4] *((const nomodify byte*) SCREEN) ← (const byte) main::c3#0 -- _deref_pbuc1=vbuc2 + lda #c3 + sta SCREEN + jmp __breturn + // main::@return + __breturn: + // [5] return + rts +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] *((const nomodify byte*) SCREEN) ← (const byte) main::c3#0 [ ] ( 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 compile-time and run-time multiplication +// Compile-time multiplication + // 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: { + .const c1 = 4 + .const c3 = c1*(c1*2+1) + // [4] *((const nomodify byte*) SCREEN) ← (const byte) main::c3#0 -- _deref_pbuc1=vbuc2 + lda #c3 + 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 +(const nomodify byte*) SCREEN = (byte*) 1024 +(void()) main() +(label) main::@return +(const byte) main::c1 = (byte) 4 +(byte) main::c2 +(byte) main::c3 +(const byte) main::c3#0 c3 = (const byte) main::c1*(const byte) main::c1*(byte) 2+(byte) 1 + + + +FINAL ASSEMBLER +Score: 12 + + // File Comments +// Test compile-time and run-time multiplication +// Compile-time multiplication + // 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: { + .const c1 = 4 + .const c3 = c1*(c1*2+1) + // SCREEN[0] = c3 + // [4] *((const nomodify byte*) SCREEN) ← (const byte) main::c3#0 -- _deref_pbuc1=vbuc2 + lda #c3 + sta SCREEN + // main::@return + // } + // [5] return + rts +} + // File Data + diff --git a/src/test/ref/multiply-1.sym b/src/test/ref/multiply-1.sym new file mode 100644 index 000000000..91d6de7fe --- /dev/null +++ b/src/test/ref/multiply-1.sym @@ -0,0 +1,11 @@ +(label) @1 +(label) @begin +(label) @end +(const nomodify byte*) SCREEN = (byte*) 1024 +(void()) main() +(label) main::@return +(const byte) main::c1 = (byte) 4 +(byte) main::c2 +(byte) main::c3 +(const byte) main::c3#0 c3 = (const byte) main::c1*(const byte) main::c1*(byte) 2+(byte) 1 + diff --git a/src/test/ref/multiply-2.asm b/src/test/ref/multiply-2.asm new file mode 100644 index 000000000..5af0303cf --- /dev/null +++ b/src/test/ref/multiply-2.asm @@ -0,0 +1,34 @@ +// Test compile-time and run-time multiplication +// var*const multiplication - converted to shift/add +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label SCREEN = $400 +main: { + ldy #0 + ldx #0 + __b1: + // for(char c1=0;c1<5;c1++) + cpx #5 + bcc __b2 + // } + rts + __b2: + // c3 = c1*c2 + txa + asl + stx.z $ff + clc + adc.z $ff + asl + stx.z $ff + clc + adc.z $ff + // SCREEN[i++] = c3 + sta SCREEN,y + // SCREEN[i++] = c3; + iny + // for(char c1=0;c1<5;c1++) + inx + jmp __b1 +} diff --git a/src/test/ref/multiply-2.cfg b/src/test/ref/multiply-2.cfg new file mode 100644 index 000000000..f96c9949a --- /dev/null +++ b/src/test/ref/multiply-2.cfg @@ -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() + +(void()) main() +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 ) + [5] (byte) main::c1#2 ← phi( main/(byte) 0 main::@2/(byte) main::c1#1 ) + [6] if((byte) main::c1#2<(byte) 5) 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::$2 ← (byte) main::c1#2 << (byte) 1 + [9] (byte~) main::$3 ← (byte~) main::$2 + (byte) main::c1#2 + [10] (byte~) main::$4 ← (byte~) main::$3 << (byte) 1 + [11] (byte) main::c3#0 ← (byte~) main::$4 + (byte) main::c1#2 + [12] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← (byte) main::c3#0 + [13] (byte) main::i#1 ← ++ (byte) main::i#2 + [14] (byte) main::c1#1 ← ++ (byte) main::c1#2 + to:main::@1 diff --git a/src/test/ref/multiply-2.log b/src/test/ref/multiply-2.log new file mode 100644 index 000000000..90aa0eb0c --- /dev/null +++ b/src/test/ref/multiply-2.log @@ -0,0 +1,488 @@ + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 + +(void()) main() +main: scope:[main] from @1 + (byte) main::i#0 ← (byte) 0 + (byte) main::c1#0 ← (byte) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (byte) main::i#3 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) + (byte) main::c1#2 ← phi( main/(byte) main::c1#0 main::@2/(byte) main::c1#1 ) + (bool~) main::$0 ← (byte) main::c1#2 < (number) 5 + if((bool~) main::$0) goto main::@2 + to:main::@return +main::@2: scope:[main] from main::@1 + (byte) main::i#2 ← phi( main::@1/(byte) main::i#3 ) + (byte) main::c1#3 ← phi( main::@1/(byte) main::c1#2 ) + (byte~) main::$1 ← (byte) main::c1#3 * (const byte) main::c2 + (byte) main::c3#0 ← (byte~) main::$1 + *((const nomodify byte*) SCREEN + (byte) main::i#2) ← (byte) main::c3#0 + (byte) main::i#1 ← ++ (byte) main::i#2 + (byte) main::c1#1 ← ++ (byte) main::c1#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 +(label) @1 +(label) @2 +(label) @begin +(label) @end +(const nomodify byte*) SCREEN = (byte*)(number) $400 +(void()) main() +(bool~) main::$0 +(byte~) main::$1 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte) main::c1 +(byte) main::c1#0 +(byte) main::c1#1 +(byte) main::c1#2 +(byte) main::c1#3 +(const byte) main::c2 = (byte)(number) 3*(number) 2+(number) 1 +(byte) main::c3 +(byte) main::c3#0 +(byte) main::i +(byte) main::i#0 +(byte) main::i#1 +(byte) main::i#2 +(byte) main::i#3 + +Adding number conversion cast (unumber) 5 in (bool~) main::$0 ← (byte) main::c1#2 < (number) 5 +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast 5 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 5 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias main::c1#2 = main::c1#3 +Alias main::i#2 = main::i#3 +Alias main::c3#0 = main::$1 +Successful SSA optimization Pass2AliasElimination +Simple Condition (bool~) main::$0 [4] if((byte) main::c1#2<(byte) 5) goto main::@2 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant (const byte) main::i#0 = 0 +Constant (const byte) main::c1#0 = 0 +Successful SSA optimization Pass2ConstantIdentification +Rewriting multiplication to use shift and addition[2] (byte) main::c3#0 ← (byte) main::c1#2 * (const byte) main::c2 +Inlining constant with var siblings (const byte) main::i#0 +Inlining constant with var siblings (const byte) main::c1#0 +Constant inlined main::c1#0 = (byte) 0 +Constant inlined main::i#0 = (byte) 0 +Successful SSA optimization Pass2ConstantInlining +Alias main::c3#0 = main::$5 +Successful SSA optimization Pass2AliasElimination +Eliminating unused constant (const byte) main::c2 +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 2 initial phi equivalence classes +Coalesced [16] main::c1#4 ← main::c1#1 +Coalesced [17] main::i#4 ← main::i#1 +Coalesced down to 2 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() + +(void()) main() +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 ) + [5] (byte) main::c1#2 ← phi( main/(byte) 0 main::@2/(byte) main::c1#1 ) + [6] if((byte) main::c1#2<(byte) 5) 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::$2 ← (byte) main::c1#2 << (byte) 1 + [9] (byte~) main::$3 ← (byte~) main::$2 + (byte) main::c1#2 + [10] (byte~) main::$4 ← (byte~) main::$3 << (byte) 1 + [11] (byte) main::c3#0 ← (byte~) main::$4 + (byte) main::c1#2 + [12] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← (byte) main::c3#0 + [13] (byte) main::i#1 ← ++ (byte) main::i#2 + [14] (byte) main::c1#1 ← ++ (byte) main::c1#2 + to:main::@1 + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(byte~) main::$2 202.0 +(byte~) main::$3 202.0 +(byte~) main::$4 202.0 +(byte) main::c1 +(byte) main::c1#1 202.0 +(byte) main::c1#2 75.75 +(byte) main::c3 +(byte) main::c3#0 202.0 +(byte) main::i +(byte) main::i#1 101.0 +(byte) main::i#2 43.285714285714285 + +Initial phi equivalence classes +[ main::c1#2 main::c1#1 ] +[ main::i#2 main::i#1 ] +Added variable main::$2 to live range equivalence class [ main::$2 ] +Added variable main::$3 to live range equivalence class [ main::$3 ] +Added variable main::$4 to live range equivalence class [ main::$4 ] +Added variable main::c3#0 to live range equivalence class [ main::c3#0 ] +Complete equivalence classes +[ main::c1#2 main::c1#1 ] +[ main::i#2 main::i#1 ] +[ main::$2 ] +[ main::$3 ] +[ main::$4 ] +[ main::c3#0 ] +Allocated zp[1]:2 [ main::c1#2 main::c1#1 ] +Allocated zp[1]:3 [ main::i#2 main::i#1 ] +Allocated zp[1]:4 [ main::$2 ] +Allocated zp[1]:5 [ main::$3 ] +Allocated zp[1]:6 [ main::$4 ] +Allocated zp[1]:7 [ main::c3#0 ] + +INITIAL ASM +Target platform is c64basic / MOS6502X + // File Comments +// Test compile-time and run-time multiplication +// var*const multiplication - converted to shift/add + // 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 c3 = 7 + .label i = 3 + .label c1 = 2 + .label __2 = 4 + .label __3 = 5 + .label __4 = 6 + // [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 + // [5] phi (byte) main::c1#2 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1 + lda #0 + sta.z c1 + jmp __b1 + // main::@1 + __b1: + // [6] if((byte) main::c1#2<(byte) 5) goto main::@2 -- vbuz1_lt_vbuc1_then_la1 + lda.z c1 + cmp #5 + bcc __b2 + jmp __breturn + // main::@return + __breturn: + // [7] return + rts + // main::@2 + __b2: + // [8] (byte~) main::$2 ← (byte) main::c1#2 << (byte) 1 -- vbuz1=vbuz2_rol_1 + lda.z c1 + asl + sta.z __2 + // [9] (byte~) main::$3 ← (byte~) main::$2 + (byte) main::c1#2 -- vbuz1=vbuz2_plus_vbuz3 + lda.z __2 + clc + adc.z c1 + sta.z __3 + // [10] (byte~) main::$4 ← (byte~) main::$3 << (byte) 1 -- vbuz1=vbuz2_rol_1 + lda.z __3 + asl + sta.z __4 + // [11] (byte) main::c3#0 ← (byte~) main::$4 + (byte) main::c1#2 -- vbuz1=vbuz2_plus_vbuz3 + lda.z __4 + clc + adc.z c1 + sta.z c3 + // [12] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← (byte) main::c3#0 -- pbuc1_derefidx_vbuz1=vbuz2 + lda.z c3 + ldy.z i + sta SCREEN,y + // [13] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 + inc.z i + // [14] (byte) main::c1#1 ← ++ (byte) main::c1#2 -- vbuz1=_inc_vbuz1 + inc.z c1 + // [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 + // [5] phi (byte) main::c1#2 = (byte) main::c1#1 [phi:main::@2->main::@1#1] -- register_copy + jmp __b1 +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [8] (byte~) main::$2 ← (byte) main::c1#2 << (byte) 1 [ main::c1#2 main::i#2 main::$2 ] ( main:2 [ main::c1#2 main::i#2 main::$2 ] { } ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::c1#2 main::c1#1 ] +Removing always clobbered register reg byte a as potential for zp[1]:3 [ main::i#2 main::i#1 ] +Statement [9] (byte~) main::$3 ← (byte~) main::$2 + (byte) main::c1#2 [ main::c1#2 main::i#2 main::$3 ] ( main:2 [ main::c1#2 main::i#2 main::$3 ] { } ) always clobbers reg byte a +Statement [10] (byte~) main::$4 ← (byte~) main::$3 << (byte) 1 [ main::c1#2 main::i#2 main::$4 ] ( main:2 [ main::c1#2 main::i#2 main::$4 ] { } ) always clobbers reg byte a +Statement [11] (byte) main::c3#0 ← (byte~) main::$4 + (byte) main::c1#2 [ main::c1#2 main::i#2 main::c3#0 ] ( main:2 [ main::c1#2 main::i#2 main::c3#0 ] { } ) always clobbers reg byte a +Statement [8] (byte~) main::$2 ← (byte) main::c1#2 << (byte) 1 [ main::c1#2 main::i#2 main::$2 ] ( main:2 [ main::c1#2 main::i#2 main::$2 ] { } ) always clobbers reg byte a +Statement [9] (byte~) main::$3 ← (byte~) main::$2 + (byte) main::c1#2 [ main::c1#2 main::i#2 main::$3 ] ( main:2 [ main::c1#2 main::i#2 main::$3 ] { } ) always clobbers reg byte a +Statement [10] (byte~) main::$4 ← (byte~) main::$3 << (byte) 1 [ main::c1#2 main::i#2 main::$4 ] ( main:2 [ main::c1#2 main::i#2 main::$4 ] { } ) always clobbers reg byte a +Statement [11] (byte) main::c3#0 ← (byte~) main::$4 + (byte) main::c1#2 [ main::c1#2 main::i#2 main::c3#0 ] ( main:2 [ main::c1#2 main::i#2 main::c3#0 ] { } ) always clobbers reg byte a +Potential registers zp[1]:2 [ main::c1#2 main::c1#1 ] : zp[1]:2 , reg byte x , reg byte y , +Potential registers zp[1]:3 [ main::i#2 main::i#1 ] : zp[1]:3 , reg byte x , reg byte y , +Potential registers zp[1]:4 [ main::$2 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:5 [ main::$3 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:6 [ main::$4 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:7 [ main::c3#0 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 277.75: zp[1]:2 [ main::c1#2 main::c1#1 ] 202: zp[1]:4 [ main::$2 ] 202: zp[1]:5 [ main::$3 ] 202: zp[1]:6 [ main::$4 ] 202: zp[1]:7 [ main::c3#0 ] 144.29: zp[1]:3 [ main::i#2 main::i#1 ] +Uplift Scope [] + +Uplifting [main] best 653 combination reg byte x [ main::c1#2 main::c1#1 ] reg byte a [ main::$2 ] reg byte a [ main::$3 ] reg byte a [ main::$4 ] zp[1]:7 [ main::c3#0 ] zp[1]:3 [ main::i#2 main::i#1 ] +Limited combination testing to 100 combinations of 2304 possible. +Uplifting [] best 653 combination +Attempting to uplift remaining variables inzp[1]:7 [ main::c3#0 ] +Uplifting [main] best 593 combination reg byte a [ main::c3#0 ] +Attempting to uplift remaining variables inzp[1]:3 [ main::i#2 main::i#1 ] +Uplifting [main] best 503 combination reg byte y [ main::i#2 main::i#1 ] + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Test compile-time and run-time multiplication +// var*const multiplication - converted to shift/add + // 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::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuyy=vbuc1 + ldy #0 + // [5] phi (byte) main::c1#2 = (byte) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1 + ldx #0 + jmp __b1 + // main::@1 + __b1: + // [6] if((byte) main::c1#2<(byte) 5) goto main::@2 -- vbuxx_lt_vbuc1_then_la1 + cpx #5 + bcc __b2 + jmp __breturn + // main::@return + __breturn: + // [7] return + rts + // main::@2 + __b2: + // [8] (byte~) main::$2 ← (byte) main::c1#2 << (byte) 1 -- vbuaa=vbuxx_rol_1 + txa + asl + // [9] (byte~) main::$3 ← (byte~) main::$2 + (byte) main::c1#2 -- vbuaa=vbuaa_plus_vbuxx + stx.z $ff + clc + adc.z $ff + // [10] (byte~) main::$4 ← (byte~) main::$3 << (byte) 1 -- vbuaa=vbuaa_rol_1 + asl + // [11] (byte) main::c3#0 ← (byte~) main::$4 + (byte) main::c1#2 -- vbuaa=vbuaa_plus_vbuxx + stx.z $ff + clc + adc.z $ff + // [12] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← (byte) main::c3#0 -- pbuc1_derefidx_vbuyy=vbuaa + sta SCREEN,y + // [13] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuyy=_inc_vbuyy + iny + // [14] (byte) main::c1#1 ← ++ (byte) main::c1#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 + // [5] phi (byte) main::c1#2 = (byte) main::c1#1 [phi:main::@2->main::@1#1] -- register_copy + jmp __b1 +} + // File Data + +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 nomodify byte*) SCREEN = (byte*) 1024 +(void()) main() +(byte~) main::$2 reg byte a 202.0 +(byte~) main::$3 reg byte a 202.0 +(byte~) main::$4 reg byte a 202.0 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte) main::c1 +(byte) main::c1#1 reg byte x 202.0 +(byte) main::c1#2 reg byte x 75.75 +(byte) main::c3 +(byte) main::c3#0 reg byte a 202.0 +(byte) main::i +(byte) main::i#1 reg byte y 101.0 +(byte) main::i#2 reg byte y 43.285714285714285 + +reg byte x [ main::c1#2 main::c1#1 ] +reg byte y [ main::i#2 main::i#1 ] +reg byte a [ main::$2 ] +reg byte a [ main::$3 ] +reg byte a [ main::$4 ] +reg byte a [ main::c3#0 ] + + +FINAL ASSEMBLER +Score: 431 + + // File Comments +// Test compile-time and run-time multiplication +// var*const multiplication - converted to shift/add + // 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::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuyy=vbuc1 + ldy #0 + // [5] phi (byte) main::c1#2 = (byte) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1 + ldx #0 + // main::@1 + __b1: + // for(char c1=0;c1<5;c1++) + // [6] if((byte) main::c1#2<(byte) 5) goto main::@2 -- vbuxx_lt_vbuc1_then_la1 + cpx #5 + bcc __b2 + // main::@return + // } + // [7] return + rts + // main::@2 + __b2: + // c3 = c1*c2 + // [8] (byte~) main::$2 ← (byte) main::c1#2 << (byte) 1 -- vbuaa=vbuxx_rol_1 + txa + asl + // [9] (byte~) main::$3 ← (byte~) main::$2 + (byte) main::c1#2 -- vbuaa=vbuaa_plus_vbuxx + stx.z $ff + clc + adc.z $ff + // [10] (byte~) main::$4 ← (byte~) main::$3 << (byte) 1 -- vbuaa=vbuaa_rol_1 + asl + // [11] (byte) main::c3#0 ← (byte~) main::$4 + (byte) main::c1#2 -- vbuaa=vbuaa_plus_vbuxx + stx.z $ff + clc + adc.z $ff + // SCREEN[i++] = c3 + // [12] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← (byte) main::c3#0 -- pbuc1_derefidx_vbuyy=vbuaa + sta SCREEN,y + // SCREEN[i++] = c3; + // [13] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuyy=_inc_vbuyy + iny + // for(char c1=0;c1<5;c1++) + // [14] (byte) main::c1#1 ← ++ (byte) main::c1#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 + // [5] phi (byte) main::c1#2 = (byte) main::c1#1 [phi:main::@2->main::@1#1] -- register_copy + jmp __b1 +} + // File Data + diff --git a/src/test/ref/multiply-2.sym b/src/test/ref/multiply-2.sym new file mode 100644 index 000000000..911a8fa0e --- /dev/null +++ b/src/test/ref/multiply-2.sym @@ -0,0 +1,26 @@ +(label) @1 +(label) @begin +(label) @end +(const nomodify byte*) SCREEN = (byte*) 1024 +(void()) main() +(byte~) main::$2 reg byte a 202.0 +(byte~) main::$3 reg byte a 202.0 +(byte~) main::$4 reg byte a 202.0 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte) main::c1 +(byte) main::c1#1 reg byte x 202.0 +(byte) main::c1#2 reg byte x 75.75 +(byte) main::c3 +(byte) main::c3#0 reg byte a 202.0 +(byte) main::i +(byte) main::i#1 reg byte y 101.0 +(byte) main::i#2 reg byte y 43.285714285714285 + +reg byte x [ main::c1#2 main::c1#1 ] +reg byte y [ main::i#2 main::i#1 ] +reg byte a [ main::$2 ] +reg byte a [ main::$3 ] +reg byte a [ main::$4 ] +reg byte a [ main::c3#0 ]