Teach AM folding about Syncs. Atm this only affects Div nodes, but is useful for...
[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  Michael Beck, Matthias Braun
24  * @version $Id$
25  */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include "adt/list.h"
31 #include "ircons.h"
32 #include "lowering.h"
33 #include "irprog_t.h"
34 #include "irgwalk.h"
35 #include "irnode_t.h"
36 #include "type_t.h"
37 #include "irtools.h"
38 #include "irgmod.h"
39 #include "error.h"
40
41 typedef struct entry entry_t;
42 struct entry {
43         struct list_head list;
44         ir_node *copyb;
45 };
46
47 typedef struct walk_env {
48         unsigned         max_size;
49         struct obstack   obst;              /**< the obstack where data is allocated on */
50         struct list_head list;              /**< the list of copyb nodes */
51 } walk_env_t;
52
53 static ir_mode *get_ir_mode(unsigned bytes)
54 {
55         switch (bytes) {
56         case 1:  return mode_Bu;
57         case 2:  return mode_Hu;
58         case 4:  return mode_Iu;
59         case 8:  return mode_Lu;
60         case 16: return mode_LLu;
61         default:
62                 panic("unexpected mode size requested in copyb lowering");
63         }
64 }
65
66 /**
67  * lower a CopyB node.
68  */
69 static void lower_copyb_nodes(ir_node *irn, unsigned mode_bytes) {
70         ir_graph        *irg = current_ir_graph;
71         unsigned         size;
72         unsigned         offset;
73         ir_mode         *mode;
74         ir_mode         *addr_mode;
75         ir_node         *mem;
76         ir_node         *addr_src;
77         ir_node         *addr_dst;
78         ir_node         *block;
79         ir_type         *tp;
80
81         addr_src  = get_CopyB_src(irn);
82         addr_dst  = get_CopyB_dst(irn);
83         mem       = get_CopyB_mem(irn);
84         addr_mode = get_irn_mode(addr_src);
85         block     = get_nodes_block(irn);
86
87         tp   = get_CopyB_type(irn);
88         size = get_type_size_bytes(tp);
89
90         offset     = 0;
91         while (offset < size) {
92                 mode = get_ir_mode(mode_bytes);
93                 for (; offset + mode_bytes <= size; offset += mode_bytes) {
94                         /* construct offset */
95                         ir_node *addr_const;
96                         ir_node *add;
97                         ir_node *load;
98                         ir_node *load_res;
99                         ir_node *load_mem;
100                         ir_node *store;
101                         ir_node *store_mem;
102
103                         addr_const = new_r_Const_long(irg, block, mode_Iu, offset);
104                         add        = new_r_Add(irg, block, addr_src, addr_const, addr_mode);
105
106                         load     = new_r_Load(irg, block, mem, add, mode);
107                         load_res = new_r_Proj(irg, block, load, mode, pn_Load_res);
108                         load_mem = new_r_Proj(irg, block, load, mode_M, pn_Load_M);
109
110                         addr_const = new_r_Const_long(irg, block, mode_Iu, offset);
111                         add        = new_r_Add(irg, block, addr_dst, addr_const, addr_mode);
112
113                         store     = new_r_Store(irg, block, mem, add, load_res);
114                         store_mem = new_r_Proj(irg, block, store, mode_M, pn_Store_M);
115
116                         mem = store_mem;
117                 }
118
119                 mode_bytes /= 2;
120         }
121
122         turn_into_tuple(irn, pn_CopyB_max);
123         set_Tuple_pred(irn, pn_CopyB_M_regular, mem);
124         set_Tuple_pred(irn, pn_CopyB_X_regular, get_irg_bad(irg));
125         set_Tuple_pred(irn, pn_CopyB_X_except,  get_irg_bad(irg));
126         set_Tuple_pred(irn, pn_CopyB_M_except,  get_irg_bad(irg));
127 }
128
129 /**
130  * Post-Walker: find small CopyB nodes.
131  */
132 static void find_copyb_nodes(ir_node *irn, void *ctx) {
133         walk_env_t *env = ctx;
134         ir_type    *tp;
135         unsigned   size;
136         entry_t    *entry;
137
138         if (is_Proj(irn)) {
139                 ir_node *pred = get_Proj_pred(irn);
140
141                 if (is_CopyB(pred) && get_Proj_proj(irn) != pn_CopyB_M_regular) {
142                         /* found an exception Proj: remove it from the list again */
143                         entry = get_irn_link(pred);
144                         list_del(&entry->list);
145                 }
146                 return;
147         }
148
149         if (! is_CopyB(irn))
150                 return;
151
152         tp = get_CopyB_type(irn);
153         if (get_type_state(tp) != layout_fixed)
154                 return;
155
156         size = get_type_size_bytes(tp);
157         if (size > env->max_size)
158                 return;
159
160         /* ok, link it in */
161         entry = obstack_alloc(&env->obst, sizeof(*entry));
162         entry->copyb = irn;
163         INIT_LIST_HEAD(&entry->list);
164         set_irn_link(irn, entry);
165         list_add_tail(&entry->list, &env->list);
166 }
167
168 void lower_CopyB(ir_graph *irg, unsigned max_size, unsigned native_mode_bytes)
169 {
170         walk_env_t env;
171         entry_t  *entry;
172         ir_graph *rem = current_ir_graph;
173
174         current_ir_graph = irg;
175
176         obstack_init(&env.obst);
177         env.max_size = max_size;
178         INIT_LIST_HEAD(&env.list);
179         irg_walk_graph(irg, NULL, find_copyb_nodes, &env);
180
181         list_for_each_entry(entry_t, entry, &env.list, list) {
182                 lower_copyb_nodes(entry->copyb, native_mode_bytes);
183         }
184
185         obstack_free(&env.obst, NULL);
186         current_ir_graph = rem;
187 }