tweak pointer access, fix and optimize reading memory from a label as pointer

This commit is contained in:
Irmen de Jong
2025-01-05 03:53:28 +01:00
parent 478e2b4ebd
commit 0ffebc25d0
7 changed files with 246 additions and 118 deletions

View File

@@ -1164,12 +1164,13 @@ $repeatLabel""")
}
}
internal fun pointerViaIndexRegisterPossible(pointerOffsetExpr: PtExpression): Pair<PtExpression, PtExpression>? {
internal fun pointerViaIndexRegisterPossible(pointerOffsetExpr: PtExpression, allowNegativeIndex: Boolean=false): Pair<PtExpression, PtExpression>? {
if (pointerOffsetExpr !is PtBinaryExpression) return null
val operator = pointerOffsetExpr.operator
val left = pointerOffsetExpr.left
val right = pointerOffsetExpr.right
if (operator != "+") return null
if (operator != "+" && (operator != "-" || !allowNegativeIndex))
return null
val leftDt = left.type
val rightDt = right.type
if(leftDt.isUnsignedWord && rightDt.isUnsignedByte)
@@ -1212,70 +1213,166 @@ $repeatLabel""")
}
if(addressExpr.operator=="+") {
val ptrAndIndex = pointerViaIndexRegisterPossible(addressExpr)
if(ptrAndIndex!=null) {
val ptrAndIndex = pointerViaIndexRegisterPossible(addressExpr, false)
if (ptrAndIndex == null) return false
if(write) {
// WRITING TO pointer + offset
val addrOf = ptrAndIndex.first as? PtAddressOf
val constOffset = (ptrAndIndex.second as? PtNumber)?.number?.toInt()
if(addrOf!=null && constOffset!=null) {
if(addrOf.isFromArrayElement) {
TODO("address-of array element $addrOf")
} else {
out(" sta ${asmSymbolName(addrOf.identifier)}+${constOffset}")
return true
}
}
val pointervar = ptrAndIndex.first as? PtIdentifier
val target = if(pointervar==null) null else symbolTable.lookup(pointervar.name)!!.astNode
when(target) {
is PtLabel -> {
if(pointervar!=null && isZpVar(pointervar)) {
val saveA = evalBytevalueWillClobberA(ptrAndIndex.second)
if(saveA) out(" pha")
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
if(saveA) out(" pla")
out(" sta (${asmSymbolName(pointervar)}),y")
} else {
// copy the pointer var to zp first
val saveA = evalBytevalueWillClobberA(ptrAndIndex.first) || evalBytevalueWillClobberA(ptrAndIndex.second)
if(saveA) out(" pha")
if(ptrAndIndex.second.isSimple()) {
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD))
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
out(" lda ${asmSymbolName(pointervar!!)},y")
return true
if(saveA) out(" pla")
out(" sta (P8ZP_SCRATCH_W2),y")
} else {
pushCpuStack(BaseDataType.UBYTE, ptrAndIndex.second)
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD))
restoreRegisterStack(CpuRegister.Y, true)
if(saveA) out(" pla")
out(" sta (P8ZP_SCRATCH_W2),y")
}
is IPtVariable, null -> {
if(write) {
if(pointervar!=null && isZpVar(pointervar)) {
val saveA = evalBytevalueWillClobberA(ptrAndIndex.second)
if(saveA)
out(" pha")
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
if(saveA)
out(" pla")
out(" sta (${asmSymbolName(pointervar)}),y")
} else {
// copy the pointer var to zp first
val saveA = evalBytevalueWillClobberA(ptrAndIndex.first) || evalBytevalueWillClobberA(ptrAndIndex.second)
if(saveA)
out(" pha")
if(ptrAndIndex.second.isSimple()) {
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD))
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
if(saveA)
out(" pla")
out(" sta (P8ZP_SCRATCH_W2),y")
} else {
pushCpuStack(BaseDataType.UBYTE, ptrAndIndex.second)
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD))
restoreRegisterStack(CpuRegister.Y, true)
if(saveA)
out(" pla")
out(" sta (P8ZP_SCRATCH_W2),y")
}
}
}
return true
}
// READING FROM pointer + offset
val addrOf = ptrAndIndex.first as? PtAddressOf
val constOffset = (ptrAndIndex.second as? PtNumber)?.number?.toInt()
if(addrOf!=null && constOffset!=null) {
if(addrOf.isFromArrayElement) {
TODO("address-of array element $addrOf")
} else {
out(" lda ${asmSymbolName(addrOf.identifier)}+${constOffset}")
return true
}
}
val pointervar = ptrAndIndex.first as? PtIdentifier
val targetVariable = if(pointervar==null) null else symbolTable.lookup(pointervar.name)!!.astNode
when(targetVariable) {
is PtLabel -> {
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
out(" lda ${asmSymbolName(pointervar!!)},y")
return true
}
is IPtVariable, null -> {
if(pointervar!=null && isZpVar(pointervar)) {
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
out(" lda (${asmSymbolName(pointervar)}),y")
} else {
// copy the pointer var to zp first
if(ptrAndIndex.second.isSimple()) {
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD))
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
out(" lda (P8ZP_SCRATCH_W2),y")
} else {
if(pointervar!=null && isZpVar(pointervar)) {
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
out(" lda (${asmSymbolName(pointervar)}),y")
} else {
// copy the pointer var to zp first
if(ptrAndIndex.second.isSimple()) {
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD))
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
out(" lda (P8ZP_SCRATCH_W2),y")
} else {
pushCpuStack(BaseDataType.UBYTE, ptrAndIndex.second)
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD))
restoreRegisterStack(CpuRegister.Y, false)
out(" lda (P8ZP_SCRATCH_W2),y")
}
}
pushCpuStack(BaseDataType.UBYTE, ptrAndIndex.second)
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD))
restoreRegisterStack(CpuRegister.Y, false)
out(" lda (P8ZP_SCRATCH_W2),y")
}
}
return true
}
else -> throw AssemblyError("invalid pointervar $pointervar")
}
}
else if(addressExpr.operator=="-") {
val ptrAndIndex = pointerViaIndexRegisterPossible(addressExpr, true)
if (ptrAndIndex == null) return false
if(write) {
// WRITING TO pointer - offset
val addrOf = ptrAndIndex.first as? PtAddressOf
val constOffset = (ptrAndIndex.second as? PtNumber)?.number?.toInt()
if(addrOf!=null && constOffset!=null) {
if(addrOf.isFromArrayElement) {
TODO("address-of array element $addrOf")
} else {
out(" sta ${asmSymbolName(addrOf.identifier)}-${constOffset}")
return true
}
else -> throw AssemblyError("invalid pointervar $pointervar")
}
if(constOffset!=null) {
println("MEMWRITE POINTER - $constOffset ${addressExpr.position}") // TODO
/*
val pointervar = ptrAndIndex.first as? PtIdentifier
if(pointervar!=null && isZpVar(pointervar)) {
val saveA = evalBytevalueWillClobberA(ptrAndIndex.second)
if(saveA) out(" pha")
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
if(saveA) out(" pla")
out(" sta (${asmSymbolName(pointervar)}),y")
} else {
// copy the pointer var to zp first
val saveA = evalBytevalueWillClobberA(ptrAndIndex.first) || evalBytevalueWillClobberA(ptrAndIndex.second)
if(saveA) out(" pha")
if(ptrAndIndex.second.isSimple()) {
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD))
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
if(saveA) out(" pla")
out(" sta (P8ZP_SCRATCH_W2),y")
} else {
pushCpuStack(BaseDataType.UBYTE, ptrAndIndex.second)
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD))
restoreRegisterStack(CpuRegister.Y, true)
if(saveA) out(" pla")
out(" sta (P8ZP_SCRATCH_W2),y")
}
}
return true
*/
}
} else {
// READING FROM pointer - offset
val addrOf = ptrAndIndex.first as? PtAddressOf
val constOffset = (ptrAndIndex.second as? PtNumber)?.number?.toInt()
if(addrOf!=null && constOffset!=null) {
if(addrOf.isFromArrayElement) {
TODO("address-of array element $addrOf")
} else {
out(" lda ${asmSymbolName(addrOf.identifier)}-${constOffset}")
return true
}
}
if(constOffset!=null) {
println("MEMREAD POINTER - $constOffset ${addressExpr.position}") // TODO
// TODO optimize more cases
}
}
}
return false
}

