mirror of
https://github.com/irmen/prog8.git
synced 2024-11-03 13:07:54 +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.AsmAssignment
|
||||||
import prog8.compiler.target.cpu6502.codegen.assignment.AssignmentAsmGen
|
import prog8.compiler.target.cpu6502.codegen.assignment.AssignmentAsmGen
|
||||||
import prog8.compiler.target.cpu6502.codegen.assignment.SourceStorageKind
|
import prog8.compiler.target.cpu6502.codegen.assignment.SourceStorageKind
|
||||||
|
import prog8.compiler.target.cpu6502.codegen.assignment.TargetStorageKind
|
||||||
import prog8.compilerinterface.*
|
import prog8.compilerinterface.*
|
||||||
import prog8.parser.SourceCode
|
import prog8.parser.SourceCode
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
@ -1015,6 +1016,16 @@ class AsmGen(private val program: Program,
|
|||||||
clc""")
|
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) {
|
if(!onlyVariables) {
|
||||||
out("; statements")
|
out("; statements")
|
||||||
sub.statements.forEach { translate(it) }
|
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) {
|
internal fun translateFunctionCall(call: IFunctionCall, isExpression: Boolean) {
|
||||||
// Output only the code to set up the parameters and perform the actual call
|
// 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!
|
// 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 sub = call.target.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${call.target}")
|
||||||
val subAsmName = asmgen.asmSymbolName(call.target)
|
val subAsmName = asmgen.asmSymbolName(call.target)
|
||||||
|
|
||||||
if(!isExpression && !sub.isAsmSubroutine)
|
if(!isExpression && !sub.isAsmSubroutine) {
|
||||||
|
if(!singleArgViaRegisters(sub))
|
||||||
throw AssemblyError("functioncall statements to non-asmsub should have been replaced by GoSub $call")
|
throw AssemblyError("functioncall statements to non-asmsub should have been replaced by GoSub $call")
|
||||||
|
}
|
||||||
|
|
||||||
if(sub.isAsmSubroutine) {
|
if(sub.isAsmSubroutine) {
|
||||||
argumentsViaRegisters(sub, call)
|
argumentsViaRegisters(sub, call)
|
||||||
@ -98,7 +102,12 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
|||||||
if(sub.inline)
|
if(sub.inline)
|
||||||
throw AssemblyError("can only reliably inline asmsub routines at this time")
|
throw AssemblyError("can only reliably inline asmsub routines at this time")
|
||||||
|
|
||||||
|
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)
|
argumentsViaVariables(sub, call)
|
||||||
|
}
|
||||||
asmgen.out(" jsr $subAsmName")
|
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)
|
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
|
// pass argument via a register parameter
|
||||||
val valueIDt = value.inferType(program)
|
val valueIDt = value.inferType(program)
|
||||||
val valueDt = valueIDt.getOrElse { throw AssemblyError("unknown dt") }
|
val valueDt = valueIDt.getOrElse { throw AssemblyError("unknown dt") }
|
||||||
if(!isArgumentTypeCompatible(valueDt, parameter.value.type))
|
if(!isArgumentTypeCompatible(valueDt, parameter.value.type))
|
||||||
throw AssemblyError("argument type incompatible")
|
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 statusflag = paramRegister.statusflag
|
||||||
val register = paramRegister.registerOrPair
|
val register = paramRegister.registerOrPair
|
||||||
val requiredDt = parameter.value.type
|
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))
|
return listOf(IAstModification.ReplaceNode(call, GoSub(null, call.target, null, call.position), parent))
|
||||||
}
|
}
|
||||||
|
|
||||||
// if(function.parameters.size==1) {
|
if(function.parameters.size==1) {
|
||||||
// // 1 param
|
// 1 param
|
||||||
// val dt = function.parameters[0].type
|
val dt = function.parameters[0].type
|
||||||
// if(dt in IntegerDatatypes)
|
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 =
|
val assignParams =
|
||||||
function.parameters.zip(call.args).map {
|
function.parameters.zip(call.args).map {
|
||||||
|
@ -324,9 +324,9 @@ class TestSubroutines: FunSpec({
|
|||||||
val text = """
|
val text = """
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
func(1)
|
func(1, 2, 3)
|
||||||
|
|
||||||
sub func(ubyte a) {
|
sub func(ubyte a, ubyte b, ubyte c) {
|
||||||
a++
|
a++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,42 @@
|
|||||||
|
%import textio
|
||||||
%import floats
|
%import floats
|
||||||
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
|
singleparamb(123)
|
||||||
singleparamb(10)
|
singleparamw(-9999)
|
||||||
singleparamw(2000)
|
doubleparamb(123,-99)
|
||||||
|
doubleparamw(8888,-9999)
|
||||||
singleparamf(1.23456)
|
singleparamf(1.23456)
|
||||||
}
|
}
|
||||||
|
|
||||||
sub singleparamb(ubyte bb) {
|
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) {
|
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) {
|
sub singleparamf(float ff) {
|
||||||
ff++
|
floats.print_f(ff)
|
||||||
|
txt.nl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user