-/**
- * Checks for address mode patterns and performs the
- * necessary transformations.
- * This function is called by a walker.
- */
-static void optimize_am(ir_node *irn, void *env) {
- ia32_am_opt_env_t *am_opt_env = env;
- ia32_code_gen_t *cg = am_opt_env->cg;
- heights_t *h = am_opt_env->h;
- ir_node *block, *left, *right;
- ir_node *store, *load, *mem_proj;
- ir_node *succ, *addr_b, *addr_i;
- int check_am_src = 0;
- int need_exchange_on_fail = 0;
- DEBUG_ONLY(firm_dbg_module_t *mod = cg->mod;)
-
- if (! is_ia32_irn(irn) || is_ia32_Ld(irn) || is_ia32_St(irn) || is_ia32_Store8Bit(irn))
- return;
-
- block = get_nodes_block(irn);
-
- DBG((mod, LEVEL_1, "checking for AM\n"));
-
- /* fold following patterns: */
- /* - op -> Load into AMop with am_Source */
- /* conditions: */
- /* - op is am_Source capable AND */
- /* - the Load is only used by this op AND */
- /* - the Load is in the same block */
- /* - Store -> op -> Load into AMop with am_Dest */
- /* conditions: */
- /* - op is am_Dest capable AND */
- /* - the Store uses the same address as the Load AND */
- /* - the Load is only used by this op AND */
- /* - the Load and Store are in the same block AND */
- /* - nobody else uses the result of the op */
-
- if ((get_ia32_am_support(irn) != ia32_am_None) && ! is_ia32_Lea(irn)) {
- ia32_am_cand_t cand = is_am_candidate(cg, h, block, irn);
- ia32_am_cand_t orig_cand = cand;
-
- /* cand == 1: load is left; cand == 2: load is right; */
-
- if (cand == IA32_AM_CAND_NONE)
- return;
-
- DBG((mod, LEVEL_1, "\tfound address mode candidate %+F ... ", irn));
-
- left = get_irn_n(irn, 2);
- if (get_irn_arity(irn) == 4) {
- /* it's an "unary" operation */
- right = left;
- }
- else {
- right = get_irn_n(irn, 3);
- }
-
- /* normalize commutative ops */
- if (node_is_ia32_comm(irn) && (cand == IA32_AM_CAND_RIGHT)) {
-
- /* Assure that left operand is always a Load if there is one */
- /* because non-commutative ops can only use Dest AM if the left */
- /* operand is a load, so we only need to check left operand. */
-
- exchange_left_right(irn, &left, &right, 3, 2);
- need_exchange_on_fail = 1;
-
- /* now: load is right */
- cand = IA32_AM_CAND_LEFT;
- }
-
- /* check for Store -> op -> Load */
-
- /* Store -> op -> Load optimization is only possible if supported by op */
- /* and if right operand is a Load */
- if ((get_ia32_am_support(irn) & ia32_am_Dest) && (cand & IA32_AM_CAND_LEFT))
- {
- /* An address mode capable op always has a result Proj. */
- /* If this Proj is used by more than one other node, we don't need to */
- /* check further, otherwise we check for Store and remember the address, */
- /* the Store points to. */
-
- succ = ia32_get_res_proj(irn);
- assert(succ && "Couldn't find result proj");
-
- addr_b = NULL;
- addr_i = NULL;
- store = NULL;
-
- /* now check for users and Store */
- if (ia32_get_irn_n_edges(succ) == 1) {
- succ = get_edge_src_irn(get_irn_out_edge_first(succ));
-
- if (is_ia32_xStore(succ) || is_ia32_Store(succ)) {
- store = succ;
- addr_b = get_irn_n(store, 0);
- addr_i = get_irn_n(store, 1);
- }
- }
-
- if (store) {
- /* we found a Store as single user: Now check for Load */
-
- /* skip the Proj for easier access */
- load = is_Proj(right) ? (is_ia32_Load(get_Proj_pred(right)) ? get_Proj_pred(right) : NULL) : NULL;
-
- /* Extra check for commutative ops with two Loads */
- /* -> put the interesting Load left */
- if (load && node_is_ia32_comm(irn) && (cand == IA32_AM_CAND_BOTH)) {
- if (load_store_addr_is_equal(load, store, addr_b, addr_i)) {
- /* We exchange left and right, so it's easier to kill */
- /* the correct Load later and to handle unary operations. */
- exchange_left_right(irn, &left, &right, 3, 2);
- need_exchange_on_fail ^= 1;
- }
- }
-
- /* skip the Proj for easier access */
- load = get_Proj_pred(left);
-
- /* Compare Load and Store address */
- if (load_store_addr_is_equal(load, store, addr_b, addr_i)) {
- /* Left Load is from same address, so we can */
- /* disconnect the Load and Store here */
-
- /* set new base, index and attributes */
- set_irn_n(irn, 0, addr_b);
- set_irn_n(irn, 1, addr_i);
- add_ia32_am_offs(irn, get_ia32_am_offs(load));
- set_ia32_am_scale(irn, get_ia32_am_scale(load));
- set_ia32_am_flavour(irn, get_ia32_am_flavour(load));
- set_ia32_op_type(irn, ia32_AddrModeD);
- 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);
-
- /* connect to Load memory and disconnect Load */
- if (get_irn_arity(irn) == 5) {
- /* binary AMop */
- set_irn_n(irn, 4, get_irn_n(load, 2));
- set_irn_n(irn, 2, ia32_get_admissible_noreg(cg, irn, 2));
- }
- else {
- /* unary AMop */
- set_irn_n(irn, 3, get_irn_n(load, 2));
- set_irn_n(irn, 2, ia32_get_admissible_noreg(cg, irn, 2));
- }
-
- /* connect the memory Proj of the Store to the op */
- mem_proj = ia32_get_proj_for_mode(store, mode_M);
- set_Proj_pred(mem_proj, irn);
- set_Proj_proj(mem_proj, 1);
-
- /* clear remat flag */
- set_ia32_flags(irn, get_ia32_flags(irn) & ~arch_irn_flags_rematerializable);
-
- try_remove_from_sched(load);
- try_remove_from_sched(store);
- DBG_OPT_AM_D(load, store, irn);
-
- DB((mod, LEVEL_1, "merged with %+F and %+F into dest AM\n", load, store));
-
- need_exchange_on_fail = 0;
- }
- } /* if (store) */
- else if (get_ia32_am_support(irn) & ia32_am_Source) {
- /* There was no store, check if we still can optimize for source address mode */
- check_am_src = 1;
- }
- } /* if (support AM Dest) */
- else if (get_ia32_am_support(irn) & ia32_am_Source) {
- /* op doesn't support am AM Dest -> check for AM Source */
- check_am_src = 1;
- }
-
- /* was exchanged but optimize failed: exchange back */
- if (need_exchange_on_fail) {
- exchange_left_right(irn, &left, &right, 3, 2);
- cand = orig_cand;
- }
-
- need_exchange_on_fail = 0;
-
- /* normalize commutative ops */
- if (check_am_src && node_is_ia32_comm(irn) && (cand == IA32_AM_CAND_LEFT)) {
-
- /* Assure that right operand is always a Load if there is one */
- /* because non-commutative ops can only use Source AM if the */
- /* right operand is a Load, so we only need to check the right */
- /* operand afterwards. */
-
- exchange_left_right(irn, &left, &right, 3, 2);
- need_exchange_on_fail = 1;
-
- /* now: load is left */
- cand = IA32_AM_CAND_RIGHT;
- }
-
- /* optimize op -> Load iff Load is only used by this op */
- /* and right operand is a Load which only used by this irn */
- if (check_am_src &&
- (cand & IA32_AM_CAND_RIGHT) &&
- (get_irn_arity(irn) == 5) &&
- (ia32_get_irn_n_edges(right) == 1))
- {
- right = get_Proj_pred(right);
-
- addr_b = get_irn_n(right, 0);
- addr_i = get_irn_n(right, 1);
-
- /* set new base, index and attributes */
- set_irn_n(irn, 0, addr_b);
- set_irn_n(irn, 1, addr_i);
- add_ia32_am_offs(irn, get_ia32_am_offs(right));
- set_ia32_am_scale(irn, get_ia32_am_scale(right));
- set_ia32_am_flavour(irn, get_ia32_am_flavour(right));
- set_ia32_op_type(irn, ia32_AddrModeS);
- set_ia32_frame_ent(irn, get_ia32_frame_ent(right));
- set_ia32_ls_mode(irn, get_ia32_ls_mode(right));
-
- set_ia32_am_sc(irn, get_ia32_am_sc(right));
- if (is_ia32_am_sc_sign(right))
- set_ia32_am_sc_sign(irn);
-
- /* clear remat flag */
- set_ia32_flags(irn, get_ia32_flags(irn) & ~arch_irn_flags_rematerializable);
-
- if (is_ia32_use_frame(right))
- set_ia32_use_frame(irn);
-
- /* connect to Load memory */
- set_irn_n(irn, 4, get_irn_n(right, 2));
-
- /* this is only needed for Compares, but currently ALL nodes
- * have this attribute :-) */
- set_ia32_pncode(irn, get_inversed_pnc(get_ia32_pncode(irn)));
-
- /* disconnect from Load */
- set_irn_n(irn, 3, ia32_get_admissible_noreg(cg, irn, 3));
-
- DBG_OPT_AM_S(right, irn);
-
- /* If Load has a memory Proj, connect it to the op */
- mem_proj = ia32_get_proj_for_mode(right, mode_M);
- if (mem_proj) {
- set_Proj_pred(mem_proj, irn);
- set_Proj_proj(mem_proj, 1);
- }
-
- try_remove_from_sched(right);