started pointer access optimization

This commit is contained in:
Irmen de Jong 2021-01-19 19:25:23 +01:00
parent c328e9018c
commit 4ed7fb771c
6 changed files with 225 additions and 258 deletions

View File

@ -558,44 +558,6 @@ internal class AsmGen(private val program: Program,
}
}
fun storeByteIntoPointer(pointervar: IdentifierReference, ldaInstructionArg: String?) {
val sourceName = asmVariableName(pointervar)
val vardecl = pointervar.targetVarDecl(program.namespace)!!
val scopedName = vardecl.makeScopedName(vardecl.name)
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) {
if (isZpVar(scopedName)) {
// pointervar is already in the zero page, no need to copy
if (ldaInstructionArg != null)
out(" lda $ldaInstructionArg")
out(" sta ($sourceName)")
} else {
out("""
ldy $sourceName
sty P8ZP_SCRATCH_W2
ldy $sourceName+1
sty P8ZP_SCRATCH_W2+1
${if (ldaInstructionArg == null) "" else "lda $ldaInstructionArg"}
sta (P8ZP_SCRATCH_W2)""")
}
} else {
if (isZpVar(scopedName)) {
// pointervar is already in the zero page, no need to copy
if (ldaInstructionArg != null)
out(" lda $ldaInstructionArg")
out(" ldy #0 | sta ($sourceName),y")
} else {
out("""
ldy $sourceName
sty P8ZP_SCRATCH_W2
ldy $sourceName+1
sty P8ZP_SCRATCH_W2+1
${if (ldaInstructionArg == null) "" else "lda $ldaInstructionArg"}
ldy #0
sta (P8ZP_SCRATCH_W2),y""")
}
}
}
private fun fixNameSymbols(name: String) = name.replace("<", "prog8_").replace(">", "") // take care of the autogenerated invalid (anon) label names
internal fun saveRegisterLocal(register: CpuRegister, scope: Subroutine) {
@ -1369,4 +1331,80 @@ $label nop""")
val vardecl = variable.targetVarDecl(program.namespace)!!
return vardecl.makeScopedName(vardecl.name) in allocatedZeropageVariables
}
internal fun pointerViaIndexRegisterPossible(pointerOffsetExpr: Expression): Pair<Expression, Expression>? {
if(pointerOffsetExpr is BinaryExpression && pointerOffsetExpr.operator=="+") {
val leftDt = pointerOffsetExpr.left.inferType(program)
val rightDt = pointerOffsetExpr.left.inferType(program)
if(leftDt.istype(DataType.UWORD) && rightDt.istype(DataType.UBYTE))
return Pair(pointerOffsetExpr.left, pointerOffsetExpr.right)
if(leftDt.istype(DataType.UBYTE) && rightDt.istype(DataType.UWORD))
return Pair(pointerOffsetExpr.right, pointerOffsetExpr.left)
if(leftDt.istype(DataType.UWORD) && rightDt.istype(DataType.UWORD)) {
// could be that the index was a constant numeric byte but converted to word, check that
val constIdx = pointerOffsetExpr.right.constValue(program)
if(constIdx!=null && constIdx.number.toInt()>=0 && constIdx.number.toInt()<=255) {
return Pair(pointerOffsetExpr.left, NumericLiteralValue(DataType.UBYTE, constIdx.number, constIdx.position))
}
// could be that the index was type casted into uword, check that
val rightTc = pointerOffsetExpr.right as? TypecastExpression
if(rightTc!=null && rightTc.expression.inferType(program).istype(DataType.UBYTE))
return Pair(pointerOffsetExpr.left, rightTc.expression)
val leftTc = pointerOffsetExpr.left as? TypecastExpression
if(leftTc!=null && leftTc.expression.inferType(program).istype(DataType.UBYTE))
return Pair(pointerOffsetExpr.right, leftTc.expression)
}
}
return null
}
internal fun tryOptimizedPointerAccessWithA(expr: BinaryExpression, write: Boolean): Boolean {
// optimize pointer,indexregister if possible
if(expr.operator=="+") {
val ptrAndIndex = pointerViaIndexRegisterPossible(expr)
if(ptrAndIndex!=null) {
val pointervar = ptrAndIndex.first as? IdentifierReference
if(write) {
when(ptrAndIndex.second) {
is NumericLiteralValue, is IdentifierReference -> {
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
if(pointervar!=null && isZpVar(pointervar)) {
out(" sta (${asmSymbolName(pointervar)}),y")
} else {
// copy the pointer var to zp first
assignExpressionToVariable(ptrAndIndex.first, asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
out(" sta (P8ZP_SCRATCH_W2),y")
}
}
else -> {
// same as above but we need to save the A register
out(" pha")
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
out(" pla")
if(pointervar!=null && isZpVar(pointervar)) {
out(" sta (${asmSymbolName(pointervar)}),y")
} else {
// copy the pointer var to zp first
assignExpressionToVariable(ptrAndIndex.first, asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
out(" sta (P8ZP_SCRATCH_W2),y")
}
}
}
} else {
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
if(pointervar!=null && isZpVar(pointervar)) {
out(" lda (${asmSymbolName(pointervar)}),y")
} else {
// copy the pointer var to zp first
assignExpressionToVariable(ptrAndIndex.first, asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
out(" lda (P8ZP_SCRATCH_W2),y")
}
}
return true
}
}
return false
}
}

View File

@ -197,8 +197,13 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
val number = (what.addressExpression as NumericLiteralValue).number
asmgen.out(" lda ${number.toHex()} | lsr a | bcc + | ora #\$80 |+ | sta ${number.toHex()}")
} else {
asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.ror2_mem_ub")
val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.addressExpression)
if(ptrAndIndex!=null) {
TODO("memread via pointer+indexregister ${ptrAndIndex.first},${ptrAndIndex.second}")
} else {
asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.ror2_mem_ub")
}
}
}
is IdentifierReference -> {
@ -240,11 +245,16 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
val number = (what.addressExpression as NumericLiteralValue).number
asmgen.out(" ror ${number.toHex()}")
} else {
asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY)
asmgen.out("""
sta (+) + 1
sty (+) + 2
+ ror ${'$'}ffff ; modified""")
val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.addressExpression)
if(ptrAndIndex!=null) {
TODO("memread via pointer+indexregister ${ptrAndIndex.first},${ptrAndIndex.second}")
} else {
asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY)
asmgen.out("""
sta (+) + 1
sty (+) + 2
+ ror ${'$'}ffff ; modified""")
}
}
}
is IdentifierReference -> {
@ -286,8 +296,13 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
val number = (what.addressExpression as NumericLiteralValue).number
asmgen.out(" lda ${number.toHex()} | cmp #\$80 | rol a | sta ${number.toHex()}")
} else {
asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.rol2_mem_ub")
val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.addressExpression)
if(ptrAndIndex!=null) {
TODO("memread via pointer+indexregister ${ptrAndIndex.first},${ptrAndIndex.second}")
} else {
asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.rol2_mem_ub")
}
}
}
is IdentifierReference -> {
@ -329,11 +344,16 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
val number = (what.addressExpression as NumericLiteralValue).number
asmgen.out(" rol ${number.toHex()}")
} else {
asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY)
asmgen.out("""
sta (+) + 1
sty (+) + 2
+ rol ${'$'}ffff ; modified""")
val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.addressExpression)
if(ptrAndIndex!=null) {
TODO("memread via pointer+indexregister ${ptrAndIndex.first},${ptrAndIndex.second}")
} else {
asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY)
asmgen.out("""
sta (+) + 1
sty (+) + 2
+ rol ${'$'}ffff ; modified""")
}
}
}
is IdentifierReference -> {
@ -564,6 +584,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
}
// all other types of swap() calls are done via a temporary variable
// TODO optimize swapping of pointer+indexregister
fun targetFromExpr(expr: Expression, datatype: DataType): AsmAssignTarget {
return when (expr) {

View File

@ -1462,51 +1462,19 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
asmgen.assignExpressionToVariable(expr.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) {
if (pushResultOnEstack) {
asmgen.out(" dex | lda (P8ZP_SCRATCH_W2) | sta P8ESTACK_LO+1,x")
asmgen.out(" lda (P8ZP_SCRATCH_W2) | dex | sta P8ESTACK_LO+1,x")
} else {
asmgen.out(" lda (P8ZP_SCRATCH_W2)")
}
} else {
if (pushResultOnEstack) {
asmgen.out(" dex | ldy #0 | lda (P8ZP_SCRATCH_W2),y | sta P8ESTACK_LO+1,x")
asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y | dex | sta P8ESTACK_LO+1,x")
} else {
asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y")
}
}
}
fun tryOptimizedPointerAccess(expr: BinaryExpression): Boolean {
// try to optimize simple cases like assignment from ptr+1, ptr+2...
if(expr.operator=="+") {
// we can assume const operand has been moved to the right.
val constOperand = expr.right.constValue(program)
if(constOperand!=null) {
val intIndex = constOperand.number.toInt()
if(intIndex in 1..255) {
val idref = expr.left as? IdentifierReference
if(idref!=null && asmgen.isZpVar(idref)) {
// pointer var is already in zp, we can indirect index immediately
if (pushResultOnEstack) {
asmgen.out(" dex | ldy #${intIndex} | lda (${asmgen.asmSymbolName(idref)}),y | sta P8ESTACK_LO+1,x")
} else {
asmgen.out(" ldy #${intIndex} | lda (${asmgen.asmSymbolName(idref)}),y")
}
} else {
// copy the pointer var to zp first
asmgen.assignExpressionToVariable(expr.left, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
if (pushResultOnEstack) {
asmgen.out(" dex | ldy #${intIndex} | lda (P8ZP_SCRATCH_W2),y | sta P8ESTACK_LO+1,x")
} else {
asmgen.out(" ldy #${intIndex} | lda (P8ZP_SCRATCH_W2),y")
}
}
return true
}
}
}
return false
}
when(expr.addressExpression) {
is NumericLiteralValue -> {
val address = (expr.addressExpression as NumericLiteralValue).number.toInt()
@ -1521,8 +1489,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
asmgen.out(" sta P8ESTACK_LO,x | dex")
}
is BinaryExpression -> {
if(!tryOptimizedPointerAccess(expr.addressExpression as BinaryExpression))
if(asmgen.tryOptimizedPointerAccessWithA(expr.addressExpression as BinaryExpression, false)) {
if(pushResultOnEstack)
asmgen.out(" sta P8ESTACK_LO,x | dex")
} else {
assignViaExprEval()
}
}
else -> assignViaExprEval()
}

View File

@ -121,31 +121,6 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
assignRegisterByte(assign.target, CpuRegister.A)
}
fun tryOptimizedPointerAccess(expr: BinaryExpression): Boolean {
// try to optimize simple cases like assignment from ptr+1, ptr+2...
if(expr.operator=="+") {
// we can assume const operand has been moved to the right.
val constOperand = expr.right.constValue(program)
if(constOperand!=null) {
val intIndex = constOperand.number.toInt()
if(intIndex in 1..255) {
val idref = expr.left as? IdentifierReference
if(idref!=null && asmgen.isZpVar(idref)) {
// pointer var is already in zp, we can indirect index immediately
asmgen.out(" ldy #${intIndex} | lda (${asmgen.asmSymbolName(idref)}),y")
} else {
// copy the pointer var to zp first
assignExpressionToVariable(expr.left, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, assign.target.scope)
asmgen.out(" ldy #${intIndex} | lda (P8ZP_SCRATCH_W2),y")
}
assignRegisterByte(assign.target, CpuRegister.A)
return true
}
}
}
return false
}
val value = assign.source.memory!!
when (value.addressExpression) {
is NumericLiteralValue -> {
@ -156,8 +131,11 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
assignMemoryByte(assign.target, null, value.addressExpression as IdentifierReference)
}
is BinaryExpression -> {
if(!tryOptimizedPointerAccess(value.addressExpression as BinaryExpression))
if(asmgen.tryOptimizedPointerAccessWithA(value.addressExpression as BinaryExpression, false)) {
assignRegisterByte(assign.target, CpuRegister.A)
} else {
assignViaExprEval(value.addressExpression)
}
}
else -> assignViaExprEval(value.addressExpression)
}
@ -331,14 +309,19 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
is DirectMemoryRead -> {
if(targetDt in WordDatatypes) {
if (value.addressExpression is NumericLiteralValue) {
val address = (value.addressExpression as NumericLiteralValue).number.toInt()
assignMemoryByteIntoWord(target, address, null)
return
}
else if (value.addressExpression is IdentifierReference) {
assignMemoryByteIntoWord(target, null, value.addressExpression as IdentifierReference)
return
when (value.addressExpression) {
is NumericLiteralValue -> {
val address = (value.addressExpression as NumericLiteralValue).number.toInt()
assignMemoryByteIntoWord(target, address, null)
return
}
is IdentifierReference -> {
assignMemoryByteIntoWord(target, null, value.addressExpression as IdentifierReference)
return
}
else -> {
TODO("memread from expression ${value.addressExpression}")
}
}
}
}
@ -749,8 +732,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
}
TargetStorageKind.MEMORY -> {
asmgen.out(" inx")
storeByteViaRegisterAInMemoryAddress("P8ESTACK_LO,x", target.memory!!)
asmgen.out(" inx | lda P8ESTACK_LO,x")
storeRegisterAInMemoryAddress(target.memory!!)
}
TargetStorageKind.ARRAY -> {
if(target.constArrayIndexValue!=null) {
@ -1178,7 +1161,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
""")
}
TargetStorageKind.MEMORY -> {
storeByteViaRegisterAInMemoryAddress(sourceName, target.memory!!)
asmgen.out(" lda $sourceName")
storeRegisterAInMemoryAddress(target.memory!!)
}
TargetStorageKind.ARRAY -> {
if (target.constArrayIndexValue!=null) {
@ -1338,7 +1322,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
asmgen.out(" st${register.name.toLowerCase()} ${target.asmVarname}")
}
TargetStorageKind.MEMORY -> {
storeRegisterInMemoryAddress(register, target.memory!!)
TODO("assignRegisterByte via storeByteViaRegisterAInMemoryAddress()")
}
TargetStorageKind.ARRAY -> {
if (target.constArrayIndexValue!=null) {
@ -1608,7 +1592,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
asmgen.out(" stz ${target.asmVarname} ")
}
TargetStorageKind.MEMORY -> {
storeByteViaRegisterAInMemoryAddress("#${byte.toHex()}", target.memory!!)
asmgen.out(" lda #${byte.toHex()}")
storeRegisterAInMemoryAddress(target.memory!!)
}
TargetStorageKind.ARRAY -> {
if (target.constArrayIndexValue!=null) {
@ -1647,7 +1632,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
asmgen.out(" lda #${byte.toHex()} | sta ${target.asmVarname} ")
}
TargetStorageKind.MEMORY -> {
storeByteViaRegisterAInMemoryAddress("#${byte.toHex()}", target.memory!!)
asmgen.out(" lda #${byte.toHex()}")
storeRegisterAInMemoryAddress(target.memory!!)
}
TargetStorageKind.ARRAY -> {
if (target.constArrayIndexValue!=null) {
@ -1831,7 +1817,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
""")
}
TargetStorageKind.MEMORY -> {
storeByteViaRegisterAInMemoryAddress(address.toHex(), target.memory!!)
asmgen.out(" lda ${address.toHex()}")
storeRegisterAInMemoryAddress(target.memory!!)
}
TargetStorageKind.ARRAY -> {
throw AssemblyError("no asm gen for assign memory byte at $address to array ${target.asmVarname}")
@ -1869,7 +1856,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
TargetStorageKind.MEMORY -> {
val sourceName = asmgen.asmVariableName(identifier)
storeByteViaRegisterAInMemoryAddress(sourceName, target.memory!!)
asmgen.out(" lda $sourceName")
storeRegisterAInMemoryAddress(target.memory!!)
}
TargetStorageKind.ARRAY -> {
throw AssemblyError("no asm gen for assign memory byte $identifier to array ${target.asmVarname} ")
@ -1965,117 +1953,73 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
}
private fun storeByteViaRegisterAInMemoryAddress(ldaInstructionArg: String, memoryAddress: DirectMemoryWrite) {
private fun storeRegisterAInMemoryAddress(memoryAddress: DirectMemoryWrite) {
val addressExpr = memoryAddress.addressExpression
val addressLv = addressExpr as? NumericLiteralValue
fun storeViaExprEval() {
assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02)
asmgen.out(" lda $ldaInstructionArg | sta (P8ZP_SCRATCH_W2)")
else
asmgen.out(" lda $ldaInstructionArg | ldy #0 | sta (P8ZP_SCRATCH_W2),y")
}
fun tryOptimizedPointerAccess(expr: BinaryExpression): Boolean {
// try to optimize simple cases like storing value to ptr+1, ptr+2...
if(expr.operator=="+") {
// we can assume const operand has been moved to the right.
val constOperand = expr.right.constValue(program)
if(constOperand!=null) {
val intIndex = constOperand.number.toInt()
if(intIndex in 1..255) {
val idref = expr.left as? IdentifierReference
if(idref!=null && asmgen.isZpVar(idref)) {
// pointer var is already in zp, we can indirect index immediately
asmgen.out(" lda $ldaInstructionArg | ldy #${intIndex} | sta (${asmgen.asmSymbolName(idref)}),y")
} else {
// copy the pointer var to zp first
assignExpressionToVariable(expr.left, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
asmgen.out(" lda $ldaInstructionArg | ldy #${intIndex} | sta (P8ZP_SCRATCH_W2),y")
}
return true
}
when(addressExpr) {
is NumericLiteralValue, is IdentifierReference -> {
assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02)
asmgen.out(" sta (P8ZP_SCRATCH_W2)")
else
asmgen.out(" ldy #0 | sta (P8ZP_SCRATCH_W2),y")
}
else -> {
// same as above but we need to save the A register
asmgen.out(" pha")
assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
asmgen.out(" pla")
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02)
asmgen.out(" sta (P8ZP_SCRATCH_W2)")
else
asmgen.out(" ldy #0 | sta (P8ZP_SCRATCH_W2),y")
}
}
}
fun storeAIntoPointerVar(pointervar: IdentifierReference) {
val sourceName = asmgen.asmVariableName(pointervar)
val vardecl = pointervar.targetVarDecl(program.namespace)!!
val scopedName = vardecl.makeScopedName(vardecl.name)
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) {
if (asmgen.isZpVar(scopedName)) {
// pointervar is already in the zero page, no need to copy
asmgen.out(" sta ($sourceName)")
} else {
asmgen.out("""
ldy $sourceName
sty P8ZP_SCRATCH_W2
ldy $sourceName+1
sty P8ZP_SCRATCH_W2+1
sta (P8ZP_SCRATCH_W2)""")
}
} else {
if (asmgen.isZpVar(scopedName)) {
// pointervar is already in the zero page, no need to copy
asmgen.out(" ldy #0 | sta ($sourceName),y")
} else {
asmgen.out("""
ldy $sourceName
sty P8ZP_SCRATCH_W2
ldy $sourceName+1
sty P8ZP_SCRATCH_W2+1
ldy #0
sta (P8ZP_SCRATCH_W2),y""")
}
}
return false
}
when {
addressLv != null -> {
asmgen.out(" lda $ldaInstructionArg | sta ${addressLv.number.toHex()}")
asmgen.out(" sta ${addressLv.number.toHex()}")
}
addressExpr is IdentifierReference -> {
asmgen.storeByteIntoPointer(addressExpr, ldaInstructionArg)
storeAIntoPointerVar(addressExpr)
}
addressExpr is BinaryExpression -> {
if(!tryOptimizedPointerAccess(addressExpr))
storeViaExprEval()
}
else -> storeViaExprEval()
}
}
private fun storeRegisterInMemoryAddress(register: CpuRegister, memoryAddress: DirectMemoryWrite) {
// this is optimized for register A.
val addressExpr = memoryAddress.addressExpression
val addressLv = addressExpr as? NumericLiteralValue
val registerName = register.name.toLowerCase()
fun storeViaExprEval() {
asmgen.saveRegisterStack(register, false)
assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
asmgen.restoreRegisterStack(CpuRegister.A, false)
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02)
asmgen.out(" sta (P8ZP_SCRATCH_W2)")
else
asmgen.out(" ldy #0 | sta (P8ZP_SCRATCH_W2),y")
}
fun tryOptimizedPointerAccess(expr: BinaryExpression): Boolean {
// try to optimize simple cases like storing value to ptr+1, ptr+2...
if(expr.operator=="+") {
// we can assume const operand has been moved to the right.
val constOperand = expr.right.constValue(program)
if(constOperand!=null) {
val intIndex = constOperand.number.toInt()
if(intIndex in 1..255) {
val idref = expr.left as? IdentifierReference
if(idref!=null && asmgen.isZpVar(idref)) {
// pointer var is already in zp, we can indirect index immediately
when(register) {
CpuRegister.A -> asmgen.out(" ldy #${intIndex} | sta (${asmgen.asmSymbolName(idref)}),y")
CpuRegister.X -> asmgen.out(" txa | ldy #${intIndex} | sta (${asmgen.asmSymbolName(idref)}),y")
CpuRegister.Y -> asmgen.out(" tya | ldy #${intIndex} | sta (${asmgen.asmSymbolName(idref)}),y")
}
} else {
// copy the pointer var to zp first
asmgen.saveRegisterStack(register, false)
assignExpressionToVariable(expr.left, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
asmgen.restoreRegisterStack(CpuRegister.A, false)
asmgen.out(" ldy #${intIndex} | sta (P8ZP_SCRATCH_W2),y")
}
return true
}
}
}
return false
}
when {
addressLv != null -> {
asmgen.out(" st$registerName ${addressLv.number.toHex()}")
}
addressExpr is IdentifierReference -> {
when (register) {
CpuRegister.A -> {}
CpuRegister.X -> asmgen.out(" txa")
CpuRegister.Y -> asmgen.out(" tya")
}
asmgen.storeByteIntoPointer(addressExpr, null)
}
addressExpr is BinaryExpression -> {
if(!tryOptimizedPointerAccess(addressExpr))
if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, true))
storeViaExprEval()
}
else -> storeViaExprEval()

View File

@ -2,15 +2,18 @@
TODO
====
- why is fibonacci example (and others) generating larger code now? fix?
- optimize pointer access @(ptr+ix) if ix<=255 (i.e. if it is of ubyte type) to use indexing register
- add any2(), all2(), max2(), min2(), reverse2(), sum2(), sort2() that take (array, startindex, length) arguments
- allow uwordpointer[index] syntax -> transform into @(uwordpointer+index) allow index to be >255!
- optimize for loop iterations better to allow proper inx, cpx #value, bne loop instructions
- can we get rid of the --longOptionName command line options and only keep the short versions? https://github.com/Kotlin/kotlinx-cli/issues/50
- add a f_seek() routine for the Cx16 that uses its seek dos api?
- add a compiler option to generate a symbol listing at the end
- optimizer: detect variables that are written but never read - mark those as unused too and remove them, such as uword unused = memory("unused222", 20) - also remove the memory slab allocation
- hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine)
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_'
- option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging)
- c64: use VIC banking to move up the graphics bitmap memory location. Move it to $e000 under the kernal rom?
- c64: make the graphics.BITMAP_ADDRESS configurable
- some support for recursive subroutines?
- via %option recursive?: allocate all params and local vars on estack, don't allow nested subroutines, can begin by first not allowing any local variables just fixing the parameters
- Or via a special recursive call operation that copies the current values of all local vars (including arguments) to the stack, replaces the arguments, jsr subroutine, and after returning copy the stack back to the local variables

View File

@ -7,40 +7,29 @@ main {
sub start() {
str name = "abcdef"
uword screen=$0400
ubyte[256] xbuf = 1
ubyte[256] ybuf = 3
uword ptr = &name
ubyte ix = 0
ubyte cc
cc = @(ptr)
txt.chrout(cc)
txt.nl()
cc = @(ptr+1)
txt.chrout(cc)
txt.nl()
cc = @(ptr+2)
txt.chrout(cc)
txt.nl()
txt.nl()
; cc = @(screen+2)
; cc++
; @(screen+2) = cc
cc=0
txt.chrout(@(ptr)+cc)
txt.chrout(@(ptr+1)+cc)
txt.chrout(@(ptr+2)+cc)
txt.nl()
@(screen + ix + cc*$0008) = cc
@(ptr) = '1'
@(ptr+1) = '2'
@(ptr+2) = '3'
txt.print(name)
txt.nl()
cc=0
@(ptr+cc) = 'a'
@(ptr+cc+1) = 'b'
@(ptr+cc+2) = 'c'
txt.print(name)
txt.nl()
; cc = @(screen+ix)
; cc++
; @(screen+ix) = cc
; for ii in 24 downto 0 {
; for i in 39 downto 0 {
; @(screen+i) = xbuf[i] + ybuf[ii]
; }
; screen+=40
; }
}
}