inclhack.def (hpux_imaginary_i): Remove spaces.
[gcc.git] / gcc / tree-ssa-address.c
1 /* Memory address lowering and addressing mode selection.
2 Copyright (C) 2004, 2006, 2007, 2008, 2009 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 GTY (()) mem_addr_template {
74 rtx ref; /* The template. */
75 rtx * GTY ((skip)) step_p; /* The point in template where the step should be
76 filled in. */
77 rtx * GTY ((skip)) off_p; /* The point in template where the offset should
78 be filled in. */
79 };
80
81 /* The templates. Each of the five bits of the index corresponds to one
82 component of TARGET_MEM_REF being present, see TEMPL_IDX. */
83
84 static GTY (()) struct mem_addr_template templates[32];
85
86 #define TEMPL_IDX(SYMBOL, BASE, INDEX, STEP, OFFSET) \
87 (((SYMBOL != 0) << 4) \
88 | ((BASE != 0) << 3) \
89 | ((INDEX != 0) << 2) \
90 | ((STEP != 0) << 1) \
91 | (OFFSET != 0))
92
93 /* Stores address for memory reference with parameters SYMBOL, BASE, INDEX,
94 STEP and OFFSET to *ADDR. Stores pointers to where step is placed to
95 *STEP_P and offset to *OFFSET_P. */
96
97 static void
98 gen_addr_rtx (rtx symbol, rtx base, rtx index, rtx step, rtx offset,
99 rtx *addr, rtx **step_p, rtx **offset_p)
100 {
101 rtx act_elem;
102
103 *addr = NULL_RTX;
104 if (step_p)
105 *step_p = NULL;
106 if (offset_p)
107 *offset_p = NULL;
108
109 if (index)
110 {
111 act_elem = index;
112 if (step)
113 {
114 act_elem = gen_rtx_MULT (Pmode, act_elem, step);
115
116 if (step_p)
117 *step_p = &XEXP (act_elem, 1);
118 }
119
120 *addr = act_elem;
121 }
122
123 if (base)
124 {
125 if (*addr)
126 *addr = simplify_gen_binary (PLUS, Pmode, base, *addr);
127 else
128 *addr = base;
129 }
130
131 if (symbol)
132 {
133 act_elem = symbol;
134 if (offset)
135 {
136 act_elem = gen_rtx_PLUS (Pmode, act_elem, offset);
137
138 if (offset_p)
139 *offset_p = &XEXP (act_elem, 1);
140
141 if (GET_CODE (symbol) == SYMBOL_REF
142 || GET_CODE (symbol) == LABEL_REF
143 || GET_CODE (symbol) == CONST)
144 act_elem = gen_rtx_CONST (Pmode, act_elem);
145 }
146
147 if (*addr)
148 *addr = gen_rtx_PLUS (Pmode, *addr, act_elem);
149 else
150 *addr = act_elem;
151 }
152 else if (offset)
153 {
154 if (*addr)
155 {
156 *addr = gen_rtx_PLUS (Pmode, *addr, offset);
157 if (offset_p)
158 *offset_p = &XEXP (*addr, 1);
159 }
160 else
161 {
162 *addr = offset;
163 if (offset_p)
164 *offset_p = addr;
165 }
166 }
167
168 if (!*addr)
169 *addr = const0_rtx;
170 }
171
172 /* Returns address for TARGET_MEM_REF with parameters given by ADDR.
173 If REALLY_EXPAND is false, just make fake registers instead
174 of really expanding the operands, and perform the expansion in-place
175 by using one of the "templates". */
176
177 rtx
178 addr_for_mem_ref (struct mem_address *addr, bool really_expand)
179 {
180 rtx address, sym, bse, idx, st, off;
181 static bool templates_initialized = false;
182 struct mem_addr_template *templ;
183
184 if (addr->step && !integer_onep (addr->step))
185 st = immed_double_const (TREE_INT_CST_LOW (addr->step),
186 TREE_INT_CST_HIGH (addr->step), Pmode);
187 else
188 st = NULL_RTX;
189
190 if (addr->offset && !integer_zerop (addr->offset))
191 off = immed_double_const (TREE_INT_CST_LOW (addr->offset),
192 TREE_INT_CST_HIGH (addr->offset), Pmode);
193 else
194 off = NULL_RTX;
195
196 if (!really_expand)
197 {
198 /* Reuse the templates for addresses, so that we do not waste memory. */
199 if (!templates_initialized)
200 {
201 unsigned i;
202
203 templates_initialized = true;
204 sym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup ("test_symbol"));
205 bse = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 1);
206 idx = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 2);
207
208 for (i = 0; i < 32; i++)
209 gen_addr_rtx ((i & 16 ? sym : NULL_RTX),
210 (i & 8 ? bse : NULL_RTX),
211 (i & 4 ? idx : NULL_RTX),
212 (i & 2 ? const0_rtx : NULL_RTX),
213 (i & 1 ? const0_rtx : NULL_RTX),
214 &templates[i].ref,
215 &templates[i].step_p,
216 &templates[i].off_p);
217 }
218
219 templ = templates + TEMPL_IDX (addr->symbol, addr->base, addr->index,
220 st, off);
221 if (st)
222 *templ->step_p = st;
223 if (off)
224 *templ->off_p = off;
225
226 return templ->ref;
227 }
228
229 /* Otherwise really expand the expressions. */
230 sym = (addr->symbol
231 ? expand_expr (build_addr (addr->symbol, current_function_decl),
232 NULL_RTX, Pmode, EXPAND_NORMAL)
233 : NULL_RTX);
234 bse = (addr->base
235 ? expand_expr (addr->base, NULL_RTX, Pmode, EXPAND_NORMAL)
236 : NULL_RTX);
237 idx = (addr->index
238 ? expand_expr (addr->index, NULL_RTX, Pmode, EXPAND_NORMAL)
239 : NULL_RTX);
240
241 gen_addr_rtx (sym, bse, idx, st, off, &address, NULL, NULL);
242 return address;
243 }
244
245 /* Returns address of MEM_REF in TYPE. */
246
247 tree
248 tree_mem_ref_addr (tree type, tree mem_ref)
249 {
250 tree addr;
251 tree act_elem;
252 tree step = TMR_STEP (mem_ref), offset = TMR_OFFSET (mem_ref);
253 tree sym = TMR_SYMBOL (mem_ref), base = TMR_BASE (mem_ref);
254 tree addr_base = NULL_TREE, addr_off = NULL_TREE;
255
256 if (sym)
257 addr_base = fold_convert (type, build_addr (sym, current_function_decl));
258 else if (base && POINTER_TYPE_P (TREE_TYPE (base)))
259 {
260 addr_base = fold_convert (type, base);
261 base = NULL_TREE;
262 }
263
264 act_elem = TMR_INDEX (mem_ref);
265 if (act_elem)
266 {
267 if (step)
268 act_elem = fold_build2 (MULT_EXPR, sizetype, act_elem, step);
269 addr_off = act_elem;
270 }
271
272 act_elem = base;
273 if (act_elem)
274 {
275 if (addr_off)
276 addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, act_elem);
277 else
278 addr_off = act_elem;
279 }
280
281 if (offset && !integer_zerop (offset))
282 {
283 if (addr_off)
284 addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, offset);
285 else
286 addr_off = offset;
287 }
288
289 if (addr_off)
290 {
291 if (addr_base)
292 addr = fold_build2 (POINTER_PLUS_EXPR, type, addr_base, addr_off);
293 else
294 addr = fold_convert (type, addr_off);
295 }
296 else if (addr_base)
297 addr = addr_base;
298 else
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 && integer_zerop (addr->offset))
333 addr->offset = NULL_TREE;
334
335 return build6 (TARGET_MEM_REF, type,
336 addr->symbol, addr->base, addr->index,
337 addr->step, addr->offset, 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 && ! DECL_DLLIMPORT_P (obj));
349 }
350
351 /* If ADDR contains an address of object that is a link time constant,
352 move it to PARTS->symbol. */
353
354 static void
355 move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
356 {
357 unsigned i;
358 tree val = NULL_TREE;
359
360 for (i = 0; i < addr->n; i++)
361 {
362 if (!double_int_one_p (addr->elts[i].coef))
363 continue;
364
365 val = addr->elts[i].val;
366 if (TREE_CODE (val) == ADDR_EXPR
367 && fixed_address_object_p (TREE_OPERAND (val, 0)))
368 break;
369 }
370
371 if (i == addr->n)
372 return;
373
374 parts->symbol = TREE_OPERAND (val, 0);
375 aff_combination_remove_elt (addr, i);
376 }
377
378 /* If ADDR contains an address of a dereferenced pointer, move it to
379 PARTS->base. */
380
381 static void
382 move_pointer_to_base (struct mem_address *parts, aff_tree *addr)
383 {
384 unsigned i;
385 tree val = NULL_TREE;
386
387 for (i = 0; i < addr->n; i++)
388 {
389 if (!double_int_one_p (addr->elts[i].coef))
390 continue;
391
392 val = addr->elts[i].val;
393 if (POINTER_TYPE_P (TREE_TYPE (val)))
394 break;
395 }
396
397 if (i == addr->n)
398 return;
399
400 parts->base = val;
401 aff_combination_remove_elt (addr, i);
402 }
403
404 /* Adds ELT to PARTS. */
405
406 static void
407 add_to_parts (struct mem_address *parts, tree elt)
408 {
409 tree type;
410
411 if (!parts->index)
412 {
413 parts->index = fold_convert (sizetype, elt);
414 return;
415 }
416
417 if (!parts->base)
418 {
419 parts->base = elt;
420 return;
421 }
422
423 /* Add ELT to base. */
424 type = TREE_TYPE (parts->base);
425 if (POINTER_TYPE_P (type))
426 parts->base = fold_build2 (POINTER_PLUS_EXPR, type,
427 parts->base,
428 fold_convert (sizetype, elt));
429 else
430 parts->base = fold_build2 (PLUS_EXPR, type,
431 parts->base, elt);
432 }
433
434 /* Finds the most expensive multiplication in ADDR that can be
435 expressed in an addressing mode and move the corresponding
436 element(s) to PARTS. */
437
438 static void
439 most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr,
440 bool speed)
441 {
442 HOST_WIDE_INT coef;
443 double_int best_mult, amult, amult_neg;
444 unsigned best_mult_cost = 0, acost;
445 tree mult_elt = NULL_TREE, elt;
446 unsigned i, j;
447 enum tree_code op_code;
448
449 best_mult = double_int_zero;
450 for (i = 0; i < addr->n; i++)
451 {
452 if (!double_int_fits_in_shwi_p (addr->elts[i].coef))
453 continue;
454
455 /* FIXME: Should use the correct memory mode rather than Pmode. */
456
457 coef = double_int_to_shwi (addr->elts[i].coef);
458 if (coef == 1
459 || !multiplier_allowed_in_address_p (coef, Pmode))
460 continue;
461
462 acost = multiply_by_cost (coef, Pmode, speed);
463
464 if (acost > best_mult_cost)
465 {
466 best_mult_cost = acost;
467 best_mult = addr->elts[i].coef;
468 }
469 }
470
471 if (!best_mult_cost)
472 return;
473
474 /* Collect elements multiplied by best_mult. */
475 for (i = j = 0; i < addr->n; i++)
476 {
477 amult = addr->elts[i].coef;
478 amult_neg = double_int_ext_for_comb (double_int_neg (amult), addr);
479
480 if (double_int_equal_p (amult, best_mult))
481 op_code = PLUS_EXPR;
482 else if (double_int_equal_p (amult_neg, best_mult))
483 op_code = MINUS_EXPR;
484 else
485 {
486 addr->elts[j] = addr->elts[i];
487 j++;
488 continue;
489 }
490
491 elt = fold_convert (sizetype, addr->elts[i].val);
492 if (mult_elt)
493 mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt);
494 else if (op_code == PLUS_EXPR)
495 mult_elt = elt;
496 else
497 mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt);
498 }
499 addr->n = j;
500
501 parts->index = mult_elt;
502 parts->step = double_int_to_tree (sizetype, best_mult);
503 }
504
505 /* Splits address ADDR into PARTS.
506
507 TODO -- be more clever about the distribution of the elements of ADDR
508 to PARTS. Some architectures do not support anything but single
509 register in address, possibly with a small integer offset; while
510 create_mem_ref will simplify the address to an acceptable shape
511 later, it would be more efficient to know that asking for complicated
512 addressing modes is useless. */
513
514 static void
515 addr_to_parts (aff_tree *addr, struct mem_address *parts, bool speed)
516 {
517 tree part;
518 unsigned i;
519
520 parts->symbol = NULL_TREE;
521 parts->base = NULL_TREE;
522 parts->index = NULL_TREE;
523 parts->step = NULL_TREE;
524
525 if (!double_int_zero_p (addr->offset))
526 parts->offset = double_int_to_tree (sizetype, addr->offset);
527 else
528 parts->offset = NULL_TREE;
529
530 /* Try to find a symbol. */
531 move_fixed_address_to_symbol (parts, addr);
532
533 /* First move the most expensive feasible multiplication
534 to index. */
535 most_expensive_mult_to_index (parts, addr, speed);
536
537 /* Try to find a base of the reference. Since at the moment
538 there is no reliable way how to distinguish between pointer and its
539 offset, this is just a guess. */
540 if (!parts->symbol)
541 move_pointer_to_base (parts, addr);
542
543 /* Then try to process the remaining elements. */
544 for (i = 0; i < addr->n; i++)
545 {
546 part = fold_convert (sizetype, addr->elts[i].val);
547 if (!double_int_one_p (addr->elts[i].coef))
548 part = fold_build2 (MULT_EXPR, sizetype, part,
549 double_int_to_tree (sizetype, addr->elts[i].coef));
550 add_to_parts (parts, part);
551 }
552 if (addr->rest)
553 add_to_parts (parts, fold_convert (sizetype, addr->rest));
554 }
555
556 /* Force the PARTS to register. */
557
558 static void
559 gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts)
560 {
561 if (parts->base)
562 parts->base = force_gimple_operand_gsi (gsi, parts->base,
563 true, NULL_TREE,
564 true, GSI_SAME_STMT);
565 if (parts->index)
566 parts->index = force_gimple_operand_gsi (gsi, parts->index,
567 true, NULL_TREE,
568 true, GSI_SAME_STMT);
569 }
570
571 /* Creates and returns a TARGET_MEM_REF for address ADDR. If necessary
572 computations are emitted in front of GSI. TYPE is the mode
573 of created memory reference. */
574
575 tree
576 create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
577 bool speed)
578 {
579 tree mem_ref, tmp;
580 tree atype;
581 struct mem_address parts;
582
583 addr_to_parts (addr, &parts, speed);
584 gimplify_mem_ref_parts (gsi, &parts);
585 mem_ref = create_mem_ref_raw (type, &parts);
586 if (mem_ref)
587 return mem_ref;
588
589 /* The expression is too complicated. Try making it simpler. */
590
591 if (parts.step && !integer_onep (parts.step))
592 {
593 /* Move the multiplication to index. */
594 gcc_assert (parts.index);
595 parts.index = force_gimple_operand_gsi (gsi,
596 fold_build2 (MULT_EXPR, sizetype,
597 parts.index, parts.step),
598 true, NULL_TREE, true, GSI_SAME_STMT);
599 parts.step = NULL_TREE;
600
601 mem_ref = create_mem_ref_raw (type, &parts);
602 if (mem_ref)
603 return mem_ref;
604 }
605
606 if (parts.symbol)
607 {
608 tmp = build_addr (parts.symbol, current_function_decl);
609 gcc_assert (is_gimple_val (tmp));
610
611 /* Add the symbol to base, eventually forcing it to register. */
612 if (parts.base)
613 {
614 gcc_assert (useless_type_conversion_p
615 (sizetype, TREE_TYPE (parts.base)));
616
617 if (parts.index)
618 {
619 atype = TREE_TYPE (tmp);
620 parts.base = force_gimple_operand_gsi (gsi,
621 fold_build2 (POINTER_PLUS_EXPR, atype,
622 tmp,
623 fold_convert (sizetype, parts.base)),
624 true, NULL_TREE, true, GSI_SAME_STMT);
625 }
626 else
627 {
628 parts.index = parts.base;
629 parts.base = tmp;
630 }
631 }
632 else
633 parts.base = tmp;
634 parts.symbol = NULL_TREE;
635
636 mem_ref = create_mem_ref_raw (type, &parts);
637 if (mem_ref)
638 return mem_ref;
639 }
640
641 if (parts.index)
642 {
643 /* Add index to base. */
644 if (parts.base)
645 {
646 atype = TREE_TYPE (parts.base);
647 parts.base = force_gimple_operand_gsi (gsi,
648 fold_build2 (POINTER_PLUS_EXPR, atype,
649 parts.base,
650 parts.index),
651 true, NULL_TREE, true, GSI_SAME_STMT);
652 }
653 else
654 parts.base = parts.index;
655 parts.index = 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.offset && !integer_zerop (parts.offset))
663 {
664 /* Try adding offset to base. */
665 if (parts.base)
666 {
667 atype = TREE_TYPE (parts.base);
668 parts.base = force_gimple_operand_gsi (gsi,
669 fold_build2 (POINTER_PLUS_EXPR, atype,
670 parts.base,
671 fold_convert (sizetype, parts.offset)),
672 true, NULL_TREE, true, GSI_SAME_STMT);
673 }
674 else
675 parts.base = parts.offset;
676
677 parts.offset = NULL_TREE;
678
679 mem_ref = create_mem_ref_raw (type, &parts);
680 if (mem_ref)
681 return mem_ref;
682 }
683
684 /* Verify that the address is in the simplest possible shape
685 (only a register). If we cannot create such a memory reference,
686 something is really wrong. */
687 gcc_assert (parts.symbol == NULL_TREE);
688 gcc_assert (parts.index == NULL_TREE);
689 gcc_assert (!parts.step || integer_onep (parts.step));
690 gcc_assert (!parts.offset || integer_zerop (parts.offset));
691 gcc_unreachable ();
692 }
693
694 /* Copies components of the address from OP to ADDR. */
695
696 void
697 get_address_description (tree op, struct mem_address *addr)
698 {
699 addr->symbol = TMR_SYMBOL (op);
700 addr->base = TMR_BASE (op);
701 addr->index = TMR_INDEX (op);
702 addr->step = TMR_STEP (op);
703 addr->offset = TMR_OFFSET (op);
704 }
705
706 /* Copies the additional information attached to target_mem_ref FROM to TO. */
707
708 void
709 copy_mem_ref_info (tree to, tree from)
710 {
711 /* And the info about the original reference. */
712 TMR_ORIGINAL (to) = TMR_ORIGINAL (from);
713 }
714
715 /* Move constants in target_mem_ref REF to offset. Returns the new target
716 mem ref if anything changes, NULL_TREE otherwise. */
717
718 tree
719 maybe_fold_tmr (tree ref)
720 {
721 struct mem_address addr;
722 bool changed = false;
723 tree ret, off;
724
725 get_address_description (ref, &addr);
726
727 if (addr.base && TREE_CODE (addr.base) == INTEGER_CST)
728 {
729 if (addr.offset)
730 addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
731 addr.offset,
732 fold_convert (sizetype, addr.base));
733 else
734 addr.offset = addr.base;
735
736 addr.base = NULL_TREE;
737 changed = true;
738 }
739
740 if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
741 {
742 off = addr.index;
743 if (addr.step)
744 {
745 off = fold_binary_to_constant (MULT_EXPR, sizetype,
746 off, addr.step);
747 addr.step = NULL_TREE;
748 }
749
750 if (addr.offset)
751 {
752 addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
753 addr.offset, off);
754 }
755 else
756 addr.offset = off;
757
758 addr.index = NULL_TREE;
759 changed = true;
760 }
761
762 if (!changed)
763 return NULL_TREE;
764
765 ret = create_mem_ref_raw (TREE_TYPE (ref), &addr);
766 if (!ret)
767 return NULL_TREE;
768
769 copy_mem_ref_info (ret, ref);
770 return ret;
771 }
772
773 /* Dump PARTS to FILE. */
774
775 extern void dump_mem_address (FILE *, struct mem_address *);
776 void
777 dump_mem_address (FILE *file, struct mem_address *parts)
778 {
779 if (parts->symbol)
780 {
781 fprintf (file, "symbol: ");
782 print_generic_expr (file, parts->symbol, TDF_SLIM);
783 fprintf (file, "\n");
784 }
785 if (parts->base)
786 {
787 fprintf (file, "base: ");
788 print_generic_expr (file, parts->base, TDF_SLIM);
789 fprintf (file, "\n");
790 }
791 if (parts->index)
792 {
793 fprintf (file, "index: ");
794 print_generic_expr (file, parts->index, TDF_SLIM);
795 fprintf (file, "\n");
796 }
797 if (parts->step)
798 {
799 fprintf (file, "step: ");
800 print_generic_expr (file, parts->step, TDF_SLIM);
801 fprintf (file, "\n");
802 }
803 if (parts->offset)
804 {
805 fprintf (file, "offset: ");
806 print_generic_expr (file, parts->offset, TDF_SLIM);
807 fprintf (file, "\n");
808 }
809 }
810
811 #include "gt-tree-ssa-address.h"