diff --git a/py/compile.c b/py/compile.c index 8a30518b33..7f96891027 100644 --- a/py/compile.c +++ b/py/compile.c @@ -2936,7 +2936,24 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind } } - assert(MP_PARSE_NODE_IS_NULL(pns->nodes[2])); // type + // pns->nodes[2] is function return annotation + mp_uint_t type_sig = MP_NATIVE_TYPE_INT; + mp_parse_node_t pn_annotation = pns->nodes[2]; + if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) { + // nodes[2] can be null or a test-expr + if (MP_PARSE_NODE_IS_ID(pn_annotation)) { + qstr ret_type = MP_PARSE_NODE_LEAF_ARG(pn_annotation); + switch (ret_type) { + case MP_QSTR_object: type_sig = MP_NATIVE_TYPE_OBJ; break; + case MP_QSTR_bool: type_sig = MP_NATIVE_TYPE_BOOL; break; + case MP_QSTR_int: type_sig = MP_NATIVE_TYPE_INT; break; + case MP_QSTR_uint: type_sig = MP_NATIVE_TYPE_UINT; break; + default: compile_syntax_error(comp, pn_annotation, "unknown type"); return; + } + } else { + compile_syntax_error(comp, pn_annotation, "return annotation must be an identifier"); + } + } mp_parse_node_t pn_body = pns->nodes[3]; // body mp_parse_node_t *nodes; @@ -3028,7 +3045,7 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind } if (comp->pass > MP_PASS_SCOPE) { - EMIT_INLINE_ASM(end_pass); + EMIT_INLINE_ASM_ARG(end_pass, type_sig); } if (comp->compile_error != MP_OBJ_NULL) { diff --git a/py/emit.h b/py/emit.h index 9d09ee2efa..7e8e03393d 100644 --- a/py/emit.h +++ b/py/emit.h @@ -268,7 +268,7 @@ typedef struct _emit_inline_asm_t emit_inline_asm_t; typedef struct _emit_inline_asm_method_table_t { void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope, mp_obj_t *error_slot); - void (*end_pass)(emit_inline_asm_t *emit); + void (*end_pass)(emit_inline_asm_t *emit, mp_uint_t type_sig); mp_uint_t (*count_params)(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params); bool (*label)(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id); void (*align)(emit_inline_asm_t *emit, mp_uint_t align); diff --git a/py/emitglue.c b/py/emitglue.c index 949a66ba9f..4157593ba3 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -162,7 +162,7 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp #endif #if MICROPY_EMIT_INLINE_THUMB case MP_CODE_NATIVE_ASM: - fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->data.u_native.fun_data); + fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->data.u_native.fun_data, rc->data.u_native.type_sig); break; #endif default: diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c index 317febe923..c31a931c25 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -84,13 +84,14 @@ STATIC void emit_inline_thumb_start_pass(emit_inline_asm_t *emit, pass_kind_t pa asm_thumb_entry(emit->as, 0); } -STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit) { +STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit, mp_uint_t type_sig) { asm_thumb_exit(emit->as); asm_thumb_end_pass(emit->as); if (emit->pass == MP_PASS_EMIT) { void *f = asm_thumb_get_code(emit->as); - mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), NULL, emit->scope->num_pos_args, 0, 0); + mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, + asm_thumb_get_code_size(emit->as), NULL, emit->scope->num_pos_args, 0, type_sig); } } diff --git a/py/nativeglue.c b/py/nativeglue.c index 3220996f95..cc0d61ce96 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -34,14 +34,14 @@ #include "py/emitglue.h" #include "py/bc.h" -#if MICROPY_EMIT_NATIVE - #if 0 // print debugging info #define DEBUG_printf DEBUG_printf #else // don't print debugging info #define DEBUG_printf(...) (void)0 #endif +#if MICROPY_EMIT_NATIVE + // convert a Micro Python object to a valid native value based on type mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type) { DEBUG_printf("mp_convert_obj_to_native(%p, " UINT_FMT ")\n", obj, type); @@ -61,6 +61,10 @@ mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type) { } } +#endif + +#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_THUMB + // convert a native value to a Micro Python object based on type mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type) { DEBUG_printf("mp_convert_native_to_obj(" UINT_FMT ", " UINT_FMT ")\n", val, type); @@ -73,6 +77,10 @@ mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type) { } } +#endif + +#if MICROPY_EMIT_NATIVE + // wrapper that accepts n_args and n_kw in one argument // (native emitter can only pass at most 3 arguments to a function) mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, mp_uint_t n_args_kw, const mp_obj_t *args) { diff --git a/py/obj.h b/py/obj.h index 14c3a81200..bfdceeb4e8 100644 --- a/py/obj.h +++ b/py/obj.h @@ -625,7 +625,7 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code, const mp_uint_t *const_table); mp_obj_t mp_obj_new_fun_native(mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data, const mp_uint_t *const_table); mp_obj_t mp_obj_new_fun_viper(mp_uint_t n_args, void *fun_data, mp_uint_t type_sig); -mp_obj_t mp_obj_new_fun_asm(mp_uint_t n_args, void *fun_data); +mp_obj_t mp_obj_new_fun_asm(mp_uint_t n_args, void *fun_data, mp_uint_t type_sig); mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun); mp_obj_t mp_obj_new_closure(mp_obj_t fun, mp_uint_t n_closed, const mp_obj_t *closed); mp_obj_t mp_obj_new_tuple(mp_uint_t n, const mp_obj_t *items); diff --git a/py/objfun.c b/py/objfun.c index f2cc34fad6..df7d162133 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -452,6 +452,7 @@ typedef struct _mp_obj_fun_asm_t { mp_obj_base_t base; mp_uint_t n_args; void *fun_data; // GC must be able to trace this pointer + mp_uint_t type_sig; } mp_obj_fun_asm_t; typedef mp_uint_t (*inline_asm_fun_0_t)(void); @@ -509,11 +510,6 @@ STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { } } -// convert a return value from inline asm to a sensible Micro Python object -STATIC mp_obj_t convert_val_from_inline_asm(mp_uint_t val) { - return MP_OBJ_NEW_SMALL_INT(val); -} - STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_obj_fun_asm_t *self = self_in; @@ -535,7 +531,7 @@ STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const ret = 0; } - return convert_val_from_inline_asm(ret); + return mp_convert_native_to_obj(ret, self->type_sig); } STATIC const mp_obj_type_t mp_type_fun_asm = { @@ -545,11 +541,12 @@ STATIC const mp_obj_type_t mp_type_fun_asm = { .unary_op = mp_generic_unary_op, }; -mp_obj_t mp_obj_new_fun_asm(mp_uint_t n_args, void *fun_data) { +mp_obj_t mp_obj_new_fun_asm(mp_uint_t n_args, void *fun_data, mp_uint_t type_sig) { mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t); o->base.type = &mp_type_fun_asm; o->n_args = n_args; o->fun_data = fun_data; + o->type_sig = type_sig; return o; } diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 122fca128b..bf774e036b 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -113,6 +113,7 @@ Q(asm_thumb) Q(label) Q(align) Q(data) +Q(uint) #endif Q(builtins) diff --git a/tests/inlineasm/asmrettype.py b/tests/inlineasm/asmrettype.py new file mode 100644 index 0000000000..f1918696ee --- /dev/null +++ b/tests/inlineasm/asmrettype.py @@ -0,0 +1,21 @@ +# test return type of inline asm + +@micropython.asm_thumb +def ret_obj(r0) -> object: + pass +ret_obj(print)(1) + +@micropython.asm_thumb +def ret_bool(r0) -> bool: + pass +print(ret_bool(0), ret_bool(1)) + +@micropython.asm_thumb +def ret_int(r0) -> int: + lsl(r0, r0, 29) +print(ret_int(0), hex(ret_int(1)), hex(ret_int(2)), hex(ret_int(4))) + +@micropython.asm_thumb +def ret_uint(r0) -> uint: + lsl(r0, r0, 29) +print(ret_uint(0), hex(ret_uint(1)), hex(ret_uint(2)), hex(ret_uint(4))) diff --git a/tests/inlineasm/asmrettype.py.exp b/tests/inlineasm/asmrettype.py.exp new file mode 100644 index 0000000000..cbb49d2472 --- /dev/null +++ b/tests/inlineasm/asmrettype.py.exp @@ -0,0 +1,4 @@ +1 +False True +0 0x20000000 0x40000000 -0x80000000 +0 0x20000000 0x40000000 0x80000000