Do not refetch a value, which we already have.
[libfirm] / ir / be / begnuas.c
index c51f6d4..c6c0063 100644 (file)
@@ -22,7 +22,6 @@
  * @brief       Dumps global variables and constants as gas assembler.
  * @author      Christian Wuerdig, Matthias Braun
  * @date        04.11.2005
- * @version     $Id$
  */
 #include "config.h"
 
@@ -43,7 +42,7 @@
 
 #include "be_t.h"
 #include "beemitter.h"
-#include "be_dbgout.h"
+#include "bedwarf.h"
 
 /** by default, we generate assembler code for the Linux gas */
 object_file_format_t  be_gas_object_file_format = OBJECT_FILE_FORMAT_ELF;
@@ -90,6 +89,7 @@ static void emit_section_macho(be_gas_section_t section)
                case GAS_SECTION_DEBUG_ABBREV:    name = "section __DWARF,__debug_abbrev,regular,debug"; break;
                case GAS_SECTION_DEBUG_LINE:      name = "section __DWARF,__debug_line,regular,debug"; break;
                case GAS_SECTION_DEBUG_PUBNAMES:  name = "section __DWARF,__debug_pubnames,regular,debug"; break;
+               case GAS_SECTION_DEBUG_FRAME:     name = "section __DWARF,__debug_frame,regular,debug"; break;
                default: panic("unsupported scetion type 0x%X", section);
                }
                be_emit_irprintf("\t.%s\n", name);
@@ -103,8 +103,10 @@ static void emit_section_macho(be_gas_section_t section)
                case GAS_SECTION_CSTRING:         name = "section __TEXT,__const_coal,coalesced"; break;
                default: panic("unsupported scetion type 0x%X", section);
                }
+       } else if (flags & GAS_SECTION_FLAG_TLS) {
+               panic("thread local storage not supported on macho (section 0x%X)", section);
        } else {
-               panic("unsupported section type 0x%X\n", section);
+               panic("unsupported section type 0x%X", section);
        }
 }
 
@@ -126,6 +128,7 @@ static void emit_section_sparc(be_gas_section_t section, const ir_entity *entity
                "debug_abbrev",
                "debug_line",
                "debug_pubnames"
+               "debug_frame",
        };
 
        if (current_section == section && !(section & GAS_SECTION_FLAG_COMDAT))
@@ -192,6 +195,7 @@ static void emit_section(be_gas_section_t section, const ir_entity *entity)
                { "debug_abbrev",   "progbits", ""   },
                { "debug_line",     "progbits", ""   },
                { "debug_pubnames", "progbits", ""   },
+               { "debug_frame",    "progbits", ""   },
        };
 
        if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
@@ -417,15 +421,8 @@ static int entity_is_string_const(const ir_entity *ent)
 
 static bool entity_is_null(const ir_entity *entity)
 {
-       if (entity->initializer != NULL) {
-               return initializer_is_null(entity->initializer);
-       } else if (entity_has_compound_ent_values(entity)) {
-               /* I'm too lazy to implement this case as compound graph paths will be
-                * remove anyway in the future */
-               return false;
-       }
-       /* uninitialized, NULL is fine */
-       return true;
+       ir_initializer_t *initializer = get_entity_initializer(entity);
+       return initializer == NULL || initializer_is_null(initializer);
 }
 
 static bool is_comdat(const ir_entity *entity)
@@ -446,7 +443,7 @@ static be_gas_section_t determine_basic_section(const ir_entity *entity)
        if (linkage & IR_LINKAGE_CONSTANT) {
                /* mach-o is the only one with a cstring section */
                if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O
-                               && entity_is_string_const(entity))
+                   && entity_is_string_const(entity))
                        return GAS_SECTION_CSTRING;
 
                return GAS_SECTION_RODATA;
