1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-23 08:32:39 +00:00

Fixed problem where zp_reserve is not being honoured after using __address. Closes #550

This commit is contained in:
jespergravgaard 2020-10-30 09:17:34 +01:00
parent eb183ada7e
commit d9fab8eb23
7 changed files with 1694 additions and 36 deletions

View File

@ -146,8 +146,19 @@ public abstract class Pass4MemoryCoalesce extends Pass2Base {
// Check the both registers have the same size // Check the both registers have the same size
if(register1.getBytes() != register2.getBytes()) if(register1.getBytes() != register2.getBytes())
return false; return false;
// check if either are in the reserved zp registers
if(register1 instanceof Registers.RegisterZpMem) {
int zp = ((Registers.RegisterZpMem) register1).getZp();
if(program.getReservedZps().contains(zp))
return false;
}
if(register2 instanceof Registers.RegisterZpMem) {
int zp = ((Registers.RegisterZpMem) register2).getZp();
if(program.getReservedZps().contains(zp))
return false;
}
return true; return true;
} }
/** /**
* Determines if two live range equivalence classes can be coalesced without clobber. * Determines if two live range equivalence classes can be coalesced without clobber.
@ -220,46 +231,46 @@ public abstract class Pass4MemoryCoalesce extends Pass2Base {
} }
/** /**
* A pair of live range equivalence classes that are candidates for coalescing. * A pair of live range equivalence classes that are candidates for coalescing.
* The pair is unordered - meaning it is equal to the pair with the same classes in opposite order. * The pair is unordered - meaning it is equal to the pair with the same classes in opposite order.
*/ */
static class LiveRangeEquivalenceClassCoalesceCandidate { static class LiveRangeEquivalenceClassCoalesceCandidate {
private LiveRangeEquivalenceClass ec1; private LiveRangeEquivalenceClass ec1;
private LiveRangeEquivalenceClass ec2; private LiveRangeEquivalenceClass ec2;
private Integer score; private Integer score;
public LiveRangeEquivalenceClassCoalesceCandidate(LiveRangeEquivalenceClass ec1, LiveRangeEquivalenceClass ec2, Integer score) { public LiveRangeEquivalenceClassCoalesceCandidate(LiveRangeEquivalenceClass ec1, LiveRangeEquivalenceClass ec2, Integer score) {
this.ec1 = ec1; this.ec1 = ec1;
this.ec2 = ec2; this.ec2 = ec2;
this.score = score; this.score = score;
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if(this == o) return true; if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false; if(o == null || getClass() != o.getClass()) return false;
LiveRangeEquivalenceClassCoalesceCandidate that = (LiveRangeEquivalenceClassCoalesceCandidate) o; LiveRangeEquivalenceClassCoalesceCandidate that = (LiveRangeEquivalenceClassCoalesceCandidate) o;
if(ec1.equals(that.ec1) && ec2.equals(that.ec2)) return true; if(ec1.equals(that.ec1) && ec2.equals(that.ec2)) return true;
if(ec1.equals(that.ec2) && ec2.equals(that.ec1)) return true; if(ec1.equals(that.ec2) && ec2.equals(that.ec1)) return true;
return false; return false;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return ec1.hashCode() + ec2.hashCode(); return ec1.hashCode() + ec2.hashCode();
} }
public Integer getScore() { public Integer getScore() {
return score; return score;
} }
public LiveRangeEquivalenceClass getEc1() { public LiveRangeEquivalenceClass getEc1() {
return ec1; return ec1;
} }
public LiveRangeEquivalenceClass getEc2() { public LiveRangeEquivalenceClass getEc2() {
return ec2; return ec2;
}
} }
} }
}

View File

