Commit 88e8acd0 authored by Matthias Braun's avatar Matthias Braun
Browse files

cleanup/rewrite of ia32_gen_decls

parent e3731d22
......@@ -55,7 +55,7 @@ void ia32_switch_section(FILE *F, section_t sec) {
".section\t.text",
".section\t.data",
".section\t.rodata",
".section\t.text",
".section\t.bss",
".section\t.tbss,\"awT\",@nobits",
".section\t.ctors,\"aw\",@progbits"
},
......@@ -63,7 +63,7 @@ void ia32_switch_section(FILE *F, section_t sec) {
".section\t.text",
".section\t.data",
".section .rdata,\"dr\"",
".section\t.text",
".section\t.bss",
".section\t.tbss,\"awT\",@nobits",
".section\t.ctors,\"aw\",@progbits"
}
......@@ -2133,18 +2133,18 @@ static void ia32_emit_align_label(FILE *F, cpu_support cpu) {
}
static int is_first_loop_block(ir_node *block, ir_node *prev_block, ia32_emit_env_t *env) {
ir_exec_freq *execfreqs = env->cg->birg->execfreqs;
ir_exec_freq *exec_freq = env->cg->birg->exec_freq;
double block_freq, prev_freq;
static const double DELTA = .0001;
cpu_support cpu = env->isa->opt_arch;
if(execfreqs == NULL)
if(exec_freq == NULL)
return 0;
if(cpu == arch_i386 || cpu == arch_i486)
return 0;
block_freq = get_block_execfreq(execfreqs, block);
prev_freq = get_block_execfreq(execfreqs, prev_block);
block_freq = get_block_execfreq(exec_freq, block);
prev_freq = get_block_execfreq(exec_freq, prev_block);
if(block_freq < DELTA || prev_freq < DELTA)
return 0;
......@@ -2228,7 +2228,7 @@ static void ia32_gen_block(ir_node *block, ir_node *last_block, ia32_emit_env_t
char cmd_buf[SNPRINTF_BUF_LEN];
int i, arity;
int align = 1;
ir_exec_freq *execfreqs = env->cg->birg->execfreqs;
ir_exec_freq *exec_freq = env->cg->birg->exec_freq;
/* align the loop headers */
if (! is_first_loop_block(block, last_block, env)) {
......@@ -2261,8 +2261,8 @@ static void ia32_gen_block(ir_node *block, ir_node *last_block, ia32_emit_env_t
fprintf(F, " %ld", get_irn_node_nr(predblock));
}
if (execfreqs != NULL) {
fprintf(F, " freq: %f", get_block_execfreq(execfreqs, block));
if (exec_freq != NULL) {
fprintf(F, " freq: %f", get_block_execfreq(exec_freq, block));
}
fprintf(F, " */\n");
......
......@@ -5,6 +5,10 @@
* @version $Id$
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
......@@ -15,6 +19,7 @@
#include "irnode.h"
#include "entity.h"
#include "irprog.h"
#include "error.h"
#include "../be.h"
......@@ -26,94 +31,13 @@ typedef struct obstack obstack_t;
typedef struct _ia32_decl_env {
obstack_t *rodata_obst;
obstack_t *data_obst;
obstack_t *comm_obst;
obstack_t *bss_obst;
obstack_t *ctor_obst;
const be_main_env_t *main_env;
} ia32_decl_env_t;
/************************************************************************/
/*
* returns the highest bit value
*/
static unsigned highest_bit(unsigned v)
{
int res = -1;
if (v >= (1U << 16U)) {
res += 16;
v >>= 16;
}
if (v >= (1U << 8U)) {
res += 8;
v >>= 8;
}
if (v >= (1U << 4U)) {
res += 4;
v >>= 4;
}
if (v >= (1U << 2U)) {
res += 2;
v >>= 2;
}
if (v >= (1U << 1U)) {
res += 1;
v >>= 1;
}
if (v >= 1)
res += 1;
return res;
}
static void ia32_dump_comm(obstack_t *obst, const char *name, ir_visibility vis, int size, int align) {
switch (asm_flavour) {
case ASM_LINUX_GAS:
if (vis == visibility_local)
obstack_printf(obst, "\t.local\t%s\n", name);
obstack_printf(obst, "\t.comm\t%s,%d,%d\n", name, size, align);
break;
case ASM_MINGW_GAS:
if (vis == visibility_local)
obstack_printf(obst, "\t.lcomm\t%s,%d\n", name, size);
else
obstack_printf(obst, "\t.comm\t%s,%d\n", name, size);
break;
default:
break;
}
}
/**
* output the alignment to an obstack
*/
static void ia32_dump_align(obstack_t *obst, int align)
{
int h = highest_bit(align);
if ((1 << h) < align)
++h;
align = (1 << h);
if (align > 1)
obstack_printf(obst, "\t.align %d\n", align);
}
/**
* output the alignment to a FILE
*/
static void ia32_dump_align_f(FILE *f, int align)
{
int h = highest_bit(align);
if ((1 << h) < align)
++h;
align = (1 << h);
if (align > 1)
fprintf(f, "\t.align %d\n", align);
}
/**
* output a tarval
*/
......@@ -150,6 +74,47 @@ static void dump_arith_tarval(obstack_t *obst, tarval *tv, int bytes)
}
}
static tarval *get_atomic_init_tv(ir_node *init)
{
ir_mode *mode = get_irn_mode(init);
switch (get_irn_opcode(init)) {
case iro_Cast:
return get_atomic_init_tv(get_Cast_op(init));
case iro_Conv:
return get_atomic_init_tv(get_Conv_op(init));
case iro_Const:
return get_Const_tarval(init);
case iro_SymConst:
switch (get_SymConst_kind(init)) {
case symconst_ofs_ent:
return new_tarval_from_long(get_entity_offset_bytes(get_SymConst_entity(init)), mode);
break;
case symconst_type_size:
return new_tarval_from_long(get_type_size_bytes(get_SymConst_type(init)), mode);
case symconst_type_align:
return new_tarval_from_long(get_type_alignment_bytes(get_SymConst_type(init)), mode);
case symconst_enum_const:
return get_enumeration_value(get_SymConst_enum(init));
default:
return NULL;
}
default:
return NULL;
}
return NULL;
}
/*
* dump an atomic value
*/
......@@ -371,236 +336,207 @@ static void dump_string_cst(obstack_t *obst, entity *ent)
obstack_printf(obst, "\"\n");
}
struct arr_info {
int n_elems;
int visit_cnt;
int size;
};
/**
* Dump the size of an object
*/
static void dump_object_size(obstack_t *obst, const char *name, int size) {
switch (asm_flavour) {
case ASM_LINUX_GAS:
obstack_printf(obst, "\t.type\t%s,@object\n", name);
obstack_printf(obst, "\t.size\t%s,%d\n", name, size);
break;
default:
break;
static void dump_array_init(obstack_t *obst, entity *ent)
{
const ir_type *ty = get_entity_type(ent);
int i;
int filler;
int size = 0;
/* potential spare values should be already included! */
for (i = 0; i < get_compound_ent_n_values(ent); ++i) {
entity *step = get_compound_ent_value_member(ent, i);
ir_type *stype = get_entity_type(step);
if (get_type_mode(stype)) {
int align = (get_type_alignment_bits(stype) + 7) >> 3;
int n = size % align;
if (n > 0) {
obstack_printf(obst, "\t.zero\t%d\n", align - n);
size += align - n;
}
}
dump_atomic_init(obst, get_compound_ent_value(ent, i));
size += get_type_size_bytes(stype);
}
filler = get_type_size_bytes(ty) - size;
if (filler > 0)
obstack_printf(obst, "\t.skip\t%d\n", filler);
}
/*
* Dumps the initialization of global variables that are not
* "uninitialized".
*/
static void dump_global(const be_main_env_t *main_env,
obstack_t *rdata_obstack, obstack_t *data_obstack,
obstack_t *comm_obstack, obstack_t *ctor_obstack,
entity *ent)
enum normal_or_bitfield_kind {
NORMAL = 0,
BITFIELD
};
typedef struct {
enum normal_or_bitfield_kind kind;
union {
ir_node *value;
unsigned char bf_val;
} v;
} normal_or_bitfield;
static void dump_compound_init(obstack_t *obst, entity *ent)
{
ir_type *ty = get_entity_type(ent);
const char *ld_name = get_entity_ld_name(ent);
obstack_t *obst = data_obstack;
int align, h;
ir_type *ty = get_entity_type(ent);
normal_or_bitfield *vals;
int type_size;
int i;
int res;
res = compute_compound_ent_array_indices(ent);
if(!res) {
panic("Couldn't emit initializer for entity '%s'\n", get_entity_ld_name(ent));
}
/*
* FIXME: did NOT work for partly constant values
* in the worst case, every entity allocates one byte, so the type
* size should be equal or bigger the number of fields
*/
if (! is_Method_type(ty)) {
ir_variability variability = get_entity_variability(ent);
ir_visibility visibility = get_entity_visibility(ent);
type_size = get_type_size_bytes(ty);
vals = alloca(type_size * sizeof(vals[0]));
memset(vals, 0, type_size * sizeof(vals[0]));
/* collect the values and store them at the offsets */
for(i = 0; i < get_compound_ent_n_values(ent); ++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_part(ent, i);
ir_node *value = get_compound_ent_value(ent, i);
entity *last_ent = get_compound_graph_path_node(path, path_len - 1);
int value_len = get_type_size_bits(get_entity_type(last_ent));
if(offset_bits != 0 || value_len % 8 != 0) {
tarval *shift, *shifted;
tarval *tv = get_atomic_init_tv(value);
if(tv == NULL) {
panic("Couldn't get numeric value for bitfield initializer '%s'\n",
get_entity_ld_name(ent));
}
shift = new_tarval_from_long(offset_bits, mode_Is);
shifted = tarval_shl(tv, shift);
if(shifted == tarval_bad || shifted == tarval_undefined) {
panic("Couldn't shift numeric value for bitfield initializer '%s'\n",
get_entity_ld_name(ent));
}
if (variability == variability_constant) {
/* a constant entity, put it on the rdata */
obst = rdata_obstack;
for(int i = 0; i < 4 && value_len > 0; ++i) {
assert(offset + i < type_size);
assert(vals[offset + i].kind == BITFIELD || vals[offset + i].v.value == NULL);
vals[offset + i].kind = BITFIELD;
vals[offset + i].v.bf_val |= get_tarval_sub_bits(shifted, i);
value_len -= 8;
}
} else {
assert(offset < type_size);
assert(vals[offset].kind == NORMAL);
assert(vals[offset].v.value == NULL);
vals[offset].v.value = value;
}
}
/* check, whether it is initialized, if yes create data */
if (variability != variability_uninitialized) {
be_dbg_variable(main_env->db_handle, obst, ent);
/* now write them sorted */
for(i = 0; i < type_size; ) {
int space = 0, skip = 0;
if (vals[i].kind == NORMAL) {
if(vals[i].v.value != NULL) {
dump_atomic_init(obst, vals[i].v.value);
skip = get_mode_size_bytes(get_irn_mode(vals[i].v.value)) - 1;
} else {
space = 1;
}
} else {
obstack_printf(obst, "\t.byte\t%d\n", vals[i].v.bf_val);
}
if (visibility == visibility_external_visible) {
obstack_printf(obst, ".globl\t%s\n", ld_name);
}
dump_object_size(obst, ld_name, get_type_size_bytes(ty));
++i;
space = 0;
while(i < type_size && vals[i].kind == NORMAL && vals[i].v.value == NULL) {
++space;
++i;
}
space -= skip;
assert(space >= 0);
align = get_type_alignment_bytes(ty);
ia32_dump_align(obst, align);
/* a gap */
if(space > 0)
obstack_printf(obst, "\t.skip\t%d\n", space);
}
}
obstack_printf(obst, "%s:\n", ld_name);
static void dump_global(ia32_decl_env_t *env, entity *ent)
{
obstack_t *obst;
ir_type *type = get_entity_type(ent);
const char *ld_name = get_entity_ld_name(ent);
ir_variability variability = get_entity_variability(ent);
ir_visibility visibility = get_entity_visibility(ent);
int align = get_type_alignment_bytes(type);
obst = env->data_obst;
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);
dump_size_type(obst, align);
obstack_printf(obst, "%s\n", ld_name);
}
return;
} else if(variability == variability_constant) {
/* a constant entity, put it on the rdata */
obst = env->rodata_obst;
} else if(variability == variability_uninitialized) {
/* uninitialized entity put it in bss segment */
obst = env->bss_obst;
}
if (is_atomic_type(ty)) {
if (get_entity_visibility(ent) != visibility_external_allocated)
dump_atomic_init(obst, get_atomic_ent_value(ent));
}
else {
int i, size = 0;
be_dbg_variable(env->main_env->db_handle, obst, ent);
if (ent_is_string_const(ent)) {
dump_string_cst(obst, ent);
}
else if (is_Array_type(ty)) {
int filler;
/* potential spare values should be already included! */
for (i = 0; i < get_compound_ent_n_values(ent); ++i) {
entity *step = get_compound_ent_value_member(ent, i);
ir_type *stype = get_entity_type(step);
if (get_type_mode(stype)) {
int align = (get_type_alignment_bits(stype) + 7) >> 3;
int n = size % align;
if (n > 0) {
obstack_printf(obst, "\t.zero\t%d\n", align - n);
size += align - n;
}
}
dump_atomic_init(obst, get_compound_ent_value(ent, i));
size += get_type_size_bytes(stype);
}
filler = get_type_size_bytes(ty) - size;
if (filler > 0)
obstack_printf(obst, "\t.zero\t%d\n", filler);
}
else if (is_compound_type(ty)) {
ir_node **vals;
int type_size, j;
/* Compound entities are NOT sorted.
* The sorting strategy used doesn't work for `value' compound fields nor
* for partially_constant entities.
*/
/*
* in the worst case, every entity allocates one byte, so the type
* size should be equal or bigger the number of fields
*/
type_size = get_type_size_bytes(ty);
vals = xcalloc(type_size, sizeof(*vals));
/* collect the values and store them at the offsets */
for(i = 0; i < get_compound_ent_n_values(ent); ++i) {
int graph_length, aipos, offset;
struct arr_info *ai;
int all_n = 1;
compound_graph_path *path = get_compound_ent_value_path(ent, i);
/* get the access path to the costant value */
graph_length = get_compound_graph_path_length(path);
ai = xcalloc(graph_length, sizeof(struct arr_info));
/* We wanna know how many arrays are on the path to the entity. We also have to know how
* many elements each array holds to calculate the offset for the entity. */
for (j = 0; j < graph_length; j++) {
entity *step = get_compound_graph_path_node(path, j);
ir_type *step_type = get_entity_type(step);
int ty_size = (get_type_size_bits(step_type) + 7) >> 3;
int k, n = 0;
if (is_Array_type(step_type))
for (k = 0; k < get_array_n_dimensions(step_type); k++)
n += get_tarval_long(get_Const_tarval(get_array_upper_bound(step_type, k)));
if (n) all_n *= n;
ai[j].n_elems = n ? all_n + 1 : 0;
ai[j].visit_cnt = 0;
ai[j].size = ty_size;
}
aipos = graph_length - 1;
if (aipos) aipos--;
for (offset = j = 0; j < graph_length; j++) {
entity *step = get_compound_graph_path_node(path, j);
ir_type *step_type = get_entity_type(step);
int ent_ofs = get_entity_offset_bytes(step);
int stepsize = 0;
/* add all positive offsets (= offsets in structs) */
if (ent_ofs >= 0) offset += ent_ofs;
if (j == graph_length - 1) {
stepsize = (get_type_size_bits(step_type) + 7) >> 3;
/* Search the next free position in vals depending on the information from above (ai). */
while (vals[offset] && aipos >= 0) {
if (ai[aipos].visit_cnt < ai[aipos].n_elems) {
offset += stepsize;
ai[aipos].visit_cnt++;
}
else
while (aipos >= 0 && ai[aipos].visit_cnt == ai[aipos].n_elems) {
stepsize = ai[aipos--].size;
offset += stepsize;
}
}
assert(aipos >= 0 && "couldn't store entity");
vals[offset] = get_compound_ent_value(ent, i);
}
}
free(ai);
}
/* now write them sorted */
for(i = 0; i < type_size; ) {
if (vals[i]) {
dump_atomic_init(obst, vals[i]);
i += (get_mode_size_bytes(get_irn_mode(vals[i])));
}
else {
/* a gap */
obstack_printf(obst, "\t.byte\t0\n");
++i;
}
}
free(vals);
}
else {
assert(0 && "unsupported type");
}
}
obstack_printf(obst, "\n");
}
else if (visibility != visibility_external_allocated) {
be_dbg_variable(main_env->db_handle, comm_obstack, ent);
/* uninitialized and NOT external */
if (get_entity_owner(ent) != get_tls_type()) {
/* calculate the alignment */
align = get_type_alignment_bytes(ty);
h = highest_bit(align);
if ((1 << h) < align)
++h;
align = (1 << h);
if (align < 1)
align = 1;
ia32_dump_comm(comm_obstack, ld_name, visibility,
get_type_size_bytes(ty), align);
} else {
/* TLS */
if (visibility == visibility_external_visible) {
obstack_printf(comm_obstack, ".globl\t%s\n", ld_name);
}
dump_object_size(comm_obstack, ld_name, get_type_size_bytes(ty));
align = get_type_alignment_bytes(ty);
ia32_dump_align(comm_obstack, align);
obstack_printf(comm_obstack, "%s:\n\t.zero %d\n", ld_name, get_type_size_bytes(ty));
}
}
} /* ! is method type */
else if (ctor_obstack && get_method_img_section(ent) == section_constructors) {
ia32_dump_align(ctor_obstack, get_type_alignment_bytes(ty));
dump_size_type(ctor_obstack, get_type_alignment_bytes(ty));
obstack_printf(ctor_obstack, "%s\n", ld_name);
/* global or not global */
if(visibility == visibility_external_visible) {
obstack_printf(obst, ".global\t%s\n", ld_name);
} else if(visibility == visibility_external_allocated) {
obstack_printf(obst, ".global\t%s\n", ld_name);
/* we can return now... */
return;
}
/* alignment */
if(align > 1) {
obstack_printf(obst, ".balign\t%d\n", align);
}
obstack_printf(obst, "%s:\n<