mirror of
https://github.com/irmen/prog8.git
synced 2024-11-22 15:33:02 +00:00
code size optimization: subroutine calls with 2 byte arg will pass it via A/Y registers instead of separate param assignments at every call site
This commit is contained in:
parent
629117e594
commit
3cf9b9d9a5
@ -1016,14 +1016,23 @@ 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(functioncallAsmGen.optimizeIntArgsViaRegisters(sub)) {
|
||||
out("; simple int arg(s) passed via register(s)")
|
||||
if(sub.parameters.size==1) {
|
||||
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)
|
||||
} else {
|
||||
require(sub.parameters.size==2)
|
||||
// 2 simple byte args, first in A, second in Y
|
||||
val target1 = AsmAssignTarget(TargetStorageKind.VARIABLE, program, this, sub.parameters[0].type, sub, variableAsmName = sub.parameters[0].name)
|
||||
val target2 = AsmAssignTarget(TargetStorageKind.VARIABLE, program, this, sub.parameters[1].type, sub, variableAsmName = sub.parameters[1].name)
|
||||
assignRegister(RegisterOrPair.A, target1)
|
||||
assignRegister(RegisterOrPair.Y, target2)
|
||||
}
|
||||
}
|
||||
|
||||
if(!onlyVariables) {
|
||||
|
@ -67,7 +67,9 @@ 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 optimizeIntArgsViaRegisters(sub: Subroutine) =
|
||||
(sub.parameters.size==1 && sub.parameters[0].type in IntegerDatatypes)
|
||||
|| (sub.parameters.size==2 && sub.parameters[0].type in ByteDatatypes && sub.parameters[1].type in ByteDatatypes)
|
||||
|
||||
internal fun translateFunctionCall(call: IFunctionCall, isExpression: Boolean) {
|
||||
// Output only the code to set up the parameters and perform the actual call
|
||||
@ -79,7 +81,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
val subAsmName = asmgen.asmSymbolName(call.target)
|
||||
|
||||
if(!isExpression && !sub.isAsmSubroutine) {
|
||||
if(!singleArgViaRegisters(sub))
|
||||
if(!optimizeIntArgsViaRegisters(sub))
|
||||
throw AssemblyError("functioncall statements to non-asmsub should have been replaced by GoSub $call")
|
||||
}
|
||||
|
||||
@ -102,9 +104,19 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
if(sub.inline)
|
||||
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)
|
||||
if(optimizeIntArgsViaRegisters(sub)) {
|
||||
if(sub.parameters.size==1) {
|
||||
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 {
|
||||
// 2 byte params, second in Y, first in A
|
||||
argumentViaRegister(sub, IndexedValue(0, sub.parameters[0]), call.args[0], RegisterOrPair.A)
|
||||
if(!call.args[1].isSimple)
|
||||
asmgen.out(" pha")
|
||||
argumentViaRegister(sub, IndexedValue(1, sub.parameters[1]), call.args[1], RegisterOrPair.Y)
|
||||
if(!call.args[1].isSimple)
|
||||
asmgen.out(" pla")
|
||||
}
|
||||
} else {
|
||||
argumentsViaVariables(sub, call)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.compilerinterface.BuiltinFunctions
|
||||
import prog8.compilerinterface.CompilationOptions
|
||||
import prog8.compilerinterface.ICompilationTarget
|
||||
import prog8.compilerinterface.IErrorReporter
|
||||
|
||||
|
||||
@ -393,11 +394,14 @@ internal class StatementReorderer(val program: Program,
|
||||
}
|
||||
|
||||
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
|
||||
if(function.parameters[0].type in IntegerDatatypes) {
|
||||
// optimization: 1 integer param is passed via register(s) directly, not by assignment to param variable
|
||||
return noModifications
|
||||
}
|
||||
}
|
||||
else if(function.parameters.size==2) {
|
||||
if(function.parameters[0].type in ByteDatatypes && function.parameters[1].type in ByteDatatypes) {
|
||||
// optimization: 2 simple byte param is passed via 2 registers directly, not by assignment to param variables
|
||||
return noModifications
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,6 @@ TODO
|
||||
|
||||
For next compiler release (7.6)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
optimization in call convention:
|
||||
non-asm subroutines with just a single byte or word parameter:
|
||||
pass the parameter via A or A/Y registers.
|
||||
add code to set the parameter variable in the start of the subroutine itself,
|
||||
rather than requiring the caller to set it there. This is not faster but saves a lot of bytes of code.
|
||||
|
||||
...
|
||||
|
||||
|
||||
|
@ -4,10 +4,17 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
ubyte xx = 0
|
||||
|
||||
singleparamb(123)
|
||||
singleparamb(123)
|
||||
singleparamw(-9999)
|
||||
doubleparamb(123,-99)
|
||||
doubleparamw(8888,-9999)
|
||||
singleparamw(-9999)
|
||||
doubleparamb(xx+111,-99)
|
||||
doubleparamb(xx+111,-99)
|
||||
doubleparamw(xx+8888,-9999)
|
||||
doubleparamw(xx+8888,-9999)
|
||||
singleparamf(1.23456)
|
||||
singleparamf(1.23456)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user