@ -44,6 +44,11 @@ public class TestPrograms {
public TestPrograms() { public TestPrograms() {
} }
@Test
public void testZpReserveCoalesceProblem() throws IOException, URISyntaxException {
compileAndCompare("zp-reserve-coalesce-problem.c");
}
@Test @Test
public void testChipsetTest() throws IOException, URISyntaxException { public void testChipsetTest() throws IOException, URISyntaxException {
compileAndCompare("chipset-test.c"); compileAndCompare("chipset-test.c");

View File

@ -0,0 +1,47 @@
// Demonstrates problem where reserved ZP addresses can still be coalesced if they are explicitly __address() assigned to variables
// https://gitlab.com/camelot/kickc/-/issues/550
#pragma target(atarixl)
#pragma zp_reserve(0x00..0x7f)
void main() {
benchmarkCountdownFor();
benchmarkLandscape();
}
char landscapeBase[] = kickasm {{
.fill 14, 0
}};
char * const lms = 0xa000;
void benchmarkCountdownFor() {
__address(0x41) signed char a;
__address(0x4b) signed char b;
for(a = 1; a >= 0; a--) {
for(b = 9; b >= 0; b--) {
}
}
}
void benchmarkLandscape() {
char colHeight[14];
for(char z: 0..9) {
for (char i: 0..13) { colHeight[i] = landscapeBase[i]; }
for (signed char x = 39; x >= 0; x--) {
char *screenAddress = lms + x;
char start = 0;
for (signed char c = 13; c >= 0; c--) {
char uc = (char) c;
char stop = colHeight[uc];
while (start < stop) {
*screenAddress = ((*screenAddress) & 0xf) | (uc << 4);
screenAddress += 40;
start++;
}
start = stop;
}
}
}
}

View File

@ -0,0 +1,173 @@
// Demonstrates problem where reserved ZP addresses can still be coalesced if they are explicitly __address() assigned to variables
// https://gitlab.com/camelot/kickc/-/issues/550
// Atari XL/XE executable XEX file with a single segment
// https://www.atarimax.com/jindroush.atari.org/afmtexe.html
.file [name="zp-reserve-coalesce-problem.xex", type="bin", segments="XexFile"]
.segmentdef XexFile
.segment XexFile
// Binary File Header
.byte $ff, $ff
// Program segment [start address, end address, data]
.word ProgramStart, ProgramEnd-1
.segmentout [ segments="Program" ]
// RunAd - Run Address Segment [start address, end address, data]
.word $02e0, $02e1
.word main
.segmentdef Program [segments="ProgramStart, Code, Data, ProgramEnd"]
.segmentdef ProgramStart [start=$2000]
.segment ProgramStart
ProgramStart:
.segmentdef Code [startAfter="ProgramStart"]
.segmentdef Data [startAfter="Code"]
.segmentdef ProgramEnd [startAfter="Data"]
.segment ProgramEnd
ProgramEnd:
.label lms = $a000
.segment Code
main: {
// benchmarkCountdownFor()
jsr benchmarkCountdownFor
// benchmarkLandscape()
jsr benchmarkLandscape
// }
rts
}
benchmarkCountdownFor: {
.label a = $41
.label b = $4b
// a
lda #0
sta.z a
// b
sta.z b
// a = 1
lda #1
sta.z a
__b1:
// for(a = 1; a >= 0; a--)
lda.z a
cmp #0
bpl __b2
// }
rts
__b2:
// b = 9
lda #9
sta.z b
__b3:
// for(b = 9; b >= 0; b--)
lda.z b
cmp #0
bpl __b4
// for(a = 1; a >= 0; a--)
dec.z a
jmp __b1
__b4:
// for(b = 9; b >= 0; b--)
dec.z b
jmp __b3
}
benchmarkLandscape: {
.label __5 = $86
.label screenAddress = $83
.label z = $80
.label stop = $85
.label x = $81
.label c = $82
lda #0
sta.z z
__b1:
ldx #0
__b2:
// colHeight[i] = landscapeBase[i]
lda landscapeBase,x
sta colHeight,x
// for (char i: 0..13)
inx
cpx #$e
bne __b2
lda #$27
sta.z x
__b3:
// for (signed char x = 39; x >= 0; x--)
lda.z x
cmp #0
bpl __b4
// for(char z: 0..9)
inc.z z
lda #$a
cmp.z z
bne __b1
// }
rts
__b4:
// screenAddress = lms + x
lda.z x
clc
adc #<lms
sta.z screenAddress
lda.z x
ora #$7f
bmi !+
lda #0
!:
adc #>lms
sta.z screenAddress+1
ldx #0
lda #$d
sta.z c
__b6:
// for (signed char c = 13; c >= 0; c--)
lda.z c
cmp #0
bpl __b7
// for (signed char x = 39; x >= 0; x--)
dec.z x
jmp __b3
__b7:
// stop = colHeight[uc]
ldy.z c
lda colHeight,y
sta.z stop
__b9:
// while (start < stop)
cpx.z stop
bcc __b10
// for (signed char c = 13; c >= 0; c--)
dec.z c
ldx.z stop
jmp __b6
__b10:
// (*screenAddress) & 0xf
lda #$f
ldy #0
and (screenAddress),y
sta.z __5
// uc << 4
lda.z c
asl
asl
asl
asl
// ((*screenAddress) & 0xf) | (uc << 4)
ora.z __5
// *screenAddress = ((*screenAddress) & 0xf) | (uc << 4)
sta (screenAddress),y
// screenAddress += 40
lda #$28
clc
adc.z screenAddress
sta.z screenAddress
bcc !+
inc.z screenAddress+1
!:
// start++;
inx
jmp __b9
.segment Data
colHeight: .fill $e, 0
}
landscapeBase:
.fill 14, 0

View File

@ -0,0 +1,95 @@
void main()
main: scope:[main] from
[0] phi()
[1] call benchmarkCountdownFor
to:main::@1
main::@1: scope:[main] from main
[2] phi()
[3] call benchmarkLandscape
to:main::@return
main::@return: scope:[main] from main::@1
[4] return
to:@return
void benchmarkCountdownFor()
benchmarkCountdownFor: scope:[benchmarkCountdownFor] from main
[5] benchmarkCountdownFor::a = 0
[6] benchmarkCountdownFor::b = 0
[7] benchmarkCountdownFor::a = 1
to:benchmarkCountdownFor::@1
benchmarkCountdownFor::@1: scope:[benchmarkCountdownFor] from benchmarkCountdownFor benchmarkCountdownFor::@5
[8] if(benchmarkCountdownFor::a>=0) goto benchmarkCountdownFor::@2
to:benchmarkCountdownFor::@return
benchmarkCountdownFor::@return: scope:[benchmarkCountdownFor] from benchmarkCountdownFor::@1
[9] return
to:@return
benchmarkCountdownFor::@2: scope:[benchmarkCountdownFor] from benchmarkCountdownFor::@1
[10] benchmarkCountdownFor::b = 9
to:benchmarkCountdownFor::@3
benchmarkCountdownFor::@3: scope:[benchmarkCountdownFor] from benchmarkCountdownFor::@2 benchmarkCountdownFor::@4
[11] if(benchmarkCountdownFor::b>=0) goto benchmarkCountdownFor::@4
to:benchmarkCountdownFor::@5
benchmarkCountdownFor::@5: scope:[benchmarkCountdownFor] from benchmarkCountdownFor::@3
[12] benchmarkCountdownFor::a = -- benchmarkCountdownFor::a
to:benchmarkCountdownFor::@1
benchmarkCountdownFor::@4: scope:[benchmarkCountdownFor] from benchmarkCountdownFor::@3
[13] benchmarkCountdownFor::b = -- benchmarkCountdownFor::b
to:benchmarkCountdownFor::@3
void benchmarkLandscape()
benchmarkLandscape: scope:[benchmarkLandscape] from main::@1
[14] phi()
to:benchmarkLandscape::@1
benchmarkLandscape::@1: scope:[benchmarkLandscape] from benchmarkLandscape benchmarkLandscape::@5
[15] benchmarkLandscape::z#8 = phi( benchmarkLandscape/0, benchmarkLandscape::@5/benchmarkLandscape::z#1 )
to:benchmarkLandscape::@2
benchmarkLandscape::@2: scope:[benchmarkLandscape] from benchmarkLandscape::@1 benchmarkLandscape::@2
[16] benchmarkLandscape::i#2 = phi( benchmarkLandscape::@1/0, benchmarkLandscape::@2/benchmarkLandscape::i#1 )
[17] benchmarkLandscape::colHeight[benchmarkLandscape::i#2] = landscapeBase[benchmarkLandscape::i#2]
[18] benchmarkLandscape::i#1 = ++ benchmarkLandscape::i#2
[19] if(benchmarkLandscape::i#1!=$e) goto benchmarkLandscape::@2
to:benchmarkLandscape::@3
benchmarkLandscape::@3: scope:[benchmarkLandscape] from benchmarkLandscape::@2 benchmarkLandscape::@8
[20] benchmarkLandscape::x#2 = phi( benchmarkLandscape::@2/$27, benchmarkLandscape::@8/benchmarkLandscape::x#1 )
[21] if(benchmarkLandscape::x#2>=0) goto benchmarkLandscape::@4
to:benchmarkLandscape::@5
benchmarkLandscape::@5: scope:[benchmarkLandscape] from benchmarkLandscape::@3
[22] benchmarkLandscape::z#1 = ++ benchmarkLandscape::z#8
[23] if(benchmarkLandscape::z#1!=$a) goto benchmarkLandscape::@1
to:benchmarkLandscape::@return
benchmarkLandscape::@return: scope:[benchmarkLandscape] from benchmarkLandscape::@5
[24] return
to:@return
benchmarkLandscape::@4: scope:[benchmarkLandscape] from benchmarkLandscape::@3
[25] benchmarkLandscape::screenAddress#0 = lms + benchmarkLandscape::x#2
to:benchmarkLandscape::@6
benchmarkLandscape::@6: scope:[benchmarkLandscape] from benchmarkLandscape::@11 benchmarkLandscape::@4
[26] benchmarkLandscape::screenAddress#4 = phi( benchmarkLandscape::@11/benchmarkLandscape::screenAddress#2, benchmarkLandscape::@4/benchmarkLandscape::screenAddress#0 )
[26] benchmarkLandscape::start#5 = phi( benchmarkLandscape::@11/benchmarkLandscape::start#7, benchmarkLandscape::@4/0 )
[26] benchmarkLandscape::c#2 = phi( benchmarkLandscape::@11/benchmarkLandscape::c#1, benchmarkLandscape::@4/$d )
[27] if(benchmarkLandscape::c#2>=0) goto benchmarkLandscape::@7
to:benchmarkLandscape::@8
benchmarkLandscape::@8: scope:[benchmarkLandscape] from benchmarkLandscape::@6
[28] benchmarkLandscape::x#1 = -- benchmarkLandscape::x#2
to:benchmarkLandscape::@3
benchmarkLandscape::@7: scope:[benchmarkLandscape] from benchmarkLandscape::@6
[29] benchmarkLandscape::stop#0 = benchmarkLandscape::colHeight[(byte)benchmarkLandscape::c#2]
to:benchmarkLandscape::@9
benchmarkLandscape::@9: scope:[benchmarkLandscape] from benchmarkLandscape::@10 benchmarkLandscape::@7
[30] benchmarkLandscape::screenAddress#2 = phi( benchmarkLandscape::@10/benchmarkLandscape::screenAddress#1, benchmarkLandscape::@7/benchmarkLandscape::screenAddress#4 )
[30] benchmarkLandscape::start#3 = phi( benchmarkLandscape::@10/benchmarkLandscape::start#1, benchmarkLandscape::@7/benchmarkLandscape::start#5 )
[31] if(benchmarkLandscape::start#3<benchmarkLandscape::stop#0) goto benchmarkLandscape::@10
to:benchmarkLandscape::@11
benchmarkLandscape::@11: scope:[benchmarkLandscape] from benchmarkLandscape::@9
[32] benchmarkLandscape::c#1 = -- benchmarkLandscape::c#2
[33] benchmarkLandscape::start#7 = benchmarkLandscape::stop#0
to:benchmarkLandscape::@6
benchmarkLandscape::@10: scope:[benchmarkLandscape] from benchmarkLandscape::@9
[34] benchmarkLandscape::$5 = *benchmarkLandscape::screenAddress#2 & $f
[35] benchmarkLandscape::$6 = (byte)benchmarkLandscape::c#2 << 4
[36] benchmarkLandscape::$7 = benchmarkLandscape::$5 | benchmarkLandscape::$6
[37] *benchmarkLandscape::screenAddress#2 = benchmarkLandscape::$7
[38] benchmarkLandscape::screenAddress#1 = benchmarkLandscape::screenAddress#2 + $28
[39] benchmarkLandscape::start#1 = ++ benchmarkLandscape::start#3
to:benchmarkLandscape::@9

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,50 @@
void benchmarkCountdownFor()
signed byte benchmarkCountdownFor::a loadstore !zp[-1]:65 zp[1]:65 54.16666666666666
signed byte benchmarkCountdownFor::b loadstore !zp[-1]:75 zp[1]:75 1038.3333333333335
void benchmarkLandscape()
byte~ benchmarkLandscape::$5 zp[1]:134 100001.0
byte~ benchmarkLandscape::$6 reg byte a 200002.0
byte~ benchmarkLandscape::$7 reg byte a 200002.0
signed byte benchmarkLandscape::c
signed byte benchmarkLandscape::c#1 c zp[1]:130 10001.0
signed byte benchmarkLandscape::c#2 c zp[1]:130 2727.5454545454545
const byte* benchmarkLandscape::colHeight[$e] = { fill( $e, 0) }
byte benchmarkLandscape::i
byte benchmarkLandscape::i#1 reg byte x 1501.5
byte benchmarkLandscape::i#2 reg byte x 2002.0
byte* benchmarkLandscape::screenAddress
byte* benchmarkLandscape::screenAddress#0 screenAddress zp[2]:131 2002.0
byte* benchmarkLandscape::screenAddress#1 screenAddress zp[2]:131 100001.0
byte* benchmarkLandscape::screenAddress#2 screenAddress zp[2]:131 52500.75
byte* benchmarkLandscape::screenAddress#4 screenAddress zp[2]:131 7001.0
byte benchmarkLandscape::start
byte benchmarkLandscape::start#1 reg byte x 200002.0
byte benchmarkLandscape::start#3 reg byte x 44286.28571428572
byte benchmarkLandscape::start#5 reg byte x 6667.333333333333
byte benchmarkLandscape::start#7 reg byte x 20002.0
byte benchmarkLandscape::stop
byte benchmarkLandscape::stop#0 stop zp[1]:133 12000.300000000001
byte benchmarkLandscape::uc
signed byte benchmarkLandscape::x
signed byte benchmarkLandscape::x#1 x zp[1]:129 2002.0
signed byte benchmarkLandscape::x#2 x zp[1]:129 250.25
byte benchmarkLandscape::z
byte benchmarkLandscape::z#1 z zp[1]:128 151.5
byte benchmarkLandscape::z#8 z zp[1]:128 9.181818181818182
const byte* landscapeBase[] = kickasm {{ .fill 14, 0
}}
const nomodify byte* lms = (byte*) 40960
void main()
zp[1]:128 [ benchmarkLandscape::z#8 benchmarkLandscape::z#1 ]
reg byte x [ benchmarkLandscape::i#2 benchmarkLandscape::i#1 ]
zp[1]:129 [ benchmarkLandscape::x#2 benchmarkLandscape::x#1 ]
zp[1]:130 [ benchmarkLandscape::c#2 benchmarkLandscape::c#1 ]
zp[2]:131 [ benchmarkLandscape::screenAddress#4 benchmarkLandscape::screenAddress#2 benchmarkLandscape::screenAddress#0 benchmarkLandscape::screenAddress#1 ]
reg byte x [ benchmarkLandscape::start#3 benchmarkLandscape::start#1 benchmarkLandscape::start#5 benchmarkLandscape::start#7 ]
zp[1]:65 [ benchmarkCountdownFor::a ]
zp[1]:75 [ benchmarkCountdownFor::b ]
zp[1]:133 [ benchmarkLandscape::stop#0 ]
zp[1]:134 [ benchmarkLandscape::$5 ]
reg byte a [ benchmarkLandscape::$6 ]
reg byte a [ benchmarkLandscape::$7 ]