mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
code size optimization: subroutine calls with 1 int arg will pass it via register instead of separate param assignment at every call site
This commit is contained in:
parent
08f87c321f
commit
629117e594
@ -16,6 +16,7 @@ import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignTarget
|
||||
import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignment
|
||||
import prog8.compiler.target.cpu6502.codegen.assignment.AssignmentAsmGen
|
||||
import prog8.compiler.target.cpu6502.codegen.assignment.SourceStorageKind
|
||||
import prog8.compiler.target.cpu6502.codegen.assignment.TargetStorageKind
|
||||
import prog8.compilerinterface.*
|
||||
import prog8.parser.SourceCode
|
||||
import java.nio.file.Path
|
||||
@ -1015,6 +1016,16 @@ class AsmGen(private val program: Program,
|
||||
clc""")
|
||||
}
|
||||
|
||||
if(functioncallAsmGen.singleArgViaRegisters(sub)) {
|
||||
out("; single arg is passed via register(s)")
|
||||
val dt = sub.parameters[0].type
|
||||
val target = AsmAssignTarget(TargetStorageKind.VARIABLE, program, this, dt, sub, variableAsmName = sub.parameters[0].name)
|
||||
if(dt in ByteDatatypes)
|
||||
assignRegister(RegisterOrPair.A, target)
|
||||
else
|
||||
assignRegister(RegisterOrPair.AY, target)
|
||||
}
|
||||
|
||||
if(!onlyVariables) {
|
||||
out("; statements")
|
||||
sub.statements.forEach { translate(it) }
|
||||
|
@ -67,6 +67,8 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
}
|
||||
}
|
||||
|
||||
internal fun singleArgViaRegisters(sub: Subroutine) = sub.parameters.size==1 && sub.parameters[0].type in IntegerDatatypes
|
||||
|
||||
internal fun translateFunctionCall(call: IFunctionCall, isExpression: Boolean) {
|
||||
// Output only the code to set up the parameters and perform the actual call
|
||||
// NOTE: does NOT output the code to deal with the result values!
|
||||
@ -76,8 +78,10 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
val sub = call.target.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${call.target}")
|
||||
val subAsmName = asmgen.asmSymbolName(call.target)
|
||||
|
||||
if(!isExpression && !sub.isAsmSubroutine)
|
||||
throw AssemblyError("functioncall statements to non-asmsub should have been replaced by GoSub $call")
|
||||
if(!isExpression && !sub.isAsmSubroutine) {
|
||||
if(!singleArgViaRegisters(sub))
|
||||
throw AssemblyError("functioncall statements to non-asmsub should have been replaced by GoSub $call")
|
||||
}
|
||||
|
||||
if(sub.isAsmSubroutine) {
|
||||
argumentsViaRegisters(sub, call)
|
||||
@ -98,7 +102,12 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
if(sub.inline)
|
||||
throw AssemblyError("can only reliably inline asmsub routines at this time")
|
||||
|
||||
argumentsViaVariables(sub, call)
|
||||
if(singleArgViaRegisters(sub)) {
|
||||
val register = if(sub.parameters[0].type in ByteDatatypes) RegisterOrPair.A else RegisterOrPair.AY
|
||||
argumentViaRegister(sub, IndexedValue(0, sub.parameters[0]), call.args[0], register)
|
||||
} else {
|
||||
argumentsViaVariables(sub, call)
|
||||
}
|
||||
asmgen.out(" jsr $subAsmName")
|
||||
}
|
||||
|
||||
@ -262,14 +271,14 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
asmgen.assignExpressionToVariable(value, varName, parameter.value.type, sub)
|
||||
}
|
||||
|
||||
private fun argumentViaRegister(sub: Subroutine, parameter: IndexedValue<SubroutineParameter>, value: Expression) {
|
||||
private fun argumentViaRegister(sub: Subroutine, parameter: IndexedValue<SubroutineParameter>, value: Expression, registerOverride: RegisterOrPair? = null) {
|
||||
// pass argument via a register parameter
|
||||
val valueIDt = value.inferType(program)
|
||||
val valueDt = valueIDt.getOrElse { throw AssemblyError("unknown dt") }
|
||||
if(!isArgumentTypeCompatible(valueDt, parameter.value.type))
|
||||
throw AssemblyError("argument type incompatible")
|
||||
|
||||
val paramRegister = sub.asmParameterRegisters[parameter.index]
|
||||
val paramRegister = if(registerOverride==null) sub.asmParameterRegisters[parameter.index] else RegisterOrStatusflag(registerOverride, null)
|
||||
val statusflag = paramRegister.statusflag
|
||||
val register = paramRegister.registerOrPair
|
||||
val requiredDt = parameter.value.type
|
||||
|
@ -392,11 +392,15 @@ internal class StatementReorderer(val program: Program,
|
||||
return listOf(IAstModification.ReplaceNode(call, GoSub(null, call.target, null, call.position), parent))
|
||||
}
|
||||
|
||||
// if(function.parameters.size==1) {
|
||||
// // 1 param
|
||||
// val dt = function.parameters[0].type
|
||||
// if(dt in IntegerDatatypes)
|
||||
// }
|
||||
if(function.parameters.size==1) {
|
||||
// 1 param
|
||||
val dt = function.parameters[0].type
|
||||
if(dt in IntegerDatatypes) {
|
||||
// optimization: 1 integer param is passed via registers directly, not by assignment to param variable
|
||||
// TODO also do this for 2x byte param , can be put in A and Y
|
||||
return noModifications
|
||||
}
|
||||
}
|
||||
|
||||
val assignParams =
|
||||
function.parameters.zip(call.args).map {
|
||||
|
@ -324,9 +324,9 @@ class TestSubroutines: FunSpec({
|
||||
val text = """
|
||||
main {
|
||||
sub start() {
|
||||
func(1)
|
||||
func(1, 2, 3)
|
||||
|
||||
sub func(ubyte a) {
|
||||
sub func(ubyte a, ubyte b, ubyte c) {
|
||||
a++
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,42 @@
|
||||
%import textio
|
||||
%import floats
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
|
||||
singleparamb(10)
|
||||
singleparamw(2000)
|
||||
singleparamb(123)
|
||||
singleparamw(-9999)
|
||||
doubleparamb(123,-99)
|
||||
doubleparamw(8888,-9999)
|
||||
singleparamf(1.23456)
|
||||
}
|
||||
|
||||
sub singleparamb(ubyte bb) {
|
||||
bb++
|
||||
txt.print_ub(bb)
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub doubleparamb(ubyte bb, byte bs) {
|
||||
txt.print_ub(bb)
|
||||
txt.spc()
|
||||
txt.print_b(bs)
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub singleparamw(word ww) {
|
||||
ww++
|
||||
txt.print_w(ww)
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub doubleparamw(uword uw, word ww) {
|
||||
txt.print_uw(uw)
|
||||
txt.spc()
|
||||
txt.print_w(ww)
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub singleparamf(float ff) {
|
||||
ff++
|
||||
floats.print_f(ff)
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user