added more missing codegen for bit shifts

This commit is contained in:
Irmen de Jong 2023-07-16 17:39:30 +02:00
parent 64254e758d
commit 47485e4b49
4 changed files with 183 additions and 87 deletions

View File

@ -512,86 +512,135 @@ internal class AssignmentAsmGen(private val program: PtProgram,
}
private fun optimizedBitshiftExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean {
val signed = expr.left.type in SignedDatatypes
val shifts = expr.right.asConstInteger()
if(shifts!=null) {
val dt = expr.left.type
val dt = expr.left.type
if(shifts==null) {
// bit shifts with variable shifts
when(expr.right.type) {
in ByteDatatypes -> {
assignExpressionToRegister(expr.right, RegisterOrPair.A, false)
}
in WordDatatypes -> {
assignExpressionToRegister(expr.right, RegisterOrPair.AY, false)
asmgen.out("""
cpy #0
beq +
lda #127
+""")
}
else -> throw AssemblyError("weird shift value type")
}
asmgen.out(" pha")
if(dt in ByteDatatypes) {
val signed = dt == DataType.BYTE
assignExpressionToRegister(expr.left, RegisterOrPair.A, signed)
if(shifts in 0..7) {
require(dt==DataType.UBYTE)
if (expr.operator == "<<") {
repeat(shifts) {
asmgen.out(" asl a")
}
} else {
if (signed && shifts > 0) {
asmgen.out(" ldy #$shifts | jsr math.lsr_byte_A")
} else {
asmgen.out(" ply")
if(expr.operator==">>")
if(signed)
asmgen.out(" jsr math.lsr_byte_A")
else
asmgen.out(" jsr math.lsr_ubyte_A")
else
asmgen.out(" jsr math.asl_byte_A")
assignRegisterByte(target, CpuRegister.A, signed)
return true
} else {
assignExpressionToRegister(expr.left, RegisterOrPair.AY, signed)
asmgen.out(" plx")
if(expr.operator==">>")
if(signed)
asmgen.out(" jsr math.lsr_word_AY")
else
asmgen.out(" jsr math.lsr_uword_AY")
else
asmgen.out(" jsr math.asl_word_AY")
assignRegisterpairWord(target, RegisterOrPair.AY)
return true
}
}
else {
// bit shift with constant value
if(dt in ByteDatatypes) {
assignExpressionToRegister(expr.left, RegisterOrPair.A, signed)
when (shifts) {
in 0..7 -> {
require(dt==DataType.UBYTE)
if (expr.operator == "<<") {
repeat(shifts) {
asmgen.out(" lsr a")
asmgen.out(" asl a")
}
} else {
if (signed && shifts > 0) {
asmgen.out(" ldy #$shifts | jsr math.lsr_byte_A")
} else {
repeat(shifts) {
asmgen.out(" lsr a")
}
}
}
assignRegisterByte(target, CpuRegister.A, signed)
return true
}
assignRegisterByte(target, CpuRegister.A, signed)
return true
} else {
if(signed && expr.operator==">>") {
TODO("signed byte >> overshift should have been compiled away?")
} else {
asmgen.out(" lda #0")
else -> {
if(signed && expr.operator==">>") {
TODO("signed byte >> overshift should have been compiled away?")
} else {
asmgen.out(" lda #0")
}
assignRegisterByte(target, CpuRegister.A, signed)
return true
}
assignRegisterByte(target, CpuRegister.A, signed)
return true
}
} else if(dt in WordDatatypes) {
val signed = dt == DataType.WORD
assignExpressionToRegister(expr.left, RegisterOrPair.AY, signed)
if(shifts in 0..7) {
if(expr.operator=="<<") {
if(shifts>0) {
asmgen.out(" sty P8ZP_SCRATCH_B1")
repeat(shifts) {
asmgen.out(" asl a | rol P8ZP_SCRATCH_B1")
}
asmgen.out(" ldy P8ZP_SCRATCH_B1")
}
} else {
if(signed && shifts>0) {
asmgen.out(" ldx #$shifts | jsr math.lsr_word_AY")
} else {
when (shifts) {
in 0..7 -> {
if(expr.operator=="<<") {
if(shifts>0) {
asmgen.out(" sty P8ZP_SCRATCH_B1")
repeat(shifts) {
asmgen.out(" lsr P8ZP_SCRATCH_B1 | ror a")
asmgen.out(" asl a | rol P8ZP_SCRATCH_B1")
}
asmgen.out(" ldy P8ZP_SCRATCH_B1")
}
} else {
if(signed && shifts>0) {
asmgen.out(" ldx #$shifts | jsr math.lsr_word_AY")
} else {
if(shifts>0) {
asmgen.out(" sty P8ZP_SCRATCH_B1")
repeat(shifts) {
asmgen.out(" lsr P8ZP_SCRATCH_B1 | ror a")
}
asmgen.out(" ldy P8ZP_SCRATCH_B1")
}
}
}
assignRegisterpairWord(target, RegisterOrPair.AY)
return true
}
assignRegisterpairWord(target, RegisterOrPair.AY)
return true
} else if (shifts in 8..15) {
if(expr.operator == "<<") {
// msb = lsb << (shifts-8), lsb = 0
repeat(shifts-8) {
asmgen.out(" asl a")
in 8..15 -> {
if(expr.operator == "<<") {
// msb = lsb << (shifts-8), lsb = 0
repeat(shifts-8) {
asmgen.out(" asl a")
}
asmgen.out(" tay | lda #0")
} else {
asmgen.out(" ldx #$shifts | jsr math.lsr_word_AY")
}
asmgen.out(" tay | lda #0")
} else {
asmgen.out(" ldx #$shifts | jsr math.lsr_word_AY")
assignRegisterpairWord(target, RegisterOrPair.AY)
return true
}
assignRegisterpairWord(target, RegisterOrPair.AY)
return true
}
else {
if(signed && expr.operator==">>") {
TODO("signed word >> overshift should have been compiled away?")
} else {
asmgen.out(" lda #0 | ldy #0")
else -> {
if(signed && expr.operator==">>") {
TODO("signed word >> overshift should have been compiled away?")
} else {
asmgen.out(" lda #0 | ldy #0")
}
assignRegisterpairWord(target, RegisterOrPair.AY)
return true
}
assignRegisterpairWord(target, RegisterOrPair.AY)
return true
}
}
}

View File

@ -751,37 +751,64 @@ mul_word_640 .proc
lsr_byte_A .proc
; -- lsr signed byte in A times the value in Y (>1)
cmp #0
bmi _negative
- lsr a
dey
bne -
rts
_negative sec
bpl lsr_ubyte_A
- sec
ror a
dey
bne _negative
bne -
rts
.pend
lsr_ubyte_A .proc
; -- lsr unsigned byte in A times the value in Y (>1)
- lsr a
dey
bne -
rts
.pend
asl_byte_A .proc
; -- asl any byte in A times the value in Y (>1)
- asl a
dey
bne -
rts
.pend
lsr_word_AY .proc
; -- lsr signed word in AY times the value in X (>1)
sta P8ZP_SCRATCH_B1
tya
bmi _negative
- lsr a
ror P8ZP_SCRATCH_B1
dex
bne -
tay
lda P8ZP_SCRATCH_B1
rts
cpy #0
bpl lsr_uword_AY
sty P8ZP_SCRATCH_B1
_negative sec
ror a
ror P8ZP_SCRATCH_B1
ror a
dex
bne _negative
tay
lda P8ZP_SCRATCH_B1
ldy P8ZP_SCRATCH_B1
rts
.pend
lsr_uword_AY .proc
; -- lsr unsigned word in AY times the value in X (>1)
sty P8ZP_SCRATCH_B1
- lsr P8ZP_SCRATCH_B1
ror a
dex
bne -
ldy P8ZP_SCRATCH_B1
rts
.pend
asl_word_AY .proc
; -- asl any word in AY times the value in X (>1)
sty P8ZP_SCRATCH_B1
- asl a
rol P8ZP_SCRATCH_B1
dex
bne -
ldy P8ZP_SCRATCH_B1
rts
.pend

View File

@ -1,6 +1,9 @@
TODO
====
- (branch): fix float expressions codegen, it relied heavily on the evalstack
- (branch): improve integer expression codegen even more to support even more cases?
- IR: instructions that do type conversion (SZ etc, CONCAT, SGN) should put the result in a DIFFERENT register.
- IR: reduce the number of branch instructions (gradually), replace with CMP(I) + status branch instruction

View File

@ -5,15 +5,32 @@ main
{
sub start()
{
byte zc = -55
uword zc = 54321
ubyte zb = 123
ubyte shift = 2
when zc*3 {
123 -> zc++
124 -> zc++
125 -> zc++
121 -> zc++
120 -> zc++
else -> zc++
}
txt.print_uw(zc<<shift)
txt.nl()
txt.print_uw(zc>>shift)
txt.nl()
txt.print_ub(zb<<shift)
txt.nl()
txt.print_ub(zb>>shift)
txt.nl()
word szc = -12345
byte szb = -123
txt.print_w(szc<<shift)
txt.nl()
txt.print_w(szc>>shift)
txt.nl()
txt.print_b(szb<<shift)
txt.nl()
txt.print_b(szb>>shift)
txt.nl()
; cx16.r1L = (zc<<shift) as ubyte
; txt.print_ub(cx16.r1L)
}
}