- never use (broken) sequential load/store in abi
[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$
26  */
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "ia32_address_mode.h"
32 #include "ia32_transform.h"
33
34 #include "irtypes.h"
35 #include "irnode_t.h"
36 #include "irprintf.h"
37 #include "error.h"
38 #include "iredges_t.h"
39 #include "irgwalk.h"
40
41 #include "../benode_t.h"
42
43 #define AGGRESSIVE_AM
44
45 /* gas/ld don't support negative symconsts :-( */
46 #undef SUPPORT_NEGATIVE_SYMCONSTS
47
48 static bitset_t *non_address_mode_nodes;
49
50 static int do_is_immediate(const ir_node *node, int *symconsts, int negate)
51 {
52         ir_node *left;
53         ir_node *right;
54
55         switch(get_irn_opcode(node)) {
56         case iro_Const:
57                 if(!tarval_is_long(get_Const_tarval(node))) {
58 #ifdef DEBUG_libfirm
59                         ir_fprintf(stderr, "Optimisation warning tarval of %+F is not a "
60                                    "long.");
61 #endif
62                         return 0;
63                 }
64                 return 1;
65         case iro_SymConst:
66 #ifndef SUPPORT_NEGATIVE_SYMCONSTS
67                 /* unfortunately the assembler/linker doesn't support -symconst */
68                 if(negate)
69                         return 0;
70 #endif
71
72                 if(get_SymConst_kind(node) != symconst_addr_ent)
73                         return 0;
74                 (*symconsts)++;
75                 if(*symconsts > 1)
76                         return 0;
77
78                 return 1;
79         case iro_Add:
80         case iro_Sub:
81                 if(bitset_is_set(non_address_mode_nodes, get_irn_idx(node)))
82                         return 0;
83
84                 left  = get_binop_left(node);
85                 right = get_binop_right(node);
86                 if(!do_is_immediate(left, symconsts, negate))
87                         return 0;
88                 if(!do_is_immediate(right, symconsts, is_Sub(node) ? !negate : negate))
89                         return 0;
90
91                 return 1;
92         default:
93                 break;
94         }
95
96         return 0;
97 }
98
99 static int is_immediate_simple(const ir_node *node)
100 {
101         int symconsts = 0;
102         return do_is_immediate(node, &symconsts, 0);
103 }
104
105 static int is_immediate(ia32_address_t *addr, const ir_node *node, int negate)
106 {
107         int symconsts = 0;
108         if(addr->symconst_ent != NULL)
109                 symconsts = 1;
110
111         return do_is_immediate(node, &symconsts, negate);
112 }
113
114 static void eat_immediate(ia32_address_t *addr, ir_node *node, int negate)
115 {
116         tarval  *tv;
117         ir_node *left;
118         ir_node *right;
119
120         switch(get_irn_opcode(node)) {
121         case iro_Const:
122                 tv = get_Const_tarval(node);
123                 long val = get_tarval_long(tv);
124                 if(negate) {
125                         addr->offset -= val;
126                 } else {
127                         addr->offset += val;
128                 }
129                 break;
130         case iro_SymConst:
131                 if(addr->symconst_ent != NULL) {
132                         panic("Internal error: more than 1 symconst in address "
133                               "calculation");
134                 }
135                 addr->symconst_ent  = get_SymConst_entity(node);
136 #ifndef SUPPORT_NEGATIVE_SYMCONSTS
137                 assert(!negate);
138 #endif
139                 addr->symconst_sign = negate;
140                 break;
141         case iro_Add:
142                 assert(!bitset_is_set(non_address_mode_nodes, get_irn_idx(node)));
143                 left  = get_Add_left(node);
144                 right = get_Add_right(node);
145                 eat_immediate(addr, left, negate);
146                 eat_immediate(addr, right, negate);
147                 break;
148         case iro_Sub:
149                 assert(!bitset_is_set(non_address_mode_nodes, get_irn_idx(node)));
150                 left  = get_Sub_left(node);
151                 right = get_Sub_right(node);
152                 eat_immediate(addr, left, negate);
153                 eat_immediate(addr, right, !negate);
154                 break;
155         default:
156                 panic("Internal error in immediate address calculation");
157         }
158 }
159
160 static ir_node *eat_immediates(ia32_address_t *addr, ir_node *node, int force)
161 {
162         if(!force && bitset_is_set(non_address_mode_nodes, get_irn_idx(node)))
163                 return node;
164
165         if(is_Add(node)) {
166                 ir_node *left  = get_Add_left(node);
167                 ir_node *right = get_Add_right(node);
168
169                 if(is_immediate(addr, left, 0)) {
170                         eat_immediate(addr, left, 0);
171                         return eat_immediates(addr, right, 0);
172                 }
173                 if(is_immediate(addr, right, 0)) {
174                         eat_immediate(addr, right, 0);
175                         return eat_immediates(addr, left, 0);
176                 }
177         } else if(is_Sub(node)) {
178                 ir_node *left  = get_Sub_left(node);
179                 ir_node *right = get_Sub_right(node);
180
181                 if(is_immediate(addr, right, 1)) {
182                         eat_immediate(addr, right, 1);
183                         return eat_immediates(addr, left, 0);
184                 }
185         }
186
187         return node;
188 }
189
190 static int eat_shl(ia32_address_t *addr, ir_node *node)
191 {
192         ir_node *right = get_Shl_right(node);
193         tarval  *tv;
194         long     val;
195
196         /* we can only eat a shl if we don't have a scale or index set */
197         if(addr->scale != 0 || addr->index != NULL)
198                 return 0;
199
200         /* we can use shl with 1, 2 or 3 shift */
201         if(!is_Const(right))
202                 return 0;
203         tv = get_Const_tarval(right);
204         if(!tarval_is_long(tv))
205                 return 0;
206         val = get_tarval_long(tv);
207         if(val < 0 || val > 3)
208                 return 0;
209         if(val == 0) {
210                 ir_fprintf(stderr, "Optimisation warning: unoptimized Shl(,0) found\n");
211         }
212         if(bitset_is_set(non_address_mode_nodes, get_irn_idx(node)))
213                 return 0;
214
215 #ifndef AGGRESSIVE_AM
216         if(get_irn_n_edges(node) > 1)
217                 return 0;
218 #endif
219
220         addr->scale = val;
221         addr->index = eat_immediates(addr, get_Shl_left(node), 0);
222         return 1;
223 }
224
225 void ia32_create_address_mode(ia32_address_t *addr, ir_node *node, int force)
226 {
227         int      res = 0;
228         ir_node *eat_imms;
229
230         if(is_immediate(addr, node, 0)) {
231                 eat_immediate(addr, node, 0);
232                 return;
233         }
234
235 #ifndef AGGRESSIVE_AM
236         if(!force && get_irn_n_edges(node) > 1) {
237                 addr->base = node;
238                 return;
239         }
240 #endif
241
242         if(!force && bitset_is_set(non_address_mode_nodes, get_irn_idx(node))) {
243                 addr->base = node;
244                 return;
245         }
246
247         eat_imms = eat_immediates(addr, node, force);
248         if(eat_imms != node) {
249                 res  = 1;
250                 node = eat_imms;
251 #ifndef AGGRESSIVE_AM
252                 if(get_irn_n_edges(node) > 1) {
253                         addr->base = node;
254                         return;
255                 }
256 #endif
257                 if(bitset_is_set(non_address_mode_nodes, get_irn_idx(node))) {
258                         addr->base = node;
259                         return;
260                 }
261         }
262
263         /* starting point Add, Sub or Shl, FrameAddr */
264         if(is_Shl(node)) {
265                 if(eat_shl(addr, node))
266                         return;
267         } else if(is_immediate(addr, node, 0)) {
268                 eat_immediate(addr, node, 0);
269                 return;
270         } else if(be_is_FrameAddr(node)) {
271                 assert(addr->base == NULL);
272                 assert(addr->frame_entity == NULL);
273                 addr->base         = be_get_FrameAddr_frame(node);
274                 addr->use_frame    = 1;
275                 addr->frame_entity = be_get_FrameAddr_entity(node);
276                 return;
277         } else if(is_Add(node)) {
278                 ir_node *left  = get_Add_left(node);
279                 ir_node *right = get_Add_right(node);
280                 assert(force || !is_immediate(addr, left, 0));
281                 assert(force || !is_immediate(addr, right, 0));
282
283                 if(is_Shl(left) && eat_shl(addr, left)) {
284                         left = NULL;
285                 } else if(is_Shl(right) && eat_shl(addr, right)) {
286                         right = NULL;
287                 }
288                 if(left != NULL && be_is_FrameAddr(left)
289                                 && !bitset_is_set(non_address_mode_nodes, get_irn_idx(left))) {
290                         assert(addr->base == NULL);
291                         assert(addr->frame_entity == NULL);
292                         addr->base         = be_get_FrameAddr_frame(left);
293                         addr->use_frame    = 1;
294                         addr->frame_entity = be_get_FrameAddr_entity(left);
295                         left               = NULL;
296                 } else if(right != NULL && be_is_FrameAddr(right)
297                                 && !bitset_is_set(non_address_mode_nodes, get_irn_idx(right))) {
298                         assert(addr->base == NULL);
299                         assert(addr->frame_entity == NULL);
300                         addr->base         = be_get_FrameAddr_frame(right);
301                         addr->use_frame    = 1;
302                         addr->frame_entity = be_get_FrameAddr_entity(right);
303                         right              = NULL;
304                 }
305
306                 if(left != NULL) {
307                         if(addr->base != NULL) {
308                                 assert(addr->index == NULL && addr->scale == 0);
309                                 assert(right == NULL);
310                                 addr->index = left;
311                         } else {
312                                 addr->base = left;
313                         }
314                 }
315                 if(right != NULL) {
316                         if(addr->base == NULL) {
317                                 addr->base = right;
318                         } else {
319                                 assert(addr->index == NULL && addr->scale == 0);
320                                 addr->index = right;
321                         }
322                 }
323                 return;
324         }
325
326         addr->base = node;
327 }
328
329
330
331 static void mark_non_address_nodes(ir_node *node, void *env)
332 {
333         int i, arity;
334         ir_node *ptr;
335         ir_node *mem;
336         ir_node *val;
337         ir_node *left;
338         ir_node *right;
339         (void) env;
340
341         switch(get_irn_opcode(node)) {
342         case iro_Load:
343                 ptr = get_Load_ptr(node);
344                 mem = get_Load_mem(node);
345
346                 bitset_set(non_address_mode_nodes, get_irn_idx(mem));
347                 break;
348
349         case iro_Store:
350                 val = get_Store_value(node);
351                 ptr = get_Store_ptr(node);
352                 mem = get_Store_mem(node);
353
354                 bitset_set(non_address_mode_nodes, get_irn_idx(val));
355                 bitset_set(non_address_mode_nodes, get_irn_idx(mem));
356                 break;
357
358         case iro_Add:
359                 left  = get_Add_left(node);
360                 right = get_Add_right(node);
361                 /* if we can do source address mode then we will never fold the add
362                  * into address mode */
363                 if(is_immediate_simple(right) ||
364                          (!use_source_address_mode(get_nodes_block(node), left, right)
365                      && !use_source_address_mode(get_nodes_block(node), right, left))) {
366                     break;
367                 }
368                 bitset_set(non_address_mode_nodes, get_irn_idx(node));
369                 /* fallthrough */
370
371         default:
372                 arity = get_irn_arity(node);
373
374                 for(i = 0; i < arity; ++i) {
375                         ir_node *in = get_irn_n(node, i);
376                         bitset_set(non_address_mode_nodes, get_irn_idx(in));
377                 }
378                 break;
379         }
380 }
381
382 void calculate_non_address_mode_nodes(ir_graph *irg)
383 {
384         non_address_mode_nodes = bitset_malloc(get_irg_last_idx(irg));
385
386         irg_walk_graph(irg, NULL, mark_non_address_nodes, NULL);
387 }
388
389 void free_non_address_mode_nodes(void)
390 {
391         bitset_free(non_address_mode_nodes);
392 }