aa17a52b8a2087aef14b4440f49f48f6ea7189ac
[libfirm] / ir / lower / lower_copyb.c
1 /*
2  * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   Lower small CopyB nodes into a series of Load/store
23  * @author  Matthias Braun, Michael Beck
24  * @version $Id$
25  */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include "ircons.h"
31 #include "lowering.h"
32 #include "irprog_t.h"
33 #include "irgwalk.h"
34 #include "irnode_t.h"
35 #include "type_t.h"
36 #include "irtools.h"
37 #include "iredges_t.h"
38 #include "irgmod.h"
39 #include "error.h"
40
41 static unsigned max_size;
42 static unsigned native_mode_bytes;
43
44 static ir_mode *get_ir_mode(unsigned bytes)
45 {
46         switch(bytes) {
47         case 1:  return mode_Bu;
48         case 2:  return mode_Hu;
49         case 4:  return mode_Iu;
50         case 8:  return mode_Lu;
51         case 16: return mode_LLu;
52         default:
53                 panic("unexpected mode size requested in copyb lowering");
54         }
55 }
56
57 /**
58  * Walker: lower small CopyB nodes.
59  */
60 static void lower_copyb_nodes(ir_node *irn, void *ctx) {
61         ir_graph        *irg = current_ir_graph;
62         ir_type         *tp;
63         unsigned         size;
64         unsigned         mode_bytes;
65         unsigned         offset;
66         ir_mode         *mode;
67         ir_mode         *addr_mode;
68         ir_node         *mem;
69         ir_node         *addr_src;
70         ir_node         *addr_dst;
71         ir_node         *block;
72         ir_node         *proj_M = NULL;
73         const ir_edge_t *edge;
74         (void) ctx;
75
76         if (! is_CopyB(irn))
77                 return;
78
79         tp = get_CopyB_type(irn);
80         if (get_type_state(tp) != layout_fixed)
81                 return;
82
83         size = get_type_size_bytes(tp);
84         if (size > max_size)
85                 return;
86
87         foreach_out_edge(irn, edge) {
88                 ir_node *node = get_edge_src_irn(edge);
89                 long     pn   = get_Proj_proj(node);
90
91                 /* we don't lower copybs with exception edges (yet) */
92                 if(pn == pn_CopyB_X_except)
93                         return;
94                 if(pn == pn_CopyB_M_regular) {
95                         assert(proj_M == NULL);
96                         proj_M = node;
97                 }
98         }
99         if(proj_M == NULL) {
100                 panic("no projM on copyb");
101         }
102
103         addr_src  = get_CopyB_src(irn);
104         addr_dst  = get_CopyB_dst(irn);
105         mem       = get_CopyB_mem(irn);
106         addr_mode = get_irn_mode(addr_src);
107         block     = get_nodes_block(irn);
108
109         offset     = 0;
110         mode_bytes = native_mode_bytes;
111         while(offset < size) {
112                 mode = get_ir_mode(mode_bytes);
113                 for( ; offset + mode_bytes <= size; offset += mode_bytes) {
114                         /* construct offset */
115                         ir_node *addr_const;
116                         ir_node *add;
117                         ir_node *load;
118                         ir_node *load_res;
119                         ir_node *load_mem;
120                         ir_node *store;
121                         ir_node *store_mem;
122
123                         addr_const = new_r_Const_long(irg, block, mode_Iu, offset);
124                         add        = new_r_Add(irg, block, addr_src, addr_const, addr_mode);
125
126                         load     = new_r_Load(irg, block, mem, add, mode);
127                         load_res = new_r_Proj(irg, block, load, mode, pn_Load_res);
128                         load_mem = new_r_Proj(irg, block, load, mode_M, pn_Load_M);
129
130                         addr_const = new_r_Const_long(irg, block, mode_Iu, offset);
131                         add        = new_r_Add(irg, block, addr_dst, addr_const, addr_mode);
132
133                         store     = new_r_Store(irg, block, mem, add, load_res);
134                         store_mem = new_r_Proj(irg, block, store, mode_M, pn_Store_M);
135
136                         mem = store_mem;
137                 }
138
139                 mode_bytes /= 2;
140         }
141
142         exchange(proj_M, mem);
143 }
144
145 void lower_CopyB(ir_graph *irg, unsigned new_max_size,
146                  unsigned new_native_mode_bytes)
147 {
148         max_size          = new_max_size;
149         native_mode_bytes = new_native_mode_bytes;
150
151         edges_assure(irg);
152
153         irg_walk_graph(irg, NULL, lower_copyb_nodes, NULL);
154 }