py, compiler: Remove emit_pass1 code, using emit_bc to do its job.
First pass for the compiler is computing the scope (eg if an identifier is local or not) and originally had an entire table of methods dedicated to this, most of which did nothing. With changes from previous commit, this set of methods can be removed and the methods from the bytecode emitter used instead, with very little modification -- this is what is done in this commit. This factoring has little to no impact on the speed of the compiler (tested by compiling 3763 Python scripts and timing it). This factoring reduces code size by about 270-300 bytes on Thumb2 archs, and 400 bytes on x86.
This commit is contained in:
parent
542bd6b4a1
commit
a210c774f9
40
py/compile.c
40
py/compile.c
|
@ -3647,9 +3647,21 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
|||
module_scope->pn = fold_constants(comp, module_scope->pn, &consts);
|
||||
mp_map_deinit(&consts);
|
||||
|
||||
// create standard emitter; it's used at least for MP_PASS_SCOPE
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
emit_t *emit_cpython = emit_cpython_new();
|
||||
#else
|
||||
emit_t *emit_bc = emit_bc_new();
|
||||
#endif
|
||||
|
||||
// compile pass 1
|
||||
comp->emit = NULL;
|
||||
comp->emit_method_table = &emit_pass1_method_table;
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
comp->emit = emit_cpython;
|
||||
comp->emit_method_table = &emit_cpython_method_table;
|
||||
#else
|
||||
comp->emit = emit_bc;
|
||||
comp->emit_method_table = &emit_bc_method_table;
|
||||
#endif
|
||||
#if MICROPY_EMIT_INLINE_THUMB
|
||||
comp->emit_inline_asm = NULL;
|
||||
comp->emit_inline_asm_method_table = NULL;
|
||||
|
@ -3676,9 +3688,15 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
|||
scope_compute_things(s);
|
||||
}
|
||||
|
||||
// set max number of labels now that it's calculated
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
emit_cpython_set_max_num_labels(emit_cpython, max_num_labels);
|
||||
#else
|
||||
emit_bc_set_max_num_labels(emit_bc, max_num_labels);
|
||||
#endif
|
||||
|
||||
// compile pass 2 and 3
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
emit_t *emit_bc = NULL;
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
emit_t *emit_native = NULL;
|
||||
#endif
|
||||
|
@ -3711,7 +3729,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
|||
// choose the emit type
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
comp->emit = emit_cpython_new(max_num_labels);
|
||||
comp->emit = emit_cpython;
|
||||
comp->emit_method_table = &emit_cpython_method_table;
|
||||
#else
|
||||
switch (s->emit_options) {
|
||||
|
@ -3746,9 +3764,6 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
|||
#endif // MICROPY_EMIT_NATIVE
|
||||
|
||||
default:
|
||||
if (emit_bc == NULL) {
|
||||
emit_bc = emit_bc_new(max_num_labels);
|
||||
}
|
||||
comp->emit = emit_bc;
|
||||
comp->emit_method_table = &emit_bc_method_table;
|
||||
break;
|
||||
|
@ -3771,10 +3786,11 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
|||
}
|
||||
|
||||
// free the emitters
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
if (emit_bc != NULL) {
|
||||
emit_bc_free(emit_bc);
|
||||
}
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
emit_cpython_free(emit_cpython);
|
||||
#else
|
||||
emit_bc_free(emit_bc);
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
if (emit_native != NULL) {
|
||||
#if MICROPY_EMIT_X64
|
||||
|
@ -3793,7 +3809,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
|||
emit_inline_thumb_free(emit_inline_thumb);
|
||||
}
|
||||
#endif
|
||||
#endif // !MICROPY_EMIT_CPYTHON
|
||||
#endif // MICROPY_EMIT_CPYTHON
|
||||
|
||||
// free the parse tree
|
||||
mp_parse_node_free(module_scope->pn);
|
||||
|
|
|
@ -159,7 +159,6 @@ void mp_emit_common_get_id_for_load(scope_t *scope, qstr qst);
|
|||
void mp_emit_common_get_id_for_modification(scope_t *scope, qstr qst);
|
||||
void mp_emit_common_id_op(emit_t *emit, const mp_emit_method_table_id_ops_t *emit_method_table, scope_t *scope, qstr qst);
|
||||
|
||||
extern const emit_method_table_t emit_pass1_method_table;
|
||||
extern const emit_method_table_t emit_cpython_method_table;
|
||||
extern const emit_method_table_t emit_bc_method_table;
|
||||
extern const emit_method_table_t emit_native_x64_method_table;
|
||||
|
@ -167,13 +166,17 @@ extern const emit_method_table_t emit_native_x86_method_table;
|
|||
extern const emit_method_table_t emit_native_thumb_method_table;
|
||||
extern const emit_method_table_t emit_native_arm_method_table;
|
||||
|
||||
emit_t *emit_cpython_new(mp_uint_t max_num_labels);
|
||||
emit_t *emit_bc_new(mp_uint_t max_num_labels);
|
||||
emit_t *emit_cpython_new(void);
|
||||
emit_t *emit_bc_new(void);
|
||||
emit_t *emit_native_x64_new(mp_uint_t max_num_labels);
|
||||
emit_t *emit_native_x86_new(mp_uint_t max_num_labels);
|
||||
emit_t *emit_native_thumb_new(mp_uint_t max_num_labels);
|
||||
emit_t *emit_native_arm_new(mp_uint_t max_num_labels);
|
||||
|
||||
void emit_cpython_set_max_num_labels(emit_t* emit, mp_uint_t max_num_labels);
|
||||
void emit_bc_set_max_num_labels(emit_t* emit, mp_uint_t max_num_labels);
|
||||
|
||||
void emit_cpython_free(emit_t *emit);
|
||||
void emit_bc_free(emit_t *emit);
|
||||
void emit_native_x64_free(emit_t *emit);
|
||||
void emit_native_x86_free(emit_t *emit);
|
||||
|
|
17
py/emitbc.c
17
py/emitbc.c
|
@ -65,11 +65,14 @@ struct _emit_t {
|
|||
STATIC void emit_bc_rot_two(emit_t *emit);
|
||||
STATIC void emit_bc_rot_three(emit_t *emit);
|
||||
|
||||
emit_t *emit_bc_new(mp_uint_t max_num_labels) {
|
||||
emit_t *emit_bc_new(void) {
|
||||
emit_t *emit = m_new0(emit_t, 1);
|
||||
return emit;
|
||||
}
|
||||
|
||||
void emit_bc_set_max_num_labels(emit_t* emit, mp_uint_t max_num_labels) {
|
||||
emit->max_num_labels = max_num_labels;
|
||||
emit->label_offsets = m_new(mp_uint_t, emit->max_num_labels);
|
||||
return emit;
|
||||
}
|
||||
|
||||
void emit_bc_free(emit_t *emit) {
|
||||
|
@ -338,6 +341,10 @@ STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
|||
}
|
||||
|
||||
STATIC void emit_bc_end_pass(emit_t *emit) {
|
||||
if (emit->pass == MP_PASS_SCOPE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check stack is back to zero size
|
||||
if (emit->stack_size != 0) {
|
||||
printf("ERROR: stack size not back to zero; got %d\n", emit->stack_size);
|
||||
|
@ -403,6 +410,9 @@ STATIC void emit_bc_set_source_line(emit_t *emit, mp_uint_t source_line) {
|
|||
}
|
||||
|
||||
STATIC void emit_bc_pre(emit_t *emit, mp_int_t stack_size_delta) {
|
||||
if (emit->pass == MP_PASS_SCOPE) {
|
||||
return;
|
||||
}
|
||||
assert((mp_int_t)emit->stack_size + stack_size_delta >= 0);
|
||||
emit->stack_size += stack_size_delta;
|
||||
if (emit->stack_size > emit->scope->stack_size) {
|
||||
|
@ -413,6 +423,9 @@ STATIC void emit_bc_pre(emit_t *emit, mp_int_t stack_size_delta) {
|
|||
|
||||
STATIC void emit_bc_label_assign(emit_t *emit, mp_uint_t l) {
|
||||
emit_bc_pre(emit, 0);
|
||||
if (emit->pass == MP_PASS_SCOPE) {
|
||||
return;
|
||||
}
|
||||
assert(l < emit->max_num_labels);
|
||||
if (emit->pass < MP_PASS_EMIT) {
|
||||
// assign label offset
|
||||
|
|
23
py/emitcpy.c
23
py/emitcpy.c
|
@ -47,11 +47,19 @@ struct _emit_t {
|
|||
mp_uint_t *label_offsets;
|
||||
};
|
||||
|
||||
emit_t *emit_cpython_new(mp_uint_t max_num_labels) {
|
||||
emit_t *emit = m_new(emit_t, 1);
|
||||
emit_t *emit_cpython_new(void) {
|
||||
emit_t *emit = m_new0(emit_t, 1);
|
||||
return emit;
|
||||
}
|
||||
|
||||
void emit_cpython_set_max_num_labels(emit_t* emit, mp_uint_t max_num_labels) {
|
||||
emit->max_num_labels = max_num_labels;
|
||||
emit->label_offsets = m_new(mp_uint_t, max_num_labels);
|
||||
return emit;
|
||||
}
|
||||
|
||||
void emit_cpython_free(emit_t *emit) {
|
||||
m_del(mp_uint_t, emit->label_offsets, emit->max_num_labels);
|
||||
m_del_obj(emit_t, emit);
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
|
||||
|
@ -69,6 +77,9 @@ STATIC void emit_cpy_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope)
|
|||
}
|
||||
|
||||
STATIC void emit_cpy_end_pass(emit_t *emit) {
|
||||
if (emit->pass == MP_PASS_SCOPE) {
|
||||
return;
|
||||
}
|
||||
// check stack is back to zero size
|
||||
if (emit->stack_size != 0) {
|
||||
printf("ERROR: stack size not back to zero; got %d\n", emit->stack_size);
|
||||
|
@ -88,6 +99,9 @@ STATIC void emit_cpy_set_source_line(emit_t *emit, mp_uint_t source_line) {
|
|||
|
||||
// TODO: module-polymorphic function (read: name clash if made global)
|
||||
static void emit_pre(emit_t *emit, int stack_size_delta, int bytecode_size) {
|
||||
if (emit->pass == MP_PASS_SCOPE) {
|
||||
return;
|
||||
}
|
||||
emit->stack_size += stack_size_delta;
|
||||
if (emit->stack_size > emit->scope->stack_size) {
|
||||
emit->scope->stack_size = emit->stack_size;
|
||||
|
@ -105,6 +119,9 @@ static void emit_pre(emit_t *emit, int stack_size_delta, int bytecode_size) {
|
|||
|
||||
STATIC void emit_cpy_label_assign(emit_t *emit, mp_uint_t l) {
|
||||
emit_pre(emit, 0, 0);
|
||||
if (emit->pass == MP_PASS_SCOPE) {
|
||||
return;
|
||||
}
|
||||
assert(l < emit->max_num_labels);
|
||||
if (emit->pass < MP_PASS_EMIT) {
|
||||
// assign label offset
|
||||
|
|
142
py/emitpass1.c
142
py/emitpass1.c
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "py/emit.h"
|
||||
|
||||
STATIC void emit_pass1_dummy(emit_t *emit) {
|
||||
(void)emit;
|
||||
}
|
||||
|
||||
STATIC void emit_pass1_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
assert(pass == MP_PASS_SCOPE);
|
||||
}
|
||||
|
||||
STATIC bool emit_pass1_last_emit_was_return_value(emit_t *emit) {
|
||||
(void)emit;
|
||||
return false;
|
||||
}
|
||||
|
||||
const emit_method_table_t emit_pass1_method_table = {
|
||||
(void*)emit_pass1_dummy,
|
||||
emit_pass1_start_pass,
|
||||
emit_pass1_dummy,
|
||||
emit_pass1_last_emit_was_return_value,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
|
||||
{
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
},
|
||||
{
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
},
|
||||
{
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
},
|
||||
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
#if MICROPY_PY_BUILTINS_SET
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
#endif
|
||||
#if MICROPY_PY_BUILTINS_SLICE
|
||||
(void*)emit_pass1_dummy,
|
||||
#endif
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
#endif
|
||||
};
|
Loading…
Reference in New Issue