/**
* @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;
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;
}