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