- Allow an arbitrary (for arbitrary < 32) number of in_rBAR and !in_rBAR constraints...
[libfirm] / ir / be / begnuas.c
index 5f81ce5..c2b87bf 100644 (file)
@@ -38,7 +38,6 @@
 #include "obst.h"
 #include "tv.h"
 #include "irnode.h"
-#include "entity.h"
 #include "irprog.h"
 #include "pdeq.h"
 #include "error.h"
@@ -80,8 +79,8 @@ 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];
 }
 
@@ -91,26 +90,36 @@ static const char *get_section_name(be_gas_section_t 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));
-       be_emit_char(env, '\n');
-       be_emit_write_line(env);
+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;
-       waitq     *worklist;
-} 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)
 {
@@ -159,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)
 {
@@ -182,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;
                        }
@@ -205,14 +235,19 @@ 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(ia32_decl_env_t *env, obstack_t *obst,
+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)) {
@@ -240,9 +275,9 @@ static void do_dump_atomic_init(ia32_decl_env_t *env, obstack_t *obst,
 
                case symconst_addr_ent:
                        ent = get_SymConst_entity(init);
-                       if(!entity_visited(ent)) {
+                       if(!is_entity_backend_marked(ent)) {
                                waitq_put(env->worklist, ent);
-                               mark_entity_visited(ent);
+                               set_entity_backend_marked(ent, 1);
                        }
                        obstack_printf(obst, "%s", get_entity_ld_name(ent));
                        break;
@@ -250,9 +285,9 @@ static void do_dump_atomic_init(ia32_decl_env_t *env, obstack_t *obst,
                case symconst_ofs_ent:
                        ent = get_SymConst_entity(init);
 #if 0       /* not needed, is it? */
-                       if(!entity_visited(ent)) {
+                       if(!is_entity_backend_marked(ent)) {
                                waitq_put(env->worklist, ent);
-                               mark_entity_visited(ent);
+                               set_entity_backend_marked(ent, 1);
                        }
 #endif
                        obstack_printf(obst, "%d", get_entity_offset(ent));
@@ -271,6 +306,11 @@ static void do_dump_atomic_init(ia32_decl_env_t *env, obstack_t *obst,
                        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");
                }
@@ -300,7 +340,10 @@ static void do_dump_atomic_init(ia32_decl_env_t *env, obstack_t *obst,
 }
 
 /**
- * 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) {
@@ -337,9 +380,13 @@ 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(ia32_decl_env_t *env, obstack_t *obst,
+static void dump_atomic_init(be_gas_decl_env_t *env, obstack_t *obst,
                              ir_node *init)
 {
        ir_mode *mode = get_irn_mode(init);
@@ -405,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);
@@ -437,37 +488,14 @@ static void dump_string_cst(obstack_t *obst, ir_entity *ent)
                }
        }
        obstack_printf(obst, "\"\n");
-}
 
-static void dump_array_init(ia32_decl_env_t *env, 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(env, 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 {
@@ -486,7 +514,7 @@ typedef struct {
 /**
  * Dump an initializer for a compound entity.
  */
-static void dump_compound_init(ia32_decl_env_t *env, obstack_t *obst,
+static void dump_compound_init(be_gas_decl_env_t *env, obstack_t *obst,
                                ir_entity *ent)
 {
        normal_or_bitfield *vals;
@@ -532,32 +560,33 @@ static void dump_compound_init(ia32_decl_env_t *env, obstack_t *obst,
 
                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;
                }
        }
@@ -578,7 +607,6 @@ static void dump_compound_init(ia32_decl_env_t *env, obstack_t *obst,
                }
 
                ++i;
-               space = 0;
                while (i < last_ofs && vals[i].kind == NORMAL && vals[i].v.value == NULL) {
                        ++space;
                        ++i;
@@ -595,16 +623,20 @@ static void dump_compound_init(ia32_decl_env_t *env, obstack_t *obst,
 
 /**
  * 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)) {
@@ -615,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;
        }
 
@@ -646,54 +682,75 @@ 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(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(env, obst, ent);
-       } else if (is_compound_type(type)) {
-               dump_compound_init(env, 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,
+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) {
+       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) {
+                       if (is_entity_backend_marked(ent) ||
+                           get_entity_visibility(ent) != visibility_external_allocated) {
                                waitq_put(worklist, ent);
-                               mark_entity_visited(ent);
+                               set_entity_backend_marked(ent, 1);
                        }
                }
        } else {
-               inc_master_type_visited();
                for (i = 0; i < n; i++) {
                        ir_entity *ent = get_compound_member(gt, i);
-                       mark_entity_visited(ent);
+                       set_entity_backend_marked(ent, 1);
                        waitq_put(worklist, ent);
                }
        }
 
        env->worklist = worklist;
 
-       while(!waitq_empty(worklist)) {
+       while (!waitq_empty(worklist)) {
                ir_entity *ent = waitq_get(worklist);
 
                dump_global(env, ent, emit_commons);
@@ -705,13 +762,17 @@ static void ia32_dump_globals(ir_type *gt, ia32_decl_env_t *env,
 
 /************************************************************************/
 
-void be_gas_emit_decls(be_emit_env_t *emit, const be_main_env_t *main_env,
+/* Generate all entities. */
+void be_gas_emit_decls(const be_main_env_t *main_env,
                        int only_emit_marked_entities)
 {
-       ia32_decl_env_t env;
-       obstack_t rodata, data, bss, ctor;
-       int    size;
-       char   *cp;
+       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);
@@ -725,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, only_emit_marked_entities);
+       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);
@@ -772,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, only_emit_marked_entities);
+       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);