72f204a6ced2cc8d7b183e25e2347358866381fc
[libfirm] / ir / be / ia32 / ia32_address_mode.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       This file contains functions for matching firm graphs for
23  *              nodes that can be used as addressmode for x86 commands
24  * @author      Matthias Braun
25  * @version     $Id: ia32_transform.c 15462 2007-08-03 16:50:59Z matze $
26  */
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "ia32_address_mode.h"
32
33 #include "irtypes.h"
34 #include "irnode_t.h"
35 #include "irprintf.h"
36 #include "error.h"
37 #include "iredges_t.h"
38
39 #include "../benode_t.h"
40
41 #undef AGGRESSIVE_AM
42
43 static int is_immediate_2(const ir_node *node, int *symconsts)
44 {
45         ir_node *left;
46         ir_node *right;
47
48         switch(get_irn_opcode(node)) {
49         case iro_Const:
50                 if(!tarval_is_long(get_Const_tarval(node))) {
51 #ifdef DEBUG_libfirm
52                         ir_fprintf(stderr, "Optimisation warning tarval of %+F is not a "
53                                    "long.");
54 #endif
55                         return 0;
56                 }
57                 return 1;
58         case iro_SymConst:
59                 if(get_SymConst_kind(node) != symconst_addr_ent)
60                         return 0;
61                 (*symconsts)++;
62                 if(*symconsts > 1)
63                         return 0;
64
65                 return 1;
66         case iro_Add:
67         case iro_Sub:
68                 left  = get_binop_left(node);
69                 right = get_binop_right(node);
70                 if(!is_immediate_2(left, symconsts))
71                         return 0;
72                 if(!is_immediate_2(right, symconsts))
73                         return 0;
74
75                 return 1;
76         default:
77                 break;
78         }
79
80         return 0;
81 }
82
83 static int is_immediate(ia32_address_t *addr, const ir_node *node)
84 {
85         int symconsts = 0;
86         if(addr->symconst_ent != NULL)
87                 symconsts = 1;
88
89         return is_immediate_2(node, &symconsts);
90 }
91
92 static void eat_immediate(ia32_address_t *addr, ir_node *node, int negate)
93 {
94         tarval  *tv;
95         ir_node *left;
96         ir_node *right;
97
98         switch(get_irn_opcode(node)) {
99         case iro_Const:
100                 tv = get_Const_tarval(node);
101                 if(negate) {
102                         addr->offset -= get_tarval_long(tv);
103                 } else {
104                         addr->offset += get_tarval_long(tv);
105                 }
106                 break;
107         case iro_SymConst:
108                 if(addr->symconst_ent != NULL) {
109                         panic("Internal error: more than 1 symconst in address "
110                               "calculation");
111                 }
112                 addr->symconst_ent  = get_SymConst_entity(node);
113                 addr->symconst_sign = negate;
114                 break;
115         case iro_Add:
116                 left  = get_Add_left(node);
117                 right = get_Add_right(node);
118                 eat_immediate(addr, left, negate);
119                 eat_immediate(addr, right, negate);
120                 break;
121         case iro_Sub:
122                 left  = get_Sub_left(node);
123                 right = get_Sub_right(node);
124                 eat_immediate(addr, left, negate);
125                 eat_immediate(addr, right, !negate);
126                 break;
127         default:
128                 panic("Internal error in immediate address calculation");
129         }
130 }
131
132 static ir_node *eat_immediates(ia32_address_t *addr, ir_node *node, int force)
133 {
134         if(is_Add(node)) {
135                 ir_node *left  = get_Add_left(node);
136                 ir_node *right = get_Add_right(node);
137
138 #if 0
139 #ifndef AGGRESSIVE_AM
140                 if(!force && get_irn_n_edges(node) > 1)
141                         return node;
142 #else
143                 (void) force;
144 #endif
145 #endif
146
147                 if(is_immediate(addr, left)) {
148                         eat_immediate(addr, left, 0);
149                         return eat_immediates(addr, right, 0);
150                 }
151                 if(is_immediate(addr, right)) {
152                         eat_immediate(addr, right, 0);
153                         return eat_immediates(addr, left, 0);
154                 }
155         } else if(is_Sub(node)) {
156                 ir_node *left  = get_Sub_left(node);
157                 ir_node *right = get_Sub_right(node);
158
159 #if 0
160 #ifndef AGGRESSIVE_AM
161                 if(!force && get_irn_n_edges(node) > 1)
162                         return node;
163 #endif
164 #endif
165
166                 if(is_immediate(addr, right)) {
167                         eat_immediate(addr, right, 1);
168                         return eat_immediates(addr, left, 0);
169                 }
170         }
171
172         return node;
173 }
174
175 static int eat_shl(ia32_address_t *addr, ir_node *node)
176 {
177         ir_node *right = get_Shl_right(node);
178         tarval  *tv;
179         long     val;
180
181         /* we can only eat a shl if we don't have a scale or index set */
182         if(addr->scale != 0 || addr->index != NULL)
183                 return 0;
184
185         /* we can use shl with 1, 2 or 3 shift */
186         if(!is_Const(right))
187                 return 0;
188         tv = get_Const_tarval(right);
189         if(!tarval_is_long(tv))
190                 return 0;
191         val = get_tarval_long(tv);
192         if(val < 0 || val > 3)
193                 return 0;
194         if(val == 0) {
195                 ir_fprintf(stderr, "Optimisation warning: unoptimized Shl(,0) found\n");
196         }
197
198 #ifndef AGGRESSIVE_AM
199         if(get_irn_n_edges(node) > 1)
200                 return 0;
201 #endif
202
203         addr->scale = val;
204         addr->index = eat_immediates(addr, get_Shl_left(node), 0);
205         return 1;
206 }
207
208 void ia32_create_address_mode(ia32_address_t *addr, ir_node *node, int force)
209 {
210         int      res = 0;
211         ir_node *eat_imms;
212
213         if(is_immediate(addr, node)) {
214                 eat_immediate(addr, node, 0);
215                 return;
216         }
217
218 #ifndef AGGRESSIVE_AM
219         if(!force && get_irn_n_edges(node) > 1) {
220                 addr->base = node;
221                 return;
222         }
223 #endif
224
225         eat_imms = eat_immediates(addr, node, force);
226         if(eat_imms != node) {
227                 res  = 1;
228                 node = eat_imms;
229 #ifndef AGGRESSIVE_AM
230                 if(get_irn_n_edges(node) > 1) {
231                         addr->base = node;
232                         return;
233                 }
234 #endif
235         }
236
237         /* starting point Add, Sub or Shl, FrameAddr */
238         if(is_Shl(node)) {
239                 if(eat_shl(addr, node))
240                         return;
241         } else if(is_immediate(addr, node)) {
242                 eat_immediate(addr, node, 0);
243                 return;
244         } else if(be_is_FrameAddr(node)) {
245                 assert(addr->base == NULL);
246                 assert(addr->frame_entity == NULL);
247                 addr->base         = be_get_FrameAddr_frame(node);
248                 addr->use_frame    = 1;
249                 addr->frame_entity = be_get_FrameAddr_entity(node);
250                 return;
251         } else if(is_Add(node)) {
252                 ir_node *left  = get_Add_left(node);
253                 ir_node *right = get_Add_right(node);
254                 assert(force || !is_immediate(addr, left));
255                 assert(force || !is_immediate(addr, right));
256
257                 if(is_Shl(left) && eat_shl(addr, left)) {
258                         left = NULL;
259                 } else if(is_Shl(right) && eat_shl(addr, right)) {
260                         right = NULL;
261                 }
262                 if(left != NULL && be_is_FrameAddr(left)) {
263                         assert(addr->base == NULL);
264                         assert(addr->frame_entity == NULL);
265                         addr->base         = be_get_FrameAddr_frame(left);
266                         addr->use_frame    = 1;
267                         addr->frame_entity = be_get_FrameAddr_entity(left);
268                         left               = NULL;
269                 } else if(right != NULL && be_is_FrameAddr(right)) {
270                         assert(addr->base == NULL);
271                         assert(addr->frame_entity == NULL);
272                         addr->base         = be_get_FrameAddr_frame(right);
273                         addr->use_frame    = 1;
274                         addr->frame_entity = be_get_FrameAddr_entity(right);
275                         right              = NULL;
276                 }
277
278                 if(left != NULL) {
279                         if(addr->base != NULL) {
280                                 assert(addr->index == NULL && addr->scale == 0);
281                                 assert(right == NULL);
282                                 addr->index = left;
283                         } else {
284                                 addr->base = left;
285                         }
286                 }
287                 if(right != NULL) {
288                         if(addr->base == NULL) {
289                                 addr->base = right;
290                         } else {
291                                 assert(addr->index == NULL && addr->scale == 0);
292                                 addr->index = right;
293                         }
294                 }
295                 return;
296         }
297
298         addr->base = node;
299 }
300
301
302 typedef struct mark_evn_t mark_evn_t;
303 struct mark_evn_t {
304         bitset_t *non_address_nodes;
305 };
306
307
308 static void mark_non_address_nodes(mark_evn_t *env, ir_node *node)
309 {
310         bitset_set(env->non_address_nodes, get_irn_idx(node));
311
312         if(is_Load(node)) {
313                 ir_node *ptr = get_Load_ptr(node);
314                 ir_node *mem = get_Load_mem(node);
315
316                 mark_non_address_nodes(env, mem);
317                 (void) ptr;
318         } else if(is_Store(node)) {
319                 ir_node *val = get_Store_value(node);
320                 ir_node *ptr = get_Store_ptr(node);
321                 ir_node *mem = get_Store_mem(node);
322
323                 mark_non_address_nodes(env, val);
324                 mark_non_address_nodes(env, mem);
325                 (void) ptr;
326         } else {
327                 int i;
328                 int arity = get_irn_arity(node);
329
330                 for(i = 0; i < arity; ++i) {
331                         ir_node *in = get_irn_n(node, i);
332                         mark_non_address_nodes(env, in);
333                 }
334         }
335 }