optimize pointer var access if var is already on zeropage

This commit is contained in:
Irmen de Jong 2021-01-16 18:09:47 +01:00
parent 1481f92cb0
commit 40cc216557
5 changed files with 61 additions and 19 deletions

View File

@ -527,7 +527,7 @@ internal class AsmGen(private val program: Program,
val vardecl = pointervar.targetVarDecl(program.namespace)!!
val scopedName = vardecl.makeScopedName(vardecl.name)
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) {
return if (scopedName in allocatedZeropageVariables) {
return if (isZpVar(scopedName)) {
// pointervar is already in the zero page, no need to copy
out(" lda ($sourceName)")
Pair(true, sourceName)
@ -541,7 +541,7 @@ internal class AsmGen(private val program: Program,
Pair(false, sourceName)
}
} else {
return if (scopedName in allocatedZeropageVariables) {
return if (isZpVar(scopedName)) {
// pointervar is already in the zero page, no need to copy
out(" ldy #0 | lda ($sourceName),y")
Pair(true, sourceName)
@ -563,7 +563,7 @@ internal class AsmGen(private val program: Program,
val vardecl = pointervar.targetVarDecl(program.namespace)!!
val scopedName = vardecl.makeScopedName(vardecl.name)
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) {
if (scopedName in allocatedZeropageVariables) {
if (isZpVar(scopedName)) {
// pointervar is already in the zero page, no need to copy
if (ldaInstructionArg != null)
out(" lda $ldaInstructionArg")
@ -578,7 +578,7 @@ internal class AsmGen(private val program: Program,
sta (P8ZP_SCRATCH_W2)""")
}
} else {
if (scopedName in allocatedZeropageVariables) {
if (isZpVar(scopedName)) {
// pointervar is already in the zero page, no need to copy
if (ldaInstructionArg != null)
out(" lda $ldaInstructionArg")
@ -1362,4 +1362,11 @@ $label nop""")
else -> throw AssemblyError("need byte type")
}
}
internal fun isZpVar(scopedName: String): Boolean = scopedName in allocatedZeropageVariables
internal fun isZpVar(variable: IdentifierReference): Boolean {
val vardecl = variable.targetVarDecl(program.namespace)!!
return vardecl.makeScopedName(vardecl.name) in allocatedZeropageVariables
}
}

View File

@ -1483,11 +1483,22 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
if(constOperand!=null) {
val intIndex = constOperand.number.toInt()
if(intIndex in 1..255) {
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")
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 {
asmgen.out(" ldy #${intIndex} | lda (P8ZP_SCRATCH_W2),y")
// 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
}

View File

@ -129,8 +129,15 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
if(constOperand!=null) {
val intIndex = constOperand.number.toInt()
if(intIndex in 1..255) {
assignExpressionToVariable(expr.left, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, assign.target.scope)
asmgen.out(" ldy #${intIndex} | lda (P8ZP_SCRATCH_W2),y")
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
}
@ -1978,8 +1985,15 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
if(constOperand!=null) {
val intIndex = constOperand.number.toInt()
if(intIndex in 1..255) {
assignExpressionToVariable(expr.left, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
asmgen.out(" lda $ldaInstructionArg | ldy #${intIndex} | sta (P8ZP_SCRATCH_W2),y")
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
}
}
@ -2026,10 +2040,21 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
if(constOperand!=null) {
val intIndex = constOperand.number.toInt()
if(intIndex in 1..255) {
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")
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
}
}

View File

@ -2,9 +2,9 @@
TODO
====
- optimize pointer access if it's via a var that's already in ZP. in AssignmentAsmGen 3 times,
and in translateDirectMemReadExpression. like loadByteFromPointerIntoA() is doing.
- why is fibonacci example (and others) generating larger code now? fix?
- 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)

View File

@ -24,7 +24,6 @@ main {
txt.nl()
cc=0
txt.chrout(@(ptr)+cc)
txt.chrout(@(ptr+1)+cc)
txt.chrout(@(ptr+2)+cc)