Output proper local lables (starting with .L/L) for the PIC base, switch tables and...
[libfirm] / ir / be / begnuas.c
index ab8c798..6d4d337 100644 (file)
@@ -110,7 +110,7 @@ static void emit_section(be_gas_section_t section, const ir_entity *entity)
                "text", "data", "rodata", "bss", "ctors", "dtors"
        };
        static const char *const type[] = {
-               "", "progbits", "progbits", "nobits", "init_array", "fini_array"
+               "progbits", "progbits", "progbits", "nobits", "init_array", "fini_array"
        };
 
        if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
@@ -572,14 +572,6 @@ static void emit_arith_tarval(tarval *tv, int bytes)
        panic("Can't dump a tarval with %d bytes", bytes);
 }
 
-/**
- * Return the label prefix for labeled blocks.
- */
-const char *be_gas_block_label_prefix(void)
-{
-       return ".LG";
-}
-
 /**
  * Return the label prefix for labeled instructions.
  */
@@ -846,7 +838,7 @@ static void emit_string_cst(const ir_entity *ent)
        remaining_space = type_size - len;
        assert(remaining_space >= 0);
        if (remaining_space > 0) {
-               be_emit_irprintf("\t.zero\t%d\n", remaining_space);
+               be_emit_irprintf("\t.space\t%d\n", remaining_space);
        }
 }
 
