X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Flower%2Flower_copyb.c;h=de1a3b3826a04fe108de4692d242da5a98935244;hb=9e32caf2e94f99e6d057b69e5b8384e26de2e785;hp=edfd9a7a56bc4b1187227957061cca13f9bd20ee;hpb=a786fc1bdb328d8b1141cd3d18f199b998947c20;p=libfirm diff --git a/ir/lower/lower_copyb.c b/ir/lower/lower_copyb.c index edfd9a7a5..de1a3b382 100644 --- a/ir/lower/lower_copyb.c +++ b/ir/lower/lower_copyb.c @@ -20,69 +20,131 @@ /** * @file * @brief Lower small CopyB nodes into a series of Load/store - * @author Michael Beck + * @author Michael Beck, Matthias Braun * @version $Id$ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif +#include "adt/list.h" #include "ircons.h" #include "lowering.h" #include "irprog_t.h" +#include "irgwalk.h" #include "irnode_t.h" #include "type_t.h" #include "irtools.h" - -typedef struct copyb_env { - ir_node *next; /**< link to the next one */ -} copyb_env; - - -typedef struct walker_env { - struct obstack obst; /**< temporary space */ - int max_size; - ir_node *list; /**< list of CopyB nodes. */ -} walker_env; +#include "irgmod.h" +#include "error.h" + +typedef struct entry entry_t; +struct entry { + struct list_head list; + ir_node *copyb; +}; + +typedef struct walk_env { + unsigned max_size; + struct obstack obst; /**< the obstack where data is allocated on */ + struct list_head list; /**< the list of copyb nodes */ +} walk_env_t; + +static ir_mode *get_ir_mode(unsigned bytes) +{ + switch (bytes) { + case 1: return mode_Bu; + case 2: return mode_Hu; + case 4: return mode_Iu; + case 8: return mode_Lu; + case 16: return mode_LLu; + default: + panic("unexpected mode size requested in copyb lowering"); + } +} /** - * Build a graph that copies an entity of type tp from src to tgt + * lower a CopyB node. */ -static ir_node *build_copy_graph(dbg_info *dbg, ir_node *blk, ir_node *mem, ir_node *src, ir_node *tgt, ir_type *tp) { - int i, n; - - if (is_Array_type(tp)) { - assert(0); - } else { - for (i = 0, n = get_compound_n_members(tp); i < n; ++i) { - ir_entity *ent = get_compound_member(tp, i); - ir_node *s = new_d_simpleSel(dbg, mem, src, ent); - ir_node *d = new_d_simpleSel(dbg, mem, tgt, ent); - ir_type *ent_tp = get_entity_type(ent); - - if (is_atomic_type(ent_tp)) { - ir_mode *mode = get_type_mode(ent_tp); - ir_node *irn = new_rd_Load(dbg, current_ir_graph, blk, mem, s, mode); - ir_node *res = new_r_Proj(current_ir_graph, blk, irn, mode, pn_Load_res); - - mem = new_r_Proj(current_ir_graph, blk, irn, mode_M, pn_Load_M); - irn = new_rd_Store(dbg, current_ir_graph, blk, mem, d, res); - mem = new_r_Proj(current_ir_graph, blk, irn, mode_M, pn_Store_M); - } else { - mem = build_copy_graph(dbg, blk, mem, s, d, ent_tp); - } +static void lower_copyb_nodes(ir_node *irn, unsigned mode_bytes) { + ir_graph *irg = current_ir_graph; + unsigned size; + unsigned offset; + ir_mode *mode; + ir_mode *addr_mode; + ir_node *mem; + ir_node *addr_src; + ir_node *addr_dst; + ir_node *block; + ir_type *tp; + + addr_src = get_CopyB_src(irn); + addr_dst = get_CopyB_dst(irn); + mem = get_CopyB_mem(irn); + addr_mode = get_irn_mode(addr_src); + block = get_nodes_block(irn); + + tp = get_CopyB_type(irn); + size = get_type_size_bytes(tp); + + offset = 0; + while (offset < size) { + mode = get_ir_mode(mode_bytes); + for (; offset + mode_bytes <= size; offset += mode_bytes) { + /* construct offset */ + ir_node *addr_const; + ir_node *add; + ir_node *load; + ir_node *load_res; + ir_node *load_mem; + ir_node *store; + ir_node *store_mem; + + addr_const = new_r_Const_long(irg, block, mode_Iu, offset); + add = new_r_Add(irg, block, addr_src, addr_const, addr_mode); + + load = new_r_Load(irg, block, mem, add, mode); + load_res = new_r_Proj(irg, block, load, mode, pn_Load_res); + load_mem = new_r_Proj(irg, block, load, mode_M, pn_Load_M); + + addr_const = new_r_Const_long(irg, block, mode_Iu, offset); + add = new_r_Add(irg, block, addr_dst, addr_const, addr_mode); + + store = new_r_Store(irg, block, mem, add, load_res); + store_mem = new_r_Proj(irg, block, store, mode_M, pn_Store_M); + + mem = store_mem; } + + mode_bytes /= 2; } - return mem; + + turn_into_tuple(irn, pn_CopyB_max); + set_Tuple_pred(irn, pn_CopyB_M_regular, mem); + set_Tuple_pred(irn, pn_CopyB_X_regular, get_irg_bad(irg)); + set_Tuple_pred(irn, pn_CopyB_X_except, get_irg_bad(irg)); + set_Tuple_pred(irn, pn_CopyB_M_except, get_irg_bad(irg)); } /** - * Walker: lower small CopyB nodes. + * Post-Walker: find small CopyB nodes. */ -static void lower_copyb_nodes(ir_node *irn, void *ctx) { +static void find_copyb_nodes(ir_node *irn, void *ctx) { + walk_env_t *env = ctx; ir_type *tp; - int size; - walker_env *env = ctx; + unsigned size; + entry_t *entry; + + if (is_Proj(irn)) { + ir_node *pred = get_Proj_pred(irn); + + if (is_CopyB(pred) && get_Proj_proj(irn) != pn_CopyB_M_regular) { + /* found an exception Proj: remove it from the list again */ + entry = get_irn_link(pred); + list_del(&entry->list); + } + return; + } if (! is_CopyB(irn)) return; @@ -95,23 +157,31 @@ static void lower_copyb_nodes(ir_node *irn, void *ctx) { if (size > env->max_size) return; - /* for now, we can only handle Struct's */ - if (is_Struct_type(tp)) { - irn = build_copy_graph(get_irn_dbg_info(irn), get_nodes_block(irn), get_CopyB_mem(irn), get_CopyB_src(irn), get_CopyB_dst(irn), tp); - } + /* ok, link it in */ + entry = obstack_alloc(&env->obst, sizeof(*entry)); + entry->copyb = irn; + INIT_LIST_HEAD(&entry->list); + set_irn_link(irn, entry); + list_add_tail(&entry->list, &env->list); } -/** - * Lower CopyB nodes of size smaller that max_size into Loads/Stores - */ -void lower_CopyB(int max_size) { - walker_env env; - int i; +void lower_CopyB(ir_graph *irg, unsigned max_size, unsigned native_mode_bytes) +{ + walk_env_t env; + entry_t *entry; + ir_graph *rem = current_ir_graph; + + current_ir_graph = irg; obstack_init(&env.obst); env.max_size = max_size; - env.list = NULL; - for (i = get_irp_n_irgs() - 1; i >= 0; --i) { - irg_walk_graph(get_irp_irg(i), firm_clear_link, lower_copyb_nodes, NULL); + INIT_LIST_HEAD(&env.list); + irg_walk_graph(irg, NULL, find_copyb_nodes, &env); + + list_for_each_entry(entry_t, entry, &env.list, list) { + lower_copyb_nodes(entry->copyb, native_mode_bytes); } + + obstack_free(&env.obst, NULL); + current_ir_graph = rem; }