1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-08-02 09:29:35 +00:00

Added tests for inline assembler & kickassembler.

This commit is contained in:
jespergravgaard 2019-03-14 23:09:50 +01:00
parent fa6ed8bff6
commit d293c47141
35 changed files with 2335 additions and 22 deletions

View File

@ -1,8 +1,9 @@
sta $ff
sec
lda {c1},y
sbc $ff
clc
sbc {c1},y
eor #$ff
sta {c1},y
bcc !+
lda {c1}+1,y
sbc #0
sta {c1},y
sbc #$01
sta {c1}+1,y
!:

View File

@ -133,6 +133,8 @@ public class ProgramValueIterator {
if(cycles!=null) {
execute(new ProgramValue.KickAsmCycles(statementKickAsm), handler, statement, statementsIt, block);
}
} else if(statement instanceof StatementAsm) {
}
}

View File

@ -44,6 +44,59 @@ public class TestPrograms {
AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false);
}
/*
@Test
public void testInlineAsmRefoutProblem() throws IOException, URISyntaxException {
compileAndCompare("inline-asm-refout-problem");
}
@Test
public void testConstIfProblem() throws IOException, URISyntaxException {
compileAndCompare("const-if-problem");
}
@Test
public void testTetrisNullPointer() throws IOException, URISyntaxException {
compileAndCompare("tetris-npe");
}
@Test
public void testUnrollCall() throws IOException, URISyntaxException {
compileAndCompare("unroll-call");
}
*/
@Test
public void testInlineKasmLoop() throws IOException, URISyntaxException {
compileAndCompare("inline-kasm-loop");
}
@Test
public void testInlineKasmData() throws IOException, URISyntaxException {
compileAndCompare("inline-kasm-data");
}
@Test
public void testInlineKasmResource() throws IOException, URISyntaxException {
compileAndCompare("inline-kasm-resource");
}
@Test
public void testInlineAsmRefout() throws IOException, URISyntaxException {
compileAndCompare("inline-asm-refout");
}
@Test
public void testInlineAsmOptimized() throws IOException, URISyntaxException {
compileAndCompare("inline-asm-optimized");
}
@Test
public void testCastNotNeeded() throws IOException, URISyntaxException {
compileAndCompare("cast-not-needed");
}
@Test
public void testNoLocalScope() throws IOException, URISyntaxException {
assertError("nolocalscope", "Symbol already declared");
@ -234,22 +287,6 @@ public class TestPrograms {
compileAndCompare("var-init-problem");
}
/*
@Test
public void testConstIfProblem() throws IOException, URISyntaxException {
compileAndCompare("const-if-problem");
}
@Test
public void testTetrisNullPointer() throws IOException, URISyntaxException {
compileAndCompare("tetris-npe");
}
@Test
public void testUnrollCall() throws IOException, URISyntaxException {
compileAndCompare("unroll-call");
}
*/
@Test
public void testFastMultiply8() throws IOException, URISyntaxException {

BIN
src/test/kc/balloon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,9 @@
//
byte* sprite = $5000;
byte* SCREEN = $4400;
void main() {
byte* sprite_ptr = SCREEN+$378;
sprite_ptr[0] = (byte)(sprite/$40);
}

View File

@ -0,0 +1,21 @@
// Tests that inline assembler is optimized
const byte* SCREEN = $400;
void main() {
*SCREEN = 0;
asm {
lda #0
sta SCREEN+1
lda #0
sta SCREEN+2
}
SCREEN[3] = 0;
asm {
lda #0
sta SCREEN+4
}
}

View File

@ -0,0 +1,16 @@
// Illustrates how inline assembler can reference data from the outside program
const byte* SCREEN = $400;
byte[] table = "cml!";
void main() {
asm {
ldx #0
!:
lda table,x
sta SCREEN+1,x
inx
cpx #4
bne !-
}
}

View File

@ -0,0 +1,19 @@
// Illustrates how inline assembler can reference data from the outside program
byte[] table = "cml!";
void main() {
const byte* SCREEN = $400;
*(SCREEN+40) = table[0];
asm {
ldx #0
!:
lda table,x
sta SCREEN+1,x
inx
cpx #4
bne !-
}
}

View File

@ -0,0 +1,19 @@
// Example of inline kickasm data
const byte* sintab = $1000;
kickasm(pc sintab) {{
.fill 25, 20 + 20*sin(toRadians(i*360/25))
}}
void main() {
byte* screen = $400;
byte* cols = $d800;
for(byte i:0..24) {
byte sin = sintab[i];
screen[sin] = '*';
screen += 40;
cols[sin] = 1;
cols += 40;
}
}

View File

@ -0,0 +1,14 @@
// Example of inline kickasm in a function
void main() {
const byte* SCREEN = $400;
*(SCREEN+1000) = 0;
kickasm {{
lda #0
.for (var i = 0; i < 1000; i++) {
sta SCREEN+i
}
}}
}

View File

@ -0,0 +1,21 @@
// Example of inline kickasm resource data
const byte* SPRITE = $0c00;
kickasm(pc SPRITE, resource "balloon.png") {{
.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)
}}
const byte* SCREEN= $400;
const byte* SPRITES_ENABLE = $d015;
const byte* SPRITES_XPOS = $d000;
const byte* SPRITES_YPOS = $d001;
void main() {
*(SCREEN+$3f8) = (byte)(SPRITE/$40);
*SPRITES_ENABLE = 1;
*SPRITES_XPOS = 100;
*SPRITES_YPOS = 100;
}

View File

@ -0,0 +1,12 @@
//
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label sprite = $5000
.label SCREEN = $4400
main: {
.label sprite_ptr = SCREEN+$378
lda #$ff&sprite/$40
sta sprite_ptr
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*) main::sprite_ptr#0) ← ((byte))(const byte*) sprite#0/(byte/signed byte/word/signed word/dword/signed dword) $40
to:main::@return
main::@return: scope:[main] from main
[5] return
to:@return

View File

@ -0,0 +1,256 @@
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte*) sprite#0 ← ((byte*)) (word/signed word/dword/signed dword) $5000
(byte*) SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $4400
to:@1
main: scope:[main] from @1
(byte*) sprite#1 ← phi( @1/(byte*) sprite#2 )
(byte*) SCREEN#1 ← phi( @1/(byte*) SCREEN#2 )
(byte*~) main::$0 ← (byte*) SCREEN#1 + (word/signed word/dword/signed dword) $378
(byte*) main::sprite_ptr#0 ← (byte*~) main::$0
(byte*~) main::$1 ← (byte*) sprite#1 / (byte/signed byte/word/signed word/dword/signed dword) $40
(byte~) main::$2 ← ((byte)) (byte*~) main::$1
*((byte*) main::sprite_ptr#0 + (byte/signed byte/word/signed word/dword/signed dword) 0) ← (byte~) main::$2
to:main::@return
main::@return: scope:[main] from main
return
to:@return
@1: scope:[] from @begin
(byte*) sprite#2 ← phi( @begin/(byte*) sprite#0 )
(byte*) SCREEN#2 ← phi( @begin/(byte*) SCREEN#0 )
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
(byte*) SCREEN#1
(byte*) SCREEN#2
(void()) main()
(byte*~) main::$0
(byte*~) main::$1
(byte~) main::$2
(label) main::@return
(byte*) main::sprite_ptr
(byte*) main::sprite_ptr#0
(byte*) sprite
(byte*) sprite#0
(byte*) sprite#1
(byte*) sprite#2
Culled Empty Block (label) @2
Successful SSA optimization Pass2CullEmptyBlocks
Alias (byte*) main::sprite_ptr#0 = (byte*~) main::$0
Alias (byte*) SCREEN#0 = (byte*) SCREEN#2
Alias (byte*) sprite#0 = (byte*) sprite#2
Successful SSA optimization Pass2AliasElimination
Redundant Phi (byte*) SCREEN#1 (byte*) SCREEN#0
Redundant Phi (byte*) sprite#1 (byte*) sprite#0
Successful SSA optimization Pass2RedundantPhiElimination
Constant (const byte*) sprite#0 = ((byte*))$5000
Constant (const byte*) SCREEN#0 = ((byte*))$4400
Successful SSA optimization Pass2ConstantIdentification
Constant (const byte*) main::sprite_ptr#0 = SCREEN#0+$378
Constant (const byte*) main::$1 = sprite#0/$40
Successful SSA optimization Pass2ConstantIdentification
Constant (const byte) main::$2 = ((byte))main::$1
Successful SSA optimization Pass2ConstantIdentification
Consolidated array index constant in *(main::sprite_ptr#0+0)
Successful SSA optimization Pass2ConstantAdditionElimination
Constant inlined main::$1 = (const byte*) sprite#0/(byte/signed byte/word/signed word/dword/signed dword) $40
Constant inlined main::$2 = ((byte))(const byte*) sprite#0/(byte/signed byte/word/signed word/dword/signed dword) $40
Successful SSA optimization Pass2ConstantInlining
Simplifying constant plus zero main::sprite_ptr#0+0
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
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
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*) main::sprite_ptr#0) ← ((byte))(const byte*) sprite#0/(byte/signed byte/word/signed word/dword/signed dword) $40
to:main::@return
main::@return: scope:[main] from main
[5] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte*) SCREEN
(void()) main()
(byte*) main::sprite_ptr
(byte*) sprite
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
//SEG0 File Comments
//
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label sprite = $5000
.label SCREEN = $4400
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
jsr main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG8 @end
bend:
//SEG9 main
main: {
.label sprite_ptr = SCREEN+$378
//SEG10 [4] *((const byte*) main::sprite_ptr#0) ← ((byte))(const byte*) sprite#0/(byte/signed byte/word/signed word/dword/signed dword) $40 -- _deref_pbuc1=vbuc2
lda #$ff&sprite/$40
sta sprite_ptr
jmp breturn
//SEG11 main::@return
breturn:
//SEG12 [5] return
rts
}
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] *((const byte*) main::sprite_ptr#0) ← ((byte))(const byte*) sprite#0/(byte/signed byte/word/signed word/dword/signed dword) $40 [ ] ( 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
//SEG0 File Comments
//
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label sprite = $5000
.label SCREEN = $4400
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
jsr main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG8 @end
bend:
//SEG9 main
main: {
.label sprite_ptr = SCREEN+$378
//SEG10 [4] *((const byte*) main::sprite_ptr#0) ← ((byte))(const byte*) sprite#0/(byte/signed byte/word/signed word/dword/signed dword) $40 -- _deref_pbuc1=vbuc2
lda #$ff&sprite/$40
sta sprite_ptr
jmp breturn
//SEG11 main::@return
breturn:
//SEG12 [5] return
rts
}
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*))(word/signed word/dword/signed dword) $4400
(void()) main()
(label) main::@return
(byte*) main::sprite_ptr
(const byte*) main::sprite_ptr#0 sprite_ptr = (const byte*) SCREEN#0+(word/signed word/dword/signed dword) $378
(byte*) sprite
(const byte*) sprite#0 sprite = ((byte*))(word/signed word/dword/signed dword) $5000
FINAL ASSEMBLER
Score: 12
//SEG0 File Comments
//
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label sprite = $5000
.label SCREEN = $4400
//SEG3 @begin
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
//SEG5 @1
//SEG6 [2] call main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
//SEG8 @end
//SEG9 main
main: {
.label sprite_ptr = SCREEN+$378
//SEG10 [4] *((const byte*) main::sprite_ptr#0) ← ((byte))(const byte*) sprite#0/(byte/signed byte/word/signed word/dword/signed dword) $40 -- _deref_pbuc1=vbuc2
lda #$ff&sprite/$40
sta sprite_ptr
//SEG11 main::@return
//SEG12 [5] return
rts
}