@@ -505,13 +502,14 @@ static void emit_weak(const ir_entity *entity)
 
 static void emit_visibility(const ir_entity *entity)
 {
-       ir_linkage linkage = get_entity_linkage(entity);
+       ir_linkage const linkage = get_entity_linkage(entity);
 
-       if (get_entity_linkage(entity) & IR_LINKAGE_WEAK) {
+       if (linkage & IR_LINKAGE_WEAK) {
                emit_weak(entity);
                /* Note: .weak seems to imply .globl so no need to output .globl */
-       } else if (get_entity_visibility(entity) == ir_visibility_default) {
-               be_emit_cstring(".globl ");
+       } else if (get_entity_visibility(entity) == ir_visibility_external
+                  && entity_has_definition(entity)) {
+               be_emit_cstring("\t.globl ");
                be_gas_emit_entity(entity);
                be_emit_char('\n');
                be_emit_write_line();
@@ -527,14 +525,17 @@ static void emit_visibility(const ir_entity *entity)
        }
 }
 
-void be_gas_emit_function_prolog(const ir_entity *entity, unsigned po2alignment)
+void be_gas_emit_function_prolog(const ir_entity *entity, unsigned po2alignment,                                 const parameter_dbg_info_t *parameter_infos)
 {
-       be_gas_section_t section = determine_section(NULL, entity);
+       be_gas_section_t section;
+
+       be_dwarf_method_before(entity, parameter_infos);
+
+       section = determine_section(NULL, entity);
        emit_section(section, entity);
 
        /* write the begin line (makes the life easier for scripts parsing the
         * assembler) */
-       be_emit_write_line();
        be_emit_cstring("# -- Begin  ");
        be_gas_emit_entity(entity);
        be_emit_char('\n');
@@ -580,10 +581,14 @@ void be_gas_emit_function_prolog(const ir_entity *entity, unsigned po2alignment)
        be_gas_emit_entity(entity);
        be_emit_cstring(":\n");
        be_emit_write_line();
+
+       be_dwarf_method_begin();
 }
 
 void be_gas_emit_function_epilog(const ir_entity *entity)
 {
+       be_dwarf_method_end();
+
        if (be_gas_object_file_format == OBJECT_FILE_FORMAT_ELF) {
                be_emit_cstring("\t.size\t");
                be_gas_emit_entity(entity);
@@ -597,6 +602,9 @@ void be_gas_emit_function_epilog(const ir_entity *entity)
        be_gas_emit_entity(entity);
        be_emit_char('\n');
        be_emit_write_line();
+
+       be_emit_char('\n');
+       be_emit_write_line();
 }
 
 /**
@@ -920,13 +928,6 @@ typedef struct {
        } v;
 } normal_or_bitfield;
 
-static int is_type_variable_size(ir_type *type)
-{
-       (void) type;
-       /* TODO */
-       return 0;
-}
-
 static size_t get_initializer_size(const ir_initializer_t *initializer,
                                    ir_type *type)
 {
@@ -938,28 +939,34 @@ static size_t get_initializer_size(const ir_initializer_t *initializer,
        case IR_INITIALIZER_NULL:
                return get_type_size_bytes(type);
        case IR_INITIALIZER_COMPOUND:
-               if (!is_type_variable_size(type)) {
-                       return get_type_size_bytes(type);
+               if (is_Array_type(type)) {
+                       if (is_array_variable_size(type)) {
+                               ir_type   *element_type = get_array_element_type(type);
+                               unsigned   element_size = get_type_size_bytes(element_type);
+                               unsigned   element_align
+                                       = get_type_alignment_bytes(element_type);
+                               unsigned   misalign     = element_size % element_align;
+                               size_t     n_inits
+                                       = get_initializer_compound_n_entries(initializer);
+                               element_size += element_align - misalign;
+                               return n_inits * element_size;
+                       } else {
+                               return get_type_size_bytes(type);
+                       }
                } else {
-                       size_t n_entries
-                               = get_initializer_compound_n_entries(initializer);
-                       size_t i;
-                       unsigned initializer_size = get_type_size_bytes(type);
-                       for (i = 0; i < n_entries; ++i) {
-                               ir_entity *entity = get_compound_member(type, i);
-                               ir_type   *type   = get_entity_type(entity);
-
-                               const ir_initializer_t *sub_initializer
-                                       = get_initializer_compound_value(initializer, i);
-
-                               unsigned offset = get_entity_offset(entity);
-                               unsigned size   = get_initializer_size(sub_initializer, type);
-
-                               if (offset + size > initializer_size) {
-                                       initializer_size = offset + size;
-                               }
+                       assert(is_compound_type(type));
+                       size_t size = get_type_size_bytes(type);
+                       if (is_compound_variable_size(type)) {
+                               /* last initializer has to be an array of variable size */
+                               size_t l = get_initializer_compound_n_entries(initializer)-1;
+                               const ir_initializer_t *last
+                                       = get_initializer_compound_value(initializer, l);
+                               const ir_entity *last_ent  = get_compound_member(type, l);
+                               ir_type         *last_type = get_entity_type(last_ent);
+                               assert(is_array_variable_size(last_type));
+                               size += get_initializer_size(last, last_type);
                        }
-                       return initializer_size;
+                       return size;
                }
        }
 
@@ -1539,7 +1546,7 @@ char const *be_gas_get_private_prefix(void)
 
 void be_gas_emit_entity(const ir_entity *entity)
 {
-       if (entity->type == firm_code_type) {
+       if (entity->type == get_code_type()) {
                ir_label_t label = get_entity_label(entity);
                be_emit_irprintf("%s_%lu", be_gas_get_private_prefix(), label);
                return;
@@ -1553,8 +1560,8 @@ void be_gas_emit_entity(const ir_entity *entity)
 
 void be_gas_emit_block_name(const ir_node *block)
 {
-       if (has_Block_entity(block)) {
-               ir_entity *entity = get_Block_entity(block);
+       ir_entity *entity = get_Block_entity(block);
+       if (entity != NULL) {
                be_gas_emit_entity(entity);
        } else {
                be_emit_irprintf("%s%ld", be_gas_get_private_prefix(), get_irn_node_nr(block));
@@ -1577,21 +1584,17 @@ static void emit_global(be_gas_decl_env_t *env, const ir_entity *entity)
        ir_linkage        linkage    = get_entity_linkage(entity);
 
        /* block labels are already emittet in the code */
-       if (type == firm_code_type)
+       if (type == get_code_type())
                return;
 
-       /* we already emitted all methods. Except for the trampolines which
-        * the assembler/linker generates */
+       /* we already emitted all methods with graphs in other functions like
+        * be_gas_emit_function_prolog(). All others don't need to be emitted.
+        */
        if (is_Method_type(type) && section != GAS_SECTION_PIC_TRAMPOLINES) {
-               /* functions with graph are already emitted with
-                * be_gas_emit_function_prolog */
-               if (get_entity_irg(entity) == NULL) {
-                       emit_visibility(entity);
-               }
                return;
        }
 
-       be_dbg_variable(entity);
+       be_dwarf_variable(entity);
 
        if (section == GAS_SECTION_BSS) {
                switch (visibility) {
@@ -1599,24 +1602,16 @@ static void emit_global(be_gas_decl_env_t *env, const ir_entity *entity)
                case ir_visibility_private:
                        emit_local_common(entity);
                        return;
-               case ir_visibility_default:
+               case ir_visibility_external:
                        if (linkage & IR_LINKAGE_MERGE) {
                                emit_common(entity);
                                return;
                        }
                        break;
-               case ir_visibility_external:
-                       if (linkage & IR_LINKAGE_MERGE)
-                               panic("merge link semantic not supported for extern entities");
-                       break;
                }
        }
 
        emit_visibility(entity);
-       if (visibility == ir_visibility_external) {
-               /* nothing to do for externally defined values */
-               return;
-       }
 
        if (!is_po2(alignment))
                panic("alignment not a power of 2");
@@ -1629,6 +1624,10 @@ static void emit_global(be_gas_decl_env_t *env, const ir_entity *entity)
                return;
        }
 
+       /* nothing left to do without an initializer */
+       if (!entity_has_definition(entity))
+               return;
+
        /* alignment */
        if (alignment > 1) {
                emit_align(alignment);
@@ -1652,6 +1651,7 @@ static void emit_global(be_gas_decl_env_t *env, const ir_entity *entity)
        }
 
        if (entity_is_null(entity)) {
+               /* we should use .space for stuff in the bss segment */
                unsigned size = get_type_size_bytes(type);
                if (size > 0) {
                        be_emit_irprintf("\t.space %u, 0\n", get_type_size_bytes(type));
@@ -1711,66 +1711,101 @@ static void emit_global_decls(const be_main_env_t *main_env)
        }
 }
 
-void emit_jump_table(const ir_node *node, long default_pn, ir_entity *entity,
-                     get_cfop_target_func get_cfop_target)
+void be_emit_jump_table(const ir_node *node, const ir_switch_table *table,
+                        ir_entity *entity, get_cfop_target_func get_cfop_target)
 {
-       long             switch_max    = LONG_MIN;
-       ir_node         *default_block = NULL;
-       unsigned long    length;
-       const ir_edge_t *edge;
-       unsigned         i;
-       ir_node        **table;
-
-       /* go over all proj's and collect them */
+       unsigned          n_outs    = arch_get_irn_n_outs(node);
+       const ir_node   **targets   = XMALLOCNZ(const ir_node*, n_outs);
+       size_t            n_entries = ir_switch_table_get_n_entries(table);
+       unsigned long     length    = 0;
+       size_t            e;
+       const ir_edge_t  *edge;
+       unsigned          i;
+       const ir_node   **labels;
+
+       /* go over all proj's and collect their jump targets */
        foreach_out_edge(node, edge) {
-               ir_node *proj = get_edge_src_irn(edge);
-               long     pn   = get_Proj_proj(proj);
-
-               /* check for default proj */
-               if (pn == default_pn) {
-                       assert(default_block == NULL); /* more than 1 default_pn? */
-                       default_block = get_cfop_target(proj);
-               } else {
-                       switch_max = pn > switch_max ? pn : switch_max;
+               ir_node *proj   = get_edge_src_irn(edge);
+               long     pn     = get_Proj_proj(proj);
+               ir_node *target = get_cfop_target(proj);
+               assert(targets[pn] == NULL);
+               targets[pn] = target;
+       }
+
+       /* go over table to determine max value (note that we normalized the
+        * ranges so that the minimum is 0) */
+       for (e = 0; e < n_entries; ++e) {
+               const ir_switch_table_entry *entry
+                       = ir_switch_table_get_entry_const(table, e);
+               ir_tarval *max = entry->max;
+               unsigned long val;
+               if (entry->pn == 0)
+                       continue;
+               if (!tarval_is_long(max))
+                       panic("switch case overflow (%+F)", node);
+               val = (unsigned long) get_tarval_long(max);
+               if (val > length) {
+                       length = val;
                }
        }
-       assert(switch_max > LONG_MIN);
 
-       length = (unsigned long) switch_max + 1;
        /* the 16000 isn't a real limit of the architecture. But should protect us
         * from seamingly endless compiler runs */
        if (length > 16000) {
                /* switch lowerer should have broken this monster to pieces... */
-               panic("too large switch encountered");
+               panic("too large switch encountered (%+F)", node);
+       }
+       ++length;
+
+       labels = XMALLOCNZ(const ir_node*, length);
+       for (e = 0; e < n_entries; ++e) {
+               const ir_switch_table_entry *entry
+                       = ir_switch_table_get_entry_const(table, e);
+               ir_tarval     *min    = entry->min;
+               ir_tarval     *max    = entry->max;
+               const ir_node *target = targets[entry->pn];
+               assert(entry->pn < (long)n_outs);
+               if (min == max) {
+                       unsigned long val = (unsigned long)get_tarval_long(max);
+                       labels[val] = target;
+               } else {
+                       unsigned long min_val;
+                       unsigned long max_val;
+                       unsigned long i;
+                       if (!tarval_is_long(min))
+                               panic("switch case overflow (%+F)", node);
+                       min_val = (unsigned long)get_tarval_long(min);
+                       max_val = (unsigned long)get_tarval_long(max);
+                       assert(min_val <= max_val);
+                       for (i = min_val; i <= max_val; ++i) {
+                               labels[i] = target;
+                       }
+               }
        }
 
-       table = XMALLOCNZ(ir_node*, length);
-       foreach_out_edge(node, edge) {
-               ir_node *proj = get_edge_src_irn(edge);
-               long     pn   = get_Proj_proj(proj);
-               if (pn == default_pn)
-                       continue;
-
-               table[pn] = get_cfop_target(proj);
+       /* emit table */
+       if (entity != NULL) {
+               be_gas_emit_switch_section(GAS_SECTION_RODATA);
+               be_emit_cstring("\t.align 4\n");
+               be_gas_emit_entity(entity);
+               be_emit_cstring(":\n");
        }
 
-       /* emit table */
-       be_gas_emit_switch_section(GAS_SECTION_RODATA);
-       be_emit_cstring("\t.align 4\n");
-       be_gas_emit_entity(entity);
-       be_emit_cstring(":\n");
        for (i = 0; i < length; ++i) {
-               ir_node *block = table[i];
+               const ir_node *block = labels[i];
                if (block == NULL)
-                       block = default_block;
+                       block = targets[0];
                be_emit_cstring("\t.long ");
                be_gas_emit_block_name(block);
                be_emit_char('\n');
                be_emit_write_line();
        }
-       be_gas_emit_switch_section(GAS_SECTION_TEXT);
 
-       xfree(table);
+       if (entity != NULL)
+               be_gas_emit_switch_section(GAS_SECTION_TEXT);
+
+       xfree(labels);
+       xfree(targets);
 }
 
 static void emit_global_asms(void)
@@ -1794,9 +1829,8 @@ static void emit_global_asms(void)
 
 void be_gas_begin_compilation_unit(const be_main_env_t *env)
 {
-       be_dbg_open();
-       be_dbg_unit_begin(env->cup_name);
-       be_dbg_types();
+       be_dwarf_open();
+       be_dwarf_unit_begin(env->cup_name);
 
        emit_global_asms();
 }
@@ -1805,6 +1839,6 @@ void be_gas_end_compilation_unit(const be_main_env_t *env)
 {
        emit_global_decls(env);
 
-       be_dbg_unit_end();
-       be_dbg_close();
+       be_dwarf_unit_end();
+       be_dwarf_close();
 }