also consider Y register for clobber check for functioncall arguments

This commit is contained in:
Irmen de Jong 2021-11-29 22:09:05 +01:00
parent b438d8aec0
commit a2db44f80c
10 changed files with 54 additions and 36 deletions

View File

@ -1,11 +1,9 @@
package prog8.compiler.target
import com.github.michaelbull.result.fold
import prog8.ast.base.ByteDatatypes
import prog8.ast.base.DataType
import prog8.ast.base.PassByReferenceDatatypes
import prog8.ast.base.WordDatatypes
import prog8.ast.base.*
import prog8.ast.expressions.Expression
import prog8.ast.statements.RegisterOrStatusflag
import prog8.ast.statements.Subroutine
import prog8.compiler.target.c64.C64MachineDefinition
import prog8.compiler.target.cbm.Petscii
@ -26,8 +24,10 @@ object C64Target: ICompilationTarget {
override fun decodeString(bytes: List<UByte>, altEncoding: Boolean) =
if (altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
override fun asmsubArgsEvalOrder(sub: Subroutine): List<Int> = asmsub6502ArgsEvalOrder(sub)
override fun asmsubArgsHaveRegisterClobberRisk(args: List<Expression>) = asmsub6502ArgsHaveRegisterClobberRisk(args)
override fun asmsubArgsEvalOrder(sub: Subroutine): List<Int> =
asmsub6502ArgsEvalOrder(sub)
override fun asmsubArgsHaveRegisterClobberRisk(args: List<Expression>, paramRegisters: List<RegisterOrStatusflag>) =
asmsub6502ArgsHaveRegisterClobberRisk(args, paramRegisters)
override fun memorySize(dt: DataType): Int {
return when(dt) {

View File

@ -6,6 +6,7 @@ import prog8.ast.base.DataType
import prog8.ast.base.PassByReferenceDatatypes
import prog8.ast.base.WordDatatypes
import prog8.ast.expressions.Expression
import prog8.ast.statements.RegisterOrStatusflag
import prog8.ast.statements.Subroutine
import prog8.compiler.target.cbm.Petscii
import prog8.compiler.target.cpu6502.codegen.asmsub6502ArgsEvalOrder
@ -27,8 +28,10 @@ object Cx16Target: ICompilationTarget {
override fun decodeString(bytes: List<UByte>, altEncoding: Boolean) =
if (altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
override fun asmsubArgsEvalOrder(sub: Subroutine): List<Int> = asmsub6502ArgsEvalOrder(sub)
override fun asmsubArgsHaveRegisterClobberRisk(args: List<Expression>) = asmsub6502ArgsHaveRegisterClobberRisk(args)
override fun asmsubArgsEvalOrder(sub: Subroutine): List<Int> =
asmsub6502ArgsEvalOrder(sub)
override fun asmsubArgsHaveRegisterClobberRisk(args: List<Expression>, paramRegisters: List<RegisterOrStatusflag>) =
asmsub6502ArgsHaveRegisterClobberRisk(args, paramRegisters)
override fun memorySize(dt: DataType): Int {
return when(dt) {

View File

@ -104,8 +104,10 @@ class AsmGen(private val program: Program,
internal fun isTargetCpu(cpu: CpuType) = compTarget.machine.cpu == cpu
internal fun haveFPWR() = compTarget is Cx16Target
internal fun asmsubArgsEvalOrder(sub: Subroutine) = compTarget.asmsubArgsEvalOrder(sub)
internal fun asmsubArgsHaveRegisterClobberRisk(args: List<Expression>) = compTarget.asmsubArgsHaveRegisterClobberRisk(args)
internal fun asmsubArgsEvalOrder(sub: Subroutine) =
compTarget.asmsubArgsEvalOrder(sub)
internal fun asmsubArgsHaveRegisterClobberRisk(args: List<Expression>, paramRegisters: List<RegisterOrStatusflag>) =
compTarget.asmsubArgsHaveRegisterClobberRisk(args, paramRegisters)
private fun header() {
val ourName = this.javaClass.name

View File

@ -3,6 +3,7 @@ package prog8.compiler.target.cpu6502.codegen
import prog8.ast.base.Cx16VirtualRegisters
import prog8.ast.base.RegisterOrPair
import prog8.ast.expressions.*
import prog8.ast.statements.RegisterOrStatusflag
import prog8.ast.statements.Subroutine
@ -34,19 +35,27 @@ internal fun asmsub6502ArgsEvalOrder(sub: Subroutine): List<Int> {
return order
}
internal fun asmsub6502ArgsHaveRegisterClobberRisk(args: List<Expression>): Boolean {
internal fun asmsub6502ArgsHaveRegisterClobberRisk(args: List<Expression>,
paramRegisters: List<RegisterOrStatusflag>): Boolean {
fun isClobberRisk(expr: Expression): Boolean {
if (expr.isSimple && expr !is PrefixExpression)
return false
if (expr is FunctionCall) {
when (expr) {
is ArrayIndexedExpression -> {
return paramRegisters.any {
it.registerOrPair in listOf(RegisterOrPair.Y, RegisterOrPair.AY, RegisterOrPair.XY)
}
}
is PrefixExpression -> {
return true // TODO really, is prefixexpression problematic for register clobbering?
}
is FunctionCall -> {
if (expr.target.nameInSource == listOf("lsb") || expr.target.nameInSource == listOf("msb"))
return isClobberRisk(expr.args[0])
if (expr.target.nameInSource == listOf("mkword"))
return isClobberRisk(expr.args[0]) && isClobberRisk(expr.args[1])
return !expr.isSimple
}
else -> return !expr.isSimple
}
return true
}
return args.size>1 && args.any { isClobberRisk(it) }

View File

@ -114,7 +114,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
if(sub.parameters.size==1) {
argumentViaRegister(sub, IndexedValue(0, sub.parameters.single()), call.args[0])
} else {
if(asmgen.asmsubArgsHaveRegisterClobberRisk(call.args)) {
if(asmgen.asmsubArgsHaveRegisterClobberRisk(call.args, sub.asmParameterRegisters)) {
registerArgsViaStackEvaluation(call, sub)
} else {
asmgen.asmsubArgsEvalOrder(sub).forEach {

View File

@ -411,7 +411,7 @@ internal class StatementReorderer(val program: Program,
scope.statements += FunctionCallStatement(IdentifierReference(listOf("sys", "rrestorex"), call.position), mutableListOf(), true, call.position)
}
return listOf(IAstModification.ReplaceNode(call, scope, parent))
} else if(!options.compTarget.asmsubArgsHaveRegisterClobberRisk(call.args)) {
} else if(!options.compTarget.asmsubArgsHaveRegisterClobberRisk(call.args, function.asmParameterRegisters)) {
// No register clobber risk, let the asmgen assign values to the registers directly.
// this is more efficient than first evaluating them to the stack.
// As complex expressions will be flagged as a clobber-risk, these will be simplified below.

View File

@ -9,6 +9,7 @@ import io.kotest.matchers.comparables.shouldBeGreaterThan
import io.kotest.matchers.shouldBe
import prog8.ast.base.DataType
import prog8.ast.expressions.Expression
import prog8.ast.statements.RegisterOrStatusflag
import prog8.ast.statements.Subroutine
import prog8.compiler.target.C64Target
import prog8.compiler.target.Cx16Target
@ -37,7 +38,8 @@ class TestAbstractZeropage: FunSpec({
throw NotImplementedError("dummy")
}
override fun asmsubArgsHaveRegisterClobberRisk(args: List<Expression>): Boolean {
override fun asmsubArgsHaveRegisterClobberRisk(args: List<Expression>,
paramRegisters: List<RegisterOrStatusflag>): Boolean {
throw NotImplementedError("dummy")
}

View File

@ -1,6 +1,7 @@
package prog8.compilerinterface
import prog8.ast.expressions.Expression
import prog8.ast.statements.RegisterOrStatusflag
import prog8.ast.statements.Subroutine
interface ICompilationTarget: IStringEncoding, IMemSizer {
@ -10,5 +11,6 @@ interface ICompilationTarget: IStringEncoding, IMemSizer {
override fun decodeString(bytes: List<UByte>, altEncoding: Boolean): String
fun asmsubArgsEvalOrder(sub: Subroutine): List<Int>
fun asmsubArgsHaveRegisterClobberRisk(args: List<Expression>): Boolean
fun asmsubArgsHaveRegisterClobberRisk(args: List<Expression>,
paramRegisters: List<RegisterOrStatusflag>): Boolean
}

View File

@ -4,6 +4,8 @@ TODO
For next compiler release (7.4)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
BUG: sys.rsave/sys.rrestore can never work as subroutine because stack is used -> builtin funcs
BUG: balls example crashes / animates wrong!
caused by c83882161521378f20dc0076c01e18e8556e363e 'refactor function arguments codegen a bit'
on the lines that call txt.setclr(BX[lp], BY[lp], BC[lp]) - they work with regular vars as args

View File

@ -1,28 +1,26 @@
%import textio
%import test_stack
%zeropage dontuse
main {
sub start() {
test_stack.test()
ubyte[50] xpos = 49 to 0 step -1
ubyte[50] ypos = 49 to 0 step -1
ubyte[20] xpos = 19 to 0 step -1
ubyte[20] ypos = 19 to 0 step -1
ubyte ball
for ball in 0 to len(xpos)-1 {
txt.print_ub(xpos[ball])
txt.spc()
txt.print_ub(ypos[ball])
txt.nl()
ubyte xx = xpos[ball] + 1
ubyte yy = ypos[ball]
txt.setchr(xx,yy,87) ; correct codegen
txt.setclr(xx,yy,5) ; correct codegen
txt.setchr(xpos[ball], ypos[ball], 81) ; TODO WRONG CODEGEN WITH NOOPT
txt.setclr(xpos[ball], ypos[ball], 6) ; TODO WRONG CODEGEN WITH NOOPT
}
ubyte @shared x1 = 10
ubyte @shared x2 = 20
ubyte @shared x3 = 30
test_stack.test()
repeat {
}