From fb1e89d9efcf54d533bc532b2427011d338317de Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 19 Feb 2025 21:05:33 +0100 Subject: [PATCH] update docs about call convention for multi-value results (first is in A or AY, then R15...R0) added sprites+coroutines+defer part to benchmark program --- benchmark-program/b_circles.p8 | 4 ++-- benchmark-program/benchmark.p8 | 11 ++++++++--- .../src/prog8/codegen/intermediate/ExpressionGen.kt | 5 ++++- compiler/res/prog8lib/coroutines.p8 | 1 + docs/source/programming.rst | 4 ++-- docs/source/technical.rst | 5 +++-- docs/source/todo.rst | 4 ---- 7 files changed, 20 insertions(+), 14 deletions(-) diff --git a/benchmark-program/b_circles.p8 b/benchmark-program/b_circles.p8 index 7b7734f1b..d35a31c6d 100644 --- a/benchmark-program/b_circles.p8 +++ b/benchmark-program/b_circles.p8 @@ -12,7 +12,7 @@ circles { sub draw(bool use_kernal, uword max_time) -> uword { if use_kernal - void cx16.set_screen_mode(128) + cx16.set_screen_mode(128) else gfx_lores.graphics_mode() @@ -33,7 +33,7 @@ circles { } if use_kernal - void cx16.set_screen_mode(3) + cx16.set_screen_mode(3) else { gfx_lores.text_mode() } diff --git a/benchmark-program/benchmark.p8 b/benchmark-program/benchmark.p8 index e8d053277..f61829897 100644 --- a/benchmark-program/benchmark.p8 +++ b/benchmark-program/benchmark.p8 @@ -15,6 +15,7 @@ %import b_queens %import b_textelite %import b_maze +%import b_sprites %zeropage basicsafe %option no_sysinit @@ -29,7 +30,7 @@ main { sub start() { ubyte benchmark_number - void cx16.set_screen_mode(3) + cx16.set_screen_mode(3) txt.color2(1, 6) txt.clear_screen() @@ -74,10 +75,14 @@ main { benchmark_score[benchmark_number] = textelite.bench(120) benchmark_number++ + announce_benchmark("sprites-coroutines-defer") + benchmark_score[benchmark_number] = animsprites.benchmark(300) + benchmark_number++ + benchmark_names[benchmark_number] = 0 benchmark_score[benchmark_number] = 0 - void cx16.set_screen_mode(3) + cx16.set_screen_mode(3) txt.uppercase() txt.color2(1, 6) uword final_score @@ -99,7 +104,7 @@ main { sub announce_benchmark(str name) { benchmark_names[benchmark_number] = name - void cx16.set_screen_mode(3) + cx16.set_screen_mode(3) txt.uppercase() txt.color2(1, 6) txt.clear_screen() diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index a4458b825..7b5f8c8dd 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -635,7 +635,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } } // return value(s) - val returnRegSpecs = if(fcall.void) emptyList() else { + // TODO: for current implemenation of the call convention in case of multiple return values, + // a list of Ir virtual registers to hold the results is NOT correct (they're loaded into AY + R15..R0 instead!) + // So we use an empty list to avoid confusion here. This may change in a future version. + val returnRegSpecs = if(fcall.void || callTarget.returns.size>1) emptyList() else { callTarget.returns.map { val returnIrType = irType(it) FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.next(returnIrType), null) diff --git a/compiler/res/prog8lib/coroutines.p8 b/compiler/res/prog8lib/coroutines.p8 index ee0ff5176..4dbb202a2 100644 --- a/compiler/res/prog8lib/coroutines.p8 +++ b/compiler/res/prog8lib/coroutines.p8 @@ -33,6 +33,7 @@ ; - call killall() to kill all tasks. ; - IMPORTANT: if you add the same subroutine multiple times, IT CANNOT DEPEND ON ANY LOCAL VARIABLES OR R0-R15 TO KEEP STATE. NOT EVEN REPEAT LOOP COUNTERS. ; Those are all shared in the different tasks! You HAVE to use a mechanism around the userdata value (pointer?) to keep separate state elsewhere! +; - IMPORTANT: ``defer`` cannot be used inside a coroutine that is reused for multiple tasks!!! coroutines { %option ignore_unused diff --git a/docs/source/programming.rst b/docs/source/programming.rst index 10c881da8..228fa9bd7 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -1170,9 +1170,9 @@ So for instance:: asmsub multisub() -> uword @AY, bool @Pc, ubyte @X { ... } -.. sidebar:: usage of cx16.r0-cx16.r15 +.. sidebar:: register usage - Subroutines with multiple return values use the "virtual registers" to return those. + Subroutines with multiple return values use cpu registers A, Y, and the R0-R15 "virtual registers" to return those. Using those virtual registers during the calculation of the values in the return statement should be avoided. Otherwise you risk overwriting an earlier return value in the sequence. diff --git a/docs/source/technical.rst b/docs/source/technical.rst index e69a01918..b752962ec 100644 --- a/docs/source/technical.rst +++ b/docs/source/technical.rst @@ -155,8 +155,9 @@ Regular subroutines - for an ``asmsub`` or ``extsub`` the subroutine's signature specifies the output registers that contain the values explicitly, just as for a single return value. - - for regular subroutines, the compiler will use the "virtual registers" cx16.r0-cx16.r15, from r15 down to r0, for the - result values left to right. This may change in a future compiler version. + - for regular subroutines, the compiler will return the first of the return values via the cpu register ``A``` (or ``A + Y``` if it's a word value), + just like for subroutines that only return a single value. + The remainder of the return values are returned via the "virtual registers" cx16.r16-cx16.r0 (using R15 first and counting down to R0). **Builtin functions can be different:** diff --git a/docs/source/todo.rst b/docs/source/todo.rst index bcf2c14ec..92c1c478a 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,10 +1,6 @@ TODO ==== -- IR: call main.two():r4.w,r5.w the registers mentioned after the call are wrong/unused in case of multi-value returns. Better to clear this to avoid confusion? (they ARE correct for single value returns!) - -- update docs about call convention for multi-value results (first is in A or AY, then R15...R0) - ...