View File

@ -0,0 +1,12 @@
(label) @1
(label) @begin
(label) @end
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $4400
(void()) main()
(label) main::@return
(byte*) main::sprite_ptr
(const byte*) main::sprite_ptr#0 sprite_ptr = (const byte*) SCREEN#0+(word/signed word/dword/signed dword) $378
(byte*) sprite
(const byte*) sprite#0 sprite = ((byte*))(word/signed word/dword/signed dword) $5000

View File

@ -0,0 +1,14 @@
// Tests that inline assembler is optimized
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label SCREEN = $400
main: {
lda #0
sta SCREEN
sta SCREEN+1
sta SCREEN+2
sta SCREEN+3
sta SCREEN+4
rts
}

View File

@ -0,0 +1,18 @@
@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/signed byte/word/signed word/dword/signed dword) 0
asm { lda#0 staSCREEN+1 lda#0 staSCREEN+2 }
[6] *((const byte*) SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte/signed byte/word/signed word/dword/signed dword) 0
asm { lda#0 staSCREEN+4 }
to:main::@return
main::@return: scope:[main] from main
[8] return
to:@return

View File

@ -0,0 +1,250 @@
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte*) SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400
to:@1
main: scope:[main] from @1
*((byte*) SCREEN#0) ← (byte/signed byte/word/signed word/dword/signed dword) 0
asm { lda#0 staSCREEN+1 lda#0 staSCREEN+2 }
*((byte*) SCREEN#0 + (byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte/signed byte/word/signed word/dword/signed dword) 0
asm { lda#0 staSCREEN+4 }
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
(byte*) SCREEN
(byte*) SCREEN#0
(void()) main()
(label) main::@return
Culled Empty Block (label) @2
Successful SSA optimization Pass2CullEmptyBlocks
Constant (const byte*) SCREEN#0 = ((byte*))$400
Successful SSA optimization Pass2ConstantIdentification
Consolidated array index constant in *(SCREEN#0+3)
Successful SSA optimization Pass2ConstantAdditionElimination
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
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
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/signed byte/word/signed word/dword/signed dword) 0
asm { lda#0 staSCREEN+1 lda#0 staSCREEN+2 }
[6] *((const byte*) SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte/signed byte/word/signed word/dword/signed dword) 0
asm { lda#0 staSCREEN+4 }
to:main::@return
main::@return: scope:[main] from main
[8] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte*) SCREEN
(void()) main()
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
//SEG0 File Comments
// Tests that inline assembler is optimized
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SCREEN = $400
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
jsr main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG8 @end
bend:
//SEG9 main
main: {
//SEG10 [4] *((const byte*) SCREEN#0) ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- _deref_pbuc1=vbuc2
lda #0
sta SCREEN
//SEG11 asm { lda#0 staSCREEN+1 lda#0 staSCREEN+2 }
lda #0
sta SCREEN+1
lda #0
sta SCREEN+2
//SEG12 [6] *((const byte*) SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- _deref_pbuc1=vbuc2
lda #0
sta SCREEN+3
//SEG13 asm { lda#0 staSCREEN+4 }
lda #0
sta SCREEN+4
jmp breturn
//SEG14 main::@return
breturn:
//SEG15 [8] return
rts
}
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] *((const byte*) SCREEN#0) ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement asm { lda#0 staSCREEN+1 lda#0 staSCREEN+2 } always clobbers reg byte a
Statement [6] *((const byte*) SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement asm { lda#0 staSCREEN+4 } always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [main]
Uplift Scope []
Uplifting [main] best 51 combination
Uplifting [] best 51 combination
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Tests that inline assembler is optimized
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SCREEN = $400
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
jsr main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG8 @end
bend:
//SEG9 main
main: {
//SEG10 [4] *((const byte*) SCREEN#0) ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- _deref_pbuc1=vbuc2
lda #0
sta SCREEN
//SEG11 asm { lda#0 staSCREEN+1 lda#0 staSCREEN+2 }
lda #0
sta SCREEN+1
lda #0
sta SCREEN+2
//SEG12 [6] *((const byte*) SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- _deref_pbuc1=vbuc2
lda #0
sta SCREEN+3
//SEG13 asm { lda#0 staSCREEN+4 }
lda #0
sta SCREEN+4
jmp breturn
//SEG14 main::@return
breturn:
//SEG15 [8] return
rts
}
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction lda #0
Removing instruction lda #0
Removing instruction lda #0
Removing instruction lda #0
Succesful ASM optimization Pass5UnnecesaryLoadElimination
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*))(word/signed word/dword/signed dword) $400
(void()) main()
(label) main::@return
FINAL ASSEMBLER
Score: 28
//SEG0 File Comments
// Tests that inline assembler is optimized
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SCREEN = $400
//SEG3 @begin
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
//SEG5 @1
//SEG6 [2] call main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
//SEG8 @end
//SEG9 main
main: {
//SEG10 [4] *((const byte*) SCREEN#0) ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- _deref_pbuc1=vbuc2
lda #0
sta SCREEN
//SEG11 asm { lda#0 staSCREEN+1 lda#0 staSCREEN+2 }
sta SCREEN+1
sta SCREEN+2
//SEG12 [6] *((const byte*) SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 3) ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- _deref_pbuc1=vbuc2
sta SCREEN+3
//SEG13 asm { lda#0 staSCREEN+4 }
sta SCREEN+4
//SEG14 main::@return
//SEG15 [8] return
rts
}

View File

@ -0,0 +1,8 @@
(label) @1
(label) @begin
(label) @end
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
(void()) main()
(label) main::@return

View File

@ -0,0 +1,18 @@
// Illustrates how inline assembler can reference data from the outside program
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
.label SCREEN = $400
lda table
sta SCREEN+$28
ldx #0
!:
lda table,x
sta SCREEN+1,x
inx
cpx #4
bne !-
rts
}
table: .text "cml!"

View File

@ -0,0 +1,16 @@
@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*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) $28) ← *((const byte[]) table#0)
asm { ldx#0 !: ldatable,x staSCREEN+1,x inx cpx#4 bne!- }
to:main::@return
main::@return: scope:[main] from main
[6] return
to:@return

View File

@ -0,0 +1,253 @@
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte[]) table#0 ← (const string) $0
to:@1
main: scope:[main] from @1
(byte*) main::SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400
(byte*~) main::$0 ← (byte*) main::SCREEN#0 + (byte/signed byte/word/signed word/dword/signed dword) $28
*((byte*~) main::$0) ← *((byte[]) table#0 + (byte/signed byte/word/signed word/dword/signed dword) 0)
asm { ldx#0 !: ldatable,x staSCREEN+1,x inx cpx#4 bne!- }
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
(const string) $0 = (string) "cml!"
(label) @1
(label) @2
(label) @begin
(label) @end
(void()) main()
(byte*~) main::$0
(label) main::@return
(byte*) main::SCREEN
(byte*) main::SCREEN#0
(byte[]) table
(byte[]) table#0
Culled Empty Block (label) @2
Successful SSA optimization Pass2CullEmptyBlocks
Constant (const byte[]) table#0 = $0
Constant (const byte*) main::SCREEN#0 = ((byte*))$400
Successful SSA optimization Pass2ConstantIdentification
Constant (const byte*) main::$0 = main::SCREEN#0+$28
Successful SSA optimization Pass2ConstantIdentification
Consolidated array index constant in *(table#0+0)
Successful SSA optimization Pass2ConstantAdditionElimination
Constant inlined $0 = (const byte[]) table#0
Constant inlined main::$0 = (const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) $28
Successful SSA optimization Pass2ConstantInlining
Simplifying constant plus zero table#0+0
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
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
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*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) $28) ← *((const byte[]) table#0)
asm { ldx#0 !: ldatable,x staSCREEN+1,x inx cpx#4 bne!- }
to:main::@return
main::@return: scope:[main] from main
[6] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte*) main::SCREEN
(byte[]) table
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
//SEG0 File Comments
// Illustrates how inline assembler can reference data from the outside program
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
jsr main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG8 @end
bend:
//SEG9 main
main: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) $28) ← *((const byte[]) table#0) -- _deref_pbuc1=_deref_pbuc2
lda table
sta SCREEN+$28
//SEG11 asm { ldx#0 !: ldatable,x staSCREEN+1,x inx cpx#4 bne!- }
ldx #0
!:
lda table,x
sta SCREEN+1,x
inx
cpx #4
bne !-
jmp breturn
//SEG12 main::@return
breturn:
//SEG13 [6] return
rts
}
table: .text "cml!"
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) $28) ← *((const byte[]) table#0) [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement asm { ldx#0 !: ldatable,x staSCREEN+1,x inx cpx#4 bne!- } always clobbers reg byte a reg byte x
REGISTER UPLIFT SCOPES
Uplift Scope [main]
Uplift Scope []
Uplifting [main] best 47 combination
Uplifting [] best 47 combination
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Illustrates how inline assembler can reference data from the outside program
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
jsr main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG8 @end
bend:
//SEG9 main
main: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) $28) ← *((const byte[]) table#0) -- _deref_pbuc1=_deref_pbuc2
lda table
sta SCREEN+$28
//SEG11 asm { ldx#0 !: ldatable,x staSCREEN+1,x inx cpx#4 bne!- }
ldx #0
!:
lda table,x
sta SCREEN+1,x
inx
cpx #4
bne !-
jmp breturn
//SEG12 main::@return
breturn:
//SEG13 [6] return
rts
}
table: .text "cml!"
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
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
(byte[]) table
(const byte[]) table#0 table = (string) "cml!"
FINAL ASSEMBLER
Score: 32
//SEG0 File Comments
// Illustrates how inline assembler can reference data from the outside program
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//SEG3 @begin
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
//SEG5 @1
//SEG6 [2] call main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
//SEG8 @end
//SEG9 main
main: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) $28) ← *((const byte[]) table#0) -- _deref_pbuc1=_deref_pbuc2
lda table
sta SCREEN+$28
//SEG11 asm { ldx#0 !: ldatable,x staSCREEN+1,x inx cpx#4 bne!- }
ldx #0
!:
lda table,x
sta SCREEN+1,x
inx
cpx #4
bne !-
//SEG12 main::@return
//SEG13 [6] return
rts
}
table: .text "cml!"

