optimize 1-arg functioncalls

This commit is contained in:
Irmen de Jong 2021-11-28 16:55:10 +01:00
parent 960b60cd2d
commit f0dadc4a43
7 changed files with 46 additions and 7 deletions

View File

@ -7,6 +7,10 @@ import prog8.ast.statements.VarDecl
import prog8.compilerinterface.IMachineDefinition
// TODO optimize subsequent pha/pla, phx/plx, phy/ply pairs
// TODO optimize pha/plx -> tax, pha/ply -> tay, etc.
// note: see https://wiki.nesdev.org/w/index.php/6502_assembly_optimisations

View File

@ -150,7 +150,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
is IdentifierReference -> {
val parameter = value.targetVarDecl(program)?.subroutineParameter
if(parameter!=null && parameter.definingSubroutine!!.isAsmSubroutine)
throw AssemblyError("can't assign from a asmsub register parameter")
throw AssemblyError("can't assign from a asmsub register parameter $value ${value.position}")
val dt = value.inferType(program).getOr(DataType.UNDEFINED)
val varName=asmgen.asmVariableName(value)
// special case: "cx16.r[0-15]" are 16-bits virtual registers of the commander X16 system

View File

@ -1,9 +1,6 @@
package prog8.optimizer
import prog8.ast.IBuiltinFunctions
import prog8.ast.IStatementContainer
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.*
import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.*
@ -118,9 +115,35 @@ class StatementOptimizer(private val program: Program,
return listOf(IAstModification.Remove(functionCallStatement, parent as IStatementContainer))
}
// see if we can optimize any complex arguments
// TODO for now, only works for single-argument functions because we use just 1 temp var: R9
if(functionCallStatement.target.nameInSource !in listOf(listOf("pop"), listOf("popw")) && functionCallStatement.args.size==1) {
val arg = functionCallStatement.args[0]
if(!arg.isSimple && arg !is TypecastExpression && arg !is IFunctionCall) {
val dt = arg.inferType(program)
val name = when {
// TODO assume (hope) cx16.r9 isn't used for anything else...
dt.istype(DataType.UBYTE) -> listOf("cx16","r9L")
dt.istype(DataType.BYTE) -> listOf("cx16","r9sL")
dt.istype(DataType.UWORD) -> listOf("cx16","r9")
dt.istype(DataType.WORD) -> listOf("cx16","r9s")
dt.isPassByReference -> listOf("cx16","r9")
else -> throw FatalAstException("invalid dt $dt")
}
val tempvar = IdentifierReference(name, functionCallStatement.position)
val assignTempvar = Assignment(AssignTarget(tempvar.copy(), null, null, functionCallStatement.position), arg, functionCallStatement.position)
return listOf(
IAstModification.InsertBefore(functionCallStatement, assignTempvar, parent as IStatementContainer),
IAstModification.ReplaceNode(arg, tempvar, functionCallStatement)
)
}
}
return noModifications
}
// TODO WHAT TO DO WITH THIS:
// override fun before(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> {
// // if the first instruction in the called subroutine is a return statement with constant value, replace with the constant value
// val subroutine = functionCall.target.targetSubroutine(program)

View File

@ -235,6 +235,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, private val o
dt.istype(DataType.BYTE) -> listOf("cx16","r9sL")
dt.istype(DataType.UWORD) -> listOf("cx16","r9")
dt.istype(DataType.WORD) -> listOf("cx16","r9s")
dt.isPassByReference -> listOf("cx16","r9")
else -> throw AssemblyError("invalid dt")
}
leftOperandReplacement = IdentifierReference(name, expr.position)

View File

@ -1070,7 +1070,12 @@ internal class AstChecker(private val program: Program,
ident = fcall.args[0] as? IdentifierReference
}
if(ident!=null && ident.nameInSource[0] == "cx16" && ident.nameInSource[1].startsWith("r")) {
val reg = RegisterOrPair.valueOf(ident.nameInSource[1].uppercase())
var regname = ident.nameInSource[1].uppercase()
if(regname.endsWith('L'))
regname=regname.substring(0, regname.length-1)
if(regname.endsWith('s'))
regname=regname.substring(0, regname.length-1)
val reg = RegisterOrPair.valueOf(regname)
val same = params.filter { it.value.registerOrPair==reg }
for(s in same) {
if(s.index!=arg.index) {

View File

@ -864,7 +864,7 @@ class FunctionCall(override var target: IdentifierReference,
args.forEach { it.linkParents(this) }
}
override fun copy() = throw NotImplementedError("no support for duplicating a FunctionCall")
override fun copy() = FunctionCall(target.copy(), args.map { it.copy() }.toMutableList(), position)
override val isSimple = target.nameInSource.size==1 && (target.nameInSource[0] in arrayOf("msb", "lsb", "peek", "peekw"))
override fun replaceChildNode(node: Node, replacement: Node) {

View File

@ -11,6 +11,8 @@ main {
sub start() {
test_stack.test()
save(8, "wob", 0, 10)
uword @shared uw
ubyte @shared ub
word @shared ww
@ -41,6 +43,10 @@ main {
}
sub save(ubyte drivenumber, uword filenameptr, uword address, uword size) {
c64.SETNAM(string.length(filenameptr), filenameptr)
}
sub single(ubyte num) {
num++
}