From 5640e6dacd39d97adffce8490991c457f457b1cd Mon Sep 17 00:00:00 2001
From: Damien George <damien.p.george@gmail.com>
Date: Fri, 17 Mar 2017 16:38:46 +1100
Subject: [PATCH] py: Provide mp_decode_uint_value to help optimise stack
 usage.

This has a noticeable improvement on x86-64 and Thumb2 archs, where stack
usage is reduced by 2 machine words in the VM.
---
 py/bc.c           | 16 +++++++++++-----
 py/bc.h           |  1 +
 py/objgenerator.c |  3 +--
 py/vm.c           |  3 +--
 4 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/py/bc.c b/py/bc.c
index db5d0e686..e7a1a333f 100644
--- a/py/bc.c
+++ b/py/bc.c
@@ -54,6 +54,16 @@ mp_uint_t mp_decode_uint(const byte **ptr) {
     return unum;
 }
 
+// This function is used to help reduce stack usage at the caller, for the case when
+// the caller doesn't need to increase the ptr argument.  If ptr is a local variable
+// and the caller uses mp_decode_uint(&ptr) instead of this function, then the compiler
+// must allocate a slot on the stack for ptr, and this slot cannot be reused for
+// anything else in the function because the pointer may have been stored in a global
+// and reused later in the function.
+mp_uint_t mp_decode_uint_value(const byte *ptr) {
+    return mp_decode_uint(&ptr);
+}
+
 STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) {
 #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
     // generic message, used also for other argument issues
@@ -246,11 +256,7 @@ continue2:;
     const byte *ip = code_state->ip;
 
     // jump over code info (source file and line-number mapping)
-    {
-        const byte *ip2 = ip;
-        size_t code_info_size = mp_decode_uint(&ip2);
-        ip += code_info_size;
-    }
+    ip += mp_decode_uint_value(ip);
 
     // bytecode prelude: initialise closed over variables
     size_t local_num;
diff --git a/py/bc.h b/py/bc.h
index 996b1a2f3..e8d428612 100644
--- a/py/bc.h
+++ b/py/bc.h
@@ -91,6 +91,7 @@ typedef struct _mp_code_state_t {
 } mp_code_state_t;
 
 mp_uint_t mp_decode_uint(const byte **ptr);
+mp_uint_t mp_decode_uint_value(const byte *ptr);
 
 mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc);
 mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t func, size_t n_args, size_t n_kw, const mp_obj_t *args);
diff --git a/py/objgenerator.c b/py/objgenerator.c
index 2baead231..e59ff3a9c 100644
--- a/py/objgenerator.c
+++ b/py/objgenerator.c
@@ -135,8 +135,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
             break;
 
         case MP_VM_RETURN_EXCEPTION: {
-            const byte *bc = self->code_state.fun_bc->bytecode;
-            size_t n_state = mp_decode_uint(&bc);
+            size_t n_state = mp_decode_uint_value(self->code_state.fun_bc->bytecode);
             self->code_state.ip = 0;
             *ret_val = self->code_state.state[n_state - 1];
             break;
diff --git a/py/vm.c b/py/vm.c
index 63a88a4fb..4ec1ea906 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -162,8 +162,7 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp
 run_code_state: ;
 #endif
     // Pointers which are constant for particular invocation of mp_execute_bytecode()
-    const byte *temp_bc = code_state->fun_bc->bytecode;
-    size_t n_state = mp_decode_uint(&temp_bc);
+    size_t n_state = mp_decode_uint_value(code_state->fun_bc->bytecode);
     mp_obj_t * /*const*/ fastn = &code_state->state[n_state - 1];
     mp_exc_stack_t * /*const*/ exc_stack = (mp_exc_stack_t*)(code_state->state + n_state);
 
-- 
GitLab