- optimize_lea(cg, node);
-}
-
-/**
- * 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;
- ir_graph *irg = get_irn_irg(irn);
- heights_t *h = am_opt_env->h;
- ir_node *block, *left, *right;
- ir_node *store, *load, *mem_proj;
- ir_node *addr_b, *addr_i;
- int need_exchange_on_fail = 0;
- ia32_am_type_t am_support;
- ia32_am_arity_t am_arity;
- ia32_am_cand_t cand;
- ia32_am_cand_t orig_cand;
- int dest_possible;
- int source_possible;
-
- static const arch_register_req_t dest_out_reg_req_0 = {
- arch_register_req_type_none,
- NULL, /* regclass */
- NULL, /* limit bitset */
- -1, /* same pos */
- -1 /* different pos */
- };
- static const arch_register_req_t *dest_am_out_reqs[] = {
- &dest_out_reg_req_0
- };
-
- if (!is_ia32_irn(irn) || is_ia32_Ld(irn) || is_ia32_St(irn))
- return;
- if (is_ia32_Lea(irn))
- return;
-
- am_support = get_ia32_am_support(irn);
- am_arity = get_ia32_am_arity(irn);
- block = get_nodes_block(irn);
-
- /* 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 (am_support == ia32_am_None)
- return;
-
- assert(am_arity == ia32_am_unary || am_arity == ia32_am_binary);
-
- cand = is_am_candidate(h, block, irn);
- if (cand == IA32_AM_CAND_NONE)
- return;
-
- orig_cand = cand;
- DBG((dbg, LEVEL_1, "\tfound address mode candidate %+F (candleft %d candright %d)... \n", irn,
- cand & IA32_AM_CAND_LEFT, cand & IA32_AM_CAND_RIGHT));
-
- left = get_irn_n(irn, 2);
- if (am_arity == ia32_am_unary) {
- assert(get_irn_arity(irn) >= 4);
- right = left;
- assert(cand == IA32_AM_CAND_BOTH);
- } else {
- assert(get_irn_arity(irn) >= 5);
- right = get_irn_n(irn, 3);
- }
-
- dest_possible = am_support & ia32_am_Dest ? 1 : 0;
- source_possible = am_support & ia32_am_Source ? 1 : 0;
-
- DBG((dbg, LEVEL_2, "\tdest_possible %d source_possible %d ... \n", dest_possible, source_possible));
-
- if (dest_possible) {
- addr_b = NULL;
- addr_i = NULL;
- store = NULL;
-
- /* we should only have 1 user which is a store */
- if (ia32_get_irn_n_edges(irn) == 1) {
- ir_node *succ = get_edge_src_irn(get_irn_out_edge_first(irn));
-
- 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 == NULL) {
- DBG((dbg, LEVEL_2, "\tno store found, not using dest_mode\n"));
- dest_possible = 0;
- }
- }
-
- if (dest_possible) {
- /* normalize nodes, we need the interesting load on the left side */
- if (cand & IA32_AM_CAND_RIGHT) {
- load = get_Proj_pred(right);
- if (load_store_addr_is_equal(load, store, addr_b, addr_i)
- && node_is_ia32_comm(irn)) {
- DBG((dbg, LEVEL_2, "\texchanging left/right\n"));
- exchange_left_right(irn, &left, &right, 3, 2);
- need_exchange_on_fail ^= 1;
- if (cand == IA32_AM_CAND_RIGHT)
- cand = IA32_AM_CAND_LEFT;
- }
- }
- }
-
- if (dest_possible) {
- if(cand & IA32_AM_CAND_LEFT && is_Proj(left)) {
- load = get_Proj_pred(left);
-
-#ifndef AGGRESSIVE_AM
- /* we have to be the only user of the load */
- if (get_irn_n_edges(left) > 1) {
- DBG((dbg, LEVEL_2, "\tmatching load has too may users, not using dest_mode\n"));
- dest_possible = 0;
- }
-#endif
- } else {
- DBG((dbg, LEVEL_2, "\tno matching load found, not using dest_mode"));
- dest_possible = 0;
- }
- }
-
- if (dest_possible) {
- /* the store has to use the loads memory or the same memory
- * as the load */
- ir_node *loadmem = get_irn_n(load, 2);
- ir_node *storemem = get_irn_n(store, 3);
- assert(get_irn_mode(loadmem) == mode_M);
- assert(get_irn_mode(storemem) == mode_M);
- /* TODO there could be a sync between store and load... */
- if(storemem != loadmem && (!is_Proj(storemem) || get_Proj_pred(storemem) != load)) {
- DBG((dbg, LEVEL_2, "\tload/store using different memories, not using dest_mode"));
- dest_possible = 0;
- }
- }
-
- if (dest_possible) {
- /* Compare Load and Store address */
- if (!load_store_addr_is_equal(load, store, addr_b, addr_i)) {
- DBG((dbg, LEVEL_2, "\taddresses not equal, not using dest_mode"));
- dest_possible = 0;
- }
- }
-
- if (dest_possible) {
- ir_mode *lsmode = get_ia32_ls_mode(load);
- if(get_mode_size_bits(lsmode) != 32) {
- dest_possible = 0;
- }
- }
-
- if (dest_possible) {
- /* all conditions fullfilled, do the transformation */
- assert(cand & IA32_AM_CAND_LEFT);
-
- /* set new base, index and attributes */
- set_irn_n(irn, 0, addr_b);
- set_irn_n(irn, 1, addr_i);
- add_ia32_am_offs_int(irn, get_ia32_am_offs_int(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);
-
- /* connect to Load memory and disconnect Load */
- if (am_arity == ia32_am_binary) {
- /* 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));
- }
-
- /* change node mode and out register requirements */
- set_irn_mode(irn, mode_M);
- set_ia32_out_req_all(irn, dest_am_out_reqs);
-
- /* connect the memory Proj of the Store to the op */
- edges_reroute(store, irn, irg);
-
- /* clear remat flag */
- set_ia32_flags(irn, get_ia32_flags(irn) & ~arch_irn_flags_rematerializable);
-
- try_kill(store);
- try_kill(load);
- DBG_OPT_AM_D(load, store, irn);
-
- DB((dbg, LEVEL_1, "merged with %+F and %+F into dest AM\n", load, store));
- need_exchange_on_fail = 0;
- source_possible = 0;
- }
-
- if (source_possible) {
- /* normalize ops, we need the load on the right */
- if(cand == IA32_AM_CAND_LEFT) {
- if(node_is_ia32_comm(irn)) {
- exchange_left_right(irn, &left, &right, 3, 2);
- need_exchange_on_fail ^= 1;
- cand = IA32_AM_CAND_RIGHT;
- } else {
- source_possible = 0;
- }
- }
- }
-
- if (source_possible) {
- /* all conditions fullfilled, do transform */
- assert(cand & IA32_AM_CAND_RIGHT);
- load = get_Proj_pred(right);
-
- if(get_irn_n_edges(right) > 1) {
- source_possible = 0;
- }
-#if 1
- /* TODO: this isn't really needed, but the code below is buggy
- as heights won't get recomputed when the graph is reconstructed
- so we can only transform loads with the result proj only */
- if(get_irn_n_edges(load) > 1) {
- source_possible = 0;
- }
-#endif
- }
-
- if (source_possible) {
- ir_mode *ls_mode = get_ia32_ls_mode(load);
- if(get_mode_size_bits(ls_mode) != 32 || ls_mode == mode_D)
- source_possible = 0;
-
- }
-
- if (source_possible) {
- const ia32_attr_t *attr_load = get_ia32_attr_const(load);
- ia32_attr_t *attr_irn = get_ia32_attr(irn);
- addr_b = get_irn_n(load, 0);
- addr_i = get_irn_n(load, 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_int(irn, get_ia32_am_offs_int(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_AddrModeS);
- set_ia32_frame_ent(irn, get_ia32_frame_ent(load));
- attr_irn->data.need_64bit_stackent
- = attr_load->data.need_64bit_stackent;
- attr_irn->data.need_32bit_stackent
- = attr_load->data.need_32bit_stackent;
-
- /* set ls_mode if not already present (conv nodes already have ls_mode
- set) */
- if(get_ia32_ls_mode(irn) == NULL) {
- 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);
-
- /* clear remat flag */
- set_ia32_flags(irn, get_ia32_flags(irn) & ~arch_irn_flags_rematerializable);
-
- if (is_ia32_use_frame(load)) {
- if(get_ia32_frame_ent(load) == NULL) {
- set_ia32_need_stackent(irn);
- }
- set_ia32_use_frame(irn);
- }
-
- /* connect to Load memory and disconnect Load */
- if (am_arity == ia32_am_binary) {
- /* binary AMop */
- right = ia32_get_admissible_noreg(cg, irn, 3);
- set_irn_n(irn, 3, right);
- set_irn_n(irn, 4, get_irn_n(load, n_ia32_Load_mem));
- } else {
- /* unary AMop */
- right = ia32_get_admissible_noreg(cg, irn, 2);
- set_irn_n(irn, 2, right);
- set_irn_n(irn, 3, get_irn_n(load, n_ia32_Load_mem));
- }
-
- DBG_OPT_AM_S(load, irn);
-
- /* If Load has a memory Proj, connect it to the op */
- mem_proj = ia32_get_proj_for_mode(load, mode_M);
- if (mem_proj != NULL) {
- ir_node *res_proj;
- ir_mode *mode = get_irn_mode(irn);
-
- if(mode != mode_T) {
- res_proj = new_rd_Proj(get_irn_dbg_info(irn), irg,
- get_nodes_block(irn),
- new_Unknown(mode_T), mode, 0);
- set_irn_mode(irn, mode_T);
- edges_reroute(irn, res_proj, irg);
- set_Proj_pred(res_proj, irn);
-
- set_Proj_pred(mem_proj, irn);
- set_Proj_proj(mem_proj, 1);
- } else {
- /* hacky: we need some proj number which is not used yet... */
- set_Proj_proj(mem_proj, -1);
- set_Proj_pred(mem_proj, irn);
- }
- }
-
- try_kill(load);
- need_exchange_on_fail = 0;
-
- /* immediate are only allowed on the right side */
- if(is_ia32_Immediate(left)) {
- exchange_left_right(irn, &left, &right, 3, 2);
- }
-
- DB((dbg, LEVEL_1, "merged with %+F into source AM\n", load));
- }
-
- /* was exchanged but optimize failed: exchange back */
- if (need_exchange_on_fail) {
- exchange_left_right(irn, &left, &right, 3, 2);
- }