X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;ds=sidebyside;f=ir%2Fopt%2Fldstopt.c;h=91347a7bea9076376bfdfabd3af816ae9dc332fa;hb=44faeb9742640d3498eb4482f98eb1255607c4d6;hp=6ecabaae64760be85a57eeefde67a62edda6e09d;hpb=df8a7c32fa1de6a6c64b69f01e2748efb7ce1c11;p=libfirm diff --git a/ir/opt/ldstopt.c b/ir/opt/ldstopt.c index 6ecabaae6..91347a7be 100644 --- a/ir/opt/ldstopt.c +++ b/ir/opt/ldstopt.c @@ -28,7 +28,6 @@ #endif #include -#include #include "iroptimize.h" #include "irnode_t.h" @@ -387,11 +386,12 @@ static compound_graph_path *rec_get_accessed_path(ir_node *ptr, int depth) { set_compound_graph_path_array_index(res, pos, get_Sel_array_index_long(ptr, 0)); } } else if (is_Add(ptr)) { - ir_node *l = get_Add_left(ptr); - ir_node *r = get_Add_right(ptr); - ir_mode *mode; + ir_node *l = get_Add_left(ptr); + ir_node *r = get_Add_right(ptr); + ir_mode *mode = get_irn_mode(ptr); + tarval *tmp; - if (is_Const(r)) { + if (is_Const(r) && get_irn_mode(l) == mode) { ptr = l; tv = get_Const_tarval(r); } else { @@ -400,6 +400,7 @@ static compound_graph_path *rec_get_accessed_path(ir_node *ptr, int depth) { } ptr_arith: mode = get_tarval_mode(tv); + tmp = tv; /* ptr must be a Sel or a SymConst, this was checked in find_constant_entity() */ if (is_Sel(ptr)) { @@ -420,10 +421,10 @@ ptr_arith: size = get_type_size_bytes(get_entity_type(ent)); sz = new_tarval_from_long(size, mode); - tv_index = tarval_div(tv, sz); - tv = tarval_mod(tv, sz); + tv_index = tarval_div(tmp, sz); + tmp = tarval_mod(tmp, sz); - if (tv_index == tarval_bad || tv == tarval_bad) + if (tv_index == tarval_bad || tmp == tarval_bad) return NULL; assert(get_array_n_dimensions(tp) == 1 && "multiarrays not implemented"); @@ -443,7 +444,7 @@ ptr_arith: /* ok, bounds check finished */ ++idx; } - if (! tarval_is_null(tv)) { + if (! tarval_is_null(tmp)) { /* access to some struct/union member */ return NULL; } @@ -501,7 +502,8 @@ ptr_arith: * valid, if the graph is in phase_high and _no_ address computation is used. */ static compound_graph_path *get_accessed_path(ir_node *ptr) { - return rec_get_accessed_path(ptr, 0); + compound_graph_path *gr = rec_get_accessed_path(ptr, 0); + return gr; } /* get_accessed_path */ typedef struct path_entry { @@ -539,7 +541,7 @@ static ir_node *rec_find_compound_ent_value(ir_node *ptr, path_entry *next) { continue; } } - if (p->index >= n) + if (p->index >= (int) n) return NULL; initializer = get_initializer_compound_value(initializer, p->index); @@ -773,41 +775,77 @@ static unsigned is_Call_pure(ir_node *call) { return (prop & (mtp_property_const|mtp_property_pure)) != 0; } /* is_Call_pure */ -static ir_node *get_base_ptr(ir_node *ptr) +static ir_node *get_base_and_offset(ir_node *ptr, long *pOffset) { - while (is_Add(ptr) && is_Const(get_Add_right(ptr))) { - ptr = get_Add_left(ptr); - } - - return ptr; -} + ir_mode *mode = get_irn_mode(ptr); + long offset = 0; -static long get_base_offset(ir_node *ptr) -{ /* TODO: long might not be enough, we should probably use some tarval thingy... */ - long offset = 0; - while (is_Add(ptr)) { - ir_node *right = get_Add_right(ptr); - if (!is_Const(right)) + for (;;) { + if (is_Add(ptr)) { + ir_node *l = get_Add_left(ptr); + ir_node *r = get_Add_right(ptr); + + if (get_irn_mode(l) != mode || !is_Const(r)) + break; + + offset += get_tarval_long(get_Const_tarval(r)); + ptr = l; + } else if (is_Sub(ptr)) { + ir_node *l = get_Sub_left(ptr); + ir_node *r = get_Sub_right(ptr); + + if (get_irn_mode(l) != mode || !is_Const(r)) + break; + + offset -= get_tarval_long(get_Const_tarval(r)); + ptr = l; + } else if (is_Sel(ptr)) { + ir_entity *ent = get_Sel_entity(ptr); + ir_type *tp = get_entity_owner(ent); + + if (is_Array_type(tp)) { + int size; + ir_node *index; + + /* only one dimensional arrays yet */ + if (get_Sel_n_indexs(ptr) != 1) + break; + index = get_Sel_index(ptr, 0); + if (! is_Const(index)) + break; + + tp = get_entity_type(ent); + if (get_type_state(tp) != layout_fixed) + break; + + size = get_type_size_bytes(tp); + offset += size * get_tarval_long(get_Const_tarval(index)); + } else { + if (get_type_state(tp) != layout_fixed) + break; + offset += get_entity_offset(ent); + } + ptr = get_Sel_ptr(ptr); + } else break; - offset += get_tarval_long(get_Const_tarval(right)); - ptr = get_Add_left(ptr); } - return offset; + *pOffset = offset; + return ptr; } -static int try_load_store(ir_node *load, +static int try_load_after_store(ir_node *load, ir_node *load_base_ptr, long load_offset, ir_node *store) { ldst_info_t *info; ir_node *store_ptr = get_Store_ptr(store); - ir_node *store_base_ptr = get_base_ptr(store_ptr); + long store_offset; + ir_node *store_base_ptr = get_base_and_offset(store_ptr, &store_offset); ir_node *store_value; ir_mode *store_mode; ir_node *load_ptr; ir_mode *load_mode; - long store_offset = get_base_offset(store_ptr); long load_mode_len; long store_mode_len; long delta; @@ -816,25 +854,26 @@ static int try_load_store(ir_node *load, if (load_base_ptr != store_base_ptr) return 0; - load_mode = get_Load_mode(load); - load_mode_len = get_mode_size_bytes(load_mode); + load_mode = get_Load_mode(load); + load_mode_len = get_mode_size_bytes(load_mode); store_mode = get_irn_mode(get_Store_value(store)); store_mode_len = get_mode_size_bytes(store_mode); - - delta = load_offset - store_offset; - if (delta < 0 || delta >= store_mode_len) + delta = load_offset - store_offset; + if (delta < 0 || delta + load_mode_len > store_mode_len) return 0; - if (store_mode_len - delta > load_mode_len) + if (get_mode_arithmetic(store_mode) != irma_twos_complement || + get_mode_arithmetic(load_mode) != irma_twos_complement) return 0; store_value = get_Store_value(store); - DBG_OPT_RAW(load, store_value); /* produce a shift to adjust offset delta */ if (delta > 0) { - ir_node *cnst = new_r_Const_long(current_ir_graph, - get_irg_start_block(current_ir_graph), mode_Iu, delta * 8); + ir_node *cnst; + + /* FIXME: only true for little endian */ + cnst = new_Const_long(mode_Iu, delta * 8); store_value = new_r_Shr(current_ir_graph, get_nodes_block(load), store_value, cnst, store_mode); } @@ -845,6 +884,8 @@ static int try_load_store(ir_node *load, store_value, load_mode); } + DBG_OPT_RAW(load, store_value); + info = get_irn_link(load); if (info->projs[pn_Load_M]) exchange(info->projs[pn_Load_M], get_Load_mem(load)); @@ -880,14 +921,12 @@ static int try_load_store(ir_node *load, * INC_MASTER() must be called before dive into */ static unsigned follow_Mem_chain(ir_node *load, ir_node *curr) { - unsigned res = 0; + unsigned res = 0; ldst_info_t *info = get_irn_link(load); - ir_node *pred; - ir_node *ptr = get_Load_ptr(load); - ir_node *mem = get_Load_mem(load); - ir_mode *load_mode = get_Load_mode(load); - ir_node *base_ptr = get_base_ptr(ptr); - long load_offset = get_base_offset(ptr); + ir_node *pred; + ir_node *ptr = get_Load_ptr(load); + ir_node *mem = get_Load_mem(load); + ir_mode *load_mode = get_Load_mode(load); for (pred = curr; load != pred; ) { ldst_info_t *pred_info = get_irn_link(pred); @@ -909,11 +948,12 @@ static unsigned follow_Mem_chain(ir_node *load, ir_node *curr) { && info->projs[pn_Load_X_except] == NULL) || get_nodes_MacroBlock(load) == get_nodes_MacroBlock(pred))) { - int changes - = try_load_store(load, base_ptr, load_offset, pred); - if (changes != 0) { + long load_offset; + ir_node *base_ptr = get_base_and_offset(ptr, &load_offset); + int changes = try_load_after_store(load, base_ptr, load_offset, pred); + + if (changes != 0) return res | changes; - } } else if (is_Load(pred) && get_Load_ptr(pred) == ptr && can_use_stored_value(get_Load_mode(pred), load_mode)) { /* @@ -1047,9 +1087,10 @@ ir_node *can_replace_load_by_const(const ir_node *load, ir_node *c) { static unsigned optimize_load(ir_node *load) { ldst_info_t *info = get_irn_link(load); - ir_node *mem, *ptr, *value; - ir_entity *ent; - unsigned res = 0; + ir_node *mem, *ptr, *value; + ir_entity *ent; + long dummy; + unsigned res = 0; /* do NOT touch volatile loads for now */ if (get_Load_volatility(load) == volatility_is_volatile) @@ -1150,6 +1191,7 @@ static unsigned optimize_load(ir_node *load) assert(is_proper_compound_graph_path(path, get_compound_graph_path_length(path)-1)); value = get_compound_ent_value_by_path(ent, path); + DB((dbg, LEVEL_1, " Constant access at %F%F resulted in %+F\n", ent, path, value)); free_compound_graph_path(path); } } @@ -1186,8 +1228,8 @@ static unsigned optimize_load(ir_node *load) } /* Check, if the address of this load is used more than once. - * If not, this load cannot be removed in any case. */ - if (get_irn_n_uses(ptr) <= 1 && get_irn_n_uses(get_base_ptr(ptr)) <= 1) + * If not, more load cannot be removed in any case. */ + if (get_irn_n_uses(ptr) <= 1 && get_irn_n_uses(get_base_and_offset(ptr, &dummy)) <= 1) return res; /* @@ -1314,18 +1356,61 @@ static unsigned follow_Mem_chain_for_Store(ir_node *store, ir_node *curr) { return res; } /* follow_Mem_chain_for_Store */ +/** find entity used as base for an address calculation */ +static ir_entity *find_entity(ir_node *ptr) +{ + switch(get_irn_opcode(ptr)) { + case iro_SymConst: + return get_SymConst_entity(ptr); + case iro_Sel: { + ir_node *pred = get_Sel_ptr(ptr); + if (get_irg_frame(get_irn_irg(ptr)) == pred) + return get_Sel_entity(ptr); + + return find_entity(pred); + } + case iro_Sub: + case iro_Add: { + ir_node *left = get_binop_left(ptr); + ir_node *right; + if (mode_is_reference(get_irn_mode(left))) + return find_entity(left); + right = get_binop_right(ptr); + if (mode_is_reference(get_irn_mode(right))) + return find_entity(right); + return NULL; + } + default: + return NULL; + } +} + /** * optimize a Store * * @param store the Store node */ static unsigned optimize_store(ir_node *store) { - ir_node *ptr, *mem; + ir_node *ptr; + ir_node *mem; + ir_entity *entity; if (get_Store_volatility(store) == volatility_is_volatile) return 0; - ptr = get_Store_ptr(store); + ptr = get_Store_ptr(store); + entity = find_entity(ptr); + + /* a store to an entity which is never read is unnecessary */ + if (entity != NULL && !(get_entity_usage(entity) & ir_usage_read)) { + ldst_info_t *info = get_irn_link(store); + if (info->projs[pn_Store_X_except] == NULL) { + exchange(info->projs[pn_Store_M], get_Store_mem(store)); + kill_node(store); + reduce_adr_usage(ptr); + return DF_CHANGED; + } + } /* Check, if the address of this Store is used more than once. * If not, this Store cannot be removed in any case. */ @@ -2107,8 +2192,8 @@ void optimize_load_store(ir_graph *irg) { assure_postdoms(irg); if (get_opt_alias_analysis()) { - assure_irg_address_taken_computed(irg); - assure_irp_globals_address_taken_computed(); + assure_irg_entity_usage_computed(irg); + assure_irp_globals_entity_usage_computed(); } obstack_init(&env.obst); @@ -2128,6 +2213,7 @@ void optimize_load_store(ir_graph *irg) { /* Handle graph state */ if (env.changes) { set_irg_outs_inconsistent(irg); + set_irg_entity_usage_state(irg, ir_entity_usage_not_computed); } if (env.changes & CF_CHANGED) {