optimize memory read expression of ptr + constant index

This commit is contained in:
Irmen de Jong 2021-01-15 21:33:57 +01:00
parent 76d54fbe5c
commit 1481f92cb0
4 changed files with 109 additions and 76 deletions

View File

@ -1457,20 +1457,8 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
internal fun translateDirectMemReadExpression(expr: DirectMemoryRead, pushResultOnEstack: Boolean) {
when(expr.addressExpression) {
is NumericLiteralValue -> {
val address = (expr.addressExpression as NumericLiteralValue).number.toInt()
asmgen.out(" lda ${address.toHex()}")
if(pushResultOnEstack)
asmgen.out(" sta P8ESTACK_LO,x | dex")
}
is IdentifierReference -> {
// the identifier is a pointer variable, so read the value from the address in it
asmgen.loadByteFromPointerIntoA(expr.addressExpression as IdentifierReference)
if(pushResultOnEstack)
asmgen.out(" sta P8ESTACK_LO,x | dex")
}
else -> {
fun assignViaExprEval() {
asmgen.assignExpressionToVariable(expr.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) {
if (pushResultOnEstack) {
@ -1486,6 +1474,46 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
}
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) {
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()
asmgen.out(" lda ${address.toHex()}")
if(pushResultOnEstack)
asmgen.out(" sta P8ESTACK_LO,x | dex")
}
is IdentifierReference -> {
// the identifier is a pointer variable, so read the value from the address in it
asmgen.loadByteFromPointerIntoA(expr.addressExpression as IdentifierReference)
if(pushResultOnEstack)
asmgen.out(" sta P8ESTACK_LO,x | dex")
}
is BinaryExpression -> {
if(!tryOptimizedPointerAccess(expr.addressExpression as BinaryExpression))
assignViaExprEval()
}
else -> assignViaExprEval()
}
}

View File

@ -121,6 +121,24 @@ 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) {
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 -> {
@ -131,25 +149,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
assignMemoryByte(assign.target, null, value.addressExpression as IdentifierReference)
}
is BinaryExpression -> {
// try to optimize simple cases like assignment from ptr+1, ptr+2...
var optimized = false
val expr = value.addressExpression as BinaryExpression
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) {
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)
optimized = true
}
}
}
if(!optimized)
assignViaExprEval(expr)
if(!tryOptimizedPointerAccess(value.addressExpression as BinaryExpression))
assignViaExprEval(value.addressExpression)
}
else -> assignViaExprEval(value.addressExpression)
}
@ -1961,8 +1962,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
val addressExpr = memoryAddress.addressExpression
val addressLv = addressExpr as? NumericLiteralValue
fun storeViaExprEval()
{
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)")
@ -1970,6 +1970,23 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
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) {
assignExpressionToVariable(expr.left, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
asmgen.out(" lda $ldaInstructionArg | ldy #${intIndex} | sta (P8ZP_SCRATCH_W2),y")
return true
}
}
}
return false
}
when {
addressLv != null -> {
asmgen.out(" lda $ldaInstructionArg | sta ${addressLv.number.toHex()}")
@ -1978,22 +1995,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
asmgen.storeByteIntoPointer(addressExpr, ldaInstructionArg)
}
addressExpr is BinaryExpression -> {
// try to optimize simple cases like storing value to ptr+1, ptr+2...
var optimized = false
if(addressExpr.operator=="+") {
// we can assume const operand has been moved to the right.
val constOperand = addressExpr.right.constValue(program)
if(constOperand!=null) {
val intIndex = constOperand.number.toInt()
if(intIndex in 1..255) {
assignExpressionToVariable(addressExpr.left, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
asmgen.out(" lda $ldaInstructionArg | ldy #${intIndex} | sta (P8ZP_SCRATCH_W2),y")
optimized = true
}
}
}
if(!optimized)
if(!tryOptimizedPointerAccess(addressExpr))
storeViaExprEval()
}
else -> storeViaExprEval()
@ -2006,8 +2008,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
val addressLv = addressExpr as? NumericLiteralValue
val registerName = register.name.toLowerCase()
fun storeViaExprEval()
{
fun storeViaExprEval() {
asmgen.saveRegisterStack(register, false)
assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
asmgen.restoreRegisterStack(CpuRegister.A, false)
@ -2017,6 +2018,25 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
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) {
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()}")
@ -2030,24 +2050,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
asmgen.storeByteIntoPointer(addressExpr, null)
}
addressExpr is BinaryExpression -> {
// try to optimize simple cases like storing value to ptr+1, ptr+2...
var optimized = false
if(addressExpr.operator=="+") {
// we can assume const operand has been moved to the right.
val constOperand = addressExpr.right.constValue(program)
if(constOperand!=null) {
val intIndex = constOperand.number.toInt()
if(intIndex in 1..255) {
asmgen.saveRegisterStack(register, false)
assignExpressionToVariable(addressExpr.left, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
asmgen.restoreRegisterStack(CpuRegister.A, false)
asmgen.out(" ldy #${intIndex} | sta (P8ZP_SCRATCH_W2),y")
optimized = true
}
}
}
if(!optimized)
if(!tryOptimizedPointerAccess(addressExpr))
storeViaExprEval()
}
else -> storeViaExprEval()

View File

@ -2,7 +2,8 @@
TODO
====
- optimize pointer access code @(pointer)? use a subroutine? macro? 65c02 vs 6502?
- 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.
- 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 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

View File

@ -23,10 +23,11 @@ main {
txt.nl()
txt.nl()
cc=0
txt.chrout(@(ptr))
txt.chrout(@(ptr+1))
txt.chrout(@(ptr+2))
txt.chrout(@(ptr)+cc)
txt.chrout(@(ptr+1)+cc)
txt.chrout(@(ptr+2)+cc)
txt.nl()
@(ptr) = '1'