@@ -1302,37 +1294,66 @@ static unsigned get_effective_entity_alignment(const ir_entity *entity)
 
 static void emit_common(const ir_entity *entity)
 {
-       const char    *name       = get_entity_ld_name(entity);
-       unsigned       size       = get_type_size_bytes(get_entity_type(entity));
-       unsigned       alignment  = get_effective_entity_alignment(entity);
-       ir_visibility  visibility = get_entity_visibility(entity);
-       ir_linkage     linkage    = get_entity_linkage(entity);
-
-       if (visibility == ir_visibility_local
-                       || visibility == ir_visibility_private) {
-               /* counter the visibility_global effect of .comm
-                * ... and to be honest I have no idea what local common symbols
-                *     are good for...
-                */
-               be_emit_irprintf("\t.local %s\n", name);
+       unsigned size      = get_type_size_bytes(get_entity_type(entity));
+       unsigned alignment = get_effective_entity_alignment(entity);
+
+       if (get_entity_linkage(entity) & IR_LINKAGE_WEAK) {
+               emit_weak(entity);
+       }
+
+       switch (be_gas_object_file_format) {
+       case OBJECT_FILE_FORMAT_MACH_O:
+               be_emit_cstring("\t.comm ");
+               be_gas_emit_entity(entity);
+               be_emit_irprintf(",%u,%u\n", size, log2_floor(alignment));
                be_emit_write_line();
+               return;
+       case OBJECT_FILE_FORMAT_ELF:
+               be_emit_cstring("\t.comm ");
+               be_gas_emit_entity(entity);
+               be_emit_irprintf(",%u,%u\n", size, alignment);
+               be_emit_write_line();
+               return;
+       case OBJECT_FILE_FORMAT_COFF:
+               be_emit_cstring("\t.comm ");
+               be_gas_emit_entity(entity);
+               be_emit_irprintf(",%u # %u\n", size, alignment);
+               be_emit_write_line();
+               return;
        }
-       if (linkage & IR_LINKAGE_WEAK) {
+       panic("invalid object file format");
+}
+
+static void emit_local_common(const ir_entity *entity)
+{
+       unsigned size      = get_type_size_bytes(get_entity_type(entity));
+       unsigned alignment = get_effective_entity_alignment(entity);
+
+       if (get_entity_linkage(entity) & IR_LINKAGE_WEAK) {
                emit_weak(entity);
        }
 
        switch (be_gas_object_file_format) {
        case OBJECT_FILE_FORMAT_MACH_O:
-               be_emit_irprintf("\t.comm %s,%u,%u\n", name, size,
-                                log2_floor(alignment));
+               be_emit_cstring("\t.lcomm ");
+               be_gas_emit_entity(entity);
+               be_emit_irprintf(",%u,%u\n", size, log2_floor(alignment));
                be_emit_write_line();
                return;
        case OBJECT_FILE_FORMAT_ELF:
-               be_emit_irprintf("\t.comm %s,%u,%u\n", name, size, alignment);
+               be_emit_cstring("\t.local ");
+               be_gas_emit_entity(entity);
+               be_emit_cstring("\n");
+               be_emit_write_line();
+               be_emit_cstring("\t.comm ");
+               be_gas_emit_entity(entity);
+               be_emit_irprintf(",%u,%u\n", size, alignment);
                be_emit_write_line();
                return;
        case OBJECT_FILE_FORMAT_COFF:
-               be_emit_irprintf("\t.comm %s,%u # %u\n", name, size, alignment);
+               be_emit_cstring("\t.lcomm ");
+               be_gas_emit_entity(entity);
+               be_emit_irprintf(",%u # %u\n", size, alignment);
                be_emit_write_line();
                return;
        }
@@ -1344,7 +1365,7 @@ static void emit_indirect_symbol(const ir_entity *entity, be_gas_section_t secti
        /* we can only do PIC code on macho so far */
        assert(be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O);
 
-       be_emit_ident(get_entity_ld_ident(entity));
+       be_gas_emit_entity(entity);
        be_emit_cstring(":\n");
        be_emit_write_line();
        be_emit_cstring("\t.indirect_symbol ");
@@ -1361,35 +1382,51 @@ static void emit_indirect_symbol(const ir_entity *entity, be_gas_section_t secti
        }
 }
 
+char const *be_gas_get_private_prefix(void)
+{
+       return
+               be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O ? "L" :
+               ".L";
+}
+
 void be_gas_emit_entity(const ir_entity *entity)
 {
        if (entity->type == firm_code_type) {
                ir_label_t label = get_entity_label(entity);
-               be_emit_string(be_gas_block_label_prefix());
-               be_emit_irprintf("%lu", label);
+               be_emit_irprintf("%s_%lu", be_gas_get_private_prefix(), label);
                return;
        }
 
        if (get_entity_visibility(entity) == ir_visibility_private) {
-               be_emit_cstring(".L");
+               be_emit_string(be_gas_get_private_prefix());
        }
        be_emit_ident(get_entity_ld_ident(entity));
 }
 
+void be_gas_emit_block_name(const ir_node *block)
+{
+       if (has_Block_entity(block)) {
+               ir_entity *entity = get_Block_entity(block);
+               be_gas_emit_entity(entity);
+       } else {
+               be_emit_irprintf("%s%ld", be_gas_get_private_prefix(), get_irn_node_nr(block));
+       }
+}
+
 /**
  * Dump a global entity.
  *
  * @param env  the gas output environment
  * @param ent  the entity to be dumped
  */
-static void emit_global(be_gas_decl_env_t *env, const ir_entity *ent)
+static void emit_global(be_gas_decl_env_t *env, const ir_entity *entity)
 {
-       ir_type          *type       = get_entity_type(ent);
-       ident            *ld_ident   = get_entity_ld_ident(ent);
-       unsigned          alignment  = get_effective_entity_alignment(ent);
-       be_gas_section_t  section    = determine_section(env, ent);
-       ir_visibility     visibility = get_entity_visibility(ent);
-       ir_linkage        linkage    = get_entity_linkage(ent);
+       ir_type          *type       = get_entity_type(entity);
+       ident            *ld_ident   = get_entity_ld_ident(entity);
+       unsigned          alignment  = get_effective_entity_alignment(entity);
+       be_gas_section_t  section    = determine_section(env, entity);
+       ir_visibility     visibility = get_entity_visibility(entity);
+       ir_linkage        linkage    = get_entity_linkage(entity);
 
        /* block labels are already emittet in the code */
        if (type == firm_code_type)
@@ -1400,23 +1437,36 @@ static void emit_global(be_gas_decl_env_t *env, const ir_entity *ent)
        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(ent) == NULL) {
-                       emit_visibility(ent);
+               if (get_entity_irg(entity) == NULL) {
+                       emit_visibility(entity);
                }
                return;
        }
 
-       be_dbg_variable(ent);
+       be_dbg_variable(entity);
+
+       if (section == GAS_SECTION_BSS) {
+               ir_visibility visibility = get_entity_visibility(entity);
 
-       if (section == GAS_SECTION_BSS && (linkage & IR_LINKAGE_MERGE)) {
-               if (get_entity_visibility(ent) == ir_visibility_external) {
-                       panic("merge link semantic not supported for extern entities");
+               switch (visibility) {
+               case ir_visibility_local:
+               case ir_visibility_private:
+                       emit_local_common(entity);
+                       return;
+               case ir_visibility_default:
+                       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_common(ent);
-               return;
        }
 
-       emit_visibility(ent);
+       emit_visibility(entity);
        if (visibility == ir_visibility_external) {
                /* nothing to do for externally defined values */
                return;
@@ -1425,11 +1475,11 @@ static void emit_global(be_gas_decl_env_t *env, const ir_entity *ent)
        if (!is_po2(alignment))
                panic("alignment not a power of 2");
 
-       emit_section(section, ent);
+       emit_section(section, entity);
 
        if (section == GAS_SECTION_PIC_TRAMPOLINES
                        || section == GAS_SECTION_PIC_SYMBOLS) {
-               emit_indirect_symbol(ent, section);
+               emit_indirect_symbol(entity, section);
                return;
        }
 
@@ -1440,28 +1490,28 @@ static void emit_global(be_gas_decl_env_t *env, const ir_entity *ent)
        if (be_gas_object_file_format == OBJECT_FILE_FORMAT_ELF
                        && be_gas_emit_types) {
                be_emit_cstring("\t.type\t");
-               be_gas_emit_entity(ent);
+               be_gas_emit_entity(entity);
                be_emit_cstring(", ");
                be_emit_char(be_gas_elf_type_char);
                be_emit_cstring("object\n\t.size\t");\
-               be_gas_emit_entity(ent);
+               be_gas_emit_entity(entity);
                be_emit_irprintf(", %u\n", get_type_size_bytes(type));
        }
 
        if (get_id_str(ld_ident)[0] != '\0') {
-           be_gas_emit_entity(ent);
+           be_gas_emit_entity(entity);
                be_emit_cstring(":\n");
                be_emit_write_line();
        }
 
-       if (entity_is_null(ent)) {
-               be_emit_irprintf("\t.zero %u\n", get_type_size_bytes(type));
+       if (entity_is_null(entity)) {
+               be_emit_irprintf("\t.space %u\n", get_type_size_bytes(type));
                be_emit_write_line();
-       } else if(entity_has_compound_ent_values(ent)) {
-               emit_compound_graph_init(env, ent);
+       } else if(entity_has_compound_ent_values(entity)) {
+               emit_compound_graph_init(env, entity);
        } else {
-               assert(ent->initializer != NULL);
-               emit_initializer(env, ent);
+               assert(entity->initializer != NULL);
+               emit_initializer(env, entity);
        }
 }