a better version of a copyb lowerer
authorMatthias Braun <matze@braunis.de>
Fri, 7 Mar 2008 16:32:19 +0000 (16:32 +0000)
committerMatthias Braun <matze@braunis.de>
Fri, 7 Mar 2008 16:32:19 +0000 (16:32 +0000)
[r18000]

include/libfirm/lowering.h
ir/lower/lower_copyb.c
ir/lower/lower_hl.c

index d6aadcb..0ddb1c1 100644 (file)
@@ -144,6 +144,12 @@ typedef struct {
  */
 void lower_calls_with_compounds(const lower_params_t *params);
 
+/**
+ *  * Lower CopyB nodes of size smaller that max_size into Loads/Stores
+ */
+void lower_CopyB(ir_graph *irg, unsigned max_size, unsigned native_mode_bytes);
+
+
 /**
  * A callback type for creating an intrinsic entity for a given opcode.
  *
index edfd9a7..aa17a52 100644 (file)
@@ -20,7 +20,7 @@
 /**
  * @file
  * @brief   Lower small CopyB nodes into a series of Load/store
- * @author  Michael Beck
+ * @author  Matthias Braun, Michael Beck
  * @version $Id$
  */
 #ifdef HAVE_CONFIG_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;
-
-/**
- * Build a graph that copies an entity of type tp from src to tgt
- */
-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);
-                       }
-               }
+#include "iredges_t.h"
+#include "irgmod.h"
+#include "error.h"
+
+static unsigned max_size;
+static unsigned native_mode_bytes;
+
+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");
        }
-       return mem;
 }
 
 /**
  * Walker: lower small CopyB nodes.
  */
 static void lower_copyb_nodes(ir_node *irn, void *ctx) {
-       ir_type    *tp;
-       int        size;
-       walker_env *env = ctx;
+       ir_graph        *irg = current_ir_graph;
+       ir_type         *tp;
+       unsigned         size;
+       unsigned         mode_bytes;
+       unsigned         offset;
+       ir_mode         *mode;
+       ir_mode         *addr_mode;
+       ir_node         *mem;
+       ir_node         *addr_src;
+       ir_node         *addr_dst;
+       ir_node         *block;
+       ir_node         *proj_M = NULL;
+       const ir_edge_t *edge;
+       (void) ctx;
 
        if (! is_CopyB(irn))
                return;
@@ -92,26 +81,74 @@ static void lower_copyb_nodes(ir_node *irn, void *ctx) {
                return;
 
        size = get_type_size_bytes(tp);
-       if (size > env->max_size)
+       if (size > 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);
+       foreach_out_edge(irn, edge) {
+               ir_node *node = get_edge_src_irn(edge);
+               long     pn   = get_Proj_proj(node);
+
+               /* we don't lower copybs with exception edges (yet) */
+               if(pn == pn_CopyB_X_except)
+                       return;
+               if(pn == pn_CopyB_M_regular) {
+                       assert(proj_M == NULL);
+                       proj_M = node;
+               }
+       }
+       if(proj_M == NULL) {
+               panic("no projM on copyb");
        }
-}
 
-/**
- * Lower CopyB nodes of size smaller that max_size into Loads/Stores
- */
-void lower_CopyB(int max_size) {
-       walker_env env;
-       int        i;
-
-       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);
+       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);
+
+       offset     = 0;
+       mode_bytes = native_mode_bytes;
+       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;
        }
+
+       exchange(proj_M, mem);
+}
+
+void lower_CopyB(ir_graph *irg, unsigned new_max_size,
+                 unsigned new_native_mode_bytes)
+{
+       max_size          = new_max_size;
+       native_mode_bytes = new_native_mode_bytes;
+
+       edges_assure(irg);
+
+       irg_walk_graph(irg, NULL, lower_copyb_nodes, NULL);
 }
index 4d5c336..70730bd 100644 (file)
@@ -223,8 +223,10 @@ static void lower_sel(ir_node *sel) {
                        newn   = get_Sel_ptr(sel);
                        offset = get_entity_offset(ent);
                        if (offset != 0) {
-                               tv = new_tarval_from_long(offset, mode_Int);
-                               cnst = new_r_Const(irg, get_irg_start_block(irg), mode_Int, tv);
+                               ir_mode *mode_UInt = get_reference_mode_unsigned_eq(mode);
+
+                               tv = new_tarval_from_long(offset, mode_UInt);
+                               cnst = new_r_Const(irg, get_irg_start_block(irg), mode_UInt, tv);
                                newn = new_rd_Add(dbg, irg, bl, newn, cnst, mode);
                        }
                } else {