View File

@@ -306,38 +306,29 @@ internal class AssignmentAsmGen(
}
}
}
SourceStorageKind.MEMORY -> {
val value = assign.source.memory!!
when (value.address) {
is PtNumber -> {
val address = (value.address as PtNumber).number.toUInt()
assignMemoryByte(assign.target, address, null)
}
is PtIdentifier -> {
assignMemoryByte(assign.target, null, value.address as PtIdentifier)
}
is PtBinaryExpression -> {
val addrExpr = value.address as PtBinaryExpression
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, false)) {
assignRegisterByte(assign.target, CpuRegister.A, false, true)
} else {
assignByteFromAddressExpression(value.address, assign.target)
}
}
else -> assignByteFromAddressExpression(value.address, assign.target)
}
}
SourceStorageKind.EXPRESSION -> {
assignExpression(assign, scope)
}
SourceStorageKind.REGISTER -> {
asmgen.assignRegister(assign.source.register!!, assign.target)
}
SourceStorageKind.MEMORY -> assignByteFromAddressExpression(assign.source.memory!!.address, assign.target)
SourceStorageKind.EXPRESSION -> assignExpression(assign, scope)
SourceStorageKind.REGISTER -> asmgen.assignRegister(assign.source.register!!, assign.target)
}
}
private fun assignByteFromAddressExpression(address: PtExpression, target: AsmAssignTarget) {
if(address is PtBinaryExpression) {
if (address is PtNumber) {
val address = address.number.toUInt()
assignMemoryByte(target, address, null)
return
}
else if (address is PtIdentifier) {
assignMemoryByte(target, null, address)
return
}
else if (address is PtBinaryExpression) {
if(asmgen.tryOptimizedPointerAccessWithA(address, false)) {
assignRegisterByte(target, CpuRegister.A, false, true)
return
}
if(address.operator=="+" && address.right.type.isUnsignedWord) {
if (address.left is PtIdentifier) {
// use (zp),Y instead of explicitly calculating the full zp pointer value
@@ -376,9 +367,11 @@ internal class AssignmentAsmGen(
}
}
// else if(address.operator=="-") {
// // does this ever occur? we could optimize it too, but it seems like a pathological case
// // TODO does this ever occur? we could optimize it too, but it seems like a pathological case
// }
}
// fallback assignmen through temporary pointer var
assignExpressionToVariable(address, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD))
asmgen.loadAFromZpPointerVar("P8ZP_SCRATCH_W2", false)
assignRegisterByte(target, CpuRegister.A, false, true)
@@ -4010,18 +4003,6 @@ $endLabel""")
asmgen.storeAIntoPointerVar(addressExpr)
}
addressExpr is PtBinaryExpression -> {
if(addressExpr.operator=="+" || addressExpr.operator=="-") {
val addrOf = addressExpr.left as? PtAddressOf
val offset = (addressExpr.right as? PtNumber)?.number?.toInt()
if(addrOf!=null && offset!=null) {
if(addrOf.isFromArrayElement) {
TODO("address-of array element $addrOf")
} else {
asmgen.out(" sta ${asmgen.asmSymbolName(addrOf.identifier)}${addressExpr.operator}${offset}")
return
}
}
}
if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, true))
storeViaExprEval()
}

View File

@@ -169,10 +169,14 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
else -> {
if(memory.address is PtBinaryExpression && tryOptimizedMemoryInplace(memory.address as PtBinaryExpression, operator, value))
return
// slower method to calculate and use the pointer to access the memory with:
asmgen.assignExpressionToRegister(memory.address, RegisterOrPair.AY, false)
asmgen.saveRegisterStack(CpuRegister.A, true)
asmgen.saveRegisterStack(CpuRegister.Y, true)
asmgen.out(" jsr prog8_lib.read_byte_from_address_in_AY_into_A")
if(asmgen.isTargetCpu(CpuType.CPU65c02))
asmgen.out(" jsr prog8_lib.read_byte_from_address_in_AY_into_A_65c02")
else
asmgen.out(" jsr prog8_lib.read_byte_from_address_in_AY_into_A")
when(value.kind) {
SourceStorageKind.LITERALBOOLEAN -> {
inplacemodificationRegisterAwithVariable(operator, "#${value.boolean!!.asInt()}", false)
@@ -212,7 +216,10 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
}
asmgen.restoreRegisterStack(CpuRegister.Y, false)
asmgen.restoreRegisterStack(CpuRegister.A, false)
asmgen.out(" jsr prog8_lib.write_byte_X_to_address_in_AY")
if(asmgen.isTargetCpu(CpuType.CPU65c02))
asmgen.out(" jsr prog8_lib.write_byte_X_to_address_in_AY_65c02")
else
asmgen.out(" jsr prog8_lib.write_byte_X_to_address_in_AY")
}
}
}