add doxygen comments
[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 /**
51  * Recursive worker for checking if a DAG with root node can be represented as a simple immediate,
52  *
53  * @param node       the node
54  * @param symconsts  number of symconsts found so far
55  * @param negate     if set, the immediate must be negated
56  *
57  * @return non-zero if the DAG represents an immediate, 0 else
58  */
59 static int do_is_immediate(const ir_node *node, int *symconsts, int negate)
60 {
61         ir_node *left;
62         ir_node *right;
63
64         switch (get_irn_opcode(node)) {
65         case iro_Const:
66                 /* Consts are typically immediates */
67                 if (!tarval_is_long(get_Const_tarval(node))) {
68 #ifdef DEBUG_libfirm
69                         ir_fprintf(stderr, "Optimisation warning tarval of %+F(%+F) is not "
70                                    "a long.\n", node, current_ir_graph);
71 #endif
72                         return 0;
73                 }
74                 return 1;
75         case iro_SymConst:
76                 /* the first SymConst of a DAG can be fold into an immediate */
77 #ifndef SUPPORT_NEGATIVE_SYMCONSTS
78                 /* unfortunately the assembler/linker doesn't support -symconst */
79                 if(negate)
80                         return 0;
81 #endif
82
83                 if(get_SymConst_kind(node) != symconst_addr_ent)
84                         return 0;
85                 (*symconsts)++;
86                 if(*symconsts > 1)
87                         return 0;
88
89                 return 1;
90         case iro_Add:
91         case iro_Sub:
92                 /* Add's and Sub's are typically supported as long as both operands are immediates */
93                 if(bitset_is_set(non_address_mode_nodes, get_irn_idx(node)))
94                         return 0;
95
96                 left  = get_binop_left(node);
97                 right = get_binop_right(node);
98                 if(!do_is_immediate(left, symconsts, negate))
99                         return 0;
100                 if(!do_is_immediate(right, symconsts, is_Sub(node) ? !negate : negate))
101                         return 0;
102
103                 return 1;
104         default:
105                 /* all other nodes are NO immediates */
106                 return 0;
107         }
108 }
109
110 /**
111  * Checks if a DAG with a single root node can be represented as a simple immediate.
112  *
113  * @param node  the node
114  *
115  * @return non-zero if the DAG represents an immediate, 0 else
116  */
117 static int is_immediate_simple(const ir_node *node) {
118         int symconsts = 0;
119         return do_is_immediate(node, &symconsts, 0);
120 }
121
122 /**
123  * Check if a DAG starting with root node can be folded into an address mode
124  * as an immediate.
125  *
126  * @param addr    the address mode data so far
127  * @param node    the node
128  * @param negate  if set, the immediate must be negated
129  */
130 static int is_immediate(ia32_address_t *addr, const ir_node *node, int negate)
131 {
132         int symconsts = (addr->symconst_ent != NULL);
133         return do_is_immediate(node, &symconsts, negate);
134 }
135
136 /**
137  * Place a DAG with root node into an address mode.
138  *
139  * @param addr    the address mode data so far
140  * @param node    the node
141  * @param negate  if set, the immediate must be negated
142  */
143 static void eat_immediate(ia32_address_t *addr, ir_node *node, int negate)
144 {
145         tarval  *tv;
146         ir_node *left;
147         ir_node *right;
148         long    val;
149
150         switch (get_irn_opcode(node)) {
151         case iro_Const:
152                 /* simply add the value to the offset */
153                 tv = get_Const_tarval(node);
154                 val = get_tarval_long(tv);
155                 if (negate) {
156                         addr->offset -= val;
157                 } else {
158                         addr->offset += val;
159                 }
160                 break;
161         case iro_SymConst:
162                 /* place the entity into the symconst */
163                 if (addr->symconst_ent != NULL) {
164                         panic("Internal error: more than 1 symconst in address "
165                               "calculation");
166                 }
167                 addr->symconst_ent  = get_SymConst_entity(node);
168 #ifndef SUPPORT_NEGATIVE_SYMCONSTS
169                 assert(!negate);
170 #endif
171                 addr->symconst_sign = negate;
172                 break;
173         case iro_Add:
174                 assert(!bitset_is_set(non_address_mode_nodes, get_irn_idx(node)));
175                 left  = get_Add_left(node);
176                 right = get_Add_right(node);
177                 eat_immediate(addr, left, negate);
178                 eat_immediate(addr, right, negate);
179                 break;
180         case iro_Sub:
181                 assert(!bitset_is_set(non_address_mode_nodes, get_irn_idx(node)));
182                 left  = get_Sub_left(node);
183                 right = get_Sub_right(node);
184                 eat_immediate(addr, left, negate);
185                 eat_immediate(addr, right, !negate);
186                 break;
187         default:
188                 panic("Internal error in immediate address calculation");
189         }
190 }
191
192 /**
193  * Place operands of node into an address mode.
194  *
195  * @param addr    the address mode data so far
196  * @param node    the node
197  * @param force   if set, ignore the marking of node as a non-address-mode node
198  *
199  * @return the folded node
200  */
201 static ir_node *eat_immediates(ia32_address_t *addr, ir_node *node, int force)
202 {
203         if(!force && bitset_is_set(non_address_mode_nodes, get_irn_idx(node)))
204                 return node;
205
206         if(is_Add(node)) {
207                 ir_node *left  = get_Add_left(node);
208                 ir_node *right = get_Add_right(node);
209
210                 if(is_immediate(addr, left, 0)) {
211                         eat_immediate(addr, left, 0);
212                         return eat_immediates(addr, right, 0);
213                 }
214                 if(is_immediate(addr, right, 0)) {
215                         eat_immediate(addr, right, 0);
216                         return eat_immediates(addr, left, 0);
217                 }
218         } else if(is_Sub(node)) {
219                 ir_node *left  = get_Sub_left(node);
220                 ir_node *right = get_Sub_right(node);
221
222                 if(is_immediate(addr, right, 1)) {
223                         eat_immediate(addr, right, 1);
224                         return eat_immediates(addr, left, 0);
225                 }
226         }
227
228         return node;
229 }
230
231 /**
232  * Try to place a Shl into an address mode.
233  *
234  * @param addr    the address mode data so far
235  * @param node   the node to place
236  *
237  * @return non-zero on success
238  */
239 static int eat_shl(ia32_address_t *addr, ir_node *node)
240 {
241         ir_node *right = get_Shl_right(node);
242         tarval  *tv;
243         long     val;
244
245         /* we can only eat a shl if we don't have a scale or index set yet */
246         if(addr->scale != 0 || addr->index != NULL)
247                 return 0;
248
249         /* we can use shl with 1, 2 or 3 shift */
250         if(!is_Const(right))
251                 return 0;
252         tv = get_Const_tarval(right);
253         if(!tarval_is_long(tv))
254                 return 0;
255         val = get_tarval_long(tv);
256         if(val < 0 || val > 3)
257                 return 0;
258         if(val == 0) {
259                 ir_fprintf(stderr, "Optimisation warning: unoptimized Shl(,0) found\n");
260         }
261         if(bitset_is_set(non_address_mode_nodes, get_irn_idx(node)))
262                 return 0;
263
264 #ifndef AGGRESSIVE_AM
265         if(get_irn_n_edges(node) > 1)
266                 return 0;
267 #endif
268
269         addr->scale = val;
270         addr->index = eat_immediates(addr, get_Shl_left(node), 0);
271         return 1;
272 }
273
274 /**
275  * Returns non-zero if a value of a given mode can be stored in GP registers.
276  */
277 static INLINE int mode_needs_gp_reg(ir_mode *mode) {
278         if(mode == mode_fpcw)
279                 return 0;
280         if(get_mode_size_bits(mode) > 32)
281                 return 0;
282         return mode_is_int(mode) || mode_is_reference(mode) || mode == mode_b;
283 }
284
285 /**
286  * Check, if a given node is a Down-Conv, ie. a integer Conv
287  * from a mode with a mode with more bits to a mode with lesser bits.
288  * Moreover, we return only true if the node has not more than 1 user.
289  *
290  * @param node   the node
291  * @return non-zero if node is a Down-Conv
292  */
293 static int is_downconv(const ir_node *node)
294 {
295         ir_mode *src_mode;
296         ir_mode *dest_mode;
297
298         if(!is_Conv(node))
299                 return 0;
300
301         /* we only want to skip the conv when we're the only user
302          * (not optimal but for now...)
303          */
304         if(get_irn_n_edges(node) > 1)
305                 return 0;
306
307         src_mode  = get_irn_mode(get_Conv_op(node));
308         dest_mode = get_irn_mode(node);
309         return mode_needs_gp_reg(src_mode)
310                 && mode_needs_gp_reg(dest_mode)
311                 && get_mode_size_bits(dest_mode) < get_mode_size_bits(src_mode);
312 }
313
314 /**
315  * Skip all Down-Conv's on a given node and return the resulting node.
316  */
317 static ir_node *skip_downconv(ir_node *node)
318 {
319         while(is_downconv(node))
320                 node = get_Conv_op(node);
321
322         return node;
323 }
324
325 /* Create an address mode for a given node. */
326 void ia32_create_address_mode(ia32_address_t *addr, ir_node *node, int force)
327 {
328         int      res = 0;
329         ir_node *eat_imms;
330
331         if(is_immediate(addr, node, 0)) {
332                 eat_immediate(addr, node, 0);
333                 return;
334         }
335
336 #ifndef AGGRESSIVE_AM
337         if(!force && get_irn_n_edges(node) > 1) {
338                 addr->base = node;
339                 return;
340         }
341 #endif
342
343         if(!force && bitset_is_set(non_address_mode_nodes, get_irn_idx(node))) {
344                 addr->base = node;
345                 return;
346         }
347
348         eat_imms = eat_immediates(addr, node, force);
349         if(eat_imms != node) {
350                 if(force) {
351                         eat_imms = skip_downconv(eat_imms);
352                 }
353
354                 res  = 1;
355                 node = eat_imms;
356 #ifndef AGGRESSIVE_AM
357                 if(get_irn_n_edges(node) > 1) {
358                         addr->base = node;
359                         return;
360                 }
361 #endif
362                 if(bitset_is_set(non_address_mode_nodes, get_irn_idx(node))) {
363                         addr->base = node;
364                         return;
365                 }
366         }
367
368         /* starting point Add, Sub or Shl, FrameAddr */
369         if(is_Shl(node)) {
370                 if(eat_shl(addr, node))
371                         return;
372         } else if(is_immediate(addr, node, 0)) {
373                 eat_immediate(addr, node, 0);
374                 return;
375         } else if(be_is_FrameAddr(node)) {
376                 assert(addr->base == NULL);
377                 assert(addr->frame_entity == NULL);
378                 addr->base         = be_get_FrameAddr_frame(node);
379                 addr->use_frame    = 1;
380                 addr->frame_entity = be_get_FrameAddr_entity(node);
381                 return;
382         } else if(is_Add(node)) {
383                 ir_node *left  = get_Add_left(node);
384                 ir_node *right = get_Add_right(node);
385
386                 if(force) {
387                         left  = skip_downconv(left);
388                         right = skip_downconv(right);
389                 }
390
391                 assert(force || !is_immediate(addr, left, 0));
392                 assert(force || !is_immediate(addr, right, 0));
393
394                 if(is_Shl(left) && eat_shl(addr, left)) {
395                         left = NULL;
396                 } else if(is_Shl(right) && eat_shl(addr, right)) {
397                         right = NULL;
398                 }
399                 if(left != NULL && be_is_FrameAddr(left)
400                                 && !bitset_is_set(non_address_mode_nodes, get_irn_idx(left))) {
401                         assert(addr->base == NULL);
402                         assert(addr->frame_entity == NULL);
403                         addr->base         = be_get_FrameAddr_frame(left);
404                         addr->use_frame    = 1;
405                         addr->frame_entity = be_get_FrameAddr_entity(left);
406                         left               = NULL;
407                 } else if(right != NULL && be_is_FrameAddr(right)
408                                 && !bitset_is_set(non_address_mode_nodes, get_irn_idx(right))) {
409                         assert(addr->base == NULL);
410                         assert(addr->frame_entity == NULL);
411                         addr->base         = be_get_FrameAddr_frame(right);
412                         addr->use_frame    = 1;
413                         addr->frame_entity = be_get_FrameAddr_entity(right);
414                         right              = NULL;
415                 }
416
417                 if(left != NULL) {
418                         if(addr->base != NULL) {
419                                 assert(addr->index == NULL && addr->scale == 0);
420                                 assert(right == NULL);
421                                 addr->index = left;
422                         } else {
423                                 addr->base = left;
424                         }
425                 }
426                 if(right != NULL) {
427                         if(addr->base == NULL) {
428                                 addr->base = right;
429                         } else {
430                                 assert(addr->index == NULL && addr->scale == 0);
431                                 addr->index = right;
432                         }
433                 }
434                 return;
435         }
436
437         addr->base = node;
438 }
439
440
441 /**
442  * Walker: mark those nodes that cannot be part of an address mode because
443  * there value must be access through an register
444  */
445 static void mark_non_address_nodes(ir_node *node, void *env)
446 {
447         int i, arity;
448         ir_node *ptr;
449         ir_node *mem;
450         ir_node *val;
451         ir_node *left;
452         ir_node *right;
453         (void) env;
454
455         switch(get_irn_opcode(node)) {
456         case iro_Load:
457                 ptr = get_Load_ptr(node);
458                 mem = get_Load_mem(node);
459
460                 bitset_set(non_address_mode_nodes, get_irn_idx(mem));
461                 break;
462
463         case iro_Store:
464                 val = get_Store_value(node);
465                 ptr = get_Store_ptr(node);
466                 mem = get_Store_mem(node);
467
468                 bitset_set(non_address_mode_nodes, get_irn_idx(val));
469                 bitset_set(non_address_mode_nodes, get_irn_idx(mem));
470                 break;
471
472         case iro_Add:
473                 left  = get_Add_left(node);
474                 right = get_Add_right(node);
475                 /* if we can do source address mode then we will never fold the add
476                  * into address mode */
477                 if(!mode_is_float(get_irn_mode(node)) && (is_immediate_simple(right) ||
478                          (!use_source_address_mode(get_nodes_block(node), left, right)
479                      && !use_source_address_mode(get_nodes_block(node), right, left))))
480                 {
481                     break;
482                 }
483                 bitset_set(non_address_mode_nodes, get_irn_idx(node));
484                 /* fallthrough */
485
486         default:
487                 arity = get_irn_arity(node);
488
489                 for(i = 0; i < arity; ++i) {
490                         ir_node *in = get_irn_n(node, i);
491                         bitset_set(non_address_mode_nodes, get_irn_idx(in));
492                 }
493                 break;
494         }
495 }
496
497 void calculate_non_address_mode_nodes(ir_graph *irg)
498 {
499         non_address_mode_nodes = bitset_malloc(get_irg_last_idx(irg));
500
501         irg_walk_graph(irg, NULL, mark_non_address_nodes, NULL);
502 }
503
504 void free_non_address_mode_nodes(void)
505 {
506         bitset_free(non_address_mode_nodes);
507 }