]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/tree-ssa-address.c
re PR tree-optimization/38835 (field-insensitive PTA causes libstdc++ miscompiles)
[thirdparty/gcc.git] / gcc / tree-ssa-address.c
1 /* Memory address lowering and addressing mode selection.
2 Copyright (C) 2004, 2006, 2007 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 3, 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 COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
19
20 /* Utility functions for manipulation with TARGET_MEM_REFs -- tree expressions
21 that directly map to addressing modes of the target. */
22
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "tree.h"
28 #include "rtl.h"
29 #include "tm_p.h"
30 #include "hard-reg-set.h"
31 #include "basic-block.h"
32 #include "output.h"
33 #include "diagnostic.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 "insn-config.h"
41 #include "recog.h"
42 #include "expr.h"
43 #include "ggc.h"
44 #include "tree-affine.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 = simplify_gen_binary (PLUS, Pmode, base, *addr);
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;
252 tree act_elem;
253 tree step = TMR_STEP (mem_ref), offset = TMR_OFFSET (mem_ref);
254 tree sym = TMR_SYMBOL (mem_ref), base = TMR_BASE (mem_ref);
255 tree addr_base = NULL_TREE, addr_off = NULL_TREE;
256
257 if (sym)
258 addr_base = fold_convert (type, build_addr (sym, current_function_decl));
259 else if (base && POINTER_TYPE_P (TREE_TYPE (base)))
260 {
261 addr_base = fold_convert (type, base);
262 base = NULL_TREE;
263 }
264
265 act_elem = TMR_INDEX (mem_ref);
266 if (act_elem)
267 {
268 if (step)
269 act_elem = fold_build2 (MULT_EXPR, sizetype, act_elem, step);
270 addr_off = act_elem;
271 }
272
273 act_elem = base;
274 if (act_elem)
275 {
276 if (addr_off)
277 addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, act_elem);
278 else
279 addr_off = act_elem;
280 }
281
282 if (offset && !integer_zerop (offset))
283 {
284 if (addr_off)
285 addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, offset);
286 else
287 addr_off = offset;
288 }
289
290 if (addr_off)
291 {
292 if (addr_base)
293 addr = fold_build2 (POINTER_PLUS_EXPR, type, addr_base, addr_off);
294 else
295 addr = fold_convert (type, addr_off);
296 }
297 else if (addr_base)
298 addr = addr_base;
299 else
300 addr = build_int_cst (type, 0);
301
302 return addr;
303 }
304
305 /* Returns true if a memory reference in MODE and with parameters given by
306 ADDR is valid on the current target. */
307
308 static bool
309 valid_mem_ref_p (enum machine_mode mode, struct mem_address *addr)
310 {
311 rtx address;
312
313 address = addr_for_mem_ref (addr, false);
314 if (!address)
315 return false;
316
317 return memory_address_p (mode, address);
318 }
319
320 /* Checks whether a TARGET_MEM_REF with type TYPE and parameters given by ADDR
321 is valid on the current target and if so, creates and returns the
322 TARGET_MEM_REF. */
323
324 static tree
325 create_mem_ref_raw (tree type, struct mem_address *addr)
326 {
327 if (!valid_mem_ref_p (TYPE_MODE (type), addr))
328 return NULL_TREE;
329
330 if (addr->step && integer_onep (addr->step))
331 addr->step = NULL_TREE;
332
333 if (addr->offset && integer_zerop (addr->offset))
334 addr->offset = NULL_TREE;
335
336 return build7 (TARGET_MEM_REF, type,
337 addr->symbol, addr->base, addr->index,
338 addr->step, addr->offset, NULL, NULL);
339 }
340
341 /* Returns true if OBJ is an object whose address is a link time constant. */
342
343 static bool
344 fixed_address_object_p (tree obj)
345 {
346 return (TREE_CODE (obj) == VAR_DECL
347 && (TREE_STATIC (obj)
348 || DECL_EXTERNAL (obj))
349 && ! DECL_DLLIMPORT_P (obj));
350 }
351
352 /* If ADDR contains an address of object that is a link time constant,
353 move it to PARTS->symbol. */
354
355 static void
356 move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
357 {
358 unsigned i;
359 tree val = NULL_TREE;
360
361 for (i = 0; i < addr->n; i++)
362 {
363 if (!double_int_one_p (addr->elts[i].coef))
364 continue;
365
366 val = addr->elts[i].val;
367 if (TREE_CODE (val) == ADDR_EXPR
368 && fixed_address_object_p (TREE_OPERAND (val, 0)))
369 break;
370 }
371
372 if (i == addr->n)
373 return;
374
375 parts->symbol = TREE_OPERAND (val, 0);
376 aff_combination_remove_elt (addr, i);
377 }
378
379 /* If ADDR contains an address of a dereferenced pointer, move it to
380 PARTS->base. */
381
382 static void
383 move_pointer_to_base (struct mem_address *parts, aff_tree *addr)
384 {
385 unsigned i;
386 tree val = NULL_TREE;
387
388 for (i = 0; i < addr->n; i++)
389 {
390 if (!double_int_one_p (addr->elts[i].coef))
391 continue;
392
393 val = addr->elts[i].val;
394 if (POINTER_TYPE_P (TREE_TYPE (val)))
395 break;
396 }
397
398 if (i == addr->n)
399 return;
400
401 parts->base = val;
402 aff_combination_remove_elt (addr, i);
403 }
404
405 /* Adds ELT to PARTS. */
406
407 static void
408 add_to_parts (struct mem_address *parts, tree elt)
409 {
410 tree type;
411
412 if (!parts->index)
413 {
414 parts->index = fold_convert (sizetype, elt);
415 return;
416 }
417
418 if (!parts->base)
419 {
420 parts->base = elt;
421 return;
422 }
423
424 /* Add ELT to base. */
425 type = TREE_TYPE (parts->base);
426 if (POINTER_TYPE_P (type))
427 parts->base = fold_build2 (POINTER_PLUS_EXPR, type,
428 parts->base,
429 fold_convert (sizetype, elt));
430 else
431 parts->base = fold_build2 (PLUS_EXPR, type,
432 parts->base, elt);
433 }
434
435 /* Finds the most expensive multiplication in ADDR that can be
436 expressed in an addressing mode and move the corresponding
437 element(s) to PARTS. */
438
439 static void
440 most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr,
441 bool speed)
442 {
443 HOST_WIDE_INT coef;
444 double_int best_mult, amult, amult_neg;
445 unsigned best_mult_cost = 0, acost;
446 tree mult_elt = NULL_TREE, elt;
447 unsigned i, j;
448 enum tree_code op_code;
449
450 best_mult = double_int_zero;
451 for (i = 0; i < addr->n; i++)
452 {
453 if (!double_int_fits_in_shwi_p (addr->elts[i].coef))
454 continue;
455
456 /* FIXME: Should use the correct memory mode rather than Pmode. */
457
458 coef = double_int_to_shwi (addr->elts[i].coef);
459 if (coef == 1
460 || !multiplier_allowed_in_address_p (coef, Pmode))
461 continue;
462
463 acost = multiply_by_cost (coef, Pmode, speed);
464
465 if (acost > best_mult_cost)
466 {
467 best_mult_cost = acost;
468 best_mult = addr->elts[i].coef;
469 }
470 }
471
472 if (!best_mult_cost)
473 return;
474
475 /* Collect elements multiplied by best_mult. */
476 for (i = j = 0; i < addr->n; i++)
477 {
478 amult = addr->elts[i].coef;
479 amult_neg = double_int_ext_for_comb (double_int_neg (amult), addr);
480
481 if (double_int_equal_p (amult, best_mult))
482 op_code = PLUS_EXPR;
483 else if (double_int_equal_p (amult_neg, best_mult))
484 op_code = MINUS_EXPR;
485 else
486 {
487 addr->elts[j] = addr->elts[i];
488 j++;
489 continue;
490 }
491
492 elt = fold_convert (sizetype, addr->elts[i].val);
493 if (mult_elt)
494 mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt);
495 else if (op_code == PLUS_EXPR)
496 mult_elt = elt;
497 else
498 mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt);
499 }
500 addr->n = j;
501
502 parts->index = mult_elt;
503 parts->step = double_int_to_tree (sizetype, best_mult);
504 }
505
506 /* Splits address ADDR into PARTS.
507
508 TODO -- be more clever about the distribution of the elements of ADDR
509 to PARTS. Some architectures do not support anything but single
510 register in address, possibly with a small integer offset; while
511 create_mem_ref will simplify the address to an acceptable shape
512 later, it would be more efficient to know that asking for complicated
513 addressing modes is useless. */
514
515 static void
516 addr_to_parts (aff_tree *addr, struct mem_address *parts, bool speed)
517 {
518 tree part;
519 unsigned i;
520
521 parts->symbol = NULL_TREE;
522 parts->base = NULL_TREE;
523 parts->index = NULL_TREE;
524 parts->step = NULL_TREE;
525
526 if (!double_int_zero_p (addr->offset))
527 parts->offset = double_int_to_tree (sizetype, addr->offset);
528 else
529 parts->offset = NULL_TREE;
530
531 /* Try to find a symbol. */
532 move_fixed_address_to_symbol (parts, addr);
533
534 /* First move the most expensive feasible multiplication
535 to index. */
536 most_expensive_mult_to_index (parts, addr, speed);
537
538 /* Try to find a base of the reference. Since at the moment
539 there is no reliable way how to distinguish between pointer and its
540 offset, this is just a guess. */
541 if (!parts->symbol)
542 move_pointer_to_base (parts, addr);
543
544 /* Then try to process the remaining elements. */
545 for (i = 0; i < addr->n; i++)
546 {
547 part = fold_convert (sizetype, addr->elts[i].val);
548 if (!double_int_one_p (addr->elts[i].coef))
549 part = fold_build2 (MULT_EXPR, sizetype, part,
550 double_int_to_tree (sizetype, addr->elts[i].coef));
551 add_to_parts (parts, part);
552 }
553 if (addr->rest)
554 add_to_parts (parts, fold_convert (sizetype, addr->rest));
555 }
556
557 /* Force the PARTS to register. */
558
559 static void
560 gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts)
561 {
562 if (parts->base)
563 parts->base = force_gimple_operand_gsi (gsi, parts->base,
564 true, NULL_TREE,
565 true, GSI_SAME_STMT);
566 if (parts->index)
567 parts->index = force_gimple_operand_gsi (gsi, parts->index,
568 true, NULL_TREE,
569 true, GSI_SAME_STMT);
570 }
571
572 /* Creates and returns a TARGET_MEM_REF for address ADDR. If necessary
573 computations are emitted in front of GSI. TYPE is the mode
574 of created memory reference. */
575
576 tree
577 create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
578 bool speed)
579 {
580 tree mem_ref, tmp;
581 tree atype;
582 struct mem_address parts;
583
584 addr_to_parts (addr, &parts, speed);
585 gimplify_mem_ref_parts (gsi, &parts);
586 mem_ref = create_mem_ref_raw (type, &parts);
587 if (mem_ref)
588 return mem_ref;
589
590 /* The expression is too complicated. Try making it simpler. */
591
592 if (parts.step && !integer_onep (parts.step))
593 {
594 /* Move the multiplication to index. */
595 gcc_assert (parts.index);
596 parts.index = force_gimple_operand_gsi (gsi,
597 fold_build2 (MULT_EXPR, sizetype,
598 parts.index, parts.step),
599 true, NULL_TREE, true, GSI_SAME_STMT);
600 parts.step = NULL_TREE;
601
602 mem_ref = create_mem_ref_raw (type, &parts);
603 if (mem_ref)
604 return mem_ref;
605 }
606
607 if (parts.symbol)
608 {
609 tmp = build_addr (parts.symbol, current_function_decl);
610 gcc_assert (is_gimple_val (tmp));
611
612 /* Add the symbol to base, eventually forcing it to register. */
613 if (parts.base)
614 {
615 gcc_assert (useless_type_conversion_p
616 (sizetype, TREE_TYPE (parts.base)));
617
618 if (parts.index)
619 {
620 atype = TREE_TYPE (tmp);
621 parts.base = force_gimple_operand_gsi (gsi,
622 fold_build2 (POINTER_PLUS_EXPR, atype,
623 tmp,
624 fold_convert (sizetype, parts.base)),
625 true, NULL_TREE, true, GSI_SAME_STMT);
626 }
627 else
628 {
629 parts.index = parts.base;
630 parts.base = tmp;
631 }
632 }
633 else
634 parts.base = tmp;
635 parts.symbol = NULL_TREE;
636
637 mem_ref = create_mem_ref_raw (type, &parts);
638 if (mem_ref)
639 return mem_ref;
640 }
641
642 if (parts.index)
643 {
644 /* Add index to base. */
645 if (parts.base)
646 {
647 atype = TREE_TYPE (parts.base);
648 parts.base = force_gimple_operand_gsi (gsi,
649 fold_build2 (POINTER_PLUS_EXPR, atype,
650 parts.base,
651 parts.index),
652 true, NULL_TREE, true, GSI_SAME_STMT);
653 }
654 else
655 parts.base = parts.index;
656 parts.index = NULL_TREE;
657
658 mem_ref = create_mem_ref_raw (type, &parts);
659 if (mem_ref)
660 return mem_ref;
661 }
662
663 if (parts.offset && !integer_zerop (parts.offset))
664 {
665 /* Try adding offset to base. */
666 if (parts.base)
667 {
668 atype = TREE_TYPE (parts.base);
669 parts.base = force_gimple_operand_gsi (gsi,
670 fold_build2 (POINTER_PLUS_EXPR, atype,
671 parts.base,
672 fold_convert (sizetype, parts.offset)),
673 true, NULL_TREE, true, GSI_SAME_STMT);
674 }
675 else
676 parts.base = parts.offset;
677
678 parts.offset = NULL_TREE;
679
680 mem_ref = create_mem_ref_raw (type, &parts);
681 if (mem_ref)
682 return mem_ref;
683 }
684
685 /* Verify that the address is in the simplest possible shape
686 (only a register). If we cannot create such a memory reference,
687 something is really wrong. */
688 gcc_assert (parts.symbol == NULL_TREE);
689 gcc_assert (parts.index == NULL_TREE);
690 gcc_assert (!parts.step || integer_onep (parts.step));
691 gcc_assert (!parts.offset || integer_zerop (parts.offset));
692 gcc_unreachable ();
693 }
694
695 /* Copies components of the address from OP to ADDR. */
696
697 void
698 get_address_description (tree op, struct mem_address *addr)
699 {
700 addr->symbol = TMR_SYMBOL (op);
701 addr->base = TMR_BASE (op);
702 addr->index = TMR_INDEX (op);
703 addr->step = TMR_STEP (op);
704 addr->offset = TMR_OFFSET (op);
705 }
706
707 /* Copies the additional information attached to target_mem_ref FROM to TO. */
708
709 void
710 copy_mem_ref_info (tree to, tree from)
711 {
712 /* Copy the annotation, to preserve the aliasing information. */
713 TMR_TAG (to) = TMR_TAG (from);
714
715 /* And the info about the original reference. */
716 TMR_ORIGINAL (to) = TMR_ORIGINAL (from);
717 }
718
719 /* Move constants in target_mem_ref REF to offset. Returns the new target
720 mem ref if anything changes, NULL_TREE otherwise. */
721
722 tree
723 maybe_fold_tmr (tree ref)
724 {
725 struct mem_address addr;
726 bool changed = false;
727 tree ret, off;
728
729 get_address_description (ref, &addr);
730
731 if (addr.base && TREE_CODE (addr.base) == INTEGER_CST)
732 {
733 if (addr.offset)
734 addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
735 addr.offset,
736 fold_convert (sizetype, addr.base));
737 else
738 addr.offset = addr.base;
739
740 addr.base = NULL_TREE;
741 changed = true;
742 }
743
744 if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
745 {
746 off = addr.index;
747 if (addr.step)
748 {
749 off = fold_binary_to_constant (MULT_EXPR, sizetype,
750 off, addr.step);
751 addr.step = NULL_TREE;
752 }
753
754 if (addr.offset)
755 {
756 addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
757 addr.offset, off);
758 }
759 else
760 addr.offset = off;
761
762 addr.index = NULL_TREE;
763 changed = true;
764 }
765
766 if (!changed)
767 return NULL_TREE;
768
769 ret = create_mem_ref_raw (TREE_TYPE (ref), &addr);
770 if (!ret)
771 return NULL_TREE;
772
773 copy_mem_ref_info (ret, ref);
774 return ret;
775 }
776
777 /* Dump PARTS to FILE. */
778
779 extern void dump_mem_address (FILE *, struct mem_address *);
780 void
781 dump_mem_address (FILE *file, struct mem_address *parts)
782 {
783 if (parts->symbol)
784 {
785 fprintf (file, "symbol: ");
786 print_generic_expr (file, parts->symbol, TDF_SLIM);
787 fprintf (file, "\n");
788 }
789 if (parts->base)
790 {
791 fprintf (file, "base: ");
792 print_generic_expr (file, parts->base, TDF_SLIM);
793 fprintf (file, "\n");
794 }
795 if (parts->index)
796 {
797 fprintf (file, "index: ");
798 print_generic_expr (file, parts->index, TDF_SLIM);
799 fprintf (file, "\n");
800 }
801 if (parts->step)
802 {
803 fprintf (file, "step: ");
804 print_generic_expr (file, parts->step, TDF_SLIM);
805 fprintf (file, "\n");
806 }
807 if (parts->offset)
808 {
809 fprintf (file, "offset: ");
810 print_generic_expr (file, parts->offset, TDF_SLIM);
811 fprintf (file, "\n");
812 }
813 }
814
815 #include "gt-tree-ssa-address.h"