Skip to content

Commit 39bf055

Browse files
committed
py/emitglue: Reorder and resize members of mp_raw_code_t.
The mp_raw_code_t struct has been reordered and some members resized. The `n_pos_args` member is renamed to `asm_n_pos_args`, and `type_sig` renamed to `asm_type_sig` to indicate that these are used only for the inline-asm emitters. These two members are also grouped together in the struct. The justifications for resizing the members are: - `fun_data_len` can be 32-bits without issue - `n_children` is already limited to 16-bits by `mp_emit_common_t::ct_cur_child` - `scope_flags` is already limited to 16-bits by `scope_t::scope_flags` - `prelude_offset` is already limited to 16-bits by the argument to `mp_emit_glue_assign_native()` - it's reasonable to limit the maximim number of inline-asm arguments to 12 (24 bits for `asm_type_sig` divided by 2) This change helps to reduce frozen code size (and in some cases RAM usage) in the following cases: - 64-bit targets - builds with MICROPY_PY_SYS_SETTRACE enabled - builds with MICROPY_EMIT_MACHINE_CODE enabled but MICROPY_EMIT_INLINE_ASM disabled With this change, unix 64-bit builds are -4080 bytes in size. Bare-metal ports like rp2 are unchanged (because mp_raw_code_t is still 32 bytes on those 32-bit targets). Signed-off-by: Damien George <damien@micropython.org>
1 parent 223e0d9 commit 39bf055

4 files changed

Lines changed: 45 additions & 36 deletions

File tree

py/emitglue.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code,
6666
#endif
6767
mp_raw_code_t **children,
6868
#if MICROPY_PERSISTENT_CODE_SAVE
69-
size_t n_children,
69+
uint16_t n_children,
7070
#endif
71-
mp_uint_t scope_flags) {
71+
uint16_t scope_flags) {
7272

7373
rc->kind = MP_CODE_BYTECODE;
7474
rc->scope_flags = scope_flags;
@@ -99,10 +99,11 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code,
9999
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len,
100100
mp_raw_code_t **children,
101101
#if MICROPY_PERSISTENT_CODE_SAVE
102-
size_t n_children,
102+
uint16_t n_children,
103103
uint16_t prelude_offset,
104104
#endif
105-
mp_uint_t scope_flags, mp_uint_t n_pos_args, mp_uint_t type_sig) {
105+
uint16_t scope_flags, uint32_t asm_n_pos_args, uint32_t asm_type_sig
106+
) {
106107

107108
assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM);
108109

@@ -145,9 +146,11 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
145146
rc->prelude_offset = prelude_offset;
146147
#endif
147148

149+
#if MICROPY_EMIT_INLINE_ASM
148150
// These two entries are only needed for MP_CODE_NATIVE_ASM.
149-
rc->n_pos_args = n_pos_args;
150-
rc->type_sig = type_sig;
151+
rc->asm_n_pos_args = asm_n_pos_args;
152+
rc->asm_type_sig = asm_type_sig;
153+
#endif
151154

152155
#if DEBUG_PRINT
153156
DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " flags=%x\n", kind, fun_data, fun_len, n_pos_args, (uint)scope_flags);
@@ -195,7 +198,7 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, const mp_module
195198
#endif
196199
#if MICROPY_EMIT_INLINE_ASM
197200
case MP_CODE_NATIVE_ASM:
198-
fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->fun_data, rc->type_sig);
201+
fun = mp_obj_new_fun_asm(rc->asm_n_pos_args, rc->fun_data, rc->asm_type_sig);
199202
break;
200203
#endif
201204
default:

py/emitglue.h

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,34 +49,38 @@ typedef enum {
4949
MP_CODE_NATIVE_ASM,
5050
} mp_raw_code_kind_t;
5151

52+
// This mp_raw_code_t struct holds static information about a non-instantiated function.
53+
// A function object is created from this information, and that object can then be executed.
54+
//
55+
// This struct appears in the following places:
5256
// compiled bytecode: instance in RAM, referenced by outer scope, usually freed after first (and only) use
5357
// mpy file: instance in RAM, created when .mpy file is loaded (same comments as above)
5458
// frozen: instance in ROM
5559
typedef struct _mp_raw_code_t {
56-
mp_uint_t kind : 3; // of type mp_raw_code_kind_t
57-
mp_uint_t scope_flags : 7;
58-
mp_uint_t n_pos_args : 11;
60+
uint32_t kind : 3; // of type mp_raw_code_kind_t
61+
uint32_t scope_flags : 7;
5962
const void *fun_data;
63+
struct _mp_raw_code_t **children;
6064
#if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS
61-
size_t fun_data_len; // so mp_raw_code_save and mp_bytecode_print work
65+
uint32_t fun_data_len; // so mp_raw_code_save and mp_bytecode_print work
6266
#endif
63-
struct _mp_raw_code_t **children;
6467
#if MICROPY_PERSISTENT_CODE_SAVE
65-
size_t n_children;
68+
uint16_t n_children;
69+
#if MICROPY_EMIT_MACHINE_CODE
70+
uint16_t prelude_offset;
71+
#endif
6672
#if MICROPY_PY_SYS_SETTRACE
67-
mp_bytecode_prelude_t prelude;
6873
// line_of_definition is a Python source line where the raw_code was
6974
// created e.g. MP_BC_MAKE_FUNCTION. This is different from lineno info
7075
// stored in prelude, which provides line number for first statement of
7176
// a function. Required to properly implement "call" trace event.
72-
mp_uint_t line_of_definition;
73-
#endif
74-
#if MICROPY_EMIT_MACHINE_CODE
75-
uint16_t prelude_offset;
77+
uint32_t line_of_definition;
78+
mp_bytecode_prelude_t prelude;
7679
#endif
7780
#endif
78-
#if MICROPY_EMIT_MACHINE_CODE
79-
mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc
81+
#if MICROPY_EMIT_INLINE_ASM
82+
uint32_t asm_n_pos_args : 8;
83+
uint32_t asm_type_sig : 24; // compressed as 2-bit types; ret is MSB, then arg0, arg1, etc
8084
#endif
8185
} mp_raw_code_t;
8286

