py: Implement full func arg passing for native emitter.

This patch gets full function argument passing working with native
emitter.  Includes named args, keyword args, default args, var args
and var keyword args.  Fully Python compliant.

It reuses the bytecode mp_setup_code_state function to do all the hard
work.  This function is slightly adjusted to accommodate native calls,
and the native emitter is forced a bit to emit similar prelude and
code-info as bytecode.
diff --git a/py/emitnative.c b/py/emitnative.c
index f72112b..ff57ef1 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -48,6 +48,7 @@
 
 #include "py/nlr.h"
 #include "py/emit.h"
+#include "py/bc.h"
 
 #if 0 // print debugging info
 #define DEBUG_PRINT (1)
@@ -70,11 +71,14 @@
 
 #define EXPORT_FUN(name) emit_native_x64_##name
 
+#define ASM_WORD_SIZE (8)
+
 #define REG_RET ASM_X64_REG_RAX
 #define REG_ARG_1 ASM_X64_REG_RDI
 #define REG_ARG_2 ASM_X64_REG_RSI
 #define REG_ARG_3 ASM_X64_REG_RDX
 #define REG_ARG_4 ASM_X64_REG_RCX
+#define REG_ARG_5 ASM_X64_REG_R08
 
 // caller-save
 #define REG_TEMP0 ASM_X64_REG_RAX
@@ -94,12 +98,16 @@
 #define ASM_NEW             asm_x64_new
 #define ASM_FREE            asm_x64_free
 #define ASM_GET_CODE        asm_x64_get_code
+#define ASM_GET_CODE_POS    asm_x64_get_code_pos
 #define ASM_GET_CODE_SIZE   asm_x64_get_code_size
 #define ASM_START_PASS      asm_x64_start_pass
 #define ASM_END_PASS        asm_x64_end_pass
 #define ASM_ENTRY           asm_x64_entry
 #define ASM_EXIT            asm_x64_exit
 
+#define ASM_ALIGN           asm_x64_align
+#define ASM_DATA            asm_x64_data
+
 #define ASM_LABEL_ASSIGN    asm_x64_label_assign
 #define ASM_JUMP            asm_x64_jmp_label
 #define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
@@ -202,14 +210,19 @@
     [MP_F_DELETE_GLOBAL] = 1,
     [MP_F_NEW_CELL] = 1,
     [MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3,
+    [MP_F_SETUP_CODE_STATE] = 5,
 };
 
 #define EXPORT_FUN(name) emit_native_x86_##name
 
+#define ASM_WORD_SIZE (4)
+
 #define REG_RET ASM_X86_REG_EAX
 #define REG_ARG_1 ASM_X86_REG_ARG_1
 #define REG_ARG_2 ASM_X86_REG_ARG_2
 #define REG_ARG_3 ASM_X86_REG_ARG_3
+#define REG_ARG_4 ASM_X86_REG_ARG_4
+#define REG_ARG_5 ASM_X86_REG_ARG_5
 
 // caller-save, so can be used as temporaries
 #define REG_TEMP0 ASM_X86_REG_EAX
@@ -229,12 +242,16 @@
 #define ASM_NEW             asm_x86_new
 #define ASM_FREE            asm_x86_free
 #define ASM_GET_CODE        asm_x86_get_code
+#define ASM_GET_CODE_POS    asm_x86_get_code_pos
 #define ASM_GET_CODE_SIZE   asm_x86_get_code_size
 #define ASM_START_PASS      asm_x86_start_pass
 #define ASM_END_PASS        asm_x86_end_pass
 #define ASM_ENTRY           asm_x86_entry
 #define ASM_EXIT            asm_x86_exit
 
+#define ASM_ALIGN           asm_x86_align
+#define ASM_DATA            asm_x86_data
+
 #define ASM_LABEL_ASSIGN    asm_x86_label_assign
 #define ASM_JUMP            asm_x86_jmp_label
 #define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
@@ -292,11 +309,14 @@
 
 #define EXPORT_FUN(name) emit_native_thumb_##name
 
+#define ASM_WORD_SIZE (4)
+
 #define REG_RET ASM_THUMB_REG_R0
 #define REG_ARG_1 ASM_THUMB_REG_R0
 #define REG_ARG_2 ASM_THUMB_REG_R1
 #define REG_ARG_3 ASM_THUMB_REG_R2
 #define REG_ARG_4 ASM_THUMB_REG_R3
