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:
Damien George 2015-03-26 15:49:53 +00:00
parent 542bd6b4a1
commit a210c774f9
6 changed files with 69 additions and 163 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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
};

View File

@ -31,7 +31,6 @@ PY_O_BASENAME = \
scope.o \
compile.o \
emitcommon.o \
emitpass1.o \
emitcpy.o \
emitbc.o \
asmx64.o \