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

fixed symconsts in address mode

parent f4026a7b
......@@ -440,9 +440,15 @@ char *ia32_emit_am(const ir_node *n, ia32_emit_env_t *env) {
}
}
obstack_printf(obst, "[");
/* emit address mode symconst */
if (get_ia32_am_sc(n)) {
if (is_ia32_am_sc_sign(n))
obstack_printf(obst, "-");
obstack_printf(obst, "%s", get_id_str(get_ia32_am_sc(n)));
}
if (am_flav & ia32_B) {
obstack_printf(obst, "[");
lc_eoprintf(ia32_get_arg_env(), obst, "%1S", n);
had_output = 1;
}
......@@ -451,6 +457,9 @@ char *ia32_emit_am(const ir_node *n, ia32_emit_env_t *env) {
if (had_output) {
obstack_printf(obst, "+");
}
else {
obstack_printf(obst, "[");
}
lc_eoprintf(ia32_get_arg_env(), obst, "%2S", n);
......@@ -464,14 +473,21 @@ char *ia32_emit_am(const ir_node *n, ia32_emit_env_t *env) {
if (am_flav & ia32_O) {
s = get_ia32_am_offs(n);
/* omit explicit + if there was no base or index */
if (! had_output && s[0] == '+')
s++;
if (s) {
/* omit explicit + if there was no base or index */
if (! had_output) {
obstack_printf(obst, "[");
if (s[0] == '+')
s++;
}
obstack_printf(obst, s);
obstack_printf(obst, s);
had_output = 1;
}
}
obstack_printf(obst, "] ");
if (had_output)
obstack_printf(obst, "] ");
size = obstack_object_size(obst);
s = obstack_finish(obst);
......
......@@ -537,6 +537,46 @@ void sub_ia32_am_offs(ir_node *node, const char *offset) {
extend_ia32_am_offs(node, (char *)offset, '-');
}
/**
* Returns the symconst ident associated to addrmode.
*/
ident *get_ia32_am_sc(const ir_node *node) {
ia32_attr_t *attr = get_ia32_attr(node);
return attr->am_sc;
}
/**
* Sets the symconst ident associated to addrmode.
*/
void set_ia32_am_sc(ir_node *node, ident *sc) {
ia32_attr_t *attr = get_ia32_attr(node);
attr->am_sc = sc;
}
/**
* Sets the sign bit for address mode symconst.
*/
void set_ia32_am_sc_sign(ir_node *node) {
ia32_attr_t *attr = get_ia32_attr(node);
attr->data.am_sc_sign = 1;
}
/**
* Clears the sign bit for address mode symconst.
*/
void clear_ia32_am_sc_sign(ir_node *node) {
ia32_attr_t *attr = get_ia32_attr(node);
attr->data.am_sc_sign = 0;
}
/**
* Returns the sign bit for address mode symconst.
*/
int is_ia32_am_sc_sign(const ir_node *node) {
ia32_attr_t *attr = get_ia32_attr(node);
return attr->data.am_sc_sign;
}
/**
* Gets the addr mode const.
*/
......
......@@ -81,6 +81,31 @@ void add_ia32_am_offs(ir_node *node, const char *offset);
*/
void sub_ia32_am_offs(ir_node *node, const char *offset);
/**
* Returns the symconst ident associated to addrmode.
*/
ident *get_ia32_am_sc(const ir_node *node);
/**
* Sets the symconst ident associated to addrmode.
*/
void set_ia32_am_sc(ir_node *node, ident *sc);
/**
* Sets the sign bit for address mode symconst.
*/
void set_ia32_am_sc_sign(ir_node *node);
/**
* Clears the sign bit for address mode symconst.
*/
void clear_ia32_am_sc_sign(ir_node *node);
/**
* Returns the sign bit for address mode symconst.
*/
int is_ia32_am_sc_sign(const ir_node *node);
/**
* Gets the addr mode const.
*/
......
......@@ -76,6 +76,7 @@ typedef struct _ia32_attr_t {
unsigned am_scale:2; /**< addrmode scale for index register */
unsigned offs_sign:1; /**< sign bit of the first offset */
unsigned am_sc_sign:1; /**< sign bit of the address mode symconst */
unsigned use_frame:1; /**< indicates whether the operation uses the frame pointer or not */
......@@ -87,10 +88,11 @@ typedef struct _ia32_attr_t {
unsigned emit_cl:1; /**< indicates whether we must emit cl instead of ecx (needed for shifts) */
unsigned n_res:9; /**< number of results produced by this node */
unsigned n_res:8; /**< number of results produced by this node */
} data;
struct obstack *am_offs; /**< offsets for AddrMode */
ident *am_sc; /**< SymConst for AddrMode */
union {
tarval *tv; /**< tarval for immediate operations */
......
......@@ -421,7 +421,7 @@ void ia32_peephole_optimization(ir_node *irn, void *env) {
*
******************************************************************/
static int node_is_comm(const ir_node *irn) {
static int node_is_ia32_comm(const ir_node *irn) {
return is_ia32_irn(irn) ? is_ia32_commutative(irn) : 0;
}
......@@ -568,21 +568,26 @@ static int load_store_addr_is_equal(const ir_node *load, const ir_node *store,
int is_equal = (addr_b == get_irn_n(load, 0)) && (addr_i == get_irn_n(load, 1));
entity *lent = get_ia32_frame_ent(load);
entity *sent = get_ia32_frame_ent(store);
ident *lid = get_ia32_am_sc(load);
ident *sid = get_ia32_am_sc(store);
char *loffs = get_ia32_am_offs(load);
char *soffs = get_ia32_am_offs(store);
/* are both entities set and equal? */
if (lent || sent)
if (is_equal && (lent || sent))
is_equal = lent && sent && (lent == sent);
/* are the load and the store of the same mode? */
is_equal = get_ia32_ls_mode(load) == get_ia32_ls_mode(store);
/* are address mode idents set and equal? */
if (is_equal && (lid || sid))
is_equal = lid && sid && (lid == sid);
/* are offsets set and equal */
if (loffs || soffs)
if (is_equal && (loffs || soffs))
is_equal = loffs && soffs && strcmp(loffs, soffs) == 0;
/* are the load and the store of the same mode? */
is_equal = is_equal ? get_ia32_ls_mode(load) == get_ia32_ls_mode(store) : 0;
return is_equal;
}
......@@ -592,18 +597,22 @@ static int load_store_addr_is_equal(const ir_node *load, const ir_node *store,
* Folds Add or Sub to LEA if possible
*/
static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn, firm_dbg_module_t *mod, ir_node *noreg) {
ir_graph *irg = get_irn_irg(irn);
dbg_info *dbg = get_irn_dbg_info(irn);
ir_node *block = get_nodes_block(irn);
ir_node *res = irn;
char *offs = NULL;
const char *offs_cnst = NULL;
char *offs_lea = NULL;
int scale = 0;
int isadd = 0;
int dolea = 0;
ir_node *left, *right, *temp;
ir_node *base, *index;
ir_graph *irg = get_irn_irg(irn);
dbg_info *dbg = get_irn_dbg_info(irn);
ir_node *block = get_nodes_block(irn);
ir_node *res = irn;
char *offs = NULL;
const char *offs_cnst = NULL;
char *offs_lea = NULL;
int scale = 0;
int isadd = 0;
int dolea = 0;
int have_am_sc = 0;
int am_sc_sign = 0;
ident *am_sc_lea = NULL;
ident *am_sc = NULL;
ir_node *left, *right, *temp;
ir_node *base, *index;
ia32_am_flavour_t am_flav;
if (is_ia32_Add(irn))
......@@ -648,13 +657,21 @@ static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn, firm_dbg_module_t *
scale = 0;
am_flav = 0;
/* check if operand is either const */
if (is_ia32_ImmConst(irn) || is_ia32_ImmSymConst(irn)) {
DBG((mod, LEVEL_1, "\tfound op with imm"));
/* check for operation with immediate */
if (is_ia32_ImmConst(irn)) {
DBG((mod, LEVEL_1, "\tfound op with imm const"));
offs_cnst = get_ia32_cnst(irn);
dolea = 1;
}
else if (is_ia32_ImmSymConst(irn)) {
DBG((mod, LEVEL_1, "\tfound op with imm symconst"));
have_am_sc = 1;
dolea = 1;
am_sc = get_ia32_id_cnst(irn);
am_sc_sign = is_ia32_am_sc_sign(irn);
}
/* determine the operand which needs to be checked */
if (be_is_NoReg(cg, right)) {
......@@ -664,12 +681,17 @@ static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn, firm_dbg_module_t *
temp = right;
}
/* check if right operand is AMConst (LEA with ia32_am_O) */
if (is_ia32_Lea(temp) && get_ia32_am_flavour(temp) == ia32_am_O) {
/* check if right operand is AMConst (LEA with ia32_am_O) */
/* but we can only eat it up if there is no other symconst */
/* because the linker won't accept two symconsts */
if (! have_am_sc && is_ia32_Lea(temp) && get_ia32_am_flavour(temp) == ia32_am_O) {
DBG((mod, LEVEL_1, "\tgot op with LEA am_O"));
offs_lea = get_ia32_am_offs(temp);
dolea = 1;
offs_lea = get_ia32_am_offs(temp);
am_sc = get_ia32_am_sc(temp);
am_sc_sign = is_ia32_am_sc_sign(temp);
have_am_sc = 1;
dolea = 1;
}
if (isadd) {
......@@ -724,17 +746,21 @@ static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn, firm_dbg_module_t *
/* a new LEA. */
/* If the LEA contains already a frame_entity then we also */
/* create a new one otherwise we would loose it. */
if ((isadd && !be_is_NoReg(cg, index) && (am_flav & ia32_am_I)) ||
get_ia32_frame_ent(left))
if ((isadd && !be_is_NoReg(cg, index) && (am_flav & ia32_am_I)) || /* no new LEA if index already set */
get_ia32_frame_ent(left) || /* no new LEA if stack access */
(have_am_sc && get_ia32_am_sc(left))) /* no new LEA if AM symconst already present */
{
DBG((mod, LEVEL_1, "\tleave old LEA, creating new one\n"));
}
else {
DBG((mod, LEVEL_1, "\tgot LEA as left operand ... assimilating\n"));
offs = get_ia32_am_offs(left);
base = get_irn_n(left, 0);
index = get_irn_n(left, 1);
scale = get_ia32_am_scale(left);
offs = get_ia32_am_offs(left);
am_sc = have_am_sc ? am_sc : get_ia32_am_sc(left);
have_am_sc = am_sc ? 1 : 0;
am_sc_sign = is_ia32_am_sc_sign(left);
base = get_irn_n(left, 0);
index = get_irn_n(left, 1);
scale = get_ia32_am_scale(left);
}
}
......@@ -770,6 +796,13 @@ static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn, firm_dbg_module_t *
}
}
/* set the address mode symconst */
if (have_am_sc) {
set_ia32_am_sc(res, am_sc);
if (am_sc_sign)
set_ia32_am_sc_sign(res);
}
/* copy the frame entity (could be set in case of Add */
/* which was a FrameAddr) */
set_ia32_frame_ent(res, get_ia32_frame_ent(irn));
......@@ -895,6 +928,10 @@ void ia32_optimize_am(ir_node *irn, void *env) {
set_ia32_am_scale(irn, get_ia32_am_scale(left));
set_ia32_am_flavour(irn, get_ia32_am_flavour(left));
set_ia32_am_sc(irn, get_ia32_am_sc(left));
if (is_ia32_am_sc_sign(left))
set_ia32_am_sc_sign(irn);
set_ia32_op_type(irn, is_ia32_Ld(irn) ? ia32_AddrModeS : ia32_AddrModeD);
/* set base and index */
......@@ -919,7 +956,7 @@ void ia32_optimize_am(ir_node *irn, void *env) {
}
/* normalize commutative ops */
if (node_is_comm(irn)) {
if (node_is_ia32_comm(irn)) {
/* Assure that right operand is always a Load if there is one */
/* because non-commutative ops can only use Dest AM if the right */
/* operand is a load, so we only need to check right operand. */
......@@ -980,7 +1017,7 @@ void ia32_optimize_am(ir_node *irn, void *env) {
/* Extra check for commutative ops with two Loads */
/* -> put the interesting Load right */
if (node_is_comm(irn) &&
if (node_is_ia32_comm(irn) &&
pred_is_specific_nodeblock(block, left, is_ia32_Ld))
{
if ((addr_b == get_irn_n(get_Proj_pred(left), 0)) &&
......@@ -1015,6 +1052,10 @@ void ia32_optimize_am(ir_node *irn, void *env) {
set_ia32_frame_ent(irn, get_ia32_frame_ent(load));
set_ia32_ls_mode(irn, get_ia32_ls_mode(load));
set_ia32_am_sc(irn, get_ia32_am_sc(load));
if (is_ia32_am_sc_sign(load))
set_ia32_am_sc_sign(irn);
if (is_ia32_use_frame(load))
set_ia32_use_frame(irn);
......@@ -1052,7 +1093,7 @@ void ia32_optimize_am(ir_node *irn, void *env) {
}
/* normalize commutative ops */
if (node_is_comm(irn)) {
if (node_is_ia32_comm(irn)) {
/* Assure that left operand is always a Load if there is one */
/* because non-commutative ops can only use Source AM if the */
/* left operand is a Load, so we only need to check the left */
......@@ -1088,6 +1129,10 @@ void ia32_optimize_am(ir_node *irn, void *env) {
set_ia32_frame_ent(irn, get_ia32_frame_ent(left));
set_ia32_ls_mode(irn, get_ia32_ls_mode(left));
set_ia32_am_sc(irn, get_ia32_am_sc(left));
if (is_ia32_am_sc_sign(left))
set_ia32_am_sc_sign(irn);
/* clear remat flag */
set_ia32_flags(irn, get_ia32_flags(irn) & ~arch_irn_flags_rematerializable);
......
......@@ -458,15 +458,35 @@ static ir_node *gen_Add(ia32_transform_env_t *env, ir_node *op1, ir_node *op2) {
/* No expr_op means, that we have two const - one symconst and */
/* one tarval or another symconst - because this case is not */
/* covered by constant folding */
/* We need to check for: */
/* 1) symconst + const -> becomes a LEA */
/* 2) symconst + symconst -> becomes a const + LEA as the elf */
/* linker doesn't support two symconsts */
if (get_ia32_op_type(op1) == ia32_SymConst && get_ia32_op_type(op2) == ia32_SymConst) {
/* this is the 2nd case */
new_op = new_rd_ia32_Lea(dbg, irg, block, op1, noreg, mode);
set_ia32_am_sc(new_op, get_ia32_id_cnst(op2));
set_ia32_am_flavour(new_op, ia32_am_OB);
}
else {
/* this is the 1st case */
new_op = new_rd_ia32_Lea(dbg, irg, block, noreg, noreg, mode);
new_op = new_rd_ia32_Lea(dbg, irg, block, noreg, noreg, mode);
add_ia32_am_offs(new_op, get_ia32_cnst(op1));
add_ia32_am_offs(new_op, get_ia32_cnst(op2));
if (get_ia32_op_type(op1) == ia32_SymConst) {
set_ia32_am_sc(new_op, get_ia32_id_cnst(op1));
add_ia32_am_offs(new_op, get_ia32_cnst(op2));
}
else {
add_ia32_am_offs(new_op, get_ia32_cnst(op1));
set_ia32_am_sc(new_op, get_ia32_id_cnst(op2));
}
set_ia32_am_flavour(new_op, ia32_am_O);
}
/* set AM support */
set_ia32_am_support(new_op, ia32_am_Source);
set_ia32_op_type(new_op, ia32_AddrModeS);
set_ia32_am_flavour(new_op, ia32_am_O);
/* Lea doesn't need a Proj */
return new_op;
......@@ -743,15 +763,37 @@ static ir_node *gen_Sub(ia32_transform_env_t *env, ir_node *op1, ir_node *op2) {
/* No expr_op means, that we have two const - one symconst and */
/* one tarval or another symconst - because this case is not */
/* covered by constant folding */
/* We need to check for: */
/* 1) symconst + const -> becomes a LEA */
/* 2) symconst + symconst -> becomes a const + LEA as the elf */
/* linker doesn't support two symconsts */
if (get_ia32_op_type(op1) == ia32_SymConst && get_ia32_op_type(op2) == ia32_SymConst) {
/* this is the 2nd case */
new_op = new_rd_ia32_Lea(dbg, irg, block, op1, noreg, mode);
set_ia32_am_sc(new_op, get_ia32_id_cnst(op2));
set_ia32_am_sc_sign(new_op);
set_ia32_am_flavour(new_op, ia32_am_OB);
}
else {
/* this is the 1st case */
new_op = new_rd_ia32_Lea(dbg, irg, block, noreg, noreg, mode);
new_op = new_rd_ia32_Lea(dbg, irg, block, noreg, noreg, mode);
add_ia32_am_offs(new_op, get_ia32_cnst(op1));
sub_ia32_am_offs(new_op, get_ia32_cnst(op2));
if (get_ia32_op_type(op1) == ia32_SymConst) {
set_ia32_am_sc(new_op, get_ia32_id_cnst(op1));
sub_ia32_am_offs(new_op, get_ia32_cnst(op2));
}
else {
add_ia32_am_offs(new_op, get_ia32_cnst(op1));
set_ia32_am_sc(new_op, get_ia32_id_cnst(op2));
set_ia32_am_sc_sign(new_op);
}
set_ia32_am_flavour(new_op, ia32_am_O);
}
/* set AM support */
set_ia32_am_support(new_op, ia32_am_Source);
set_ia32_op_type(new_op, ia32_AddrModeS);
set_ia32_am_flavour(new_op, ia32_am_O);
/* Lea doesn't need a Proj */
return new_op;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment