Commit d99b65fa authored by Christian Würdig's avatar Christian Würdig
Browse files

register allocator interface implemented

renamed files
fixed a lot of bugs
parent ee2cec82
#include "tv.h"
#include "iredges.h"
#include "ia32_emitter.h"
#include "ia32_nodes_attr.h"
#include "ia32_new_nodes.h"
#define TARVAL_SNPRINTF_BUF_LEN 1024
const char *get_dest_reg_name(ir_node *n, int num) {
return get_ia32_out_reg_name(n, --num);
}
const char *get_source_reg_name(ir_node *n, int num) {
return get_ia32_in_reg_name(n, --num);
}
char *node_const_to_str(ir_node *n) {
char *buf = malloc(TARVAL_SNPRINTF_BUF_LEN);
tarval_snprintf(buf, TARVAL_SNPRINTF_BUF_LEN, get_ia32_Immop_tarval(n));
return buf;
}
char *node_offset_to_str(ir_node *n) {
char *buf = malloc(TARVAL_SNPRINTF_BUF_LEN);
tarval_snprintf(buf, TARVAL_SNPRINTF_BUF_LEN, get_ia32_offs(n));
return buf;
}
void equalize_dest_src(FILE *F, ir_node *n) {
if (get_ia32_out_regnr(n, 0) != get_ia32_in_regnr(n, 0))
fprintf(F, "\tmovl %%%s, %%%s\t\t\t/* src -> dest for 2 address code */\n", get_source_reg_name(n, 1), get_dest_reg_name(n, 1));
}
/*
* coding of conditions
*/
struct cmp2conditon_t {
const char *name;
pn_Cmp num;
};
/*
* positive conditions for signed compares
*/
static const struct cmp2conditon_t cmp2condition_s[] = {
{ NULL, pn_Cmp_False }, /* always false */
{ "e", pn_Cmp_Eq }, /* == */
{ "l", pn_Cmp_Lt }, /* < */
{ "le", pn_Cmp_Le }, /* <= */
{ "g", pn_Cmp_Gt }, /* > */
{ "ge", pn_Cmp_Ge }, /* >= */
{ "ne", pn_Cmp_Lg }, /* != */
{ "ordered", pn_Cmp_Leg }, /* Floating point: ordered */
{ "unordered", pn_Cmp_Uo }, /* FLoting point: unordered */
{ "unordered or ==", pn_Cmp_Ue }, /* Floating point: unordered or == */
{ "unordered or <", pn_Cmp_Ul }, /* Floating point: unordered or < */
{ "unordered or <=", pn_Cmp_Ule }, /* Floating point: unordered or <= */
{ "unordered or >", pn_Cmp_Ug }, /* Floating point: unordered or > */
{ "unordered or >=", pn_Cmp_Uge }, /* Floating point: unordered or >= */
{ "unordered or !=", pn_Cmp_Ne }, /* Floating point: unordered or != */
{ NULL, pn_Cmp_True }, /* always true */
};
/*
* positive conditions for unsigned compares
*/
static const struct cmp2conditon_t cmp2condition_u[] = {
{ NULL, pn_Cmp_False }, /* always false */
{ "e", pn_Cmp_Eq }, /* == */
{ "b", pn_Cmp_Lt }, /* < */
{ "be", pn_Cmp_Le }, /* <= */
{ "a", pn_Cmp_Gt }, /* > */
{ "ae", pn_Cmp_Ge }, /* >= */
{ "ne", pn_Cmp_Lg }, /* != */
{ "ordered", pn_Cmp_Leg }, /* Floating point: ordered */
{ "unordered", pn_Cmp_Uo }, /* FLoting point: unordered */
{ "unordered or ==", pn_Cmp_Ue }, /* Floating point: unordered or == */
{ "unordered or <", pn_Cmp_Ul }, /* Floating point: unordered or < */
{ "unordered or <=", pn_Cmp_Ule }, /* Floating point: unordered or <= */
{ "unordered or >", pn_Cmp_Ug }, /* Floating point: unordered or > */
{ "unordered or >=", pn_Cmp_Uge }, /* Floating point: unordered or >= */
{ "unordered or !=", pn_Cmp_Ne }, /* Floating point: unordered or != */
{ NULL, pn_Cmp_True }, /* always true */
};
/*
* returns the condition code
*/
const char *get_cmp_suffix(int cmp_code, int unsigned_cmp)
{
assert(cmp2condition_s[cmp_code].num == cmp_code);
assert(cmp2condition_u[cmp_code].num == cmp_code);
return unsigned_cmp ? cmp2condition_u[cmp_code & 7].name : cmp2condition_s[cmp_code & 7].name;
}
void emit_ia32_Proj_Cond(FILE *F, ir_node *n, ir_node *cond) {
ir_node *succ_block = get_edge_src_irn(get_irn_out_edge_first(n));
ir_node *sel = get_Cond_selector(cond);
ir_mode *sel_mode = get_irn_mode(sel);
assert(succ_block && "Target block of Proj_Cond missing!");
if (sel_mode == mode_b) { // Boolean condition
int label = get_irn_node_nr(succ_block);
int nr = get_Proj_proj(n);
fprintf(F, "j%s%s Label%d\t\t\t/* if (%sCond) goto Label */\n",
nr == pn_Cond_true ? "" : "n",
get_cmp_suffix(get_Proj_proj(sel), mode_is_signed(sel_mode)),
label,
nr == pn_Cond_true ? "" : "!");
}
}
#ifndef _IA32_EMITTER_H_
#define _IA32_EMITTER_H_
#include "irnode.h"
const char *get_dest_reg_name(ir_node *n, int num);
const char *get_source_reg_name(ir_node *n, int num);
char *node_const_to_str(ir_node *n);
char *node_offset_to_str(ir_node *n);
void equalize_dest_src(FILE *F, ir_node *n);
#endif /* _IA32_EMITTER_H_ */
/**
* Dumps global variables and constants as ia32 assembler.
* @author Christian Wuerdig
* @date 04.11.2005
* @version $Id$
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <obstack.h>
#ifdef obstack_chunk_alloc
# undef obstack_chunk_alloc
# define obstack_chunk_alloc malloc
#else
# define obstack_chunk_alloc malloc
# define obstack_chunk_free free
#endif
#include "tv.h"
#include "irnode.h"
#include "entity.h"
#include "irprog.h"
#include "ia32_gen_decls.h"
/************************************************************************/
/*
* 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;
}
/*
* output the alignment
*/
static void ia32_dump_align(struct obstack *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);
}
static void dump_arith_tarval(struct obstack *obst, tarval *tv, int bytes)
{
switch (bytes) {
case 1:
obstack_printf(obst, "0x%02x", get_tarval_sub_bits(tv, 0));
break;
case 2:
obstack_printf(obst, "0x%02x%02x", get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
break;
case 4:
obstack_printf(obst, "0x%02x%02x%02x%02x",
get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
break;
case 8:
obstack_printf(obst, "0x%02x%02x%02x%02x%02x%02x%02x%02x",
get_tarval_sub_bits(tv, 7), get_tarval_sub_bits(tv, 6), get_tarval_sub_bits(tv, 5), get_tarval_sub_bits(tv, 4),
get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
break;
case 10:
case 12:
break;
default:
fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
assert(0);
}
}
/*
* dump an arithmetic tarval
*/
static void ia32_dump_arith_tarval(struct obstack *obst, tarval *tv, int bytes)
{
switch (bytes) {
case 1:
obstack_printf(obst, "\t.byte\t");
break;
case 2:
obstack_printf(obst, "\t.value\t");
break;
case 4:
obstack_printf(obst, "\t.long\t");
break;
case 8:
obstack_printf(obst, "\t.quad\t");
break;
case 10:
case 12:
break;
default:
fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
assert(0);
}
dump_arith_tarval(obst, tv, bytes);
}
/*
* dump an atomic value
*/
static void do_dump_atomic_init(struct obstack *obst, ir_node *init)
{
ir_mode *mode = get_irn_mode(init);
int bytes = get_mode_size_bytes(mode);
tarval *tv;
switch (get_irn_opcode(init)) {
case iro_Cast:
do_dump_atomic_init(obst, get_Cast_op(init));
return;
case iro_Conv:
do_dump_atomic_init(obst, get_Conv_op(init));
return;
case iro_Const:
tv = get_Const_tarval(init);
/* beware of old stuff */
assert(! mode_is_reference(mode));
/* it's a arithmetic value */
dump_arith_tarval(obst, tv, bytes);
return;
case iro_SymConst:
switch (get_SymConst_kind(init)) {
case symconst_addr_name:
obstack_printf(obst, "%s", get_id_str(get_SymConst_name(init)));
break;
case symconst_addr_ent:
obstack_printf(obst, "%s", get_entity_ld_name(get_SymConst_entity(init)));
break;
case symconst_size:
obstack_printf(obst, "%d", get_type_size_bytes(get_SymConst_type(init)));
break;
default:
assert(0 && "dump_atomic_init(): don't know how to init from this SymConst");
}
return;
case iro_Add:
do_dump_atomic_init(obst, get_Add_left(init));
obstack_printf(obst, " + ");
do_dump_atomic_init(obst, get_Add_right(init));
return;
case iro_Sub:
do_dump_atomic_init(obst, get_Sub_left(init));
obstack_printf(obst, " - ");
do_dump_atomic_init(obst, get_Sub_right(init));
return;
case iro_Mul:
do_dump_atomic_init(obst, get_Mul_left(init));
obstack_printf(obst, " * ");
do_dump_atomic_init(obst, get_Mul_right(init));
return;
default:
assert(0 && "dump_atomic_init(): unknown IR-node");
}
}
/*
* dump an atomic value
*/
static void dump_atomic_init(struct obstack *obst, ir_node *init)
{
ir_mode *mode = get_irn_mode(init);
int bytes = get_mode_size_bytes(mode);
switch (bytes) {
case 1:
obstack_printf(obst, "\t.byte\t");
break;
case 2:
obstack_printf(obst, "\t.value\t");
break;
case 4:
obstack_printf(obst, "\t.long\t");
break;
case 8:
obstack_printf(obst, "\t.quad\t");
break;
case 10:
case 12:
/* handled in arith */
break;
default:
fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
assert(0);
}
do_dump_atomic_init(obst, init);
obstack_printf(obst, "\n");
}
/************************************************************************/
/* Routines to dump global variables */
/************************************************************************/
/**
* Determine if an entity is a string constant
* @param ent The entity
* @return 1 if it is a string constant, 0 otherwise
*/
static int ent_is_string_const(entity *ent)
{
int res = 0;
type *ty;
ty = get_entity_type(ent);
/* if it's an array */
if (is_Array_type(ty)) {
type *elm_ty = get_array_element_type(ty);
/* and the array's alement type is primitive */
if (is_Primitive_type(elm_ty)) {
ir_mode *mode = get_type_mode(elm_ty);
/*
* and the mode of the element type is an int of
* the same size as the byte mode
*/
if (mode_is_int(mode)
&& get_mode_size_bits(mode) == get_mode_size_bits(mode_Bs))
{
int i, c, n;
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;
}
res = 1;
}
}
}
return res;
}
/**
* Dump a atring constant.
* No checks are made!!
* @param obst The obst to dump on.
* @param ent The entity to dump.
*/
static void dump_string_cst(struct obstack *obst, entity *ent)
{
int i, n;
obstack_printf(obst, "\t.string \"");
n = get_compound_ent_n_values(ent);
for (i = 0; i < n-1; ++i) {
ir_node *irn;
int c;
irn = get_compound_ent_value(ent, i);
c = (int) get_tarval_long(get_Const_tarval(irn));
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;
default :
if (isprint(c))
obstack_printf(obst, "%c", c);
else
obstack_printf(obst, "%O", c);
break;
}
}
obstack_printf(obst, "\"\n");
}
struct arr_info {
int n_elems;
int visit_cnt;
int size;
};
/*
* Dumps the initialization of global variables that are not
* "uninitialized".
*/
static void dump_global(struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack, entity *ent)
{
type *ty = get_entity_type(ent);
const char *ld_name = get_entity_ld_name(ent);
int align, h;
struct obstack *obst = data_obstack;
/*
* FIXME: did NOT work for partly constant values
*/
if (! is_Method_type(ty)) {
ent_variability variability = get_entity_variability(ent);
visibility visibility = get_entity_visibility(ent);
if (variability == variability_constant) {
/* a constant entity, put it on the rdata */
obst = rdata_obstack;
}
/* check, wether it is initialized, if yes create data */
if (variability != variability_uninitialized) {
if (visibility == visibility_external_visible) {
obstack_printf(obst, ".globl\t%s\n", ld_name);
}
obstack_printf(obst, "\t.type\t%s,@object\n", ld_name);
obstack_printf(obst, "\t.size\t%s,%d\n", ld_name, (get_type_size_bits(ty) + 7) >> 3);
align = get_type_alignment_bytes(ty);
ia32_dump_align(obst, align);
obstack_printf(obst, "%s:\n", ld_name);
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;
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);
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 = calloc(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 = calloc(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);
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);
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). */