/*
- * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved.
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
*
* This file is part of libFirm.
*
#include "irnode.h"
#include "irprog.h"
#include "pdeq.h"
+#include "entity_t.h"
#include "error.h"
#include "be_t.h"
".section\t.bss",
".section\t.tbss,\"awT\",@nobits",
".section\t.ctors,\"aw\",@progbits"
+ },
+ {
+ ".section\t.text",
+ ".section\t.data",
+ ".section\t.rodata",
+ ".section\t.bss",
+ ".section\t.tbss,\"awT\",@nobits",
+ ".section\t.ctors,\"aw\",@progbits"
}
};
* @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();
}
/**
ir_label_t label;
ir_entity *ent;
+ init = skip_Id(init);
+
switch (get_irn_opcode(init)) {
case iro_Cast:
break;
case symconst_type_size:
- obstack_printf(obst, "%d", get_type_size_bytes(get_SymConst_type(init)));
+ obstack_printf(obst, "%u", get_type_size_bytes(get_SymConst_type(init)));
break;
case symconst_type_align:
- obstack_printf(obst, "%d", get_type_alignment_bytes(get_SymConst_type(init)));
+ obstack_printf(obst, "%u", get_type_alignment_bytes(get_SymConst_type(init)));
break;
case symconst_enum_const:
* @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) {
+static void dump_size_type(obstack_t *obst, size_t size) {
switch (size) {
case 1:
break;
case 2:
- obstack_printf(obst, "\t.value\t");
+ obstack_printf(obst, "\t.word\t");
break;
case 4:
/* Routines to dump global variables */
/************************************************************************/
+static int initializer_is_string_const(const ir_initializer_t *initializer)
+{
+ size_t i, len;
+
+ if(initializer->kind != IR_INITIALIZER_COMPOUND)
+ return 0;
+
+ len = initializer->compound.n_initializers;
+ if (len < 1)
+ return 0;
+ for(i = 0; i < len; ++i) {
+ int c;
+ tarval *tv;
+ ir_mode *mode;
+ ir_initializer_t *sub_initializer
+ = initializer->compound.initializers[i];
+
+ if(sub_initializer->kind != IR_INITIALIZER_TARVAL)
+ return 0;
+
+ tv = sub_initializer->tarval.value;
+ mode = get_tarval_mode(tv);
+
+ if (!mode_is_int(mode)
+ || get_mode_size_bits(mode) != get_mode_size_bits(mode_Bs))
+ return 0;
+
+ c = get_tarval_long(tv);
+ if (i < len - 1) {
+ if (!isgraph(c) && !isspace(c))
+ return 0;
+ } else {
+ if (c != 0)
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
/**
* Determine if an entity is a string constant
* @param ent The entity
|| get_mode_size_bits(mode) != get_mode_size_bits(mode_Bs))
return 0;
- /* if it contains only printable chars and a 0 at the end */
- n = get_compound_ent_n_values(ent);
- for (i = 0; i < n; ++i) {
- ir_node *irn = get_compound_ent_value(ent, i);
- if(get_irn_opcode(irn) != iro_Const)
- return 0;
-
- c = (int) get_tarval_long(get_Const_tarval(irn));
-
- if((i < n - 1 && !(isgraph(c) || isspace(c)))
- || (i == n - 1 && c != '\0'))
- return 0;
+ if(ent->has_initializer) {
+ /* TODO */
+ return 0;
+ } else {
+ /* if it contains only printable chars and a 0 at the end */
+ n = get_compound_ent_n_values(ent);
+ for (i = 0; i < n; ++i) {
+ ir_node *irn = get_compound_ent_value(ent, i);
+ if (! is_Const(irn))
+ return 0;
+
+ c = (int) get_tarval_long(get_Const_tarval(irn));
+
+ if((i < n - 1 && !(isgraph(c) || isspace(c)))
+ || (i == n - 1 && c != '\0'))
+ return 0;
+ }
}
/* then we can emit it as a string constant */
}
}
+static void dump_string_initializer(obstack_t *obst,
+ const ir_initializer_t *initializer)
+{
+ size_t i, len;
+
+ obstack_printf(obst, "\t.string \"");
+
+ len = initializer->compound.n_initializers;
+ for(i = 0; i < len - 1; ++i) {
+ const ir_initializer_t *sub_initializer
+ = get_initializer_compound_value(initializer, i);
+
+ tarval *tv = get_initializer_tarval_value(sub_initializer);
+ int c = get_tarval_long(tv);
+
+ switch (c) {
+ case '"' : obstack_printf(obst, "\\\""); break;
+ case '\n': obstack_printf(obst, "\\n"); break;
+ case '\r': obstack_printf(obst, "\\r"); break;
+ case '\t': obstack_printf(obst, "\\t"); break;
+ case '\\': obstack_printf(obst, "\\\\"); break;
+ default :
+ if (isprint(c))
+ obstack_printf(obst, "%c", c);
+ else
+ obstack_printf(obst, "\\%o", c);
+ break;
+ }
+ }
+ obstack_printf(obst, "\"\n");
+}
+
enum normal_or_bitfield_kind {
NORMAL = 0,
+ TARVAL,
BITFIELD
};
typedef struct {
enum normal_or_bitfield_kind kind;
union {
- ir_node *value;
- unsigned char bf_val;
+ ir_node *value;
+ tarval *tarval;
+ unsigned char bf_val;
} 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)
+{
+ switch(get_initializer_kind(initializer)) {
+ case IR_INITIALIZER_TARVAL: {
+ assert(get_tarval_mode(get_initializer_tarval_value(initializer)) == get_type_mode(type));
+ return get_type_size_bytes(type);
+ }
+ case IR_INITIALIZER_CONST:
+ 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);
+ } else {
+ unsigned n_entries
+ = get_initializer_compound_n_entries(initializer);
+ unsigned 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;
+ }
+ }
+ return initializer_size;
+ }
+ }
+ }
+
+ panic("found invalid initializer");
+}
+
+#ifndef NDEBUG
+static normal_or_bitfield *glob_vals;
+static size_t max_vals;
+#endif
+
+static void dump_bitfield(normal_or_bitfield *vals, size_t offset_bits,
+ const ir_initializer_t *initializer, ir_type *type)
+{
+ unsigned char last_bits = 0;
+ ir_mode *mode = get_type_mode(type);
+ tarval *tv = NULL;
+ unsigned char curr_bits;
+ int value_len;
+ int j;
+
+ switch(get_initializer_kind(initializer)) {
+ case IR_INITIALIZER_NULL:
+ return;
+ case IR_INITIALIZER_TARVAL:
+ tv = get_initializer_tarval_value(initializer);
+ break;
+ case IR_INITIALIZER_CONST: {
+ ir_node *node = get_initializer_const_value(initializer);
+ if(!is_Const(node)) {
+ panic("bitfield initializer not a Const node");
+ }
+ tv = get_Const_tarval(node);
+ break;
+ }
+ case IR_INITIALIZER_COMPOUND:
+ panic("bitfield initializer is compound");
+ }
+ if (tv == NULL) {
+ panic("Couldn't get numeric value for bitfield initializer\n");
+ }
+
+ /* normalize offset */
+ vals += offset_bits >> 3;
+ offset_bits &= 7;
+ value_len = get_mode_size_bits(mode);
+
+ /* combine bits with existing bits */
+ for (j = 0; value_len + (int) offset_bits > 0; ++j) {
+ assert((size_t) (vals - glob_vals) + j < max_vals);
+ assert(vals[j].kind == BITFIELD ||
+ (vals[j].kind == NORMAL && vals[j].v.value == NULL));
+ vals[j].kind = BITFIELD;
+ curr_bits = get_tarval_sub_bits(tv, j);
+ vals[j].v.bf_val
+ |= (last_bits >> (8 - offset_bits)) | (curr_bits << offset_bits);
+ value_len -= 8;
+ last_bits = curr_bits;
+ }
+}
+
+static void dump_ir_initializer(normal_or_bitfield *vals,
+ const ir_initializer_t *initializer,
+ ir_type *type)
+{
+ assert((size_t) (vals - glob_vals) < max_vals);
+
+ switch(get_initializer_kind(initializer)) {
+ case IR_INITIALIZER_NULL:
+ return;
+ case IR_INITIALIZER_TARVAL: {
+ size_t i;
+
+ assert(vals->kind != BITFIELD);
+ vals->kind = TARVAL;
+ vals->v.tarval = get_initializer_tarval_value(initializer);
+ assert(get_type_mode(type) == get_tarval_mode(vals->v.tarval));
+ for(i = 1; i < get_type_size_bytes(type); ++i) {
+ vals[i].kind = NORMAL;
+ vals[i].v.value = NULL;
+ }
+ return;
+ }
+ case IR_INITIALIZER_CONST: {
+ size_t i;
+
+ assert(vals->kind != BITFIELD);
+ vals->kind = NORMAL;
+ vals->v.value = get_initializer_const_value(initializer);
+ for(i = 1; i < get_type_size_bytes(type); ++i) {
+ vals[i].kind = NORMAL;
+ vals[i].v.value = NULL;
+ }
+ return;
+ }
+ case IR_INITIALIZER_COMPOUND: {
+ size_t i = 0;
+ size_t n = get_initializer_compound_n_entries(initializer);
+
+ if(is_Array_type(type)) {
+ ir_type *element_type = get_array_element_type(type);
+ size_t skip = get_type_size_bytes(element_type);
+ size_t alignment = get_type_alignment_bytes(element_type);
+ size_t misalign = skip % alignment;
+ if(misalign != 0) {
+ skip += alignment - misalign;
+ }
+
+ for(i = 0; i < n; ++i) {
+ ir_initializer_t *sub_initializer
+ = get_initializer_compound_value(initializer, i);
+
+ dump_ir_initializer(vals, sub_initializer, element_type);
+
+ vals += skip;
+ }
+ } else {
+ size_t n_members, i;
+ assert(is_compound_type(type));
+ n_members = get_compound_n_members(type);
+ for(i = 0; i < n_members; ++i) {
+ ir_entity *member = get_compound_member(type, i);
+ size_t offset = get_entity_offset(member);
+ ir_type *subtype = get_entity_type(member);
+ ir_mode *mode = get_type_mode(subtype);
+ ir_initializer_t *sub_initializer;
+
+ assert(i < get_initializer_compound_n_entries(initializer));
+ sub_initializer
+ = get_initializer_compound_value(initializer, i);
+
+ if(mode != NULL) {
+ size_t offset_bits
+ = get_entity_offset_bits_remainder(member);
+ size_t value_len = get_mode_size_bits(mode);
+
+ if(offset_bits != 0 ||
+ (value_len != 8 && value_len != 16 && value_len != 32
+ && value_len != 64)) {
+ dump_bitfield(&vals[offset], offset_bits,
+ sub_initializer, subtype);
+ continue;
+ }
+ }
+
+ dump_ir_initializer(&vals[offset], sub_initializer, subtype);
+ }
+ }
+
+ return;
+ }
+ }
+ panic("invalid ir_initializer kind found");
+}
+
+static void dump_initializer(be_gas_decl_env_t *env, obstack_t *obst,
+ ir_entity *entity)
+{
+ const ir_initializer_t *initializer = entity->attr.initializer;
+ ir_type *type;
+ normal_or_bitfield *vals;
+ size_t size;
+ size_t k;
+
+ if(initializer_is_string_const(initializer)) {
+ dump_string_initializer(obst, initializer);
+ return;
+ }
+
+ type = get_entity_type(entity);
+ size = get_initializer_size(initializer, type);
+
+ if (size == 0)
+ return;
+
+ /*
+ * In the worst case, every initializer allocates one byte.
+ * Moreover, initializer might be big, do not allocate on stack.
+ */
+ vals = xcalloc(size, sizeof(vals[0]));
+
+#ifndef NDEBUG
+ glob_vals = vals;
+ max_vals = size;
+#endif
+
+ dump_ir_initializer(vals, initializer, type);
+
+ /* now write values sorted */
+ for (k = 0; k < size; ) {
+ int space = 0, skip = 0;
+ if (vals[k].kind == NORMAL) {
+ if(vals[k].v.value != NULL) {
+ dump_atomic_init(env, obst, vals[k].v.value);
+ skip = get_mode_size_bytes(get_irn_mode(vals[k].v.value)) - 1;
+ } else {
+ space = 1;
+ }
+ } else if(vals[k].kind == TARVAL) {
+ tarval *tv = vals[k].v.tarval;
+ size_t size = get_mode_size_bytes(get_tarval_mode(tv));
+
+ assert(tv != NULL);
+
+ skip = size - 1;
+ dump_size_type(obst, size);
+ dump_arith_tarval(obst, tv, size);
+ obstack_1grow(obst, '\n');
+ } else {
+ assert(vals[k].kind == BITFIELD);
+ obstack_printf(obst, "\t.byte\t%d\n", vals[k].v.bf_val);
+ }
+
+ ++k;
+ while (k < size && vals[k].kind == NORMAL && vals[k].v.value == NULL) {
+ ++space;
+ ++k;
+ }
+ space -= skip;
+ assert(space >= 0);
+
+ /* a gap */
+ if (space > 0)
+ obstack_printf(obst, "\t.skip\t%d\n", space);
+ }
+ xfree(vals);
+
+}
+
/**
* Dump an initializer for a compound entity.
*/
ir_entity *ent)
{
normal_or_bitfield *vals;
- int i, j, n = get_compound_ent_n_values(ent);
- int last_ofs;
+ int i, j, n;
+ unsigned k, last_ofs;
+
+ if(ent->has_initializer) {
+ dump_initializer(env, obst, ent);
+ return;
+ }
+
+ n = get_compound_ent_n_values(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 = 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);
- const compound_graph_path *path = get_compound_ent_value_path(ent, i);
- int path_len = get_compound_graph_path_length(path);
- ir_entity *last_ent = get_compound_graph_path_node(path, path_len - 1);
- int value_len = get_type_size_bits(get_entity_type(last_ent));
+ unsigned offset = get_compound_ent_value_offset_bytes(ent, i);
+ unsigned bits_remainder = get_compound_ent_value_offset_bit_remainder(ent, i);
+ ir_node *value = get_compound_ent_value(ent, i);
+ unsigned value_len = get_mode_size_bits(get_irn_mode(value));
offset += (value_len + bits_remainder + 7) >> 3;
/* collect the values and store them at the offsets */
for (i = 0; i < n; ++i) {
- const compound_graph_path *path = get_compound_ent_value_path(ent, i);
- int path_len = get_compound_graph_path_length(path);
- int offset = get_compound_ent_value_offset_bytes(ent, i);
- int offset_bits = get_compound_ent_value_offset_bit_remainder(ent, i);
- ir_node *value = get_compound_ent_value(ent, i);
- ir_entity *last_ent = get_compound_graph_path_node(path, path_len - 1);
- int value_len = get_type_size_bits(get_entity_type(last_ent));
- assert(offset >= 0);
+ unsigned offset = get_compound_ent_value_offset_bytes(ent, i);
+ int offset_bits = get_compound_ent_value_offset_bit_remainder(ent, i);
+ ir_node *value = get_compound_ent_value(ent, i);
+ int value_len = get_mode_size_bits(get_irn_mode(value));
+
assert(offset_bits >= 0);
if (offset_bits != 0 ||
(value_len != 8 && value_len != 16 && value_len != 32 && value_len != 64)) {
tarval *tv = get_atomic_init_tv(value);
- unsigned char curr_bits, last_bits = 0;
+ 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));
}
- /* normalize offset */
- offset += offset_bits >> 3;
- offset_bits &= 7;
+ /* normalize offset */
+ offset += offset_bits >> 3;
+ offset_bits &= 7;
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;
- curr_bits = get_tarval_sub_bits(tv, j);
+ 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;
+ 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;
}
}
/* now write them sorted */
- for (i = 0; i < last_ofs; ) {
+ for (k = 0; k < last_ofs; ) {
int space = 0, skip = 0;
- if (vals[i].kind == NORMAL) {
- if(vals[i].v.value != NULL) {
- dump_atomic_init(env, obst, vals[i].v.value);
- skip = get_mode_size_bytes(get_irn_mode(vals[i].v.value)) - 1;
+ if (vals[k].kind == NORMAL) {
+ if(vals[k].v.value != NULL) {
+ dump_atomic_init(env, obst, vals[k].v.value);
+ skip = get_mode_size_bytes(get_irn_mode(vals[k].v.value)) - 1;
} else {
space = 1;
}
} else {
- assert(vals[i].kind == BITFIELD);
- obstack_printf(obst, "\t.byte\t%d\n", vals[i].v.bf_val);
+ assert(vals[k].kind == BITFIELD);
+ obstack_printf(obst, "\t.byte\t%d\n", vals[k].v.bf_val);
}
- ++i;
- while (i < last_ofs && vals[i].kind == NORMAL && vals[i].v.value == NULL) {
+ ++k;
+ while (k < last_ofs && vals[k].kind == NORMAL && vals[k].v.value == NULL) {
++space;
- ++i;
+ ++k;
}
space -= skip;
assert(space >= 0);
obstack_t *obst;
ir_type *type = get_entity_type(ent);
const char *ld_name = get_entity_ld_name(ent);
- int align = get_type_alignment_bytes(type);
+ unsigned align = get_type_alignment_bytes(type);
int emit_as_common = 0;
ir_variability variability;
ir_visibility visibility;
if (is_Method_type(type)) {
if (get_method_img_section(ent) == section_constructors) {
obst = env->ctor_obst;
- obstack_printf(obst, ".balign\t%d\n", align);
+ obstack_printf(obst, ".balign\t%u\n", align);
dump_size_type(obst, align);
obstack_printf(obst, "%s\n", ld_name);
}
}
/* alignment */
if (align > 1 && !emit_as_common) {
- obstack_printf(obst, ".balign\t%d\n", align);
+ obstack_printf(obst, ".balign\t%u\n", align);
}
if (!emit_as_common) {
}
if (variability == variability_uninitialized) {
- if(emit_as_common) {
- if (be_gas_flavour == GAS_FLAVOUR_NORMAL)
- obstack_printf(obst, "\t.comm %s,%d,%d\n",
+ if (emit_as_common) {
+ switch (be_gas_flavour) {
+ case GAS_FLAVOUR_NORMAL:
+ case GAS_FLAVOUR_YASM:
+ obstack_printf(obst, "\t.comm %s,%u,%u\n",
ld_name, get_type_size_bytes(type), align);
- else
- obstack_printf(obst, "\t.comm %s,%d # %d\n",
+ break;
+ case GAS_FLAVOUR_MINGW:
+ obstack_printf(obst, "\t.comm %s,%u # %u\n",
ld_name, get_type_size_bytes(type), align);
+ break;
+ case GAS_FLAVOUR_MAX:
+ panic("invalid gas flavour selected");
+ }
} else {
- obstack_printf(obst, "\t.zero %d\n", get_type_size_bytes(type));
+ obstack_printf(obst, "\t.zero %u\n", get_type_size_bytes(type));
}
} else {
if (is_atomic_entity(ent)) {
/************************************************************************/
/* Generate all entities. */
-void be_gas_emit_decls(be_emit_env_t *emit, const be_main_env_t *main_env,
+void be_gas_emit_decls(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;
+ obstack_t rodata;
+ obstack_t data;
+ obstack_t bss;
+ obstack_t ctor;
+ int size;
+ char *cp;
/* dump the global type */
obstack_init(&rodata);
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);
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);