-/**
- * Folds Add or Sub to LEA if possible
- */
-static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn) {
- ir_graph *irg = get_irn_irg(irn);
- dbg_info *dbg_info = get_irn_dbg_info(irn);
- ir_node *block = get_nodes_block(irn);
- ir_node *res = irn;
- ir_node *shift = NULL;
- ir_node *lea_o = NULL;
- ir_node *lea = NULL;
- long offs = 0;
- long offs_cnst = 0;
- long offs_lea = 0;
- int scale = 0;
- int isadd = 0;
- int dolea = 0;
- int have_am_sc = 0;
- int am_sc_sign = 0;
- ir_entity *am_sc = NULL;
- ir_entity *lea_ent = NULL;
- ir_node *noreg = ia32_new_NoReg_gp(cg);
- ir_node *left, *right, *temp;
- ir_node *base, *index;
- int consumed_left_shift;
- ia32_am_flavour_t am_flav;
-
- if (is_ia32_Add(irn))
- isadd = 1;
-
- left = get_irn_n(irn, 2);
- right = get_irn_n(irn, 3);
-
- /* "normalize" arguments in case of add with two operands */
- if (isadd && ! be_is_NoReg(cg, right)) {
- /* put LEA == ia32_am_O as right operand */
- if (is_ia32_Lea(left) && get_ia32_am_flavour(left) == ia32_am_O) {
- set_irn_n(irn, 2, right);
- set_irn_n(irn, 3, left);
- temp = left;
- left = right;
- right = temp;
- }
-
- /* put LEA != ia32_am_O as left operand */
- if (is_ia32_Lea(right) && get_ia32_am_flavour(right) != ia32_am_O) {
- set_irn_n(irn, 2, right);
- set_irn_n(irn, 3, left);
- temp = left;
- left = right;
- right = temp;
- }
-
- /* put SHL as left operand iff left is NOT a LEA */
- if (! is_ia32_Lea(left) && pred_is_specific_node(right, is_ia32_Shl)) {
- set_irn_n(irn, 2, right);
- set_irn_n(irn, 3, left);
- temp = left;
- left = right;
- right = temp;
- }
- }
-
- base = left;
- index = noreg;
- offs = 0;
- scale = 0;
- am_flav = 0;
-
- /* check for operation with immediate */
- if (is_ia32_ImmConst(irn)) {
- tarval *tv = get_ia32_Immop_tarval(irn);
-
- DBG((dbg, LEVEL_1, "\tfound op with imm const"));
-
- offs_cnst = get_tarval_long(tv);
- dolea = 1;
- }
- else if (isadd && is_ia32_ImmSymConst(irn)) {
- DBG((dbg, LEVEL_1, "\tfound op with imm symconst"));
-
- have_am_sc = 1;
- dolea = 1;
- am_sc = get_ia32_Immop_symconst(irn);
- am_sc_sign = is_ia32_am_sc_sign(irn);
- }
-
- /* determine the operand which needs to be checked */
- temp = be_is_NoReg(cg, right) ? left : right;
-
- /* 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((dbg, LEVEL_1, "\tgot op with LEA am_O"));
-
- offs_lea = get_ia32_am_offs_int(temp);
- am_sc = get_ia32_am_sc(temp);
- am_sc_sign = is_ia32_am_sc_sign(temp);
- have_am_sc = 1;
- dolea = 1;
- lea_o = temp;
-
- if (temp == base)
- base = noreg;
- else if (temp == right)
- right = noreg;
- }
-
- if (isadd) {
- /* default for add -> make right operand to index */
- index = right;
- dolea = 1;
- consumed_left_shift = -1;
-
- DBG((dbg, LEVEL_1, "\tgot LEA candidate with index %+F\n", index));
-
- /* determine the operand which needs to be checked */
- temp = left;
- if (is_ia32_Lea(left)) {
- temp = right;
- consumed_left_shift = 0;
- }
-
- /* check for SHL 1,2,3 */
- if (pred_is_specific_node(temp, is_ia32_Shl)) {
- ir_node *right = get_irn_n(temp, n_ia32_Shl_right);
-
- if (is_ia32_Immediate(right)) {
- const ia32_immediate_attr_t *attr
- = get_ia32_immediate_attr_const(right);
- long shiftval = attr->offset;
-
- if (shiftval <= 3) {
- index = get_irn_n(temp, 2);
- consumed_left_shift = consumed_left_shift < 0 ? 1 : 0;
- shift = temp;
- scale = shiftval;
-
- DBG((dbg, LEVEL_1, "\tgot scaled index %+F\n", index));
- }
- }
- }
-
- /* fix base */
- if (! be_is_NoReg(cg, index)) {
- /* if we have index, but left == right -> no base */
- if (left == right) {
- base = noreg;
- }
- else if (consumed_left_shift == 1) {
- /* -> base is right operand */
- base = (right == lea_o) ? noreg : right;
- }
- }
- }
-
- /* Try to assimilate a LEA as left operand */
- if (is_ia32_Lea(left) && (get_ia32_am_flavour(left) != ia32_am_O)) {
- /* check if we can assimilate the LEA */
- int take_attr = do_new_lea(irn, base, index, left, have_am_sc, cg);
-
- if (take_attr == IA32_LEA_ATTR_NONE) {
- DBG((dbg, LEVEL_1, "\tleave old LEA, creating new one\n"));
- }
- else {
- DBG((dbg, LEVEL_1, "\tgot LEA as left operand ... assimilating\n"));
- lea = left; /* for statistics */
-
- if (take_attr & IA32_LEA_ATTR_OFFS)
- offs = get_ia32_am_offs_int(left);
-
- if (take_attr & IA32_LEA_ATTR_AMSC) {
- am_sc = get_ia32_am_sc(left);
- have_am_sc = 1;
- am_sc_sign = is_ia32_am_sc_sign(left);
- }
-
- if (take_attr & IA32_LEA_ATTR_SCALE)
- scale = get_ia32_am_scale(left);
-
- if (take_attr & IA32_LEA_ATTR_BASE)
- base = get_irn_n(left, 0);
-
- if (take_attr & IA32_LEA_ATTR_INDEX)
- index = get_irn_n(left, 1);
-
- if (take_attr & IA32_LEA_ATTR_FENT)
- lea_ent = get_ia32_frame_ent(left);
- }
- }
-
- /* ok, we can create a new LEA */
- if (dolea) {
- res = new_rd_ia32_Lea(dbg_info, irg, block, base, index);
- /* we don't want stuff before the barrier... */
- if(be_is_NoReg(cg, base) && be_is_NoReg(cg, index)) {
- add_irn_dep(res, get_irg_frame(irg));
- }
-
- /* add the old offset of a previous LEA */
- add_ia32_am_offs_int(res, offs);
-
- /* add the new offset */
- if (isadd) {
- add_ia32_am_offs_int(res, offs_cnst);
- add_ia32_am_offs_int(res, offs_lea);
- } else {
- /* either lea_O-cnst, -cnst or -lea_O */
- if (offs_cnst != 0) {
- add_ia32_am_offs_int(res, offs_lea);
- add_ia32_am_offs_int(res, -offs_cnst);
- } else {
- add_ia32_am_offs_int(res, offs_lea);
- }
- }
-
- /* 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) */
- if (lea_ent != NULL) {
- set_ia32_frame_ent(res, lea_ent);
- set_ia32_use_frame(res);
- } else {
- set_ia32_frame_ent(res, get_ia32_frame_ent(irn));
- if(is_ia32_use_frame(irn))
- set_ia32_use_frame(res);
- }
-
- /* set scale */
- set_ia32_am_scale(res, scale);
-
- am_flav = ia32_am_N;
- /* determine new am flavour */
- if (offs || offs_cnst || offs_lea || have_am_sc) {
- am_flav |= ia32_O;
- }
- if (! be_is_NoReg(cg, base)) {
- am_flav |= ia32_B;
- }
- if (! be_is_NoReg(cg, index)) {
- am_flav |= ia32_I;
- }
- if (scale > 0) {
- am_flav |= ia32_S;
- }
- set_ia32_am_flavour(res, am_flav);
-
- set_ia32_op_type(res, ia32_AddrModeS);
-
- SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(cg, irn));
-
- DBG((dbg, LEVEL_1, "\tLEA [%+F + %+F * %d + %d]\n", base, index, scale, get_ia32_am_offs_int(res)));
-
- assert(irn && "Couldn't find result proj");
-
- /* get the result Proj of the Add/Sub */
- try_add_to_sched(irn, res);
-
- /* exchange the old op with the new LEA */
- try_kill(irn);
- exchange(irn, res);
-
- /* we will exchange it, report here before the Proj is created */
- if (shift && lea && lea_o) {
- try_kill(shift);
- try_kill(lea);
- try_kill(lea_o);
- DBG_OPT_LEA4(irn, lea_o, lea, shift, res);
- } else if (shift && lea) {
- try_kill(shift);
- try_kill(lea);
- DBG_OPT_LEA3(irn, lea, shift, res);
- } else if (shift && lea_o) {
- try_kill(shift);
- try_kill(lea_o);
- DBG_OPT_LEA3(irn, lea_o, shift, res);
- } else if (lea && lea_o) {
- try_kill(lea);
- try_kill(lea_o);
- DBG_OPT_LEA3(irn, lea_o, lea, res);
- } else if (shift) {
- try_kill(shift);
- DBG_OPT_LEA2(irn, shift, res);
- } else if (lea) {
- try_kill(lea);
- DBG_OPT_LEA2(irn, lea, res);
- } else if (lea_o) {
- try_kill(lea_o);
- DBG_OPT_LEA2(irn, lea_o, res);
- } else {
- DBG_OPT_LEA1(irn, res);
- }
- }
-
- return res;
-}
-
-
-/**
- * Merges a Load/Store node with a LEA.
- * @param irn The Load/Store node
- * @param lea The LEA
- */
-static void merge_loadstore_lea(ir_node *irn, ir_node *lea) {
- ir_entity *irn_ent = get_ia32_frame_ent(irn);
- ir_entity *lea_ent = get_ia32_frame_ent(lea);
-
- /* If the irn and the LEA both have a different frame entity set: do not merge */
- if (irn_ent != NULL && lea_ent != NULL && (irn_ent != lea_ent))
- return;
- else if (irn_ent == NULL && lea_ent != NULL) {
- set_ia32_frame_ent(irn, lea_ent);
- set_ia32_use_frame(irn);
- }
-
- /* get the AM attributes from the LEA */
- add_ia32_am_offs_int(irn, get_ia32_am_offs_int(lea));
- set_ia32_am_scale(irn, get_ia32_am_scale(lea));
- set_ia32_am_flavour(irn, get_ia32_am_flavour(lea));
-
- set_ia32_am_sc(irn, get_ia32_am_sc(lea));
- if (is_ia32_am_sc_sign(lea))
- set_ia32_am_sc_sign(irn);
-
- set_ia32_op_type(irn, is_ia32_Ld(irn) ? ia32_AddrModeS : ia32_AddrModeD);
-
- /* set base and index */
- set_irn_n(irn, 0, get_irn_n(lea, 0));
- set_irn_n(irn, 1, get_irn_n(lea, 1));
-
- try_kill(lea);
-
- /* clear remat flag */
- set_ia32_flags(irn, get_ia32_flags(irn) & ~arch_irn_flags_rematerializable);
-
- if (is_ia32_Ld(irn))
- DBG_OPT_LOAD_LEA(lea, irn);
- else
- DBG_OPT_STORE_LEA(lea, irn);
-
-}
-
-/**
- * Sets new_right index of irn to right and new_left index to left.
- * Also exchange left and right
- */
-static void exchange_left_right(ir_node *irn, ir_node **left, ir_node **right,
- int new_left, int new_right)
-{
- ir_node *temp;
-
- assert(is_ia32_commutative(irn));
-
- set_irn_n(irn, new_right, *right);
- set_irn_n(irn, new_left, *left);
-
- temp = *left;
- *left = *right;
- *right = temp;
-
- /* this is only needed for Compares, but currently ALL nodes
- * have this attribute :-) */
- set_ia32_pncode(irn, get_inversed_pnc(get_ia32_pncode(irn)));
-}
-
-/**
- * Performs address calculation optimization (create LEAs if possible)
- */
-static void optimize_lea(ia32_code_gen_t *cg, ir_node *irn) {
- if (! is_ia32_irn(irn))
- return;
-
- /* Following cases can occur: */
- /* - Sub (l, imm) -> LEA [base - offset] */
- /* - Sub (l, r == LEA with ia32_am_O) -> LEA [base - offset] */
- /* - Add (l, imm) -> LEA [base + offset] */
- /* - Add (l, r == LEA with ia32_am_O) -> LEA [base + offset] */
- /* - Add (l == LEA with ia32_am_O, r) -> LEA [base + offset] */
- /* - Add (l, r) -> LEA [base + index * scale] */
- /* with scale > 1 iff l/r == shl (1,2,3) */
- if (is_ia32_Sub(irn) || is_ia32_Add(irn)) {
- ir_node *res;
-
- if(!is_addr_candidate(irn))
- return;
-
- DBG((dbg, LEVEL_1, "\tfound address calculation candidate %+F ... ", irn));
- res = fold_addr(cg, irn);
-
- if (res != irn)
- DB((dbg, LEVEL_1, "transformed into %+F\n", res));
- else
- DB((dbg, LEVEL_1, "not transformed\n"));
- } else if (is_ia32_Ld(irn) || is_ia32_St(irn)) {
- /* - Load -> LEA into Load } TODO: If the LEA is used by more than one Load/Store */
- /* - Store -> LEA into Store } it might be better to keep the LEA */
- ir_node *left = get_irn_n(irn, 0);
-
- if (is_ia32_Lea(left)) {
- const ir_edge_t *edge, *ne;
- ir_node *src;
-
- /* merge all Loads/Stores connected to this LEA with the LEA */
- foreach_out_edge_safe(left, edge, ne) {
- src = get_edge_src_irn(edge);
-
- if (src && (get_edge_src_pos(edge) == 0) && (is_ia32_Ld(src) || is_ia32_St(src))) {
- DBG((dbg, LEVEL_1, "\nmerging %+F into %+F\n", left, irn));
- if (! is_ia32_got_lea(src))
- merge_loadstore_lea(src, left);
- set_ia32_got_lea(src);
- }
- }
- }
- }
-}
-