amd64: small changes w.r.t. stack alignment.
[libfirm] / ir / be / begnuas.c
index b7baf71..98557f0 100644 (file)
@@ -62,17 +62,114 @@ typedef struct _be_gas_decl_env {
        const be_main_env_t *main_env;
 } be_gas_decl_env_t;
 
+static void emit_section_macho(be_gas_section_t section)
+{
+       be_gas_section_t  base  = section & GAS_SECTION_TYPE_MASK;
+       be_gas_section_t  flags = section & ~GAS_SECTION_TYPE_MASK;
+       const char       *name;
+
+       if (current_section == section)
+               return;
+       current_section = section;
+
+       /* shortforms */
+       if (flags == 0) {
+               switch (base) {
+               case GAS_SECTION_TEXT:            name = "text";          break;
+               case GAS_SECTION_DATA:            name = "data";          break;
+               case GAS_SECTION_RODATA:          name = "const";         break;
+               case GAS_SECTION_BSS:             name = "data";          break;
+               case GAS_SECTION_CONSTRUCTORS:    name = "mod_init_func"; break;
+               case GAS_SECTION_DESTRUCTORS:     name = "mod_term_func"; break;
+               case GAS_SECTION_PIC_TRAMPOLINES: name = "section\t__IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5"; break;
+               case GAS_SECTION_PIC_SYMBOLS:     name = "section\t__IMPORT,__pointers,non_lazy_symbol_pointers"; break;
+               case GAS_SECTION_CSTRING:         name = "cstring";       break;
+               default: panic("unsupported scetion type 0x%X", section);
+               }
+               be_emit_irprintf("\t.%s\n", name);
+               be_emit_write_line();
+       } else if (flags & GAS_SECTION_FLAG_COMDAT) {
+               switch (base) {
+               case GAS_SECTION_TEXT:            name = "section __TEXT,__textcoal_nt,coalesced,pure_instructions"; break;
+               case GAS_SECTION_BSS:
+               case GAS_SECTION_DATA:            name = "section __DATA,__datacoal_nt,coalesced"; break;
+               case GAS_SECTION_RODATA:          name = "section __TEXT,__const_coal,coalesced"; break;
+               case GAS_SECTION_CSTRING:         name = "section __TEXT,__const_coal,coalesced"; break;
+               default: panic("unsupported scetion type 0x%X", section);
+               }
+       } else {
+               panic("unsupported section type 0x%X\n", section);
+       }
+}
+
+static void emit_section_sparc(be_gas_section_t section, const ir_entity *entity)
+{
+       be_gas_section_t base = section & GAS_SECTION_TYPE_MASK;
+       be_gas_section_t flags = section & ~GAS_SECTION_TYPE_MASK;
+       static const char *const basename[] = {
+               "text", "data", "rodata", "bss", "ctors", "dtors"
+       };
+
+       if (current_section == section && !(section & GAS_SECTION_FLAG_COMDAT))
+               return;
+       current_section = section;
+
+       be_emit_cstring("\t.section\t\".");
+
+       /* Part1: section-name */
+       if (flags & GAS_SECTION_FLAG_TLS)
+               be_emit_char('t');
+       assert(base < sizeof(basename)/sizeof(basename[0]));
+       be_emit_string(basename[base]);
+
+       if (flags & GAS_SECTION_FLAG_COMDAT) {
+               be_emit_char('.');
+               be_gas_emit_entity(entity);
+       }
+       be_emit_char('"');
+
+       /* for the simple sections we're done here */
+       if (flags == 0)
+               goto end;
+
+       be_emit_cstring(",#alloc");
+
+       switch (base) {
+       case GAS_SECTION_TEXT: be_emit_cstring(",#execinstr"); break;
+       case GAS_SECTION_DATA:
+       case GAS_SECTION_BSS:  be_emit_cstring(",#write"); break;
+       default:
+               /* nothing */
+               break;
+       }
+       if (flags & GAS_SECTION_FLAG_TLS) {
+               be_emit_cstring(",#tls");
+       }
+
+end:
+       be_emit_char('\n');
+       be_emit_write_line();
+}
+
 static void emit_section(be_gas_section_t section, const ir_entity *entity)
 {
        be_gas_section_t base = section & GAS_SECTION_TYPE_MASK;
        be_gas_section_t flags = section & ~GAS_SECTION_TYPE_MASK;
-       static const char *basename[] = {
+       static const char *const basename[] = {
                "text", "data", "rodata", "bss", "ctors", "dtors"
        };
-       static const char *type[] = {
-               "", "progbits", "progbits", "nobits", "init_array", "fini_array"
+       static const char *const type[] = {
+               "progbits", "progbits", "progbits", "nobits", "init_array", "fini_array"
        };
 
+       if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
+               emit_section_macho(section);
+               return;
+       } else if(be_gas_object_file_format == OBJECT_FILE_FORMAT_ELF_SPARC) {
+               emit_section_sparc(section, entity);
+               return;
+       }
+
        if (current_section == section && !(section & GAS_SECTION_FLAG_COMDAT))
                return;
        current_section = section;
@@ -116,15 +213,20 @@ static void emit_section(be_gas_section_t section, const ir_entity *entity)
        be_emit_cstring(",\"");
        if (be_gas_object_file_format != OBJECT_FILE_FORMAT_COFF)
                be_emit_char('a');
-       if (base != GAS_SECTION_RODATA)
+       if (base == GAS_SECTION_TEXT)
+               be_emit_char('x');
+       if (base != GAS_SECTION_RODATA && base != GAS_SECTION_TEXT)
                be_emit_char('w');
        if (flags & GAS_SECTION_FLAG_TLS)
                be_emit_char('T');
        if (flags & GAS_SECTION_FLAG_COMDAT)
                be_emit_char('G');
-       be_emit_cstring("\",");
-       be_emit_char(be_gas_elf_type_char);
-       be_emit_string(type[base]);
+       /* section type */
+       if (be_gas_object_file_format != OBJECT_FILE_FORMAT_COFF) {
+               be_emit_cstring("\",");
+               be_emit_char(be_gas_elf_type_char);
+               be_emit_string(type[base]);
+       }
 
        if (flags & GAS_SECTION_FLAG_COMDAT) {
                be_emit_char(',');
@@ -135,6 +237,8 @@ static void emit_section(be_gas_section_t section, const ir_entity *entity)
        be_emit_write_line();
 }
 
+
+
 void be_gas_emit_switch_section(be_gas_section_t section)
 {
        /* you have to produce a switch_section call with entity manually
@@ -144,6 +248,19 @@ void be_gas_emit_switch_section(be_gas_section_t section)
        emit_section(section, NULL);
 }
 
+static tarval *get_initializer_tarval(const ir_initializer_t *initializer)
+{
+       if (initializer->kind == IR_INITIALIZER_TARVAL)
+               return initializer->tarval.value;
+       if (initializer->kind == IR_INITIALIZER_CONST) {
+               ir_node *node = initializer->consti.value;
+               if (is_Const(node)) {
+                       return get_Const_tarval(node);
+               }
+       }
+       return get_tarval_undefined();
+}
+
 static int initializer_is_string_const(const ir_initializer_t *initializer)
 {
        size_t i, len;
@@ -162,12 +279,11 @@ static int initializer_is_string_const(const ir_initializer_t *initializer)
                ir_initializer_t *sub_initializer
                        = initializer->compound.initializers[i];
 
-               if (sub_initializer->kind != IR_INITIALIZER_TARVAL)
+               tv = get_initializer_tarval(sub_initializer);
+               if (!tarval_is_constant(tv))
                        return 0;
 
-               tv   = sub_initializer->tarval.value;
                mode = get_tarval_mode(tv);
-
                if (!mode_is_int(mode) || get_mode_size_bits(mode) != 8)
                        return 0;
 
@@ -276,6 +392,7 @@ static bool entity_is_null(const ir_entity *entity)
        } 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;
@@ -336,6 +453,11 @@ static be_gas_section_t determine_section(be_gas_decl_env_t *env,
                return section | GAS_SECTION_FLAG_TLS;
        }
 
+       /* the java frontend keeps some functions inside classes */
+       if (is_Class_type(owner)) {
+               return determine_basic_section(entity);
+       }
+
        panic("Couldn't determine section for %+F?!?", entity);
 }
 
@@ -402,6 +524,7 @@ void be_gas_emit_function_prolog(const ir_entity *entity, unsigned po2alignment)
 
        switch (be_gas_object_file_format) {
        case OBJECT_FILE_FORMAT_ELF:
+       case OBJECT_FILE_FORMAT_ELF_SPARC:
                be_emit_cstring("\t.type\t");
                be_gas_emit_entity(entity);
                be_emit_cstring(", ");
@@ -515,14 +638,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.
  */
@@ -613,10 +728,6 @@ static void do_emit_atomic_init(be_gas_decl_env_t *env, ir_node *init)
 
        case iro_SymConst:
                switch (get_SymConst_kind(init)) {
-               case symconst_addr_name:
-                       be_emit_ident(get_SymConst_name(init));
-                       break;
-
                case symconst_addr_ent:
                        ent = get_SymConst_entity(init);
                        be_gas_emit_entity(ent);
@@ -789,7 +900,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);
        }
 }
 
@@ -809,7 +920,7 @@ static void emit_string_initializer(const ir_initializer_t *initializer)
                const ir_initializer_t *sub_initializer
                        = get_initializer_compound_value(initializer, i);
 
-               tarval *tv = get_initializer_tarval_value(sub_initializer);
+               tarval *tv = get_initializer_tarval(sub_initializer);
                int     c  = get_tarval_long(tv);
 
                switch (c) {
@@ -1245,37 +1356,68 @@ 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:
+       case OBJECT_FILE_FORMAT_ELF_SPARC:
+               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);
+       case OBJECT_FILE_FORMAT_ELF_SPARC:
+               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;
        }
@@ -1287,7 +1429,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 ");
@@ -1304,35 +1446,49 @@ 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)
@@ -1343,23 +1499,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 && (linkage & IR_LINKAGE_MERGE)) {
-               if (get_entity_visibility(ent) == ir_visibility_external) {
-                       panic("merge link semantic not supported for extern entities");
+       if (section == GAS_SECTION_BSS) {
+               ir_visibility visibility = get_entity_visibility(entity);
+
+               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;
@@ -1368,11 +1537,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;
        }
 
@@ -1383,28 +1552,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);
        }
 }