Add a testcase for PR target/43668.
[official-gcc.git] / gcc / tree-ssa-address.c
blobf0cbdfee8c99949c12fec729476d4790dd60024a
1 /* Memory address lowering and addressing mode selection.
2 Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010
3 Free Software Foundation, Inc.
5 This file is part of GCC.
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.
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.
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/>. */
21 /* Utility functions for manipulation with TARGET_MEM_REFs -- tree expressions
22 that directly map to addressing modes of the target. */
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 #include "tree-affine.h"
46 #include "target.h"
48 /* TODO -- handling of symbols (according to Richard Hendersons
49 comments, http://gcc.gnu.org/ml/gcc-patches/2005-04/msg00949.html):
51 There are at least 5 different kinds of symbols that we can run up against:
53 (1) binds_local_p, small data area.
54 (2) binds_local_p, eg local statics
55 (3) !binds_local_p, eg global variables
56 (4) thread local, local_exec
57 (5) thread local, !local_exec
59 Now, (1) won't appear often in an array context, but it certainly can.
60 All you have to do is set -GN high enough, or explicitly mark any
61 random object __attribute__((section (".sdata"))).
63 All of these affect whether or not a symbol is in fact a valid address.
64 The only one tested here is (3). And that result may very well
65 be incorrect for (4) or (5).
67 An incorrect result here does not cause incorrect results out the
68 back end, because the expander in expr.c validizes the address. However
69 it would be nice to improve the handling here in order to produce more
70 precise results. */
72 /* A "template" for memory address, used to determine whether the address is
73 valid for mode. */
75 typedef struct GTY (()) mem_addr_template {
76 rtx ref; /* The template. */
77 rtx * GTY ((skip)) step_p; /* The point in template where the step should be
78 filled in. */
79 rtx * GTY ((skip)) off_p; /* The point in template where the offset should
80 be filled in. */
81 } mem_addr_template;
83 DEF_VEC_O (mem_addr_template);
84 DEF_VEC_ALLOC_O (mem_addr_template, gc);
86 /* The templates. Each of the low five bits of the index corresponds to one
87 component of TARGET_MEM_REF being present, while the high bits identify
88 the address space. See TEMPL_IDX. */
90 static GTY(()) VEC (mem_addr_template, gc) *mem_addr_template_list;
92 #define TEMPL_IDX(AS, SYMBOL, BASE, INDEX, STEP, OFFSET) \
93 (((int) (AS) << 5) \
94 | ((SYMBOL != 0) << 4) \
95 | ((BASE != 0) << 3) \
96 | ((INDEX != 0) << 2) \
97 | ((STEP != 0) << 1) \
98 | (OFFSET != 0))
100 /* Stores address for memory reference with parameters SYMBOL, BASE, INDEX,
101 STEP and OFFSET to *ADDR using address mode ADDRESS_MODE. Stores pointers
102 to where step is placed to *STEP_P and offset to *OFFSET_P. */
104 static void
105 gen_addr_rtx (enum machine_mode address_mode,
106 rtx symbol, rtx base, rtx index, rtx step, rtx offset,
107 rtx *addr, rtx **step_p, rtx **offset_p)
109 rtx act_elem;
111 *addr = NULL_RTX;
112 if (step_p)
113 *step_p = NULL;
114 if (offset_p)
115 *offset_p = NULL;
117 if (index)
119 act_elem = index;
120 if (step)
122 act_elem = gen_rtx_MULT (address_mode, act_elem, step);
124 if (step_p)
125 *step_p = &XEXP (act_elem, 1);
128 *addr = act_elem;
131 if (base)
133 if (*addr)
134 *addr = simplify_gen_binary (PLUS, address_mode, base, *addr);
135 else
136 *addr = base;
139 if (symbol)
141 act_elem = symbol;
142 if (offset)
144 act_elem = gen_rtx_PLUS (address_mode, act_elem, offset);
146 if (offset_p)
147 *offset_p = &XEXP (act_elem, 1);
149 if (GET_CODE (symbol) == SYMBOL_REF
150 || GET_CODE (symbol) == LABEL_REF
151 || GET_CODE (symbol) == CONST)
152 act_elem = gen_rtx_CONST (address_mode, act_elem);
155 if (*addr)
156 *addr = gen_rtx_PLUS (address_mode, *addr, act_elem);
157 else
158 *addr = act_elem;
160 else if (offset)
162 if (*addr)
164 *addr = gen_rtx_PLUS (address_mode, *addr, offset);
165 if (offset_p)
166 *offset_p = &XEXP (*addr, 1);
168 else
170 *addr = offset;
171 if (offset_p)
172 *offset_p = addr;
176 if (!*addr)
177 *addr = const0_rtx;
180 /* Returns address for TARGET_MEM_REF with parameters given by ADDR
181 in address space AS.
182 If REALLY_EXPAND is false, just make fake registers instead
183 of really expanding the operands, and perform the expansion in-place
184 by using one of the "templates". */
187 addr_for_mem_ref (struct mem_address *addr, addr_space_t as,
188 bool really_expand)
190 enum machine_mode address_mode = targetm.addr_space.address_mode (as);
191 rtx address, sym, bse, idx, st, off;
192 struct mem_addr_template *templ;
194 if (addr->step && !integer_onep (addr->step))
195 st = immed_double_int_const (tree_to_double_int (addr->step), address_mode);
196 else
197 st = NULL_RTX;
199 if (addr->offset && !integer_zerop (addr->offset))
200 off = immed_double_int_const (tree_to_double_int (addr->offset), address_mode);
201 else
202 off = NULL_RTX;
204 if (!really_expand)
206 unsigned int templ_index
207 = TEMPL_IDX (as, addr->symbol, addr->base, addr->index, st, off);
209 if (templ_index
210 >= VEC_length (mem_addr_template, mem_addr_template_list))
211 VEC_safe_grow_cleared (mem_addr_template, gc, mem_addr_template_list,
212 templ_index + 1);
214 /* Reuse the templates for addresses, so that we do not waste memory. */
215 templ = VEC_index (mem_addr_template, mem_addr_template_list, templ_index);
216 if (!templ->ref)
218 sym = (addr->symbol ?
219 gen_rtx_SYMBOL_REF (address_mode, ggc_strdup ("test_symbol"))
220 : NULL_RTX);
221 bse = (addr->base ?
222 gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 1)
223 : NULL_RTX);
224 idx = (addr->index ?
225 gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 2)
226 : NULL_RTX);
228 gen_addr_rtx (address_mode, sym, bse, idx,
229 st? const0_rtx : NULL_RTX,
230 off? const0_rtx : NULL_RTX,
231 &templ->ref,
232 &templ->step_p,
233 &templ->off_p);
236 if (st)
237 *templ->step_p = st;
238 if (off)
239 *templ->off_p = off;
241 return templ->ref;
244 /* Otherwise really expand the expressions. */
245 sym = (addr->symbol
246 ? expand_expr (build_addr (addr->symbol, current_function_decl),
247 NULL_RTX, address_mode, EXPAND_NORMAL)
248 : NULL_RTX);
249 bse = (addr->base
250 ? expand_expr (addr->base, NULL_RTX, address_mode, EXPAND_NORMAL)
251 : NULL_RTX);
252 idx = (addr->index
253 ? expand_expr (addr->index, NULL_RTX, address_mode, EXPAND_NORMAL)
254 : NULL_RTX);
256 gen_addr_rtx (address_mode, sym, bse, idx, st, off, &address, NULL, NULL);
257 return address;
260 /* Returns address of MEM_REF in TYPE. */
262 tree
263 tree_mem_ref_addr (tree type, tree mem_ref)
265 tree addr;
266 tree act_elem;
267 tree step = TMR_STEP (mem_ref), offset = TMR_OFFSET (mem_ref);
268 tree sym = TMR_SYMBOL (mem_ref), base = TMR_BASE (mem_ref);
269 tree addr_base = NULL_TREE, addr_off = NULL_TREE;
271 if (sym)
272 addr_base = fold_convert (type, build_addr (sym, current_function_decl));
273 else if (base && POINTER_TYPE_P (TREE_TYPE (base)))
275 addr_base = fold_convert (type, base);
276 base = NULL_TREE;
279 act_elem = TMR_INDEX (mem_ref);
280 if (act_elem)
282 if (step)
283 act_elem = fold_build2 (MULT_EXPR, sizetype, act_elem, step);
284 addr_off = act_elem;
287 act_elem = base;
288 if (act_elem)
290 if (addr_off)
291 addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, act_elem);
292 else
293 addr_off = act_elem;
296 if (offset && !integer_zerop (offset))
298 if (addr_off)
299 addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, offset);
300 else
301 addr_off = offset;
304 if (addr_off)
306 if (addr_base)
307 addr = fold_build2 (POINTER_PLUS_EXPR, type, addr_base, addr_off);
308 else
309 addr = fold_convert (type, addr_off);
311 else if (addr_base)
312 addr = addr_base;
313 else
314 addr = build_int_cst (type, 0);
316 return addr;
319 /* Returns true if a memory reference in MODE and with parameters given by
320 ADDR is valid on the current target. */
322 static bool
323 valid_mem_ref_p (enum machine_mode mode, addr_space_t as,
324 struct mem_address *addr)
326 rtx address;
328 address = addr_for_mem_ref (addr, as, false);
329 if (!address)
330 return false;
332 return memory_address_addr_space_p (mode, address, as);
335 /* Checks whether a TARGET_MEM_REF with type TYPE and parameters given by ADDR
336 is valid on the current target and if so, creates and returns the
337 TARGET_MEM_REF. */
339 static tree
340 create_mem_ref_raw (tree type, struct mem_address *addr)
342 if (!valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), addr))
343 return NULL_TREE;
345 if (addr->step && integer_onep (addr->step))
346 addr->step = NULL_TREE;
348 if (addr->offset && integer_zerop (addr->offset))
349 addr->offset = NULL_TREE;
351 return build6 (TARGET_MEM_REF, type,
352 addr->symbol, addr->base, addr->index,
353 addr->step, addr->offset, NULL);
356 /* Returns true if OBJ is an object whose address is a link time constant. */
358 static bool
359 fixed_address_object_p (tree obj)
361 return (TREE_CODE (obj) == VAR_DECL
362 && (TREE_STATIC (obj)
363 || DECL_EXTERNAL (obj))
364 && ! DECL_DLLIMPORT_P (obj));
367 /* If ADDR contains an address of object that is a link time constant,
368 move it to PARTS->symbol. */
370 static void
371 move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
373 unsigned i;
374 tree val = NULL_TREE;
376 for (i = 0; i < addr->n; i++)
378 if (!double_int_one_p (addr->elts[i].coef))
379 continue;
381 val = addr->elts[i].val;
382 if (TREE_CODE (val) == ADDR_EXPR
383 && fixed_address_object_p (TREE_OPERAND (val, 0)))
384 break;
387 if (i == addr->n)
388 return;
390 parts->symbol = TREE_OPERAND (val, 0);
391 aff_combination_remove_elt (addr, i);
394 /* If ADDR contains an instance of BASE_HINT, move it to PARTS->base. */
396 static void
397 move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
398 aff_tree *addr)
400 unsigned i;
401 tree val = NULL_TREE;
402 int qual;
404 for (i = 0; i < addr->n; i++)
406 if (!double_int_one_p (addr->elts[i].coef))
407 continue;
409 val = addr->elts[i].val;
410 if (operand_equal_p (val, base_hint, 0))
411 break;
414 if (i == addr->n)
415 return;
417 /* Cast value to appropriate pointer type. We cannot use a pointer
418 to TYPE directly, as the back-end will assume registers of pointer
419 type are aligned, and just the base itself may not actually be.
420 We use void pointer to the type's address space instead. */
421 qual = ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (type));
422 type = build_qualified_type (void_type_node, qual);
423 parts->base = fold_convert (build_pointer_type (type), val);
424 aff_combination_remove_elt (addr, i);
427 /* If ADDR contains an address of a dereferenced pointer, move it to
428 PARTS->base. */
430 static void
431 move_pointer_to_base (struct mem_address *parts, aff_tree *addr)
433 unsigned i;
434 tree val = NULL_TREE;
436 for (i = 0; i < addr->n; i++)
438 if (!double_int_one_p (addr->elts[i].coef))
439 continue;
441 val = addr->elts[i].val;
442 if (POINTER_TYPE_P (TREE_TYPE (val)))
443 break;
446 if (i == addr->n)
447 return;
449 parts->base = val;
450 aff_combination_remove_elt (addr, i);
453 /* Adds ELT to PARTS. */
455 static void
456 add_to_parts (struct mem_address *parts, tree elt)
458 tree type;
460 if (!parts->index)
462 parts->index = fold_convert (sizetype, elt);
463 return;
466 if (!parts->base)
468 parts->base = elt;
469 return;
472 /* Add ELT to base. */
473 type = TREE_TYPE (parts->base);
474 if (POINTER_TYPE_P (type))
475 parts->base = fold_build2 (POINTER_PLUS_EXPR, type,
476 parts->base,
477 fold_convert (sizetype, elt));
478 else
479 parts->base = fold_build2 (PLUS_EXPR, type,
480 parts->base, elt);
483 /* Finds the most expensive multiplication in ADDR that can be
484 expressed in an addressing mode and move the corresponding
485 element(s) to PARTS. */
487 static void
488 most_expensive_mult_to_index (tree type, struct mem_address *parts,
489 aff_tree *addr, bool speed)
491 addr_space_t as = TYPE_ADDR_SPACE (type);
492 enum machine_mode address_mode = targetm.addr_space.address_mode (as);
493 HOST_WIDE_INT coef;
494 double_int best_mult, amult, amult_neg;
495 unsigned best_mult_cost = 0, acost;
496 tree mult_elt = NULL_TREE, elt;
497 unsigned i, j;
498 enum tree_code op_code;
500 best_mult = double_int_zero;
501 for (i = 0; i < addr->n; i++)
503 if (!double_int_fits_in_shwi_p (addr->elts[i].coef))
504 continue;
506 coef = double_int_to_shwi (addr->elts[i].coef);
507 if (coef == 1
508 || !multiplier_allowed_in_address_p (coef, TYPE_MODE (type), as))
509 continue;
511 acost = multiply_by_cost (coef, address_mode, speed);
513 if (acost > best_mult_cost)
515 best_mult_cost = acost;
516 best_mult = addr->elts[i].coef;
520 if (!best_mult_cost)
521 return;
523 /* Collect elements multiplied by best_mult. */
524 for (i = j = 0; i < addr->n; i++)
526 amult = addr->elts[i].coef;
527 amult_neg = double_int_ext_for_comb (double_int_neg (amult), addr);
529 if (double_int_equal_p (amult, best_mult))
530 op_code = PLUS_EXPR;
531 else if (double_int_equal_p (amult_neg, best_mult))
532 op_code = MINUS_EXPR;
533 else
535 addr->elts[j] = addr->elts[i];
536 j++;
537 continue;
540 elt = fold_convert (sizetype, addr->elts[i].val);
541 if (mult_elt)
542 mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt);
543 else if (op_code == PLUS_EXPR)
544 mult_elt = elt;
545 else
546 mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt);
548 addr->n = j;
550 parts->index = mult_elt;
551 parts->step = double_int_to_tree (sizetype, best_mult);
554 /* Splits address ADDR for a memory access of type TYPE into PARTS.
555 If BASE_HINT is non-NULL, it specifies an SSA name to be used
556 preferentially as base of the reference.
558 TODO -- be more clever about the distribution of the elements of ADDR
559 to PARTS. Some architectures do not support anything but single
560 register in address, possibly with a small integer offset; while
561 create_mem_ref will simplify the address to an acceptable shape
562 later, it would be more efficient to know that asking for complicated
563 addressing modes is useless. */
565 static void
566 addr_to_parts (tree type, aff_tree *addr, tree base_hint,
567 struct mem_address *parts, bool speed)
569 tree part;
570 unsigned i;
572 parts->symbol = NULL_TREE;
573 parts->base = NULL_TREE;
574 parts->index = NULL_TREE;
575 parts->step = NULL_TREE;
577 if (!double_int_zero_p (addr->offset))
578 parts->offset = double_int_to_tree (sizetype, addr->offset);
579 else
580 parts->offset = NULL_TREE;
582 /* Try to find a symbol. */
583 move_fixed_address_to_symbol (parts, addr);
585 /* First move the most expensive feasible multiplication
586 to index. */
587 most_expensive_mult_to_index (type, parts, addr, speed);
589 /* Try to find a base of the reference. Since at the moment
590 there is no reliable way how to distinguish between pointer and its
591 offset, this is just a guess. */
592 if (!parts->symbol && base_hint)
593 move_hint_to_base (type, parts, base_hint, addr);
594 if (!parts->symbol && !parts->base)
595 move_pointer_to_base (parts, addr);
597 /* Then try to process the remaining elements. */
598 for (i = 0; i < addr->n; i++)
600 part = fold_convert (sizetype, addr->elts[i].val);
601 if (!double_int_one_p (addr->elts[i].coef))
602 part = fold_build2 (MULT_EXPR, sizetype, part,
603 double_int_to_tree (sizetype, addr->elts[i].coef));
604 add_to_parts (parts, part);
606 if (addr->rest)
607 add_to_parts (parts, fold_convert (sizetype, addr->rest));
610 /* Force the PARTS to register. */
612 static void
613 gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts)
615 if (parts->base)
616 parts->base = force_gimple_operand_gsi (gsi, parts->base,
617 true, NULL_TREE,
618 true, GSI_SAME_STMT);
619 if (parts->index)
620 parts->index = force_gimple_operand_gsi (gsi, parts->index,
621 true, NULL_TREE,
622 true, GSI_SAME_STMT);
625 /* Creates and returns a TARGET_MEM_REF for address ADDR. If necessary
626 computations are emitted in front of GSI. TYPE is the mode
627 of created memory reference. */
629 tree
630 create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
631 tree base_hint, bool speed)
633 tree mem_ref, tmp;
634 tree atype;
635 struct mem_address parts;
637 addr_to_parts (type, addr, base_hint, &parts, speed);
638 gimplify_mem_ref_parts (gsi, &parts);
639 mem_ref = create_mem_ref_raw (type, &parts);
640 if (mem_ref)
641 return mem_ref;
643 /* The expression is too complicated. Try making it simpler. */
645 if (parts.step && !integer_onep (parts.step))
647 /* Move the multiplication to index. */
648 gcc_assert (parts.index);
649 parts.index = force_gimple_operand_gsi (gsi,
650 fold_build2 (MULT_EXPR, sizetype,
651 parts.index, parts.step),
652 true, NULL_TREE, true, GSI_SAME_STMT);
653 parts.step = NULL_TREE;
655 mem_ref = create_mem_ref_raw (type, &parts);
656 if (mem_ref)
657 return mem_ref;
660 if (parts.symbol)
662 tmp = build_addr (parts.symbol, current_function_decl);
663 gcc_assert (is_gimple_val (tmp));
665 /* Add the symbol to base, eventually forcing it to register. */
666 if (parts.base)
668 gcc_assert (useless_type_conversion_p
669 (sizetype, TREE_TYPE (parts.base)));
671 if (parts.index)
673 atype = TREE_TYPE (tmp);
674 parts.base = force_gimple_operand_gsi (gsi,
675 fold_build2 (POINTER_PLUS_EXPR, atype,
676 tmp,
677 fold_convert (sizetype, parts.base)),
678 true, NULL_TREE, true, GSI_SAME_STMT);
680 else
682 parts.index = parts.base;
683 parts.base = tmp;
686 else
687 parts.base = tmp;
688 parts.symbol = NULL_TREE;
690 mem_ref = create_mem_ref_raw (type, &parts);
691 if (mem_ref)
692 return mem_ref;
695 if (parts.index)
697 /* Add index to base. */
698 if (parts.base)
700 atype = TREE_TYPE (parts.base);
701 parts.base = force_gimple_operand_gsi (gsi,
702 fold_build2 (POINTER_PLUS_EXPR, atype,
703 parts.base,
704 parts.index),
705 true, NULL_TREE, true, GSI_SAME_STMT);
707 else
708 parts.base = parts.index;
709 parts.index = NULL_TREE;
711 mem_ref = create_mem_ref_raw (type, &parts);
712 if (mem_ref)
713 return mem_ref;
716 if (parts.offset && !integer_zerop (parts.offset))
718 /* Try adding offset to base. */
719 if (parts.base)
721 atype = TREE_TYPE (parts.base);
722 parts.base = force_gimple_operand_gsi (gsi,
723 fold_build2 (POINTER_PLUS_EXPR, atype,
724 parts.base,
725 fold_convert (sizetype, parts.offset)),
726 true, NULL_TREE, true, GSI_SAME_STMT);
728 else
729 parts.base = parts.offset;
731 parts.offset = NULL_TREE;
733 mem_ref = create_mem_ref_raw (type, &parts);
734 if (mem_ref)
735 return mem_ref;
738 /* Verify that the address is in the simplest possible shape
739 (only a register). If we cannot create such a memory reference,
740 something is really wrong. */
741 gcc_assert (parts.symbol == NULL_TREE);
742 gcc_assert (parts.index == NULL_TREE);
743 gcc_assert (!parts.step || integer_onep (parts.step));
744 gcc_assert (!parts.offset || integer_zerop (parts.offset));
745 gcc_unreachable ();
748 /* Copies components of the address from OP to ADDR. */
750 void
751 get_address_description (tree op, struct mem_address *addr)
753 addr->symbol = TMR_SYMBOL (op);
754 addr->base = TMR_BASE (op);
755 addr->index = TMR_INDEX (op);
756 addr->step = TMR_STEP (op);
757 addr->offset = TMR_OFFSET (op);
760 /* Copies the additional information attached to target_mem_ref FROM to TO. */
762 void
763 copy_mem_ref_info (tree to, tree from)
765 /* And the info about the original reference. */
766 TMR_ORIGINAL (to) = TMR_ORIGINAL (from);
767 TREE_SIDE_EFFECTS (to) = TREE_SIDE_EFFECTS (from);
768 TREE_THIS_VOLATILE (to) = TREE_THIS_VOLATILE (from);
771 /* Move constants in target_mem_ref REF to offset. Returns the new target
772 mem ref if anything changes, NULL_TREE otherwise. */
774 tree
775 maybe_fold_tmr (tree ref)
777 struct mem_address addr;
778 bool changed = false;
779 tree ret, off;
781 get_address_description (ref, &addr);
783 if (addr.base && TREE_CODE (addr.base) == INTEGER_CST)
785 if (addr.offset)
786 addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
787 addr.offset,
788 fold_convert (sizetype, addr.base));
789 else
790 addr.offset = addr.base;
792 addr.base = NULL_TREE;
793 changed = true;
796 if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
798 off = addr.index;
799 if (addr.step)
801 off = fold_binary_to_constant (MULT_EXPR, sizetype,
802 off, addr.step);
803 addr.step = NULL_TREE;
806 if (addr.offset)
808 addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
809 addr.offset, off);
811 else
812 addr.offset = off;
814 addr.index = NULL_TREE;
815 changed = true;
818 if (!changed)
819 return NULL_TREE;
821 ret = create_mem_ref_raw (TREE_TYPE (ref), &addr);
822 if (!ret)
823 return NULL_TREE;
825 copy_mem_ref_info (ret, ref);
826 return ret;
829 /* Dump PARTS to FILE. */
831 extern void dump_mem_address (FILE *, struct mem_address *);
832 void
833 dump_mem_address (FILE *file, struct mem_address *parts)
835 if (parts->symbol)
837 fprintf (file, "symbol: ");
838 print_generic_expr (file, parts->symbol, TDF_SLIM);
839 fprintf (file, "\n");
841 if (parts->base)
843 fprintf (file, "base: ");
844 print_generic_expr (file, parts->base, TDF_SLIM);
845 fprintf (file, "\n");
847 if (parts->index)
849 fprintf (file, "index: ");
850 print_generic_expr (file, parts->index, TDF_SLIM);
851 fprintf (file, "\n");
853 if (parts->step)
855 fprintf (file, "step: ");
856 print_generic_expr (file, parts->step, TDF_SLIM);
857 fprintf (file, "\n");
859 if (parts->offset)
861 fprintf (file, "offset: ");
862 print_generic_expr (file, parts->offset, TDF_SLIM);
863 fprintf (file, "\n");
867 #include "gt-tree-ssa-address.h"