X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fbegnuas.c;h=0b8ae0a2c87f96eaafe1d383ad54d3a54dd4a4d8;hb=9276447aec4972df060349e162f583c4898dfec8;hp=2fa023a6d2ece8a4f4a101aa8c9e74483d8da869;hpb=2adf84106c02caf097c2d6cf1764706bdc437bcc;p=libfirm diff --git a/ir/be/begnuas.c b/ir/be/begnuas.c index 2fa023a6d..0b8ae0a2c 100644 --- a/ir/be/begnuas.c +++ b/ir/be/begnuas.c @@ -1,8 +1,28 @@ +/* + * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved. + * + * This file is part of libFirm. + * + * This file may be distributed and/or modified under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation and appearing in the file LICENSE.GPL included in the + * packaging of this file. + * + * Licensees holding valid libFirm Professional Edition licenses may use + * this file in accordance with the libFirm Commercial License. + * Agreement provided with the Software. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ + /** - * Dumps global variables and constants as gas assembler. - * @author Christian Wuerdig, Matthias Braun - * @date 04.11.2005 - * @version $Id$ + * @file + * @brief Dumps global variables and constants as gas assembler. + * @author Christian Wuerdig, Matthias Braun + * @date 04.11.2005 + * @version $Id$ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -20,6 +40,7 @@ #include "irnode.h" #include "entity.h" #include "irprog.h" +#include "pdeq.h" #include "error.h" #include "be_t.h" @@ -31,7 +52,15 @@ typedef struct obstack obstack_t; /** by default, we generate assembler code for the Linux gas */ be_gas_flavour_t be_gas_flavour = GAS_FLAVOUR_NORMAL; -static const char* get_section_name(be_gas_section_t section) { +/** + * Return the pseudo-instruction to be issued for a section switch + * depending on the current flavour. + * + * @param section the section to switch to + * + * @return the pseudo-instruction + */ +static const char *get_section_name(be_gas_section_t section) { static const char *text[GAS_FLAVOUR_MAX][GAS_SECTION_MAX] = { { ".section\t.text", @@ -56,6 +85,12 @@ static const char* get_section_name(be_gas_section_t section) { return text[be_gas_flavour][section]; } +/** + * Emit necessary code to switch to a section. + * + * @param env the emitter environment + * @param section the section to switch to + */ void be_gas_emit_switch_section(be_emit_env_t *env, be_gas_section_t section) { be_emit_char(env, '\t'); be_emit_string(env, get_section_name(section)); @@ -63,18 +98,29 @@ void be_gas_emit_switch_section(be_emit_env_t *env, be_gas_section_t section) { be_emit_write_line(env); } -typedef struct _ia32_decl_env { - obstack_t *rodata_obst; - obstack_t *data_obst; - obstack_t *bss_obst; - obstack_t *ctor_obst; - const be_main_env_t *main_env; -} ia32_decl_env_t; +/** + * An environment containing all needed dumper data. + * Currently we create the file completely in memory first, then + * write it to the disk. This is an artifact from the old C-generating backend + * and even there NOT needed. So we might change it in the future. + */ +typedef struct _be_gas_decl_env { + obstack_t *rodata_obst; /**< An obstack that will be filled with all rodata entities. */ + obstack_t *data_obst; /**< An obstack that will be filled with the initialized entities. */ + obstack_t *bss_obst; /**< An obstack that will be filled with the uninitialized entities. */ + obstack_t *ctor_obst; /**< An obstack that will be filled with the constructor entities. */ + const be_main_env_t *main_env; /**< The main backend environment, used for it's debug handle. */ + waitq *worklist; /**< A worklist we use to place not yet handled entities on. */ +} be_gas_decl_env_t; /************************************************************************/ /** - * output a tarval + * Output a tarval. + * + * @param obst the obstack where the data is written too + * @param tv the tarval + * @param bytes the width of the tarvals value in bytes */ static void dump_arith_tarval(obstack_t *obst, tarval *tv, int bytes) { @@ -125,6 +171,10 @@ static void dump_arith_tarval(obstack_t *obst, tarval *tv, int bytes) /** * Return the tarval of an atomic initializer. + * + * @param init a node representing the initializer (on teh const code irg) + * + * @return the tarval */ static tarval *get_atomic_init_tv(ir_node *init) { @@ -146,15 +196,15 @@ static tarval *get_atomic_init_tv(ir_node *init) case iro_SymConst: switch (get_SymConst_kind(init)) { - case symconst_ofs_ent: - return new_tarval_from_long(get_entity_offset(get_SymConst_entity(init)), mode); - case symconst_type_size: return new_tarval_from_long(get_type_size_bytes(get_SymConst_type(init)), mode); case symconst_type_align: return new_tarval_from_long(get_type_alignment_bytes(get_SymConst_type(init)), mode); + case symconst_ofs_ent: + return new_tarval_from_long(get_entity_offset(get_SymConst_entity(init)), mode); + case symconst_enum_const: return get_enumeration_value(get_SymConst_enum(init)); @@ -169,22 +219,28 @@ static tarval *get_atomic_init_tv(ir_node *init) } /** - * dump an atomic value + * Dump an atomic value. + * + * @param env the gas output environment + * @param obst an obstack the output is written to + * @param init a node representing the atomic value (on the const code irg) */ -static void do_dump_atomic_init(obstack_t *obst, ir_node *init) +static void do_dump_atomic_init(be_gas_decl_env_t *env, obstack_t *obst, + ir_node *init) { ir_mode *mode = get_irn_mode(init); int bytes = get_mode_size_bytes(mode); tarval *tv; + ir_entity *ent; switch (get_irn_opcode(init)) { case iro_Cast: - do_dump_atomic_init(obst, get_Cast_op(init)); + do_dump_atomic_init(env, obst, get_Cast_op(init)); return; case iro_Conv: - do_dump_atomic_init(obst, get_Conv_op(init)); + do_dump_atomic_init(env, obst, get_Conv_op(init)); return; case iro_Const: @@ -201,11 +257,23 @@ static void do_dump_atomic_init(obstack_t *obst, ir_node *init) break; case symconst_addr_ent: - obstack_printf(obst, "%s", get_entity_ld_name(get_SymConst_entity(init))); + ent = get_SymConst_entity(init); + if(!entity_visited(ent)) { + waitq_put(env->worklist, ent); + mark_entity_visited(ent); + } + obstack_printf(obst, "%s", get_entity_ld_name(ent)); break; case symconst_ofs_ent: - obstack_printf(obst, "%d", get_entity_offset(get_SymConst_entity(init))); + ent = get_SymConst_entity(init); +#if 0 /* not needed, is it? */ + if(!entity_visited(ent)) { + waitq_put(env->worklist, ent); + mark_entity_visited(ent); + } +#endif + obstack_printf(obst, "%d", get_entity_offset(ent)); break; case symconst_type_size: @@ -227,21 +295,21 @@ static void do_dump_atomic_init(obstack_t *obst, ir_node *init) return; case iro_Add: - do_dump_atomic_init(obst, get_Add_left(init)); + do_dump_atomic_init(env, obst, get_Add_left(init)); obstack_printf(obst, " + "); - do_dump_atomic_init(obst, get_Add_right(init)); + do_dump_atomic_init(env, obst, get_Add_right(init)); return; case iro_Sub: - do_dump_atomic_init(obst, get_Sub_left(init)); + do_dump_atomic_init(env, obst, get_Sub_left(init)); obstack_printf(obst, " - "); - do_dump_atomic_init(obst, get_Sub_right(init)); + do_dump_atomic_init(env, obst, get_Sub_right(init)); return; case iro_Mul: - do_dump_atomic_init(obst, get_Mul_left(init)); + do_dump_atomic_init(env, obst, get_Mul_left(init)); obstack_printf(obst, " * "); - do_dump_atomic_init(obst, get_Mul_right(init)); + do_dump_atomic_init(env, obst, get_Mul_right(init)); return; default: @@ -250,7 +318,10 @@ static void do_dump_atomic_init(obstack_t *obst, ir_node *init) } /** - * dumps the type for given size (.byte, .long, ...) + * Dumps the type for given size (.byte, .long, ...) + * + * @param obst an obstack the output is written to + * @param size the size in bytes */ static void dump_size_type(obstack_t *obst, int size) { switch (size) { @@ -287,15 +358,20 @@ static void dump_size_type(obstack_t *obst, int size) { } /** - * dump an atomic value to an obstack + * Dump an atomic value to an obstack. + * + * @param env the gas output environment + * @param obst an obstack the output is written to + * @param init a node representing the atomic value (on the const code irg) */ -static void dump_atomic_init(obstack_t *obst, ir_node *init) +static void dump_atomic_init(be_gas_decl_env_t *env, obstack_t *obst, + ir_node *init) { ir_mode *mode = get_irn_mode(init); int bytes = get_mode_size_bytes(mode); dump_size_type(obst, bytes); - do_dump_atomic_init(obst, init); + do_dump_atomic_init(env, obst, init); obstack_printf(obst, "\n"); } @@ -354,8 +430,9 @@ static int ent_is_string_const(ir_entity *ent) /** * Dump a string constant. * No checks are made!! + * * @param obst The obst to dump on. - * @param ent The entity to dump. + * @param ent The entity to dump. */ static void dump_string_cst(obstack_t *obst, ir_entity *ent) { @@ -388,7 +465,8 @@ static void dump_string_cst(obstack_t *obst, ir_entity *ent) obstack_printf(obst, "\"\n"); } -static void dump_array_init(obstack_t *obst, ir_entity *ent) +static void dump_array_init(be_gas_decl_env_t *env, obstack_t *obst, + ir_entity *ent) { const ir_type *ty = get_entity_type(ent); int i; @@ -409,7 +487,7 @@ static void dump_array_init(obstack_t *obst, ir_entity *ent) size += align - n; } } - dump_atomic_init(obst, get_compound_ent_value(ent, i)); + dump_atomic_init(env, obst, get_compound_ent_value(ent, i)); size += get_type_size_bytes(stype); } filler = get_type_size_bytes(ty) - size; @@ -434,7 +512,8 @@ typedef struct { /** * Dump an initializer for a compound entity. */ -static void dump_compound_init(obstack_t *obst, ir_entity *ent) +static void dump_compound_init(be_gas_decl_env_t *env, obstack_t *obst, + ir_entity *ent) { normal_or_bitfield *vals; int i, j, n = get_compound_ent_n_values(ent); @@ -443,7 +522,7 @@ static void dump_compound_init(obstack_t *obst, ir_entity *ent) /* Find the initializer size. Sorrily gcc support a nasty feature: The last field of a compound may be a flexible array. This allows initializers bigger than the type size. */ - last_ofs = 0; + last_ofs = get_type_size_bytes(get_entity_type(ent)); for (i = 0; i < n; ++i) { int offset = get_compound_ent_value_offset_bytes(ent, i); int bits_remainder = get_compound_ent_value_offset_bit_remainder(ent, i); @@ -514,7 +593,7 @@ static void dump_compound_init(obstack_t *obst, ir_entity *ent) int space = 0, skip = 0; if (vals[i].kind == NORMAL) { if(vals[i].v.value != NULL) { - dump_atomic_init(obst, vals[i].v.value); + dump_atomic_init(env, obst, vals[i].v.value); skip = get_mode_size_bytes(get_irn_mode(vals[i].v.value)) - 1; } else { space = 1; @@ -542,8 +621,12 @@ static void dump_compound_init(obstack_t *obst, ir_entity *ent) /** * Dump a global entity. + * + * @param env the gas output environment + * @param ent the entity to be dumped + * @param emit_commons if non-zero, emit commons (non-local uninitialized entities) */ -static void dump_global(ia32_decl_env_t *env, ir_entity *ent, int emit_commons) +static void dump_global(be_gas_decl_env_t *env, ir_entity *ent, int emit_commons) { obstack_t *obst; ir_type *type = get_entity_type(ent); @@ -593,19 +676,23 @@ static void dump_global(ia32_decl_env_t *env, ir_entity *ent, int emit_commons) if (variability == variability_uninitialized) { if(emit_as_common) { - obstack_printf(obst, "\t.comm %s,%d,%d\n", + if (be_gas_flavour == GAS_FLAVOUR_NORMAL) + obstack_printf(obst, "\t.comm %s,%d,%d\n", + ld_name, get_type_size_bytes(type), align); + else + obstack_printf(obst, "\t.comm %s,%d # %d\n", ld_name, get_type_size_bytes(type), align); } else { obstack_printf(obst, "\t.zero %d\n", get_type_size_bytes(type)); } } else if (is_atomic_type(type)) { - dump_atomic_init(obst, get_atomic_ent_value(ent)); + dump_atomic_init(env, obst, get_atomic_ent_value(ent)); } else if (ent_is_string_const(ent)) { dump_string_cst(obst, ent); } else if (is_Array_type(type)) { - dump_array_init(obst, ent); + dump_array_init(env, obst, ent); } else if (is_compound_type(type)) { - dump_compound_init(obst, ent); + dump_compound_init(env, obst, ent); } else { assert(0 && "unsupported type"); } @@ -613,21 +700,56 @@ static void dump_global(ia32_decl_env_t *env, ir_entity *ent, int emit_commons) /** * Dumps declarations of global variables and the initialization code. + * + * @param gt a global like type, either the global or the TLS one + * @param env an environment + * @param emit_commons if non-zero, emit commons (non-local uninitialized entities) + * @param only_emit_marked if non-zero, external allocated entities that do not have + * its visited flag set are ignored */ -static void ia32_dump_globals(ir_type *gt, ia32_decl_env_t *env, int emit_commons) +static void be_gas_dump_globals(ir_type *gt, be_gas_decl_env_t *env, + int emit_commons, int only_emit_marked) { int i, n = get_compound_n_members(gt); + waitq *worklist = new_waitq(); + + if(only_emit_marked) { + for (i = 0; i < n; i++) { + ir_entity *ent = get_compound_member(gt, i); + if(entity_visited(ent) || + get_entity_visibility(ent) != visibility_external_allocated) { + waitq_put(worklist, ent); + mark_entity_visited(ent); + } + } + } else { + inc_master_type_visited(); + for (i = 0; i < n; i++) { + ir_entity *ent = get_compound_member(gt, i); + mark_entity_visited(ent); + waitq_put(worklist, ent); + } + } + + env->worklist = worklist; + + while(!waitq_empty(worklist)) { + ir_entity *ent = waitq_get(worklist); - for (i = 0; i < n; i++) { - ir_entity *ent = get_compound_member(gt, i); dump_global(env, ent, emit_commons); } + + del_waitq(worklist); + env->worklist = NULL; } /************************************************************************/ -void be_gas_emit_decls(be_emit_env_t *emit, const be_main_env_t *main_env) { - ia32_decl_env_t env; +/* Generate all entities. */ +void be_gas_emit_decls(be_emit_env_t *emit, const be_main_env_t *main_env, + int only_emit_marked_entities) +{ + be_gas_decl_env_t env; obstack_t rodata, data, bss, ctor; int size; char *cp; @@ -644,7 +766,7 @@ void be_gas_emit_decls(be_emit_env_t *emit, const be_main_env_t *main_env) { env.ctor_obst = &ctor; env.main_env = main_env; - ia32_dump_globals(get_glob_type(), &env, 1); + be_gas_dump_globals(get_glob_type(), &env, 1, only_emit_marked_entities); size = obstack_object_size(&data); cp = obstack_finish(&data); @@ -691,7 +813,7 @@ void be_gas_emit_decls(be_emit_env_t *emit, const be_main_env_t *main_env) { env.bss_obst = &data; env.ctor_obst = NULL; - ia32_dump_globals(get_tls_type(), &env, 0); + be_gas_dump_globals(get_tls_type(), &env, 0, only_emit_marked_entities); size = obstack_object_size(&data); cp = obstack_finish(&data);