@@ -88,17 +92,17 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code,
8892
#endif
8993
mp_raw_code_t **children,
9094
#if MICROPY_PERSISTENT_CODE_SAVE
91-
size_t n_children,
95+
uint16_t n_children,
9296
#endif
93-
mp_uint_t scope_flags);
97+
uint16_t scope_flags);
9498

9599
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len,
96100
mp_raw_code_t **children,
97101
#if MICROPY_PERSISTENT_CODE_SAVE
98-
size_t n_children,
102+
uint16_t n_children,
99103
uint16_t prelude_offset,
100104
#endif
101-
mp_uint_t scope_flags, mp_uint_t n_pos_args, mp_uint_t type_sig);
105+
uint16_t scope_flags, uint32_t asm_n_pos_args, uint32_t asm_type_sig);
102106

103107
mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, const mp_module_context_t *context, const mp_obj_t *def_args);
104108
mp_obj_t mp_make_closure_from_raw_code(const mp_raw_code_t *rc, const mp_module_context_t *context, mp_uint_t n_closed_over, const mp_obj_t *args);

py/persistentcode.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -578,10 +578,12 @@ STATIC void save_raw_code(mp_print_t *print, const mp_raw_code_t *rc) {
578578
} else if (rc->kind == MP_CODE_NATIVE_VIPER || rc->kind == MP_CODE_NATIVE_ASM) {
579579
// Save basic scope info for viper and asm
580580
mp_print_uint(print, rc->scope_flags & MP_SCOPE_FLAG_ALL_SIG);
581+
#if MICROPY_EMIT_INLINE_ASM
581582
if (rc->kind == MP_CODE_NATIVE_ASM) {
582-
mp_print_uint(print, rc->n_pos_args);
583-
mp_print_uint(print, rc->type_sig);
583+
mp_print_uint(print, rc->asm_n_pos_args);
584+
mp_print_uint(print, rc->asm_type_sig);
584585
}
586+
#endif
585587
}
586588
#endif
587589

tools/mpy-tool.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -909,21 +909,24 @@ def freeze_raw_code(self, prelude_ptr=None, type_sig=0):
909909
print("static const mp_raw_code_t raw_code_%s = {" % self.escaped_name)
910910
print(" .kind = %s," % RawCode.code_kind_str[self.code_kind])
911911
print(" .scope_flags = 0x%02x," % self.scope_flags)
912-
print(" .n_pos_args = %u," % self.n_pos_args)
913912
print(" .fun_data = fun_data_%s," % self.escaped_name)
914-
print(" #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS")
915-
print(" .fun_data_len = %u," % len(self.fun_data))
916-
print(" #endif")
917913
if len(self.children):
918914
print(" .children = (void *)&children_%s," % self.escaped_name)
919915
elif prelude_ptr:
920916
print(" .children = (void *)%s," % prelude_ptr)
921917
else:
922918
print(" .children = NULL,")
919+
print(" #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS")
920+
print(" .fun_data_len = %u," % len(self.fun_data))
921+
print(" #endif")
923922
print(" #if MICROPY_PERSISTENT_CODE_SAVE")
924923
print(" .n_children = %u," % len(self.children))
924+
print(" #if MICROPY_EMIT_MACHINE_CODE")
925+
print(" .prelude_offset = %u," % self.prelude_offset)
926+
print(" #endif")
925927
if self.code_kind == MP_CODE_BYTECODE:
926928
print(" #if MICROPY_PY_SYS_SETTRACE")
929+
print(" .line_of_definition = %u," % 0) # TODO
927930
print(" .prelude = {")
928931
print(" .n_state = %u," % self.prelude_signature[0])
929932
print(" .n_exc_stack = %u," % self.prelude_signature[1])
@@ -944,14 +947,11 @@ def freeze_raw_code(self, prelude_ptr=None, type_sig=0):
944947
" .opcodes = fun_data_%s + %u," % (self.escaped_name, self.offset_opcodes)
945948
)
946949
print(" },")
947-
print(" .line_of_definition = %u," % 0) # TODO
948950
print(" #endif")
949-
print(" #if MICROPY_EMIT_MACHINE_CODE")
950-
print(" .prelude_offset = %u," % self.prelude_offset)
951-
print(" #endif")
952951
print(" #endif")
953-
print(" #if MICROPY_EMIT_MACHINE_CODE")
954-
print(" .type_sig = %u," % type_sig)
952+
print(" #if MICROPY_EMIT_INLINE_ASM")
953+
print(" .asm_n_pos_args = %u," % self.n_pos_args)
954+
print(" .asm_type_sig = %u," % type_sig)
955955
print(" #endif")
956956
print("};")
957957

0 commit comments

Comments
 (0)