From a210c774f9cfbcde284f5b8a63442b4d6da1ae5b Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 26 Mar 2015 15:49:53 +0000 Subject: [PATCH] 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. --- py/compile.c | 40 +++++++++----- py/emit.h | 9 ++-- py/emitbc.c | 17 +++++- py/emitcpy.c | 23 ++++++-- py/emitpass1.c | 142 ------------------------------------------------- py/py.mk | 1 - 6 files changed, 69 insertions(+), 163 deletions(-) delete mode 100644 py/emitpass1.c diff --git a/py/compile.c b/py/compile.c index 4b78b7f37c..a41851c3a1 100644 --- a/py/compile.c +++ b/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); diff --git a/py/emit.h b/py/emit.h index 47ef16256d..33eccda2c2 100644 --- a/py/emit.h +++ b/py/emit.h @@ -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); diff --git a/py/emitbc.c b/py/emitbc.c index 53437a8f86..52e10130c4 100644 --- a/py/emitbc.c +++ b/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 diff --git a/py/emitcpy.c b/py/emitcpy.c index 0e040b0e9e..48c293091c 100644 --- a/py/emitcpy.c +++ b/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 diff --git a/py/emitpass1.c b/py/emitpass1.c deleted file mode 100644 index 995aceddef..0000000000 --- a/py/emitpass1.c +++ /dev/null @@ -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 - -#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 -}; diff --git a/py/py.mk b/py/py.mk index 6227ad9eb4..e120f8be4a 100644 --- a/py/py.mk +++ b/py/py.mk @@ -31,7 +31,6 @@ PY_O_BASENAME = \ scope.o \ compile.o \ emitcommon.o \ - emitpass1.o \ emitcpy.o \ emitbc.o \ asmx64.o \