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