liveness variants with ir_nodeset_t
[libfirm] / ir / be / begnuas.c
index 0d68ca5..0b8ae0a 100644 (file)
@@ -1,11 +1,31 @@
+/*
+ * 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>
+#include "config.h"
 #endif
 
 #include "begnuas.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);