mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-09-08 17:54:40 +00:00
Added another example of loophead optimization giving wrong return value. #290
This commit is contained in:
parent
2739456cc3
commit
b97d8300b3
@ -42,11 +42,10 @@ public class TestPrograms {
|
|||||||
compileAndCompare("optimize-unsigned-comparisons");
|
compileAndCompare("optimize-unsigned-comparisons");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Fix loop head problem! https://gitlab.com/camelot/kickc/issues/290
|
||||||
// TODO: Fix loop head problem! https://gitlab.com/camelot/kickc/issues/261
|
|
||||||
@Test
|
@Test
|
||||||
public void testLoopheadProblem() throws IOException, URISyntaxException {
|
public void testLoopheadProblem3() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("loophead-problem");
|
compileAndCompare("loophead-problem-3");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Fix loop head problem! https://gitlab.com/camelot/kickc/issues/290
|
// TODO: Fix loop head problem! https://gitlab.com/camelot/kickc/issues/290
|
||||||
@ -55,6 +54,11 @@ public class TestPrograms {
|
|||||||
compileAndCompare("loophead-problem-2");
|
compileAndCompare("loophead-problem-2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Fix loop head problem! https://gitlab.com/camelot/kickc/issues/261
|
||||||
|
@Test
|
||||||
|
public void testLoopheadProblem() throws IOException, URISyntaxException {
|
||||||
|
compileAndCompare("loophead-problem");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAsmMnemonicNames() throws IOException, URISyntaxException {
|
public void testAsmMnemonicNames() throws IOException, URISyntaxException {
|
||||||
|
12
src/test/kc/loophead-problem-3.kc
Normal file
12
src/test/kc/loophead-problem-3.kc
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Program where loop-head optimization produces wrong return value
|
||||||
|
// Reported by Richard-William Loerakker
|
||||||
|
|
||||||
|
import "c64"
|
||||||
|
import "multiply"
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
dword result = mul16u(4,123);
|
||||||
|
word kaputt = <result;
|
||||||
|
*BORDERCOL = <kaputt;
|
||||||
|
*BGCOL = >kaputt;
|
||||||
|
}
|
79
src/test/ref/loophead-problem-3.asm
Normal file
79
src/test/ref/loophead-problem-3.asm
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// Program where loop-head optimization produces wrong return value
|
||||||
|
// Reported by Richard-William Loerakker
|
||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
.label BORDERCOL = $d020
|
||||||
|
.label BGCOL = $d021
|
||||||
|
main: {
|
||||||
|
.label result = 2
|
||||||
|
.label kaputt = $a
|
||||||
|
jsr mul16u
|
||||||
|
lda.z result
|
||||||
|
sta.z kaputt
|
||||||
|
lda.z result+1
|
||||||
|
sta.z kaputt+1
|
||||||
|
lda.z kaputt
|
||||||
|
sta BORDERCOL
|
||||||
|
lda.z kaputt+1
|
||||||
|
sta BGCOL
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// Perform binary multiplication of two unsigned 16-bit words into a 32-bit unsigned double word
|
||||||
|
// mul16u(word zeropage($a) a)
|
||||||
|
mul16u: {
|
||||||
|
.const b = $7b
|
||||||
|
.label a = $a
|
||||||
|
.label mb = 6
|
||||||
|
.label res = 2
|
||||||
|
.label return = 2
|
||||||
|
lda #<b
|
||||||
|
sta.z mb
|
||||||
|
lda #>b
|
||||||
|
sta.z mb+1
|
||||||
|
lda #<b>>$10
|
||||||
|
sta.z mb+2
|
||||||
|
lda #>b>>$10
|
||||||
|
sta.z mb+3
|
||||||
|
lda #0
|
||||||
|
sta.z res
|
||||||
|
sta.z res+1
|
||||||
|
sta.z res+2
|
||||||
|
sta.z res+3
|
||||||
|
lda #<4
|
||||||
|
sta.z a
|
||||||
|
lda #>4
|
||||||
|
sta.z a+1
|
||||||
|
b1:
|
||||||
|
lda.z a
|
||||||
|
bne b2
|
||||||
|
lda.z a+1
|
||||||
|
bne b2
|
||||||
|
rts
|
||||||
|
b2:
|
||||||
|
lda #1
|
||||||
|
and.z a
|
||||||
|
cmp #0
|
||||||
|
beq b3
|
||||||
|
lda.z res
|
||||||
|
clc
|
||||||
|
adc.z mb
|
||||||
|
sta.z res
|
||||||
|
lda.z res+1
|
||||||
|
adc.z mb+1
|
||||||
|
sta.z res+1
|
||||||
|
lda.z res+2
|
||||||
|
adc.z mb+2
|
||||||
|
sta.z res+2
|
||||||
|
lda.z res+3
|
||||||
|
adc.z mb+3
|
||||||
|
sta.z res+3
|
||||||
|
b3:
|
||||||
|
lsr.z a+1
|
||||||
|
ror.z a
|
||||||
|
asl.z mb
|
||||||
|
rol.z mb+1
|
||||||
|
rol.z mb+2
|
||||||
|
rol.z mb+3
|
||||||
|
jmp b1
|
||||||
|
}
|
49
src/test/ref/loophead-problem-3.cfg
Normal file
49
src/test/ref/loophead-problem-3.cfg
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
@begin: scope:[] from
|
||||||
|
[0] phi()
|
||||||
|
to:@1
|
||||||
|
@1: scope:[] from @begin
|
||||||
|
[1] phi()
|
||||||
|
[2] call main
|
||||||
|
to:@end
|
||||||
|
@end: scope:[] from @1
|
||||||
|
[3] phi()
|
||||||
|
main: scope:[main] from @1
|
||||||
|
[4] phi()
|
||||||
|
[5] call mul16u
|
||||||
|
[6] (dword) mul16u::return#2 ← (dword) mul16u::res#2
|
||||||
|
to:main::@1
|
||||||
|
main::@1: scope:[main] from main
|
||||||
|
[7] (dword) main::result#0 ← (dword) mul16u::return#2
|
||||||
|
[8] (word) main::kaputt#0 ← < (dword) main::result#0
|
||||||
|
[9] (byte~) main::$2 ← < (word) main::kaputt#0
|
||||||
|
[10] *((const byte*) BORDERCOL#0) ← (byte~) main::$2
|
||||||
|
[11] (byte~) main::$3 ← > (word) main::kaputt#0
|
||||||
|
[12] *((const byte*) BGCOL#0) ← (byte~) main::$3
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main::@1
|
||||||
|
[13] return
|
||||||
|
to:@return
|
||||||
|
mul16u: scope:[mul16u] from main
|
||||||
|
[14] phi()
|
||||||
|
to:mul16u::@1
|
||||||
|
mul16u::@1: scope:[mul16u] from mul16u mul16u::@3
|
||||||
|
[15] (dword) mul16u::mb#2 ← phi( mul16u/(const word) mul16u::b#0 mul16u::@3/(dword) mul16u::mb#1 )
|
||||||
|
[15] (dword) mul16u::res#2 ← phi( mul16u/(byte) 0 mul16u::@3/(dword) mul16u::res#6 )
|
||||||
|
[15] (word) mul16u::a#2 ← phi( mul16u/(byte) 4 mul16u::@3/(word) mul16u::a#0 )
|
||||||
|
[16] if((word) mul16u::a#2!=(byte) 0) goto mul16u::@2
|
||||||
|
to:mul16u::@return
|
||||||
|
mul16u::@return: scope:[mul16u] from mul16u::@1
|
||||||
|
[17] return
|
||||||
|
to:@return
|
||||||
|
mul16u::@2: scope:[mul16u] from mul16u::@1
|
||||||
|
[18] (byte~) mul16u::$1 ← (word) mul16u::a#2 & (byte) 1
|
||||||
|
[19] if((byte~) mul16u::$1==(byte) 0) goto mul16u::@3
|
||||||
|
to:mul16u::@4
|
||||||
|
mul16u::@4: scope:[mul16u] from mul16u::@2
|
||||||
|
[20] (dword) mul16u::res#1 ← (dword) mul16u::res#2 + (dword) mul16u::mb#2
|
||||||
|
to:mul16u::@3
|
||||||
|
mul16u::@3: scope:[mul16u] from mul16u::@2 mul16u::@4
|
||||||
|
[21] (dword) mul16u::res#6 ← phi( mul16u::@2/(dword) mul16u::res#2 mul16u::@4/(dword) mul16u::res#1 )
|
||||||
|
[22] (word) mul16u::a#0 ← (word) mul16u::a#2 >> (byte) 1
|
||||||
|
[23] (dword) mul16u::mb#1 ← (dword) mul16u::mb#2 << (byte) 1
|
||||||
|
to:mul16u::@1
|
964
src/test/ref/loophead-problem-3.log
Normal file
964
src/test/ref/loophead-problem-3.log
Normal file
@ -0,0 +1,964 @@
|
|||||||
|
Inlined call (byte~) vicSelectGfxBank::$0 ← call toDd00 (byte*) vicSelectGfxBank::gfx
|
||||||
|
Culled Empty Block (label) @1
|
||||||
|
Culled Empty Block (label) @2
|
||||||
|
Culled Empty Block (label) @3
|
||||||
|
Culled Empty Block (label) @4
|
||||||
|
Culled Empty Block (label) @5
|
||||||
|
Culled Empty Block (label) @6
|
||||||
|
Culled Empty Block (label) @7
|
||||||
|
Culled Empty Block (label) mul16u::@5
|
||||||
|
Culled Empty Block (label) mul16u::@6
|
||||||
|
Culled Empty Block (label) mul16u::@8
|
||||||
|
Culled Empty Block (label) mul16u::@9
|
||||||
|
Culled Empty Block (label) @8
|
||||||
|
Culled Empty Block (label) @9
|
||||||
|
|
||||||
|
CONTROL FLOW GRAPH SSA
|
||||||
|
@begin: scope:[] from
|
||||||
|
(byte*) BORDERCOL#0 ← ((byte*)) (number) $d020
|
||||||
|
(byte*) BGCOL#0 ← ((byte*)) (number) $d021
|
||||||
|
to:@10
|
||||||
|
mul16u: scope:[mul16u] from main
|
||||||
|
(word) mul16u::a#5 ← phi( main/(word) mul16u::a#1 )
|
||||||
|
(word) mul16u::b#1 ← phi( main/(word) mul16u::b#0 )
|
||||||
|
(dword) mul16u::res#0 ← (number) 0
|
||||||
|
(dword) mul16u::mb#0 ← (word) mul16u::b#1
|
||||||
|
to:mul16u::@1
|
||||||
|
mul16u::@1: scope:[mul16u] from mul16u mul16u::@4
|
||||||
|
(dword) mul16u::mb#5 ← phi( mul16u/(dword) mul16u::mb#0 mul16u::@4/(dword) mul16u::mb#1 )
|
||||||
|
(dword) mul16u::res#4 ← phi( mul16u/(dword) mul16u::res#0 mul16u::@4/(dword) mul16u::res#6 )
|
||||||
|
(word) mul16u::a#2 ← phi( mul16u/(word) mul16u::a#5 mul16u::@4/(word) mul16u::a#0 )
|
||||||
|
(bool~) mul16u::$0 ← (word) mul16u::a#2 != (number) 0
|
||||||
|
if((bool~) mul16u::$0) goto mul16u::@2
|
||||||
|
to:mul16u::@3
|
||||||
|
mul16u::@2: scope:[mul16u] from mul16u::@1
|
||||||
|
(dword) mul16u::res#5 ← phi( mul16u::@1/(dword) mul16u::res#4 )
|
||||||
|
(dword) mul16u::mb#4 ← phi( mul16u::@1/(dword) mul16u::mb#5 )
|
||||||
|
(word) mul16u::a#3 ← phi( mul16u::@1/(word) mul16u::a#2 )
|
||||||
|
(number~) mul16u::$1 ← (word) mul16u::a#3 & (number) 1
|
||||||
|
(bool~) mul16u::$2 ← (number~) mul16u::$1 != (number) 0
|
||||||
|
(bool~) mul16u::$3 ← ! (bool~) mul16u::$2
|
||||||
|
if((bool~) mul16u::$3) goto mul16u::@4
|
||||||
|
to:mul16u::@7
|
||||||
|
mul16u::@3: scope:[mul16u] from mul16u::@1
|
||||||
|
(dword) mul16u::res#2 ← phi( mul16u::@1/(dword) mul16u::res#4 )
|
||||||
|
(dword) mul16u::return#0 ← (dword) mul16u::res#2
|
||||||
|
to:mul16u::@return
|
||||||
|
mul16u::@4: scope:[mul16u] from mul16u::@2 mul16u::@7
|
||||||
|
(dword) mul16u::res#6 ← phi( mul16u::@2/(dword) mul16u::res#5 mul16u::@7/(dword) mul16u::res#1 )
|
||||||
|
(dword) mul16u::mb#2 ← phi( mul16u::@2/(dword) mul16u::mb#4 mul16u::@7/(dword) mul16u::mb#3 )
|
||||||
|
(word) mul16u::a#4 ← phi( mul16u::@2/(word) mul16u::a#3 mul16u::@7/(word) mul16u::a#6 )
|
||||||
|
(word~) mul16u::$5 ← (word) mul16u::a#4 >> (number) 1
|
||||||
|
(word) mul16u::a#0 ← (word~) mul16u::$5
|
||||||
|
(dword~) mul16u::$6 ← (dword) mul16u::mb#2 << (number) 1
|
||||||
|
(dword) mul16u::mb#1 ← (dword~) mul16u::$6
|
||||||
|
to:mul16u::@1
|
||||||
|
mul16u::@7: scope:[mul16u] from mul16u::@2
|
||||||
|
(word) mul16u::a#6 ← phi( mul16u::@2/(word) mul16u::a#3 )
|
||||||
|
(dword) mul16u::mb#3 ← phi( mul16u::@2/(dword) mul16u::mb#4 )
|
||||||
|
(dword) mul16u::res#3 ← phi( mul16u::@2/(dword) mul16u::res#5 )
|
||||||
|
(dword~) mul16u::$4 ← (dword) mul16u::res#3 + (dword) mul16u::mb#3
|
||||||
|
(dword) mul16u::res#1 ← (dword~) mul16u::$4
|
||||||
|
to:mul16u::@4
|
||||||
|
mul16u::@return: scope:[mul16u] from mul16u::@3
|
||||||
|
(dword) mul16u::return#3 ← phi( mul16u::@3/(dword) mul16u::return#0 )
|
||||||
|
(dword) mul16u::return#1 ← (dword) mul16u::return#3
|
||||||
|
return
|
||||||
|
to:@return
|
||||||
|
main: scope:[main] from @10
|
||||||
|
(word) mul16u::a#1 ← (number) 4
|
||||||
|
(word) mul16u::b#0 ← (number) $7b
|
||||||
|
call mul16u
|
||||||
|
(dword) mul16u::return#2 ← (dword) mul16u::return#1
|
||||||
|
to:main::@1
|
||||||
|
main::@1: scope:[main] from main
|
||||||
|
(dword) mul16u::return#4 ← phi( main/(dword) mul16u::return#2 )
|
||||||
|
(dword~) main::$0 ← (dword) mul16u::return#4
|
||||||
|
(dword) main::result#0 ← (dword~) main::$0
|
||||||
|
(word~) main::$1 ← < (dword) main::result#0
|
||||||
|
(word) main::kaputt#0 ← (word~) main::$1
|
||||||
|
(byte~) main::$2 ← < (word) main::kaputt#0
|
||||||
|
*((byte*) BORDERCOL#0) ← (byte~) main::$2
|
||||||
|
(byte~) main::$3 ← > (word) main::kaputt#0
|
||||||
|
*((byte*) BGCOL#0) ← (byte~) main::$3
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main::@1
|
||||||
|
return
|
||||||
|
to:@return
|
||||||
|
@10: scope:[] from @begin
|
||||||
|
call main
|
||||||
|
to:@11
|
||||||
|
@11: scope:[] from @10
|
||||||
|
to:@end
|
||||||
|
@end: scope:[] from @11
|
||||||
|
|
||||||
|
SYMBOL TABLE SSA
|
||||||
|
(label) @10
|
||||||
|
(label) @11
|
||||||
|
(label) @begin
|
||||||
|
(label) @end
|
||||||
|
(byte*) BGCOL
|
||||||
|
(byte*) BGCOL#0
|
||||||
|
(byte*) BORDERCOL
|
||||||
|
(byte*) BORDERCOL#0
|
||||||
|
(void()) main()
|
||||||
|
(dword~) main::$0
|
||||||
|
(word~) main::$1
|
||||||
|
(byte~) main::$2
|
||||||
|
(byte~) main::$3
|
||||||
|
(label) main::@1
|
||||||
|
(label) main::@return
|
||||||
|
(word) main::kaputt
|
||||||
|
(word) main::kaputt#0
|
||||||
|
(dword) main::result
|
||||||
|
(dword) main::result#0
|
||||||
|
(dword()) mul16u((word) mul16u::a , (word) mul16u::b)
|
||||||
|
(bool~) mul16u::$0
|
||||||
|
(number~) mul16u::$1
|
||||||
|
(bool~) mul16u::$2
|
||||||
|
(bool~) mul16u::$3
|
||||||
|
(dword~) mul16u::$4
|
||||||
|
(word~) mul16u::$5
|
||||||
|
(dword~) mul16u::$6
|
||||||
|
(label) mul16u::@1
|
||||||
|
(label) mul16u::@2
|
||||||
|
(label) mul16u::@3
|
||||||
|
(label) mul16u::@4
|
||||||
|
(label) mul16u::@7
|
||||||
|
(label) mul16u::@return
|
||||||
|
(word) mul16u::a
|
||||||
|
(word) mul16u::a#0
|
||||||
|
(word) mul16u::a#1
|
||||||
|
(word) mul16u::a#2
|
||||||
|
(word) mul16u::a#3
|
||||||
|
(word) mul16u::a#4
|
||||||
|
(word) mul16u::a#5
|
||||||
|
(word) mul16u::a#6
|
||||||
|
(word) mul16u::b
|
||||||
|
(word) mul16u::b#0
|
||||||
|
(word) mul16u::b#1
|
||||||
|
(dword) mul16u::mb
|
||||||
|
(dword) mul16u::mb#0
|
||||||
|
(dword) mul16u::mb#1
|
||||||
|
(dword) mul16u::mb#2
|
||||||
|
(dword) mul16u::mb#3
|
||||||
|
(dword) mul16u::mb#4
|
||||||
|
(dword) mul16u::mb#5
|
||||||
|
(dword) mul16u::res
|
||||||
|
(dword) mul16u::res#0
|
||||||
|
(dword) mul16u::res#1
|
||||||
|
(dword) mul16u::res#2
|
||||||
|
(dword) mul16u::res#3
|
||||||
|
(dword) mul16u::res#4
|
||||||
|
(dword) mul16u::res#5
|
||||||
|
(dword) mul16u::res#6
|
||||||
|
(dword) mul16u::return
|
||||||
|
(dword) mul16u::return#0
|
||||||
|
(dword) mul16u::return#1
|
||||||
|
(dword) mul16u::return#2
|
||||||
|
(dword) mul16u::return#3
|
||||||
|
(dword) mul16u::return#4
|
||||||
|
|
||||||
|
Adding number conversion cast (unumber) 0 in (dword) mul16u::res#0 ← (number) 0
|
||||||
|
Adding number conversion cast (unumber) 0 in (bool~) mul16u::$0 ← (word) mul16u::a#2 != (number) 0
|
||||||
|
Adding number conversion cast (unumber) 1 in (number~) mul16u::$1 ← (word) mul16u::a#3 & (number) 1
|
||||||
|
Adding number conversion cast (unumber) mul16u::$1 in (number~) mul16u::$1 ← (word) mul16u::a#3 & (unumber)(number) 1
|
||||||
|
Adding number conversion cast (unumber) 0 in (bool~) mul16u::$2 ← (unumber~) mul16u::$1 != (number) 0
|
||||||
|
Adding number conversion cast (unumber) 1 in (word~) mul16u::$5 ← (word) mul16u::a#4 >> (number) 1
|
||||||
|
Adding number conversion cast (unumber) 1 in (dword~) mul16u::$6 ← (dword) mul16u::mb#2 << (number) 1
|
||||||
|
Adding number conversion cast (unumber) 4 in (word) mul16u::a#1 ← (number) 4
|
||||||
|
Adding number conversion cast (unumber) $7b in (word) mul16u::b#0 ← (number) $7b
|
||||||
|
Successful SSA optimization PassNAddNumberTypeConversions
|
||||||
|
Inlining cast (byte*) BORDERCOL#0 ← (byte*)(number) $d020
|
||||||
|
Inlining cast (byte*) BGCOL#0 ← (byte*)(number) $d021
|
||||||
|
Inlining cast (dword) mul16u::res#0 ← (unumber)(number) 0
|
||||||
|
Inlining cast (word) mul16u::a#1 ← (unumber)(number) 4
|
||||||
|
Inlining cast (word) mul16u::b#0 ← (unumber)(number) $7b
|
||||||
|
Successful SSA optimization Pass2InlineCast
|
||||||
|
Simplifying constant pointer cast (byte*) 53280
|
||||||
|
Simplifying constant pointer cast (byte*) 53281
|
||||||
|
Simplifying constant integer cast 0
|
||||||
|
Simplifying constant integer cast 0
|
||||||
|
Simplifying constant integer cast 1
|
||||||
|
Simplifying constant integer cast 0
|
||||||
|
Simplifying constant integer cast 1
|
||||||
|
Simplifying constant integer cast 1
|
||||||
|
Simplifying constant integer cast 4
|
||||||
|
Simplifying constant integer cast $7b
|
||||||
|
Successful SSA optimization PassNCastSimplification
|
||||||
|
Finalized unsigned number type (byte) 0
|
||||||
|
Finalized unsigned number type (byte) 0
|
||||||
|
Finalized unsigned number type (byte) 1
|
||||||
|
Finalized unsigned number type (byte) 0
|
||||||
|
Finalized unsigned number type (byte) 1
|
||||||
|
Finalized unsigned number type (byte) 1
|
||||||
|
Finalized unsigned number type (byte) 4
|
||||||
|
Finalized unsigned number type (byte) $7b
|
||||||
|
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||||
|
Inferred type updated to byte in (unumber~) mul16u::$1 ← (word) mul16u::a#3 & (byte) 1
|
||||||
|
Inversing boolean not [11] (bool~) mul16u::$3 ← (byte~) mul16u::$1 == (byte) 0 from [10] (bool~) mul16u::$2 ← (byte~) mul16u::$1 != (byte) 0
|
||||||
|
Successful SSA optimization Pass2UnaryNotSimplification
|
||||||
|
Alias (dword) mul16u::mb#0 = (word) mul16u::b#1
|
||||||
|
Alias (word) mul16u::a#2 = (word) mul16u::a#3 (word) mul16u::a#6
|
||||||
|
Alias (dword) mul16u::mb#3 = (dword) mul16u::mb#4 (dword) mul16u::mb#5
|
||||||
|
Alias (dword) mul16u::res#2 = (dword) mul16u::res#5 (dword) mul16u::res#4 (dword) mul16u::return#0 (dword) mul16u::res#3 (dword) mul16u::return#3 (dword) mul16u::return#1
|
||||||
|
Alias (word) mul16u::a#0 = (word~) mul16u::$5
|
||||||
|
Alias (dword) mul16u::mb#1 = (dword~) mul16u::$6
|
||||||
|
Alias (dword) mul16u::res#1 = (dword~) mul16u::$4
|
||||||
|
Alias (dword) mul16u::return#2 = (dword) mul16u::return#4
|
||||||
|
Alias (dword) main::result#0 = (dword~) main::$0
|
||||||
|
Alias (word) main::kaputt#0 = (word~) main::$1
|
||||||
|
Successful SSA optimization Pass2AliasElimination
|
||||||
|
Alias (word) mul16u::a#2 = (word) mul16u::a#4
|
||||||
|
Alias (dword) mul16u::mb#2 = (dword) mul16u::mb#3
|
||||||
|
Successful SSA optimization Pass2AliasElimination
|
||||||
|
Identical Phi Values (dword) mul16u::mb#0 (word) mul16u::b#0
|
||||||
|
Identical Phi Values (word) mul16u::a#5 (word) mul16u::a#1
|
||||||
|
Successful SSA optimization Pass2IdenticalPhiElimination
|
||||||
|
Simple Condition (bool~) mul16u::$0 [7] if((word) mul16u::a#2!=(byte) 0) goto mul16u::@2
|
||||||
|
Simple Condition (bool~) mul16u::$3 [12] if((byte~) mul16u::$1==(byte) 0) goto mul16u::@4
|
||||||
|
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||||
|
Constant (const byte*) BORDERCOL#0 = (byte*) 53280
|
||||||
|
Constant (const byte*) BGCOL#0 = (byte*) 53281
|
||||||
|
Constant (const dword) mul16u::res#0 = 0
|
||||||
|
Constant (const word) mul16u::a#1 = 4
|
||||||
|
Constant (const word) mul16u::b#0 = $7b
|
||||||
|
Successful SSA optimization Pass2ConstantIdentification
|
||||||
|
Inlining constant with var siblings (const dword) mul16u::res#0
|
||||||
|
Inlining constant with var siblings (const word) mul16u::a#1
|
||||||
|
Constant inlined mul16u::res#0 = (byte) 0
|
||||||
|
Constant inlined mul16u::a#1 = (byte) 4
|
||||||
|
Successful SSA optimization Pass2ConstantInlining
|
||||||
|
Added new block during phi lifting mul16u::@10(between mul16u::@2 and mul16u::@4)
|
||||||
|
Adding NOP phi() at start of @begin
|
||||||
|
Adding NOP phi() at start of @10
|
||||||
|
Adding NOP phi() at start of @11
|
||||||
|
Adding NOP phi() at start of @end
|
||||||
|
Adding NOP phi() at start of main
|
||||||
|
Adding NOP phi() at start of mul16u
|
||||||
|
Adding NOP phi() at start of mul16u::@3
|
||||||
|
CALL GRAPH
|
||||||
|
Calls in [] to main:2
|
||||||
|
Calls in [main] to mul16u:6
|
||||||
|
|
||||||
|
Created 4 initial phi equivalence classes
|
||||||
|
Coalesced [23] mul16u::res#9 ← mul16u::res#1
|
||||||
|
Coalesced [27] mul16u::a#7 ← mul16u::a#0
|
||||||
|
Coalesced [28] mul16u::res#7 ← mul16u::res#6
|
||||||
|
Coalesced [29] mul16u::mb#6 ← mul16u::mb#1
|
||||||
|
Coalesced (already) [30] mul16u::res#8 ← mul16u::res#2
|
||||||
|
Coalesced down to 3 phi equivalence classes
|
||||||
|
Culled Empty Block (label) @11
|
||||||
|
Culled Empty Block (label) mul16u::@3
|
||||||
|
Culled Empty Block (label) mul16u::@10
|
||||||
|
Renumbering block @10 to @1
|
||||||
|
Renumbering block mul16u::@4 to mul16u::@3
|
||||||
|
Renumbering block mul16u::@7 to mul16u::@4
|
||||||
|
Adding NOP phi() at start of @begin
|
||||||
|
Adding NOP phi() at start of @1
|
||||||
|
Adding NOP phi() at start of @end
|
||||||
|
Adding NOP phi() at start of main
|
||||||
|
Adding NOP phi() at start of mul16u
|
||||||
|
|
||||||
|
FINAL CONTROL FLOW GRAPH
|
||||||
|
@begin: scope:[] from
|
||||||
|
[0] phi()
|
||||||
|
to:@1
|
||||||
|
@1: scope:[] from @begin
|
||||||
|
[1] phi()
|
||||||
|
[2] call main
|
||||||
|
to:@end
|
||||||
|
@end: scope:[] from @1
|
||||||
|
[3] phi()
|
||||||
|
main: scope:[main] from @1
|
||||||
|
[4] phi()
|
||||||
|
[5] call mul16u
|
||||||
|
[6] (dword) mul16u::return#2 ← (dword) mul16u::res#2
|
||||||
|
to:main::@1
|
||||||
|
main::@1: scope:[main] from main
|
||||||
|
[7] (dword) main::result#0 ← (dword) mul16u::return#2
|
||||||
|
[8] (word) main::kaputt#0 ← < (dword) main::result#0
|
||||||
|
[9] (byte~) main::$2 ← < (word) main::kaputt#0
|
||||||
|
[10] *((const byte*) BORDERCOL#0) ← (byte~) main::$2
|
||||||
|
[11] (byte~) main::$3 ← > (word) main::kaputt#0
|
||||||
|
[12] *((const byte*) BGCOL#0) ← (byte~) main::$3
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main::@1
|
||||||
|
[13] return
|
||||||
|
to:@return
|
||||||
|
mul16u: scope:[mul16u] from main
|
||||||
|
[14] phi()
|
||||||
|
to:mul16u::@1
|
||||||
|
mul16u::@1: scope:[mul16u] from mul16u mul16u::@3
|
||||||
|
[15] (dword) mul16u::mb#2 ← phi( mul16u/(const word) mul16u::b#0 mul16u::@3/(dword) mul16u::mb#1 )
|
||||||
|
[15] (dword) mul16u::res#2 ← phi( mul16u/(byte) 0 mul16u::@3/(dword) mul16u::res#6 )
|
||||||
|
[15] (word) mul16u::a#2 ← phi( mul16u/(byte) 4 mul16u::@3/(word) mul16u::a#0 )
|
||||||
|
[16] if((word) mul16u::a#2!=(byte) 0) goto mul16u::@2
|
||||||
|
to:mul16u::@return
|
||||||
|
mul16u::@return: scope:[mul16u] from mul16u::@1
|
||||||
|
[17] return
|
||||||
|
to:@return
|
||||||
|
mul16u::@2: scope:[mul16u] from mul16u::@1
|
||||||
|
[18] (byte~) mul16u::$1 ← (word) mul16u::a#2 & (byte) 1
|
||||||
|
[19] if((byte~) mul16u::$1==(byte) 0) goto mul16u::@3
|
||||||
|
to:mul16u::@4
|
||||||
|
mul16u::@4: scope:[mul16u] from mul16u::@2
|
||||||
|
[20] (dword) mul16u::res#1 ← (dword) mul16u::res#2 + (dword) mul16u::mb#2
|
||||||
|
to:mul16u::@3
|
||||||
|
mul16u::@3: scope:[mul16u] from mul16u::@2 mul16u::@4
|
||||||
|
[21] (dword) mul16u::res#6 ← phi( mul16u::@2/(dword) mul16u::res#2 mul16u::@4/(dword) mul16u::res#1 )
|
||||||
|
[22] (word) mul16u::a#0 ← (word) mul16u::a#2 >> (byte) 1
|
||||||
|
[23] (dword) mul16u::mb#1 ← (dword) mul16u::mb#2 << (byte) 1
|
||||||
|
to:mul16u::@1
|
||||||
|
|
||||||
|
|
||||||
|
VARIABLE REGISTER WEIGHTS
|
||||||
|
(byte*) BGCOL
|
||||||
|
(byte*) BORDERCOL
|
||||||
|
(void()) main()
|
||||||
|
(byte~) main::$2 4.0
|
||||||
|
(byte~) main::$3 4.0
|
||||||
|
(word) main::kaputt
|
||||||
|
(word) main::kaputt#0 2.0
|
||||||
|
(dword) main::result
|
||||||
|
(dword) main::result#0 4.0
|
||||||
|
(dword()) mul16u((word) mul16u::a , (word) mul16u::b)
|
||||||
|
(byte~) mul16u::$1 22.0
|
||||||
|
(word) mul16u::a
|
||||||
|
(word) mul16u::a#0 11.0
|
||||||
|
(word) mul16u::a#2 7.333333333333333
|
||||||
|
(word) mul16u::b
|
||||||
|
(dword) mul16u::mb
|
||||||
|
(dword) mul16u::mb#1 22.0
|
||||||
|
(dword) mul16u::mb#2 4.714285714285714
|
||||||
|
(dword) mul16u::res
|
||||||
|
(dword) mul16u::res#1 22.0
|
||||||
|
(dword) mul16u::res#2 5.833333333333333
|
||||||
|
(dword) mul16u::res#6 11.0
|
||||||
|
(dword) mul16u::return
|
||||||
|
(dword) mul16u::return#2 4.0
|
||||||
|
|
||||||
|
Initial phi equivalence classes
|
||||||
|
[ mul16u::a#2 mul16u::a#0 ]
|
||||||
|
[ mul16u::res#2 mul16u::res#6 mul16u::res#1 ]
|
||||||
|
[ mul16u::mb#2 mul16u::mb#1 ]
|
||||||
|
Added variable mul16u::return#2 to zero page equivalence class [ mul16u::return#2 ]
|
||||||
|
Added variable main::result#0 to zero page equivalence class [ main::result#0 ]
|
||||||
|
Added variable main::kaputt#0 to zero page equivalence class [ main::kaputt#0 ]
|
||||||
|
Added variable main::$2 to zero page equivalence class [ main::$2 ]
|
||||||
|
Added variable main::$3 to zero page equivalence class [ main::$3 ]
|
||||||
|
Added variable mul16u::$1 to zero page equivalence class [ mul16u::$1 ]
|
||||||
|
Complete equivalence classes
|
||||||
|
[ mul16u::a#2 mul16u::a#0 ]
|
||||||
|
[ mul16u::res#2 mul16u::res#6 mul16u::res#1 ]
|
||||||
|
[ mul16u::mb#2 mul16u::mb#1 ]
|
||||||
|
[ mul16u::return#2 ]
|
||||||
|
[ main::result#0 ]
|
||||||
|
[ main::kaputt#0 ]
|
||||||
|
[ main::$2 ]
|
||||||
|
[ main::$3 ]
|
||||||
|
[ mul16u::$1 ]
|
||||||
|
Allocated zp ZP_WORD:2 [ mul16u::a#2 mul16u::a#0 ]
|
||||||
|
Allocated zp ZP_DWORD:4 [ mul16u::res#2 mul16u::res#6 mul16u::res#1 ]
|
||||||
|
Allocated zp ZP_DWORD:8 [ mul16u::mb#2 mul16u::mb#1 ]
|
||||||
|
Allocated zp ZP_DWORD:12 [ mul16u::return#2 ]
|
||||||
|
Allocated zp ZP_DWORD:16 [ main::result#0 ]
|
||||||
|
Allocated zp ZP_WORD:20 [ main::kaputt#0 ]
|
||||||
|
Allocated zp ZP_BYTE:22 [ main::$2 ]
|
||||||
|
Allocated zp ZP_BYTE:23 [ main::$3 ]
|
||||||
|
Allocated zp ZP_BYTE:24 [ mul16u::$1 ]
|
||||||
|
|
||||||
|
INITIAL ASM
|
||||||
|
Target platform is c64basic
|
||||||
|
// File Comments
|
||||||
|
// Program where loop-head optimization produces wrong return value
|
||||||
|
// Reported by Richard-William Loerakker
|
||||||
|
// Upstart
|
||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(bbegin)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
// Global Constants & labels
|
||||||
|
.label BORDERCOL = $d020
|
||||||
|
.label BGCOL = $d021
|
||||||
|
// @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 _2 = $16
|
||||||
|
.label _3 = $17
|
||||||
|
.label result = $10
|
||||||
|
.label kaputt = $14
|
||||||
|
// [5] call mul16u
|
||||||
|
// [14] phi from main to mul16u [phi:main->mul16u]
|
||||||
|
mul16u_from_main:
|
||||||
|
jsr mul16u
|
||||||
|
// [6] (dword) mul16u::return#2 ← (dword) mul16u::res#2 -- vduz1=vduz2
|
||||||
|
lda.z mul16u.res
|
||||||
|
sta.z mul16u.return
|
||||||
|
lda.z mul16u.res+1
|
||||||
|
sta.z mul16u.return+1
|
||||||
|
lda.z mul16u.res+2
|
||||||
|
sta.z mul16u.return+2
|
||||||
|
lda.z mul16u.res+3
|
||||||
|
sta.z mul16u.return+3
|
||||||
|
jmp b1
|
||||||
|
// main::@1
|
||||||
|
b1:
|
||||||
|
// [7] (dword) main::result#0 ← (dword) mul16u::return#2 -- vduz1=vduz2
|
||||||
|
lda.z mul16u.return
|
||||||
|
sta.z result
|
||||||
|
lda.z mul16u.return+1
|
||||||
|
sta.z result+1
|
||||||
|
lda.z mul16u.return+2
|
||||||
|
sta.z result+2
|
||||||
|
lda.z mul16u.return+3
|
||||||
|
sta.z result+3
|
||||||
|
// [8] (word) main::kaputt#0 ← < (dword) main::result#0 -- vwuz1=_lo_vduz2
|
||||||
|
lda.z result
|
||||||
|
sta.z kaputt
|
||||||
|
lda.z result+1
|
||||||
|
sta.z kaputt+1
|
||||||
|
// [9] (byte~) main::$2 ← < (word) main::kaputt#0 -- vbuz1=_lo_vwuz2
|
||||||
|
lda.z kaputt
|
||||||
|
sta.z _2
|
||||||
|
// [10] *((const byte*) BORDERCOL#0) ← (byte~) main::$2 -- _deref_pbuc1=vbuz1
|
||||||
|
lda.z _2
|
||||||
|
sta BORDERCOL
|
||||||
|
// [11] (byte~) main::$3 ← > (word) main::kaputt#0 -- vbuz1=_hi_vwuz2
|
||||||
|
lda.z kaputt+1
|
||||||
|
sta.z _3
|
||||||
|
// [12] *((const byte*) BGCOL#0) ← (byte~) main::$3 -- _deref_pbuc1=vbuz1
|
||||||
|
lda.z _3
|
||||||
|
sta BGCOL
|
||||||
|
jmp breturn
|
||||||
|
// main::@return
|
||||||
|
breturn:
|
||||||
|
// [13] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// mul16u
|
||||||
|
// Perform binary multiplication of two unsigned 16-bit words into a 32-bit unsigned double word
|
||||||
|
// mul16u(word zeropage(2) a)
|
||||||
|
mul16u: {
|
||||||
|
.const b = $7b
|
||||||
|
.label _1 = $18
|
||||||
|
.label a = 2
|
||||||
|
.label mb = 8
|
||||||
|
.label res = 4
|
||||||
|
.label return = $c
|
||||||
|
// [15] phi from mul16u to mul16u::@1 [phi:mul16u->mul16u::@1]
|
||||||
|
b1_from_mul16u:
|
||||||
|
// [15] phi (dword) mul16u::mb#2 = (const word) mul16u::b#0 [phi:mul16u->mul16u::@1#0] -- vduz1=vduc1
|
||||||
|
lda #<b
|
||||||
|
sta.z mb
|
||||||
|
lda #>b
|
||||||
|
sta.z mb+1
|
||||||
|
lda #<b>>$10
|
||||||
|
sta.z mb+2
|
||||||
|
lda #>b>>$10
|
||||||
|
sta.z mb+3
|
||||||
|
// [15] phi (dword) mul16u::res#2 = (byte) 0 [phi:mul16u->mul16u::@1#1] -- vduz1=vbuc1
|
||||||
|
lda #0
|
||||||
|
sta.z res
|
||||||
|
lda #0
|
||||||
|
sta.z res+1
|
||||||
|
sta.z res+2
|
||||||
|
sta.z res+3
|
||||||
|
// [15] phi (word) mul16u::a#2 = (byte) 4 [phi:mul16u->mul16u::@1#2] -- vwuz1=vbuc1
|
||||||
|
lda #<4
|
||||||
|
sta.z a
|
||||||
|
lda #>4
|
||||||
|
sta.z a+1
|
||||||
|
jmp b1
|
||||||
|
// mul16u::@1
|
||||||
|
b1:
|
||||||
|
// [16] if((word) mul16u::a#2!=(byte) 0) goto mul16u::@2 -- vwuz1_neq_0_then_la1
|
||||||
|
lda.z a
|
||||||
|
bne b2
|
||||||
|
lda.z a+1
|
||||||
|
bne b2
|
||||||
|
jmp breturn
|
||||||
|
// mul16u::@return
|
||||||
|
breturn:
|
||||||
|
// [17] return
|
||||||
|
rts
|
||||||
|
// mul16u::@2
|
||||||
|
b2:
|
||||||
|
// [18] (byte~) mul16u::$1 ← (word) mul16u::a#2 & (byte) 1 -- vbuz1=vwuz2_band_vbuc1
|
||||||
|
lda #1
|
||||||
|
and.z a
|
||||||
|
sta.z _1
|
||||||
|
// [19] if((byte~) mul16u::$1==(byte) 0) goto mul16u::@3 -- vbuz1_eq_0_then_la1
|
||||||
|
lda.z _1
|
||||||
|
cmp #0
|
||||||
|
beq b3_from_b2
|
||||||
|
jmp b4
|
||||||
|
// mul16u::@4
|
||||||
|
b4:
|
||||||
|
// [20] (dword) mul16u::res#1 ← (dword) mul16u::res#2 + (dword) mul16u::mb#2 -- vduz1=vduz1_plus_vduz2
|
||||||
|
lda.z res
|
||||||
|
clc
|
||||||
|
adc.z mb
|
||||||
|
sta.z res
|
||||||
|
lda.z res+1
|
||||||
|
adc.z mb+1
|
||||||
|
sta.z res+1
|
||||||
|
lda.z res+2
|
||||||
|
adc.z mb+2
|
||||||
|
sta.z res+2
|
||||||
|
lda.z res+3
|
||||||
|
adc.z mb+3
|
||||||
|
sta.z res+3
|
||||||
|
// [21] phi from mul16u::@2 mul16u::@4 to mul16u::@3 [phi:mul16u::@2/mul16u::@4->mul16u::@3]
|
||||||
|
b3_from_b2:
|
||||||
|
b3_from_b4:
|
||||||
|
// [21] phi (dword) mul16u::res#6 = (dword) mul16u::res#2 [phi:mul16u::@2/mul16u::@4->mul16u::@3#0] -- register_copy
|
||||||
|
jmp b3
|
||||||
|
// mul16u::@3
|
||||||
|
b3:
|
||||||
|
// [22] (word) mul16u::a#0 ← (word) mul16u::a#2 >> (byte) 1 -- vwuz1=vwuz1_ror_1
|
||||||
|
lsr.z a+1
|
||||||
|
ror.z a
|
||||||
|
// [23] (dword) mul16u::mb#1 ← (dword) mul16u::mb#2 << (byte) 1 -- vduz1=vduz1_rol_1
|
||||||
|
asl.z mb
|
||||||
|
rol.z mb+1
|
||||||
|
rol.z mb+2
|
||||||
|
rol.z mb+3
|
||||||
|
// [15] phi from mul16u::@3 to mul16u::@1 [phi:mul16u::@3->mul16u::@1]
|
||||||
|
b1_from_b3:
|
||||||
|
// [15] phi (dword) mul16u::mb#2 = (dword) mul16u::mb#1 [phi:mul16u::@3->mul16u::@1#0] -- register_copy
|
||||||
|
// [15] phi (dword) mul16u::res#2 = (dword) mul16u::res#6 [phi:mul16u::@3->mul16u::@1#1] -- register_copy
|
||||||
|
// [15] phi (word) mul16u::a#2 = (word) mul16u::a#0 [phi:mul16u::@3->mul16u::@1#2] -- register_copy
|
||||||
|
jmp b1
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
||||||
|
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||||
|
Statement [6] (dword) mul16u::return#2 ← (dword) mul16u::res#2 [ mul16u::return#2 ] ( main:2 [ mul16u::return#2 ] ) always clobbers reg byte a
|
||||||
|
Statement [7] (dword) main::result#0 ← (dword) mul16u::return#2 [ main::result#0 ] ( main:2 [ main::result#0 ] ) always clobbers reg byte a
|
||||||
|
Statement [8] (word) main::kaputt#0 ← < (dword) main::result#0 [ main::kaputt#0 ] ( main:2 [ main::kaputt#0 ] ) always clobbers reg byte a
|
||||||
|
Statement [9] (byte~) main::$2 ← < (word) main::kaputt#0 [ main::kaputt#0 main::$2 ] ( main:2 [ main::kaputt#0 main::$2 ] ) always clobbers reg byte a
|
||||||
|
Statement [11] (byte~) main::$3 ← > (word) main::kaputt#0 [ main::$3 ] ( main:2 [ main::$3 ] ) always clobbers reg byte a
|
||||||
|
Statement [16] if((word) mul16u::a#2!=(byte) 0) goto mul16u::@2 [ mul16u::res#2 mul16u::a#2 mul16u::mb#2 ] ( main:2::mul16u:5 [ mul16u::res#2 mul16u::a#2 mul16u::mb#2 ] ) always clobbers reg byte a
|
||||||
|
Statement [18] (byte~) mul16u::$1 ← (word) mul16u::a#2 & (byte) 1 [ mul16u::res#2 mul16u::a#2 mul16u::mb#2 mul16u::$1 ] ( main:2::mul16u:5 [ mul16u::res#2 mul16u::a#2 mul16u::mb#2 mul16u::$1 ] ) always clobbers reg byte a
|
||||||
|
Statement [20] (dword) mul16u::res#1 ← (dword) mul16u::res#2 + (dword) mul16u::mb#2 [ mul16u::a#2 mul16u::mb#2 mul16u::res#1 ] ( main:2::mul16u:5 [ mul16u::a#2 mul16u::mb#2 mul16u::res#1 ] ) always clobbers reg byte a
|
||||||
|
Potential registers zp ZP_WORD:2 [ mul16u::a#2 mul16u::a#0 ] : zp ZP_WORD:2 ,
|
||||||
|
Potential registers zp ZP_DWORD:4 [ mul16u::res#2 mul16u::res#6 mul16u::res#1 ] : zp ZP_DWORD:4 ,
|
||||||
|
Potential registers zp ZP_DWORD:8 [ mul16u::mb#2 mul16u::mb#1 ] : zp ZP_DWORD:8 ,
|
||||||
|
Potential registers zp ZP_DWORD:12 [ mul16u::return#2 ] : zp ZP_DWORD:12 ,
|
||||||
|
Potential registers zp ZP_DWORD:16 [ main::result#0 ] : zp ZP_DWORD:16 ,
|
||||||
|
Potential registers zp ZP_WORD:20 [ main::kaputt#0 ] : zp ZP_WORD:20 ,
|
||||||
|
Potential registers zp ZP_BYTE:22 [ main::$2 ] : zp ZP_BYTE:22 , reg byte a , reg byte x , reg byte y ,
|
||||||
|
Potential registers zp ZP_BYTE:23 [ main::$3 ] : zp ZP_BYTE:23 , reg byte a , reg byte x , reg byte y ,
|
||||||
|
Potential registers zp ZP_BYTE:24 [ mul16u::$1 ] : zp ZP_BYTE:24 , reg byte a , reg byte x , reg byte y ,
|
||||||
|
|
||||||
|
REGISTER UPLIFT SCOPES
|
||||||
|
Uplift Scope [mul16u] 38.83: zp ZP_DWORD:4 [ mul16u::res#2 mul16u::res#6 mul16u::res#1 ] 26.71: zp ZP_DWORD:8 [ mul16u::mb#2 mul16u::mb#1 ] 22: zp ZP_BYTE:24 [ mul16u::$1 ] 18.33: zp ZP_WORD:2 [ mul16u::a#2 mul16u::a#0 ] 4: zp ZP_DWORD:12 [ mul16u::return#2 ]
|
||||||
|
Uplift Scope [main] 4: zp ZP_DWORD:16 [ main::result#0 ] 4: zp ZP_BYTE:22 [ main::$2 ] 4: zp ZP_BYTE:23 [ main::$3 ] 2: zp ZP_WORD:20 [ main::kaputt#0 ]
|
||||||
|
Uplift Scope []
|
||||||
|
|
||||||
|
Uplifting [mul16u] best 1617 combination zp ZP_DWORD:4 [ mul16u::res#2 mul16u::res#6 mul16u::res#1 ] zp ZP_DWORD:8 [ mul16u::mb#2 mul16u::mb#1 ] reg byte a [ mul16u::$1 ] zp ZP_WORD:2 [ mul16u::a#2 mul16u::a#0 ] zp ZP_DWORD:12 [ mul16u::return#2 ]
|
||||||
|
Uplifting [main] best 1605 combination zp ZP_DWORD:16 [ main::result#0 ] reg byte a [ main::$2 ] reg byte a [ main::$3 ] zp ZP_WORD:20 [ main::kaputt#0 ]
|
||||||
|
Uplifting [] best 1605 combination
|
||||||
|
Coalescing zero page register [ zp ZP_DWORD:4 [ mul16u::res#2 mul16u::res#6 mul16u::res#1 ] ] with [ zp ZP_DWORD:12 [ mul16u::return#2 ] ] - score: 1
|
||||||
|
Coalescing zero page register [ zp ZP_DWORD:4 [ mul16u::res#2 mul16u::res#6 mul16u::res#1 mul16u::return#2 ] ] with [ zp ZP_DWORD:16 [ main::result#0 ] ] - score: 1
|
||||||
|
Coalescing zero page register [ zp ZP_WORD:20 [ main::kaputt#0 ] ] with [ zp ZP_WORD:2 [ mul16u::a#2 mul16u::a#0 ] ]
|
||||||
|
Allocated (was zp ZP_DWORD:4) zp ZP_DWORD:2 [ mul16u::res#2 mul16u::res#6 mul16u::res#1 mul16u::return#2 main::result#0 ]
|
||||||
|
Allocated (was zp ZP_DWORD:8) zp ZP_DWORD:6 [ mul16u::mb#2 mul16u::mb#1 ]
|
||||||
|
Allocated (was zp ZP_WORD:20) zp ZP_WORD:10 [ main::kaputt#0 mul16u::a#2 mul16u::a#0 ]
|
||||||
|
|
||||||
|
ASSEMBLER BEFORE OPTIMIZATION
|
||||||
|
// File Comments
|
||||||
|
// Program where loop-head optimization produces wrong return value
|
||||||
|
// Reported by Richard-William Loerakker
|
||||||
|
// Upstart
|
||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(bbegin)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
// Global Constants & labels
|
||||||
|
.label BORDERCOL = $d020
|
||||||
|
.label BGCOL = $d021
|
||||||
|
// @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 result = 2
|
||||||
|
.label kaputt = $a
|
||||||
|
// [5] call mul16u
|
||||||
|
// [14] phi from main to mul16u [phi:main->mul16u]
|
||||||
|
mul16u_from_main:
|
||||||
|
jsr mul16u
|
||||||
|
// [6] (dword) mul16u::return#2 ← (dword) mul16u::res#2
|
||||||
|
jmp b1
|
||||||
|
// main::@1
|
||||||
|
b1:
|
||||||
|
// [7] (dword) main::result#0 ← (dword) mul16u::return#2
|
||||||
|
// [8] (word) main::kaputt#0 ← < (dword) main::result#0 -- vwuz1=_lo_vduz2
|
||||||
|
lda.z result
|
||||||
|
sta.z kaputt
|
||||||
|
lda.z result+1
|
||||||
|
sta.z kaputt+1
|
||||||
|
// [9] (byte~) main::$2 ← < (word) main::kaputt#0 -- vbuaa=_lo_vwuz1
|
||||||
|
lda.z kaputt
|
||||||
|
// [10] *((const byte*) BORDERCOL#0) ← (byte~) main::$2 -- _deref_pbuc1=vbuaa
|
||||||
|
sta BORDERCOL
|
||||||
|
// [11] (byte~) main::$3 ← > (word) main::kaputt#0 -- vbuaa=_hi_vwuz1
|
||||||
|
lda.z kaputt+1
|
||||||
|
// [12] *((const byte*) BGCOL#0) ← (byte~) main::$3 -- _deref_pbuc1=vbuaa
|
||||||
|
sta BGCOL
|
||||||
|
jmp breturn
|
||||||
|
// main::@return
|
||||||
|
breturn:
|
||||||
|
// [13] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// mul16u
|
||||||
|
// Perform binary multiplication of two unsigned 16-bit words into a 32-bit unsigned double word
|
||||||
|
// mul16u(word zeropage($a) a)
|
||||||
|
mul16u: {
|
||||||
|
.const b = $7b
|
||||||
|
.label a = $a
|
||||||
|
.label mb = 6
|
||||||
|
.label res = 2
|
||||||
|
.label return = 2
|
||||||
|
// [15] phi from mul16u to mul16u::@1 [phi:mul16u->mul16u::@1]
|
||||||
|
b1_from_mul16u:
|
||||||
|
// [15] phi (dword) mul16u::mb#2 = (const word) mul16u::b#0 [phi:mul16u->mul16u::@1#0] -- vduz1=vduc1
|
||||||
|
lda #<b
|
||||||
|
sta.z mb
|
||||||
|
lda #>b
|
||||||
|
sta.z mb+1
|
||||||
|
lda #<b>>$10
|
||||||
|
sta.z mb+2
|
||||||
|
lda #>b>>$10
|
||||||
|
sta.z mb+3
|
||||||
|
// [15] phi (dword) mul16u::res#2 = (byte) 0 [phi:mul16u->mul16u::@1#1] -- vduz1=vbuc1
|
||||||
|
lda #0
|
||||||
|
sta.z res
|
||||||
|
lda #0
|
||||||
|
sta.z res+1
|
||||||
|
sta.z res+2
|
||||||
|
sta.z res+3
|
||||||
|
// [15] phi (word) mul16u::a#2 = (byte) 4 [phi:mul16u->mul16u::@1#2] -- vwuz1=vbuc1
|
||||||
|
lda #<4
|
||||||
|
sta.z a
|
||||||
|
lda #>4
|
||||||
|
sta.z a+1
|
||||||
|
jmp b1
|
||||||
|
// mul16u::@1
|
||||||
|
b1:
|
||||||
|
// [16] if((word) mul16u::a#2!=(byte) 0) goto mul16u::@2 -- vwuz1_neq_0_then_la1
|
||||||
|
lda.z a
|
||||||
|
bne b2
|
||||||
|
lda.z a+1
|
||||||
|
bne b2
|
||||||
|
jmp breturn
|
||||||
|
// mul16u::@return
|
||||||
|
breturn:
|
||||||
|
// [17] return
|
||||||
|
rts
|
||||||
|
// mul16u::@2
|
||||||
|
b2:
|
||||||
|
// [18] (byte~) mul16u::$1 ← (word) mul16u::a#2 & (byte) 1 -- vbuaa=vwuz1_band_vbuc1
|
||||||
|
lda #1
|
||||||
|
and.z a
|
||||||
|
// [19] if((byte~) mul16u::$1==(byte) 0) goto mul16u::@3 -- vbuaa_eq_0_then_la1
|
||||||
|
cmp #0
|
||||||
|
beq b3_from_b2
|
||||||
|
jmp b4
|
||||||
|
// mul16u::@4
|
||||||
|
b4:
|
||||||
|
// [20] (dword) mul16u::res#1 ← (dword) mul16u::res#2 + (dword) mul16u::mb#2 -- vduz1=vduz1_plus_vduz2
|
||||||
|
lda.z res
|
||||||
|
clc
|
||||||
|
adc.z mb
|
||||||
|
sta.z res
|
||||||
|
lda.z res+1
|
||||||
|
adc.z mb+1
|
||||||
|
sta.z res+1
|
||||||
|
lda.z res+2
|
||||||
|
adc.z mb+2
|
||||||
|
sta.z res+2
|
||||||
|
lda.z res+3
|
||||||
|
adc.z mb+3
|
||||||
|
sta.z res+3
|
||||||
|
// [21] phi from mul16u::@2 mul16u::@4 to mul16u::@3 [phi:mul16u::@2/mul16u::@4->mul16u::@3]
|
||||||
|
b3_from_b2:
|
||||||
|
b3_from_b4:
|
||||||
|
// [21] phi (dword) mul16u::res#6 = (dword) mul16u::res#2 [phi:mul16u::@2/mul16u::@4->mul16u::@3#0] -- register_copy
|
||||||
|
jmp b3
|
||||||
|
// mul16u::@3
|
||||||
|
b3:
|
||||||
|
// [22] (word) mul16u::a#0 ← (word) mul16u::a#2 >> (byte) 1 -- vwuz1=vwuz1_ror_1
|
||||||
|
lsr.z a+1
|
||||||
|
ror.z a
|
||||||
|
// [23] (dword) mul16u::mb#1 ← (dword) mul16u::mb#2 << (byte) 1 -- vduz1=vduz1_rol_1
|
||||||
|
asl.z mb
|
||||||
|
rol.z mb+1
|
||||||
|
rol.z mb+2
|
||||||
|
rol.z mb+3
|
||||||
|
// [15] phi from mul16u::@3 to mul16u::@1 [phi:mul16u::@3->mul16u::@1]
|
||||||
|
b1_from_b3:
|
||||||
|
// [15] phi (dword) mul16u::mb#2 = (dword) mul16u::mb#1 [phi:mul16u::@3->mul16u::@1#0] -- register_copy
|
||||||
|
// [15] phi (dword) mul16u::res#2 = (dword) mul16u::res#6 [phi:mul16u::@3->mul16u::@1#1] -- register_copy
|
||||||
|
// [15] phi (word) mul16u::a#2 = (word) mul16u::a#0 [phi:mul16u::@3->mul16u::@1#2] -- register_copy
|
||||||
|
jmp b1
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
||||||
|
ASSEMBLER OPTIMIZATIONS
|
||||||
|
Removing instruction jmp b1
|
||||||
|
Removing instruction jmp bend
|
||||||
|
Removing instruction jmp b1
|
||||||
|
Removing instruction jmp breturn
|
||||||
|
Removing instruction jmp b1
|
||||||
|
Removing instruction jmp breturn
|
||||||
|
Removing instruction jmp b4
|
||||||
|
Removing instruction jmp b3
|
||||||
|
Succesful ASM optimization Pass5NextJumpElimination
|
||||||
|
Removing instruction lda #0
|
||||||
|
Succesful ASM optimization Pass5UnnecesaryLoadElimination
|
||||||
|
Replacing label b3_from_b2 with b3
|
||||||
|
Removing instruction b1_from_bbegin:
|
||||||
|
Removing instruction b1:
|
||||||
|
Removing instruction main_from_b1:
|
||||||
|
Removing instruction bend_from_b1:
|
||||||
|
Removing instruction b3_from_b2:
|
||||||
|
Removing instruction b3_from_b4:
|
||||||
|
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||||
|
Removing instruction bend:
|
||||||
|
Removing instruction mul16u_from_main:
|
||||||
|
Removing instruction b1:
|
||||||
|
Removing instruction breturn:
|
||||||
|
Removing instruction b1_from_mul16u:
|
||||||
|
Removing instruction breturn:
|
||||||
|
Removing instruction b4:
|
||||||
|
Removing instruction b1_from_b3:
|
||||||
|
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||||
|
Updating BasicUpstart to call main directly
|
||||||
|
Removing instruction jsr main
|
||||||
|
Succesful ASM optimization Pass5SkipBegin
|
||||||
|
Removing instruction bbegin:
|
||||||
|
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||||
|
|
||||||
|
FINAL SYMBOL TABLE
|
||||||
|
(label) @1
|
||||||
|
(label) @begin
|
||||||
|
(label) @end
|
||||||
|
(byte*) BGCOL
|
||||||
|
(const byte*) BGCOL#0 BGCOL = (byte*) 53281
|
||||||
|
(byte*) BORDERCOL
|
||||||
|
(const byte*) BORDERCOL#0 BORDERCOL = (byte*) 53280
|
||||||
|
(void()) main()
|
||||||
|
(byte~) main::$2 reg byte a 4.0
|
||||||
|
(byte~) main::$3 reg byte a 4.0
|
||||||
|
(label) main::@1
|
||||||
|
(label) main::@return
|
||||||
|
(word) main::kaputt
|
||||||
|
(word) main::kaputt#0 kaputt zp ZP_WORD:10 2.0
|
||||||
|
(dword) main::result
|
||||||
|
(dword) main::result#0 result zp ZP_DWORD:2 4.0
|
||||||
|
(dword()) mul16u((word) mul16u::a , (word) mul16u::b)
|
||||||
|
(byte~) mul16u::$1 reg byte a 22.0
|
||||||
|
(label) mul16u::@1
|
||||||
|
(label) mul16u::@2
|
||||||
|
(label) mul16u::@3
|
||||||
|
(label) mul16u::@4
|
||||||
|
(label) mul16u::@return
|
||||||
|
(word) mul16u::a
|
||||||
|
(word) mul16u::a#0 a zp ZP_WORD:10 11.0
|
||||||
|
(word) mul16u::a#2 a zp ZP_WORD:10 7.333333333333333
|
||||||
|
(word) mul16u::b
|
||||||
|
(const word) mul16u::b#0 b = (byte) $7b
|
||||||
|
(dword) mul16u::mb
|
||||||
|
(dword) mul16u::mb#1 mb zp ZP_DWORD:6 22.0
|
||||||
|
(dword) mul16u::mb#2 mb zp ZP_DWORD:6 4.714285714285714
|
||||||
|
(dword) mul16u::res
|
||||||
|
(dword) mul16u::res#1 res zp ZP_DWORD:2 22.0
|
||||||
|
(dword) mul16u::res#2 res zp ZP_DWORD:2 5.833333333333333
|
||||||
|
(dword) mul16u::res#6 res zp ZP_DWORD:2 11.0
|
||||||
|
(dword) mul16u::return
|
||||||
|
(dword) mul16u::return#2 return zp ZP_DWORD:2 4.0
|
||||||
|
|
||||||
|
zp ZP_DWORD:2 [ mul16u::res#2 mul16u::res#6 mul16u::res#1 mul16u::return#2 main::result#0 ]
|
||||||
|
zp ZP_DWORD:6 [ mul16u::mb#2 mul16u::mb#1 ]
|
||||||
|
zp ZP_WORD:10 [ main::kaputt#0 mul16u::a#2 mul16u::a#0 ]
|
||||||
|
reg byte a [ main::$2 ]
|
||||||
|
reg byte a [ main::$3 ]
|
||||||
|
reg byte a [ mul16u::$1 ]
|
||||||
|
|
||||||
|
|
||||||
|
FINAL ASSEMBLER
|
||||||
|
Score: 1399
|
||||||
|
|
||||||
|
// File Comments
|
||||||
|
// Program where loop-head optimization produces wrong return value
|
||||||
|
// Reported by Richard-William Loerakker
|
||||||
|
// Upstart
|
||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
// Global Constants & labels
|
||||||
|
.label BORDERCOL = $d020
|
||||||
|
.label BGCOL = $d021
|
||||||
|
// @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: {
|
||||||
|
.label result = 2
|
||||||
|
.label kaputt = $a
|
||||||
|
// mul16u(4,123)
|
||||||
|
// [5] call mul16u
|
||||||
|
// [14] phi from main to mul16u [phi:main->mul16u]
|
||||||
|
jsr mul16u
|
||||||
|
// mul16u(4,123)
|
||||||
|
// [6] (dword) mul16u::return#2 ← (dword) mul16u::res#2
|
||||||
|
// main::@1
|
||||||
|
// result = mul16u(4,123)
|
||||||
|
// [7] (dword) main::result#0 ← (dword) mul16u::return#2
|
||||||
|
// kaputt = <result
|
||||||
|
// [8] (word) main::kaputt#0 ← < (dword) main::result#0 -- vwuz1=_lo_vduz2
|
||||||
|
lda.z result
|
||||||
|
sta.z kaputt
|
||||||
|
lda.z result+1
|
||||||
|
sta.z kaputt+1
|
||||||
|
// <kaputt
|
||||||
|
// [9] (byte~) main::$2 ← < (word) main::kaputt#0 -- vbuaa=_lo_vwuz1
|
||||||
|
lda.z kaputt
|
||||||
|
// *BORDERCOL = <kaputt
|
||||||
|
// [10] *((const byte*) BORDERCOL#0) ← (byte~) main::$2 -- _deref_pbuc1=vbuaa
|
||||||
|
sta BORDERCOL
|
||||||
|
// >kaputt
|
||||||
|
// [11] (byte~) main::$3 ← > (word) main::kaputt#0 -- vbuaa=_hi_vwuz1
|
||||||
|
lda.z kaputt+1
|
||||||
|
// *BGCOL = >kaputt
|
||||||
|
// [12] *((const byte*) BGCOL#0) ← (byte~) main::$3 -- _deref_pbuc1=vbuaa
|
||||||
|
sta BGCOL
|
||||||
|
// main::@return
|
||||||
|
// }
|
||||||
|
// [13] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// mul16u
|
||||||
|
// Perform binary multiplication of two unsigned 16-bit words into a 32-bit unsigned double word
|
||||||
|
// mul16u(word zeropage($a) a)
|
||||||
|
mul16u: {
|
||||||
|
.const b = $7b
|
||||||
|
.label a = $a
|
||||||
|
.label mb = 6
|
||||||
|
.label res = 2
|
||||||
|
.label return = 2
|
||||||
|
// [15] phi from mul16u to mul16u::@1 [phi:mul16u->mul16u::@1]
|
||||||
|
// [15] phi (dword) mul16u::mb#2 = (const word) mul16u::b#0 [phi:mul16u->mul16u::@1#0] -- vduz1=vduc1
|
||||||
|
lda #<b
|
||||||
|
sta.z mb
|
||||||
|
lda #>b
|
||||||
|
sta.z mb+1
|
||||||
|
lda #<b>>$10
|
||||||
|
sta.z mb+2
|
||||||
|
lda #>b>>$10
|
||||||
|
sta.z mb+3
|
||||||
|
// [15] phi (dword) mul16u::res#2 = (byte) 0 [phi:mul16u->mul16u::@1#1] -- vduz1=vbuc1
|
||||||
|
lda #0
|
||||||
|
sta.z res
|
||||||
|
sta.z res+1
|
||||||
|
sta.z res+2
|
||||||
|
sta.z res+3
|
||||||
|
// [15] phi (word) mul16u::a#2 = (byte) 4 [phi:mul16u->mul16u::@1#2] -- vwuz1=vbuc1
|
||||||
|
lda #<4
|
||||||
|
sta.z a
|
||||||
|
lda #>4
|
||||||
|
sta.z a+1
|
||||||
|
// mul16u::@1
|
||||||
|
b1:
|
||||||
|
// while(a!=0)
|
||||||
|
// [16] if((word) mul16u::a#2!=(byte) 0) goto mul16u::@2 -- vwuz1_neq_0_then_la1
|
||||||
|
lda.z a
|
||||||
|
bne b2
|
||||||
|
lda.z a+1
|
||||||
|
bne b2
|
||||||
|
// mul16u::@return
|
||||||
|
// }
|
||||||
|
// [17] return
|
||||||
|
rts
|
||||||
|
// mul16u::@2
|
||||||
|
b2:
|
||||||
|
// a&1
|
||||||
|
// [18] (byte~) mul16u::$1 ← (word) mul16u::a#2 & (byte) 1 -- vbuaa=vwuz1_band_vbuc1
|
||||||
|
lda #1
|
||||||
|
and.z a
|
||||||
|
// if( (a&1) != 0)
|
||||||
|
// [19] if((byte~) mul16u::$1==(byte) 0) goto mul16u::@3 -- vbuaa_eq_0_then_la1
|
||||||
|
cmp #0
|
||||||
|
beq b3
|
||||||
|
// mul16u::@4
|
||||||
|
// res = res + mb
|
||||||
|
// [20] (dword) mul16u::res#1 ← (dword) mul16u::res#2 + (dword) mul16u::mb#2 -- vduz1=vduz1_plus_vduz2
|
||||||
|
lda.z res
|
||||||
|
clc
|
||||||
|
adc.z mb
|
||||||
|
sta.z res
|
||||||
|
lda.z res+1
|
||||||
|
adc.z mb+1
|
||||||
|
sta.z res+1
|
||||||
|
lda.z res+2
|
||||||
|
adc.z mb+2
|
||||||
|
sta.z res+2
|
||||||
|
lda.z res+3
|
||||||
|
adc.z mb+3
|
||||||
|
sta.z res+3
|
||||||
|
// [21] phi from mul16u::@2 mul16u::@4 to mul16u::@3 [phi:mul16u::@2/mul16u::@4->mul16u::@3]
|
||||||
|
// [21] phi (dword) mul16u::res#6 = (dword) mul16u::res#2 [phi:mul16u::@2/mul16u::@4->mul16u::@3#0] -- register_copy
|
||||||
|
// mul16u::@3
|
||||||
|
b3:
|
||||||
|
// a = a>>1
|
||||||
|
// [22] (word) mul16u::a#0 ← (word) mul16u::a#2 >> (byte) 1 -- vwuz1=vwuz1_ror_1
|
||||||
|
lsr.z a+1
|
||||||
|
ror.z a
|
||||||
|
// mb = mb<<1
|
||||||
|
// [23] (dword) mul16u::mb#1 ← (dword) mul16u::mb#2 << (byte) 1 -- vduz1=vduz1_rol_1
|
||||||
|
asl.z mb
|
||||||
|
rol.z mb+1
|
||||||
|
rol.z mb+2
|
||||||
|
rol.z mb+3
|
||||||
|
// [15] phi from mul16u::@3 to mul16u::@1 [phi:mul16u::@3->mul16u::@1]
|
||||||
|
// [15] phi (dword) mul16u::mb#2 = (dword) mul16u::mb#1 [phi:mul16u::@3->mul16u::@1#0] -- register_copy
|
||||||
|
// [15] phi (dword) mul16u::res#2 = (dword) mul16u::res#6 [phi:mul16u::@3->mul16u::@1#1] -- register_copy
|
||||||
|
// [15] phi (word) mul16u::a#2 = (word) mul16u::a#0 [phi:mul16u::@3->mul16u::@1#2] -- register_copy
|
||||||
|
jmp b1
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
44
src/test/ref/loophead-problem-3.sym
Normal file
44
src/test/ref/loophead-problem-3.sym
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
(label) @1
|
||||||
|
(label) @begin
|
||||||
|
(label) @end
|
||||||
|
(byte*) BGCOL
|
||||||
|
(const byte*) BGCOL#0 BGCOL = (byte*) 53281
|
||||||
|
(byte*) BORDERCOL
|
||||||
|
(const byte*) BORDERCOL#0 BORDERCOL = (byte*) 53280
|
||||||
|
(void()) main()
|
||||||
|
(byte~) main::$2 reg byte a 4.0
|
||||||
|
(byte~) main::$3 reg byte a 4.0
|
||||||
|
(label) main::@1
|
||||||
|
(label) main::@return
|
||||||
|
(word) main::kaputt
|
||||||
|
(word) main::kaputt#0 kaputt zp ZP_WORD:10 2.0
|
||||||
|
(dword) main::result
|
||||||
|
(dword) main::result#0 result zp ZP_DWORD:2 4.0
|
||||||
|
(dword()) mul16u((word) mul16u::a , (word) mul16u::b)
|
||||||
|
(byte~) mul16u::$1 reg byte a 22.0
|
||||||
|
(label) mul16u::@1
|
||||||
|
(label) mul16u::@2
|
||||||
|
(label) mul16u::@3
|
||||||
|
(label) mul16u::@4
|
||||||
|
(label) mul16u::@return
|
||||||
|
(word) mul16u::a
|
||||||
|
(word) mul16u::a#0 a zp ZP_WORD:10 11.0
|
||||||
|
(word) mul16u::a#2 a zp ZP_WORD:10 7.333333333333333
|
||||||
|
(word) mul16u::b
|
||||||
|
(const word) mul16u::b#0 b = (byte) $7b
|
||||||
|
(dword) mul16u::mb
|
||||||
|
(dword) mul16u::mb#1 mb zp ZP_DWORD:6 22.0
|
||||||
|
(dword) mul16u::mb#2 mb zp ZP_DWORD:6 4.714285714285714
|
||||||
|
(dword) mul16u::res
|
||||||
|
(dword) mul16u::res#1 res zp ZP_DWORD:2 22.0
|
||||||
|
(dword) mul16u::res#2 res zp ZP_DWORD:2 5.833333333333333
|
||||||
|
(dword) mul16u::res#6 res zp ZP_DWORD:2 11.0
|
||||||
|
(dword) mul16u::return
|
||||||
|
(dword) mul16u::return#2 return zp ZP_DWORD:2 4.0
|
||||||
|
|
||||||
|
zp ZP_DWORD:2 [ mul16u::res#2 mul16u::res#6 mul16u::res#1 mul16u::return#2 main::result#0 ]
|
||||||
|
zp ZP_DWORD:6 [ mul16u::mb#2 mul16u::mb#1 ]
|
||||||
|
zp ZP_WORD:10 [ main::kaputt#0 mul16u::a#2 mul16u::a#0 ]
|
||||||
|
reg byte a [ main::$2 ]
|
||||||
|
reg byte a [ main::$3 ]
|
||||||
|
reg byte a [ mul16u::$1 ]
|
Loading…
Reference in New Issue
Block a user