+// rest of args go on stack
 
 #define REG_TEMP0 ASM_THUMB_REG_R0
 #define REG_TEMP1 ASM_THUMB_REG_R1
@@ -314,12 +334,16 @@
 #define ASM_NEW             asm_thumb_new
 #define ASM_FREE            asm_thumb_free
 #define ASM_GET_CODE        asm_thumb_get_code
+#define ASM_GET_CODE_POS    asm_thumb_get_code_pos
 #define ASM_GET_CODE_SIZE   asm_thumb_get_code_size
 #define ASM_START_PASS      asm_thumb_start_pass
 #define ASM_END_PASS        asm_thumb_end_pass
 #define ASM_ENTRY           asm_thumb_entry
 #define ASM_EXIT            asm_thumb_exit
 
+#define ASM_ALIGN           asm_thumb_align
+#define ASM_DATA            asm_thumb_data
+
 #define ASM_LABEL_ASSIGN    asm_thumb_label_assign
 #define ASM_JUMP            asm_thumb_b_label
 #define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
@@ -504,6 +528,10 @@
     stack_info_t *stack_info;
     vtype_kind_t saved_stack_vtype;
 
+    int code_info_size;
+    int code_info_offset;
+    int prelude_offset;
+    int n_state;
     int stack_start;
     int stack_size;
 
@@ -561,6 +589,8 @@
 STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num);
 STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num);
 
+#define STATE_START (sizeof(mp_code_state) / sizeof(mp_uint_t))
+
 STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
     DEBUG_printf("start_pass(pass=%u, scope=%p)\n", pass, scope);
 
@@ -584,14 +614,23 @@
         emit->stack_info = m_new(stack_info_t, emit->stack_info_alloc);
     }
 
-    // set default type for return and arguments
+    // set default type for return
     emit->return_vtype = VTYPE_PYOBJ;
-    for (mp_uint_t i = 0; i < emit->scope->num_pos_args; i++) {
+
+    // set default type for arguments
+    mp_uint_t num_args = emit->scope->num_pos_args + emit->scope->num_kwonly_args;
+    if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) {
+        num_args += 1;
+    }
+    if (scope->scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) {
+        num_args += 1;
+    }
+    for (mp_uint_t i = 0; i < num_args; i++) {
         emit->local_vtype[i] = VTYPE_PYOBJ;
     }
 
     // local variables begin unbound, and have unknown type
-    for (mp_uint_t i = emit->scope->num_pos_args; i < emit->local_vtype_alloc; i++) {
+    for (mp_uint_t i = num_args; i < emit->local_vtype_alloc; i++) {
         emit->local_vtype[i] = VTYPE_UNBOUND;
     }
 
@@ -603,107 +642,157 @@
 
     ASM_START_PASS(emit->as, pass == MP_PASS_EMIT ? ASM_PASS_EMIT : ASM_PASS_COMPUTE);
 
-    // entry to function
-    int num_locals = 0;
-    if (pass > MP_PASS_SCOPE) {
-        num_locals = scope->num_locals - REG_LOCAL_NUM;
-        if (num_locals < 0) {
-            num_locals = 0;
-        }
-        emit->stack_start = num_locals;
-        num_locals += scope->stack_size;
-    }
-    ASM_ENTRY(emit->as, num_locals);
+    // generate code for entry to function
 
-    // initialise locals from parameters
-#if N_X64
-    for (int i = 0; i < scope->num_pos_args; i++) {
-        if (i == 0) {
-            ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1);
-        } else if (i == 1) {
-            ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2);
-        } else if (i == 2) {
-            ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3);
-        } else if (i == 3) {
-            asm_x64_mov_r64_to_local(emit->as, REG_ARG_4, i - REG_LOCAL_NUM);
-        } else {
-            // TODO not implemented
-            assert(0);
+    if (emit->do_viper_types) {
+
+        // entry to function
+        int num_locals = 0;
+        if (pass > MP_PASS_SCOPE) {
+            num_locals = scope->num_locals - REG_LOCAL_NUM;
+            if (num_locals < 0) {
+                num_locals = 0;
+            }
+            emit->stack_start = num_locals;
+            num_locals += scope->stack_size;
         }
-    }
-#elif N_X86
-    for (int i = 0; i < scope->num_pos_args; i++) {
-        if (i == 0) {
-            asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_1);
-        } else if (i == 1) {
-            asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_2);
-        } else if (i == 2) {
-            asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_3);
-        } else {
-            asm_x86_mov_arg_to_r32(emit->as, i, REG_TEMP0);
-            asm_x86_mov_r32_to_local(emit->as, REG_TEMP0, i - REG_LOCAL_NUM);
+        ASM_ENTRY(emit->as, num_locals);
+
+        #if N_X86
+        for (int i = 0; i < scope->num_pos_args; i++) {
+            if (i == 0) {
+                asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_1);
+            } else if (i == 1) {
+                asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_2);
+            } else if (i == 2) {
+                asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_3);
+            } else {
+                asm_x86_mov_arg_to_r32(emit->as, i, REG_TEMP0);
+                asm_x86_mov_r32_to_local(emit->as, REG_TEMP0, i - REG_LOCAL_NUM);
+            }
         }