View File

@ -0,0 +1,10 @@
(label) @1
(label) @begin
(label) @end
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
(byte[]) table
(const byte[]) table#0 table = (string) "cml!"

View File

@ -0,0 +1,45 @@
// Example of inline kickasm data
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label sintab = $1000
main: {
.label screen = 2
.label cols = 4
lda #<$d800
sta cols
lda #>$d800
sta cols+1
lda #<$400
sta screen
lda #>$400
sta screen+1
ldx #0
b1:
ldy sintab,x
lda #'*'
sta (screen),y
lda screen
clc
adc #$28
sta screen
bcc !+
inc screen+1
!:
lda #1
sta (cols),y
lda cols
clc
adc #$28
sta cols
bcc !+
inc cols+1
!:
inx
cpx #$19
bne b1
rts
}
.pc = sintab "sintab"
.fill 25, 20 + 20*sin(toRadians(i*360/25))

View File

@ -0,0 +1,28 @@
@begin: scope:[] from
kickasm(location (const byte*) sintab#0) {{ .fill 25, 20 + 20*sin(toRadians(i*360/25))
}}
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::@1
[5] (byte*) main::cols#2 ← phi( main/((byte*))(word/dword/signed dword) $d800 main::@1/(byte*) main::cols#1 )
[5] (byte*) main::screen#2 ← phi( main/((byte*))(word/signed word/dword/signed dword) $400 main::@1/(byte*) main::screen#1 )
[5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@1/(byte) main::i#1 )
[6] (byte) main::sin#0 ← *((const byte*) sintab#0 + (byte) main::i#2)
[7] *((byte*) main::screen#2 + (byte) main::sin#0) ← (byte) '*'
[8] (byte*) main::screen#1 ← (byte*) main::screen#2 + (byte/signed byte/word/signed word/dword/signed dword) $28
[9] *((byte*) main::cols#2 + (byte) main::sin#0) ← (byte/signed byte/word/signed word/dword/signed dword) 1
[10] (byte*) main::cols#1 ← (byte*) main::cols#2 + (byte/signed byte/word/signed word/dword/signed dword) $28
[11] (byte) main::i#1 ← ++ (byte) main::i#2
[12] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $19) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[13] return
to:@return

View File

@ -0,0 +1,505 @@
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte*) sintab#0 ← ((byte*)) (word/signed word/dword/signed dword) $1000
kickasm(location (byte*) sintab#0) {{ .fill 25, 20 + 20*sin(toRadians(i*360/25))
}}
to:@1
main: scope:[main] from @1
(byte*) main::screen#0 ← ((byte*)) (word/signed word/dword/signed dword) $400
(byte*) main::cols#0 ← ((byte*)) (word/dword/signed dword) $d800
(byte) main::i#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:main::@1
main::@1: scope:[main] from main main::@1
(byte*) main::cols#2 ← phi( main/(byte*) main::cols#0 main::@1/(byte*) main::cols#1 )
(byte*) main::screen#2 ← phi( main/(byte*) main::screen#0 main::@1/(byte*) main::screen#1 )
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 )
(byte) main::sin#0 ← *((byte*) sintab#0 + (byte) main::i#2)
*((byte*) main::screen#2 + (byte) main::sin#0) ← (byte) '*'
(byte*) main::screen#1 ← (byte*) main::screen#2 + (byte/signed byte/word/signed word/dword/signed dword) $28
*((byte*) main::cols#2 + (byte) main::sin#0) ← (byte/signed byte/word/signed word/dword/signed dword) 1
(byte*) main::cols#1 ← (byte*) main::cols#2 + (byte/signed byte/word/signed word/dword/signed dword) $28
(byte) main::i#1 ← (byte) main::i#2 + rangenext(0,$18)
(bool~) main::$0 ← (byte) main::i#1 != rangelast(0,$18)
if((bool~) main::$0) goto main::@1
to:main::@return
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
(void()) main()
(bool~) main::$0
(label) main::@1
(label) main::@return
(byte*) main::cols
(byte*) main::cols#0
(byte*) main::cols#1
(byte*) main::cols#2
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte*) main::screen
(byte*) main::screen#0
(byte*) main::screen#1
(byte*) main::screen#2
(byte) main::sin
(byte) main::sin#0
(byte*) sintab
(byte*) sintab#0
Culled Empty Block (label) @2
Successful SSA optimization Pass2CullEmptyBlocks
Simple Condition (bool~) main::$0 [13] if((byte) main::i#1!=rangelast(0,$18)) goto main::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte*) sintab#0 = ((byte*))$1000
Constant (const byte*) main::screen#0 = ((byte*))$400
Constant (const byte*) main::cols#0 = ((byte*))$d800
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Resolved ranged next value main::i#1 ← ++ main::i#2 to ++
Resolved ranged comparison value if(main::i#1!=rangelast(0,$18)) goto main::@1 to (byte/signed byte/word/signed word/dword/signed dword) $19
Inlining constant with var siblings (const byte*) main::screen#0
Inlining constant with var siblings (const byte*) main::cols#0
Inlining constant with var siblings (const byte) main::i#0
Constant inlined main::screen#0 = ((byte*))(word/signed word/dword/signed dword) $400
Constant inlined main::i#0 = (byte/signed byte/word/signed word/dword/signed dword) 0
Constant inlined main::cols#0 = ((byte*))(word/dword/signed dword) $d800
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting main::@3(between main::@1 and main::@1)
Adding NOP phi() at start of @1
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 [14] main::i#3 ← main::i#1
Coalesced [15] main::screen#3 ← main::screen#1
Coalesced [16] main::cols#3 ← main::cols#1
Coalesced down to 3 phi equivalence classes
Culled Empty Block (label) main::@3
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
kickasm(location (const byte*) sintab#0) {{ .fill 25, 20 + 20*sin(toRadians(i*360/25))
}}
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::@1
[5] (byte*) main::cols#2 ← phi( main/((byte*))(word/dword/signed dword) $d800 main::@1/(byte*) main::cols#1 )
[5] (byte*) main::screen#2 ← phi( main/((byte*))(word/signed word/dword/signed dword) $400 main::@1/(byte*) main::screen#1 )
[5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@1/(byte) main::i#1 )
[6] (byte) main::sin#0 ← *((const byte*) sintab#0 + (byte) main::i#2)
[7] *((byte*) main::screen#2 + (byte) main::sin#0) ← (byte) '*'
[8] (byte*) main::screen#1 ← (byte*) main::screen#2 + (byte/signed byte/word/signed word/dword/signed dword) $28
[9] *((byte*) main::cols#2 + (byte) main::sin#0) ← (byte/signed byte/word/signed word/dword/signed dword) 1
[10] (byte*) main::cols#1 ← (byte*) main::cols#2 + (byte/signed byte/word/signed word/dword/signed dword) $28
[11] (byte) main::i#1 ← ++ (byte) main::i#2
[12] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $19) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[13] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte*) main::cols
(byte*) main::cols#1 7.333333333333333
(byte*) main::cols#2 6.6000000000000005
(byte) main::i
(byte) main::i#1 16.5
(byte) main::i#2 5.5
(byte*) main::screen
(byte*) main::screen#1 4.4
(byte*) main::screen#2 11.0
(byte) main::sin
(byte) main::sin#0 11.0
(byte*) sintab
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
[ main::screen#2 main::screen#1 ]
[ main::cols#2 main::cols#1 ]
Added variable main::sin#0 to zero page equivalence class [ main::sin#0 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::screen#2 main::screen#1 ]
[ main::cols#2 main::cols#1 ]
[ main::sin#0 ]
Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Allocated zp ZP_WORD:3 [ main::screen#2 main::screen#1 ]
Allocated zp ZP_WORD:5 [ main::cols#2 main::cols#1 ]
Allocated zp ZP_BYTE:7 [ main::sin#0 ]
INITIAL ASM
//SEG0 File Comments
// Example of inline kickasm data
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label sintab = $1000
//SEG3 @begin
bbegin:
//SEG4 kickasm(location (const byte*) sintab#0) {{ .fill 25, 20 + 20*sin(toRadians(i*360/25)) }}
//SEG5 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG6 @1
b1:
//SEG7 [2] call main
//SEG8 [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
//SEG9 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG10 @end
bend:
//SEG11 main
main: {
.label sin = 7
.label screen = 3
.label cols = 5
.label i = 2
//SEG12 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG13 [5] phi (byte*) main::cols#2 = ((byte*))(word/dword/signed dword) $d800 [phi:main->main::@1#0] -- pbuz1=pbuc1
lda #<$d800
sta cols
lda #>$d800
sta cols+1
//SEG14 [5] phi (byte*) main::screen#2 = ((byte*))(word/signed word/dword/signed dword) $400 [phi:main->main::@1#1] -- pbuz1=pbuc1
lda #<$400
sta screen
lda #>$400
sta screen+1
//SEG15 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#2] -- vbuz1=vbuc1
lda #0
sta i
jmp b1
//SEG16 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
b1_from_b1:
//SEG17 [5] phi (byte*) main::cols#2 = (byte*) main::cols#1 [phi:main::@1->main::@1#0] -- register_copy
//SEG18 [5] phi (byte*) main::screen#2 = (byte*) main::screen#1 [phi:main::@1->main::@1#1] -- register_copy
//SEG19 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#2] -- register_copy
jmp b1
//SEG20 main::@1
b1:
//SEG21 [6] (byte) main::sin#0 ← *((const byte*) sintab#0 + (byte) main::i#2) -- vbuz1=pbuc1_derefidx_vbuz2
ldy i
lda sintab,y
sta sin
//SEG22 [7] *((byte*) main::screen#2 + (byte) main::sin#0) ← (byte) '*' -- pbuz1_derefidx_vbuz2=vbuc1
lda #'*'
ldy sin
sta (screen),y
//SEG23 [8] (byte*) main::screen#1 ← (byte*) main::screen#2 + (byte/signed byte/word/signed word/dword/signed dword) $28 -- pbuz1=pbuz1_plus_vbuc1
lda screen
clc
adc #$28
sta screen
bcc !+
inc screen+1
!:
//SEG24 [9] *((byte*) main::cols#2 + (byte) main::sin#0) ← (byte/signed byte/word/signed word/dword/signed dword) 1 -- pbuz1_derefidx_vbuz2=vbuc1
lda #1
ldy sin
sta (cols),y
//SEG25 [10] (byte*) main::cols#1 ← (byte*) main::cols#2 + (byte/signed byte/word/signed word/dword/signed dword) $28 -- pbuz1=pbuz1_plus_vbuc1
lda cols
clc
adc #$28
sta cols
bcc !+
inc cols+1
!:
//SEG26 [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG27 [12] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $19) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda i
cmp #$19
bne b1_from_b1
jmp breturn
//SEG28 main::@return
breturn:
//SEG29 [13] return
rts
}
.pc = sintab "sintab"
.fill 25, 20 + 20*sin(toRadians(i*360/25))
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [7] *((byte*) main::screen#2 + (byte) main::sin#0) ← (byte) '*' [ main::i#2 main::screen#2 main::cols#2 main::sin#0 ] ( main:2 [ main::i#2 main::screen#2 main::cols#2 main::sin#0 ] ) 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 ]
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:7 [ main::sin#0 ]
Statement [8] (byte*) main::screen#1 ← (byte*) main::screen#2 + (byte/signed byte/word/signed word/dword/signed dword) $28 [ main::i#2 main::cols#2 main::screen#1 main::sin#0 ] ( main:2 [ main::i#2 main::cols#2 main::screen#1 main::sin#0 ] ) always clobbers reg byte a
Statement [9] *((byte*) main::cols#2 + (byte) main::sin#0) ← (byte/signed byte/word/signed word/dword/signed dword) 1 [ main::i#2 main::cols#2 main::screen#1 ] ( main:2 [ main::i#2 main::cols#2 main::screen#1 ] ) always clobbers reg byte a
Statement [10] (byte*) main::cols#1 ← (byte*) main::cols#2 + (byte/signed byte/word/signed word/dword/signed dword) $28 [ main::i#2 main::screen#1 main::cols#1 ] ( main:2 [ main::i#2 main::screen#1 main::cols#1 ] ) always clobbers reg byte a
Statement [7] *((byte*) main::screen#2 + (byte) main::sin#0) ← (byte) '*' [ main::i#2 main::screen#2 main::cols#2 main::sin#0 ] ( main:2 [ main::i#2 main::screen#2 main::cols#2 main::sin#0 ] ) always clobbers reg byte a
Statement [8] (byte*) main::screen#1 ← (byte*) main::screen#2 + (byte/signed byte/word/signed word/dword/signed dword) $28 [ main::i#2 main::cols#2 main::screen#1 main::sin#0 ] ( main:2 [ main::i#2 main::cols#2 main::screen#1 main::sin#0 ] ) always clobbers reg byte a
Statement [9] *((byte*) main::cols#2 + (byte) main::sin#0) ← (byte/signed byte/word/signed word/dword/signed dword) 1 [ main::i#2 main::cols#2 main::screen#1 ] ( main:2 [ main::i#2 main::cols#2 main::screen#1 ] ) always clobbers reg byte a
Statement [10] (byte*) main::cols#1 ← (byte*) main::cols#2 + (byte/signed byte/word/signed word/dword/signed dword) $28 [ main::i#2 main::screen#1 main::cols#1 ] ( main:2 [ main::i#2 main::screen#1 main::cols#1 ] ) always clobbers reg byte a
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y ,
Potential registers zp ZP_WORD:3 [ main::screen#2 main::screen#1 ] : zp ZP_WORD:3 ,
Potential registers zp ZP_WORD:5 [ main::cols#2 main::cols#1 ] : zp ZP_WORD:5 ,
Potential registers zp ZP_BYTE:7 [ main::sin#0 ] : zp ZP_BYTE:7 , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 22: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 15.4: zp ZP_WORD:3 [ main::screen#2 main::screen#1 ] 13.93: zp ZP_WORD:5 [ main::cols#2 main::cols#1 ] 11: zp ZP_BYTE:7 [ main::sin#0 ]
Uplift Scope []
Uplifting [main] best 1204 combination reg byte x [ main::i#2 main::i#1 ] zp ZP_WORD:3 [ main::screen#2 main::screen#1 ] zp ZP_WORD:5 [ main::cols#2 main::cols#1 ] reg byte y [ main::sin#0 ]
Uplifting [] best 1204 combination
Allocated (was zp ZP_WORD:3) zp ZP_WORD:2 [ main::screen#2 main::screen#1 ]
Allocated (was zp ZP_WORD:5) zp ZP_WORD:4 [ main::cols#2 main::cols#1 ]
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Example of inline kickasm data
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label sintab = $1000
//SEG3 @begin
bbegin:
//SEG4 kickasm(location (const byte*) sintab#0) {{ .fill 25, 20 + 20*sin(toRadians(i*360/25)) }}
//SEG5 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG6 @1
b1:
//SEG7 [2] call main
//SEG8 [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
//SEG9 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG10 @end
bend:
//SEG11 main
main: {
.label screen = 2
.label cols = 4
//SEG12 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG13 [5] phi (byte*) main::cols#2 = ((byte*))(word/dword/signed dword) $d800 [phi:main->main::@1#0] -- pbuz1=pbuc1
lda #<$d800
sta cols
lda #>$d800
sta cols+1
//SEG14 [5] phi (byte*) main::screen#2 = ((byte*))(word/signed word/dword/signed dword) $400 [phi:main->main::@1#1] -- pbuz1=pbuc1
lda #<$400
sta screen
lda #>$400
sta screen+1
//SEG15 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#2] -- vbuxx=vbuc1
ldx #0
jmp b1
//SEG16 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
b1_from_b1:
//SEG17 [5] phi (byte*) main::cols#2 = (byte*) main::cols#1 [phi:main::@1->main::@1#0] -- register_copy
//SEG18 [5] phi (byte*) main::screen#2 = (byte*) main::screen#1 [phi:main::@1->main::@1#1] -- register_copy
//SEG19 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#2] -- register_copy
jmp b1
//SEG20 main::@1
b1:
//SEG21 [6] (byte) main::sin#0 ← *((const byte*) sintab#0 + (byte) main::i#2) -- vbuyy=pbuc1_derefidx_vbuxx
ldy sintab,x
//SEG22 [7] *((byte*) main::screen#2 + (byte) main::sin#0) ← (byte) '*' -- pbuz1_derefidx_vbuyy=vbuc1
lda #'*'
sta (screen),y
//SEG23 [8] (byte*) main::screen#1 ← (byte*) main::screen#2 + (byte/signed byte/word/signed word/dword/signed dword) $28 -- pbuz1=pbuz1_plus_vbuc1
lda screen
clc
adc #$28
sta screen
bcc !+
inc screen+1
!:
//SEG24 [9] *((byte*) main::cols#2 + (byte) main::sin#0) ← (byte/signed byte/word/signed word/dword/signed dword) 1 -- pbuz1_derefidx_vbuyy=vbuc1
lda #1
sta (cols),y
//SEG25 [10] (byte*) main::cols#1 ← (byte*) main::cols#2 + (byte/signed byte/word/signed word/dword/signed dword) $28 -- pbuz1=pbuz1_plus_vbuc1
lda cols
clc
adc #$28
sta cols
bcc !+
inc cols+1
!:
//SEG26 [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG27 [12] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $19) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #$19
bne b1_from_b1
jmp breturn
//SEG28 main::@return
breturn:
//SEG29 [13] return
rts
}
.pc = sintab "sintab"
.fill 25, 20 + 20*sin(toRadians(i*360/25))
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing label b1_from_b1 with b1
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Removing instruction b1_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction b1_from_main:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction jmp b1
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(void()) main()
(label) main::@1
(label) main::@return
(byte*) main::cols
(byte*) main::cols#1 cols zp ZP_WORD:4 7.333333333333333
(byte*) main::cols#2 cols zp ZP_WORD:4 6.6000000000000005
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#2 reg byte x 5.5
(byte*) main::screen
(byte*) main::screen#1 screen zp ZP_WORD:2 4.4
(byte*) main::screen#2 screen zp ZP_WORD:2 11.0
(byte) main::sin
(byte) main::sin#0 reg byte y 11.0
(byte*) sintab
(const byte*) sintab#0 sintab = ((byte*))(word/signed word/dword/signed dword) $1000
reg byte x [ main::i#2 main::i#1 ]
zp ZP_WORD:2 [ main::screen#2 main::screen#1 ]
zp ZP_WORD:4 [ main::cols#2 main::cols#1 ]
reg byte y [ main::sin#0 ]
FINAL ASSEMBLER
Score: 1102
//SEG0 File Comments
// Example of inline kickasm data
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label sintab = $1000
//SEG3 @begin
//SEG4 kickasm(location (const byte*) sintab#0) {{ .fill 25, 20 + 20*sin(toRadians(i*360/25)) }}
//SEG5 [1] phi from @begin to @1 [phi:@begin->@1]
//SEG6 @1
//SEG7 [2] call main
//SEG8 [4] phi from @1 to main [phi:@1->main]
//SEG9 [3] phi from @1 to @end [phi:@1->@end]
//SEG10 @end
//SEG11 main
main: {
.label screen = 2
.label cols = 4
//SEG12 [5] phi from main to main::@1 [phi:main->main::@1]
//SEG13 [5] phi (byte*) main::cols#2 = ((byte*))(word/dword/signed dword) $d800 [phi:main->main::@1#0] -- pbuz1=pbuc1
lda #<$d800
sta cols
lda #>$d800
sta cols+1
//SEG14 [5] phi (byte*) main::screen#2 = ((byte*))(word/signed word/dword/signed dword) $400 [phi:main->main::@1#1] -- pbuz1=pbuc1
lda #<$400
sta screen
lda #>$400
sta screen+1
//SEG15 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#2] -- vbuxx=vbuc1
ldx #0
//SEG16 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
//SEG17 [5] phi (byte*) main::cols#2 = (byte*) main::cols#1 [phi:main::@1->main::@1#0] -- register_copy
//SEG18 [5] phi (byte*) main::screen#2 = (byte*) main::screen#1 [phi:main::@1->main::@1#1] -- register_copy
//SEG19 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#2] -- register_copy
//SEG20 main::@1
b1:
//SEG21 [6] (byte) main::sin#0 ← *((const byte*) sintab#0 + (byte) main::i#2) -- vbuyy=pbuc1_derefidx_vbuxx
ldy sintab,x
//SEG22 [7] *((byte*) main::screen#2 + (byte) main::sin#0) ← (byte) '*' -- pbuz1_derefidx_vbuyy=vbuc1
lda #'*'
sta (screen),y
//SEG23 [8] (byte*) main::screen#1 ← (byte*) main::screen#2 + (byte/signed byte/word/signed word/dword/signed dword) $28 -- pbuz1=pbuz1_plus_vbuc1
lda screen
clc
adc #$28
sta screen
bcc !+
inc screen+1
!:
//SEG24 [9] *((byte*) main::cols#2 + (byte) main::sin#0) ← (byte/signed byte/word/signed word/dword/signed dword) 1 -- pbuz1_derefidx_vbuyy=vbuc1
lda #1
sta (cols),y
//SEG25 [10] (byte*) main::cols#1 ← (byte*) main::cols#2 + (byte/signed byte/word/signed word/dword/signed dword) $28 -- pbuz1=pbuz1_plus_vbuc1
lda cols
clc
adc #$28
sta cols
bcc !+
inc cols+1
!:
//SEG26 [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG27 [12] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $19) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #$19
bne b1
//SEG28 main::@return
//SEG29 [13] return
rts
}
.pc = sintab "sintab"
.fill 25, 20 + 20*sin(toRadians(i*360/25))

View File

@ -0,0 +1,24 @@
(label) @1
(label) @begin
(label) @end
(void()) main()
(label) main::@1
(label) main::@return
(byte*) main::cols
(byte*) main::cols#1 cols zp ZP_WORD:4 7.333333333333333
(byte*) main::cols#2 cols zp ZP_WORD:4 6.6000000000000005
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#2 reg byte x 5.5
(byte*) main::screen
(byte*) main::screen#1 screen zp ZP_WORD:2 4.4
(byte*) main::screen#2 screen zp ZP_WORD:2 11.0
(byte) main::sin
(byte) main::sin#0 reg byte y 11.0
(byte*) sintab
(const byte*) sintab#0 sintab = ((byte*))(word/signed word/dword/signed dword) $1000
reg byte x [ main::i#2 main::i#1 ]
zp ZP_WORD:2 [ main::screen#2 main::screen#1 ]
zp ZP_WORD:4 [ main::cols#2 main::cols#1 ]
reg byte y [ main::sin#0 ]

View File

@ -0,0 +1,15 @@
// Example of inline kickasm in a function
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
.label SCREEN = $400
lda #0
sta SCREEN+$3e8
lda #0
.for (var i = 0; i < 1000; i++) {
sta SCREEN+i
}
rts
}

View File

@ -0,0 +1,20 @@
@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*) main::SCREEN#0+(word/signed word/dword/signed dword) $3e8) ← (byte/signed byte/word/signed word/dword/signed dword) 0
kickasm {{ lda #0
.for (var i = 0; i < 1000; i++) {
sta SCREEN+i
}
}}
to:main::@return
main::@return: scope:[main] from main
[6] return
to:@return

View File

@ -0,0 +1,239 @@
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
main: scope:[main] from @1
(byte*) main::SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400
(byte*~) main::$0 ← (byte*) main::SCREEN#0 + (word/signed word/dword/signed dword) $3e8
*((byte*~) main::$0) ← (byte/signed byte/word/signed word/dword/signed dword) 0
kickasm {{ lda #0
.for (var i = 0; i < 1000; i++) {
sta SCREEN+i
}
}}
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
(void()) main()
(byte*~) main::$0
(label) main::@return
(byte*) main::SCREEN
(byte*) main::SCREEN#0
Culled Empty Block (label) @2
Successful SSA optimization Pass2CullEmptyBlocks
Constant (const byte*) main::SCREEN#0 = ((byte*))$400
Successful SSA optimization Pass2ConstantIdentification
Constant (const byte*) main::$0 = main::SCREEN#0+$3e8
Successful SSA optimization Pass2ConstantIdentification
Constant inlined main::$0 = (const byte*) main::SCREEN#0+(word/signed word/dword/signed dword) $3e8
Successful SSA optimization Pass2ConstantInlining
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
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
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*) main::SCREEN#0+(word/signed word/dword/signed dword) $3e8) ← (byte/signed byte/word/signed word/dword/signed dword) 0
kickasm {{ lda #0
.for (var i = 0; i < 1000; i++) {
sta SCREEN+i
}
}}
to:main::@return
main::@return: scope:[main] from main
[6] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte*) main::SCREEN
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
//SEG0 File Comments
// Example of inline kickasm in a function
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
jsr main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG8 @end
bend:
//SEG9 main
main: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0+(word/signed word/dword/signed dword) $3e8) ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- _deref_pbuc1=vbuc2
lda #0
sta SCREEN+$3e8
//SEG11 kickasm {{ lda #0 .for (var i = 0; i < 1000; i++) { sta SCREEN+i } }}
lda #0
.for (var i = 0; i < 1000; i++) {
sta SCREEN+i
}
jmp breturn
//SEG12 main::@return
breturn:
//SEG13 [6] return
rts
}
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] *((const byte*) main::SCREEN#0+(word/signed word/dword/signed dword) $3e8) ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ ] ( main:2 [ ] ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [main]
Uplift Scope []
Uplifting [main] best 283 combination
Uplifting [] best 283 combination
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Example of inline kickasm in a function
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
jsr main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG8 @end
bend:
//SEG9 main
main: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0+(word/signed word/dword/signed dword) $3e8) ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- _deref_pbuc1=vbuc2
lda #0
sta SCREEN+$3e8
//SEG11 kickasm {{ lda #0 .for (var i = 0; i < 1000; i++) { sta SCREEN+i } }}
lda #0
.for (var i = 0; i < 1000; i++) {
sta SCREEN+i
}
jmp breturn
//SEG12 main::@return
breturn:
//SEG13 [6] return
rts
}
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
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
FINAL ASSEMBLER
Score: 268
//SEG0 File Comments
// Example of inline kickasm in a function
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//SEG3 @begin
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
//SEG5 @1
//SEG6 [2] call main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
//SEG8 @end
//SEG9 main
main: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0+(word/signed word/dword/signed dword) $3e8) ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- _deref_pbuc1=vbuc2
lda #0
sta SCREEN+$3e8
//SEG11 kickasm {{ lda #0 .for (var i = 0; i < 1000; i++) { sta SCREEN+i } }}
lda #0
.for (var i = 0; i < 1000; i++) {
sta SCREEN+i
}
//SEG12 main::@return
//SEG13 [6] return
rts
}

View File

@ -0,0 +1,8 @@
(label) @1
(label) @begin
(label) @end
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400

View File

@ -0,0 +1,25 @@
// Example of inline kickasm resource data
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label SPRITE = $c00
.label SCREEN = $400
.label SPRITES_ENABLE = $d015
.label SPRITES_XPOS = $d000
.label SPRITES_YPOS = $d001
main: {
lda #$ff&SPRITE/$40
sta SCREEN+$3f8
lda #1
sta SPRITES_ENABLE
lda #$64
sta SPRITES_XPOS
sta SPRITES_YPOS
rts
}
.pc = SPRITE "SPRITE"
.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)

View File

@ -0,0 +1,22 @@
@begin: scope:[] from
kickasm(location (const byte*) SPRITE#0) {{ .var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)
}}
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+(word/signed word/dword/signed dword) $3f8) ← ((byte))(const byte*) SPRITE#0/(byte/signed byte/word/signed word/dword/signed dword) $40
[5] *((const byte*) SPRITES_ENABLE#0) ← (byte/signed byte/word/signed word/dword/signed dword) 1
[6] *((const byte*) SPRITES_XPOS#0) ← (byte/signed byte/word/signed word/dword/signed dword) $64
[7] *((const byte*) SPRITES_YPOS#0) ← (byte/signed byte/word/signed word/dword/signed dword) $64
to:main::@return
main::@return: scope:[main] from main
[8] return
to:@return

View File

@ -0,0 +1,325 @@
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte*) SPRITE#0 ← ((byte*)) (word/signed word/dword/signed dword) $c00
kickasm(location (byte*) SPRITE#0) {{ .var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)
}}
(byte*) SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400
(byte*) SPRITES_ENABLE#0 ← ((byte*)) (word/dword/signed dword) $d015
(byte*) SPRITES_XPOS#0 ← ((byte*)) (word/dword/signed dword) $d000
(byte*) SPRITES_YPOS#0 ← ((byte*)) (word/dword/signed dword) $d001
to:@1
main: scope:[main] from @1
(byte*~) main::$0 ← (byte*) SCREEN#0 + (word/signed word/dword/signed dword) $3f8
(byte*~) main::$1 ← (byte*) SPRITE#0 / (byte/signed byte/word/signed word/dword/signed dword) $40
(byte~) main::$2 ← ((byte)) (byte*~) main::$1
*((byte*~) main::$0) ← (byte~) main::$2
*((byte*) SPRITES_ENABLE#0) ← (byte/signed byte/word/signed word/dword/signed dword) 1
*((byte*) SPRITES_XPOS#0) ← (byte/signed byte/word/signed word/dword/signed dword) $64
*((byte*) SPRITES_YPOS#0) ← (byte/signed byte/word/signed word/dword/signed dword) $64
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
(byte*) SCREEN
(byte*) SCREEN#0
(byte*) SPRITE
(byte*) SPRITE#0
(byte*) SPRITES_ENABLE
(byte*) SPRITES_ENABLE#0
(byte*) SPRITES_XPOS
(byte*) SPRITES_XPOS#0
(byte*) SPRITES_YPOS
(byte*) SPRITES_YPOS#0
(void()) main()
(byte*~) main::$0
(byte*~) main::$1
(byte~) main::$2
(label) main::@return
Culled Empty Block (label) @2
Successful SSA optimization Pass2CullEmptyBlocks
Constant (const byte*) SPRITE#0 = ((byte*))$c00
Constant (const byte*) SCREEN#0 = ((byte*))$400
Constant (const byte*) SPRITES_ENABLE#0 = ((byte*))$d015
Constant (const byte*) SPRITES_XPOS#0 = ((byte*))$d000
Constant (const byte*) SPRITES_YPOS#0 = ((byte*))$d001
Successful SSA optimization Pass2ConstantIdentification
Constant (const byte*) main::$0 = SCREEN#0+$3f8
Constant (const byte*) main::$1 = SPRITE#0/$40
Successful SSA optimization Pass2ConstantIdentification
Constant (const byte) main::$2 = ((byte))main::$1
Successful SSA optimization Pass2ConstantIdentification
Constant inlined main::$1 = (const byte*) SPRITE#0/(byte/signed byte/word/signed word/dword/signed dword) $40
Constant inlined main::$2 = ((byte))(const byte*) SPRITE#0/(byte/signed byte/word/signed word/dword/signed dword) $40
Constant inlined main::$0 = (const byte*) SCREEN#0+(word/signed word/dword/signed dword) $3f8
Successful SSA optimization Pass2ConstantInlining
Adding NOP phi() at start of @1
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
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
kickasm(location (const byte*) SPRITE#0) {{ .var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)
}}
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+(word/signed word/dword/signed dword) $3f8) ← ((byte))(const byte*) SPRITE#0/(byte/signed byte/word/signed word/dword/signed dword) $40
[5] *((const byte*) SPRITES_ENABLE#0) ← (byte/signed byte/word/signed word/dword/signed dword) 1
[6] *((const byte*) SPRITES_XPOS#0) ← (byte/signed byte/word/signed word/dword/signed dword) $64
[7] *((const byte*) SPRITES_YPOS#0) ← (byte/signed byte/word/signed word/dword/signed dword) $64
to:main::@return
main::@return: scope:[main] from main
[8] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte*) SCREEN
(byte*) SPRITE
(byte*) SPRITES_ENABLE
(byte*) SPRITES_XPOS
(byte*) SPRITES_YPOS
(void()) main()
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
//SEG0 File Comments
// Example of inline kickasm resource data
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SPRITE = $c00
.label SCREEN = $400
.label SPRITES_ENABLE = $d015
.label SPRITES_XPOS = $d000
.label SPRITES_YPOS = $d001
//SEG3 @begin
bbegin:
//SEG4 kickasm(location (const byte*) SPRITE#0) {{ .var pic = LoadPicture("balloon.png", List().add($000000, $ffffff)) .for (var y=0; y<21; y++) .for (var x=0;x<3; x++) .byte pic.getSinglecolorByte(x,y) }}
//SEG5 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG6 @1
b1:
//SEG7 [2] call main
jsr main
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG9 @end
bend:
//SEG10 main
main: {
//SEG11 [4] *((const byte*) SCREEN#0+(word/signed word/dword/signed dword) $3f8) ← ((byte))(const byte*) SPRITE#0/(byte/signed byte/word/signed word/dword/signed dword) $40 -- _deref_pbuc1=vbuc2
lda #$ff&SPRITE/$40
sta SCREEN+$3f8
//SEG12 [5] *((const byte*) SPRITES_ENABLE#0) ← (byte/signed byte/word/signed word/dword/signed dword) 1 -- _deref_pbuc1=vbuc2
lda #1
sta SPRITES_ENABLE
//SEG13 [6] *((const byte*) SPRITES_XPOS#0) ← (byte/signed byte/word/signed word/dword/signed dword) $64 -- _deref_pbuc1=vbuc2
lda #$64
sta SPRITES_XPOS
//SEG14 [7] *((const byte*) SPRITES_YPOS#0) ← (byte/signed byte/word/signed word/dword/signed dword) $64 -- _deref_pbuc1=vbuc2
lda #$64
sta SPRITES_YPOS
jmp breturn
//SEG15 main::@return
breturn:
//SEG16 [8] return
rts
}
.pc = SPRITE "SPRITE"
.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] *((const byte*) SCREEN#0+(word/signed word/dword/signed dword) $3f8) ← ((byte))(const byte*) SPRITE#0/(byte/signed byte/word/signed word/dword/signed dword) $40 [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [5] *((const byte*) SPRITES_ENABLE#0) ← (byte/signed byte/word/signed word/dword/signed dword) 1 [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [6] *((const byte*) SPRITES_XPOS#0) ← (byte/signed byte/word/signed word/dword/signed dword) $64 [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [7] *((const byte*) SPRITES_YPOS#0) ← (byte/signed byte/word/signed word/dword/signed dword) $64 [ ] ( main:2 [ ] ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [main]
Uplift Scope []
Uplifting [main] best 301 combination
Uplifting [] best 301 combination
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Example of inline kickasm resource data
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SPRITE = $c00
.label SCREEN = $400
.label SPRITES_ENABLE = $d015
.label SPRITES_XPOS = $d000
.label SPRITES_YPOS = $d001
//SEG3 @begin
bbegin:
//SEG4 kickasm(location (const byte*) SPRITE#0) {{ .var pic = LoadPicture("balloon.png", List().add($000000, $ffffff)) .for (var y=0; y<21; y++) .for (var x=0;x<3; x++) .byte pic.getSinglecolorByte(x,y) }}
//SEG5 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG6 @1
b1:
//SEG7 [2] call main
jsr main
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG9 @end
bend:
//SEG10 main
main: {
//SEG11 [4] *((const byte*) SCREEN#0+(word/signed word/dword/signed dword) $3f8) ← ((byte))(const byte*) SPRITE#0/(byte/signed byte/word/signed word/dword/signed dword) $40 -- _deref_pbuc1=vbuc2
lda #$ff&SPRITE/$40
sta SCREEN+$3f8
//SEG12 [5] *((const byte*) SPRITES_ENABLE#0) ← (byte/signed byte/word/signed word/dword/signed dword) 1 -- _deref_pbuc1=vbuc2
lda #1
sta SPRITES_ENABLE
//SEG13 [6] *((const byte*) SPRITES_XPOS#0) ← (byte/signed byte/word/signed word/dword/signed dword) $64 -- _deref_pbuc1=vbuc2
lda #$64
sta SPRITES_XPOS
//SEG14 [7] *((const byte*) SPRITES_YPOS#0) ← (byte/signed byte/word/signed word/dword/signed dword) $64 -- _deref_pbuc1=vbuc2
lda #$64
sta SPRITES_YPOS
jmp breturn
//SEG15 main::@return
breturn:
//SEG16 [8] return
rts
}
.pc = SPRITE "SPRITE"
.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction lda #$64
Succesful ASM optimization Pass5UnnecesaryLoadElimination
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*))(word/signed word/dword/signed dword) $400
(byte*) SPRITE
(const byte*) SPRITE#0 SPRITE = ((byte*))(word/signed word/dword/signed dword) $c00
(byte*) SPRITES_ENABLE
(const byte*) SPRITES_ENABLE#0 SPRITES_ENABLE = ((byte*))(word/dword/signed dword) $d015
(byte*) SPRITES_XPOS
(const byte*) SPRITES_XPOS#0 SPRITES_XPOS = ((byte*))(word/dword/signed dword) $d000
(byte*) SPRITES_YPOS
(const byte*) SPRITES_YPOS#0 SPRITES_YPOS = ((byte*))(word/dword/signed dword) $d001
(void()) main()
(label) main::@return
FINAL ASSEMBLER
Score: 284
//SEG0 File Comments
// Example of inline kickasm resource data
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SPRITE = $c00
.label SCREEN = $400
.label SPRITES_ENABLE = $d015
.label SPRITES_XPOS = $d000
.label SPRITES_YPOS = $d001
//SEG3 @begin
//SEG4 kickasm(location (const byte*) SPRITE#0) {{ .var pic = LoadPicture("balloon.png", List().add($000000, $ffffff)) .for (var y=0; y<21; y++) .for (var x=0;x<3; x++) .byte pic.getSinglecolorByte(x,y) }}
//SEG5 [1] phi from @begin to @1 [phi:@begin->@1]
//SEG6 @1
//SEG7 [2] call main
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
//SEG9 @end
//SEG10 main
main: {
//SEG11 [4] *((const byte*) SCREEN#0+(word/signed word/dword/signed dword) $3f8) ← ((byte))(const byte*) SPRITE#0/(byte/signed byte/word/signed word/dword/signed dword) $40 -- _deref_pbuc1=vbuc2
lda #$ff&SPRITE/$40
sta SCREEN+$3f8
//SEG12 [5] *((const byte*) SPRITES_ENABLE#0) ← (byte/signed byte/word/signed word/dword/signed dword) 1 -- _deref_pbuc1=vbuc2
lda #1
sta SPRITES_ENABLE
//SEG13 [6] *((const byte*) SPRITES_XPOS#0) ← (byte/signed byte/word/signed word/dword/signed dword) $64 -- _deref_pbuc1=vbuc2
lda #$64
sta SPRITES_XPOS
//SEG14 [7] *((const byte*) SPRITES_YPOS#0) ← (byte/signed byte/word/signed word/dword/signed dword) $64 -- _deref_pbuc1=vbuc2
sta SPRITES_YPOS
//SEG15 main::@return
//SEG16 [8] return
rts
}
.pc = SPRITE "SPRITE"
.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)

View File

@ -0,0 +1,16 @@
(label) @1
(label) @begin
(label) @end
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
(byte*) SPRITE
(const byte*) SPRITE#0 SPRITE = ((byte*))(word/signed word/dword/signed dword) $c00
(byte*) SPRITES_ENABLE
(const byte*) SPRITES_ENABLE#0 SPRITES_ENABLE = ((byte*))(word/dword/signed dword) $d015
(byte*) SPRITES_XPOS
(const byte*) SPRITES_XPOS#0 SPRITES_XPOS = ((byte*))(word/dword/signed dword) $d000
(byte*) SPRITES_YPOS
(const byte*) SPRITES_YPOS#0 SPRITES_YPOS = ((byte*))(word/dword/signed dword) $d001
(void()) main()
(label) main::@return