long args call convention is to pass via parameter variable not R14R15

This commit is contained in:
Irmen de Jong
2026-02-15 17:28:59 +01:00
parent 6a0b22bb64
commit 74ca190ce0
5 changed files with 63 additions and 25 deletions

View File

@@ -57,13 +57,13 @@ class FSignature(val pure: Boolean, // does it have side effects?
return when {
actualParamTypes.isEmpty() -> CallConvention(emptyList(), returns)
actualParamTypes.size==1 -> {
// One parameter goes via register/registerpair.
// One parameter goes via register/registerpair (except longs)
// this avoids repeated code for every caller to store the value in the subroutine's argument variable.
// (that store is still done, but only coded once at the start at the subroutine itself rather than at every call site).
val paramConv = when(val paramType = actualParamTypes[0]) {
BaseDataType.UBYTE, BaseDataType.BYTE -> ParamConvention(paramType, RegisterOrPair.A, false)
BaseDataType.UWORD, BaseDataType.WORD -> ParamConvention(paramType, RegisterOrPair.AY, false)
BaseDataType.LONG -> ParamConvention(paramType, RegisterOrPair.R14R15, false) // TODO longs should not be passed in R14R15 but via parameter variable
BaseDataType.LONG -> ParamConvention(paramType, null, true)
BaseDataType.FLOAT -> ParamConvention(paramType, RegisterOrPair.AY, false) // NOTE: for builtin functions, floating point arguments are passed by reference (so you get a pointer in AY)
in IterableDatatypes -> ParamConvention(paramType, RegisterOrPair.AY, false)
else -> ParamConvention(paramType, null, false)

View File

@@ -511,12 +511,12 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
private fun funcSqrt(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
when(fcall.args[0].type.base) {
BaseDataType.UBYTE -> {
translateArguments(fcall, scope)
translateArguments(fcall, null, scope)
asmgen.out(" ldy #0 | jsr prog8_lib.func_sqrt16_into_A")
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false, false)
}
BaseDataType.UWORD -> {
translateArguments(fcall, scope)
translateArguments(fcall, null, scope)
asmgen.out(" jsr prog8_lib.func_sqrt16_into_A")
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false, false)
}
@@ -527,7 +527,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, scope, asmgen),RegisterOrPair.AY)
}
BaseDataType.FLOAT -> {
translateArguments(fcall, scope)
translateArguments(fcall, null, scope)
asmgen.out(" jsr floats.func_sqrt_into_FAC1")
assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, fcall.position, scope, asmgen))
}
@@ -967,14 +967,31 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
private fun funcSgn(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
translateArguments(fcall, scope)
when (val dt = fcall.args.single().type.base) {
BaseDataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_into_A")
BaseDataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_into_A")
BaseDataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_into_A")
BaseDataType.WORD -> asmgen.out(" jsr prog8_lib.func_sign_w_into_A")
BaseDataType.LONG -> asmgen.out(" jsr prog8_lib.func_sign_l_r14r15_into_A") // note: long arg is stored in R14:R15
BaseDataType.FLOAT -> asmgen.out(" jsr floats.func_sign_f_into_A")
BaseDataType.UBYTE -> {
translateArguments(fcall, null, scope)
asmgen.out(" jsr prog8_lib.func_sign_ub_into_A")
}
BaseDataType.BYTE -> {
translateArguments(fcall, null, scope)
asmgen.out(" jsr prog8_lib.func_sign_b_into_A")
}
BaseDataType.UWORD -> {
translateArguments(fcall, null, scope)
asmgen.out(" jsr prog8_lib.func_sign_uw_into_A")
}
BaseDataType.WORD -> {
translateArguments(fcall, null, scope)
asmgen.out(" jsr prog8_lib.func_sign_w_into_A")
}
BaseDataType.LONG -> {
translateArguments(fcall, funcname="func_sign_l_into_A", scope)
asmgen.out(" jsr prog8_lib.func_sign_l_into_A")
}
BaseDataType.FLOAT -> {
translateArguments(fcall, null, scope)
asmgen.out(" jsr floats.func_sign_f_into_A")
}
else -> throw AssemblyError("weird type $dt")
}
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, true, true)
@@ -1463,7 +1480,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
private fun funcAbs(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
translateArguments(fcall, scope)
translateArguments(fcall, null, scope)
val dt = fcall.args.single().type.base
when (dt) {
BaseDataType.BYTE -> {
@@ -2712,7 +2729,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
private fun translateArguments(call: PtBuiltinFunctionCall, scope: IPtSubroutine?) {
private fun translateArguments(call: PtBuiltinFunctionCall, funcname: String?, scope: IPtSubroutine?) {
val signature = BuiltinFunctions.getValue(call.name)
val callConv = signature.callConvention(call.args.map {
require(it.type.isNumericOrBool)
@@ -2756,13 +2773,15 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
}
val libfuncname = funcname ?: "func_${call.name}"
call.args.zip(callConv.params).zip(signature.parameters).forEach {
val paramName = it.second.name
val conv = it.first.second
val value = it.first.first
when {
conv.variable -> {
val varname = "prog8_lib.func_${call.name}._arg_${paramName}"
val varname = "prog8_lib.${libfuncname}._arg_${paramName}"
val src = when {
conv.dt==BaseDataType.FLOAT -> getSourceForFloat(value)
conv.dt==BaseDataType.LONG -> getSourceForLong(value)

View File

@@ -99,15 +99,16 @@ _negative lda #-1
rts
.pend
func_sign_l_r14r15_into_A .proc
lda cx16.r14+3 ; msb
func_sign_l_into_A .proc
; NOTE: takes long argument in _arg_value
lda _arg_value+3 ; msb
bmi _negative
bne _positive
lda cx16.r14+2
lda _arg_value+2
bne _positive
lda cx16.r14+1
lda _arg_value+1
bne _positive
lda cx16.r14
lda _arg_value
beq _zero
lda #1
_zero
@@ -119,6 +120,8 @@ _positive
lda #1
rts
_arg_value .byte 0,0,0,0
.pend

View File

@@ -1,11 +1,6 @@
TODO
====
- FSignature.callConvention should not pass long via R14R15
- func_sign_l_r14r15_into_A should not take the long in r14r15 but in regular parameter like sqrt_long
Known bugs:
- fix chained aliasing errors see test "chained aliasing"
- fix crash in ir loader/vm for deeply nested symbol reference, see test "deeply scoped variable references"

View File

@@ -12,8 +12,29 @@ main {
long @shared l1 = -1000000
cx16.r0sL = sgn(b1)
txt.print_b(cx16.r0sL)
txt.spc()
cx16.r1sL = sgn(w1)
txt.print_b(cx16.r1sL)
txt.spc()
cx16.r2sL = sgn(l1)
txt.print_b(cx16.r2sL)
txt.nl()
b1 = 100
w1 = 1000
l1 = 1000000
cx16.r0sL = sgn(b1)
txt.print_b(cx16.r0sL)
txt.spc()
cx16.r1sL = sgn(w1)
txt.print_b(cx16.r1sL)
txt.spc()
cx16.r2sL = sgn(l1)
txt.print_b(cx16.r2sL)
txt.nl()
}
sub start() {