-    }
-#elif N_THUMB
-    for (int i = 0; i < scope->num_pos_args; i++) {
-        if (i == 0) {
-            ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1);
-        } else if (i == 1) {
-            ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2);
-        } else if (i == 2) {
-            ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3);
-        } else if (i == 3) {
-            asm_thumb_mov_local_reg(emit->as, i - REG_LOCAL_NUM, REG_ARG_4);
-        } else {
-            // TODO not implemented
-            assert(0);
+        #else
+        for (int i = 0; i < scope->num_pos_args; i++) {
+            if (i == 0) {
+                ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1);
+            } else if (i == 1) {
+                ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2);
+            } else if (i == 2) {
+                ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3);
+            } else if (i == 3) {
+                ASM_MOV_REG_TO_LOCAL(emit->as, REG_ARG_4, i - REG_LOCAL_NUM);
+            } else {
+                // TODO not implemented
+                assert(0);
+            }
+        }
+        #endif
+
+    } else {
+        // work out size of state (locals plus stack)
+        emit->n_state = scope->num_locals + scope->stack_size;
+
+        // allocate space on C-stack for code_state structure, which includes state
+        ASM_ENTRY(emit->as, STATE_START + emit->n_state);
+
+        // prepare incoming arguments for call to mp_setup_code_state
+        #if N_X86
+        asm_x86_mov_arg_to_r32(emit->as, 0, REG_ARG_2);
+        asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_3);
+        asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_4);
+        asm_x86_mov_arg_to_r32(emit->as, 3, REG_ARG_5);
+        #else
+        #if N_THUMB
+        ASM_MOV_REG_REG(emit->as, ASM_THUMB_REG_R4, REG_ARG_4);
+        #else
+        ASM_MOV_REG_REG(emit->as, REG_ARG_5, REG_ARG_4);
+        #endif
+        ASM_MOV_REG_REG(emit->as, REG_ARG_4, REG_ARG_3);
+        ASM_MOV_REG_REG(emit->as, REG_ARG_3, REG_ARG_2);
+        ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_ARG_1);
+        #endif
+
+        // set code_state.code_info (offset from start of this function to code_info data)
+        // XXX this encoding may change size
+        ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->code_info_offset, offsetof(mp_code_state, code_info) / sizeof(mp_uint_t), REG_ARG_1);
+
+        // set code_state.ip (offset from start of this function to prelude info)
+        // XXX this encoding may change size
+        ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->prelude_offset, offsetof(mp_code_state, ip) / sizeof(mp_uint_t), REG_ARG_1);
+
+        // set code_state.n_state
+        ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->n_state, offsetof(mp_code_state, n_state) / sizeof(mp_uint_t), REG_ARG_1);
+
+        // put address of code_state into first arg
+        ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, 0, REG_ARG_1);
+
+        // call mp_setup_code_state to prepare code_state structure
+        #if N_THUMB
+        asm_thumb_op16(emit->as, 0xb400 | (1 << ASM_THUMB_REG_R4)); // push 5th arg
+        asm_thumb_bl_ind(emit->as, mp_fun_table[MP_F_SETUP_CODE_STATE], MP_F_SETUP_CODE_STATE, ASM_THUMB_REG_R4);
+        asm_thumb_op16(emit->as, 0xbc00 | (1 << REG_RET)); // pop dummy (was 5th arg)
+        #else
+        ASM_CALL_IND(emit->as, mp_fun_table[MP_F_SETUP_CODE_STATE], MP_F_SETUP_CODE_STATE);
+        #endif
+
+        // cache some locals in registers
+        if (scope->num_locals > 0) {
+            ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 0, REG_LOCAL_1);
+            if (scope->num_locals > 1) {
+                ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 1, REG_LOCAL_2);
+                if (scope->num_locals > 2) {
+                    ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 2, REG_LOCAL_3);
+                }
+            }
+        }
+
+        // set the type of closed over variables
+        for (mp_uint_t i = 0; i < scope->id_info_len; i++) {
+            id_info_t *id = &scope->id_info[i];
+            if (id->kind == ID_INFO_KIND_CELL) {
+                emit->local_vtype[id->local_num] = VTYPE_PYOBJ;
+            }
         }
     }
 
