Commit cf79ddfe authored by Matthias Braun's avatar Matthias Braun
Browse files

introduce new mode for initializer

[r17319]
parent d573712d
......@@ -67,6 +67,8 @@ typedef struct ir_exec_freq ir_exec_freq, *ir_exec_freq_ptr;
typedef struct ir_cdep ir_cdep, *ir_cdep_ptr;
typedef struct sn_entry *seqno_t;
typedef union ir_initializer_t ir_initializer_t, *ir_initializer_ptr;
typedef void irg_walk_func(ir_node *, void *);
typedef void irg_reg_walk_func(ir_region *, void *);
......
......@@ -454,6 +454,55 @@ ir_node *copy_const_value(dbg_info *dbg, ir_node *n);
ir_node *get_atomic_ent_value(ir_entity *ent);
void set_atomic_ent_value(ir_entity *ent, ir_node *val);
/** the kind (type) of an initializer */
typedef enum ir_initializer_kind_t {
/* initializer containing an ir_node from the const-code irg */
IR_INITIALIZER_CONST,
/* initializer containing a tarval */
IR_INITIALIZER_TARVAL,
/* initializes type with default values (usually 0) */
IR_INITIALIZER_NULL,
/* list of initializers used to initializer a compound or array type */
IR_INITIALIZER_COMPOUND
} ir_initializer_kind_t;
/** returns kind of an initializer */
ir_initializer_kind_t get_initializer_kind(const ir_initializer_t *initializer);
/**
* returns the null initializer (there's only one instance of it in a program )
*/
ir_initializer_t *get_initializer_null(void);
/**
* creates an initializer containing a reference to a node on the const-code
* irg.
*/
ir_initializer_t *create_initializer_const(ir_node *value);
/** creates an initializer containing a single tarval value */
ir_initializer_t *create_initializer_tarval(tarval *tv);
/** return value contained in a const initializer */
ir_node *get_initializer_const_value(const ir_initializer_t *initializer);
/** return value contained in a tarval initializer */
tarval *get_initializer_tarval_value(const ir_initializer_t *initialzier);
/** creates a compound initializer which holds @p n_entries entries */
ir_initializer_t *create_initializer_compound(unsigned n_entries);
/** returns the number of entries in a compound initializer */
unsigned get_initializer_compound_n_entries(const ir_initializer_t *initializer);
/** sets entry with index @p index to the initializer @p value */
void set_initializer_compound_value(ir_initializer_t *initializer,
unsigned index, ir_initializer_t *value);
/** returns the value with index @p index of a compound initializer */
ir_initializer_t *get_initializer_compound_value(
const ir_initializer_t *initializer, unsigned index);
/** Creates a new compound graph path of given length. */
compound_graph_path *new_compound_graph_path(ir_type *tp, int length);
......@@ -515,6 +564,10 @@ ir_entity *get_compound_ent_value_member(ir_entity *ent, int pos);
/** Sets the path at pos 0 */
void set_compound_ent_value(ir_entity *ent, ir_node *val, ir_entity *member, int pos);
void set_entity_initializer(ir_entity *entity, ir_initializer_t *initializer);
ir_initializer_t *get_entity_initializer(const ir_entity *entity);
/** Initializes the entity ent which must be of a one dimensional
array type with the values given in the values array.
The array must have a lower and an upper bound. Keeps the
......
......@@ -58,6 +58,7 @@
#include "eset.h"
#include "pmap.h"
#include "array.h"
#include "error.h"
#include "irdump.h"
......@@ -478,6 +479,39 @@ static void free_ana_walker(ir_node *node, void *env) {
set_irn_link(node, NULL);
}
static void add_method_address_intitialzer(ir_initializer_t *initializer,
eset *set)
{
switch(initializer->kind) {
case IR_INITIALIZER_CONST: {
ir_node *n = initializer->consti.value;
/* let's check if it's the address of a function */
if (is_SymConst_addr_ent(n)) {
ir_entity *ent = get_SymConst_entity(n);
if (is_Method_type(get_entity_type(ent)))
eset_insert(set, ent);
}
return;
}
case IR_INITIALIZER_TARVAL:
case IR_INITIALIZER_NULL:
return;
case IR_INITIALIZER_COMPOUND: {
size_t i;
for(i = 0; i < initializer->compound.n_initializers; ++i) {
ir_initializer_t *sub_initializer
= initializer->compound.initializers[i];
add_method_address_intitialzer(sub_initializer, set);
}
return;
}
}
panic("invalid initializer found");
}
/**
* Add all method addresses in global initializers to the set.
*
......@@ -499,7 +533,9 @@ static void add_method_address(ir_entity *ent, eset *set)
if (get_entity_variability(ent) == variability_uninitialized)
return;
if (is_atomic_entity(ent)) {
if (ent->has_initializer) {
} else if (is_atomic_entity(ent)) {
tp = get_entity_type(ent);
/* ignore methods: these of course reference it's address */
......
......@@ -41,6 +41,7 @@
#include "irgwalk.h"
#include "irprintf.h"
#include "debug.h"
#include "error.h"
/** The debug handle. */
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
......@@ -952,6 +953,36 @@ static void init_taken_flag(ir_type * tp) {
}
} /* init_taken_flag */
static void check_initializer_nodes(ir_initializer_t *initializer)
{
switch(initializer->kind) {
case IR_INITIALIZER_CONST: {
ir_node *n = initializer->consti.value;
/* let's check if it's an address */
if (is_SymConst_addr_ent(n)) {
ir_entity *ent = get_SymConst_entity(n);
set_entity_address_taken(ent, ir_address_taken);
}
return;
}
case IR_INITIALIZER_TARVAL:
case IR_INITIALIZER_NULL:
return;
case IR_INITIALIZER_COMPOUND: {
size_t i;
for(i = 0; i < initializer->compound.n_initializers; ++i) {
ir_initializer_t *sub_initializer
= initializer->compound.initializers[i];
check_initializer_nodes(sub_initializer);
}
return;
}
}
panic("invalid initialzier found");
}
/**
* Mark all entities used in the initializer for the given entity as address taken
*/
......@@ -968,7 +999,9 @@ static void check_initializer(ir_entity *ent) {
if (is_Method_type(get_entity_type(ent)))
return;
if (is_atomic_entity(ent)) {
if (ent->has_initializer) {
check_initializer_nodes(ent->attr.initializer);
} else if (is_atomic_entity(ent)) {
/* let's check if it's an address */
n = get_atomic_ent_value(ent);
if (is_SymConst_addr_ent(n)) {
......
......@@ -40,6 +40,7 @@
#include "irnode.h"
#include "irprog.h"
#include "pdeq.h"
#include "entity_t.h"
#include "error.h"
#include "be_t.h"
......@@ -353,7 +354,7 @@ static void do_dump_atomic_init(be_gas_decl_env_t *env, obstack_t *obst,
* @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:
......@@ -409,6 +410,40 @@ static void dump_atomic_init(be_gas_decl_env_t *env, obstack_t *obst,
/* 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;
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 && !(isgraph(c) || isspace(c)))
|| (i >= len - 1 && c != 0))
return 0;
}
return 1;
}
/**
* Determine if an entity is a string constant
* @param ent The entity
......@@ -439,18 +474,23 @@ static int ent_is_string_const(ir_entity *ent)
|| 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 (! 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;
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 */
......@@ -506,19 +546,299 @@ static void dump_string_cst(obstack_t *obst, ir_entity *ent)
}
}
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; ++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: {
tarval *tv = get_initializer_tarval_value(initializer);
assert(get_tarval_mode(tv) == 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_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 {
assert(is_compound_type(type));
size_t n_members = get_compound_n_members(type);
size_t i;
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_initializer_t *sub_initializer;
assert(i < get_initializer_compound_n_entries(initializer));
sub_initializer
= get_initializer_compound_value(initializer, i);
dump_ir_initializer(&vals[offset], sub_initializer, subtype);
}
}
return;
}
}
#if 0
/* collect the values and store them at the offsets */
for (i = 0; i < n; ++i) {
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;
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;
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);
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);
for (i = 1; i < value_len / 8; ++i) {
assert(vals[offset + i].v.value == NULL);
}
vals[offset].v.value = value;
}
}
#endif
}
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);
/*
* 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.
*/
......@@ -526,9 +846,16 @@ static void dump_compound_init(be_gas_decl_env_t *env, obstack_t *obst,
ir_entity *ent)
{
normal_or_bitfield *vals;
int i, j, n = get_compound_ent_n_values(ent);
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. */
......@@ -695,6 +1022,8 @@ static void dump_global(be_gas_decl_env_t *env, ir_entity *ent, int emit_commons
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 %u\n", get_type_size_bytes(type));
......
......@@ -40,13 +40,13 @@
#include "irhooks.h"
#include "irprintf.h"
/* All this is needed to build the constant node for methods: */
#include "irprog_t.h"
#include "ircons.h"
#include "tv_t.h"
#include "irdump.h" /* for output if errors occur. */
#include "irdump.h"
#include "irgraph_t.h"
#include "callgraph.h" /* for dumping debug output */
#include "callgraph.h"
/**