diff --git a/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/AsmOptimizer.kt b/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/AsmOptimizer.kt index b688c92a1..0e465f790 100644 --- a/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/AsmOptimizer.kt +++ b/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/AsmOptimizer.kt @@ -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 diff --git a/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/assignment/AsmAssignment.kt b/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/assignment/AsmAssignment.kt index f29d601c3..eaeb4c23b 100644 --- a/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/assignment/AsmAssignment.kt +++ b/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/assignment/AsmAssignment.kt @@ -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 diff --git a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt index 0f753513d..095459bb8 100644 --- a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt @@ -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 { // // 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) diff --git a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt index 021ee776b..e95c6dda2 100644 --- a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt +++ b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt @@ -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) diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 66badb45a..1977e794e 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -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) { diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index 7748fef48..93eb4bf6f 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -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) { diff --git a/examples/test.p8 b/examples/test.p8 index 89c78d6c7..b570f3534 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -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++ }