+    #if N_THUMB
     // TODO don't load r7 if we don't need it
     asm_thumb_mov_reg_i32(emit->as, ASM_THUMB_REG_R7, (mp_uint_t)mp_fun_table);
-#elif N_ARM
-    for (int i = 0; i < scope->num_pos_args; i++) {
-        if (i == 0) {
-            ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1);
-        } else if (i == 1) {
-            ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2);
-        } else if (i == 2) {
-            ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3);
-        } else if (i == 3) {
-            asm_arm_mov_local_reg(emit->as, i - REG_LOCAL_NUM, REG_ARG_4);
-        } else {
-            // TODO not implemented
-            assert(0);
-        }
-    }
+    #endif
 
+    #if N_ARM
     // TODO don't load r7 if we don't need it
     asm_arm_mov_reg_i32(emit->as, ASM_ARM_REG_R7, (mp_uint_t)mp_fun_table);
-#else
-    #error not implemented
-#endif
-
-    // initialise closed over variables
-    for (int i = 0; i < scope->id_info_len; i++) {
-        id_info_t *id = &scope->id_info[i];
-        if (id->kind == ID_INFO_KIND_CELL) {
-            if (emit->local_vtype[id->local_num] != VTYPE_UNBOUND) {
-                emit_native_load_fast(emit, id->qst, id->local_num);
-                vtype_kind_t vtype;
-                emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
-            }
-            ASM_CALL_IND(emit->as, mp_fun_table[MP_F_NEW_CELL], MP_F_NEW_CELL);
-            emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
-            emit_native_store_fast(emit, id->qst, id->local_num);
-        }
-    }
+    #endif
 }
 
 STATIC void emit_native_end_pass(emit_t *emit) {
     if (!emit->last_emit_was_return_value) {
         ASM_EXIT(emit->as);
     }
+
+    if (!emit->do_viper_types) {
+        // write dummy code info (for mp_setup_code_state to parse) and arg names
+        emit->code_info_offset = ASM_GET_CODE_POS(emit->as);
+        ASM_DATA(emit->as, 1, emit->code_info_size);
+        ASM_ALIGN(emit->as, ASM_WORD_SIZE);
+        emit->code_info_size = ASM_GET_CODE_POS(emit->as) - emit->code_info_offset;
+        for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) {
+            ASM_DATA(emit->as, ASM_WORD_SIZE, (mp_uint_t)MP_OBJ_NEW_QSTR(emit->scope->id_info[i].qst));
+        }
+
+        // bytecode prelude: initialise closed over variables
+        emit->prelude_offset = ASM_GET_CODE_POS(emit->as);
+        for (int i = 0; i < emit->scope->id_info_len; i++) {
+            id_info_t *id = &emit->scope->id_info[i];
+            if (id->kind == ID_INFO_KIND_CELL) {
+                assert(id->local_num < 255);
+                ASM_DATA(emit->as, 1, id->local_num); // write the local which should be converted to a cell
+            }
+        }
+        ASM_DATA(emit->as, 1, 255); // end of list sentinel
+    }
+
     ASM_END_PASS(emit->as);
 
     // check stack is back to zero size
@@ -722,7 +811,10 @@
             type_sig |= (emit->local_vtype[i] & 3) << (i * 2 + 2);
         }
 
-        mp_emit_glue_assign_native(emit->scope->raw_code, emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY, f, f_len, emit->scope->num_pos_args, type_sig);
+        mp_emit_glue_assign_native(emit->scope->raw_code,
+            emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY,
+            f, f_len, emit->scope->num_pos_args, emit->scope->num_kwonly_args,
+            emit->scope->scope_flags, type_sig);
     }
 }
 
@@ -1199,7 +1291,6 @@
         printf("ViperTypeError: local %s used before type known\n", qstr_str(qst));
     }
     emit_native_pre(emit);
