optimize some result register cases for peekw()

This commit is contained in:
Irmen de Jong
2026-02-22 22:52:38 +01:00
parent fe8d904792
commit f6b59c6832
7 changed files with 168 additions and 44 deletions
@@ -2576,7 +2576,7 @@ $repeatLabel""")
jsr floats.MOVFM""")
}
internal fun loadIndirectWord(zpPtrVar: String, offset: UByte) {
internal fun loadIndirectWordAY(zpPtrVar: String, offset: UByte) {
// loads word pointed to by the ptr var into AY
if (offset > 0u) {
out("""
@@ -2606,6 +2606,41 @@ $repeatLabel""")
}
}
internal fun loadIndirectWordAX(zpPtrVar: String, offset: UByte) {
// loads word pointed to by the ptr var into AX
if (offset > 0u) {
out("""
ldy #$offset+1
lda ($zpPtrVar),y
tax
dey
lda ($zpPtrVar),y""")
} else {
if(isTargetCpu(CpuType.CPU65C02))
out("""
ldy #1
lda ($zpPtrVar),y
tax
lda ($zpPtrVar)""")
else
out("""
ldy #1
lda ($zpPtrVar),y
tax
dey
lda ($zpPtrVar),y""")
}
}
internal fun loadIndirectWordIntoRegisters(zpPtrVar: String, offset: UByte, register: RegisterOrPair) {
when(register) {
RegisterOrPair.AY -> loadIndirectWordAY(zpPtrVar, offset)
RegisterOrPair.AX -> loadIndirectWordAX(zpPtrVar, offset)
RegisterOrPair.XY -> TODO("load into XY")
else -> throw AssemblyError("invalid register for indirect load word $register")
}
}
internal fun loadIndirectLongIntoCombinedLongRegister(zpPtrVar: String, offset: UByte, targetRegPair: RegisterOrPair) {
val regstart = targetRegPair.startregname()
out("""
@@ -1646,7 +1646,12 @@ import prog8.codegen.cpu6502.assignment.*
is PtIdentifier -> {
val varname = asmgen.asmVariableName(addrExpr)
if(asmgen.isZpVar(addrExpr)) {
asmgen.loadIndirectWord(varname, 0u)
if(resultReg in arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
asmgen.loadIndirectWordIntoRegisters(varname, 0u, resultReg)
return arrayOf(resultReg)
} else {
asmgen.loadIndirectWordAY(varname, 0u)
}
}
else
fallback()
@@ -1659,25 +1664,70 @@ import prog8.codegen.cpu6502.assignment.*
// can do (ZP),Y indexing
val varname = asmgen.asmVariableName(pointer)
asmgen.assignExpressionToRegister(result.second, RegisterOrPair.Y)
asmgen.out("""
lda ($varname),y
tax
iny
lda ($varname),y
tay
txa""")
when(resultReg) {
RegisterOrPair.AX -> {
asmgen.out("""
iny
lda ($varname),y
tax
dey
lda ($varname),y""")
return arrayOf(RegisterOrPair.AX)
}
RegisterOrPair.AY -> {
asmgen.out("""
lda ($varname),y
tax
iny
lda ($varname),y
tay
txa""")
return arrayOf(RegisterOrPair.AY)
}
RegisterOrPair.XY -> TODO("peekw into xy ${fcall.position}")
else -> throw AssemblyError("invalid register for indirect load word $resultReg ${fcall.position}")
}
} else if(addressOfIdentifier!=null && (addressOfIdentifier.type.isWord || addressOfIdentifier.type.isPointer || addressOfIdentifier.type.isByteArray)) {
val varname = asmgen.asmVariableName(addressOfIdentifier)
if(result.second is PtNumber) {
val offset = (result.second as PtNumber).number.toInt()
asmgen.out(" lda $varname+$offset | ldy $varname+${offset + 1}")
when(resultReg) {
RegisterOrPair.AX -> asmgen.out(" lda $varname+$offset | ldx $varname+${offset + 1}")
RegisterOrPair.AY -> asmgen.out(" lda $varname+$offset | ldy $varname+${offset + 1}")
RegisterOrPair.XY -> asmgen.out(" ldx $varname+$offset | ldy $varname+${offset + 1}")
else -> throw AssemblyError("peekw must have result in AX, AY or XY ${fcall.position}")
}
} else if(result.second is PtIdentifier) {
val offsetname = asmgen.asmVariableName(result.second as PtIdentifier)
asmgen.out("""
ldx $offsetname
lda $varname+1,x
tay
lda $varname,x""")
when(resultReg) {
RegisterOrPair.AX -> {
asmgen.out("""
ldy $offsetname
lda $varname+1,y
tax
lda $varname,y""")
return arrayOf(RegisterOrPair.AX)
}
RegisterOrPair.AY -> {
asmgen.out("""
ldx $offsetname
lda $varname+1,x
tay
lda $varname,x""")
return arrayOf(RegisterOrPair.AY)
}
RegisterOrPair.XY -> {
asmgen.out("""
ldx $offsetname
lda $varname+1,x
tay
lda $varname,x
tax""")
return arrayOf(RegisterOrPair.XY)
}
else -> throw AssemblyError("peekw must have result in AX, AY or XY ${fcall.position}")
}
// TODO load directly into other registers
} else fallback()
} else if(addrExpr.operator=="+" && addrExpr.left is PtIdentifier) {
readValueFromPointerPlusOffset(addrExpr.left as PtIdentifier, addrExpr.right, BaseDataType.UWORD)
@@ -2072,7 +2122,15 @@ import prog8.codegen.cpu6502.assignment.*
else -> throw AssemblyError("invalid register for lsb: $resultReg")
}
} else {
if(arg is PtArrayIndexer) {
if(fromLong) {
asmgen.assignExpressionToRegister(arg, RegisterOrPair.R14R15, arg.type.isSigned)
when(resultReg) {
RegisterOrPair.A -> asmgen.out(" lda cx16.r14")
RegisterOrPair.X -> asmgen.out(" ldx cx16.r14")
RegisterOrPair.Y -> asmgen.out(" ldy cx16.r14")
else -> throw AssemblyError("invalid register for lsb: $resultReg")
}
} else if(arg is PtArrayIndexer) {
// just read the lsb byte out of the word array
if(arg.variable==null)
TODO("support for ptr indexing ${arg.position}")
@@ -2094,19 +2152,19 @@ import prog8.codegen.cpu6502.assignment.*
}
else -> throw AssemblyError("invalid register for lsb: $resultReg")
}
} else if(fromLong) {
asmgen.assignExpressionToRegister(arg, RegisterOrPair.R14R15, arg.type.isSigned)
when(resultReg) {
RegisterOrPair.A -> asmgen.out(" lda cx16.r14")
RegisterOrPair.X -> asmgen.out(" ldx cx16.r14")
RegisterOrPair.Y -> asmgen.out(" ldy cx16.r14")
else -> throw AssemblyError("invalid register for lsb: $resultReg")
}
} else {
asmgen.assignExpressionToRegister(arg, RegisterOrPair.AY)
// NOTE: we rely on the fact that the above assignment to AY, assigns the Lsb to A as the last instruction.
// this is required because the compiler assumes the status bits are set according to what A is (lsb)
// and will not generate another cmp when lsb() is directly used inside a comparison expression.
when(resultReg) {
RegisterOrPair.A -> asmgen.assignExpressionToRegister(arg, RegisterOrPair.AY)
RegisterOrPair.X -> asmgen.assignExpressionToRegister(arg, RegisterOrPair.XY)
RegisterOrPair.Y -> {
asmgen.assignExpressionToRegister(arg, RegisterOrPair.AY)
asmgen.out(" tay")
}
else -> throw AssemblyError("invalid register for lsb: $resultReg")
}
}
}
@@ -548,8 +548,12 @@ internal class AssignmentAsmGen(
asmgen.assignRegister(RegisterOrPair.A, assign.target)
}
dt.isWord ||dt.isPointer -> {
asmgen.loadIndirectWord(zpPtrVar, offset)
asmgen.assignRegister(RegisterOrPair.AY, assign.target)
if(assign.target.register in arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
asmgen.loadIndirectWordIntoRegisters(zpPtrVar, offset, assign.target.register!!)
} else {
asmgen.loadIndirectWordAY(zpPtrVar, offset)
asmgen.assignRegister(RegisterOrPair.AY, assign.target)
}
}
dt.isFloat -> {
asmgen.loadIndirectFloat(zpPtrVar, offset)
@@ -248,8 +248,12 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
asmgen.assignRegister(RegisterOrPair.A, target)
}
else if(value.type.isWord || value.type.isPointer) {
asmgen.loadIndirectWord(zpPtrVar, offset)
asmgen.assignRegister(RegisterOrPair.AY, target)
if(target.register in arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
asmgen.loadIndirectWordIntoRegisters(zpPtrVar, offset, target.register!!)
} else {
asmgen.loadIndirectWordAY(zpPtrVar, offset)
asmgen.assignRegister(RegisterOrPair.AY, target)
}
}
else if(value.type.isFloat) {
asmgen.loadIndirectFloat(zpPtrVar, offset)
@@ -1738,7 +1742,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
fun multiply() {
// on entry here: number placed in routine argument variable
asmgen.loadIndirectWord(zpPtrVar, 0u)
asmgen.loadIndirectWordAY(zpPtrVar, 0u)
asmgen.out("""
jsr prog8_math.multiply_words
tax
@@ -1807,7 +1811,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
val number = value.number!!.number.toInt()
if(number in powersOfTwoInt)
throw AssemblyError("divide by power of two should have been a shift $value.position")
asmgen.loadIndirectWord(zpPtrVar, 0u)
asmgen.loadIndirectWordAY(zpPtrVar, 0u)
asmgen.out("""
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
@@ -1818,7 +1822,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
SourceStorageKind.VARIABLE -> {
require(value.datatype.isWord)
val varname = value.asmVarname
asmgen.loadIndirectWord(zpPtrVar, 0u)
asmgen.loadIndirectWordAY(zpPtrVar, 0u)
asmgen.out("""
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
@@ -1830,7 +1834,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
val register = value.register!!
require(register.isWord())
val regname = asmgen.asmSymbolName(register)
asmgen.loadIndirectWord(zpPtrVar, 0u)
asmgen.loadIndirectWordAY(zpPtrVar, 0u)
asmgen.out("""
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
@@ -1839,7 +1843,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
divide(target.dt.isSigned)
}
SourceStorageKind.EXPRESSION -> {
asmgen.loadIndirectWord(zpPtrVar, 0u)
asmgen.loadIndirectWordAY(zpPtrVar, 0u)
asmgen.out(" sta P8ZP_SCRATCH_W1 | sty P8ZP_SCRATCH_W1+1")
asmgen.assignExpressionToRegister(value.expression!!, RegisterOrPair.AY)
divide(target.dt.isSigned)
@@ -1869,7 +1873,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
val number = value.number!!.number.toInt()
if(number in powersOfTwoInt)
throw AssemblyError("divide by power of two should have been a shift $value.position")
asmgen.loadIndirectWord(zpPtrVar, 0u)
asmgen.loadIndirectWordAY(zpPtrVar, 0u)
asmgen.out("""
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
@@ -1880,7 +1884,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
SourceStorageKind.VARIABLE -> {
require(value.datatype.isWord)
val varname = value.asmVarname
asmgen.loadIndirectWord(zpPtrVar, 0u)
asmgen.loadIndirectWordAY(zpPtrVar, 0u)
asmgen.out("""
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
@@ -1892,7 +1896,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
val register = value.register!!
require(register.isWord())
val regname = asmgen.asmSymbolName(register)
asmgen.loadIndirectWord(zpPtrVar, 0u)
asmgen.loadIndirectWordAY(zpPtrVar, 0u)
asmgen.out("""
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
@@ -1901,7 +1905,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
modulus()
}
SourceStorageKind.EXPRESSION -> {
asmgen.loadIndirectWord(zpPtrVar, 0u)
asmgen.loadIndirectWordAY(zpPtrVar, 0u)
asmgen.out(" sta P8ZP_SCRATCH_W1 | sty P8ZP_SCRATCH_W1+1")
asmgen.assignExpressionToRegister(value.expression!!, RegisterOrPair.AY)
modulus()