avoid unnecessary word extension when assigning a register byte to a byte target

This commit is contained in:
Irmen de Jong
2025-02-17 22:03:54 +01:00
parent d06e9ea7f6
commit 09ec508f82
3 changed files with 110 additions and 21 deletions
@@ -727,7 +727,7 @@ class AsmGen6502Internal (
}
assignExpressionToRegister(value, RegisterOrPair.A)
assignRegister(RegisterOrPair.A, target)
assignmentAsmGen.assignRegisterByte(target, CpuRegister.A, target.datatype.isSigned, false)
}
target.datatype.isWord || target.datatype.isPassByRef -> {
assignExpressionToRegister(value, RegisterOrPair.AY)
@@ -1063,26 +1063,39 @@ $repeatLabel""")
private fun translate(ret: PtReturn) {
val returnvalue = ret.children.singleOrNull()
val sub = ret.definingSub()!!
val returnRegs = sub.returnsWhatWhere()
if(returnvalue!=null) {
val sub = ret.definingSub()!!
val returnReg = sub.returnsWhatWhere().single()
if (sub.returns.single().isNumericOrBool==true) {
assignExpressionToRegister(returnvalue as PtExpression, returnReg.first.registerOrPair!!)
assignExpressionToRegister(returnvalue as PtExpression, returnRegs.single().first.registerOrPair!!)
}
else {
// all else take its address and assign that also to AY register pair
val addrofValue = PtAddressOf(returnvalue.position)
addrofValue.add(returnvalue as PtIdentifier)
addrofValue.parent = ret.parent
assignmentAsmGen.assignExpressionToRegister(addrofValue, returnReg.first.registerOrPair!!, false)
assignmentAsmGen.assignExpressionToRegister(addrofValue, returnRegs.single().first.registerOrPair!!, false)
}
}
else if(ret.children.size>1) {
// multi-value returns are passed throug cx16.R15 down to R0 (allows unencumbered use of many Rx registers if you don't return that many values)
val registersReverseOrder = Cx16VirtualRegisters.reversed()
ret.children.zip(registersReverseOrder).forEach { (value, register) ->
assignExpressionToRegister(value as PtExpression, register)
val assigns = ret.children.zip(returnRegs).map { it.first to it.second }
assigns.forEach {
val tgt = AsmAssignTarget(TargetStorageKind.REGISTER, this, it.second.second, null, it.first.position, register = it.second.first.registerOrPair!!)
assignExpressionTo(it.first as PtExpression, tgt)
}
// TODO: note: multi-value returns are passed throug cx16.R15 down to R0 (allows unencumbered use of many Rx registers if you don't return that many values)
// TODO: to avoid register clobbering, assign the first return value last in row.
/*
assigns.drop(1).forEach {
val tgt = AsmAssignTarget(TargetStorageKind.REGISTER, this, it.second.second, null, it.first.position, register = it.second.first.registerOrPair!!)
assignExpressionTo(it.first as PtExpression, tgt)
}
assigns.first().also {
assignExpressionToRegister(it.first as PtExpression, it.second.first.registerOrPair!!)
}
*/
}
out(" rts")
}
@@ -3,7 +3,7 @@ package prog8.codegen.cpu6502
import prog8.code.ast.IPtSubroutine
import prog8.code.ast.PtAsmSub
import prog8.code.ast.PtSub
import prog8.code.core.AssemblyError
import prog8.code.core.Cx16VirtualRegisters
import prog8.code.core.DataType
import prog8.code.core.RegisterOrPair
import prog8.code.core.RegisterOrStatusflag
@@ -17,21 +17,31 @@ internal fun IPtSubroutine.returnsWhatWhere(): List<Pair<RegisterOrStatusflag, D
is PtSub -> {
// for non-asm subroutines, determine the return registers based on the type of the return values
fun cpuRegisterFor(returntype: DataType): RegisterOrStatusflag = when {
returntype.isByteOrBool -> RegisterOrStatusflag(RegisterOrPair.A, null)
returntype.isWord -> RegisterOrStatusflag(RegisterOrPair.AY, null)
returntype.isFloat -> RegisterOrStatusflag(RegisterOrPair.FAC1, null)
else -> RegisterOrStatusflag(RegisterOrPair.AY, null)
}
when(returns.size) {
0 -> return emptyList()
1 -> {
val returntype = returns.single()
val register = when {
returntype.isByteOrBool -> RegisterOrStatusflag(RegisterOrPair.A, null)
returntype.isWord -> RegisterOrStatusflag(RegisterOrPair.AY, null)
returntype.isFloat -> RegisterOrStatusflag(RegisterOrPair.FAC1, null)
else -> RegisterOrStatusflag(RegisterOrPair.AY, null)
}
val register = cpuRegisterFor(returntype)
return listOf(Pair(register, returntype))
}
else -> {
// TODO for multi-value results, put the first one in register(s) and only the rest in the virtual registers?
throw AssemblyError("multi-value returns from a normal subroutine are not put into registers, this routine shouldn't have been called in this scenario")
val others = returns.zip(Cx16VirtualRegisters.reversed())
.map { (type, reg) -> RegisterOrStatusflag(reg, null) to type }
return others
// TODO for multi-value results, put the first one in A or AY cpu register(s) and the rest in the virtual registers starting from R15 and counting down
// val first = cpuRegisterFor(returns.first()) to returns.first()
// val others = returns.drop(1)
// .zip(Cx16VirtualRegisters.reversed())
// .map { (type, reg) -> RegisterOrStatusflag(reg, null) to type }
// return listOf(first) + others
}
}
}
+69 -3
View File
@@ -1,12 +1,78 @@
%import textio
%zeropage basicsafe
%option no_sysinit
main {
sub start() {
const uword MAX_CAVE_WIDTH = 440 ; word here to avoid having to cast to word all the time
cx16.r5 = one()
txt.print_uw(cx16.r5)
txt.nl()
if cx16.r0L > MAX_CAVE_WIDTH
return
cx16.r5, cx16.r6 = two()
txt.print_uw(cx16.r5)
txt.spc()
txt.print_uw(cx16.r6)
txt.nl()
cx16.r5, cx16.r6, cx16.r7 = three()
txt.print_uw(cx16.r5)
txt.spc()
txt.print_uw(cx16.r6)
txt.spc()
txt.print_uw(cx16.r7)
txt.nl()
; bytes
cx16.r5L = oneb()
txt.print_ub(cx16.r5L)
txt.nl()
cx16.r5L, cx16.r6L = twob()
txt.print_ub(cx16.r5L)
txt.spc()
txt.print_ub(cx16.r6L)
txt.nl()
cx16.r5L, cx16.r6L, cx16.r7L = threeb()
txt.print_ub(cx16.r5L)
txt.spc()
txt.print_ub(cx16.r6L)
txt.spc()
txt.print_ub(cx16.r7L)
txt.nl()
}
uword @shared w1=1111
uword @shared w2=2222
uword @shared w3=3333
ubyte @shared b1=11
ubyte @shared b2=22
ubyte @shared b3=33
sub one() -> uword {
cx16.r0L++
return w1
}
sub two() -> uword, uword { ; TODO no P8SRC generated in IR?
return w1, w2
}
sub three() -> uword, uword, uword { ; TODO no P8SRC generated in IR?
return w1, w2, w3
}
sub oneb() -> ubyte {
cx16.r0L++
return b1
}
sub twob() -> ubyte,ubyte { ; TODO no P8SRC generated in IR?
return b1, b2
}
sub threeb() -> ubyte, ubyte, ubyte { ; TODO no P8SRC generated in IR?
return b1, b2, b3
}
}