-#if N_X64
     if (local_num == 0) {
         emit_post_push_reg(emit, vtype, REG_LOCAL_1);
     } else if (local_num == 1) {
@@ -1208,48 +1299,13 @@
         emit_post_push_reg(emit, vtype, REG_LOCAL_3);
     } else {
         need_reg_single(emit, REG_TEMP0, 0);
-        asm_x64_mov_local_to_r64(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0);
+        if (emit->do_viper_types) {
+            ASM_MOV_LOCAL_TO_REG(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0);
+        } else {
+            ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - local_num, REG_TEMP0);
+        }
         emit_post_push_reg(emit, vtype, REG_TEMP0);
     }
-#elif N_X86
-    if (local_num == 0) {
-        emit_post_push_reg(emit, vtype, REG_LOCAL_1);
-    } else if (local_num == 1) {
-        emit_post_push_reg(emit, vtype, REG_LOCAL_2);
-    } else if (local_num == 2) {
-        emit_post_push_reg(emit, vtype, REG_LOCAL_3);
-    } else {
-        need_reg_single(emit, REG_TEMP0, 0);
-        asm_x86_mov_local_to_r32(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0);
-        emit_post_push_reg(emit, vtype, REG_TEMP0);
-    }
-#elif N_THUMB
-    if (local_num == 0) {
-        emit_post_push_reg(emit, vtype, REG_LOCAL_1);
-    } else if (local_num == 1) {
-        emit_post_push_reg(emit, vtype, REG_LOCAL_2);
-    } else if (local_num == 2) {
-        emit_post_push_reg(emit, vtype, REG_LOCAL_3);
-    } else {
-        need_reg_single(emit, REG_TEMP0, 0);
-        asm_thumb_mov_reg_local(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM);
-        emit_post_push_reg(emit, vtype, REG_TEMP0);
-    }
-#elif N_ARM
-    if (local_num == 0) {
-        emit_post_push_reg(emit, vtype, REG_LOCAL_1);
-    } else if (local_num == 1) {
-        emit_post_push_reg(emit, vtype, REG_LOCAL_2);
-    } else if (local_num == 2) {
-        emit_post_push_reg(emit, vtype, REG_LOCAL_3);
-    } else {
-        need_reg_single(emit, REG_TEMP0, 0);
-        asm_arm_mov_reg_local(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM);
-        emit_post_push_reg(emit, vtype, REG_TEMP0);
-    }
-#else
-    #error not implemented
-#endif
 }
 
 STATIC void emit_native_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
@@ -1417,7 +1473,6 @@
 
 STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
     vtype_kind_t vtype;
-#if N_X64
     if (local_num == 0) {
         emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1);
     } else if (local_num == 1) {
@@ -1426,45 +1481,12 @@
         emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3);
     } else {
         emit_pre_pop_reg(emit, &vtype, REG_TEMP0);
-        asm_x64_mov_r64_to_local(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM);
+        if (emit->do_viper_types) {
+            ASM_MOV_REG_TO_LOCAL(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM);
+        } else {
+            ASM_MOV_REG_TO_LOCAL(emit->as, REG_TEMP0, STATE_START + emit->n_state - 1 - local_num);
+        }
     }
-#elif N_X86
-    if (local_num == 0) {
-        emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1);
-    } else if (local_num == 1) {
-        emit_pre_pop_reg(emit, &vtype, REG_LOCAL_2);
-    } else if (local_num == 2) {
-        emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3);
-    } else {
-        emit_pre_pop_reg(emit, &vtype, REG_TEMP0);
-        asm_x86_mov_r32_to_local(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM);
-    }
-#elif N_THUMB
-    if (local_num == 0) {
-        emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1);
-    } else if (local_num == 1) {
-        emit_pre_pop_reg(emit, &vtype, REG_LOCAL_2);
-    } else if (local_num == 2) {
-        emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3);
-    } else {
-        emit_pre_pop_reg(emit, &vtype, REG_TEMP0);
-        asm_thumb_mov_local_reg(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0);
-    }
-#elif N_ARM
-    if (local_num == 0) {
-        emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1);
-    } else if (local_num == 1) {
-        emit_pre_pop_reg(emit, &vtype, REG_LOCAL_2);
-    } else if (local_num == 2) {
-        emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3);
-    } else {
-        emit_pre_pop_reg(emit, &vtype, REG_TEMP0);
-        asm_arm_mov_local_reg(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0);
-    }
-#else
-    #error not implemented
-#endif
-
     emit_post(emit);
 
     // check types