diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 36274bccb..735d88d00 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -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 } } } diff --git a/compiler/res/prog8lib/math.asm b/compiler/res/prog8lib/math.asm index 3efa4e42e..abbbbc3bb 100644 --- a/compiler/res/prog8lib/math.asm +++ b/compiler/res/prog8lib/math.asm @@ -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 diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 6289ce662..f6c13877e 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -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 diff --git a/examples/test.p8 b/examples/test.p8 index d1e61c976..6298b9e33 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -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_ub(zb<>shift) + txt.nl() + + word szc = -12345 + byte szb = -123 + txt.print_w(szc<>shift) + txt.nl() + txt.print_b(szb<>shift) + txt.nl() + + +; cx16.r1L = (zc<