X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fopt%2Fldstopt.c;h=dd0231e2d86a7a71bee37711708ee9ba64703277;hb=c59d37f47fdab6d74f1da6738b2d3f3373a378b9;hp=ce87077cee99c0da417db2cbf5a88973f94542c6;hpb=7fcabe88f484291a1d97c829beb68335babf4497;p=libfirm diff --git a/ir/opt/ldstopt.c b/ir/opt/ldstopt.c index ce87077ce..dd0231e2d 100644 --- a/ir/opt/ldstopt.c +++ b/ir/opt/ldstopt.c @@ -43,11 +43,12 @@ #include "array_t.h" #include "irhooks.h" #include "iredges.h" -#include "irtools.h" +#include "irpass.h" #include "opt_polymorphy.h" #include "irmemory.h" #include "irphase_t.h" #include "irgopt.h" +#include "set.h" #include "debug.h" /** The debug handle. */ @@ -112,8 +113,7 @@ static ldst_info_t *get_ldst_info(ir_node *node, struct obstack *obst) { ldst_info_t *info = get_irn_link(node); if (! info) { - info = obstack_alloc(obst, sizeof(*info)); - memset(info, 0, sizeof(*info)); + info = OALLOCZ(obst, ldst_info_t); set_irn_link(node, info); } return info; @@ -126,8 +126,7 @@ static block_info_t *get_block_info(ir_node *node, struct obstack *obst) { block_info_t *info = get_irn_link(node); if (! info) { - info = obstack_alloc(obst, sizeof(*info)); - memset(info, 0, sizeof(*info)); + info = OALLOCZ(obst, block_info_t); set_irn_link(node, info); } return info; @@ -704,7 +703,7 @@ static void handle_load_update(ir_node *load) { /* 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))); + exchange(info->projs[pn_Load_X_regular], new_r_Jmp(get_nodes_block(load))); kill_node(load); reduce_adr_usage(ptr); } @@ -870,14 +869,13 @@ static int try_load_after_store(ir_node *load, /* 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 = new_r_Shr(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); + store_value = new_r_Conv(get_nodes_block(load), store_value, load_mode); } } @@ -894,7 +892,7 @@ static int try_load_after_store(ir_node *load, 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))); + exchange( info->projs[pn_Load_X_regular], new_r_Jmp(get_nodes_block(load))); res |= CF_CHANGED; } @@ -971,13 +969,13 @@ static unsigned follow_Mem_chain(ir_node *load, ir_node *curr) { if (info->projs[pn_Load_res]) { if (pred_info->projs[pn_Load_res] == NULL) { /* create a new Proj again */ - pred_info->projs[pn_Load_res] = new_r_Proj(current_ir_graph, get_nodes_block(pred), pred, get_Load_mode(pred), pn_Load_res); + pred_info->projs[pn_Load_res] = new_r_Proj(get_nodes_block(pred), pred, get_Load_mode(pred), pn_Load_res); } value = pred_info->projs[pn_Load_res]; /* add an convert if needed */ if (get_Load_mode(pred) != load_mode) { - value = new_r_Conv(current_ir_graph, get_nodes_block(load), value, load_mode); + value = new_r_Conv(get_nodes_block(load), value, load_mode); } exchange(info->projs[pn_Load_res], value); @@ -992,7 +990,7 @@ static unsigned follow_Mem_chain(ir_node *load, ir_node *curr) { 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))); + exchange( info->projs[pn_Load_X_regular], new_r_Jmp(get_nodes_block(load))); res |= CF_CHANGED; } @@ -1067,7 +1065,7 @@ ir_node *can_replace_load_by_const(const ir_node *load, ir_node *c) { /* 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); + res = new_rd_Conv(dbg, block, res, l_mode); } } else { /* copy the value from the const code irg */ @@ -1118,7 +1116,7 @@ static unsigned optimize_load(ir_node *load) */ 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))); + exchange(info->projs[pn_Load_X_regular], new_r_Jmp(get_nodes_block(load))); info->projs[pn_Load_X_regular] = NULL; res |= CF_CHANGED; } @@ -1133,7 +1131,7 @@ static unsigned optimize_load(ir_node *load) if (info->projs[pn_Load_X_regular]) { /* should not happen, but if it does, remove it */ - exchange(info->projs[pn_Load_X_regular], new_r_Jmp(current_ir_graph, get_nodes_block(load))); + exchange(info->projs[pn_Load_X_regular], new_r_Jmp(get_nodes_block(load))); res |= CF_CHANGED; } kill_node(load); @@ -1161,7 +1159,7 @@ static unsigned optimize_load(ir_node *load) 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))); + exchange(info->projs[pn_Load_X_regular], new_r_Jmp(get_nodes_block(load))); info->projs[pn_Load_X_regular] = NULL; res |= CF_CHANGED; } @@ -1201,7 +1199,7 @@ static unsigned optimize_load(ir_node *load) 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))); + exchange(info->projs[pn_Load_X_regular], new_r_Jmp(get_nodes_block(load))); info->projs[pn_Load_X_regular] = NULL; res |= CF_CHANGED; } @@ -1442,6 +1440,7 @@ static unsigned optimize_store(ir_node *store) { 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) { + DB((dbg, LEVEL_1, " Killing useless %+F to never read entity %+F\n", store, entity)); exchange(info->projs[pn_Store_M], get_Store_mem(store)); kill_node(store); reduce_adr_usage(ptr); @@ -1610,10 +1609,10 @@ static unsigned optimize_phi(ir_node *phi, walk_env_t *wenv) block = get_nodes_block(phi); /* second step: create a new memory Phi */ - phiM = new_rd_Phi(get_irn_dbg_info(phi), current_ir_graph, block, n, inM, mode_M); + phiM = new_rd_Phi(get_irn_dbg_info(phi), block, n, inM, mode_M); /* third step: create a new data Phi */ - phiD = new_rd_Phi(get_irn_dbg_info(phi), current_ir_graph, block, n, inD, mode); + phiD = new_rd_Phi(get_irn_dbg_info(phi), block, n, inD, mode); /* rewire memory and kill the node */ for (i = n - 1; i >= 0; --i) { @@ -1627,19 +1626,19 @@ static unsigned optimize_phi(ir_node *phi, walk_env_t *wenv) } /* fourth step: create the Store */ - store = new_rd_Store(db, current_ir_graph, block, phiM, ptr, phiD, 0); + store = new_rd_Store(db, block, phiM, ptr, phiD, 0); #ifdef DO_CACHEOPT co_set_irn_name(store, co_get_irn_ident(old_store)); #endif - projM = new_rd_Proj(NULL, current_ir_graph, block, store, mode_M, pn_Store_M); + projM = new_rd_Proj(NULL, block, store, mode_M, pn_Store_M); info = get_ldst_info(store, &wenv->obst); info->projs[pn_Store_M] = projM; /* fifths step: repair exception flow */ if (exc) { - ir_node *projX = new_rd_Proj(NULL, current_ir_graph, block, store, mode_X, pn_Store_X_except); + ir_node *projX = new_rd_Proj(NULL, block, store, mode_X, pn_Store_X_except); info->projs[pn_Store_X_except] = projX; info->exc_block = exc; @@ -1696,7 +1695,6 @@ typedef struct scc { typedef struct node_entry { unsigned DFSnum; /**< the DFS number of this node */ unsigned low; /**< the low number of this node */ - ir_node *header; /**< the header of this node */ int in_stack; /**< flag, set if the node is on the stack */ ir_node *next; /**< link to the next node the the same scc */ scc *pscc; /**< the scc of this node */ @@ -1783,6 +1781,33 @@ struct phi_entry { phi_entry *next; }; +/** + * An entry in the avail set. + */ +typedef struct avail_entry_t { + ir_node *ptr; /**< the address pointer */ + ir_mode *mode; /**< the load mode */ + ir_node *load; /**< the associated Load */ +} avail_entry_t; + +/** + * Compare two avail entries. + */ +static int cmp_avail_entry(const void *elt, const void *key, size_t size) { + const avail_entry_t *a = elt; + const avail_entry_t *b = key; + (void) size; + + return a->ptr != b->ptr || a->mode != b->mode; +} /* cmp_avail_entry */ + +/** + * Calculate the hash value of an avail entry. + */ +static unsigned hash_cache_entry(const avail_entry_t *entry) { + return get_irn_idx(entry->ptr) * 9 + HASH_PTR(entry->mode); +} /* hash_cache_entry */ + /** * Move loops out of loops if possible. * @@ -1794,6 +1819,9 @@ static void move_loads_out_of_loops(scc *pscc, loop_env *env) { ir_entity *ent; int j; phi_entry *phi_list = NULL; + set *avail; + + avail = new_set(cmp_avail_entry, 8); /* collect all outer memories */ for (phi = pscc->head; phi != NULL; phi = next) { @@ -1804,7 +1832,7 @@ static void move_loads_out_of_loops(scc *pscc, loop_env *env) { if (! is_Phi(phi)) continue; - assert(get_irn_mode(phi) == mode_M && "DFS geturn non-memory Phi"); + assert(get_irn_mode(phi) == mode_M && "DFS return non-memory Phi"); for (j = get_irn_arity(phi) - 1; j >= 0; --j) { ir_node *pred = get_irn_n(phi, j); @@ -1824,6 +1852,10 @@ static void move_loads_out_of_loops(scc *pscc, loop_env *env) { /* no Phis no fun */ assert(phi_list != NULL && "DFS found a loop without Phi"); + /* for now, we cannot handle more than one input (only reducible cf) */ + if (phi_list->next != NULL) + return; + for (load = pscc->head; load; load = next) { ir_mode *load_mode; node_entry *ne = get_irn_ne(load, env); @@ -1837,10 +1869,10 @@ static void move_loads_out_of_loops(scc *pscc, loop_env *env) { if (info->projs[pn_Load_res] == NULL || info->projs[pn_Load_X_regular] != NULL || info->projs[pn_Load_X_except] != NULL) continue; - /* for now, we can only handle Load(Global) */ + /* for now, we can only move Load(Global) */ if (! is_Global(ptr)) continue; - ent = get_Global_entity(ptr); + ent = get_Global_entity(ptr); load_mode = get_Load_mode(load); for (other = pscc->head; other != NULL; other = next_other) { node_entry *ne = get_irn_ne(other, env); @@ -1856,17 +1888,13 @@ static void move_loads_out_of_loops(scc *pscc, loop_env *env) { if (rel != ir_no_alias) break; } - /* only pure Calls are allowed here, so ignore them */ + /* only Phis and pure Calls are allowed here, so ignore them */ } if (other == NULL) { ldst_info_t *ninfo; phi_entry *pe; dbg_info *db; - /* for now, we cannot handle more than one input */ - if (phi_list->next != NULL) - return; - /* yep, no aliasing Store found, Load can be moved */ DB((dbg, LEVEL_1, " Found a Load that could be moved: %+F\n", load)); @@ -1877,16 +1905,26 @@ static void move_loads_out_of_loops(scc *pscc, loop_env *env) { ir_node *blk = get_nodes_block(phi); ir_node *pred = get_Block_cfgpred_block(blk, pos); ir_node *irn, *mem; - - pe->load = irn = new_rd_Load(db, current_ir_graph, pred, get_Phi_pred(phi, pos), ptr, load_mode, 0); + avail_entry_t entry, *res; + + entry.ptr = ptr; + entry.mode = load_mode; + res = set_find(avail, &entry, sizeof(entry), hash_cache_entry(&entry)); + if (res != NULL) { + irn = res->load; + } else { + irn = new_rd_Load(db, pred, get_Phi_pred(phi, pos), ptr, load_mode, 0); + entry.load = irn; + set_insert(avail, &entry, sizeof(entry), hash_cache_entry(&entry)); + DB((dbg, LEVEL_1, " Created %+F in %+F\n", irn, pred)); + } + pe->load = irn; ninfo = get_ldst_info(irn, phase_obst(&env->ph)); - ninfo->projs[pn_Load_M] = mem = new_r_Proj(current_ir_graph, pred, irn, mode_M, pn_Load_M); + ninfo->projs[pn_Load_M] = mem = new_r_Proj(pred, irn, mode_M, pn_Load_M); set_Phi_pred(phi, pos, mem); - ninfo->projs[pn_Load_res] = new_r_Proj(current_ir_graph, pred, irn, load_mode, pn_Load_res); - - DB((dbg, LEVEL_1, " Created %+F in %+F\n", irn, pred)); + ninfo->projs[pn_Load_res] = new_r_Proj(pred, irn, load_mode, pn_Load_res); } /* now kill the old Load */ @@ -1897,6 +1935,7 @@ static void move_loads_out_of_loops(scc *pscc, loop_env *env) { } } } + del_set(avail); } /* move_loads_out_of_loops */ /** @@ -1919,13 +1958,12 @@ static void process_loop(scc *pscc, loop_env *env) { next = e->next; b = get_irn_ne(block, env); - if (header) { + if (header != NULL) { if (h->POnum < b->POnum) { header = block; h = b; } - } - else { + } else { header = block; h = b; } @@ -1980,10 +2018,12 @@ static void process_loop(scc *pscc, loop_env *env) { /* not a memory loop */ goto fail; } - if (! out_rc) { + if (out_rc == NULL) { + /* first region constant */ out_rc = pred; ++num_outside; } else if (out_rc != pred) { + /* another region constant */ ++num_outside; } } @@ -2003,22 +2043,20 @@ static void process_loop(scc *pscc, loop_env *env) { for (irn = pscc->head; irn; irn = next) { node_entry *e = get_irn_ne(irn, env); next = e->next; - e->header = NULL; exchange(irn, out_rc); } env->changes |= DF_CHANGED; return; } - /* set the header for every node in this scc */ +#ifdef DEBUG_libfirm for (irn = pscc->head; irn; irn = next) { node_entry *e = get_irn_ne(irn, env); - e->header = header; next = e->next; DB((dbg, LEVEL_2, " %+F,", irn)); } DB((dbg, LEVEL_2, "\n")); - +#endif move_loads_out_of_loops(pscc, env); fail: @@ -2260,3 +2298,8 @@ int optimize_load_store(ir_graph *irg) { } return env.changes != 0; } /* optimize_load_store */ + +ir_graph_pass_t *optimize_load_store_pass(const char *name) +{ + return def_graph_pass_ret(name ? name : "ldst", optimize_load_store); +} /* optimize_load_store_pass */