]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/tree-ssa-address.c
gcc/
[thirdparty/gcc.git] / gcc / tree-ssa-address.c
1 /* Memory address lowering and addressing mode selection.
2 Copyright (C) 2004, 2006 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING. If not, write to the Free
18 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301, USA. */
20
21 /* Utility functions for manipulation with TARGET_MEM_REFs -- tree expressions
22 that directly map to addressing modes of the target. */
23
24 #include "config.h"
25 #include "system.h"
26 #include "coretypes.h"
27 #include "tm.h"
28 #include "tree.h"
29 #include "rtl.h"
30 #include "tm_p.h"
31 #include "hard-reg-set.h"
32 #include "basic-block.h"
33 #include "output.h"
34 #include "diagnostic.h"
35 #include "tree-flow.h"
36 #include "tree-dump.h"
37 #include "tree-pass.h"
38 #include "timevar.h"
39 #include "flags.h"
40 #include "tree-inline.h"
41 #include "insn-config.h"
42 #include "recog.h"
43 #include "expr.h"
44 #include "ggc.h"
45
46 /* TODO -- handling of symbols (according to Richard Hendersons
47 comments, http://gcc.gnu.org/ml/gcc-patches/2005-04/msg00949.html):
48
49 There are at least 5 different kinds of symbols that we can run up against:
50
51 (1) binds_local_p, small data area.
52 (2) binds_local_p, eg local statics
53 (3) !binds_local_p, eg global variables
54 (4) thread local, local_exec
55 (5) thread local, !local_exec
56
57 Now, (1) won't appear often in an array context, but it certainly can.
58 All you have to do is set -GN high enough, or explicitly mark any
59 random object __attribute__((section (".sdata"))).
60
61 All of these affect whether or not a symbol is in fact a valid address.
62 The only one tested here is (3). And that result may very well
63 be incorrect for (4) or (5).
64
65 An incorrect result here does not cause incorrect results out the
66 back end, because the expander in expr.c validizes the address. However
67 it would be nice to improve the handling here in order to produce more
68 precise results. */
69
70 /* A "template" for memory address, used to determine whether the address is
71 valid for mode. */
72
73 struct mem_addr_template GTY (())
74 {
75 rtx ref; /* The template. */
76 rtx * GTY ((skip)) step_p; /* The point in template where the step should be
77 filled in. */
78 rtx * GTY ((skip)) off_p; /* The point in template where the offset should
79 be filled in. */
80 };
81
82 /* The templates. Each of the five bits of the index corresponds to one
83 component of TARGET_MEM_REF being present, see TEMPL_IDX. */
84
85 static GTY (()) struct mem_addr_template templates[32];
86
87 #define TEMPL_IDX(SYMBOL, BASE, INDEX, STEP, OFFSET) \
88 (((SYMBOL != 0) << 4) \
89 | ((BASE != 0) << 3) \
90 | ((INDEX != 0) << 2) \
91 | ((STEP != 0) << 1) \
92 | (OFFSET != 0))
93
94 /* Stores address for memory reference with parameters SYMBOL, BASE, INDEX,
95 STEP and OFFSET to *ADDR. Stores pointers to where step is placed to
96 *STEP_P and offset to *OFFSET_P. */
97
98 static void
99 gen_addr_rtx (rtx symbol, rtx base, rtx index, rtx step, rtx offset,
100 rtx *addr, rtx **step_p, rtx **offset_p)
101 {
102 rtx act_elem;
103
104 *addr = NULL_RTX;
105 if (step_p)
106 *step_p = NULL;
107 if (offset_p)
108 *offset_p = NULL;
109
110 if (index)
111 {
112 act_elem = index;
113 if (step)
114 {
115 act_elem = gen_rtx_MULT (Pmode, act_elem, step);
116
117 if (step_p)
118 *step_p = &XEXP (act_elem, 1);
119 }
120
121 *addr = act_elem;
122 }
123
124 if (base)
125 {
126 if (*addr)
127 *addr = gen_rtx_PLUS (Pmode, *addr, base);
128 else
129 *addr = base;
130 }
131
132 if (symbol)
133 {
134 act_elem = symbol;
135 if (offset)
136 {
137 act_elem = gen_rtx_PLUS (Pmode, act_elem, offset);
138
139 if (offset_p)
140 *offset_p = &XEXP (act_elem, 1);
141
142 if (GET_CODE (symbol) == SYMBOL_REF
143 || GET_CODE (symbol) == LABEL_REF
144 || GET_CODE (symbol) == CONST)
145 act_elem = gen_rtx_CONST (Pmode, act_elem);
146 }
147
148 if (*addr)
149 *addr = gen_rtx_PLUS (Pmode, *addr, act_elem);
150 else
151 *addr = act_elem;
152 }
153 else if (offset)
154 {
155 if (*addr)
156 {
157 *addr = gen_rtx_PLUS (Pmode, *addr, offset);
158 if (offset_p)
159 *offset_p = &XEXP (*addr, 1);
160 }
161 else
162 {
163 *addr = offset;
164 if (offset_p)
165 *offset_p = addr;
166 }
167 }
168
169 if (!*addr)
170 *addr = const0_rtx;
171 }
172
173 /* Returns address for TARGET_MEM_REF with parameters given by ADDR.
174 If REALLY_EXPAND is false, just make fake registers instead
175 of really expanding the operands, and perform the expansion in-place
176 by using one of the "templates". */
177
178 rtx
179 addr_for_mem_ref (struct mem_address *addr, bool really_expand)
180 {
181 rtx address, sym, bse, idx, st, off;
182 static bool templates_initialized = false;
183 struct mem_addr_template *templ;
184
185 if (addr->step && !integer_onep (addr->step))
186 st = immed_double_const (TREE_INT_CST_LOW (addr->step),
187 TREE_INT_CST_HIGH (addr->step), Pmode);
188 else
189 st = NULL_RTX;
190
191 if (addr->offset && !integer_zerop (addr->offset))
192 off = immed_double_const (TREE_INT_CST_LOW (addr->offset),
193 TREE_INT_CST_HIGH (addr->offset), Pmode);
194 else
195 off = NULL_RTX;
196
197 if (!really_expand)
198 {
199 /* Reuse the templates for addresses, so that we do not waste memory. */
200 if (!templates_initialized)
201 {
202 unsigned i;
203
204 templates_initialized = true;
205 sym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup ("test_symbol"));
206 bse = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 1);
207 idx = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 2);
208
209 for (i = 0; i < 32; i++)
210 gen_addr_rtx ((i & 16 ? sym : NULL_RTX),
211 (i & 8 ? bse : NULL_RTX),
212 (i & 4 ? idx : NULL_RTX),
213 (i & 2 ? const0_rtx : NULL_RTX),
214 (i & 1 ? const0_rtx : NULL_RTX),
215 &templates[i].ref,
216 &templates[i].step_p,
217 &templates[i].off_p);
218 }
219
220 templ = templates + TEMPL_IDX (addr->symbol, addr->base, addr->index,
221 st, off);
222 if (st)
223 *templ->step_p = st;
224 if (off)
225 *templ->off_p = off;
226
227 return templ->ref;
228 }
229
230 /* Otherwise really expand the expressions. */
231 sym = (addr->symbol
232 ? expand_expr (build_addr (addr->symbol, current_function_decl),
233 NULL_RTX, Pmode, EXPAND_NORMAL)
234 : NULL_RTX);
235 bse = (addr->base
236 ? expand_expr (addr->base, NULL_RTX, Pmode, EXPAND_NORMAL)
237 : NULL_RTX);
238 idx = (addr->index
239 ? expand_expr (addr->index, NULL_RTX, Pmode, EXPAND_NORMAL)
240 : NULL_RTX);
241
242 gen_addr_rtx (sym, bse, idx, st, off, &address, NULL, NULL);
243 return address;
244 }
245
246 /* Returns address of MEM_REF in TYPE. */
247
248 tree
249 tree_mem_ref_addr (tree type, tree mem_ref)
250 {
251 tree addr = NULL_TREE;
252 tree act_elem;
253 tree step = TMR_STEP (mem_ref), offset = TMR_OFFSET (mem_ref);
254
255 act_elem = TMR_INDEX (mem_ref);
256 if (act_elem)
257 {
258 act_elem = fold_convert (type, act_elem);
259
260 if (step)
261 act_elem = fold_build2 (MULT_EXPR, type, act_elem,
262 fold_convert (type, step));
263 addr = act_elem;
264 }
265
266 act_elem = TMR_BASE (mem_ref);
267 if (act_elem)
268 {
269 act_elem = fold_convert (type, act_elem);
270
271 if (addr)
272 addr = fold_build2 (PLUS_EXPR, type, addr, act_elem);
273 else
274 addr = act_elem;
275 }
276
277 act_elem = TMR_SYMBOL (mem_ref);
278 if (act_elem)
279 {
280 act_elem = fold_convert (type, build_addr (act_elem,
281 current_function_decl));
282 if (addr)
283 addr = fold_build2 (PLUS_EXPR, type, addr, act_elem);
284 else
285 addr = act_elem;
286 }
287
288 if (!zero_p (offset))
289 {
290 act_elem = fold_convert (type, offset);
291
292 if (addr)
293 addr = fold_build2 (PLUS_EXPR, type, addr, act_elem);
294 else
295 addr = act_elem;
296 }
297
298 if (!addr)
299 addr = build_int_cst (type, 0);
300
301 return addr;
302 }
303
304 /* Returns true if a memory reference in MODE and with parameters given by
305 ADDR is valid on the current target. */
306
307 static bool
308 valid_mem_ref_p (enum machine_mode mode, struct mem_address *addr)
309 {
310 rtx address;
311
312 address = addr_for_mem_ref (addr, false);
313 if (!address)
314 return false;
315
316 return memory_address_p (mode, address);
317 }
318
319 /* Checks whether a TARGET_MEM_REF with type TYPE and parameters given by ADDR
320 is valid on the current target and if so, creates and returns the
321 TARGET_MEM_REF. */
322
323 static tree
324 create_mem_ref_raw (tree type, struct mem_address *addr)
325 {
326 if (!valid_mem_ref_p (TYPE_MODE (type), addr))
327 return NULL_TREE;
328
329 if (addr->step && integer_onep (addr->step))
330 addr->step = NULL_TREE;
331
332 if (addr->offset && zero_p (addr->offset))
333 addr->offset = NULL_TREE;
334
335 return build7 (TARGET_MEM_REF, type,
336 addr->symbol, addr->base, addr->index,
337 addr->step, addr->offset, NULL, NULL);
338 }
339
340 /* Returns true if OBJ is an object whose address is a link time constant. */
341
342 static bool
343 fixed_address_object_p (tree obj)
344 {
345 return (TREE_CODE (obj) == VAR_DECL
346 && (TREE_STATIC (obj)
347 || DECL_EXTERNAL (obj)));
348 }
349
350 /* Adds COEF * ELT to PARTS. TYPE is the type of the address we
351 construct. */
352
353 static void
354 add_to_parts (struct mem_address *parts, tree type, tree elt,
355 unsigned HOST_WIDE_INT coef)
356 {
357 /* Check if this is a symbol. */
358 if (!parts->symbol
359 && coef == 1
360 && TREE_CODE (elt) == ADDR_EXPR
361 && fixed_address_object_p (TREE_OPERAND (elt, 0)))
362 {
363 parts->symbol = TREE_OPERAND (elt, 0);
364 return;
365 }
366
367 if (coef != 1)
368 elt = fold_build2 (MULT_EXPR, type, fold_convert (type, elt),
369 build_int_cst_type (type, coef));
370 else
371 elt = fold_convert (type, elt);
372
373 if (!parts->base)
374 {
375 parts->base = elt;
376 return;
377 }
378
379 if (!parts->index)
380 {
381 parts->index = elt;
382 return;
383 }
384
385 /* Add ELT to base. */
386 parts->base = fold_build2 (PLUS_EXPR, type, parts->base, elt);
387 }
388
389 /* Finds the most expensive multiplication in ADDR that can be
390 expressed in an addressing mode and move the corresponding
391 element(s) to PARTS. TYPE is the type of the address we
392 construct. */
393
394 static void
395 most_expensive_mult_to_index (struct mem_address *parts, tree type,
396 struct affine_tree_combination *addr)
397 {
398 unsigned HOST_WIDE_INT best_mult = 0;
399 unsigned best_mult_cost = 0, acost;
400 tree mult_elt = NULL_TREE, elt;
401 unsigned i, j;
402
403 for (i = 0; i < addr->n; i++)
404 {
405 if (addr->coefs[i] == 1
406 || !multiplier_allowed_in_address_p (addr->coefs[i]))
407 continue;
408
409 acost = multiply_by_cost (addr->coefs[i], Pmode);
410
411 if (acost > best_mult_cost)
412 {
413 best_mult_cost = acost;
414 best_mult = addr->coefs[i];
415 }
416 }
417
418 if (!best_mult)
419 return;
420
421 for (i = j = 0; i < addr->n; i++)
422 {
423 if (addr->coefs[i] != best_mult)
424 {
425 addr->coefs[j] = addr->coefs[i];
426 addr->elts[j] = addr->elts[i];
427 j++;
428 continue;
429 }
430
431 elt = fold_convert (type, addr->elts[i]);
432 if (!mult_elt)
433 mult_elt = elt;
434 else
435 mult_elt = fold_build2 (PLUS_EXPR, type, mult_elt, elt);
436 }
437 addr->n = j;
438
439 parts->index = mult_elt;
440 parts->step = build_int_cst_type (type, best_mult);
441 }
442
443 /* Splits address ADDR into PARTS.
444
445 TODO -- be more clever about the distribution of the elements of ADDR
446 to PARTS. Some architectures do not support anything but single
447 register in address, possibly with a small integer offset; while
448 create_mem_ref will simplify the address to an acceptable shape
449 later, it would be a small bit more efficient to know that asking
450 for complicated addressing modes is useless. */
451
452 static void
453 addr_to_parts (struct affine_tree_combination *addr, tree type,
454 struct mem_address *parts)
455 {
456 unsigned i;
457
458 parts->symbol = NULL_TREE;
459 parts->base = NULL_TREE;
460 parts->index = NULL_TREE;
461 parts->step = NULL_TREE;
462
463 if (addr->offset)
464 parts->offset = build_int_cst_type (type, addr->offset);
465 else
466 parts->offset = NULL_TREE;
467
468 /* First move the most expensive feasible multiplication
469 to index. */
470 most_expensive_mult_to_index (parts, type, addr);
471
472 /* Then try to process the remaining elements. */
473 for (i = 0; i < addr->n; i++)
474 add_to_parts (parts, type, addr->elts[i], addr->coefs[i]);
475 if (addr->rest)
476 add_to_parts (parts, type, addr->rest, 1);
477 }
478
479 /* Force the PARTS to register. */
480
481 static void
482 gimplify_mem_ref_parts (block_stmt_iterator *bsi, struct mem_address *parts)
483 {
484 if (parts->base)
485 parts->base = force_gimple_operand_bsi (bsi, parts->base,
486 true, NULL_TREE);
487 if (parts->index)
488 parts->index = force_gimple_operand_bsi (bsi, parts->index,
489 true, NULL_TREE);
490 }
491
492 /* Creates and returns a TARGET_MEM_REF for address ADDR. If necessary
493 computations are emitted in front of BSI. TYPE is the mode
494 of created memory reference. */
495
496 tree
497 create_mem_ref (block_stmt_iterator *bsi, tree type,
498 struct affine_tree_combination *addr)
499 {
500 tree mem_ref, tmp;
501 tree addr_type = build_pointer_type (type);
502 struct mem_address parts;
503
504 addr_to_parts (addr, addr_type, &parts);
505 gimplify_mem_ref_parts (bsi, &parts);
506 mem_ref = create_mem_ref_raw (type, &parts);
507 if (mem_ref)
508 return mem_ref;
509
510 /* The expression is too complicated. Try making it simpler. */
511
512 if (parts.step && !integer_onep (parts.step))
513 {
514 /* Move the multiplication to index. */
515 gcc_assert (parts.index);
516 parts.index = force_gimple_operand_bsi (bsi,
517 build2 (MULT_EXPR, addr_type,
518 parts.index, parts.step),
519 true, NULL_TREE);
520 parts.step = NULL_TREE;
521
522 mem_ref = create_mem_ref_raw (type, &parts);
523 if (mem_ref)
524 return mem_ref;
525 }
526
527 if (parts.symbol)
528 {
529 tmp = build_addr (parts.symbol, current_function_decl);
530
531 /* Add the symbol to base, eventually forcing it to register. */
532 if (parts.base)
533 {
534 if (parts.index)
535 parts.base = force_gimple_operand_bsi (bsi,
536 build2 (PLUS_EXPR, addr_type,
537 parts.base, tmp),
538 true, NULL_TREE);
539 else
540 {
541 parts.index = parts.base;
542 parts.base = tmp;
543 }
544 }
545 else
546 parts.base = tmp;
547 parts.symbol = NULL_TREE;
548
549 mem_ref = create_mem_ref_raw (type, &parts);
550 if (mem_ref)
551 return mem_ref;
552 }
553
554 if (parts.base)
555 {
556 /* Add base to index. */
557 if (parts.index)
558 parts.index = force_gimple_operand_bsi (bsi,
559 build2 (PLUS_EXPR, addr_type,
560 parts.base,
561 parts.index),
562 true, NULL_TREE);
563 else
564 parts.index = parts.base;
565 parts.base = NULL_TREE;
566
567 mem_ref = create_mem_ref_raw (type, &parts);
568 if (mem_ref)
569 return mem_ref;
570 }
571
572 if (parts.offset && !integer_zerop (parts.offset))
573 {
574 /* Try adding offset to index. */
575 if (parts.index)
576 parts.index = force_gimple_operand_bsi (bsi,
577 build2 (PLUS_EXPR, addr_type,
578 parts.index,
579 parts.offset),
580 true, NULL_TREE);
581 else
582 parts.index = parts.offset, bsi;
583
584 parts.offset = NULL_TREE;
585
586 mem_ref = create_mem_ref_raw (type, &parts);
587 if (mem_ref)
588 return mem_ref;
589 }
590
591 /* Verify that the address is in the simplest possible shape
592 (only a register). If we cannot create such a memory reference,
593 something is really wrong. */
594 gcc_assert (parts.symbol == NULL_TREE);
595 gcc_assert (parts.base == NULL_TREE);
596 gcc_assert (!parts.step || integer_onep (parts.step));
597 gcc_assert (!parts.offset || integer_zerop (parts.offset));
598 gcc_unreachable ();
599 }
600
601 /* Copies components of the address from OP to ADDR. */
602
603 void
604 get_address_description (tree op, struct mem_address *addr)
605 {
606 addr->symbol = TMR_SYMBOL (op);
607 addr->base = TMR_BASE (op);
608 addr->index = TMR_INDEX (op);
609 addr->step = TMR_STEP (op);
610 addr->offset = TMR_OFFSET (op);
611 }
612
613 /* Copies the additional information attached to target_mem_ref FROM to TO. */
614
615 void
616 copy_mem_ref_info (tree to, tree from)
617 {
618 /* Copy the annotation, to preserve the aliasing information. */
619 TMR_TAG (to) = TMR_TAG (from);
620
621 /* And the info about the original reference. */
622 TMR_ORIGINAL (to) = TMR_ORIGINAL (from);
623 }
624
625 /* Move constants in target_mem_ref REF to offset. Returns the new target
626 mem ref if anything changes, NULL_TREE otherwise. */
627
628 tree
629 maybe_fold_tmr (tree ref)
630 {
631 struct mem_address addr;
632 bool changed = false;
633 tree ret, off;
634
635 get_address_description (ref, &addr);
636
637 if (addr.base && TREE_CODE (addr.base) == INTEGER_CST)
638 {
639 if (addr.offset)
640 addr.offset = fold_binary_to_constant (PLUS_EXPR, ptr_type_node,
641 addr.offset, addr.base);
642 else
643 addr.offset = addr.base;
644
645 addr.base = NULL_TREE;
646 changed = true;
647 }
648
649 if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
650 {
651 off = addr.index;
652 if (addr.step)
653 {
654 off = fold_binary_to_constant (MULT_EXPR, ptr_type_node,
655 off, addr.step);
656 addr.step = NULL_TREE;
657 }
658
659 if (addr.offset)
660 {
661 addr.offset = fold_binary_to_constant (PLUS_EXPR, ptr_type_node,
662 addr.offset, off);
663 }
664 else
665 addr.offset = off;
666
667 addr.index = NULL_TREE;
668 changed = true;
669 }
670
671 if (!changed)
672 return NULL_TREE;
673
674 ret = create_mem_ref_raw (TREE_TYPE (ref), &addr);
675 if (!ret)
676 return NULL_TREE;
677
678 copy_mem_ref_info (ret, ref);
679 return ret;
680 }
681
682 /* Dump PARTS to FILE. */
683
684 extern void dump_mem_address (FILE *, struct mem_address *);
685 void
686 dump_mem_address (FILE *file, struct mem_address *parts)
687 {
688 if (parts->symbol)
689 {
690 fprintf (file, "symbol: ");
691 print_generic_expr (file, parts->symbol, TDF_SLIM);
692 fprintf (file, "\n");
693 }
694 if (parts->base)
695 {
696 fprintf (file, "base: ");
697 print_generic_expr (file, parts->base, TDF_SLIM);
698 fprintf (file, "\n");
699 }
700 if (parts->index)
701 {
702 fprintf (file, "index: ");
703 print_generic_expr (file, parts->index, TDF_SLIM);
704 fprintf (file, "\n");
705 }
706 if (parts->step)
707 {
708 fprintf (file, "step: ");
709 print_generic_expr (file, parts->step, TDF_SLIM);
710 fprintf (file, "\n");
711 }
712 if (parts->offset)
713 {
714 fprintf (file, "offset: ");
715 print_generic_expr (file, parts->offset, TDF_SLIM);
716 fprintf (file, "\n");
717 }
718 }
719
720 #include "gt-tree-ssa-address.h"