mirror of
https://github.com/irmen/prog8.git
synced 2024-11-25 19:31:36 +00:00
optimize 1-arg functioncalls
This commit is contained in:
parent
960b60cd2d
commit
f0dadc4a43
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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++
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user