]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/tree-ssa-address.c
diagnostic.c: Don't include tm.h, tree.h, tm_p.h, langhooks.h or langhooks-def.h.
[thirdparty/gcc.git] / gcc / tree-ssa-address.c
1 /* Memory address lowering and addressing mode selection.
2 Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010
3 Free Software Foundation, Inc.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3, or (at your option) any
10 later version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
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 "tm_p.h"
30 #include "basic-block.h"
31 #include "output.h"
32 #include "diagnostic.h"
33 #include "tree-pretty-print.h"
34 #include "tree-flow.h"
35 #include "tree-dump.h"
36 #include "tree-pass.h"
37 #include "timevar.h"
38 #include "flags.h"
39 #include "tree-inline.h"
40 #include "tree-affine.h"
41
42 /* FIXME: We compute address costs using RTL. */
43 #include "insn-config.h"
44 #include "rtl.h"
45 #include "recog.h"
46 #include "expr.h"
47 #include "ggc.h"
48 #include "target.h"
49
50 /* TODO -- handling of symbols (according to Richard Hendersons
51 comments, http://gcc.gnu.org/ml/gcc-patches/2005-04/msg00949.html):
52
53 There are at least 5 different kinds of symbols that we can run up against:
54
55 (1) binds_local_p, small data area.
56 (2) binds_local_p, eg local statics
57 (3) !binds_local_p, eg global variables
58 (4) thread local, local_exec
59 (5) thread local, !local_exec
60
61 Now, (1) won't appear often in an array context, but it certainly can.
62 All you have to do is set -GN high enough, or explicitly mark any
63 random object __attribute__((section (".sdata"))).
64
65 All of these affect whether or not a symbol is in fact a valid address.
66 The only one tested here is (3). And that result may very well
67 be incorrect for (4) or (5).
68
69 An incorrect result here does not cause incorrect results out the
70 back end, because the expander in expr.c validizes the address. However
71 it would be nice to improve the handling here in order to produce more
72 precise results. */
73
74 /* A "template" for memory address, used to determine whether the address is
75 valid for mode. */
76
77 typedef struct GTY (()) mem_addr_template {
78 rtx ref; /* The template. */
79 rtx * GTY ((skip)) step_p; /* The point in template where the step should be
80 filled in. */
81 rtx * GTY ((skip)) off_p; /* The point in template where the offset should
82 be filled in. */
83 } mem_addr_template;
84
85 DEF_VEC_O (mem_addr_template);
86 DEF_VEC_ALLOC_O (mem_addr_template, gc);
87
88 /* The templates. Each of the low five bits of the index corresponds to one
89 component of TARGET_MEM_REF being present, while the high bits identify
90 the address space. See TEMPL_IDX. */
91
92 static GTY(()) VEC (mem_addr_template, gc) *mem_addr_template_list;
93
94 #define TEMPL_IDX(AS, SYMBOL, BASE, INDEX, STEP, OFFSET) \
95 (((int) (AS) << 5) \
96 | ((SYMBOL != 0) << 4) \
97 | ((BASE != 0) << 3) \
98 | ((INDEX != 0) << 2) \
99 | ((STEP != 0) << 1) \
100 | (OFFSET != 0))
101
102 /* Stores address for memory reference with parameters SYMBOL, BASE, INDEX,
103 STEP and OFFSET to *ADDR using address mode ADDRESS_MODE. Stores pointers
104 to where step is placed to *STEP_P and offset to *OFFSET_P. */
105
106 static void
107 gen_addr_rtx (enum machine_mode address_mode,
108 rtx symbol, rtx base, rtx index, rtx step, rtx offset,
109 rtx *addr, rtx **step_p, rtx **offset_p)
110 {
111 rtx act_elem;
112
113 *addr = NULL_RTX;
114 if (step_p)
115 *step_p = NULL;
116 if (offset_p)
117 *offset_p = NULL;
118
119 if (index)
120 {
121 act_elem = index;
122 if (step)
123 {
124 act_elem = gen_rtx_MULT (address_mode, act_elem, step);
125
126 if (step_p)
127 *step_p = &XEXP (act_elem, 1);
128 }
129
130 *addr = act_elem;
131 }
132
133 if (base)
134 {
135 if (*addr)
136 *addr = simplify_gen_binary (PLUS, address_mode, base, *addr);
137 else
138 *addr = base;
139 }
140
141 if (symbol)
142 {
143 act_elem = symbol;
144 if (offset)
145 {
146 act_elem = gen_rtx_PLUS (address_mode, act_elem, offset);
147
148 if (offset_p)
149 *offset_p = &XEXP (act_elem, 1);
150
151 if (GET_CODE (symbol) == SYMBOL_REF
152 || GET_CODE (symbol) == LABEL_REF
153 || GET_CODE (symbol) == CONST)
154 act_elem = gen_rtx_CONST (address_mode, act_elem);
155 }
156
157 if (*addr)
158 *addr = gen_rtx_PLUS (address_mode, *addr, act_elem);
159 else
160 *addr = act_elem;
161 }
162 else if (offset)
163 {
164 if (*addr)
165 {
166 *addr = gen_rtx_PLUS (address_mode, *addr, offset);
167 if (offset_p)
168 *offset_p = &XEXP (*addr, 1);
169 }
170 else
171 {
172 *addr = offset;
173 if (offset_p)
174 *offset_p = addr;
175 }
176 }
177
178 if (!*addr)
179 *addr = const0_rtx;
180 }
181
182 /* Returns address for TARGET_MEM_REF with parameters given by ADDR
183 in address space AS.
184 If REALLY_EXPAND is false, just make fake registers instead
185 of really expanding the operands, and perform the expansion in-place
186 by using one of the "templates". */
187
188 rtx
189 addr_for_mem_ref (struct mem_address *addr, addr_space_t as,
190 bool really_expand)
191 {
192 enum machine_mode address_mode = targetm.addr_space.address_mode (as);
193 rtx address, sym, bse, idx, st, off;
194 struct mem_addr_template *templ;
195
196 if (addr->step && !integer_onep (addr->step))
197 st = immed_double_int_const (tree_to_double_int (addr->step), address_mode);
198 else
199 st = NULL_RTX;
200
201 if (addr->offset && !integer_zerop (addr->offset))
202 off = immed_double_int_const (tree_to_double_int (addr->offset), address_mode);
203 else
204 off = NULL_RTX;
205
206 if (!really_expand)
207 {
208 unsigned int templ_index
209 = TEMPL_IDX (as, addr->symbol, addr->base, addr->index, st, off);
210
211 if (templ_index
212 >= VEC_length (mem_addr_template, mem_addr_template_list))
213 VEC_safe_grow_cleared (mem_addr_template, gc, mem_addr_template_list,
214 templ_index + 1);
215
216 /* Reuse the templates for addresses, so that we do not waste memory. */
217 templ = VEC_index (mem_addr_template, mem_addr_template_list, templ_index);
218 if (!templ->ref)
219 {
220 sym = (addr->symbol ?
221 gen_rtx_SYMBOL_REF (address_mode, ggc_strdup ("test_symbol"))
222 : NULL_RTX);
223 bse = (addr->base ?
224 gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 1)
225 : NULL_RTX);
226 idx = (addr->index ?
227 gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 2)
228 : NULL_RTX);
229
230 gen_addr_rtx (address_mode, sym, bse, idx,
231 st? const0_rtx : NULL_RTX,
232 off? const0_rtx : NULL_RTX,
233 &templ->ref,
234 &templ->step_p,
235 &templ->off_p);
236 }
237
238 if (st)
239 *templ->step_p = st;
240 if (off)
241 *templ->off_p = off;
242
243 return templ->ref;
244 }
245
246 /* Otherwise really expand the expressions. */
247 sym = (addr->symbol
248 ? expand_expr (build_addr (addr->symbol, current_function_decl),
249 NULL_RTX, address_mode, EXPAND_NORMAL)
250 : NULL_RTX);
251 bse = (addr->base
252 ? expand_expr (addr->base, NULL_RTX, address_mode, EXPAND_NORMAL)
253 : NULL_RTX);
254 idx = (addr->index
255 ? expand_expr (addr->index, NULL_RTX, address_mode, EXPAND_NORMAL)
256 : NULL_RTX);
257
258 gen_addr_rtx (address_mode, sym, bse, idx, st, off, &address, NULL, NULL);
259 return address;
260 }
261
262 /* Returns address of MEM_REF in TYPE. */
263
264 tree
265 tree_mem_ref_addr (tree type, tree mem_ref)
266 {
267 tree addr;
268 tree act_elem;
269 tree step = TMR_STEP (mem_ref), offset = TMR_OFFSET (mem_ref);
270 tree sym = TMR_SYMBOL (mem_ref), base = TMR_BASE (mem_ref);
271 tree addr_base = NULL_TREE, addr_off = NULL_TREE;
272
273 if (sym)
274 addr_base = fold_convert (type, build_addr (sym, current_function_decl));
275 else if (base && POINTER_TYPE_P (TREE_TYPE (base)))
276 {
277 addr_base = fold_convert (type, base);
278 base = NULL_TREE;
279 }
280
281 act_elem = TMR_INDEX (mem_ref);
282 if (act_elem)
283 {
284 if (step)
285 act_elem = fold_build2 (MULT_EXPR, sizetype, act_elem, step);
286 addr_off = act_elem;
287 }
288
289 act_elem = base;
290 if (act_elem)
291 {
292 if (addr_off)
293 addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, act_elem);
294 else
295 addr_off = act_elem;
296 }
297
298 if (offset && !integer_zerop (offset))
299 {
300 if (addr_off)
301 addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, offset);
302 else
303 addr_off = offset;
304 }
305
306 if (addr_off)
307 {
308 if (addr_base)
309 addr = fold_build2 (POINTER_PLUS_EXPR, type, addr_base, addr_off);
310 else
311 addr = fold_convert (type, addr_off);
312 }
313 else if (addr_base)
314 addr = addr_base;
315 else
316 addr = build_int_cst (type, 0);
317
318 return addr;
319 }
320
321 /* Returns true if a memory reference in MODE and with parameters given by
322 ADDR is valid on the current target. */
323
324 static bool
325 valid_mem_ref_p (enum machine_mode mode, addr_space_t as,
326 struct mem_address *addr)
327 {
328 rtx address;
329
330 address = addr_for_mem_ref (addr, as, false);
331 if (!address)
332 return false;
333
334 return memory_address_addr_space_p (mode, address, as);
335 }
336
337 /* Checks whether a TARGET_MEM_REF with type TYPE and parameters given by ADDR
338 is valid on the current target and if so, creates and returns the
339 TARGET_MEM_REF. */
340
341 static tree
342 create_mem_ref_raw (tree type, struct mem_address *addr)
343 {
344 if (!valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), addr))
345 return NULL_TREE;
346
347 if (addr->step && integer_onep (addr->step))
348 addr->step = NULL_TREE;
349
350 if (addr->offset && integer_zerop (addr->offset))
351 addr->offset = NULL_TREE;
352
353 return build6 (TARGET_MEM_REF, type,
354 addr->symbol, addr->base, addr->index,
355 addr->step, addr->offset, NULL);
356 }
357
358 /* Returns true if OBJ is an object whose address is a link time constant. */
359
360 static bool
361 fixed_address_object_p (tree obj)
362 {
363 return (TREE_CODE (obj) == VAR_DECL
364 && (TREE_STATIC (obj)
365 || DECL_EXTERNAL (obj))
366 && ! DECL_DLLIMPORT_P (obj));
367 }
368
369 /* If ADDR contains an address of object that is a link time constant,
370 move it to PARTS->symbol. */
371
372 static void
373 move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
374 {
375 unsigned i;
376 tree val = NULL_TREE;
377
378 for (i = 0; i < addr->n; i++)
379 {
380 if (!double_int_one_p (addr->elts[i].coef))
381 continue;
382
383 val = addr->elts[i].val;
384 if (TREE_CODE (val) == ADDR_EXPR
385 && fixed_address_object_p (TREE_OPERAND (val, 0)))
386 break;
387 }
388
389 if (i == addr->n)
390 return;
391
392 parts->symbol = TREE_OPERAND (val, 0);
393 aff_combination_remove_elt (addr, i);
394 }
395
396 /* If ADDR contains an instance of BASE_HINT, move it to PARTS->base. */
397
398 static void
399 move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
400 aff_tree *addr)
401 {
402 unsigned i;
403 tree val = NULL_TREE;
404 int qual;
405
406 for (i = 0; i < addr->n; i++)
407 {
408 if (!double_int_one_p (addr->elts[i].coef))
409 continue;
410
411 val = addr->elts[i].val;
412 if (operand_equal_p (val, base_hint, 0))
413 break;
414 }
415
416 if (i == addr->n)
417 return;
418
419 /* Cast value to appropriate pointer type. We cannot use a pointer
420 to TYPE directly, as the back-end will assume registers of pointer
421 type are aligned, and just the base itself may not actually be.
422 We use void pointer to the type's address space instead. */
423 qual = ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (type));
424 type = build_qualified_type (void_type_node, qual);
425 parts->base = fold_convert (build_pointer_type (type), val);
426 aff_combination_remove_elt (addr, i);
427 }
428
429 /* If ADDR contains an address of a dereferenced pointer, move it to
430 PARTS->base. */
431
432 static void
433 move_pointer_to_base (struct mem_address *parts, aff_tree *addr)
434 {
435 unsigned i;
436 tree val = NULL_TREE;
437
438 for (i = 0; i < addr->n; i++)
439 {
440 if (!double_int_one_p (addr->elts[i].coef))
441 continue;
442
443 val = addr->elts[i].val;
444 if (POINTER_TYPE_P (TREE_TYPE (val)))
445 break;
446 }
447
448 if (i == addr->n)
449 return;
450
451 parts->base = val;
452 aff_combination_remove_elt (addr, i);
453 }
454
455 /* Adds ELT to PARTS. */
456
457 static void
458 add_to_parts (struct mem_address *parts, tree elt)
459 {
460 tree type;
461
462 if (!parts->index)
463 {
464 parts->index = fold_convert (sizetype, elt);
465 return;
466 }
467
468 if (!parts->base)
469 {
470 parts->base = elt;
471 return;
472 }
473
474 /* Add ELT to base. */
475 type = TREE_TYPE (parts->base);
476 if (POINTER_TYPE_P (type))
477 parts->base = fold_build2 (POINTER_PLUS_EXPR, type,
478 parts->base,
479 fold_convert (sizetype, elt));
480 else
481 parts->base = fold_build2 (PLUS_EXPR, type,
482 parts->base, elt);
483 }
484
485 /* Finds the most expensive multiplication in ADDR that can be
486 expressed in an addressing mode and move the corresponding
487 element(s) to PARTS. */
488
489 static void
490 most_expensive_mult_to_index (tree type, struct mem_address *parts,
491 aff_tree *addr, bool speed)
492 {
493 addr_space_t as = TYPE_ADDR_SPACE (type);
494 enum machine_mode address_mode = targetm.addr_space.address_mode (as);
495 HOST_WIDE_INT coef;
496 double_int best_mult, amult, amult_neg;
497 unsigned best_mult_cost = 0, acost;
498 tree mult_elt = NULL_TREE, elt;
499 unsigned i, j;
500 enum tree_code op_code;
501
502 best_mult = double_int_zero;
503 for (i = 0; i < addr->n; i++)
504 {
505 if (!double_int_fits_in_shwi_p (addr->elts[i].coef))
506 continue;
507
508 coef = double_int_to_shwi (addr->elts[i].coef);
509 if (coef == 1
510 || !multiplier_allowed_in_address_p (coef, TYPE_MODE (type), as))
511 continue;
512
513 acost = multiply_by_cost (coef, address_mode, speed);
514
515 if (acost > best_mult_cost)
516 {
517 best_mult_cost = acost;
518 best_mult = addr->elts[i].coef;
519 }
520 }
521
522 if (!best_mult_cost)
523 return;
524
525 /* Collect elements multiplied by best_mult. */
526 for (i = j = 0; i < addr->n; i++)
527 {
528 amult = addr->elts[i].coef;
529 amult_neg = double_int_ext_for_comb (double_int_neg (amult), addr);
530
531 if (double_int_equal_p (amult, best_mult))
532 op_code = PLUS_EXPR;
533 else if (double_int_equal_p (amult_neg, best_mult))
534 op_code = MINUS_EXPR;
535 else
536 {
537 addr->elts[j] = addr->elts[i];
538 j++;
539 continue;
540 }
541
542 elt = fold_convert (sizetype, addr->elts[i].val);
543 if (mult_elt)
544 mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt);
545 else if (op_code == PLUS_EXPR)
546 mult_elt = elt;
547 else
548 mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt);
549 }
550 addr->n = j;
551
552 parts->index = mult_elt;
553 parts->step = double_int_to_tree (sizetype, best_mult);
554 }
555
556 /* Splits address ADDR for a memory access of type TYPE into PARTS.
557 If BASE_HINT is non-NULL, it specifies an SSA name to be used
558 preferentially as base of the reference.
559
560 TODO -- be more clever about the distribution of the elements of ADDR
561 to PARTS. Some architectures do not support anything but single
562 register in address, possibly with a small integer offset; while
563 create_mem_ref will simplify the address to an acceptable shape
564 later, it would be more efficient to know that asking for complicated
565 addressing modes is useless. */
566
567 static void
568 addr_to_parts (tree type, aff_tree *addr, tree base_hint,
569 struct mem_address *parts, bool speed)
570 {
571 tree part;
572 unsigned i;
573
574 parts->symbol = NULL_TREE;
575 parts->base = NULL_TREE;
576 parts->index = NULL_TREE;
577 parts->step = NULL_TREE;
578
579 if (!double_int_zero_p (addr->offset))
580 parts->offset = double_int_to_tree (sizetype, addr->offset);
581 else
582 parts->offset = NULL_TREE;
583
584 /* Try to find a symbol. */
585 move_fixed_address_to_symbol (parts, addr);
586
587 /* First move the most expensive feasible multiplication
588 to index. */
589 most_expensive_mult_to_index (type, parts, addr, speed);
590
591 /* Try to find a base of the reference. Since at the moment
592 there is no reliable way how to distinguish between pointer and its
593 offset, this is just a guess. */
594 if (!parts->symbol && base_hint)
595 move_hint_to_base (type, parts, base_hint, addr);
596 if (!parts->symbol && !parts->base)
597 move_pointer_to_base (parts, addr);
598
599 /* Then try to process the remaining elements. */
600 for (i = 0; i < addr->n; i++)
601 {
602 part = fold_convert (sizetype, addr->elts[i].val);
603 if (!double_int_one_p (addr->elts[i].coef))
604 part = fold_build2 (MULT_EXPR, sizetype, part,
605 double_int_to_tree (sizetype, addr->elts[i].coef));
606 add_to_parts (parts, part);
607 }
608 if (addr->rest)
609 add_to_parts (parts, fold_convert (sizetype, addr->rest));
610 }
611
612 /* Force the PARTS to register. */
613
614 static void
615 gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts)
616 {
617 if (parts->base)
618 parts->base = force_gimple_operand_gsi (gsi, parts->base,
619 true, NULL_TREE,
620 true, GSI_SAME_STMT);
621 if (parts->index)
622 parts->index = force_gimple_operand_gsi (gsi, parts->index,
623 true, NULL_TREE,
624 true, GSI_SAME_STMT);
625 }
626
627 /* Creates and returns a TARGET_MEM_REF for address ADDR. If necessary
628 computations are emitted in front of GSI. TYPE is the mode
629 of created memory reference. */
630
631 tree
632 create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
633 tree base_hint, bool speed)
634 {
635 tree mem_ref, tmp;
636 tree atype;
637 struct mem_address parts;
638
639 addr_to_parts (type, addr, base_hint, &parts, speed);
640 gimplify_mem_ref_parts (gsi, &parts);
641 mem_ref = create_mem_ref_raw (type, &parts);
642 if (mem_ref)
643 return mem_ref;
644
645 /* The expression is too complicated. Try making it simpler. */
646
647 if (parts.step && !integer_onep (parts.step))
648 {
649 /* Move the multiplication to index. */
650 gcc_assert (parts.index);
651 parts.index = force_gimple_operand_gsi (gsi,
652 fold_build2 (MULT_EXPR, sizetype,
653 parts.index, parts.step),
654 true, NULL_TREE, true, GSI_SAME_STMT);
655 parts.step = NULL_TREE;
656
657 mem_ref = create_mem_ref_raw (type, &parts);
658 if (mem_ref)
659 return mem_ref;
660 }
661
662 if (parts.symbol)
663 {
664 tmp = build_addr (parts.symbol, current_function_decl);
665 gcc_assert (is_gimple_val (tmp));
666
667 /* Add the symbol to base, eventually forcing it to register. */
668 if (parts.base)
669 {
670 gcc_assert (useless_type_conversion_p
671 (sizetype, TREE_TYPE (parts.base)));
672
673 if (parts.index)
674 {
675 atype = TREE_TYPE (tmp);
676 parts.base = force_gimple_operand_gsi (gsi,
677 fold_build2 (POINTER_PLUS_EXPR, atype,
678 tmp,
679 fold_convert (sizetype, parts.base)),
680 true, NULL_TREE, true, GSI_SAME_STMT);
681 }
682 else
683 {
684 parts.index = parts.base;
685 parts.base = tmp;
686 }
687 }
688 else
689 parts.base = tmp;
690 parts.symbol = NULL_TREE;
691
692 mem_ref = create_mem_ref_raw (type, &parts);
693 if (mem_ref)
694 return mem_ref;
695 }
696
697 if (parts.index)
698 {
699 /* Add index to base. */
700 if (parts.base)
701 {
702 atype = TREE_TYPE (parts.base);
703 parts.base = force_gimple_operand_gsi (gsi,
704 fold_build2 (POINTER_PLUS_EXPR, atype,
705 parts.base,
706 parts.index),
707 true, NULL_TREE, true, GSI_SAME_STMT);
708 }
709 else
710 parts.base = parts.index;
711 parts.index = NULL_TREE;
712
713 mem_ref = create_mem_ref_raw (type, &parts);
714 if (mem_ref)
715 return mem_ref;
716 }
717
718 if (parts.offset && !integer_zerop (parts.offset))
719 {
720 /* Try adding offset to base. */
721 if (parts.base)
722 {
723 atype = TREE_TYPE (parts.base);
724 parts.base = force_gimple_operand_gsi (gsi,
725 fold_build2 (POINTER_PLUS_EXPR, atype,
726 parts.base,
727 fold_convert (sizetype, parts.offset)),
728 true, NULL_TREE, true, GSI_SAME_STMT);
729 }
730 else
731 parts.base = parts.offset;
732
733 parts.offset = NULL_TREE;
734
735 mem_ref = create_mem_ref_raw (type, &parts);
736 if (mem_ref)
737 return mem_ref;
738 }
739
740 /* Verify that the address is in the simplest possible shape
741 (only a register). If we cannot create such a memory reference,
742 something is really wrong. */
743 gcc_assert (parts.symbol == NULL_TREE);
744 gcc_assert (parts.index == NULL_TREE);
745 gcc_assert (!parts.step || integer_onep (parts.step));
746 gcc_assert (!parts.offset || integer_zerop (parts.offset));
747 gcc_unreachable ();
748 }
749
750 /* Copies components of the address from OP to ADDR. */
751
752 void
753 get_address_description (tree op, struct mem_address *addr)
754 {
755 addr->symbol = TMR_SYMBOL (op);
756 addr->base = TMR_BASE (op);
757 addr->index = TMR_INDEX (op);
758 addr->step = TMR_STEP (op);
759 addr->offset = TMR_OFFSET (op);
760 }
761
762 /* Copies the additional information attached to target_mem_ref FROM to TO. */
763
764 void
765 copy_mem_ref_info (tree to, tree from)
766 {
767 /* And the info about the original reference. */
768 TMR_ORIGINAL (to) = TMR_ORIGINAL (from);
769 TREE_SIDE_EFFECTS (to) = TREE_SIDE_EFFECTS (from);
770 TREE_THIS_VOLATILE (to) = TREE_THIS_VOLATILE (from);
771 }
772
773 /* Move constants in target_mem_ref REF to offset. Returns the new target
774 mem ref if anything changes, NULL_TREE otherwise. */
775
776 tree
777 maybe_fold_tmr (tree ref)
778 {
779 struct mem_address addr;
780 bool changed = false;
781 tree ret, off;
782
783 get_address_description (ref, &addr);
784
785 if (addr.base && TREE_CODE (addr.base) == INTEGER_CST)
786 {
787 if (addr.offset)
788 addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
789 addr.offset,
790 fold_convert (sizetype, addr.base));
791 else
792 addr.offset = addr.base;
793
794 addr.base = NULL_TREE;
795 changed = true;
796 }
797
798 if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
799 {
800 off = addr.index;
801 if (addr.step)
802 {
803 off = fold_binary_to_constant (MULT_EXPR, sizetype,
804 off, addr.step);
805 addr.step = NULL_TREE;
806 }
807
808 if (addr.offset)
809 {
810 addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
811 addr.offset, off);
812 }
813 else
814 addr.offset = off;
815
816 addr.index = NULL_TREE;
817 changed = true;
818 }
819
820 if (!changed)
821 return NULL_TREE;
822
823 ret = create_mem_ref_raw (TREE_TYPE (ref), &addr);
824 if (!ret)
825 return NULL_TREE;
826
827 copy_mem_ref_info (ret, ref);
828 return ret;
829 }
830
831 /* Dump PARTS to FILE. */
832
833 extern void dump_mem_address (FILE *, struct mem_address *);
834 void
835 dump_mem_address (FILE *file, struct mem_address *parts)
836 {
837 if (parts->symbol)
838 {
839 fprintf (file, "symbol: ");
840 print_generic_expr (file, parts->symbol, TDF_SLIM);
841 fprintf (file, "\n");
842 }
843 if (parts->base)
844 {
845 fprintf (file, "base: ");
846 print_generic_expr (file, parts->base, TDF_SLIM);
847 fprintf (file, "\n");
848 }
849 if (parts->index)
850 {
851 fprintf (file, "index: ");
852 print_generic_expr (file, parts->index, TDF_SLIM);
853 fprintf (file, "\n");
854 }
855 if (parts->step)
856 {
857 fprintf (file, "step: ");
858 print_generic_expr (file, parts->step, TDF_SLIM);
859 fprintf (file, "\n");
860 }
861 if (parts->offset)
862 {
863 fprintf (file, "offset: ");
864 print_generic_expr (file, parts->offset, TDF_SLIM);
865 fprintf (file, "\n");
866 }
867 }
868
869 #include "gt-tree-ssa-address.h"