X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fbegnuas.c;h=c2b87bf197f4f531369b888790d00f2ac95be19a;hb=bd31a5350ce9e110c058b4ad2223d460c9eb5c4e;hp=2fa023a6d2ece8a4f4a101aa8c9e74483d8da869;hpb=2adf84106c02caf097c2d6cf1764706bdc437bcc;p=libfirm diff --git a/ir/be/begnuas.c b/ir/be/begnuas.c index 2fa023a6d..c2b87bf19 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" @@ -18,8 +38,8 @@ #include "obst.h" #include "tv.h" #include "irnode.h" -#include "entity.h" #include "irprog.h" +#include "pdeq.h" #include "error.h" #include "be_t.h" @@ -31,7 +51,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", @@ -51,30 +79,47 @@ static const char* get_section_name(be_gas_section_t section) { } }; - assert(be_gas_flavour >= 0 && be_gas_flavour < GAS_FLAVOUR_MAX); - assert(section >= 0 && section < GAS_SECTION_MAX); + assert((int) be_gas_flavour >= 0 && be_gas_flavour < GAS_FLAVOUR_MAX); + assert((int) section >= 0 && section < GAS_SECTION_MAX); return text[be_gas_flavour][section]; } -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)); - be_emit_char(env, '\n'); - be_emit_write_line(env); +/** + * 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_gas_section_t section) { + be_emit_char('\t'); + be_emit_string(get_section_name(section)); + be_emit_char('\n'); + be_emit_write_line(); } -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) { @@ -123,8 +168,26 @@ static void dump_arith_tarval(obstack_t *obst, tarval *tv, int bytes) } } +/** + * Return the label prefix for labeled blocks. + */ +const char *be_gas_label_prefix(void) { + return ".LG"; +} + +/** + * Dump a label. + */ +static void dump_label(obstack_t *obst, ir_label_t label) { + obstack_printf(obst, "%s%ld", be_gas_label_prefix(), label); +} + /** * Return the tarval of an atomic initializer. + * + * @param init a node representing the initializer (on the const code irg) + * + * @return the tarval */ static tarval *get_atomic_init_tv(ir_node *init) { @@ -146,18 +209,21 @@ 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)); + case symconst_label: + return NULL; + default: return NULL; } @@ -169,22 +235,29 @@ 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_label_t label; + 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 +274,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(!is_entity_backend_marked(ent)) { + waitq_put(env->worklist, ent); + set_entity_backend_marked(ent, 1); + } + 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(!is_entity_backend_marked(ent)) { + waitq_put(env->worklist, ent); + set_entity_backend_marked(ent, 1); + } +#endif + obstack_printf(obst, "%d", get_entity_offset(ent)); break; case symconst_type_size: @@ -221,27 +306,32 @@ static void do_dump_atomic_init(obstack_t *obst, ir_node *init) dump_arith_tarval(obst, tv, bytes); break; + case symconst_label: + label = get_SymConst_label(init); + dump_label(obst, label); + break; + default: assert(!"dump_atomic_init(): don't know how to init from this SymConst"); } 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 +340,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 +380,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,12 +452,16 @@ 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) { - int i, n; + int i, n; + ir_type *type; + int type_size; + int remaining_space; obstack_printf(obst, "\t.string \""); n = get_compound_ent_n_values(ent); @@ -386,36 +488,14 @@ 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) -{ - const ir_type *ty = get_entity_type(ent); - int i; - int filler; - int size = 0; - - /* potential spare values should be already included! */ - for (i = 0; i < get_compound_ent_n_values(ent); ++i) { - ir_entity *step = get_compound_ent_value_member(ent, i); - ir_type *stype = get_entity_type(step); - - if (get_type_mode(stype)) { - int align = (get_type_alignment_bits(stype) + 7) >> 3; - int n = size % align; - - if (n > 0) { - obstack_printf(obst, "\t.zero\t%d\n", align - n); - size += align - n; - } - } - dump_atomic_init(obst, get_compound_ent_value(ent, i)); - size += get_type_size_bytes(stype); + type = get_entity_type(ent); + type_size = get_type_size_bytes(type); + remaining_space = type_size - n; + assert(remaining_space >= 0); + if(remaining_space > 0) { + obstack_printf(obst, "\t.skip\t%d\n", remaining_space); } - filler = get_type_size_bytes(ty) - size; - - if (filler > 0) - obstack_printf(obst, "\t.skip\t%d\n", filler); } enum normal_or_bitfield_kind { @@ -434,7 +514,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 +524,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); @@ -479,32 +560,33 @@ static void dump_compound_init(obstack_t *obst, ir_entity *ent) if (offset_bits != 0 || (value_len != 8 && value_len != 16 && value_len != 32 && value_len != 64)) { - tarval *shift, *shifted; tarval *tv = get_atomic_init_tv(value); + unsigned char curr_bits, last_bits = 0; if (tv == NULL) { panic("Couldn't get numeric value for bitfield initializer '%s'\n", get_entity_ld_name(ent)); } - tv = tarval_convert_to(tv, mode_Lu); - shift = new_tarval_from_long(offset_bits, mode_Is); - shifted = tarval_shl(tv, shift); - if (shifted == tarval_bad || shifted == tarval_undefined) { - panic("Couldn't shift numeric value for bitfield initializer '%s'\n", - get_entity_ld_name(ent)); - } + /* normalize offset */ + offset += offset_bits >> 3; + offset_bits &= 7; - for (j = 0; value_len > 0; ++j) { + for (j = 0; value_len + offset_bits > 0; ++j) { assert(offset + j < last_ofs); assert(vals[offset + j].kind == BITFIELD || vals[offset + j].v.value == NULL); vals[offset + j].kind = BITFIELD; - vals[offset + j].v.bf_val |= get_tarval_sub_bits(shifted, j); - value_len -= 8 - offset_bits; - offset_bits = 0; + curr_bits = get_tarval_sub_bits(tv, j); + vals[offset + j].v.bf_val |= (last_bits >> (8 - offset_bits)) | (curr_bits << offset_bits); + value_len -= 8; + last_bits = curr_bits; } } else { + int i; + assert(offset < last_ofs); assert(vals[offset].kind == NORMAL); - assert(vals[offset].v.value == NULL); + for (i = 1; i < value_len / 8; ++i) { + assert(vals[offset + i].v.value == NULL); + } vals[offset].v.value = value; } } @@ -514,7 +596,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; @@ -525,7 +607,6 @@ static void dump_compound_init(obstack_t *obst, ir_entity *ent) } ++i; - space = 0; while (i < last_ofs && vals[i].kind == NORMAL && vals[i].v.value == NULL) { ++space; ++i; @@ -542,16 +623,20 @@ 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); const char *ld_name = get_entity_ld_name(ent); - ir_variability variability = get_entity_variability(ent); - ir_visibility visibility = get_entity_visibility(ent); int align = get_type_alignment_bytes(type); int emit_as_common = 0; + ir_variability variability; + ir_visibility visibility; obst = env->data_obst; if (is_Method_type(type)) { @@ -562,13 +647,17 @@ static void dump_global(ia32_decl_env_t *env, ir_entity *ent, int emit_commons) obstack_printf(obst, "%s\n", ld_name); } return; - } else if (variability == variability_constant) { + } + + variability = get_entity_variability(ent); + visibility = get_entity_visibility(ent); + if (variability == variability_constant) { /* a constant entity, put it on the rdata */ obst = env->rodata_obst; } else if (variability == variability_uninitialized) { /* uninitialized entity put it in bss segment */ obst = env->bss_obst; - if(emit_commons && visibility != visibility_local) + if (emit_commons && visibility != visibility_local) emit_as_common = 1; } @@ -593,44 +682,97 @@ 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)); - } else if (ent_is_string_const(ent)) { - dump_string_cst(obst, ent); - } else if (is_Array_type(type)) { - dump_array_init(obst, ent); - } else if (is_compound_type(type)) { - dump_compound_init(obst, ent); } else { - assert(0 && "unsupported type"); + if (is_atomic_entity(ent)) { + dump_atomic_init(env, obst, get_atomic_ent_value(ent)); + } else { + /* sort_compound_ent_values(ent); */ + + switch (get_type_tpop_code(get_entity_type(ent))) { + case tpo_array: + if (ent_is_string_const(ent)) + dump_string_cst(obst, ent); + else + dump_compound_init(env, obst, ent); + break; + case tpo_struct: + case tpo_class: + case tpo_union: + dump_compound_init(env, obst, ent); + break; + default: + assert(0); + } + } } } /** * 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 (is_entity_backend_marked(ent) || + get_entity_visibility(ent) != visibility_external_allocated) { + waitq_put(worklist, ent); + set_entity_backend_marked(ent, 1); + } + } + } else { + for (i = 0; i < n; i++) { + ir_entity *ent = get_compound_member(gt, i); + set_entity_backend_marked(ent, 1); + 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; - obstack_t rodata, data, bss, ctor; - int size; - char *cp; +/* Generate all entities. */ +void be_gas_emit_decls(const be_main_env_t *main_env, + int only_emit_marked_entities) +{ + be_gas_decl_env_t env; + obstack_t rodata; + obstack_t data; + obstack_t bss; + obstack_t ctor; + int size; + char *cp; /* dump the global type */ obstack_init(&rodata); @@ -644,38 +786,38 @@ 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); if (size > 0) { - be_gas_emit_switch_section(emit, GAS_SECTION_DATA); - be_emit_string_len(emit, cp, size); - be_emit_write_line(emit); + be_gas_emit_switch_section(GAS_SECTION_DATA); + be_emit_string_len(cp, size); + be_emit_write_line(); } size = obstack_object_size(&rodata); cp = obstack_finish(&rodata); if (size > 0) { - be_gas_emit_switch_section(emit, GAS_SECTION_RODATA); - be_emit_string_len(emit, cp, size); - be_emit_write_line(emit); + be_gas_emit_switch_section(GAS_SECTION_RODATA); + be_emit_string_len(cp, size); + be_emit_write_line(); } size = obstack_object_size(&bss); cp = obstack_finish(&bss); if (size > 0) { - be_gas_emit_switch_section(emit, GAS_SECTION_COMMON); - be_emit_string_len(emit, cp, size); - be_emit_write_line(emit); + be_gas_emit_switch_section(GAS_SECTION_COMMON); + be_emit_string_len(cp, size); + be_emit_write_line(); } size = obstack_object_size(&ctor); cp = obstack_finish(&ctor); if (size > 0) { - be_gas_emit_switch_section(emit, GAS_SECTION_CTOR); - be_emit_string_len(emit, cp, size); - be_emit_write_line(emit); + be_gas_emit_switch_section(GAS_SECTION_CTOR); + be_emit_string_len(cp, size); + be_emit_write_line(); } obstack_free(&rodata, NULL); @@ -691,16 +833,16 @@ 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); if (size > 0) { - be_gas_emit_switch_section(emit, GAS_SECTION_TLS); - be_emit_cstring(emit, ".balign\t32\n"); - be_emit_write_line(emit); - be_emit_string_len(emit, cp, size); - be_emit_write_line(emit); + be_gas_emit_switch_section(GAS_SECTION_TLS); + be_emit_cstring(".balign\t32\n"); + be_emit_write_line(); + be_emit_string_len(cp, size); + be_emit_write_line(); } obstack_free(&data, NULL);