py/inlineasm: Add ability to specify return type of asm_thumb funcs.
Supported return types are: object, bool, int, uint. For example: @micropython.asm_thumb def foo(r0, r1) -> uint: add(r0, r0, r1)
This commit is contained in:
parent
3d42aa07dd
commit
8f54c08691
21
py/compile.c
21
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 pn_body = pns->nodes[3]; // body
|
||||||
mp_parse_node_t *nodes;
|
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) {
|
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) {
|
if (comp->compile_error != MP_OBJ_NULL) {
|
||||||
|
|
|
@ -268,7 +268,7 @@ typedef struct _emit_inline_asm_t emit_inline_asm_t;
|
||||||
|
|
||||||
typedef struct _emit_inline_asm_method_table_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 (*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);
|
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);
|
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);
|
void (*align)(emit_inline_asm_t *emit, mp_uint_t align);
|
||||||
|
|
|
@ -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
|
#endif
|
||||||
#if MICROPY_EMIT_INLINE_THUMB
|
#if MICROPY_EMIT_INLINE_THUMB
|
||||||
case MP_CODE_NATIVE_ASM:
|
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;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -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);
|
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_exit(emit->as);
|
||||||
asm_thumb_end_pass(emit->as);
|
asm_thumb_end_pass(emit->as);
|
||||||
|
|
||||||
if (emit->pass == MP_PASS_EMIT) {
|
if (emit->pass == MP_PASS_EMIT) {
|
||||||
void *f = asm_thumb_get_code(emit->as);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,14 +34,14 @@
|
||||||
#include "py/emitglue.h"
|
#include "py/emitglue.h"
|
||||||
#include "py/bc.h"
|
#include "py/bc.h"
|
||||||
|
|
||||||
#if MICROPY_EMIT_NATIVE
|
|
||||||
|
|
||||||
#if 0 // print debugging info
|
#if 0 // print debugging info
|
||||||
#define DEBUG_printf DEBUG_printf
|
#define DEBUG_printf DEBUG_printf
|
||||||
#else // don't print debugging info
|
#else // don't print debugging info
|
||||||
#define DEBUG_printf(...) (void)0
|
#define DEBUG_printf(...) (void)0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MICROPY_EMIT_NATIVE
|
||||||
|
|
||||||
// convert a Micro Python object to a valid native value based on type
|
// 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) {
|
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);
|
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
|
// 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) {
|
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);
|
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
|
// wrapper that accepts n_args and n_kw in one argument
|
||||||
// (native emitter can only pass at most 3 arguments to a function)
|
// (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) {
|
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) {
|
||||||
|
|
2
py/obj.h
2
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_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_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_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_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_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);
|
mp_obj_t mp_obj_new_tuple(mp_uint_t n, const mp_obj_t *items);
|
||||||
|
|
11
py/objfun.c
11
py/objfun.c
|
@ -452,6 +452,7 @@ typedef struct _mp_obj_fun_asm_t {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
mp_uint_t n_args;
|
mp_uint_t n_args;
|
||||||
void *fun_data; // GC must be able to trace this pointer
|
void *fun_data; // GC must be able to trace this pointer
|
||||||
|
mp_uint_t type_sig;
|
||||||
} mp_obj_fun_asm_t;
|
} mp_obj_fun_asm_t;
|
||||||
|
|
||||||
typedef mp_uint_t (*inline_asm_fun_0_t)(void);
|
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) {
|
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;
|
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;
|
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 = {
|
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,
|
.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);
|
mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t);
|
||||||
o->base.type = &mp_type_fun_asm;
|
o->base.type = &mp_type_fun_asm;
|
||||||
o->n_args = n_args;
|
o->n_args = n_args;
|
||||||
o->fun_data = fun_data;
|
o->fun_data = fun_data;
|
||||||
|
o->type_sig = type_sig;
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,7 @@ Q(asm_thumb)
|
||||||
Q(label)
|
Q(label)
|
||||||
Q(align)
|
Q(align)
|
||||||
Q(data)
|
Q(data)
|
||||||
|
Q(uint)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Q(builtins)
|
Q(builtins)
|
||||||
|
|
|
@ -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)))
|
|
@ -0,0 +1,4 @@
|
||||||
|
1
|
||||||
|
False True
|
||||||
|
0 0x20000000 0x40000000 -0x80000000
|
||||||
|
0 0x20000000 0x40000000 0x80000000
|
Loading…
Reference in New Issue