X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;ds=sidebyside;f=ir%2Fopt%2Fldstopt.c;h=ac883ed29cce5d41b8275843f1d378e2a49a44de;hb=b4a3d8471ab4a2ad12041f4ef1cb2473d9b5fe4c;hp=f5e2cb42834001974ee47d44f0fdb40a6085790b;hpb=e40b97bd28e9d4316aecceb642337847d303d4de;p=libfirm diff --git a/ir/opt/ldstopt.c b/ir/opt/ldstopt.c index f5e2cb428..ac883ed29 100644 --- a/ir/opt/ldstopt.c +++ b/ir/opt/ldstopt.c @@ -257,10 +257,7 @@ static ir_entity *find_constant_entity(ir_node *ptr) { for (;;) { if (is_SymConst(ptr) && get_SymConst_kind(ptr) == symconst_addr_ent) { - ir_entity *ent = get_SymConst_entity(ptr); - if (variability_constant == get_entity_variability(ent)) - return ent; - return NULL; + return get_SymConst_entity(ptr); } else if (is_Sel(ptr)) { ir_entity *ent = get_Sel_entity(ptr); ir_type *tp = get_entity_owner(ent); @@ -364,7 +361,7 @@ static compound_graph_path *rec_get_accessed_path(ir_node *ptr, int depth) { if (is_SymConst(ptr)) { /* a SymConst. If the depth is 0, this is an access to a global * entity and we don't need a component path, else we know - * at least it's length. + * at least its length. */ assert(get_SymConst_kind(ptr) == symconst_addr_ent); root = get_SymConst_entity(ptr); @@ -386,11 +383,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 { @@ -399,6 +397,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)) { @@ -410,7 +409,6 @@ ptr_arith: for (ent = field;;) { unsigned size; tarval *sz, *tv_index, *tlower, *tupper; - long index; ir_node *bound; tp = get_entity_type(ent); @@ -420,10 +418,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"); @@ -441,10 +439,9 @@ ptr_arith: return NULL; /* ok, bounds check finished */ - index = get_tarval_long(tv_index); ++idx; } - if (! tarval_is_null(tv)) { + if (! tarval_is_null(tmp)) { /* access to some struct/union member */ return NULL; } @@ -502,7 +499,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 { @@ -540,7 +538,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); @@ -693,7 +691,7 @@ static ir_node *find_compound_ent_value(ir_node *ptr) { static void reduce_adr_usage(ir_node *ptr); /** - * Update a Load that may lost it's usage. + * Update a Load that may have lost its users. */ static void handle_load_update(ir_node *load) { ldst_info_t *info = get_irn_link(load); @@ -706,7 +704,7 @@ static void handle_load_update(ir_node *load) { ir_node *ptr = get_Load_ptr(load); ir_node *mem = get_Load_mem(load); - /* a Load which value is neither used nor exception checked, remove it */ + /* a Load whose value is neither used nor exception checked, remove it */ exchange(info->projs[pn_Load_M], mem); if (info->projs[pn_Load_X_regular]) exchange(info->projs[pn_Load_X_regular], new_r_Jmp(current_ir_graph, get_nodes_block(load))); @@ -716,7 +714,7 @@ static void handle_load_update(ir_node *load) { } /* handle_load_update */ /** - * A Use of an address node is vanished. Check if this was a Proj + * A use of an address node has vanished. Check if this was a Proj * node and update the counters. */ static void reduce_adr_usage(ir_node *ptr) { @@ -729,7 +727,7 @@ static void reduce_adr_usage(ir_node *ptr) { ldst_info_t *info = get_irn_link(pred); info->projs[get_Proj_proj(ptr)] = NULL; - /* this node lost it's result proj, handle that */ + /* this node lost its result proj, handle that */ handle_load_update(pred); } } @@ -774,6 +772,141 @@ 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_and_offset(ir_node *ptr, long *pOffset) +{ + ir_mode *mode = get_irn_mode(ptr); + long offset = 0; + + /* TODO: long might not be enough, we should probably use some tarval thingy... */ + 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; + } + + *pOffset = offset; + return ptr; +} + +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); + 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 load_mode_len; + long store_mode_len; + long delta; + int res; + + if (load_base_ptr != store_base_ptr) + return 0; + + 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 + load_mode_len > store_mode_len) + return 0; + + 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); + + /* produce a shift to adjust offset delta */ + if (delta > 0) { + 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); + } + + /* add an convert if needed */ + if (store_mode != load_mode) { + store_value = new_r_Conv(current_ir_graph, get_nodes_block(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)); + + res = 0; + /* no exception */ + if (info->projs[pn_Load_X_except]) { + exchange( info->projs[pn_Load_X_except], new_Bad()); + res |= CF_CHANGED; + } + if (info->projs[pn_Load_X_regular]) { + exchange( info->projs[pn_Load_X_regular], new_r_Jmp(current_ir_graph, get_nodes_block(load))); + res |= CF_CHANGED; + } + + if (info->projs[pn_Load_res]) + exchange(info->projs[pn_Load_res], store_value); + + load_ptr = get_Load_ptr(load); + kill_node(load); + reduce_adr_usage(load_ptr); + return res | DF_CHANGED; +} + /** * Follow the memory chain as long as there are only Loads, * alias free Stores, and constant Calls and try to replace the @@ -785,67 +918,39 @@ static unsigned is_Call_pure(ir_node *call) { * 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 *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); /* - * BEWARE: one might think that checking the modes is useless, because - * if the pointers are identical, they refer to the same object. - * This is only true in strong typed languages, not in C were the following - * is possible a = *(ir_type1 *)p; b = *(ir_type2 *)p ... + * a Load immediately after a Store -- a read after write. + * We may remove the Load, if both Load & Store does not have an + * exception handler OR they are in the same MacroBlock. In the latter + * case the Load cannot throw an exception when the previous Store was + * quiet. + * + * Why we need to check for Store Exception? If the Store cannot + * be executed (ROM) the exception handler might simply jump into + * the load MacroBlock :-( + * We could make it a little bit better if we would know that the + * exception handler of the Store jumps directly to the end... */ - if (is_Store(pred) && get_Store_ptr(pred) == ptr && - can_use_stored_value(get_irn_mode(get_Store_value(pred)), load_mode)) { - /* - * a Load immediately after a Store -- a read after write. - * We may remove the Load, if both Load & Store does not have an exception handler - * OR they are in the same MacroBlock. In the latter case the Load cannot - * throw an exception when the previous Store was quiet. - * - * Why we need to check for Store Exception? If the Store cannot - * be executed (ROM) the exception handler might simply jump into - * the load MacroBlock :-( - * We could make it a little bit better if we would know that the exception - * handler of the Store jumps directly to the end... - */ - if ((pred_info->projs[pn_Store_X_except] == NULL && info->projs[pn_Load_X_except] == NULL) || - get_nodes_MacroBlock(load) == get_nodes_MacroBlock(pred)) { - ir_node *value = get_Store_value(pred); - - DBG_OPT_RAW(load, value); - - /* add an convert if needed */ - if (get_irn_mode(get_Store_value(pred)) != load_mode) { - value = new_r_Conv(current_ir_graph, get_nodes_block(load), value, load_mode); - } - - if (info->projs[pn_Load_M]) - exchange(info->projs[pn_Load_M], mem); - - /* no exception */ - if (info->projs[pn_Load_X_except]) { - exchange( info->projs[pn_Load_X_except], new_Bad()); - res |= CF_CHANGED; - } - if (info->projs[pn_Load_X_regular]) { - exchange( info->projs[pn_Load_X_regular], new_r_Jmp(current_ir_graph, get_nodes_block(load))); - res |= CF_CHANGED; - } - - if (info->projs[pn_Load_res]) - exchange(info->projs[pn_Load_res], value); - - kill_node(load); - reduce_adr_usage(ptr); - return res | DF_CHANGED; - } + if (is_Store(pred) && ((pred_info->projs[pn_Store_X_except] == NULL + && info->projs[pn_Load_X_except] == NULL) + || get_nodes_MacroBlock(load) == get_nodes_MacroBlock(pred))) + { + 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)) { /* @@ -944,6 +1049,33 @@ static unsigned follow_Mem_chain(ir_node *load, ir_node *curr) { return res; } /* follow_Mem_chain */ +/* + * Check if we can replace the load by a given const from + * the const code irg. + */ +ir_node *can_replace_load_by_const(const ir_node *load, ir_node *c) { + ir_mode *c_mode = get_irn_mode(c); + ir_mode *l_mode = get_Load_mode(load); + ir_node *res = NULL; + + if (c_mode != l_mode) { + /* check, if the mode matches OR can be easily converted info */ + if (is_reinterpret_cast(c_mode, l_mode)) { + /* we can safely cast */ + dbg_info *dbg = get_irn_dbg_info(load); + ir_node *block = get_nodes_block(load); + + /* copy the value from the const code irg and cast it */ + res = copy_const_value(dbg, c); + res = new_rd_Conv(dbg, current_ir_graph, block, res, l_mode); + } + } else { + /* copy the value from the const code irg */ + res = copy_const_value(get_irn_dbg_info(load), c); + } + return res; +} /* can_replace_load_by_const */ + /** * optimize a Load * @@ -952,9 +1084,10 @@ static unsigned follow_Mem_chain(ir_node *load, ir_node *curr) { static unsigned optimize_load(ir_node *load) { ldst_info_t *info = get_irn_link(load); - ir_node *mem, *ptr, *new_node; - 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) @@ -972,43 +1105,27 @@ static unsigned optimize_load(ir_node *load) * like x = new O; x->t; */ if (info->projs[pn_Load_X_except]) { - if (is_Sel(ptr)) { - ir_node *mem = get_Sel_mem(ptr); - - /* FIXME: works with the current FE, but better use the base */ - if (is_Alloc(skip_Proj(mem))) { - /* ok, check the types */ - ir_entity *ent = get_Sel_entity(ptr); - ir_type *s_type = get_entity_type(ent); - ir_type *a_type = get_Alloc_type(mem); - - if (is_SubClass_of(s_type, a_type)) { - /* ok, condition met: there can't be an exception because - * Alloc guarantees that enough memory was allocated */ - - exchange(info->projs[pn_Load_X_except], new_Bad()); - info->projs[pn_Load_X_except] = NULL; - exchange(info->projs[pn_Load_X_regular], new_r_Jmp(current_ir_graph, get_nodes_block(load))); - info->projs[pn_Load_X_regular] = NULL; - res |= CF_CHANGED; - } - } - } else if (is_Alloc(skip_Proj(skip_Cast(ptr)))) { - /* simple case: a direct load after an Alloc. Firm Alloc throw - * an exception in case of out-of-memory. So, there is no way for an - * exception in this load. - * This code is constructed by the "exception lowering" in the Jack compiler. - */ - exchange(info->projs[pn_Load_X_except], new_Bad()); - info->projs[pn_Load_X_except] = NULL; - exchange(info->projs[pn_Load_X_regular], new_r_Jmp(current_ir_graph, get_nodes_block(load))); - info->projs[pn_Load_X_regular] = NULL; - res |= CF_CHANGED; + ir_node *addr = ptr; + + /* find base address */ + while (is_Sel(addr)) + addr = get_Sel_ptr(addr); + if (is_Alloc(skip_Proj(skip_Cast(addr)))) { + /* simple case: a direct load after an Alloc. Firm Alloc throw + * an exception in case of out-of-memory. So, there is no way for an + * exception in this load. + * This code is constructed by the "exception lowering" in the Jack compiler. + */ + exchange(info->projs[pn_Load_X_except], new_Bad()); + info->projs[pn_Load_X_except] = NULL; + exchange(info->projs[pn_Load_X_regular], new_r_Jmp(current_ir_graph, get_nodes_block(load))); + info->projs[pn_Load_X_regular] = NULL; + res |= CF_CHANGED; } } /* The mem of the Load. Must still be returned after optimization. */ - mem = get_Load_mem(load); + mem = get_Load_mem(load); if (! info->projs[pn_Load_res] && ! info->projs[pn_Load_X_except]) { /* a Load which value is neither used nor exception checked, remove it */ @@ -1026,37 +1143,16 @@ static unsigned optimize_load(ir_node *load) /* Load from a constant polymorphic field, where we can resolve polymorphism. */ - new_node = transform_node_Load(load); - if (new_node != load) { - if (info->projs[pn_Load_M]) { - exchange(info->projs[pn_Load_M], mem); - info->projs[pn_Load_M] = NULL; - } - if (info->projs[pn_Load_X_except]) { - exchange(info->projs[pn_Load_X_except], new_Bad()); - info->projs[pn_Load_X_except] = NULL; - res |= CF_CHANGED; - } - if (info->projs[pn_Load_X_regular]) { - exchange(info->projs[pn_Load_X_regular], new_r_Jmp(current_ir_graph, get_nodes_block(load))); - info->projs[pn_Load_X_regular] = NULL; - res |= CF_CHANGED; - } - if (info->projs[pn_Load_res]) - exchange(info->projs[pn_Load_res], new_node); - - kill_node(load); - reduce_adr_usage(ptr); - return res | DF_CHANGED; - } - - /* check if we can determine the entity that will be loaded */ - ent = find_constant_entity(ptr); - if (ent) { - if ((allocation_static == get_entity_allocation(ent)) && - (visibility_external_allocated != get_entity_visibility(ent))) { + value = transform_polymorph_Load(load); + if (value == load) { + value = NULL; + /* check if we can determine the entity that will be loaded */ + ent = find_constant_entity(ptr); + if (ent != NULL && + allocation_static == get_entity_allocation(ent) && + visibility_external_allocated != get_entity_visibility(ent)) { /* a static allocation that is not external: there should be NO exception - * when loading. */ + * when loading even if we cannot replace the load itself. */ /* no exception, clear the info field as it might be checked later again */ if (info->projs[pn_Load_X_except]) { @@ -1072,78 +1168,59 @@ static unsigned optimize_load(ir_node *load) if (variability_constant == get_entity_variability(ent)) { if (is_atomic_entity(ent)) { - /* Might not be atomic after - lowering of Sels. In this - case we could also load, but - it's more complicated. */ + /* Might not be atomic after lowering of Sels. In this case we + * could also load, but it's more complicated. */ /* more simpler case: we load the content of a constant value: - * replace it by the constant itself - */ - - /* no memory */ - if (info->projs[pn_Load_M]) { - exchange(info->projs[pn_Load_M], mem); - res |= DF_CHANGED; - } - /* no result :-) */ - if (info->projs[pn_Load_res]) { - if (is_atomic_entity(ent)) { - ir_node *c = copy_const_value(get_irn_dbg_info(load), get_atomic_ent_value(ent)); - - DBG_OPT_RC(load, c); - exchange(info->projs[pn_Load_res], c); - res |= DF_CHANGED; - } - } - kill_node(load); - reduce_adr_usage(ptr); - return res; + * replace it by the constant itself */ + value = get_atomic_ent_value(ent); + } else if (ent->has_initializer) { + /* new style initializer */ + value = find_compound_ent_value(ptr); } else { - ir_node *c = NULL; - if (ent->has_initializer) { - /* new style initializer */ - c = find_compound_ent_value(ptr); - } else { - /* old style initializer */ - compound_graph_path *path = get_accessed_path(ptr); - - if (path) { - assert(is_proper_compound_graph_path(path, get_compound_graph_path_length(path)-1)); - - c = get_compound_ent_value_by_path(ent, path); - free_compound_graph_path(path); - } - } - if (c != NULL) { - if (info->projs[pn_Load_M]) { - exchange(info->projs[pn_Load_M], mem); - res |= DF_CHANGED; - } - if (info->projs[pn_Load_res]) { - exchange(info->projs[pn_Load_res], copy_const_value(get_irn_dbg_info(load), c)); - res |= DF_CHANGED; - } - kill_node(load); - reduce_adr_usage(ptr); - return res; - } else { - /* We can not determine a correct access path. E.g., in jack, we load - a byte from an object to generate an exception. Happens in test program - Reflectiontest. - printf(">>>>>>>>>>>>> Found access to constant entity %s in function %s\n", get_entity_name(ent), - get_entity_name(get_irg_entity(current_ir_graph))); - ir_printf(" load: %+F\n", load); - ir_printf(" ptr: %+F\n", ptr); - */ + /* old style initializer */ + compound_graph_path *path = get_accessed_path(ptr); + + if (path != NULL) { + 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); } } + if (value != NULL) + value = can_replace_load_by_const(load, value); } } } + if (value != NULL) { + /* we completely replace the load by this value */ + if (info->projs[pn_Load_X_except]) { + exchange(info->projs[pn_Load_X_except], new_Bad()); + info->projs[pn_Load_X_except] = NULL; + res |= CF_CHANGED; + } + if (info->projs[pn_Load_X_regular]) { + exchange(info->projs[pn_Load_X_regular], new_r_Jmp(current_ir_graph, get_nodes_block(load))); + info->projs[pn_Load_X_regular] = NULL; + res |= CF_CHANGED; + } + if (info->projs[pn_Load_M]) { + exchange(info->projs[pn_Load_M], mem); + res |= DF_CHANGED; + } + if (info->projs[pn_Load_res]) { + exchange(info->projs[pn_Load_res], value); + res |= DF_CHANGED; + } + kill_node(load); + reduce_adr_usage(ptr); + return res; + } /* 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) + * 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; /* @@ -1228,7 +1305,7 @@ static unsigned follow_Mem_chain_for_Store(ir_node *store, ir_node *curr) { } if (is_Store(pred)) { - /* check if we can pass thru this store */ + /* check if we can pass through this store */ ir_alias_relation rel = get_alias_relation( current_ir_graph, get_Store_ptr(pred), @@ -1270,18 +1347,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. */ @@ -2063,8 +2183,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); @@ -2084,6 +2204,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) {